hvcc-0.16.0/LICENSE0000644000000000000000000007640500000000000010431 0ustar00GNU 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 hvcc-0.16.0/README.md0000644000000000000000000002001700000000000010667 0ustar00# Heavy Compiler Collection (hvcc) [![Build Status](https://github.com/Wasted-Audio/hvcc/actions/workflows/ci.yml/badge.svg)](https://github.com/Wasted-Audio/hvcc/actions) [![pypi](https://img.shields.io/pypi/v/hvcc.svg)](https://pypi.python.org/pypi/hvcc) [![python](https://img.shields.io/pypi/pyversions/hvcc.svg)](https://pypi.python.org/pypi/hvcc) `hvcc` is a python-based dataflow audio programming language compiler that generates C/C++ code and a variety of specific framework wrappers. ## Background Originaly created by Enzien Audio, the need for `hvcc` arose from running against performance limitations while creating interactive music and sound products for the iPhone. [Pure Data](https://puredata.info) (libpd) was the only real choice for a design tool as it was embeddable and provided a high enough abstraction level that musicians or sound designers could be creative. The goal was to leverage Pure Data as a design interface and statically interpret the resultant patches to generate a low-level, portable and optimised C/C++ program that would be structured to take advantage of modern hardware whilst still generating the same behaviour and audio output as Pure Data. It has since then been expanded to provide further support for many different platforms and frameworks, targeting game audio design, daw plugins and embedded production tools. In 2021 Wasted Audio took over maintenance of the project. ## Documentation - [Introduction](docs/getting-started/index.md) - [What is heavy?](docs/getting-started/index.md#what-is-heavy) - [Supported patch formats](docs/getting-started/index.md#supported-patch-formats) - [Supported platforms](docs/getting-started/index.md#supported-platforms) - [Supported frameworks](docs/getting-started/index.md#supported-frameworks) - [Licensing](docs/getting-started/index.md#licensing) - [Getting Started](docs/getting-started/patching.md) - [Generators](docs/generators/index.md) - [MIDI](docs/reference/midi.md) - [C API](docs/reference/c.md) - [C++ API](docs/reference/cpp.md) - [Heavy Lang Info](docs/reference/ir/heavy_lang.md) - [Heavy IR Info](docs/reference/ir/heavy_ir.md) - [Heavy GUI IR Info](docs/reference/ir/heavy_gui_ir.md) - [Supported vanilla objects](docs/reference/objects/supported.md) - [Unsupported vanilla objects](docs/reference/objects/unsupported.md) ## Integrations hvcc has been integrated into several projects and services. This allows to easily compile patches without having to install hvcc manually. - [plugdata](https://plugdata.org/) - Modern interface for Pure Data. Includes a full cross-platform toolchain and targets Daisy, DPF and PD Externals. - [mod-cloud-builder](https://github.com/moddevices/mod-cloud-builder) - Online service for building LV2 plugins for the MOD platform. - [OWL Patch Library](https://www.rebeltech.org/patch-library) - Online service for building OWL plugins (uses an old fork). ## Requirements Python 3.9 up to 3.14 - `jinja2` (for generator templating) - `pydantic` (for data types) - `pydantic-extra-types` (for data types) - `arpeggio` (for `expr~` translation) For tests: - `tox` (python install) - `numpy/scipy` (dev dependencies) - `midifile` (git submodule) - `tinywav` (git submodule) - `clang/clang++` (system install) ## Installation hvcc is available from pypi.org and can be installed using python3 pip: ```sh pip3 install hvcc ``` If you want to develop hvcc you can install it from the source directory: ```sh git clone https://github.com/Wasted-Audio/hvcc.git cd hvcc/ pip3 install -e . ``` Also review our [Contribution Guide](CONTRIBUTING.md) before opening a pull request. ## Usage `hvcc` requires at least one argument that determines the top-level patch file to be loaded. Generate a C/C++ program from `input.pd` and place the files in `~/myProject/` ```sh hvcc ~/myProject/_main.pd ``` This command will generate the following directories: - `~/myProject/hv` heavylang representation of the input pd patch(es) - `~/myProject/ir` heavyir representation of the heavylang patch - `~/myProject/c` final generated C/C++ source files (this is what you would use in your project) ### `-o` Select output directory As seen in the above command, typical output of `hvcc` is split into several directories that contain the intermediate files used by the compiler itself, the final generated source files, and any additional framework specific files and projects. The `-o` or `--out_dir` parameter will specify where the output files are placed after a successful compile. For example: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ ``` Will place all the generated files in `~/Desktop/somewhere/else/`. ### `-n` Specify Patch Name The `-n` or `--name` parameter can be used to easily namespace the generated code so that there are no conflicts when integrating multiple patches into the same project. ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth ``` ### `-g` Generators Once `hvcc` has generated internal information about the patch the `-g` or `--gen` parameter can be used to specify the output files it should generate. By default it will always include `c` for the C/C++ source files and additional generators can specified for certain framework targets. For example: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth -g unity ``` Will also generate a `unity` section in the output directory contain all the build projects and source files to compile a Unity plugin. It is also possible to pass a list of generators: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth -g unity wwise js ``` A list of available generator options can be found [here](docs/generators/index.md) ### `-p` Search Paths `hvcc` will iterate through various directories when resolving patch objects and abstractions. The `-p` or `--search_paths` argument can be used to add additional folders for `hvcc` to look in. Note that this argument is not needed for abstractions in the same folder as the top-level patch. This can be handy when using a third-party patch library like [heavylib](https://github.com/Wasted-Audio/heavylib) for example. Simply append any folder paths after the `-p` flag like so: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth -p ~/Workspace/Projects/Enzien/heavylib/ ~/Desktop/myLib/ ``` ### `-m` Meta Data `hvcc` can take extra meta-data via a supplied json file. It depends on the generator which fields are supported. ### `--copyright` User Copyright By default all the generated source files via `hvcc` will have the following copyright text applied to the top of the file: `Copyright (c) 2018 Enzien Audio, Ltd.` This can be changed with `--copyright` parameter ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth --copyright "Copyright (c) Los Pollos Hermanos 2019" ``` ### `--help` Displays all the available parameters and options for hvcc. ## Contact The Heavy community aims to be safe and inclusive, please read our [Code of Conduct](CODE_OF_CONDUCT.md) before engaging. There are several places where heavy/hvcc conversation is happening: - [Discord](https://discord.gg/fmxJveg) - [IRC](https://web.libera.chat/#hvcc) - A number of forums: - [Bela](https://forum.bela.io/?q=hvcc) - [Rebel Technology](https://community.rebeltech.org/tags/puredata) - [Daisy](https://forum.electro-smith.com/c/integrations/pure-data/32) - [MOD](https://forum.moddevices.com/c/developers/pure-data/56) Or you can use the [discussions](https://github.com/Wasted-Audio/hvcc/discussions) tab of this repository ## Funding This project is partially funded through [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/HVCC). [NLnet foundation logo](https://nlnet.nl) [NGI Zero Logo](https://nlnet.nl/commonsfund) hvcc-0.16.0/hvcc/__init__.py0000644000000000000000000000012600000000000012443 0ustar00from hvcc.compiler import compile_dataflow # noqa from hvcc.main import main # noqa hvcc-0.16.0/hvcc/compiler.py0000644000000000000000000003234100000000000012522 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import importlib import inspect import json import os import re import sys from typing import Any, List, Dict, Optional from pathlib import Path from hvcc.interpreters.pd2gui import pd2gui from hvcc.interpreters.pd2hv import pd2hv from hvcc.core.hv2ir import hv2ir from hvcc.generators.ir2c import ir2c, ir2c_perf from hvcc.generators.c2js import c2js from hvcc.generators.c2daisy import c2daisy from hvcc.generators.c2dpf import c2dpf from hvcc.generators.c2owl import c2owl from hvcc.generators.c2pdext import c2pdext from hvcc.generators.c2wwise import c2wwise from hvcc.generators.c2unity import c2unity from hvcc.generators.c2fmod import c2fmod from hvcc.types.compiler import ( CompilerResults, CompilerResp, CompilerNotif, CompilerMsg, Generator, ExternInfo, ExternMemoryPool, ExternMidi, ExternEvents, ExternParams ) from hvcc.types.IR import IRGraph from hvcc.types.meta import Meta def add_error( results: CompilerResults, error: str ) -> CompilerResults: if "hvcc" in results.root: results.root["hvcc"].notifs.errors.append(CompilerMsg(message=error)) else: results.root["hvcc"] = CompilerResp( stage="hvcc", notifs=CompilerNotif( has_error=True, errors=[CompilerMsg(message=error)] ) ) return results def check_extern_name_conflicts(extern_type: str, extern_list: List, results: CompilerResults) -> None: """ In most of the generator code extern names become capitalised when used as enums. This method makes sure that there are no cases where two unique keys become the same after being capitalised. Note(joe): hvcc is probably the best place to check as at this point we have a list of all extern names. """ for i, v in enumerate(extern_list): for j, u in enumerate(extern_list[i + 1:]): if v[0].upper() == u[0].upper(): add_error(results, f"Conflicting {extern_type} names '{v[0]}' and '{u[0]}', make sure that " "capital letters are not the only difference.") def count_midi_objects(hvir: IRGraph) -> Dict[str, List[str]]: in_midi = [] out_midi = [] midi_in_objs = [ '__hv_bendin', '__hv_ctlin', '__hv_midiin', '__hv_midirealtimein', '__hv_notein', '__hv_pgmin', '__hv_polytouchin', '__hv_touchin', ] midi_out_objs = [ '__hv_bendout', '__hv_ctlout', '__hv_midiout', '__hv_midioutport', '__hv_noteout', '__hv_pgmout', '__hv_polytouchout', '__hv_touchout', ] for recv in hvir.control.receivers.keys(): if recv in midi_in_objs: in_midi.append(recv) for msg in hvir.control.sendMessage: if msg.name in midi_out_objs: out_midi.append(msg.name) return { 'in': in_midi, 'out': out_midi } def filter_midi_from_out_parameters(output_parameter_list: List, midi_out_objects: List) -> List: new_out_list = [] for item in output_parameter_list: if not item[0] in midi_out_objects: new_out_list.append(item) return new_out_list def generate_extern_info(hvir: IRGraph, results: CompilerResults) -> ExternInfo: """ Simplifies the receiver/send and table lists by only containing values externed with @hv_param, @hv_event or @hv_table """ # Exposed input parameters in_parameter_list = [(k, v) for k, v in hvir.control.receivers.items() if v.extern == "param"] in_parameter_list.sort(key=lambda x: x[0]) check_extern_name_conflicts("input parameter", in_parameter_list, results) # Exposed input events in_event_list = [(k, v) for k, v in hvir.control.receivers.items() if v.extern == "event"] in_event_list.sort(key=lambda x: x[0]) check_extern_name_conflicts("input event", in_event_list, results) # Exposed output parameters out_parameter_list = [(v.name, v) for v in hvir.control.sendMessage if v.extern == "param"] # remove duplicate output parameters/events # NOTE(joe): is the id argument important here? We'll only take the first one in this case. out_parameter_list = list(dict(out_parameter_list).items()) out_parameter_list.sort(key=lambda x: x[0]) check_extern_name_conflicts("output parameter", out_parameter_list, results) # Exposed output events out_event_list = [(v.name, v) for v in hvir.control.sendMessage if v.extern == "event"] out_event_list = list(dict(out_event_list).items()) out_event_list.sort(key=lambda x: x[0]) check_extern_name_conflicts("output event", out_event_list, results) # Exposed tables table_list = [(k, v) for k, v in hvir.tables.items() if v.extern] table_list.sort(key=lambda x: x[0]) check_extern_name_conflicts("table", table_list, results) # Exposed midi objects midi_objects = count_midi_objects(hvir) # filter midi objects from the output parameters list out_parameter_list = filter_midi_from_out_parameters(out_parameter_list, midi_objects['out']) return ExternInfo( parameters=ExternParams( inParam=in_parameter_list, outParam=out_parameter_list ), events=ExternEvents( inEvent=in_event_list, outEvent=out_event_list ), midi=ExternMidi( inMidi=midi_objects['in'], outMidi=midi_objects['out'] ), tables=table_list, # generate patch heuristics to ensure enough memory allocated for the patch memoryPoolSizesKb=ExternMemoryPool( internal=10, # TODO(joe): should this increase if there are a lot of internal connections? inputQueue=max(2, int( len(in_parameter_list) + (len(in_event_list) / 4) + len(midi_objects['in']) # TODO(dreamer): should this depend on the MIDI type? )), outputQueue=max(2, int( len(out_parameter_list) + (len(out_event_list) / 4) + len(midi_objects['out']) )) ) ) def load_ext_generator(module_name: str, verbose: bool) -> Optional[Generator]: try: module = importlib.import_module(module_name) for _, member in inspect.getmembers(module): if inspect.isclass(member) and not inspect.isabstract(member) and issubclass(member, Generator): return member() if verbose: print(f"---> Module {module_name} does not contain a class derived from hvcc.types.Compiler") return None except ModuleNotFoundError: print(f"---> Module {module_name} not found") return None def compile_dataflow( in_path: Path, out_dir: Path, patch_name: str = "heavy", patch_meta_file: Optional[Path] = None, search_paths: Optional[List[Path]] = None, generators: Optional[List[str]] = None, ext_generators: Optional[List[str]] = None, verbose: bool = False, copyright: Optional[str] = None, nodsp: Optional[bool] = False, gui: Optional[bool] = False ) -> CompilerResults: results = CompilerResults(root={}) patch_meta = Meta() # basic error checking on input if in_path.is_file(): if not str(in_path).endswith((".pd")): return add_error(results, "Can only process Pd files.") elif in_path.is_dir(): if not os.path.basename("c"): return add_error(results, "Can only process c directories.") else: return add_error(results, f"Unknown input path {in_path}") # meta-data file if patch_meta_file is not None: if patch_meta_file.is_file(): with open(patch_meta_file) as json_file: try: patch_meta_json = json.load(json_file) patch_meta = Meta(**patch_meta_json) except Exception as e: return add_error(results, f"Unable to open json_file: {e}") patch_name = patch_meta.name or patch_name generators = ["c"] if generators is None else [x.lower() for x in generators] if verbose: print("--> Generating C") results.root["pd2hv"] = pd2hv.pd2hv.compile( pd_path=in_path, hv_dir=Path(out_dir, "hv"), search_paths=search_paths, verbose=verbose) # ensure that the ir filenames have no funky characters in it subst_name = re.sub(r'\W', '_', patch_name) if gui: if verbose: print("--> Generating GUI IR") results.root["pd2gui"] = pd2gui.pd2gui.compile( pd_path=in_path, ir_file=Path(out_dir, "ir", f"{subst_name}.heavy.gui.json"), search_paths=search_paths, verbose=verbose) # check for errors response: CompilerResp = list(results.root.values())[0] if response.notifs.has_error: return results results.root["hv2ir"] = hv2ir.hv2ir.compile( hv_file=Path(response.out_dir, response.out_file), # ensure that the ir filename has no funky characters in it ir_file=Path(out_dir, "ir", f"{subst_name}.heavy.ir.json"), patch_name=patch_name, verbose=verbose) # check for errors if results.root["hv2ir"].notifs.has_error: return results # get the hvir data hvir = results.root["hv2ir"].ir assert hvir is not None patch_name = hvir.name.escaped externs = generate_extern_info(hvir, results) # get application path if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): application_path = Path(sys._MEIPASS, 'hvcc') elif __file__: application_path = Path(__file__).parent c_src_dir = Path(out_dir, "c") results.root["ir2c"] = ir2c.ir2c.compile( hv_ir_path=Path(results.root["hv2ir"].out_dir, results.root["hv2ir"].out_file), static_dir=Path(application_path, "generators/ir2c/static"), output_dir=c_src_dir, externs=externs, copyright=copyright, nodsp=nodsp) # check for errors if results.root["ir2c"].notifs.has_error: return results # ir2c_perf results.root["ir2c_perf"] = CompilerResp( stage="ir2c_perf", obj_perf=ir2c_perf.ir2c_perf.perf(hvir, verbose=verbose), in_dir=results.root["hv2ir"].out_dir, in_file=results.root["hv2ir"].out_file, ) # run the c2x generators, merge the results num_input_channels = hvir.signal.numInputBuffers num_output_channels = hvir.signal.numOutputBuffers gen_args: Dict[str, Any] = { 'c_src_dir': c_src_dir, 'out_dir': out_dir, 'patch_name': patch_name, 'patch_meta': patch_meta, 'num_input_channels': num_input_channels, 'num_output_channels': num_output_channels, 'externs': externs, 'copyright': copyright, 'verbose': verbose } if "js" in generators: if verbose: print("--> Generating Javascript") results.root["c2js"] = c2js.c2js.compile(**gen_args) if "daisy" in generators: if verbose: print("--> Generating Daisy module") results.root["c2daisy"] = c2daisy.c2daisy.compile(**gen_args) if "dpf" in generators: if verbose: print("--> Generating DPF plugin") results.root["c2dpf"] = c2dpf.c2dpf.compile(**gen_args) if "owl" in generators: if verbose: print("--> Generating OWL plugin") results.root["c2owl"] = c2owl.c2owl.compile(**gen_args) if "pdext" in generators: if verbose: print("--> Generating Pd external") results.root["c2pdext"] = c2pdext.c2pdext.compile(**gen_args) if "unity" in generators: if verbose: print("--> Generating Unity plugin") results.root["c2unity"] = c2unity.c2unity.compile(**gen_args) if "wwise" in generators: if verbose: print("--> Generating Wwise plugin") results.root["c2wwise"] = c2wwise.c2wwise.compile(**gen_args) if "fmod" in generators: if verbose: print("--> Generating Fmod plugin") results.root["c2fmod"] = c2fmod.c2fmod.compile(**gen_args) if ext_generators: for module_name in ext_generators: generator = load_ext_generator(module_name, verbose) if generator is not None: if verbose: print(f"--> Executing custom generator from module {module_name}") results.root[module_name] = generator.compile(**gen_args) return results hvcc-0.16.0/hvcc/core/__init__.py0000644000000000000000000000000000000000000013362 0ustar00hvcc-0.16.0/hvcc/core/hv2ir/BufferPool.py0000644000000000000000000001023000000000000014726 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from collections import defaultdict from typing import Dict, List, Optional, Tuple from .HeavyException import HeavyException class BufferPool: def __init__(self) -> None: # the idea is that the same buffer is reused as quickly as possible so that it doesn't need # to be moved around in the cache. It does not give substantially different results # from a Counter-based implementation, but it is more consistent and predictable. self.pool: Dict = { "~f>": defaultdict(list), "~i>": defaultdict(list) } def num_buffers(self, connection_type: Optional[str] = None) -> int: """ Returns the number of buffers with the given retain count. By default returns the size of the entire pool. Number of buffers per connection type can also be retrieved. """ if connection_type is None: return self.num_buffers("~f>") + self.num_buffers("~i>") elif connection_type in self.pool: return sum(len(v) for v in self.pool[connection_type].values()) else: raise HeavyException(f"Unknown connection type: \"{connection_type}\"") def get_buffer(self, connection_type: str, count: int = 1, excludeSet: Optional[set] = None) -> Tuple[str, int]: """ Returns a currently unused buffer. The buffer can be assigned a retain count. An optional exclude set can also be supplied, ensuring that the returned buffer is not one of them. """ excludeSet = excludeSet if excludeSet is not None else set() pool = self.pool[connection_type] # get the most recently used, unused buffer b = next((b for b in reversed(pool[0]) if b not in excludeSet), None) if b is not None: pool[0].remove(b) else: # if we get here, then no available buffer was found. Create a new one. b = (connection_type, self.num_buffers(connection_type)) # new buffer index for the given type pool[count].append(b) return b def retain_buffer(self, b: List, count: int = 1) -> int: """ Increases the retain count of the buffer. Returns the new count. """ # adc~ and ZERO_BUFFER are special. They cannot be retained. if b[0] in {"zero", "input"}: return 0 else: pool = self.pool[b[0]] for k, v in pool.items(): if b in v: v.remove(b) pool[k + count].append(b) return k + count # return the new retain count raise HeavyException(f"{b} not found in BufferPool!") def release_buffer(self, b: tuple[str, int], count: int = 1) -> int: """ Reduces the retain count of the buffer. Returns the new count. """ # adc~, ZERO_BUFFER, send~ buffers are special. They can not be released. # if the buffer is otherwise unknown (as may be in the case that objects provide their own), # they cannot be released if b[0] in {"zero", "input"}: return 0 else: pool = self.pool[b[0]] for k, v in pool.items(): if b in v: v.remove(b) pool[k - count].append(b) return k - count # return the new retain count raise HeavyException(f"{b} not found in BufferPool!") def __repr__(self) -> str: return self.pool["~f>"].__repr__() + self.pool["~i>"].__repr__() hvcc-0.16.0/hvcc/core/hv2ir/Connection.py0000644000000000000000000000621300000000000014770 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, TYPE_CHECKING if TYPE_CHECKING: from .HeavyIrObject import HeavyIrObject class Connection: """ A Connection describes a connection between two objects. """ def __init__( self, from_object: 'HeavyIrObject', outlet_index: int, to_object: 'HeavyIrObject', inlet_index: int, conn_type: str ) -> None: self.from_object = from_object self.outlet_index = outlet_index self.to_object = to_object self.inlet_index = inlet_index self.type = conn_type # cache the hash of this object self.__hash = hash(( self.from_object, self.outlet_index, self.to_object, self.inlet_index, self.type)) def copy( self, from_object: Optional['HeavyIrObject'] = None, outlet_index: Optional[int] = None, to_object: Optional['HeavyIrObject'] = None, inlet_index: Optional[int] = None, type: Optional[str] = None ) -> 'Connection': """ Create a new connection based on the existing one, changing the given values. """ return Connection(from_object=self.from_object if from_object is None else from_object, outlet_index=self.outlet_index if outlet_index is None else outlet_index, to_object=self.to_object if to_object is None else to_object, inlet_index=self.inlet_index if inlet_index is None else inlet_index, conn_type=self.type if type is None else type) @property def is_signal(self) -> bool: return self.is_signal_type(self.type) @property def is_control(self) -> bool: return self.type == "-->" @property def is_float_signal(self) -> bool: return self.type == "~f>" @property def is_integer_signal(self) -> bool: return self.type == "~i>" @property def is_mixed(self) -> bool: return self.type == "-~>" @classmethod def is_signal_type(cls, type: Optional[str]) -> bool: return type in {"~i>", "~f>"} def __eq__(self, other: object) -> bool: return self.__hash == other.__hash__() if isinstance(other, Connection) else False def __hash__(self) -> int: return self.__hash def __repr__(self) -> str: return f"[{self.from_object}:{self.outlet_index}] {self.type} [{self.to_object}:{self.inlet_index}]" hvcc-0.16.0/hvcc/core/hv2ir/HIrConvolution.py0000644000000000000000000000327200000000000015615 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, Optional, List, Set, Tuple from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrConvolution(HeavyIrObject): """ __conv~f """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type == "__conv~f" super().__init__(obj_type, args=args, graph=graph, annotations=annotations) def reduce(self) -> Optional[Tuple[Set, List]]: if self.graph is not None: table_obj = self.graph.resolve_object_for_name( self.args["table"], ["table", "__table"]) if table_obj is not None: self.args["table_id"] = table_obj.id return ({self}, []) else: self.add_error(f"Cannot find table named \"{self.args['table']}\" for object {self}.") return None hvcc-0.16.0/hvcc/core/hv2ir/HIrExpr.py0000644000000000000000000000324500000000000014214 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . from typing import Dict, Optional from .HeavyIrObject import HeavyIrObject from .HeavyException import HeavyException from .HeavyGraph import HeavyGraph class HIrExpr(HeavyIrObject): """ This needs little logic as the expression is forwarded to ir2c """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: super().__init__(obj_type, args=args, graph=graph, num_inlets=args["num_inlets"] if args is not None else 1, num_outlets=1, annotations=annotations) def inlet_requires_signal(self, inlet_index: int = 0) -> bool: """ Overriding HeavyIrObject to deal with variable number of inlets """ if inlet_index >= self.num_inlets: raise HeavyException(f"inlet_index: {inlet_index} is greater than number of inlets") return True hvcc-0.16.0/hvcc/core/hv2ir/HIrInlet.py0000644000000000000000000000400400000000000014343 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, Optional from .HeavyException import HeavyException from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph from hvcc.types.Lang import LangLetType class HIrInlet(HeavyIrObject): """ A specific implementation of the inlet object. """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: super().__init__("__inlet", args=args, graph=graph, annotations=annotations) def _resolved_outlet_type(self, outlet_index: int = 0) -> Optional[LangLetType]: if self.graph is not None: connections = self.graph.inlet_connections[self.args["index"]] connection_type_set = {c.type for c in connections} if len(connection_type_set) == 0: # object has no incident connections. return "-->" # outlet type defaults to control (-->) elif len(connection_type_set) == 1: return list(connection_type_set)[0] else: raise HeavyException( f"{self} has multiple incident connections of differing type. " "The outlet type cannot be explicitly resolved.") return None hvcc-0.16.0/hvcc/core/hv2ir/HIrLorenz.py0000644000000000000000000000226700000000000014552 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Dict, Optional from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrLorenz(HeavyIrObject): """ __lorenz~f """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type == "__lorenz~f" super().__init__(obj_type, args=args, graph=graph, annotations=annotations) hvcc-0.16.0/hvcc/core/hv2ir/HIrNam.py0000644000000000000000000000336700000000000014016 0ustar00# Copyright (C) 2026 Wasted Audio # # 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 . from typing import Dict, Optional from pathlib import Path from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph from hvcc.generators.ir2c.SignalNamHeader import ModelNet, load_nam_file class HIrNam(HeavyIrObject): """ __nam~f """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type == "__nam~f" # load the nam file to retrieve the model type assert args is not None model_net, _, _ = load_nam_file(Path(args["nam"])) # overload the object type based on the model if model_net == ModelNet.Nano: obj_type = "__nam_nano~f" elif model_net == ModelNet.Feather: obj_type = "__nam_feather~f" elif model_net == ModelNet.Lite: obj_type = "__nam_lite~f" elif model_net == ModelNet.Standard: obj_type = "__nam_standard~f" super().__init__(obj_type, args=args, graph=graph, annotations=annotations) hvcc-0.16.0/hvcc/core/hv2ir/HIrOutlet.py0000644000000000000000000000300700000000000014546 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List, Optional from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph from hvcc.types.IR import IROnMessage class HIrOutlet(HeavyIrObject): """ A specific implementation of the outlet object. """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: super().__init__("__outlet", args=args, graph=graph, annotations=annotations) def get_ir_on_message(self, inlet_index: int = 0) -> List[IROnMessage]: x = [] if self.graph is not None: for c in self.graph.outlet_connections[self.args["index"]]: x.extend(c.to_object.get_ir_on_message(c.inlet_index)) return x hvcc-0.16.0/hvcc/core/hv2ir/HIrPack.py0000644000000000000000000000252700000000000014156 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Dict, Optional from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrPack(HeavyIrObject): def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: if args is not None: num_inlets = len(args["values"]) else: num_inlets = 0 super().__init__("__pack", args=args, graph=graph, num_inlets=num_inlets, num_outlets=1, annotations=annotations) hvcc-0.16.0/hvcc/core/hv2ir/HIrReceive.py0000644000000000000000000000324500000000000014660 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . import re from typing import Dict, Optional, TYPE_CHECKING from .HeavyIrObject import HeavyIrObject if TYPE_CHECKING: from .HeavyGraph import HeavyGraph class HIrReceive(HeavyIrObject): """ A specific implementation of the __receive object. """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional['HeavyGraph'] = None, annotations: Optional[Dict] = None ) -> None: super().__init__("__receive", args=args, graph=graph, annotations=annotations) if args is not None and args["extern"]: # externed receivers must contain only alphanumeric characters or underscores, # so that the names can be easily and transparently turned into code if re.search(r"\W", args["name"]): self.add_error(f"Parameter and Event names may only contain \ alphanumeric characters or underscore: '{args['name']}'") hvcc-0.16.0/hvcc/core/hv2ir/HIrSend.py0000644000000000000000000000466300000000000014174 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . import re from typing import Dict, List, Optional from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph from hvcc.types.IR import IRSendMessage class HIrSend(HeavyIrObject): """ A specific implementation of the __send object. """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: super().__init__("__send", args=args, graph=graph, annotations=annotations) if args is not None and args["extern"]: # output parameters must contain only alphanumeric characters or underscores, # so that the names can be easily and transparently turned into code if re.search(r"\W", args["name"]): self.add_error(f"Parameter and Event names may only contain \ alphanumeric characters or underscore: '{args['name']}'") def get_ir_control_list(self) -> List[IRSendMessage]: if self.graph is not None and self.name is not None: receive_objs = self.graph.resolve_objects_for_name(self.name, "__receive") on_message_list = [x for o in receive_objs for x in o.get_ir_on_message(inlet_index=0)] return [IRSendMessage( id=self.id, type="send", onMessage=[on_message_list], extern=self.args["extern"], attributes=self.args["attributes"], hash=self.args["hash"], display=self.args["name"], name=((f"_{self.args['name']}") if re.match(r"\d", self.args["name"]) else self.args["name"]) )] else: return [] hvcc-0.16.0/hvcc/core/hv2ir/HIrSwitchcase.py0000644000000000000000000000273300000000000015374 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Dict, Optional from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrSwitchcase(HeavyIrObject): """ A specific implementation of the __switchcase object. """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: if args is not None: num_cases = len(args["cases"]) else: num_cases = 0 super().__init__("__switchcase", args=args, graph=graph, num_inlets=1, num_outlets=num_cases + 1, annotations=annotations) hvcc-0.16.0/hvcc/core/hv2ir/HIrTabhead.py0000644000000000000000000000331300000000000014622 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, Optional, List, Set, Tuple from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrTabhead(HeavyIrObject): """ __tabhead~f and __tabhead """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type in {"__tabhead~f", "__tabhead"} super().__init__(obj_type, args=args, graph=graph, annotations=annotations) def reduce(self) -> Optional[Tuple[Set, List]]: if self.graph is not None: table_obj = self.graph.resolve_object_for_name( self.args["table"], ["table", "__table"]) if table_obj is not None: self.args["table_id"] = table_obj.id return ({self}, []) else: self.add_error(f"Can't find table with name \"{self.args['table']}\".") return None hvcc-0.16.0/hvcc/core/hv2ir/HIrTabread.py0000644000000000000000000000342300000000000014636 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, Optional, List, Set, Tuple from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrTabread(HeavyIrObject): """ __tabread~if """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type in {"__tabread~if", "__tabread~f", "__tabread_stoppable~f", "__tabreadu~f", "__tabread"} super().__init__(obj_type, args=args, graph=graph, annotations=annotations) def reduce(self) -> Optional[Tuple[Set, List]]: if self.graph is not None: table_obj = self.graph.resolve_object_for_name( self.args["table"].split(" ")[0], ["table", "__table"]) if table_obj is not None: self.args["table_id"] = table_obj.id return ({self}, []) else: self.add_error(f"Cannot find table named \"{self.args['table']}\" for object {self}.") return None hvcc-0.16.0/hvcc/core/hv2ir/HIrTabwrite.py0000644000000000000000000000335000000000000015054 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, Optional, List, Set, Tuple from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HIrTabwrite(HeavyIrObject): """ __tabwrite~f """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional[HeavyGraph] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type in {"__tabwrite~f", "__tabwrite_stoppable~f", "__tabwrite"} super().__init__(obj_type, args=args, graph=graph, annotations=annotations) def reduce(self) -> Optional[Tuple[Set, List]]: if self.graph is not None: table_obj = self.graph.resolve_object_for_name( self.args["table"].split(" ")[0], ["table", "__table"]) if table_obj is not None: self.args["table_id"] = table_obj.id return ({self}, []) else: self.add_error(f"Can't find table with name \"{self.args['table']}\".") return None hvcc-0.16.0/hvcc/core/hv2ir/HLangAdc.py0000644000000000000000000000432200000000000014271 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph from hvcc.types.Lang import LangLetType class HLangAdc(HeavyLangObject): """ adc """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "adc" super().__init__(obj_type, args, graph, num_inlets=0, num_outlets=len(args[self._HEAVY_LANG_DICT[obj_type].args[0].name]), annotations=annotations) def _resolved_outlet_type(self, outlet_index: int = 0) -> LangLetType: return "~f>" def reduce(self) -> tuple: objects = set() connections = [] # reduce a HeavyLang adc to a number of individual HeavyIR __inlet objects for i, channel_index in enumerate(self.args["channels"]): if len(self.outlet_connections[i]) > 0: # if there are any connections to this inlet x = HeavyIrObject("__inlet", args={ "index": 127 + channel_index }) x.outlet_buffers[0] = ("input", channel_index - 1) # channel indicies are one-indexed objects.add(x) for c in self.outlet_connections[i]: connections.append((c, [c.copy(from_object=x, outlet_index=0)])) return (objects, connections) hvcc-0.16.0/hvcc/core/hv2ir/HLangBinop.py0000644000000000000000000002516000000000000014654 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .Connection import Connection from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangBinop(HeavyLangObject): __HEAVY_DICT = { "+": ["__add", "__add_k", "__add~f", "__add~i"], "-": ["__sub", "__sub_k", "__sub~f", "__sub~i"], "*": ["__mul", "__mul_k", "__mul~f", "__mul~i"], "/": ["__div", "__div_k", "__div~f", "__div~i"], "max": ["__max", "__max_k", "__max~f", "__max~i"], "min": ["__min", "__min_k", "__min~f", "__min~i"], ">": ["__gt", "__gt_k", "__gt~f", "__gt~i"], ">=": ["__gte", "__gte_k", "__gte~f", "__gte~i"], "==": ["__eq", "__eq_k", "__eq~f", "__eq~i"], "!=": ["__neq", "__neq_k", "__neq~f", "__neq~i"], "<": ["__lt", "__lt_k", "__lt~f", "__lt~i"], "<=": ["__lte", "__lte_k", "__lte~f", "__lte~i"], "&": ["__and", "__and_k", "__and~f", "__and~i"], # binary and "&&": ["__logand", "__logand_k"], # logical or "&!": ["__andnot", "__andnot~f", "__andnot~i"], "|": ["__or", "__or_k", "__or~f", "__or~i"], # binary or "||": ["__logor", "__logor_k"], # logical or "pow": ["__pow", "__pow_k", "__pow~f", "__pow~i"], "atan2": ["__atan2", "__atan2_k", "__atan2~f"], "mod": ["__unimod", "__unimod_k"], "%": ["__bimod", "__bimod_k"], ">>": ["__shiftright", "__shiftright_k"], # binary right shift "<<": ["__shiftleft", "__shiftleft_k"] # binary left shift } def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional['HeavyGraph'] = None, annotations: Optional[Dict] = None ) -> None: super().__init__(obj_type, args, graph, num_inlets=2, num_outlets=1, annotations=annotations) @classmethod def handles_type(cls, obj_type: str) -> bool: """Returns True if this class handles the given object type. False otherwise. """ return obj_type in HLangBinop.__HEAVY_DICT def reduce(self) -> Optional[tuple]: if self.has_inlet_connection_format("__") or \ self.has_inlet_connection_format("_c") or \ self.has_inlet_connection_format("_f") or \ self.has_outlet_connection_format("_"): # binary operator objects must have a left inlet or outlet connection. return (set(), []) # remove this object if self.has_inlet_connection_format("ff"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~f")][0] x = HeavyIrObject(ir_type) return ({x}, self.get_connection_move_list(x)) elif self.has_inlet_connection_format("fc"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~f")][0] x = HeavyIrObject(ir_type) y = HeavyIrObject("__var~f", {"k": self.args[self.name_for_arg()]}) z = HeavyIrObject("__varread~f", {"var_id": y.id}) connections = [(None, [Connection(z, 0, x, 1, "~f>")])] for c in self.inlet_connections[0]: # left inlet to ir_type connections.append((c, [c.copy(to_object=x)])) for c in self.inlet_connections[1]: # right inlet to __var~f connections.append((c, [c.copy(to_object=y, inlet_index=0)])) for c in self.outlet_connections[0]: # ir_type outlet connections.append((c, [c.copy(from_object=x)])) return ({x, y, z}, connections) elif self.has_inlet_connection_format("f_"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~f")][0] # handle identity-operations if (self.type == "+" and self.args["k"] == 0.0) or \ (self.type == "-" and self.args["k"] == 0.0) or \ (self.type == "*" and self.args["k"] == 1.0) or \ (self.type == "/" and self.args["k"] == 1.0): if len(self.inlet_connections[0]) == 0: return (set(), []) # remove this object elif len(self.inlet_connections[0]) == 1: # there is only one connection, pass through the connection # and remove this object c = self.inlet_connections[0][0] connections = [(c, [c.copy(to_object=v.to_object, inlet_index=v.inlet_index) for v in self.outlet_connections[0]])] return (set(), connections) else: # len(self.inlet_connections[0]) > 1 # there are multiple connections to the left inlet # create a __add~f, move one connection to the left inlet # and the remainder to the right inlet x = HeavyIrObject("__add~f") c = self.inlet_connections[0][0] connections = [(c, [c.copy(to_object=x, inlet_index=0)])] for c in self.inlet_connections[0][1:]: connections.append((c, [c.copy(to_object=x, inlet_index=1)])) for c in self.outlet_connections[0]: connections.append((c, [c.copy(from_object=x, outlet_index=0)])) return ({x}, connections) if self.type == "*": # self.args["k"] == 1.0 case handled above if self.args["k"] == 0.0: # this object does nothing at all. Remove it. return (set(), []) if self.args["k"] == -1.0: x = HeavyIrObject("__neg~f") return ({x}, self.get_connection_move_list(x)) x = HeavyIrObject(ir_type) # add constant generator y = HeavyIrObject( "__var_k~f", args={"k": self.args[self.name_for_arg()]}) connections = self.get_connection_move_list(x) connections.append((None, [Connection(y, 0, x, 1, "~f>")])) return ({x, y}, connections) elif self.has_inlet_connection_format("ii"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~i")][0] x = HeavyIrObject(ir_type) return ({x}, self.get_connection_move_list(x)) elif self.has_inlet_connection_format("ic"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~i")][0] x = HeavyIrObject(ir_type) y = HeavyIrObject("__var~i", {"k": self.args[self.name_for_arg()]}) z = HeavyIrObject("__varread~i", {"var_id": y.id}) connections = [(None, [Connection(z, 0, x, 1, "~f>")])] for c in self.inlet_connections[0]: connections.append((c, [c.copy(to_object=x)])) for c in self.inlet_connections[1]: connections.append((c, [c.copy(to_object=y, inlet_index=0)])) for c in self.outlet_connections[0]: connections.append((c, [c.copy(from_object=x)])) return ({x, y, z}, connections) elif self.has_inlet_connection_format("i_"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~i")][0] x = HeavyIrObject(ir_type) # add constant generator y = HeavyIrObject( "__var_k~i", args={"k": self.args[self.name_for_arg()]}) connections = [(None, [Connection(y, 0, x, 1, "~i>")])] for c in self.inlet_connections[0]: connections.append((c, [c.copy(to_object=x)])) for c in self.inlet_connections[1]: connections.append((c, [c.copy(to_object=y, inlet_index=0)])) for c in self.outlet_connections[0]: connections.append((c, [c.copy(from_object=x)])) return ({x, y}, connections) elif self.has_inlet_connection_format("cc"): ir_type = HLangBinop.__HEAVY_DICT[self.type][0] # standardise the operation's constant argument name to "k" args = {"k": self.args[self.name_for_arg()]} x = HeavyIrObject(ir_type, args) return ({x}, self.get_connection_move_list(x)) elif self.has_inlet_connection_format("c_"): # if the right inlet is empty, generate a constant variation of the object ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("_k")][0] # standardise the operation's constant argument name to "k" args = {"k": self.args[self.name_for_arg()]} x = HeavyIrObject(ir_type, args) return ({x}, self.get_connection_move_list(x)) elif self.has_inlet_connection_format("cf"): ir_type = [x for x in HLangBinop.__HEAVY_DICT[self.type] if x.endswith("~f")][0] x = HeavyIrObject(ir_type) v = HeavyIrObject("__var~f") vr = HeavyIrObject("__varread~f", args={"var_id": v.id}) obj_set = set([x, v, vr]) connections = [(None, [Connection(vr, 0, x, 0, "~f>")])] for c in self.inlet_connections[0]: connections.append((c, [c.copy(to_object=v, inlet_index=0)])) for c in self.inlet_connections[1]: connections.append((c, [c.copy(to_object=x, inlet_index=1)])) for c in self.outlet_connections[0]: connections.append((c, [c.copy(from_object=x, outlet_index=0)])) return (obj_set, connections) else: fmt = self._get_connection_format(self.inlet_connections) if "m" in fmt: self.add_error( "A binary operator cannot have both a signal and control " f"connection to the same inlet: {fmt}") else: self.add_error(f"Unknown inlet configuration: {fmt}") return None hvcc-0.16.0/hvcc/core/hv2ir/HLangBiquad.py0000644000000000000000000000400700000000000015007 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . import re from typing import Optional, Dict from .HeavyException import HeavyException from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangBiquad(HeavyLangObject): """ Translates HeavyLang object biquad to HeavyIR biquad~. """ # used to detect valid connection configuration formats __re_fmt_k = re.compile("[f_][c_]+") __re_fmt_f = re.compile("[f_]+") def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "biquad" super().__init__(obj_type, args, graph, num_inlets=6, num_outlets=1, annotations=annotations) def reduce(self) -> tuple: fmt = self._get_connection_format(self.inlet_connections) if self.__re_fmt_k.search(fmt): x = HeavyIrObject("__biquad_k~f", self.args) return {x}, self.get_connection_move_list(x) elif self.__re_fmt_f.search(fmt): x = HeavyIrObject("__biquad~f", self.args) return {x}, self.get_connection_move_list(x) else: raise HeavyException(f"Unsupported connection format to biquad: {fmt}") hvcc-0.16.0/hvcc/core/hv2ir/HLangDac.py0000644000000000000000000000415100000000000014271 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangDac(HeavyLangObject): """ Translates HeavyLang [dac] to HeavyIR [__add~f]. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "dac" super().__init__(obj_type, args, graph, num_inlets=len(args[self._HEAVY_LANG_DICT[obj_type].args[0].name]), num_outlets=0, annotations=annotations) def reduce(self) -> tuple: objects = set() connections = [] # reduce a HeavyLang dac to a number of individual HeavyIR __add~f objects for i, channel_index in enumerate(self.args["channels"]): if len(self.inlet_connections[i]) > 0: # if there are any connections to this inlet x = HeavyIrObject("__add~f") x.inlet_buffers[1] = ("output", channel_index - 1) # channel indicies are one-indexed x.outlet_buffers[0] = ("output", channel_index - 1) objects.add(x) for c in self.inlet_connections[i]: connections.append((c, [c.copy(to_object=x, inlet_index=0)])) return (objects, connections) hvcc-0.16.0/hvcc/core/hv2ir/HLangDelay.py0000644000000000000000000000276300000000000014647 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangDelay(HeavyLangObject): """ Handle the delay object. """ def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional['HeavyGraph'] = None, annotations: Optional[Dict] = None ) -> None: assert obj_type == "delay" super().__init__("delay", args, graph, num_inlets=2, num_outlets=1, annotations=annotations) def reduce(self) -> tuple: x = HeavyIrObject("__delay", self.args, annotations=self.annotations) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangIf.py0000644000000000000000000000412100000000000014135 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . # moved to HeavyParser.py because of circular dependency # from pathlib import Path # from .HeavyException import HeavyException # from .HeavyIrObject import HeavyIrObject # from .HeavyLangObject import HeavyLangObject # class HLangIf(HeavyLangObject): # """ Translates HeavyLang object [if] to HeavyIR [if] or [if~]. # """ # def __init__( # self, # obj_type: str, # args: Dict, # graph: HeavyGraph, # annotations: Optional[Dict] = None # ) -> None: # assert obj_type == "if" # super().__init__("if", args, graph, num_inlets=2, num_outlets=2, annotations=annotations) # def reduce(self) -> Tuple[Set, List]: # if self.has_inlet_connection_format(["cc", "_c", "c_", "__"]): # x = HeavyIrObject("__if", self.args) # elif self.has_inlet_connection_format("ff"): # # TODO(mhroth): implement this # x = HeavyParser.graph_from_file(Path("./hvlib/if~f.hv.json")) # elif self.has_inlet_connection_format("ii"): # # TODO(mhroth): implement this # x = HeavyParser.graph_from_file(Path("./hvlib/if~i.hv.json")) # else: # fmt = self._get_connection_format(self.inlet_connections) # raise HeavyException(f"Unhandled connection configuration to object [if]: {fmt}") # return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangLine.py0000644000000000000000000000330700000000000014473 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangLine(HeavyLangObject): """ Translates HeavyLang object [line] to HeavyIR [__line] or [__line~f]. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "line" super().__init__("line", args, graph, num_inlets=2, num_outlets=1, annotations=annotations) def reduce(self) -> tuple: if self.has_outlet_connection_format("f"): x = HeavyIrObject("__line~f", self.args) elif self.has_outlet_connection_format("c"): x = HeavyIrObject("__line", self.args) else: self.add_error("Unknown inlet configuration.") return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangMessage.py0000644000000000000000000000271100000000000015166 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangMessage(HeavyLangObject): """ Handles the HeavyLang "message" object. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "message" super().__init__(obj_type, args, graph, num_inlets=1, num_outlets=1, annotations=annotations) def reduce(self) -> tuple: x = HeavyIrObject("__message", self.args) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangNoise.py0000644000000000000000000000330700000000000014661 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . # moved to HeavyParser.py because of circular dependency # import random # from pathlib import Path # from .HeavyLangObject import HeavyLangObject # from .HeavyParser import HeavyParser # class HLangNoise(HeavyLangObject): # """ Handles the HeavyLang "noise" object. # """ # def __init__( # self, # obj_type: str, # args: Dict, # graph: HeavyGraph, # annotations: Optional[Dict] = None # ) -> None: # assert obj_type == "noise" # super().__init__("noise", args, graph, num_inlets=1, num_outlets=1, annotations=annotations) # def reduce(self) -> Tuple[Set, List]: # seed = int(random.uniform(1, 2147483647)) # assign a random 32-bit seed # noise_path = Path(Path(__file__).parent, "./hvlib/noise.hv.json") # x = HeavyParser.graph_from_file(noise_path, graph_args={"seed": seed}) # x.reduce() # # TODO(mhroth): deal with control input # return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangPhasor.py0000644000000000000000000000307000000000000015035 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangPhasor(HeavyLangObject): """ Translates HeavyLang object [phasor] to HeavyIR [phasor~]. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "phasor" super().__init__(obj_type, args, graph, annotations=annotations) def reduce(self) -> tuple: if self.has_inlet_connection_format(["f_", "fc"]): x = HeavyIrObject("__phasor~f", self.args) return ({x}, self.get_connection_move_list(x)) else: x = HeavyIrObject("__phasor_k~f", self.args) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangPrint.py0000644000000000000000000000270100000000000014675 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangPrint(HeavyLangObject): """ Handles the HeavyLang "print" object. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "print" super().__init__(obj_type, args, graph, num_inlets=1, num_outlets=0, annotations=annotations) def reduce(self) -> tuple: x = HeavyIrObject("__print", self.args) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangRandom.py0000644000000000000000000000303300000000000015020 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . import random from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangRandom(HeavyLangObject): """ Handles the HeavyLang "print" object. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "random" super().__init__(obj_type, args, graph, num_inlets=2, num_outlets=1, annotations=annotations) def reduce(self) -> tuple: self.args["seed"] = int(random.uniform(-2147483647, 2147483648)) x = HeavyIrObject("__random", self.args) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangReceive.py0000644000000000000000000000421200000000000015162 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HIrReceive import HIrReceive from .HeavyGraph import HeavyGraph class HLangReceive(HeavyLangObject): """ Translates HeavyLang object [receive] to HeavyIR [__receive if control, otherwise for signal connections it will remove the send~/receive~ objects and reorder the graph. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "receive" super().__init__(obj_type, args, graph, annotations=annotations) def reduce(self) -> Optional[tuple]: if self.has_outlet_connection_format(["c"]): x = HIrReceive("__receive", self.args, annotations=self.annotations) return ({x}, self.get_connection_move_list(x)) elif self.has_outlet_connection_format(["f"]): # this case should be handled already in HeavyGraph.remap_send_receive() # clean up just in case return (set(), []) elif self.has_outlet_connection_format("_"): self.add_warning("receive~ object doesn't have any outputs, this one is being removed.") return (set(), []) else: fmt = self._get_connection_format(self.outlet_connections) self.add_error(f"Unknown outlet configuration: {fmt}") return None hvcc-0.16.0/hvcc/core/hv2ir/HLangSend.py0000644000000000000000000000470100000000000014474 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HIrSend import HIrSend from .HeavyGraph import HeavyGraph class HLangSend(HeavyLangObject): """ Translates HeavyLang object [send] to HeavyIR [__send] if control, otherwise for signal connections it will remove the send~/receive~ objects and reorder the graph. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "send" super().__init__(obj_type, args, graph, annotations=annotations) def reduce(self) -> Optional[tuple]: if self.has_inlet_connection_format("c"): ir_args = dict(self.args) ir_args["hash"] = f"0x{HeavyLangObject.get_hash(ir_args['name']):X}" x = HIrSend("__send", ir_args, annotations=self.annotations) return ({x}, self.get_connection_move_list(x)) elif self.has_inlet_connection_format("f"): # this case should be handled already in HeavyGraph.remap_send_receive() # clean up just in case return (set(), []) elif self.has_inlet_connection_format("_"): self.add_warning("send~ object doesn't have any inputs, this one is being removed.") return (set(), []) elif self.has_inlet_connection_format("m"): self.add_error( "Inlet can support either control or signal connections, " "but not both at the same time.") return None else: fmt = self._get_connection_format(self.inlet_connections) self.add_error(f"Unknown inlet configuration: {fmt}") return None hvcc-0.16.0/hvcc/core/hv2ir/HLangSequence.py0000644000000000000000000000636100000000000015357 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Optional, Dict, List from .Connection import Connection from .HeavyException import HeavyException from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangSequence(HeavyLangObject): def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: # get the number of outlets that this object has num_outlets = len(args[self._HEAVY_LANG_DICT[obj_type].args[0].name]) super().__init__(obj_type, args, graph, num_inlets=1, num_outlets=num_outlets, annotations=annotations) def reduce(self) -> tuple: cast_objs: List = [] for a in self.args[self.name_for_arg()]: if a in {"a", "anything", "l", "list"}: cast_objs.append(None) # pass through elif a in {"b", "bang"}: cast_objs.append(HeavyIrObject("__cast_b", {})) elif a in {"f", "float"}: cast_objs.append(HeavyIrObject("__cast_f", {})) elif a in {"s", "symbol"}: cast_objs.append(HeavyIrObject("__cast_s", {})) else: raise HeavyException(f"Unsupported cast type '{a}'.") connections = [] # establish connections from inlet objects to the cast objects for ci in self.inlet_connections[0]: c_list = [] for i in range(self.num_outlets - 1, -1, -1): if cast_objs[i] is not None: c_list.append(Connection.copy(ci, to_object=cast_objs[i], inlet_index=0)) else: # for anything casts, establish a connection directly to the target for co in self.outlet_connections[i]: c_list.append(Connection.copy(ci, to_object=co.to_object, inlet_index=co.inlet_index)) connections.append((ci, c_list)) # establish connections from the cast objects for i in range(self.num_outlets - 1, -1, -1): if cast_objs[i] is not None: for c in self.outlet_connections[i]: connections.append((c, [c.copy(from_object=cast_objs[i], outlet_index=0)])) # remove None objects from cast_objs. It was only used as a placeholder # to indicate that a cast passthrough objects = set(cast_objs) objects.discard(None) return (objects, connections) hvcc-0.16.0/hvcc/core/hv2ir/HLangSlice.py0000644000000000000000000000270100000000000014640 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangSlice(HeavyLangObject): """ Handles the HeavyLang "slice" object. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "slice" super().__init__(obj_type, args, graph, num_inlets=3, num_outlets=2, annotations=annotations) def reduce(self) -> tuple: x = HeavyIrObject("__slice", self.args) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangSystem.py0000644000000000000000000000270500000000000015071 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangSystem(HeavyLangObject): """ Handles the HeavyLang "system" object. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "system" super().__init__(obj_type, args, graph, num_inlets=1, num_outlets=1, annotations=annotations) def reduce(self) -> tuple: x = HeavyIrObject("__system", self.args) return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangTable.py0000644000000000000000000000416700000000000014640 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . import re from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangTable(HeavyLangObject): """ Handles the HeavyLang "table" object. """ def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "table" super().__init__(obj_type, args, graph, annotations=annotations) # the values argument overrides the size argument if len(self.args.get("values", [])) > 0: self.args["size"] = len(self.args["values"]) if self.args["extern"]: # externed tables must contain only alphanumeric characters or underscores, # so that the names can be easily and transparently turned into code if re.search(r"\W", args["name"]): self.add_error(f"Table names may only contain alphanumeric characters \ or underscore: '{args['name']}'") def reduce(self) -> tuple: x = HeavyIrObject("__table", self.args) # ensure that __table object maintains the same id as the original # table object. The latter is referenced by id from other objects. # Consistency must be maintained. x.id = self.id return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangUnop.py0000644000000000000000000000771100000000000014530 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyLangObject import HeavyLangObject from .HeavyIrObject import HeavyIrObject from .HeavyGraph import HeavyGraph class HLangUnop(HeavyLangObject): __HEAVY_DICT = { "log": ["__log"], "log10": ["__log10"], "log2": ["__log2", "__log2~f"], "cos": ["__cos", "__cos~f"], "acos": ["__acos", "__acos~f"], "cosh": ["__cosh", "__cosh~f"], "acosh": ["__acosh", "__acosh~f"], "sin": ["__sin", "__sin~f"], "asin": ["__asin", "__asin~f"], "sinh": ["__sinh", "__sinh~f"], "asinh": ["__asinh", "__asin~f"], "tan": ["__tan", "__tan~f"], "atan": ["__atan", "__atan~f"], "tanh": ["__tanh", "__tanh~f"], "atanh": ["__atanh", "__atanh~f"], "exp": ["__exp", "__exp~f"], "sqrt": ["__sqrt", "__sqrt~f"], "abs": ["__abs", "__abs~f", "__abs~i"], "floor": ["__floor", "__floor~f"], "ceil": ["__ceil", "__ceil~f"], "cast_fi": ["__cast~fi"], "cast_if": ["__cast~if"] } def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert self.handles_type(obj_type) super().__init__(obj_type, args, graph, num_inlets=1, num_outlets=1, annotations=annotations) @classmethod def handles_type(cls, obj_type: str) -> bool: """ Returns True if this class handles the given object type. False otherwise. """ return obj_type in HLangUnop.__HEAVY_DICT def reduce(self) -> Optional[tuple]: if len(self.inlet_connections[0]) == 0: self.add_error("Unary operator objects must have an input.") # TODO(mhroth): there is no general consensus on how to handle incoming # and outgoing connections of different types, given the local let-type # definitions. if self.type == "cast_fi": x = HeavyIrObject(self.type) # is this correct? no idea what x is otherwise return ({HeavyIrObject("__cast~fi", {})}, self.get_connection_move_list(x)) elif self.type == "cast_if": x = HeavyIrObject(self.type) # is this correct? no idea what x is otherwise return ({HeavyIrObject("__cast~if", {})}, self.get_connection_move_list(x)) elif self.has_inlet_connection_format("f"): ir_type = f"__{self.type}~f" assert ir_type in HLangUnop.__HEAVY_DICT[self.type] x = HeavyIrObject(ir_type) return ({x}, self.get_connection_move_list(x, "~f>")) elif self.has_inlet_connection_format("i"): ir_type = f"__{self.type}~i" assert ir_type in HLangUnop.__HEAVY_DICT[self.type] x = HeavyIrObject(ir_type) return ({x}, self.get_connection_move_list(x, "~i>")) elif self.has_inlet_connection_format("c"): ir_type = f"__{self.type}" assert ir_type in HLangUnop.__HEAVY_DICT[self.type] x = HeavyIrObject(ir_type) return ({x}, self.get_connection_move_list(x, "-->")) else: self.add_error("Unknown inlet configuration.") return None hvcc-0.16.0/hvcc/core/hv2ir/HLangVar.py0000644000000000000000000000555700000000000014345 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangVar(HeavyLangObject): def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "var" super().__init__(obj_type, args, graph, annotations=annotations) def reduce(self) -> tuple: if self.has_inlet_connection_format("_") and self.has_outlet_connection_format("f"): x = HeavyIrObject("__var_k~f", self.args) elif self.has_inlet_connection_format("_") and self.has_outlet_connection_format("i"): x = HeavyIrObject("__var_k~i", self.args) elif self.has_inlet_connection_format(["_", "c"]) and self.has_outlet_connection_format("f"): x = HeavyIrObject("__var~f", self.args) x.id = self.id y = HeavyIrObject("__varread~f", {"var_id": self.id}) move_list = [] for c in [c for cc in self.inlet_connections for c in cc]: move_list.append((c, [c.copy(to_object=x)])) for c in [c for cc in self.outlet_connections for c in cc]: move_list.append((c, [c.copy(from_object=y)])) return ({x, y}, move_list) elif self.has_inlet_connection_format(["_", "c"]) and self.has_outlet_connection_format("i"): x = HeavyIrObject("__var~i", self.args) x.id = self.id y = HeavyIrObject("__varread~i", {"var_id": self.id}) move_list = [] for c in [c for cc in self.inlet_connections for c in cc]: move_list.append((c, [c.copy(to_object=x)])) for c in [c for cc in self.outlet_connections for c in cc]: move_list.append((c, [c.copy(from_object=y)])) return ({x, y}, move_list) elif self.has_inlet_connection_format(["_", "c"]) and self.has_outlet_connection_format(["_", "c"]): x = HeavyIrObject("__var", self.args) else: raise Exception() return ({x}, self.get_connection_move_list(x)) hvcc-0.16.0/hvcc/core/hv2ir/HLangVario.py0000644000000000000000000000505400000000000014665 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, Dict from .HeavyException import HeavyException from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HeavyGraph import HeavyGraph class HLangVario(HeavyLangObject): def __init__( self, obj_type: str, args: Dict, graph: 'HeavyGraph', annotations: Optional[Dict] = None ) -> None: assert obj_type == "vario" super().__init__(obj_type, args, graph, annotations=annotations) def reduce(self) -> Optional[tuple]: if self.graph is not None and self.name is not None: var_obj = self.graph.resolve_object_for_name(self.name, "var") if var_obj is None: raise HeavyException( f"No corresponding \"var\" object found for object {self} in file {self.graph.file}" ) if self.has_inlet_connection_format("f") and self.has_outlet_connection_format("_"): x = HeavyIrObject("__varwrite~f", {"var_id": var_obj.id}) return {x}, self.get_connection_move_list(x) elif self.has_inlet_connection_format("i") and self.has_outlet_connection_format("_"): x = HeavyIrObject("__varwrite~i", {"var_id": var_obj.id}) return {x}, self.get_connection_move_list(x) elif self.has_inlet_connection_format("_") and self.has_outlet_connection_format("f"): x = HeavyIrObject("__varread~f", {"var_id": var_obj.id}) return {x}, self.get_connection_move_list(x) elif self.has_inlet_connection_format("_") and self.has_outlet_connection_format("i"): x = HeavyIrObject("__varread~i", {"var_id": var_obj.id}) return {x}, self.get_connection_move_list(x) else: raise Exception() return None hvcc-0.16.0/hvcc/core/hv2ir/HeavyException.py0000644000000000000000000000210000000000000015613 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from hvcc.types.compiler import CompilerNotif class HeavyException(Exception): """ This exception is raised if anything goes wrong during the hv2ir compilation process. """ def __init__(self, message: str = "") -> None: super(Exception, self).__init__(message) self.message = message self.notes: CompilerNotif = CompilerNotif() hvcc-0.16.0/hvcc/core/hv2ir/HeavyGraph.py0000644000000000000000000012564600000000000014743 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import re from collections import Counter from typing import Optional, Union, Dict, List, Set, Tuple from pathlib import Path from .BufferPool import BufferPool from .Connection import Connection from .LocalVars import LocalVars from .HeavyException import HeavyException from .HeavyIrObject import HeavyIrObject from .HIrReceive import HIrReceive from .HeavyLangObject import HeavyLangObject from hvcc.types.compiler import CompilerNotif from hvcc.types.IR import ( IRObjectdict, IRGraph, IRName, IRInit, IRControl, IRReceiver, IRSendMessage, IROnMessage, IRSignalList, IRSignal, IRTable, IRNumTempBuffer, ) from hvcc.types.Lang import LangLetType class HeavyGraph(HeavyIrObject): """ Represents a graph. Subclasses HeavyIrObject for functionality. "__graph" does exist as a HeavyIR object, though it has no functionality and should not appear in any IR output. """ def __init__( self, graph: Optional['HeavyGraph'] = None, graph_args: Optional[Dict] = None, file: Path = Path(), xname: str = "heavy" ) -> None: # zero inlets and outlets until inlet/outlet objects are declared super().__init__("__graph", graph_args, graph, 0, 0) # the heavy file which defines this graph self.file = file # a user-defined name of this graph self.xname = xname # the dictionary of all objects in the graph self.objs: Dict = {} # set the local arguments if graph_args is not None: self.args = graph_args else: self.args = {} # initialise the local variables self.local_vars = LocalVars() # the list of all constituent inlet and outlet objects # graphs always start with no inlet/outlets self.inlet_objs: List = [] self.outlet_objs: List = [] # the set of input/output channels that this graph writes to self.input_channel_set: set = set() self.output_channel_set: set = set() # an ordered list of signal objects to process self.signal_order: List = [] # a pool of signal buffers for use during signal ordering and buffer assignment self.buffer_pool: Optional[BufferPool] = None def resolve_arguments(self, obj_args: Dict) -> Dict: """ Resolves the object arguments based on values from the local graph. """ args = dict(obj_args) # make a copy of the input arguments for key, value in args.items(): # do any of them reference a variable input? if isinstance(value, str): if value.find("$") > -1: # is there a value provided for that key in the graph arguments? for k in self.args: # replace all instances of $k with the argument value # do this for all keys in the graph's argument dictionary dollar_key = f"${k}" if value.find(dollar_key) > -1: if value == dollar_key: value = self.args[k] # maintain the original data type break # break because all dollar arguments have by definition been replaced else: # otherwise assume a string value value = value.replace(dollar_key, str(self.args[k])) # continue around the loop in case value has multiple dollar args if isinstance(value, str) and value.find("$") > -1: # if the variable cannot be resolved, leave it alone. # When the arguments are passed to the object, they will be # set to the default value. These unset variables are simply # removed from the argument dictionary args.pop(key, None) self.add_warning(f"Variable \"{key}\":\"{value}\" could not be resolved.") else: args[key] = value return args def connect_objects(self, c: Connection, require_intra_graph_connection: bool = True) -> None: """ Establish a connection from one object to another. Typically a connection must be made within a single graph, though this requirement may be subpressed. """ if require_intra_graph_connection: assert c.from_object.graph is c.to_object.graph, \ f"Conection established between two objects not in the same graph: {c}" # add the connection from the parent to the child c.from_object.add_connection(c) # add the connection to the child from the parent c.to_object.add_connection(c) def disconnect_objects(self, c: Connection) -> None: """ Remove a connection from one object to another. """ # remove the connection from the parent to the child c.from_object.remove_connection(c) # remove the connection to the child from the parent c.to_object.remove_connection(c) def update_connection(self, c: Connection, n_list: List) -> None: """ Update the old connection (c) with the new connections (n_list). Connection order is maintained. If c is None, this method acts as connect_objects(). If n is empty, this method acts as disconnect_objects(). """ if c is not None and len(n_list) > 0: if all([c.from_object is n.from_object for n in n_list]): # connections start at the same point c.from_object.replace_connection(c, n_list) c.to_object.remove_connection(c) for n in n_list: n.to_object.add_connection(n) elif all([c.to_object is n.to_object for n in n_list]): # connections end at the same point c.to_object.replace_connection(c, n_list) c.from_object.remove_connection(c) for n in n_list: n.from_object.add_connection(n) else: raise HeavyException(f"Connections must have a common endpoint: {c} / {n_list}") elif c is not None and len(n_list) == 0: self.disconnect_objects(c) # remove connection c elif c is None and len(n_list) > 0: for n in n_list: self.connect_objects(n) # add connection n def add_object( self, obj: HeavyIrObject, obj_id: Optional[Union[int, str]] = None ) -> None: """ Add an object to the graph based on the given id. Per-object bookkeeping is performed. """ obj_id = obj_id or obj.id if obj_id not in self.objs: obj.graph = self self.objs[obj_id] = obj # some object needs to be specially handled when added to the graph if obj.type in {"inlet", "__inlet"}: self.inlet_connections.append([]) self.inlet_buffers.append(("zero", 0)) self.inlet_objs.append(obj) # sort inlet objects according to their index, ascending self.inlet_objs.sort(key=lambda o: o.args["index"]) elif obj.type in {"outlet", "__outlet"}: self.outlet_connections.append([]) self.outlet_buffers.append(("zero", 0)) self.outlet_objs.append(obj) self.outlet_objs.sort(key=lambda o: o.args["index"]) elif obj.type in {"adc"}: self.input_channel_set.update(obj.args["channels"]) elif obj.type in {"dac"}: # if the object is a dac, keep track of the output channels # that this graph is writing to self.output_channel_set.update(obj.args["channels"]) elif obj.type in {"receive", "__receive", "send", "__send"}: self.__register_named_object(obj, obj.name) elif obj.type in {"table", "__table"}: self.__register_named_object( obj, obj.name, static=obj.static, unique=True) elif obj.type in {"var"} and obj.name is not None: self.__register_named_object( obj, obj.name, static=obj.static, unique=True) else: self.add_error(f"Duplicate object id {obj_id} found in graph.") def __register_named_object( self, obj: HeavyIrObject, name: Optional[str] = None, static: bool = False, unique: bool = False ) -> None: """ Register a named object at the appropriate graph level. """ name = name or obj.name if name is not None: if obj.scope == "private" and not static: # stay at this level self.local_vars.register_object(obj, name, static, unique) elif obj.scope == "protected": # go up one level g = self.graph if self.graph is not None else self g.local_vars.register_object(obj, name, static, unique) elif obj.scope == "public" or static: self.get_root_graph().local_vars.register_object(obj, name, static, unique) else: raise HeavyException(f"Unknown scope \"{obj.scope}\" for object {obj}.") else: raise HeavyException(f"Unknown scope \"{obj.scope}\" for object {obj}.") def __unregister_named_object( self, obj: HeavyIrObject, name: Optional[str] = None, static: bool = False, unique: bool = False ) -> None: """ Unregister a named object at the appropriate graph level. """ name = name or obj.name if name is not None: if obj.scope == "private" and not static: self.local_vars.unregister_object(obj, name) elif obj.scope == "protected": # go up one level g = self.graph if self.graph is not None else self g.local_vars.unregister_object(obj, name) elif obj.scope == "public" or static: self.get_root_graph().local_vars.unregister_object(obj, name) else: raise HeavyException(f"Unknown scope \"{obj.scope}\" for object {obj}.") else: raise HeavyException(f"Unknown scope \"{obj.scope}\" for object {obj}.") def resolve_objects_for_name( self, name: str, obj_types: Union[List, str], local_graph: Optional['HeavyGraph'] = None ) -> List: """ Returns all objects with the given name and type that are visible from this graph. Returns an empty list if no objects could be found. The results are otherwise ordered from most local/private first, and the most global last. """ obj_types = obj_types if isinstance(obj_types, list) else [obj_types] local_graph = local_graph or self obj_list = [o for o in self.local_vars.get_objects_for_name(name, obj_types) if not (o.scope == "private" and o.graph is not local_graph)] if self.graph is not None: obj_list_from_super_graph = self.graph.resolve_objects_for_name(name, obj_types, local_graph) obj_list.extend(obj_list_from_super_graph) return obj_list def resolve_object_for_name( self, name: str, obj_types: Union[List, str], local_graph: Optional['HeavyGraph'] = None ) -> Optional[HeavyIrObject]: """ Returns the first object with the given name and type that is visible from this graph. Returns None if no objects are available. This is a convenience method. """ objs = self.resolve_objects_for_name(name, obj_types, local_graph) return objs[0] if len(objs) > 0 else None def is_root_graph(self) -> bool: """ Returns true if this is the top-level (i.e. root) graph. False otherwise. """ return self.graph is None def get_root_graph(self) -> 'HeavyGraph': """Returns the top-level graph. """ if self.is_root_graph(): return self elif self.graph is not None: return self.graph.get_root_graph() else: # NOTE(dromer): we should never get here raise Exception def find_path_for_abstraction(self, obj_type: str) -> Optional[Path]: """ Travels up the graph heirarchy looking for a file path to an abstraction. Returns None if no abstraction is found. """ file_path = self.local_vars.find_path_for_abstraction(obj_type) if file_path is not None: return file_path else: return self.graph.find_path_for_abstraction(obj_type) if self.graph is not None else None def remove_object(self, o: HeavyIrObject, obj_id: Optional[str] = None) -> None: """ Removes an object and all of its connections from the graph. A custom id for the object to be removed can be given. """ for connections in o.inlet_connections: for c in list(connections): # make copy of connections as it will be mutated self.disconnect_objects(c) for connections in o.outlet_connections: for c in list(connections): # make copy self.disconnect_objects(c) for k, v in self.objs.items(): if o is v: del self.objs[k] break if o.type in {"receive", "__receive", "send", "__send"}: self.__unregister_named_object(o, o.name) def get_inlet_object(self, index: int) -> HeavyIrObject: """ Returns the indexed inlet object of this graph. """ return self.inlet_objs[index] def get_outlet_object(self, index: int) -> HeavyIrObject: """ Returns the indexed outlet object of this graph. """ return self.outlet_objs[index] def get_input_channel_set(self, recursive: bool = False) -> set: """ Returns the set of input channels that this graph writes to. Optionally includes all subgraphs as well. """ if recursive: channels = set(self.input_channel_set) # copy the output channel set for o in [o for o in self.objs.values() if o.type == "__graph"]: channels.update(o.get_input_channel_set(recursive=True)) return channels else: return self.input_channel_set def get_output_channel_set(self, recursive: bool = False) -> set: """ Returns the set of output channels that this graph writes to. Optionally includes all subgraphs as well. """ if recursive: channels = set(self.output_channel_set) # copy the output channel set for o in [o for o in self.objs.values() if o.type == "__graph"]: channels.update(o.get_output_channel_set(recursive=True)) return channels else: return self.output_channel_set def get_notices(self) -> CompilerNotif: notices = HeavyLangObject.get_notices(self) for o in self.objs.values(): n = o.get_notices() notices.warnings.extend(n.warnings) notices.errors.extend(n.errors) return notices def get_objects_for_type(self, obj_type: str, recursive: bool = False) -> List: """ Returns a list of all objects of a given type in this graph. The optional parameter "recursive" also includes all objects from subgraphs. """ obj_list = [] for o in self.objs.values(): if o.type == "__graph" and recursive: obj_list.extend(o.get_objects_for_type(obj_type, recursive)) elif o.type == obj_type: obj_list.append(o) return obj_list def get_object_counter(self, recursive: bool = False) -> Counter: """ Returns a counter of all object types in this graph. Graph objects are explicitly removed. "__inlet" and "__outlet" objects are renamed to "inlet" and "outlet", for clarity. An optional recursive argument includes all subgraphs. """ c: Counter = Counter() for o in self.objs.values(): if o.type == "__graph" and recursive: c += o.get_object_counter(recursive=True) elif o.type in {"__inlet", "__outlet"}: c[o.type[2:]] += 1 # remove leading "__" else: c[o.type] += 1 return c def prepare(self) -> None: """ Prepares a graph to be exported. Must be called from a root graph. """ assert self.is_root_graph() try: # apply graph transformations when all graphs have been read # All transformations must be recursive. # resolve all connection types such that all HeavyLang objects can # be correctly reduced self._resolve_connection_types() # TODO(mhroth): prune unnecessary objects and connections # All unnecessary objects and connections should be removed before the # graph is reduced. Reduction generally takes into account the existence # of connections when deciding on what HeavyIR objects to used. self._remove_unused_inlet_connections() # reconnect all send~/receive~ objects and remove them from the graph self.remap_send_receive() # now that the basic graph has been constructed, # objects are reduced to their well-defined low-level types. # Some objects may be replaced by graphs containing only low-level objects. # The graph is changed in-place and consists of only low-level # objects and subgraphs. All invalid connections are pruned. self.reduce() # +~~ expansion # ensures that there is at most one signal connection at any inlet self.cascade_expansion() # fma replacement # convert [__mul~f ~f> __add~f] into [__fma~f] self.fma_replacement() # group all control receivers with the same name under one logical receiver self.group_control_receivers() # assign signal buffers to signal objects # Buffer assignment only takes place at the very end, # and does so recursively over all objects and subgraphs. # All objects are ordered before buffers are assigned. self.assign_signal_buffers() except HeavyException as e: e.notes = self.get_notices() e.notes.has_error = True e.notes.exception = e raise e def _remove_unused_inlet_connections(self) -> None: """ Remove connections from inlet object, if there are no incoming connections to it. This is a basic approach to pruning unused or unnecessary connections, which allow further optimisation later in the pipeline. """ for i, cc in enumerate(self.inlet_connections): if len(cc) == 0: # make copy of outlet_connections list because it will be changed for c in list(self.inlet_objs[i].outlet_connections[0]): self.disconnect_objects(c) # the recursive bit for o in [o for o in self.objs.values() if (o.type == "__graph")]: o._remove_unused_inlet_connections() def _resolved_outlet_type(self, outlet_index: int = 0) -> LangLetType: # a graph's outlet type depends on the connections incident on the # corresponding outlet object connection_type_set = {c.type for c in self.outlet_objs[outlet_index].inlet_connections[0]} if len(connection_type_set) == 0: return "-->" # object has no incident connections, default to --> elif len(connection_type_set) == 1: return list(connection_type_set)[0] else: raise HeavyException(f"{self} has multiple incident connections of differing type.\ The outlet type cannot be explicitly resolved.") def _resolve_connection_types(self, obj_stack: Optional[set] = None) -> None: """ Resolves the type of all connections before reduction to IR object types. If connections incident on an object are incompatible, they are either resolved, potentially by inserting conversion objects, or pruned. If a viable resolution cannot be found, an exception may be raised. """ obj_stack = obj_stack or set() if self in obj_stack: return # ensure that each object is only resolved once (no infinite loops) else: obj_stack.add(self) # start from all roots and resolve all connections downwards for o in [o for o in self.objs.values() if o.is_root()]: o._resolve_connection_types(obj_stack) # when all internal connections have been resolved, # continue the recursion and resolve all outgoing connections for c in [c for cc in self.outlet_connections for c in cc]: if c.is_mixed: # resolve connection type and update it connection_type = self._resolved_outlet_type(c.outlet_index) self.update_connection(c, [c.copy(type=connection_type)]) c.to_object._resolve_connection_types(obj_stack) # turtle on down def remap_send_receive(self) -> None: """ Recursively finds all signal send/receive objects and for each unique send name, get all of the sends, and all of the corresponding receives. Reconnect all incoming connections to a __add~f, and fan out the results to all of receivers' connections. At most one __add~f must be added, and a lot of connections remapped. """ sends_dict = self.local_vars.get_registered_objects_for_type("send") receives_dict = self.local_vars.get_registered_objects_for_type("receive") for (name, send_objs) in sends_dict.items(): # unconnected send/receives will be removed in the reduce step, # if necessary (depending on control or signal functionality). # All signal sends will also be removed, regardless of whether they # have corresponding receives or not. So here we really only need to # be concerned with connecting "normal" signal send/receives. # get all signal sends for a name s_list = [o for o in send_objs if o.has_inlet_connection_format("f")] # assume that all similarly named receives will also be signal format r_list = [o for o in receives_dict[name]] if len(s_list) == 0: continue # there are no signals going into this send elif len(s_list) == 1: s = s_list[0] c = s.inlet_connections[0][0] # the connection ir_var = HeavyIrObject("__var~f") ir_varset = HeavyIrObject("__varwrite~f", {"var_id": ir_var.id}) s.graph.add_object(ir_var) s.graph.add_object(ir_varset) # move all connection to send object, to ir_varset for c in list(s.inlet_connections[0]): s.graph.update_connection(c, [c.copy(to_object=ir_varset)]) # move connections from receivers, to be from __var~f for o in r_list: ir_varread = HeavyIrObject("__varread~f", {"var_id": ir_var.id}) o.graph.add_object(ir_varread) for x in list(o.outlet_connections[0]): o.graph.update_connection(x, [x.copy(from_object=ir_varread)]) else: ir_vars = [HeavyIrObject("__var~f") for s in s_list] for i, o in enumerate(s_list): ir_varset = HeavyIrObject("__varwrite~f", {"var_id": ir_vars[i].id}) o.graph.add_object(ir_vars[i]) o.graph.add_object(ir_varset) for c in list(o.inlet_connections[0]): o.graph.update_connection(c, [c.copy(to_object=ir_varset, inlet_index=0)]) for r in r_list: ir_add = HeavyIrObject("__add~f") r.graph.add_object(ir_add) for i, s in enumerate(s_list): ir_varread = HeavyIrObject("__varread~f", {"var_id": ir_vars[i].id}) r.graph.add_object(ir_varread) r.graph.connect_objects(Connection( from_object=ir_varread, outlet_index=0, to_object=ir_add, inlet_index=(0 if i == 0 else 1), conn_type="~f>" )) for c in list(r.outlet_connections[0]): r.graph.update_connection(c, [c.copy(from_object=ir_add)]) # when all is said and done, remove the send and receive objects for o in s_list: o.graph.remove_object(o) for o in r_list: o.graph.remove_object(o) def reduce(self) -> Tuple[Set, List]: """ Breaks this object into low-level objects. This method returns either the object that it is called on, or a graph. In case of a graph, it contains only low-level objects. Unnecessary connections are pruned. Because this method is called on graphs while they are being constructed, returned graphs contains no sub-graphs. Thus this method does not process subgraphs. """ # refactor all constituent objects for (obj_id, o) in self.objs.copy().items(): # use items and not iteritems so that object dictionary remains mutable # break the object into atomic (i.e. low-level) objects and # update connections. Replace the new representation with the old # one in the graph. objects, connections = o.reduce() # if x is the original object (the case with low-level objects), # then no change must be made if (len(objects) == 1) and (o in objects): continue # add the new objects for x in objects: self.add_object(x) # replace existing connections # control connection order is maintained for c in connections: # c is a tuple containing the old and new connections # the new connection is a possibly empty list of new connections, # indicating that there is no replacement self.update_connection(c[0], c[1]) # remove the old object (and any remaining connections) from the graph self.remove_object(o, obj_id=obj_id) # o.id may not be the same as obj_id if the object comes from an abstraction # a graph is reduced in-place and does not change any connections return ({self}, []) def cascade_expansion(self) -> None: """ Turns implicit +~ into explicit cascading +~ trees. It is assumed that this simplification operation is run on a reduced graph. """ for o in self.objs.copy().values(): # all items in the graph for i in range(len(o.inlet_connections)): # for each inlet # if there is more than one signal connection # get all of the signal connections to an object at this inlet cc = [c for c in o.inlet_connections[i] if c.is_signal] if len(cc) > 1: oL = HeavyIrObject("__add~f") self.add_object(oL) self.update_connection( cc[0], [Connection.copy(cc[0], to_object=oL, inlet_index=0)]) self.update_connection( cc[1], [Connection.copy(cc[1], to_object=oL, inlet_index=1)]) for j in range(2, len(cc)): x = HeavyIrObject("__add~f") self.add_object(x) self.connect_objects(Connection( from_object=oL, outlet_index=0, to_object=x, inlet_index=0, conn_type="~f>")) self.update_connection( cc[j], [Connection.copy(cc[j], to_object=x, inlet_index=1)]) oL = x # add a connection from the last +~ to this inlet self.connect_objects(Connection( from_object=oL, outlet_index=0, to_object=o, inlet_index=i, conn_type="~f>")) if o.type == "__graph": o.cascade_expansion() def fma_replacement(self) -> None: """ Replace: [__mul~f] ~f> [__add~f] with [__fma~f] or [__mul~f] ~f> [__sub~f] with [__fms~f] """ # for all __mul~f objects for o in self.objs.copy().values(): if o.type == "__mul~f" \ and len(o.inlet_connections[0]) == 1 \ and len(o.inlet_connections[1]) == 1 \ and len(o.outlet_connections[0]) == 1 \ and (o.outlet_connections[0][0].to_object.type == "__add~f" or (o.outlet_connections[0][0].to_object.type == "__sub~f" and o.outlet_connections[0][0].inlet_index == 0)) \ and len(o.outlet_connections[0][0].to_object.inlet_connections[0]) == 1 \ and len(o.outlet_connections[0][0].to_object.inlet_connections[1]) == 1 \ and len(o.outlet_connections[0][0].to_object.outlet_connections[0]) > 0: fma_type = "__fma~f" if o.outlet_connections[0][0].to_object.type == "__add~f" else "__fms~f" fma = HeavyIrObject(fma_type) self.add_object(fma) # move connection to left inlet of fma~ c = o.inlet_connections[0][0] self.update_connection(c, [c.copy(to_object=fma)]) # move connection to right inlet of fma~ c = o.inlet_connections[1][0] self.update_connection(c, [c.copy(to_object=fma)]) o_add = o.outlet_connections[0][0].to_object # move connection to third inlet of fma~ from +~ (not connected to *~) i = o.outlet_connections[0][0].inlet_index # i is either 0 or 1 # i ^ 1 # use the other inlet; 0 > 1, 1 > 0 c = o_add.inlet_connections[i ^ 1][0] self.update_connection(c, [c.copy(to_object=fma, inlet_index=2)]) # move all +~ outlet connections to fma~ outlet for c in o_add.outlet_connections[0]: self.connect_objects(c.copy(from_object=fma)) # remove old *~ and +~ objects from the graph # (along with any remaining connections) o.graph.remove_object(o) # *~ o_add.graph.remove_object(o_add) # +~ elif o.type == "__graph": o.fma_replacement() # recurse through all subgraphs def group_control_receivers(self) -> None: """ Group all control receivers with the same name under one receiver with that name. This way only one message must be scheduled to hit all receivers. """ for name, receivers in self.local_vars.get_registered_objects_for_type("__receive").items(): # ensure that all receiver arguments are consistent extern = list(set([r.args["extern"] for r in receivers]) - set([None])) attributes = [r.args["attributes"] for r in receivers if len(r.args["attributes"]) > 0] scope = list(set([r.annotations["scope"] for r in receivers])) if len(extern) > 1: self.add_error(f"Parameter \"{name}\" has conflicting extern types: {extern[0]} != {extern[1]}") # NOTE(mhroth): not checking for conflicting scope types right now. Not sure what to do with it. if not all(attributes[0] == a for a in attributes): self.add_error(f"Conflicting min/max/default values for parameter \"{name}\"") # create a new receiver recv = HIrReceive("__receive", args={ "name": name, "extern": extern[0] if len(extern) > 0 else None, "attributes": attributes[0] if len(attributes) > 0 else {}, }, annotations={"scope": scope[0]}) # add new receiver to the top level graph self.add_object(recv) # sort receivers by priority receivers.sort(key=lambda x: x.args["priority"], reverse=True) # move all connections to new receiver for r in receivers: for c in r.outlet_connections[0]: self.connect_objects(c.copy(from_object=recv), require_intra_graph_connection=False) # remove old receivers for r in receivers: r.graph.remove_object(r) @property def does_process_signal(self) -> bool: # this graph processes a signal if it contains any adc~ (__inlet # objects with index > 127) return any(o.does_process_signal for o in self.objs.values()) or \ any(o.args["index"] > 127 for o in self.inlet_objs) def order_signal_objects(self) -> None: """ Places the signal objects in the correct order to be processed. Only the objects in this graph are ordered, stopping at the inlet objects. """ # for all leaves of graph, get the parent objects and combine the lists self.signal_order = [] # ordered objects for o in [o for o in self.objs.values() if o.is_leaf()]: self.signal_order.extend(o.get_parent_order()) # retain only objects that process a signal self.signal_order = [o for o in self.signal_order if o.does_process_signal] def assign_signal_buffers(self, buffer_pool: Optional[BufferPool] = None) -> None: # the top-level graph owns the buffer pool if buffer_pool is not None: self.buffer_pool = buffer_pool else: self.buffer_pool = BufferPool() # before signal buffers can be assigned, the objects must be ordered self.order_signal_objects() for c_list in self.inlet_connections: c_list = [c for c in c_list if c.is_signal] # only consider signal connections to inlet if len(c_list) == 0: continue # no connections at this inlet, it already contains the zero buffer if len(c_list) == 1: c = c_list[0] # get the connection # get the buffer at the outlet of the connected object buf = c.from_object.outlet_buffers[c.outlet_index] # assign the buffer to the outlet of the corresponding inlet object inlet_obj = self.inlet_objs[c.inlet_index] inlet_obj.outlet_buffers[0] = buf # ensure that the retain count is accurately reflected by the inlet's connections # some inlets are mixed with both signal and control connections, count only the signal connections self.buffer_pool.retain_buffer(buf, len([c for c in inlet_obj.outlet_connections[0] if c.is_signal]) - 1) else: raise HeavyException( f"Object {inlet_obj} in graph {inlet_obj.graph.file} has {len(c_list)} (> 1) signal inputs.") # for all objects in the signal order for o in self.signal_order: o.assign_signal_buffers(self.buffer_pool) # assign the output buffers for i, outlet_obj in enumerate(self.outlet_objs): # only assign signal buffers to outlets that have incoming signal connections c_list = [c for c in outlet_obj.inlet_connections[0] if c.is_signal] if len(c_list) == 0: continue if len(c_list) == 1: c = c_list[0] # get the connection buf = c.from_object.outlet_buffers[c.outlet_index] self.outlet_buffers[i] = buf self.buffer_pool.retain_buffer(buf, len(self.outlet_connections[i]) - 1) else: raise HeavyException( f"Object {outlet_obj} in graph {outlet_obj.graph.file} has {len(c_list)} (> 1) signal inputs.") def __repr__(self) -> str: if self.xname is not None: # TODO(mhroth): does not handle nested subgraph return f"__graph.{self.id}({self.file.name}/{self.xname})" else: return f"__graph.{self.id}({self.file.name})" # # Intermediate Representation generators # def to_ir(self) -> Optional[IRGraph]: """ Returns Heavy intermediate representation. """ # the set of all input/output signal channels used by the graph input_channel_set = self.get_input_channel_set(recursive=True) output_channel_set = self.get_output_channel_set(recursive=True) if self.buffer_pool is not None: return IRGraph( name=IRName( escaped=re.sub(r"\W", "_", self.xname), display=self.xname ), objects=self.get_object_dict(), init=IRInit( order=self.get_ir_init_list() ), tables=self.get_ir_table_dict(), control=IRControl( receivers=self.get_ir_receiver_dict(), sendMessage=self.get_ir_control_list() ), signal=IRSignal( numInputBuffers=max(input_channel_set) if len(input_channel_set) > 0 else 0, numOutputBuffers=max(output_channel_set) if len(output_channel_set) > 0 else 0, numTemporaryBuffers=IRNumTempBuffer( float=self.buffer_pool.num_buffers("~f>"), integer=self.buffer_pool.num_buffers("~i>") ), processOrder=self.get_ir_signal_list() ) ) else: # we should never get here raise Exception def get_object_dict(self) -> Dict[str, IRObjectdict]: # d = {o.id: o.get_object_dict() for o in self.objs.values() if o.type not in # ["inlet", "__inlet", "outlet", "__outlet"]} d = {} for o in self.objs.values(): # NOTE(mhroth): a bit of a hack to remove unnecessary inlet and outlet ir objects if o.type not in ["inlet", "__inlet", "outlet", "__outlet"]: d.update(o.get_object_dict()) return d def get_ir_init_list(self) -> List[str]: """ Init list is returned with all signal objects at the front, in the order that they are processed. This is to reduce cache misses on the signal object state as the process function is executed. """ init_list = [x for o in self.objs.values() for x in o.get_ir_init_list()] signal_list = self.get_ir_signal_list() s_init_list = [x.id for x in signal_list if x.id in init_list] i_init_list = [o_id for o_id in init_list if o_id not in s_init_list] ordered_init_list = s_init_list + i_init_list # ordered_init_list = list(OrderedDict.fromkeys(s_init_list + i_init_list)) return ordered_init_list def get_ir_on_message(self, inlet_index: int = 0) -> List[IROnMessage]: # pass the method through the inlet object, but only follow control connections x = [] for c in self.inlet_objs[inlet_index].outlet_connections[0]: if c.is_control: x.extend(c.to_object.get_ir_on_message(c.inlet_index)) return x def get_ir_table_dict(self) -> Dict[str, IRTable]: """ Returns a dictionary of all publicly visible tables at the root graph and their ids. """ assert self.is_root_graph(), "This function should only be called from the root graph." d = self.local_vars.get_registered_objects_for_type("__table") # update(), because tables can be registered either as Heavy tables # or HeavyIr __tables. We need to be able to handle them both. d.update(self.local_vars.get_registered_objects_for_type("table")) e = {} for k, v in d.items(): # escape table key to be used as the value for code stubs key = (f"_{k}") if re.match(r"\d", k) else k if key not in e: e[key] = IRTable( id=v[0].id, display=k, hash=f"0x{HeavyLangObject.get_hash(k):X}", extern=v[0].args["extern"] ) return e def get_ir_control_list(self) -> List[IRSendMessage]: return [x for o in self.objs.values() for x in o.get_ir_control_list()] def get_ir_receiver_dict(self) -> Dict[str, IRReceiver]: # NOTE(mhroth): this code assumes that v is always an array of length 1, # as the grouping of control receivers should have grouped all same-named # receivers into one logical receiver. # NOTE(mhroth): a code-compatible name is only necessary for externed receivers return {((f"_{k}") if re.match(r"\d", k) else k): IRReceiver( display=k, hash=f"0x{HeavyLangObject.get_hash(k):X}", extern=v[0].args["extern"], attributes=v[0].args["attributes"], ids=[v[0].id] ) for k, v in self.local_vars.get_registered_objects_for_type("__receive").items()} def get_ir_signal_list(self) -> List[IRSignalList]: return [x for o in self.signal_order for x in o.get_ir_signal_list()] hvcc-0.16.0/hvcc/core/hv2ir/HeavyIrObject.py0000644000000000000000000002461400000000000015374 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import json from typing import Dict, List, Optional, TYPE_CHECKING from pathlib import Path from .Connection import Connection from .HeavyException import HeavyException from .HeavyLangObject import HeavyLangObject from .BufferPool import BufferPool from hvcc.types.IR import HeavyIRType, IRNode, IRObjectdict, IRSendMessage, IROnMessage, IRSignalList, IRBuffer from hvcc.types.Lang import LangLetType if TYPE_CHECKING: from .HeavyGraph import HeavyGraph class HeavyIrObject(HeavyLangObject): """ Intermediate Representation (IR) objects are atomic and have strictly defined interfaces and types. These are generally defined in the file heavy.ir.json. """ # load the HeavyIR object definitions with open(Path(Path(__file__).parent, "../json/heavy.ir.json"), "r") as f: __HEAVY_OBJS_IR_DICT = HeavyIRType(**json.load(f)).root def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional['HeavyGraph'] = None, num_inlets: int = -1, num_outlets: int = -1, annotations: Optional[Dict] = None ) -> None: # allow the number of inlets and outlets to be overridden num_inlets = (len(self.__HEAVY_OBJS_IR_DICT[obj_type].inlets) if num_inlets < 0 else num_inlets) num_outlets = (len(self.__HEAVY_OBJS_IR_DICT[obj_type].outlets) if num_outlets < 0 else num_outlets) super().__init__(obj_type, args, graph, num_inlets, num_outlets, annotations) # resolve arguments and fill in missing defaults for HeavyIR objects self.__resolve_default_ir_args() # the list of signal buffers at the inlets and outlets # these are filled in by HeavyGraph.assign_signal_buffers() self.inlet_buffers: list[tuple[str, int]] = [("zero", 0)] * self.num_inlets self.outlet_buffers: list[tuple[str, int]] = [("zero", 0)] * self.num_outlets # True if this object has already been ordered in the signal chain self.__is_ordered = False def __resolve_default_ir_args(self) -> None: """ Resolves missing default arguments. Also checks to make sure that all required arguments are present. """ if self.type in self.__HEAVY_OBJS_IR_DICT.keys(): for arg in self.__obj_desc.args: if arg.name not in self.args: # if a defined argument is not in the argument dictionary if not arg.required: # if the argument is not required, use the default self.args[arg.name] = arg.default else: self.add_error(f"Required argument \"{arg.name}\" not present for object {self}.") else: # enforce argument types. # if the default argument is null, don't worry about about the arg if arg.default is not None: self.args[arg.name] = self.force_arg_type( self.args[arg.name], arg.value_type, self.graph) @classmethod def is_ir(cls, obj_type: str) -> bool: """Returns true if the type is an IR object. False otherwise. """ return obj_type in cls.__HEAVY_OBJS_IR_DICT.keys() @property def does_process_signal(self) -> bool: """Returns True if this object processes a signal. False otherwise. """ return self.__obj_desc.ir.signal @property def __obj_desc(self) -> IRNode: """ Returns the original HeavyIR object description. """ return self.__HEAVY_OBJS_IR_DICT[self.type] def inlet_requires_signal(self, inlet_index: int = 0) -> bool: """ Returns True if the indexed inlet requires a signal connection. False otherwise. """ return self.__obj_desc.inlets[inlet_index] in {"~i>", "~f>"} def outlet_requires_signal(self, inlet_index: int = 0) -> bool: """ Returns True if the indexed outlet requires a signal connection. False otherwise. """ return self.__obj_desc.outlets[inlet_index] in {"~i>", "~f>"} def reduce(self) -> Optional[tuple]: # A Heavy IR object is already reduced. Returns itself and no connection changes. return ({self}, []) def get_parent_order(self) -> List: """ Returns a list of all objects in process order, with this object at the end. """ if self.__is_ordered: return [] else: self.__is_ordered = True if self.is_root(): return [self] else: order_list = [] for c in [c for inlet in self.inlet_connections for c in inlet]: order_list.extend(c.from_object.get_parent_order()) order_list.append(self) return order_list def assign_signal_buffers(self, buffer_pool: Optional[BufferPool]) -> None: if buffer_pool is not None: # assign the inlet buffers for cc in self.inlet_connections: cc = [c for c in cc if c.is_signal] # only need to deal with signal connections if len(cc) == 0: continue if len(cc) == 1: c: Connection = cc[0] # get the connection # get the buffer at the outlet of the connected object buf = c.from_object.outlet_buffers[c.outlet_index] # assign the buffer to the inlet of this object self.inlet_buffers[c.inlet_index] = buf # decrease the retain count of the buffer buffer_pool.release_buffer(buf) else: raise HeavyException(f"This object has {len(cc)} (> 1) signal inputs.") # assign the output buffers exclude_set: set = set() for i in range(self.num_outlets): # buffers are assigned even if the outlet has no connections. # The buffer will still be filled. However, if the buffer has already # been set (i.e. non-zero) (e.g. in the case of dac~), # then we skip this set connection_type = self._resolved_outlet_type(outlet_index=i) if Connection.is_signal_type(connection_type) and self.outlet_buffers[i][0] == "zero" \ and connection_type is not None: b = buffer_pool.get_buffer( connection_type, len(self.outlet_connections[i]), exclude_set) self.outlet_buffers[i] = b # if the buffer has no dependencies, make sure that it isn't reused # right away. All outlets should have independent buffers. if len(self.outlet_connections[i]) == 0: exclude_set.add(b) def _resolved_outlet_type(self, outlet_index: int = 0) -> Optional[LangLetType]: """ Returns the connection type at the given outlet. This information is always well-defined for IR objects. """ return self.__obj_desc.outlets[outlet_index] # # Intermediate Representation generators # def get_object_dict(self) -> Dict[str, IRObjectdict]: """ Returns a dictionary of all constituent low-level objects, indexed by id, including their arguments and type. """ return { self.id: IRObjectdict( args=self.args, type=self.type ) } def get_ir_init_list(self) -> List[str]: """ Returns a list of all object id for obejcts that need initialisation. """ return [self.id] if self.__obj_desc.ir.init else [] def get_ir_on_message(self, inlet_index: int = 0) -> List[IROnMessage]: """ Returns an array of dictionaries containing the information for the corresponding on_message call. """ return [IROnMessage( id=self.id, inletIndex=inlet_index )] def get_ir_control_list(self) -> List[IRSendMessage]: """ Returns the intermediate representation for object control functions. Basically, does sendMessage() need to be written? """ if self.__obj_desc.ir.control: on_message_list = [] for connections in self.outlet_connections: on_messages_let = [] # only look at control connections for c in [c for c in connections if c.is_control]: on_messages_let.extend(c.to_object.get_ir_on_message(c.inlet_index)) on_message_list.append(on_messages_let) return [IRSendMessage( id=self.id, onMessage=on_message_list )] else: return [] def get_ir_signal_list(self) -> List[IRSignalList]: """ Returns the intermediate representation for object process functions. Only outputs buffer information for lets that require a signal. """ # we assume that this method will only be called on signal objects assert self.__obj_desc.ir.signal return [IRSignalList( id=self.id, inputBuffers=[ IRBuffer(type=b[0], index=b[1]) for i, b in enumerate(self.inlet_buffers) if self.inlet_requires_signal(i) ], outputBuffers=[ IRBuffer(type=b[0], index=b[1]) for i, b in enumerate(self.outlet_buffers) if self.outlet_requires_signal(i) ] )] hvcc-0.16.0/hvcc/core/hv2ir/HeavyLangObject.py0000644000000000000000000004130600000000000015700 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import decimal import json import random import string from struct import unpack, pack from typing import Optional, Union, List, Dict, Any, TYPE_CHECKING from pathlib import Path from .Connection import Connection from .HeavyException import HeavyException from hvcc.types.compiler import CompilerMsg, CompilerNotif from hvcc.types.Lang import HeavyLangType, LangNode, LangLet, LangLetType, LangValueType if TYPE_CHECKING: from .HeavyGraph import HeavyGraph from .HeavyIrObject import HeavyIrObject class HeavyLangObject: """ This is the base Heavy object class. """ __RANDOM = random.Random() __ID_CHARS = string.ascii_letters + string.digits # load the Heavy object definitions with open(Path(Path(__file__).parent, "../json/heavy.lang.json"), "r") as f: _HEAVY_LANG_DICT = HeavyLangType(**json.load(f)).root def __init__( self, obj_type: str, args: Optional[Dict] = None, graph: Optional['HeavyGraph'] = None, num_inlets: int = -1, num_outlets: int = -1, annotations: Optional[Dict] = None ) -> None: # set the object type self.type = obj_type # generate a unique id for this object self.id = "".join(self.__RANDOM.choice(self.__ID_CHARS) for _ in range(8)) # assign the parent graph self.graph = graph # set local arguments self.args: Dict = args or {} # set local annotations self.annotations: Dict = annotations or {} # a list of locally generated warnings and errors (notifications) self.warnings: List[CompilerMsg] = [] self.errors: List[CompilerMsg] = [] # resolve arguments and fill in missing defaults for HeavyLang objects self.__resolve_default_lang_args() # the list of connections at each inlet num_inlets = num_inlets if num_inlets >= 0 else len(self._obj_desc.inlets) self.inlet_connections: List = [[] for _ in range(num_inlets)] # the list of connections at each outlet num_outlets = num_outlets if num_outlets >= 0 else len(self._obj_desc.outlets) self.outlet_connections: List = [[] for _ in range(num_outlets)] @property def scope(self) -> str: """ Returns the scope of this object, private by default. Scope may be public, protected, private. """ return self.annotations.get("scope", "private") @property def static(self) -> bool: """ Returns true of this object is marked as static. False by default. """ return self.annotations.get("static", False) @property def const(self) -> bool: """ Returns true of this object is marked as constant. False by default. """ return self.annotations.get("const", False) @property def name(self) -> Optional[str]: """ Returns the name of this object. Returns None if there is no name. """ return self.args.get("name", None) @property def _obj_desc(self) -> LangNode: """ Returns the HeavyLang object description. """ return self._HEAVY_LANG_DICT[self.type] def inlet_connection_type(self, index: int) -> LangLet: return self._obj_desc.inlets[index] def outlet_connection_type(self, index: int) -> LangLet: return self._obj_desc.outlets[index] def name_for_arg(self, index: int = 0) -> str: """ Returns the name of the argument at the given index. """ return self._obj_desc.args[index].name def add_warning(self, warning: str) -> None: """ Add a warning to this object. """ self.warnings.append(CompilerMsg(message=warning)) def add_error(self, error: str) -> None: """ Add an error to this object and raise an exception. """ self.errors.append(CompilerMsg(message=error)) raise HeavyException(error) def get_notices(self) -> CompilerNotif: """ Returns a dictionary of all warnings and errors at this object. """ return CompilerNotif( has_error=len(self.errors) > 0, warnings=[CompilerMsg(message=f"{self}: {n.message}") for n in self.warnings], errors=[CompilerMsg(message=f"{self}: {n.message}") for n in self.errors], ) @classmethod def force_arg_type( cls, value: LangValueType, value_type: Optional[str] = None, graph: Optional['HeavyGraph'] = None ) -> Any: """ Attempts to convert a value to a given value type. Raises an Exception otherwise. If the value_type is unknown and a graph is provided, a warning will be registered. """ if value_type == "float": try: return float(value) except Exception: raise Exception(f"Cannot convert argument \"{value}\" into float.") elif value_type == "int": return int(decimal.Decimal(value)) elif value_type == "string": return str(value) if value is not None else None elif value_type == "bool": if isinstance(value, str): return value.strip().lower() not in ["false", "f", "0"] else: return bool(value) elif value_type == "floatarray": if isinstance(value, list): return [float(v) for v in value] if isinstance(value, str): return [float(v) for v in value.split()] else: raise HeavyException(f"Cannot convert value to type floatarray: {value}") elif value_type == "intarray": if isinstance(value, list): return [int(v) for v in value] if isinstance(value, str): return [int(v) for v in value.split()] else: raise HeavyException(f"Cannot convert value to type intarray: {value}") elif value_type == "stringarray": if isinstance(value, list): return [str(v) for v in value] if isinstance(value, str): return [str(v) for v in value.split()] else: raise HeavyException(f"Cannot convert value to type stringarray: {value}") else: # NOTE(mhroth): if value_type is not a known type or None, that is # not necessarily an error. It may simply be that the value should # not be resolved to anything other than what it already is. # This happens most often with message objects. # if graph is not None: # graph.add_warning(f"Unknown value type \"{value_type}\" for value: {value}") return value def __resolve_default_lang_args(self) -> None: """ Resolves missing default arguments. Also checks to make sure that all required arguments are present. Does nothing if the object is IR. """ if self.type in self._HEAVY_LANG_DICT.keys(): for arg in self._obj_desc.args: if arg.name not in self.args: # if a defined argument is not in the argument dictionary if not arg.required: # if the argument is not required, use the default self.args[arg.name] = arg.default else: self.add_error(f"Required argument \"{arg.name}\" not present for object {self}.") else: # enforce argument types self.args[arg.name] = self.force_arg_type( self.args[arg.name], arg.value_type, self.graph) @property def num_inlets(self) -> int: return len(self.inlet_connections) @property def num_outlets(self) -> int: return len(self.outlet_connections) def add_connection(self, c: Connection) -> None: """ Add a connection to this object. """ try: if c.to_object is self: self.inlet_connections[c.inlet_index].append(c) elif c.from_object is self: self.outlet_connections[c.outlet_index].append(c) else: raise HeavyException(f"Connection {c} does not connect to this object {self}.") except Exception as exc: raise HeavyException(f"Connection {c} connects to out-of-range let: {exc}") def remove_connection(self, c: Connection) -> None: """ Remove a connection to this object. """ if c.to_object is self: self.inlet_connections[c.inlet_index].remove(c) elif c.from_object is self: self.outlet_connections[c.outlet_index].remove(c) else: raise HeavyException(f"Connection {c} does not connect to this object {self}.") def replace_connection(self, c: Connection, n_list: List) -> None: """ Replaces connection c with connection list n_list, maintaining connection order """ if c.from_object is self: cc = self.outlet_connections[c.outlet_index] # NOTE(mhroth): this will throw an exception if c does not exist # if a heavy object connects to itself, such as through a [t a] # or directly, there may be an error here, i = cc.index(c) self.outlet_connections[c.outlet_index] = cc[0:i] + n_list + cc[i + 1:] elif c.to_object is self: # connection order doesn't matter at the inlet self.inlet_connections[c.inlet_index].remove(c) self.inlet_connections[c.inlet_index].extend(n_list) else: raise HeavyException(f"Connections must have a common endpoint: {c} / {n_list}") def get_connection_move_list(self, o: 'HeavyIrObject', connection_type_filter: str = "-~>") -> List: """ Create a list of commands to move all connections from this object to the given object o. """ m = [] for c in [c for cc in self.inlet_connections for c in cc]: m.append((c, [c.copy(to_object=o)])) for c in [c for cc in self.outlet_connections for c in cc]: m.append((c, [c.copy(from_object=o)])) return m def _get_connection_format(self, connections_list: List) -> str: fmt = [] for cc in connections_list: s = {c.type for c in cc} if len(s) == 0: fmt.append("_") elif len(s) == 1: if "-->" in s: fmt.append("c") elif "~f>" in s: fmt.append("f") elif "~i>" in s: fmt.append("i") else: raise Exception(f"Unknown connection type in set {cc} in file {cc[0].from_object.graph.file}.") elif s in [{"~f>", "-->"}, {"~i>", "-->"}]: fmt.append("m") else: fmt.append("m") return "".join(fmt) def has_inlet_connection_format(self, fmts: Optional[Union[str, List]] = None) -> bool: """ Returns true if the object has given format at its inlets. """ fmts = fmts if isinstance(fmts, list) else [fmts] return self._get_connection_format(self.inlet_connections) in fmts def has_outlet_connection_format(self, fmts: Optional[Union[str, List]] = None) -> bool: """ Returns true if the object has given format at its outlets. Take either litteral or list as input. """ fmts = fmts if isinstance(fmts, list) else [fmts] return self._get_connection_format(self.outlet_connections) in fmts def is_leaf(self) -> bool: """ Returns True if this object is a leaf in the graph. False otherwise. """ return all(len(c) == 0 for c in self.outlet_connections) def is_root(self) -> bool: """ Returns True if this object is a root in the graph. False otherwise. """ return all(len(c) == 0 for c in self.inlet_connections) def _resolved_outlet_type(self, outlet_index: int = 0) -> Optional[LangLetType]: """ Returns the connection type expected at the given outlet. The result may be influenced by the state of the input connections. """ # get the defined connection type connection_type = self._obj_desc.outlets[outlet_index].connectionType if connection_type == "-~>" and self.graph is not None: # if the connection type is defined as mixed, # use the default approach to resolve it connection_type_set = {c.type for c in self.inlet_connections[0]} if len(connection_type_set) == 0: return "-->" elif len(connection_type_set) == 1: return list(connection_type_set)[0] elif len(connection_type_set) == 2: if {"-->", "~f>"} == connection_type_set: return "~f>" elif {"-->", "~i>"} == connection_type_set: return "~i>" # if the connection type cannot be resolved to a well-defined type self.graph.add_error("Connection type cannot be resolved." f"Unknown inlet connection type configuration: {connection_type_set}") else: return connection_type return None def _resolve_connection_types(self, obj_stack: Optional[set] = None) -> None: """ Resolves the type of all connections before reduction to IR object types. If connections incident on an object are incompatible, they are either resolved, potentially by inserting conversion objects, or pruned. If a viable resolution cannot be found, an exception may be raised. """ obj_stack = obj_stack or set() if self in obj_stack: return else: obj_stack.add(self) # for all outgoing connections if self.graph is not None: for c in [c for cc in self.outlet_connections for c in cc]: if c.is_mixed: connection_type = self._resolved_outlet_type(outlet_index=c.outlet_index) if connection_type == "-~>": self.graph.add_error("Cannot resolve connection type from -~>.") else: self.graph.update_connection(c, [c.copy(type=connection_type)]) c.to_object._resolve_connection_types(obj_stack) # turtle all the way down @classmethod def get_hash(cls, x: str) -> int: """ Compute the message element hash used by msg_getHash(). Returns a 32-bit integer. """ if isinstance(x, float) or isinstance(x, int): # interpret the float bytes as an unsigned integer return unpack("@I", pack("@f", float(x)))[0] elif x == "bang": return 0xFFFFFFFF elif isinstance(x, str): # this hash is based MurmurHash2 # http://en.wikipedia.org/wiki/MurmurHash # https://sites.google.com/site/murmurhash/ x = str(x) m = 0x5bd1e995 r = 24 h = len(x) i = 0 while i < len(x) & ~0x3: k = unpack("@I", bytes(x[i:i + 4], "utf-8"))[0] k = (k * m) & 0xFFFFFFFF k ^= k >> r k = (k * m) & 0xFFFFFFFF h = (h * m) & 0xFFFFFFFF h ^= k i += 4 n = len(x) & 0x3 x = x[i:i + n] if n >= 3: h ^= (ord(x[2]) << 16) & 0xFFFFFFFF if n >= 2: h ^= (ord(x[1]) << 8) & 0xFFFFFFFF if n >= 1: h ^= ord(x[0]) h = (h * m) & 0xFFFFFFFF h ^= h >> 13 h = (h * m) & 0xFFFFFFFF h ^= h >> 15 return h else: raise Exception("Message element hashes can only be computed for float and string types.") def __repr__(self) -> str: arg_str = " ".join([f"{k}:{o}" for (k, o) in self.args.items()]) return f"{self.type} {{{arg_str}}}" if len(arg_str) > 0 else self.type hvcc-0.16.0/hvcc/core/hv2ir/HeavyParser.py0000644000000000000000000002717000000000000015127 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import json import random from typing import Any, Dict, List, Optional, Set, Tuple from pathlib import Path from .HIrConvolution import HIrConvolution from .HIrExpr import HIrExpr from .HIrInlet import HIrInlet from .HIrLorenz import HIrLorenz from .HIrNam import HIrNam from .HIrOutlet import HIrOutlet from .HIrPack import HIrPack from .HIrSwitchcase import HIrSwitchcase from .HIrTabhead import HIrTabhead from .HIrTabread import HIrTabread from .HIrTabwrite import HIrTabwrite from .HLangAdc import HLangAdc from .HLangBinop import HLangBinop from .HLangBiquad import HLangBiquad from .HLangDac import HLangDac from .HLangDelay import HLangDelay # from .HLangIf import HLangIf # circular import. moved here from .HeavyException import HeavyException from .HeavyIrObject import HeavyIrObject from .HeavyLangObject import HeavyLangObject from .HLangLine import HLangLine from .HLangMessage import HLangMessage # from .HLangNoise import HLangNoise # circular import. moved here from .HLangPhasor import HLangPhasor from .HLangPrint import HLangPrint from .HLangReceive import HLangReceive from .HLangRandom import HLangRandom from .HLangSend import HLangSend from .HLangSequence import HLangSequence from .HLangSlice import HLangSlice from .HLangSystem import HLangSystem from .HLangTable import HLangTable from .HLangUnop import HLangUnop from .HLangVar import HLangVar from .HLangVario import HLangVario from .HeavyGraph import HeavyGraph from .Connection import Connection class HeavyParser: @classmethod def graph_from_file( cls, hv_file: Path, graph: Optional[HeavyGraph] = None, graph_args: Optional[Dict] = None, path_stack: Optional[set] = None, xname: Optional[str] = None ) -> HeavyGraph: """ Read a graph object from a file. @param graph The parent graph of this graph. @param graph_args The arguments to this graph, in the form of a completely resolved dictionary. @param path_stack The path_stack is the current stack of resolved abstractions. It prevents infinite recursion when reading many abstractions deep. """ # ensure that we have an absolute path to the hv_file hv_file = hv_file.expanduser().absolute() # copy the path stack such that no changes are made to the calling stack path_stack = path_stack or set() if hv_file in path_stack: raise HeavyException(f"Abstraction recursion detected. Rereading {hv_file} on stack {path_stack}.") else: path_stack.add(hv_file) # open and parse the heavy file with open(hv_file, "r") as f: json_heavy = json.load(f) return cls.graph_from_object(hv_file, json_heavy, path_stack, graph, graph_args, xname) @classmethod def graph_from_object( cls, hv_file: Path, json_heavy: Dict, path_stack: set, graph: Optional[HeavyGraph] = None, graph_args: Optional[Dict] = None, xname: Optional[str] = None ) -> HeavyGraph: """ Parse a graph object. @param graph The parent graph. @param graph_args The resolved arguments to this graph, in the form of a dictionary. @param hv_file The Heavy file where this graph can be found. """ # resolve default graph arguments graph_args = graph_args or {} for a in json_heavy["args"]: if a["name"] not in graph_args: if a["required"]: raise HeavyException(f"Required argument \"{a['name']}\" not present.") else: graph_args[a["name"]] = a["default"] else: # just to be safe, ensure that the argument type is correct graph_args[a["name"]] = HeavyLangObject.force_arg_type( graph_args[a["name"]], a["value_type"], graph=graph) # create a new graph subpatch_name = json_heavy.get("annotations", {}).get("name", xname) g = HeavyGraph(graph, graph_args, file=hv_file, xname=subpatch_name) # add the import paths to the global vars g.local_vars.add_import_paths(json_heavy.get("imports", [])) # add the file's relative directory to global vars g.local_vars.add_import_paths([hv_file.parent]) # instantiate all objects try: for obj_id, o in json_heavy["objects"].items(): if o["type"] == "comment": continue # first and foremost, ignore comment objects elif o["type"] == "graph": # inline HeavyGraph objects (i.e. subgraphs) # require a different set of initialisation arguments x: Any = cls.graph_from_object(hv_file, o, path_stack, g, g.args, xname) else: # resolve the arguments dictionary based on the graph args args = g.resolve_arguments(o["args"]) # before anything, search for an abstraction # in case we want to override default functionality # However, if we are in an abstraction that has the same # name as the type that we are looking for, don't recurse! abs_path = g.find_path_for_abstraction(o["type"]) if abs_path is not None and abs_path not in path_stack: x = cls.graph_from_file( hv_file=abs_path, graph=g, graph_args=args, path_stack=path_stack) # if we know how to handle this object type natively # either as a custom type or as a generic IR object elif HeavyParser.get_class_for_type(o["type"]) is not None: obj_cls = HeavyParser.get_class_for_type(o["type"]) x = obj_cls(o["type"], args, g, o.get("annotations", {})) # handle generic IR objects elif HeavyIrObject.is_ir(o["type"]): x = HeavyIrObject(o["type"], args, g, annotations=o.get("annotations", {})) # an object definition can't be found else: g.add_error(f"Object type \"{o['type']}\" cannot be found.") # note that add_error() raises an exception. So really, there is no continue. continue # add the new object to the graph's object dictionary g.add_object(x, obj_id) # parse all of the connections for c in json_heavy["connections"]: g.connect_objects(Connection( g.objs[c["from"]["id"]], c["from"]["outlet"], g.objs[c["to"]["id"]], c["to"]["inlet"], c["type"])) except HeavyException as e: if g.is_root_graph(): # add the notification dictionary at the top level e.notes = g.get_notices() e.notes.has_error = True e.notes.exception = e raise e if (g.graph is None) or (g.graph.file != g.file): # remove this graph from the stack when finished. # Subpatches should not remove themselves. path_stack.remove(g.file) return g @classmethod def get_class_for_type(cls, obj_type: str) -> Any: """ Returns the class which can handle the given object type. """ if HLangUnop.handles_type(obj_type): return HLangUnop elif HLangBinop.handles_type(obj_type): return HLangBinop elif obj_type in LANG_CLASS_DICT: return LANG_CLASS_DICT[obj_type] else: return None class HLangIf(HeavyLangObject): """ Translates HeavyLang object [if] to HeavyIR [if] or [if~]. """ def __init__( self, obj_type: str, args: Dict, graph: HeavyGraph, annotations: Optional[Dict] = None ) -> None: assert obj_type == "if" super().__init__("if", args, graph, num_inlets=2, num_outlets=2, annotations=annotations) def reduce(self) -> Tuple[Set, List]: if self.has_inlet_connection_format(["cc", "_c", "c_", "__"]): x = HeavyIrObject("__if", self.args) elif self.has_inlet_connection_format("ff"): # TODO(mhroth): implement this x = HeavyParser.graph_from_file(Path("./hvlib/if~f.hv.json")) elif self.has_inlet_connection_format("ii"): # TODO(mhroth): implement this x = HeavyParser.graph_from_file(Path("./hvlib/if~i.hv.json")) else: fmt = self._get_connection_format(self.inlet_connections) raise HeavyException(f"Unhandled connection configuration to object [if]: {fmt}") return ({x}, self.get_connection_move_list(x)) class HLangNoise(HeavyLangObject): """ Handles the HeavyLang "noise" object. """ def __init__( self, obj_type: str, args: Dict, graph: HeavyGraph, annotations: Optional[Dict] = None ) -> None: assert obj_type == "noise" super().__init__("noise", args, graph, num_inlets=1, num_outlets=1, annotations=annotations) def reduce(self) -> Tuple[Set, List]: seed = int(random.uniform(1, 2147483647)) # assign a random 32-bit seed noise_path = Path(Path(__file__).parent, "./hvlib/noise.hv.json") x = HeavyParser.graph_from_file(noise_path, graph_args={"seed": seed}) x.reduce() # TODO(mhroth): deal with control input return ({x}, self.get_connection_move_list(x)) # A list of all of the HeavyLang objects and the classes # that will translate them into HeavyIR objects. LANG_CLASS_DICT = { "__conv~f": HIrConvolution, "biquad": HLangBiquad, "if": HLangIf, "inlet": HIrInlet, "var": HLangVar, "vario": HLangVario, "outlet": HIrOutlet, "__lorenz~f": HIrLorenz, "print": HLangPrint, "sequence": HLangSequence, "adc": HLangAdc, "dac": HLangDac, "message": HLangMessage, "noise": HLangNoise, "system": HLangSystem, "phasor": HLangPhasor, "line": HLangLine, "__nam~f": HIrNam, "random": HLangRandom, "delay": HLangDelay, "table": HLangTable, "slice": HLangSlice, "__tabread~if": HIrTabread, "__tabread~f": HIrTabread, "__tabread_stoppable~f": HIrTabread, "__tabreadu~f": HIrTabread, "__tabread": HIrTabread, "__tabhead~f": HIrTabhead, "__tabhead": HIrTabhead, "__tabwrite~f": HIrTabwrite, "__tabwrite_stoppable~f": HIrTabwrite, "__tabwrite": HIrTabwrite, "receive": HLangReceive, "send": HLangSend, "__switchcase": HIrSwitchcase, "switchcase": HIrSwitchcase, "__pack": HIrPack, "__expr": HIrExpr, "__expr~": HIrExpr, } hvcc-0.16.0/hvcc/core/hv2ir/LocalVars.py0000644000000000000000000000760200000000000014562 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import os from collections import defaultdict from typing import Optional, Union, Dict, List from pathlib import Path from .HeavyException import HeavyException from .HeavyLangObject import HeavyLangObject class LocalVars: """ A set of scoped objects. """ def __init__(self, stdlib_dir: str = "./") -> None: # a dictionary of name-registered objects # the data structure is a list map # key is the name under which the object is registered, value is a # list of all objects who are registered with that name self.__REGISTERED_OBJ_DICT: Dict = defaultdict(list) # the list of globally declared paths self.declared_paths = [stdlib_dir] # initialise with the standard library directory def find_path_for_abstraction(self, name: str) -> Optional[Path]: # the file name based on the abstraction name file_name = f"{name}.hv.json" # iterate in order through the declared paths in order to find the file for d in self.declared_paths: file_path = Path(d, file_name) if file_path.exists(): return file_path # if a matching abstraction is found, return the path return None # otherwise return None def add_import_paths(self, path_list: List) -> None: """ Add import paths. Paths are expanded and made as explicit as possible. """ self.declared_paths.extend([os.path.abspath(os.path.expanduser(p)) for p in path_list]) def register_object(self, obj: HeavyLangObject, name: str, static: bool = False, unique: bool = False) -> None: """ Registers a named object. """ objs = self.get_objects_for_name(name, obj.type) if (unique and len(objs) > 0) or (static and len(objs) > 1): # if there is already a registered object of this type and the new # object is not declared as static, throw an error raise HeavyException(f"Object {obj} with name \"{name}\" already exists, " "and the new object is static or unique.") elif len(objs) == 1 and static: pass # the static object has already been registered, move on else: self.__REGISTERED_OBJ_DICT[name].append(obj) def unregister_object(self, obj: HeavyLangObject, name: str) -> None: """ Unregisters a named object. """ self.__REGISTERED_OBJ_DICT[name].remove(obj) def get_objects_for_name(self, name: str, obj_types: Union[str, List]) -> List: """ Returns a list of objects registered under a name in this scope. """ obj_types = obj_types if isinstance(obj_types, list) else [obj_types] return [o for o in self.__REGISTERED_OBJ_DICT[name] if o.type in obj_types] def get_registered_objects_for_type(self, obj_type: str) -> Dict: """ Returns a list-dictionary for all objects of the given type, indexed by name. """ d = defaultdict(list) for k, v in self.__REGISTERED_OBJ_DICT.items(): x = [o for o in v if o.type == obj_type] if len(x) > 0: # only return names that actually have associated objects d[k].extend(x) return d hvcc-0.16.0/hvcc/core/hv2ir/__init__.py0000644000000000000000000000000000000000000014414 0ustar00hvcc-0.16.0/hvcc/core/hv2ir/hv2ir.py0000644000000000000000000001207500000000000013726 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import argparse import json import os import time from typing import Optional from pathlib import Path from hvcc.core.hv2ir.HeavyException import HeavyException from hvcc.core.hv2ir.HeavyParser import HeavyParser from hvcc.types.compiler import CompilerResp, CompilerNotif, CompilerMsg class hv2ir: @classmethod def compile( cls, hv_file: Path, ir_file: Path, patch_name: Optional[str] = None, verbose: bool = False ) -> CompilerResp: """ Compiles a HeavyLang file into a HeavyIR file. Returns a tuple of compile time in seconds, a notification dictionary, and a heavy object counter. """ # keep track of the total compile time tick = time.time() hv_file = hv_file.expanduser().absolute() ir_file = ir_file.expanduser().absolute() try: # parse heavy file hv_graph = HeavyParser.graph_from_file(hv_file=hv_file, xname=patch_name) except HeavyException as e: return CompilerResp( stage="hv2ir", compile_time=time.time() - tick, notifs=CompilerNotif( has_error=True, exception=e, errors=[CompilerMsg(message=e.message)], warnings=[] ), in_file=hv_file, in_dir=hv_file.parent, out_file=ir_file, out_dir=ir_file.parent ) try: # get a counter of all heavy objects hv_counter = hv_graph.get_object_counter(recursive=True) # prepare the graph for exporting hv_graph.prepare() # ensure that the output directory exists if not ir_file.parent.exists(): os.makedirs(ir_file.parent) # generate Heavy.IR ir = hv_graph.to_ir() except HeavyException as e: return CompilerResp( stage="hv2ir", compile_time=time.time() - tick, notifs=CompilerNotif( has_error=True, exception=e, errors=[CompilerMsg(message=e.message)], warnings=[] ), in_file=hv_file, in_dir=hv_file.parent, out_file=ir_file, out_dir=ir_file.parent, obj_counter=hv_counter ) if ir is not None: # write the hv.ir file with open(ir_file, "w") as f: json.dump(ir.model_dump(), f, indent=4) if verbose and ir is not None: if len(ir.signal.processOrder) > 0: print("") print("=== Signal Order ===") for so in ir.signal.processOrder: o = ir.objects[so.id] if len(o.args) > 0: print("{0} {{{1}}}".format( o.type, " ".join([f"{k}:{v}" for k, v in o.args.items()]))) else: print(o.type) return CompilerResp( stage="hv2ir", compile_time=time.time() - tick, # record the total compile time notifs=hv_graph.get_notices(), in_file=hv_file, in_dir=hv_file.parent, out_file=ir_file, out_dir=ir_file.parent, obj_counter=hv_counter, ir=ir ) def main() -> None: parser = argparse.ArgumentParser( description="A C-language compiler for the Heavy audio programming language.") parser.add_argument( "hv_path", help="The patch to the top-level patch to compile.") parser.add_argument( "--hv_ir_path", default="./heavy.hv.ir.json", help="The output path of the hv.ir.json file.") parser.add_argument( "--name", default="heavy", help="") parser.add_argument("-v", "--verbose", action="count") args = parser.parse_args() d = hv2ir.compile( hv_file=args.hv_path, ir_file=args.hv_ir_path, patch_name=args.name, verbose=args.verbose) if args.verbose: print(f"Total hv2ir time: {(d.compile_time * 1000):.2f}ms") if __name__ == "__main__": main() hvcc-0.16.0/hvcc/core/json/heavy.ir.json0000644000000000000000000015160600000000000014665 0ustar00{ "__^": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__^_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__abs": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__neg~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 0.5, "sse": 0.5 }, "args": [ ] }, "__abs~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 0.5, "sse": 0.5 }, "args": [ ] }, "__abs~i": { "inlets": [ "~i>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~i>" ] }, "__acos": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__acosh": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__acosh~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__acos~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__add": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__add_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__add~f": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ "~f>", "~f>" ], "outlets": [ "~f>" ], "perf": { "avx": 3, "sse": 3 }, "args": [ ] }, "__add~i": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ "~i>", "~i>" ], "outlets": [ "~i>" ], "perf": { "avx": 2, "sse": 0.5 }, "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__and": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "int", "name": "k", "description": "constant", "required": false }] }, "__and_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "int", "name": "k", "description": "constant", "required": false }] }, "__and~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 0.5, "sse": 0.5 } }, "__andnot~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 0.5, "sse": 0.5 } }, "__asin": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__asinh": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__atan": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__atan2": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 1, "value_type": "float", "name": "y", "description": "", "required": false }] }, "__atan2_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "y", "description": "", "required": false }] }, "__atan2~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__atanh": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__bimod": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [ ] }, "__bimod_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__biquad_k~f": { "inlets": [ "~f>", "-->", "-->", "-->", "-->", "-->" ], "args": [{ "name": "ff0", "value_type": "float", "description": "", "default": 1, "required": false }, { "name": "ff1", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "ff2", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "fb1", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "fb2", "value_type": "float", "description": "", "default": 0, "required": false }], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "perf": { "avx": 30, "sse": 15 } }, "__biquad~f": { "inlets": [ "~f>", "~f>", "~f>", "~f>", "~f>", "~f>" ], "args": [ ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "perf": { } }, "__cast_b": { "inlets": [ "-->" ], "args": [ ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__cast_f": { "inlets": [ "-->" ], "args": [ ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__cast_s": { "inlets": [ "-->" ], "args": [ ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__cast~fi": { "args": [ ], "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~i>" ], "perf": { "avx": 1, "sse": 1 } }, "__cast~if": { "args": [ ], "inlets": [ "~i>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 1, "sse": 1 } }, "__ceil": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__ceil~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 1, "sse": 1 } }, "__conv~f": { "inlets": [ "~f>", "-->", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "name": "table", "value_type": "string", "description": "", "default": "", "required": true }, { "name": "size", "value_type": "float", "description": "", "default": 0, "required": true }], "perf": { "avx": 0, "sse": 0 } }, "__cos": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__cosh": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__cosh~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__cos~f": { "inlets": [ "~f>" ], "args": [ ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__cpole~f": { "inlets": [ "~f>", "~f>", "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>", "~f>" ], "args": [ ], "perf": { "avx": 143, "sse": 53 } }, "__del1~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 5, "sse": 2 } }, "__delay": { "inlets": [ "-->", "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "delay", "description": "The message delay in milliseconds.", "required": false }] }, "__div": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__div_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__div~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }], "perf": { "avx": 25, "sse": 25 } }, "__div~i": { "inlets": [ "~i>", "~i>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~i>" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__env~f": { "inlets": [ "~f>" ], "ir": { "control": true, "signal": true, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "windowSize", "value_type": "float", "description": "", "default": 1024, "required": false }, { "name": "period", "value_type": "float", "description": "", "default": 512, "required": false }], "perf": { "avx": 9, "sse": 9 } }, "__eq": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__eq_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__eq~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 3, "sse": 3 } }, "__exp": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__exc_or~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [], "perf": {} }, "__expr": { "inlets": [], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "expressions", "value_type": "stringarray", "description": "The expression to evaluate", "default": "", "required": true }, { "name": "num_inlets", "value_type": "int", "description": "Number of inlets for this instance", "default": "", "required": true }] }, "__expr~": { "inlets": [], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [{ "name": "expressions", "value_type": "stringarray", "description": "The expression to evaluate", "default": "", "required": true }, { "name": "num_inlets", "value_type": "int", "description": "Number of inlets for this instance", "default": "", "required": true }] }, "__floor": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [] }, "__floor~f": { "args": [ ], "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 5, "sse": 5 } }, "__fma~f": { "inlets": [ "~f>", "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 5, "sse": 5 }, "args": [ ] }, "__fms~f": { "inlets": [ "~f>", "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 5, "sse": 5 }, "args": [ ] }, "__gt": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__gt_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__gte": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__gte_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__gte~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 1, "sse": 1 } }, "__gt~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 1, "sse": 1 } }, "__if": { "args": [{ "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false }], "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->", "-->" ] }, "__inlet": { "inlets": [ ], "ir": { "control": false, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__intdiv": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 1, "required": false }] }, "__intdiv_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 1, "required": false }] }, "__line~f": { "inlets": [ "-->", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 5.5, "sse": 3.5 } }, "__log": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__log10": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__log2": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__log2~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ] }, "__logand": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__logand_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__logor": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__logor_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__lorenz~f": { "inlets": [ "~f>", "~f>", "~f>", "~f>", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>", "~f>", "~f>" ], "args": [{ "name": "x", "value_type": "float", "description": "Initial x output value", "default": 0, "required": false }, { "name": "y", "value_type": "float", "description": "Initial y output value", "default": 0, "required": false }, { "name": "z", "value_type": "float", "description": "Initial z output value", "default": 0, "required": false }] }, "__lt": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__lt_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__lte": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__lte_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__lt~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 1, "sse": 1 } }, "__lte~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 1, "sse": 1 } }, "__max": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__max_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__max~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 3, "sse": 3 } }, "__max~i": { "inlets": [ "~i>", "~i>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~i>" ], "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__message": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__min": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__min_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__min~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 3, "sse": 3 }, "args": [ ] }, "__min~i": { "inlets": [ "~i>", "~i>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~i>" ], "perf": { "sse": 0.5 }, "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__mul": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__mul_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__mul~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 5, "sse": 5 }, "args": [ ] }, "__mul~i": { "inlets": [ "~i>", "~i>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~i>" ], "perf": { "avx": 3, "sse": 1 }, "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__nam~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "name": "nam", "value_type": "string", "description": "path to NAM file", "default": "", "required": true }], "perf": {} }, "__nam_nano~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "name": "nam", "value_type": "string", "description": "path to NAM file", "default": "", "required": true }], "perf": {} }, "__nam_feather~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "name": "nam", "value_type": "string", "description": "path to NAM file", "default": "", "required": true }], "perf": {} }, "__nam_lite~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "name": "nam", "value_type": "string", "description": "path to NAM file", "default": "", "required": true }], "perf": {} }, "__nam_standard~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "name": "nam", "value_type": "string", "description": "path to NAM file", "default": "", "required": true }], "perf": {} }, "__neq": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__neq_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__neq~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 3, "sse": 3 } }, "__or": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "constant", "required": false }] }, "__or_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": 0, "value_type": "int", "name": "k", "description": "constant", "required": false }] }, "__or~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 1, "sse": 1 } }, "__outlet": { "inlets": [ "-->" ], "ir": { "control": false, "signal": false, "init": false }, "outlets": [ ] }, "__pack": { "inlets": [ ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "values", "value_type": "mixedarray", "description": "The preset values to this pack object.", "default": [0.0, 0.0], "required": false }] }, "__phasor_k~f": { "inlets": [ "-->", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "default": 440, "value_type": "float", "name": "frequency", "description": "", "required": false }, { "default": 0, "value_type": "float", "name": "phase", "description": "", "required": false }], "perf": { "avx": 13, "sse": 10 } }, "__phasor~f": { "inlets": [ "~f>", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 38, "sse": 26 } }, "__pow": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ] }, "__pow_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ] }, "__pow~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__print": { "inlets": [ "-->" ], "ir": { "control": false, "signal": false, "init": false }, "outlets": [ ] }, "__random": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "range", "value_type": "float", "description": "", "default": 2, "required": false }, { "name": "seed", "value_type": "float", "description": "", "default": 1, "required": false }] }, "__receive": { "inlets": [ ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__rpole~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 143, "sse": 53 } }, "__rsqrt~f": { "inlets": [ "~f>" ], "args": [ ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__samphold~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [ ], "perf": { "avx": 0, "sse": 3 } }, "__sample~f": { "inlets": [ "~f>", "-->" ], "ir": { "control": true, "signal": true, "init": true }, "outlets": [ "-->" ], "args": [ ], "perf": { "avx": 1, "sse": 1 } }, "__send": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ ], "args": [{ "name": "name", "value_type": "string", "description": "", "default": null, "required": true }, { "name": "hash", "value_type": "string", "description": "The 32-bit hash of the \"name\" argument in \"0x00000000\" format.", "default": null, "required": true }] }, "__shiftleft": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__shiftleft_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__shiftright": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__shiftright_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "int", "description": "", "default": 0, "required": false }] }, "__sin": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__sinh": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__sin~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__slice": { "description": "", "ir": { "control": true, "signal": false, "init": true }, "inlets": [ "-->", "-->", "-->" ], "outlets": [ "-->", "-->" ], "args": [{ "name": "index", "value_type": "float", "description": "The start index of the slice.", "default": 0, "required": false }, { "name": "length", "value_type": "float", "description": "The number of elements to include in the slice.", "default": 1, "required": false }], "alias": [ ], "tags": [ ] }, "__sqrt": { "inlets": [ "-->" ], "args": [ ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__sqrt~f": { "inlets": [ "~f>" ], "args": [ ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__sub": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__sub_k": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__sub~f": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ "~f>", "~f>" ], "outlets": [ "~f>" ], "perf": { "avx": 3, "sse": 3 } }, "__sub~i": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ "~i>", "~i>" ], "outlets": [ "~i>" ], "perf": { "avx": 3, "sse": 1 }, "args": [{ "name": "k", "value_type": "float", "description": "", "default": 0, "required": false }] }, "__switchcase": { "ir": { "control": true, "signal": false, "init": false }, "inlets": [ "-->" ], "outlets": [ ], "args": [{ "default": [ ], "value_type": "mixedarray", "name": "cases", "description": "", "required": false }] }, "__system": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__tabhead": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }] }, "__tabhead~f": { "inlets": [ "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 0.5, "sse": 0.5 } }, "__table": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "name", "value_type": "string", "description": "", "default": null, "required": true }, { "name": "size", "value_type": "int", "description": "The number of samples in this table.", "default": 0, "required": false }, { "name": "values", "value_type": "floatarray", "description": "The preset values in this table. The length of this list overrides the \"size\" argument.", "default": [ ], "required": false }] }, "__tabread": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "table", "value_type": "string", "description": "", "default": null, "required": true }] }, "__tabreadu~f": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": true, "init": true }, "outlets": [ "~f>", "-->" ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 2, "sse": 2 } }, "__tabread~f": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": true, "init": true }, "outlets": [ "~f>", "-->" ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 1, "sse": 1 } }, "__tabread_stoppable~f": { "inlets": [ "-->", "-->", "-->" ], "ir": { "control": true, "signal": true, "init": true }, "outlets": [ "~f>", "-->", "-->" ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 1, "sse": 1 } }, "__tabread~if": { "inlets": [ "~i>", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ "~f>" ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 4, "sse": 2 } }, "__tabwrite": { "inlets": [ "-->", "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "table", "value_type": "string", "description": "", "default": null, "required": true }] }, "__tabwrite_stoppable~f": { "inlets": [ "~f>", "-->", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 2, "sse": 2 } }, "__tabwrite~f": { "inlets": [ "~f>", "-->", "-->" ], "ir": { "control": false, "signal": true, "init": true }, "outlets": [ ], "args": [{ "default": null, "value_type": "string", "name": "table", "description": "The name of the table to reference.", "required": true }], "perf": { "avx": 1, "sse": 1 } }, "__tan": { "inlets": [ "-->" ], "args": [ ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ] }, "__tanh": { "inlets": [ "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__unimod": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [ ] }, "__unimod_k": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": false }, "outlets": [ "-->" ], "args": [ ] }, "__var": { "inlets": [ "-->", "-->" ], "ir": { "control": true, "signal": false, "init": true }, "outlets": [ "-->" ], "args": [{ "name": "k", "value_type": "auto", "description": "", "default": 0, "required": false }] }, "__var_k~f": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "The value of this variable.", "required": false }, { "default": 0, "value_type": "float", "name": "step", "description": "The value step increment.", "required": false }, { "default": false, "value_type": "boolean", "name": "reverse", "description": "True if the value and step increments should be reversed.", "required": false }], "outlets": [ "~f>" ], "keywords": [ ], "perf": { "avx": 0.5, "sse": 0.5 } }, "__var_k~i": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ ], "args": [{ "default": 0, "value_type": "int", "name": "k", "description": "The value of this variable.", "required": false }, { "default": 0, "value_type": "int", "name": "step", "description": "The value step increment.", "required": false }, { "default": false, "value_type": "boolean", "name": "reverse", "description": "True if the value and step increments should be reversed.", "required": false }], "outlets": [ "~i>" ], "keywords": [ ], "perf": { "avx": 0.5, "sse": 0.5 } }, "__varread~f": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ ], "args": [{ "default": null, "value_type": "string", "name": "var_id", "description": "The id the of the var object to read from.", "required": true }], "outlets": [ "~f>" ], "perf": { "avx": 1, "sse": 1 } }, "__varread~i": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ ], "args": [{ "default": null, "value_type": "string", "name": "var_id", "description": "The id the of the var object to read from.", "required": true }], "outlets": [ "~i>" ], "perf": { "avx": 1, "sse": 1 } }, "__varwrite~f": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ "~f>" ], "args": [{ "default": null, "value_type": "string", "name": "var_id", "description": "The id the of the var object to write to.", "required": true }], "outlets": [ ], "perf": { "avx": 1, "sse": 1 } }, "__varwrite~i": { "ir": { "control": false, "signal": true, "init": false }, "inlets": [ "~i>" ], "args": [{ "default": null, "value_type": "string", "name": "var_id", "description": "The id the of the var object to write to.", "required": true }], "outlets": [ ], "perf": { "avx": 1, "sse": 1 } }, "__var~f": { "ir": { "control": false, "signal": false, "init": true }, "inlets": [ "-->" ], "args": [{ "default": 0, "value_type": "float", "name": "k", "description": "The value of this variable.", "required": false }, { "default": 0, "value_type": "float", "name": "step", "description": "The value step increment.", "required": false }, { "default": false, "value_type": "boolean", "name": "reverse", "description": "True if the value and step increments should be reversed.", "required": false }], "outlets": [ "~f>" ], "keywords": [ "static" ], "perf": { "avx": 0, "sse": 0, "neon": 0 } }, "__var~i": { "ir": { "control": false, "signal": false, "init": true }, "inlets": [ "-->" ], "args": [{ "default": 0, "value_type": "int", "name": "k", "description": "The value of this variable.", "required": false }, { "default": 0, "value_type": "int", "name": "step", "description": "The value step increment.", "required": false }, { "default": false, "value_type": "boolean", "name": "reverse", "description": "True if the value and step increments should be reversed.", "required": false }], "outlets": [ "~i>" ], "perf": { "avx": 0, "sse": 0, "neon": 0 } }, "__asinh~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ] }, "__asin~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__atanh~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__atan~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__bit_and~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__bit_or~f": { "inlets": [ "~f>", "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__bit_not~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__bitsafe~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__exp~f": { "inlets": [ "~f>" ], "args": [], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "perf": { "avx": 0, "sse": 0, "neon": 0 } }, "__sinh~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ], "args": [ ] }, "__tanh~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] }, "__tan~f": { "inlets": [ "~f>" ], "ir": { "control": false, "signal": true, "init": false }, "outlets": [ "~f>" ] } } hvcc-0.16.0/hvcc/core/json/heavy.lang.json0000644000000000000000000012361100000000000015167 0ustar00{ "!=": { "description": "Output = (bool) (Input != k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "ne" ], "tags": [ "math", "logical" ] }, "%": { "description": "Output = Input % k", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 1, "required": false } ], "alias": [ "mod" ], "tags": [ "math", "logical" ] }, "&": { "description": "Binary AND operation.", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "int", "description": "constant", "default": 0, "required": false } ], "alias": [ "binaryand" ], "tags": [ "math", "bitwise" ] }, "&&": { "description": "Logical AND operation.", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "logicaland" ], "tags": [ "math", "logical" ] }, "*": { "description": "Output = Input * k", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "mult" ], "tags": [ "math", "arithmetic" ] }, "+": { "description": "Output = Input + k", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "add" ], "tags": [ "math", "arithmetic" ] }, "-": { "description": "Output = Input - k", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "sub" ], "tags": [ "math", "arithmetic" ] }, "/": { "description": "Output = Input / k", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 1, "required": false } ], "alias": [ "divide" ], "tags": [ "math", "arithmetic" ] }, "<": { "description": "Output = (bool) (Input < k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "lt" ], "tags": [ "math", "logical" ] }, "<<": { "description": "Output = (Input << k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "int", "description": "constant", "default": 0, "required": false } ], "alias": [ "leftshift" ], "tags": [ "math", "bitwise" ] }, "<=": { "description": "Output = (bool) (Input <= k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "lte" ], "tags": [ "math", "logical" ] }, "==": { "description": "Output = (bool) (Input == k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "eq" ], "tags": [ "math", "logical" ] }, ">": { "description": "Output = (bool) (Input > k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "gt" ], "tags": [ "math", "logical" ] }, ">=": { "description": "Output = (bool) (Input >= k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "gte" ], "tags": [ "math", "logical" ] }, ">>": { "description": "Output = (Input >> k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "int", "description": "constant", "default": 0, "required": false } ], "alias": [ "rightshift" ], "tags": [ "math", "bitwise" ] }, "^": { "description": "Output = (Input ^ k)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "xor" ], "tags": [ "math", "bitwise" ] }, "abs": { "description": "Output = abs(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math" ] }, "acos": { "description": "Output = acos(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "acosh": { "description": "Output = acosh(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "adc": { "description": "", "inlets": [ ], "outlets": [ { "name": "", "connectionType": "~f>", "description": "" } ], "args": [ { "name": "channels", "value_type": "intarray", "description": "Channels from input.", "default": [ 1, 2 ], "required": false } ], "alias": [ ], "tags": [ ] }, "asin": { "description": "Output = asin(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "asinh": { "description": "Output = asinh(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "atan": { "description": "Output = atan(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "atan2": { "description": "Output = atan2(x, y)", "inlets": [ { "name": "x", "connectionType": "-~>", "description": "Set x" }, { "name": "y", "connectionType": "-~>", "description": "Set y" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "y", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "atanh": { "description": "Output = atanh(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "biquad": { "description": "out = in[0]*x0 + in[-1]*x1 + in[-2]*x2 - out[-1]*y1 - out[-2]*y2", "inlets": [ { "name": "input", "connectionType": "~f>", "description": "Filter input." }, { "name": "x0", "connectionType": "-~>", "description": "" }, { "name": "x1", "connectionType": "-~>", "description": "" }, { "name": "x2", "connectionType": "-~>", "description": "" }, { "name": "y1", "connectionType": "-~>", "description": "" }, { "name": "y2", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "output", "connectionType": "~f>", "description": "Filter output." } ], "args": [ { "name": "ff0", "value_type": "float", "description": "", "default": 1, "required": false }, { "name": "ff1", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "ff2", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "fb1", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "fb2", "value_type": "float", "description": "", "default": 0, "required": false } ], "alias": [ ], "tags": [ "filters" ] }, "ceil": { "description": "", "inlets": [ { "name": "k", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "ceil(k)" } ], "args": [ ], "alias": [ ], "tags": [ ] }, "comment": { "description": "A text comment.", "inlets": [ ], "outlets": [ ], "args": [ { "name": "text", "value_type": "string", "description": "The comment string.", "default": null, "required": true }, { "name": "mime", "value_type": "string", "description": "The MIME type of this comment.", "default": "text/plain", "required": false } ], "alias": [ ], "tags": [ ] }, "cos": { "description": "Output = cos(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "dac": { "description": "", "inlets": [ { "name": "", "connectionType": "~f>", "description": "" } ], "outlets": [ ], "args": [ { "name": "channels", "value_type": "intarray", "description": "Channels to output.", "default": [ 1, 2 ], "required": false } ], "alias": [ ], "tags": [ ] }, "delay": { "description": "", "inlets": [ { "name": "message", "connectionType": "-->", "description": "The message to delay." }, { "name": "delay", "connectionType": "-->", "description": "The delay is milliseconds." } ], "outlets": [ { "name": "outlet", "connectionType": "-->", "description": "The delayed message." } ], "args": [ { "name": "delay", "value_type": "float", "description": "The message delay in milliseconds.", "default": 0, "required": false } ], "alias": [ ], "tags": [ ] }, "env~": { "description": "", "inlets": [ { "name": "", "connectionType": "~f>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "args": [ { "name": "windowSize", "value_type": "float", "description": "", "default": 1024, "required": false }, { "name": "period", "value_type": "float", "description": "", "default": 512, "required": false } ], "alias": [ "envelope" ], "tags": [ ] }, "exp": { "description": "Output = exp(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math" ] }, "floor": { "description": "", "inlets": [ { "name": "k", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "floor(k)" } ], "args": [ ], "alias": [ ], "tags": [ ] }, "graph": { "description": "", "inlets": [ ], "outlets": [ ], "args": [ ], "alias": [ ], "tags": [ ] }, "if": { "description": "Input to the first inlet is routed to the first outlet if k == 0, else it's routed to the second outlet.", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "k is False", "connectionType": "-~>", "description": "Output." }, { "name": "k is True", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ ], "tags": [ "sequencing" ] }, "inlet": { "description": "", "inlets": [ ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "args": [ { "name": "name", "value_type": "string", "description": "inlet name", "default": "", "required": false }, { "name": "index", "value_type": "int", "description": "Determines the inlet position within an abstraction/sub-graph", "default": 0, "required": true }, { "name": "type", "value_type": "string", "description": "Specifies the inlet connection type", "default": null, "required": true } ], "alias": [ ], "tags": [ ] }, "line": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" }, { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "args": [ ], "alias": [ ], "tags": [ ] }, "loadbang": { "description": "Triggers an event once the patch is initialised", "inlets": [ ], "outlets": [ { "name": "outlet", "connectionType": "-->", "description": "Bang output." } ], "args": [ { "name": "priority", "value_type": "int", "description": "Relative priority for when this loadbang should fire. Higher executes sooner.", "default": 0, "required": false } ], "alias": [ ], "tags": [ "sequencing" ] }, "log": { "description": "Output = round(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math" ] }, "log10": { "description": "Output = log10(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math" ] }, "log2": { "description": "Output = log2(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math" ] }, "max": { "description": "Finds the maximum of the two inputs.", "inlets": [ { "name": "", "connectionType": "-~>", "description": "" }, { "name": "", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ ], "tags": [ "math" ] }, "message": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "args": [ { "name": "local", "value_type": null, "description": "A list of message lists to send.", "default": null, "required": true }, { "name": "remote", "value_type": null, "description": "A list of message lists to send.", "default": [ ], "required": false } ], "alias": [ ], "tags": [ ] }, "min": { "description": "Finds the minimum of the two inputs.", "inlets": [ { "name": "", "connectionType": "-~>", "description": "" }, { "name": "", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ ], "tags": [ "math" ] }, "mod": { "description": "Output = Input % k, (always positive)", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 1, "required": false } ], "alias": [ ], "tags": [ "math", "arithmetic" ] }, "noise": { "description": "White noise signal generator.", "inlets": [ { "name": "seed", "connectionType": "-->", "description": "Currently unused." } ], "outlets": [ { "name": "Output", "connectionType": "~f>", "description": "White noise." } ], "args": [ { "name": "noise", "value_type": "string", "description": "The type of noise to produce. Currently only `uniform` is supported.", "default": "uniform", "required": false }, { "name": "seed", "value_type": "float", "description": "The seed for the random number generator (RNG).", "default": 0, "required": false } ], "alias": [ ], "tags": [ "~f>", "generators" ] }, "outlet": { "description": "", "inlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "outlets": [ ], "args": [ { "name": "name", "value_type": "string", "description": "outlet name", "default": "", "required": false }, { "name": "index", "value_type": "int", "description": "Determines the outlet position within an abstraction/sub-graph", "default": 0, "required": true }, { "name": "type", "value_type": "string", "description": "specifies the outlet connection type", "default": null, "required": true } ], "alias": [ ], "tags": [ ] }, "phasor": { "description": "", "inlets": [ { "name": "frequency", "connectionType": "-~>", "description": "" }, { "name": "phase", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "~f>", "connectionType": "~f>", "description": "" } ], "args": [ { "name": "frequency", "value_type": "float", "description": "", "default": 0, "required": false }, { "name": "phase", "value_type": "float", "description": "", "default": 0, "required": false } ], "alias": [ ], "tags": [ ] }, "pow": { "description": "Output = pow(Input, k)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" }, { "name": "constant", "connectionType": "-~>", "description": "set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ ], "tags": [ "math" ] }, "print": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ ], "args": [ { "name": "label", "value_type": "string", "description": "", "default": "print", "required": false } ], "alias": [ ], "tags": [ "debugging" ] }, "random": { "description": "Random number generator", "inlets": [ { "name": "trigger", "connectionType": "-->", "description": "Outputs random number when triggered." }, { "name": "range", "connectionType": "-->", "description": "Generated number will be in the range [0.0, 1.0)." } ], "outlets": [ { "name": "outlet", "connectionType": "-->", "description": "Output." } ], "args": [ { "name": "seed", "value_type": "int", "description": "seed", "default": -1, "required": false } ], "alias": [ ], "tags": [ "math" ] }, "receive": { "description": "", "inlets": [ ], "outlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "args": [ { "name": "name", "value_type": "string", "description": "The name of this receiver.", "default": null, "required": true }, { "name": "priority", "value_type": "int", "description": "Higher priority receivers will be executed first.", "default": 0, "required": false }, { "name": "extern", "value_type": "string", "description": "If the receiver should be exposed to external (user) interfaces, 'param' or 'event'.", "default": null, "required": false }, { "name": "attributes", "value_type": "dict", "description": "Variable argument information depending on the extern type.", "default": {}, "required": false } ], "alias": [ "r" ], "tags": [ ] }, "send": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ ], "args": [ { "name": "name", "value_type": "string", "description": "", "default": null, "required": true } ], "alias": [ "s" ], "tags": [ ] }, "sequence": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "value", "connectionType": "-->", "description": "" } ], "args": [ { "name": "casts", "value_type": "stringarray", "description": "Sequence and cast types.", "default": null, "required": true } ], "alias": [ "seq" ], "tags": [ "sequencing" ] }, "sin": { "description": "Output = sin(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "sinh": { "description": "Output = sinh(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "slice": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" }, { "name": "", "connectionType": "-->", "description": "" }, { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-->", "description": "The sliced output." }, { "name": "", "connectionType": "-->", "description": "If no slice is possible, a bang is emitted." } ], "args": [ { "name": "index", "value_type": "int", "description": "The start index of the slice.", "default": 0, "required": false }, { "name": "length", "value_type": "int", "description": "The number of elements to include in the slice.", "default": 1, "required": false } ], "alias": [ ], "tags": [ ] }, "sqrt": { "description": "Output = sqrt(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math" ] }, "system": { "description": "Returns system properties such as samplerate or block size.", "inlets": [ { "name": "parameter", "connectionType": "-->", "description": "The requested system parameter." } ], "outlets": [ { "name": "value", "connectionType": "-->", "description": "The system parameter value." } ], "args": [ ], "alias": [ ], "tags": [ ] }, "table": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "args": [ { "name": "name", "value_type": "string", "description": "", "default": null, "required": true }, { "name": "size", "value_type": "int", "description": "The number of samples in this table.", "default": 256, "required": false }, { "name": "values", "value_type": "floatarray", "description": "The preset values in this table. The length of this list overrides the \"size\" argument.", "default": [], "required": false }, { "name": "extern", "value_type": "bool", "description": "Determines if the table should be publicly exposed in a framework.", "default": false, "required": false } ], "alias": [ ], "tags": [ ] }, "tabread": { "description": "", "inlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "output = table[input]" }, { "name": "", "connectionType": "-~>", "description": "output = table[input+1]" } ], "args": [ { "name": "table", "value_type": "string", "description": "The name of the table to read from.", "default": null, "required": true }, { "name": "delay", "value_type": "float", "description": "", "default": 0, "required": false } ], "alias": [ ], "tags": [ ] }, "tabwrite": { "description": "", "inlets": [ { "name": "", "connectionType": "-->", "description": "" } ], "outlets": [ { "name": "", "connectionType": "~f>", "description": "" } ], "args": [ { "name": "name", "value_type": "string", "description": "The name of the table to read from.", "default": null, "required": true }, { "name": "loop", "value_type": "bool", "description": "If the object should continue writing to the table when the end is reached.", "default": true, "required": false } ], "alias": [ ], "tags": [ ] }, "tan": { "description": "Output = tan(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "tanh": { "description": "Output = tanh(Input)", "inlets": [ { "name": "inlet", "connectionType": "-~>", "description": "Input" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ ], "alias": [ ], "tags": [ "math", "trigonometric" ] }, "var": { "description": "", "inlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "args": [ { "default": 0, "value_type": "float", "name": "k", "description": "The value of this variable.", "required": false }, { "default": 0, "value_type": "float", "name": "step", "description": "The value step increment.", "required": false }, { "default": false, "value_type": "bool", "name": "reverse", "description": "True if the value and step increments should be reversed.", "required": false }, { "default": null, "value_type": "string", "name": "name", "description": "The variable may be named, which is especially useful when used in conjunction with the __varset~f object.", "required": false } ], "alias": [ ], "tags": [ ] }, "vario": { "description": "", "inlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "outlets": [ { "name": "", "connectionType": "-~>", "description": "" } ], "args": [ { "default": null, "value_type": "string", "name": "name", "description": "The named variable which will be manipulated.", "required": true } ], "alias": [ ], "tags": [ ] }, "|": { "description": "Binary OR operation.", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "int", "description": "constant", "default": 0, "required": false } ], "alias": [ "binaryor" ], "tags": [ "math", "bitwise" ] }, "||": { "description": "Logical OR operation.", "inlets": [ { "name": "Input", "connectionType": "-~>", "description": "Set input" }, { "name": "k", "connectionType": "-~>", "description": "Set k" } ], "outlets": [ { "name": "outlet", "connectionType": "-~>", "description": "Output." } ], "args": [ { "name": "k", "value_type": "float", "description": "constant", "default": 0, "required": false } ], "alias": [ "logicalor" ], "tags": [ "math", "logical" ] } } hvcc-0.16.0/hvcc/generators/__init__.py0000644000000000000000000000000000000000000014603 0ustar00hvcc-0.16.0/hvcc/generators/c2daisy/__init__.py0000644000000000000000000000000000000000000016141 0ustar00hvcc-0.16.0/hvcc/generators/c2daisy/c2daisy.py0000644000000000000000000001751500000000000015763 0ustar00# Copyright (C) 2021-2026 Wasted Audio # # 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 . import jinja2 import shutil import time from typing import Any, Dict, Optional from pathlib import Path from ..copyright import copyright_manager from .parameters import parse_parameters, display_parameters, display_processor from .json2daisy import generate_header_from_file, generate_header_from_name from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta, Daisy hv_midi_messages = [ "__hv_noteout", "__hv_ctlout", "__hv_polytouchout", "__hv_pgmout", "__hv_touchout", "__hv_bendout", "__hv_midiout", "__hv_midioutport" ] class c2daisy(Generator): """ Generates a Daisy wrapper for a given patch. """ @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() warnings = [] out_dir = Path(out_dir, "daisy") daisy_meta: Daisy = patch_meta.daisy board = daisy_meta.board copyright_c = copyright_manager.get_copyright_for_c(copyright) try: # ensure that the output directory does not exist out_dir = out_dir.absolute() if out_dir.exists(): shutil.rmtree(out_dir) # copy over static files shutil.copytree(Path(Path(__file__).parent, "static"), out_dir) # copy over generated C source files source_dir = Path(out_dir, "source") shutil.copytree(c_src_dir, source_dir) if daisy_meta.board_file is not None: header, board_info = generate_header_from_file(Path(daisy_meta.board_file)) display_params = display_parameters(daisy_meta.board_file) else: header, board_info = generate_header_from_name(board) display_params = {} warnings.append( CompilerMsg( enum=NotificationEnum.WARNING_GENERIC, message=f"Unable to load board description from {daisy_meta.board_file}. Using fallback." ) ) # inject display process code try: display_process = display_processor(daisy_meta.board_file) except (FileNotFoundError, KeyError, ValueError): display_process = board_info['displayprocess'] warnings.append( CompilerMsg( enum=NotificationEnum.WARNING_GENERIC, message=f"Unable to load display code from {daisy_meta.board_file}. Using fallback." ) ) # remove heavy out params from externs externs.parameters.outParam = [ t for t in externs.parameters.outParam if not any(x == y for x in (hv_midi_messages + list(display_params.keys())) for y in t) ] component_glue = parse_parameters( externs.parameters, board_info['components'], board_info['aliases'], 'hardware') component_glue['class_name'] = board_info['name'] component_glue['patch_name'] = patch_name component_glue['header'] = f"HeavyDaisy_{patch_name}.hpp" component_glue['max_channels'] = board_info['channels'] component_glue['num_output_channels'] = num_output_channels component_glue['has_midi'] = board_info['has_midi'] component_glue['debug_printing'] = daisy_meta.debug_printing component_glue['usb_midi'] = daisy_meta.usb_midi component_glue['pool_sizes_kb'] = externs.memoryPoolSizesKb component_glue['display_params'] = display_params component_glue['display_process'] = display_process # samplerate samplerate = daisy_meta.samplerate if samplerate >= 96000: component_glue['samplerate'] = 96000 elif samplerate >= 48000: component_glue['samplerate'] = 48000 elif samplerate >= 32000: component_glue['samplerate'] = 32000 elif samplerate >= 16000: component_glue['samplerate'] = 16000 else: component_glue['samplerate'] = 8000 # blocksize blocksize = daisy_meta.blocksize if blocksize is not None: component_glue['blocksize'] = max(min(256, blocksize), 1) else: component_glue['blocksize'] = None component_glue['copyright'] = copyright_c daisy_h_path = Path(source_dir, f"HeavyDaisy_{patch_name}.hpp") with open(daisy_h_path, "w") as f: f.write(header) loader = jinja2.FileSystemLoader(Path(Path(__file__).parent, 'templates')) env = jinja2.Environment(loader=loader, trim_blocks=True, lstrip_blocks=True) daisy_cpp_path = Path(source_dir, f"HeavyDaisy_{patch_name}.cpp") rendered_cpp = env.get_template('HeavyDaisy.cpp').render(component_glue) with open(daisy_cpp_path, 'w') as f: f.write(rendered_cpp) makefile_replacements: Dict[str, Any] = {'name': patch_name} makefile_replacements['linker_script'] = daisy_meta.linker_script # libdaisy path path = daisy_meta.libdaisy_path if isinstance(path, int): makefile_replacements['libdaisy_path'] = f'{"../" * path}libdaisy' elif isinstance(path, str): makefile_replacements['libdaisy_path'] = path makefile_replacements['bootloader'] = daisy_meta.bootloader makefile_replacements['debug_printing'] = daisy_meta.debug_printing rendered_makefile = env.get_template('Makefile').render(makefile_replacements) with open(Path(source_dir, "Makefile"), "w") as f: f.write(rendered_makefile) # ====================================================================================== return CompilerResp( stage="c2daisy", notifs=CompilerNotif( warnings=warnings ), in_dir=c_src_dir, out_dir=out_dir, out_file=daisy_h_path, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2daisy", notifs=CompilerNotif( has_error=True, exception=e, warnings=warnings, errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/LICENSE.md0000644000000000000000000000212200000000000017530 0ustar00MIT License Copyright (c) 2021 Electrosmith Copyright (c) 2025-2026 Wasted Audio Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/__init__.py0000644000000000000000000000004200000000000020234 0ustar00from .json2daisy import * # noqa hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/json2daisy.py0000644000000000000000000003233600000000000020575 0ustar00import jinja2 import json from importlib import resources from typing import Optional from pathlib import Path def map_load(pair: list, json_defs_file: Path): """ Helper for loading and processing the definitions, component list, etc """ # load the default components comp_string = Path(Path(__file__).parent, json_defs_file) component_defs = json.loads(comp_string.read_bytes()) pair[1]['name'] = pair[0] # the default if it exists component = component_defs.get(pair[1]['component'], None) if (component): # copy component defs into the def # TODO this should be recursive for object structures.. for k in component: if k not in pair[1]: pair[1][k] = component[k] else: raise Exception(f'unknown component "{pair[1]["component"]}"') return pair[1] def filter_match( component_set: list, key: str, match: str, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> filter: if (key_exclude is not None and match_exclude): return filter(lambda x: x.get(key, '') == match and x.get(key_exclude, '') != match_exclude, component_set) else: return filter(lambda x: x.get(key, '') == match, component_set) def filter_matches( component_set: list, key: str, matches: list, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> filter: if (key_exclude is not None and match_exclude): return filter(lambda x: x.get(key, '') in matches and x.get(key_exclude, '') != match_exclude, component_set) else: return filter(lambda x: x.get(key, '') in matches, component_set) def filter_has( component_set: list, key: str, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> filter: if (key_exclude is not None and match_exclude): return filter(lambda x: x.get(key, '') != '' and x.get(key_exclude, '') != match_exclude, component_set) else: return filter(lambda x: x.get(key, '') != '', component_set) # filter out the components we need, then map them onto the init for that part def filter_map_init( component_set: list, key: str, match: str, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> str: filtered = filter_match(component_set, key, match, key_exclude=key_exclude, match_exclude=match_exclude) return "\n ".join(map(lambda x: x['map_init'].format_map(x), filtered)) # this function is not used anywhere? def filter_map_set( component_set: list, key: str, match: str, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> str: filtered = filter_match(component_set, key, match, key_exclude=key_exclude, match_exclude=match_exclude) return "\n ".join( map(lambda x: x['mapping'][0]['set'].format_map(x['mapping'][0]['name'].format_map(x)), filtered) ) def filter_map_ctrl( component_set: list, key: str, matches: list, init_key: str, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> str: component_filt = filter_matches(component_set, key, matches, key_exclude=key_exclude, match_exclude=match_exclude) component_map = map(lambda x, i: {**x, 'i': i}, component_filt, range(1000)) return "\n ".join(map(lambda x: x[init_key].format_map(x), component_map)) # filter out the components with a certain field, then fill in the template def filter_map_template( component_set: list, name: str, key_exclude: Optional[str] = None, match_exclude: bool = False ) -> str: filtered = filter_has(component_set, name, key_exclude=key_exclude, match_exclude=match_exclude) return "\n ".join(map(lambda x: x[name].format_map(x), filtered)) def flatten_pin_dicts(comp: dict) -> dict: newcomp = {} for key, val in comp.items(): if (isinstance(val, dict) and key == 'pin'): for subkey, subval in val.items(): newcomp[f'{key}_{subkey}'] = subval else: newcomp[key] = val return newcomp def flatten_index_dicts(comp: dict) -> dict: newcomp = {} for key, val in comp.items(): if (isinstance(val, dict) and key == 'index'): for subkey, subval in val.items(): newcomp[f'{key}_{subkey}'] = subval else: newcomp[key] = val return newcomp def generate_header(board_description_dict: dict) -> 'tuple[str, dict]': """ Generate a C++ Daisy board header from a dictionary board description. Returns a tuple containing the board header as a string and an information dictionary. The dictionary provides sufficient information to generate interface code, including component getters and setters, audio channel count, etc. """ target = board_description_dict # flesh out target components: components = target.get('components', {}) parents = target.get('parents', {}) for key in parents: parents[key]['is_parent'] = True components.update(parents) seed_defs = Path("resources", 'component_defs.json') patchsm_defs = Path("resources", 'component_defs_patchsm.json') petalsm_defs = Path("resources", 'component_defs_petalsm.json') definitions = {'seed': seed_defs, 'patch_sm': patchsm_defs, 'petal_125b_sm': petalsm_defs} som = target.get('som', 'seed') try: json_defs_file = definitions[som] except KeyError: raise NameError(f'Unkown som "{som}"') # alphabetize by component name components = sorted(components.items(), key=lambda x: x[1]['component']) components = list(map(lambda p: map_load(p, json_defs_file), components)) # flatten pin dicts into multiple entries # e.g. "pin": {"a": 12} => "pin_a": 12 components = [flatten_pin_dicts(comp) for comp in components] components = [flatten_index_dicts(comp) for comp in components] target['components'] = components if 'name' not in target: target['name'] = 'custom' if 'aliases' not in target: target['aliases'] = {} if 'display' in target: # apply defaults if not present in config target['display']['driver'] = target['display'].get('driver', "daisy::SSD130x4WireSpi128x64Driver") target['display']['config'] = target['display'].get('config', []) target['display']['dim'] = target['display'].get('dim', [128, 64]) target['displayprocess'] = target['display'].get('process', '') replacements = {} replacements['name'] = target['name'] replacements['som'] = som replacements['external_codecs'] = target.get('external_codecs', []) som_classes = { 'seed': 'daisy::DaisySeed', 'patch_sm': 'daisy::patch_sm::DaisyPatchSM', 'petal_125b_sm': 'daisy::Petal125BSM', } replacements['som_class'] = som_classes.get(som, som_classes['seed']) replacements['display_conditional'] = ('#include "dev/oled_ssd130x.h"' if ('display' in target) else "") replacements['target_name'] = target['name'] replacements['init'] = filter_map_template(components, 'init', key_exclude='default', match_exclude=True) replacements['analogcount'] = len(list(filter_matches( components, 'component', ['AnalogControl', 'AnalogControlBipolar', 'CD4051'], key_exclude='default', match_exclude=True))) replacements['init_single'] = filter_map_ctrl( components, 'component', ['AnalogControl', 'AnalogControlBipolar', 'CD4051'], 'init_single', key_exclude='default', match_exclude=True) replacements['ctrl_init'] = filter_map_ctrl( components, 'component', ['AnalogControl', 'AnalogControlBipolar'], 'map_init', key_exclude='default', match_exclude=True) comp_string = Path(Path(__file__).parent, json_defs_file) definitions_dict = json.loads(comp_string.read_bytes()) for name in definitions_dict: if name not in ('AnalogControl', 'AnalogControlBipolar', 'CD4051'): replacements[name] = filter_map_init( components, 'component', name, key_exclude='default', match_exclude=True) if 'display' in target: replacements['dispdec'] = f'daisy::OledDisplay<{target["display"]["driver"]}> display;' replacements['display'] = f""" daisy::OledDisplay<{target['display']['driver']}>::Config display_config; display_config.driver_config.transport_config.Defaults(); {"".join(map(lambda x: x, target['display'].get('config', {})))} display.Init(display_config); display.Fill(0); display.Update(); """ else: replacements['display'] = '' if 'defines' in target: # deprecate old oopsy syntax at some point if target['defines'].get('HAS_MIDI') or target['defines'].get('OOPSY_TARGET_HAS_MIDI_INPUT'): target['has_midi'] = True replacements['midi'] = """daisy::MidiUartHandler midi;""" replacements['process'] = filter_map_template( components, 'process', key_exclude='default', match_exclude=True) replacements['loopprocess'] = filter_map_template( components, 'loopprocess', key_exclude='default', match_exclude=True) replacements['postprocess'] = filter_map_template( components, 'postprocess', key_exclude='default', match_exclude=True) replacements['displayprocess'] = filter_map_template( components, 'display', key_exclude='default', match_exclude=True) replacements['hidupdaterates'] = filter_map_template( components, 'updaterate', key_exclude='default', match_exclude=True) license_string = resources.files(__package__).joinpath('resources/LICENSE').read_text() replacements['license'] = '/*\n * ' + '\n * '.join([line for line in license_string.split('\n')]) + '\n */' component_declarations = list(filter(lambda x: not x.get('default', False), components)) component_declarations = list(filter(lambda x: x.get('typename', '') != '', component_declarations)) if len(component_declarations) > 0: replacements['comps'] = ";\n ".join( map(lambda x: x['typename'].format_map(x) + ' ' + x['name'], component_declarations) ) + ';' non_class_declarations = list(filter(lambda x: 'non_class_decl' in x, component_declarations)) if len(non_class_declarations) > 0: replacements['non_class_declarations'] = "\n".join( map(lambda x: x['non_class_decl'].format_map(x), non_class_declarations) ) # env_opts = {"trim_blocks": True, "lstrip_blocks": True} # Ideally, this would be what we use, but we'll need to get the jinja PackageLoader class working # loader = jinja2.PackageLoader(__name__) # env = jinja2.Environment(loader=loader, **env_opts) # rendered_header = env.get_template('daisy.h').render(replacements) # This following works, but is really annoying header_str = Path(Path(__file__).parent, Path('templates', 'daisy.h')).read_text() header_env = jinja2.Environment( loader=jinja2.BaseLoader(), trim_blocks=True, lstrip_blocks=True ).from_string(header_str) rendered_header = header_env.render(replacements) rendered_header_lines = rendered_header.splitlines() rendered_header = "\n".join(line.rstrip() for line in rendered_header_lines) + "\n" # removing all unnecessary fields for comp in components: if 'map_init' in comp: del comp['map_init'] if 'typename' in comp: del comp['typename'] audio_info = target.get('audio', None) audio_channels = audio_info.get('channels', 2) if audio_info is not None else 2 # This dictionary contains the necessary information to automatically (or manually) # write code to interface with the generated board board_info = { 'name': target['name'], 'components': components, 'aliases': target['aliases'], 'channels': audio_channels, 'has_midi': target.get('has_midi', False), 'displayprocess': target.get('displayprocess', '') } return rendered_header, board_info def generate_header_from_file(description_file: Path) -> 'tuple[str, dict]': """ Generate a C++ Daisy board header from a JSON description file. Returns a tuple containing the board header as a string and an information dictionary. The dictionary provides sufficient information to generate interface code, including component getters and setters, audio channel count, etc. """ with open(description_file, 'rb') as file: daisy_description = json.load(file) return generate_header(daisy_description) def generate_header_from_name(board_name: str) -> 'tuple[str, dict]': """ Generate a C++ Daisy board header for an existing daisy board. Returns a tuple containing the board header as a string and an information dictionary. The dictionary provides sufficient information to generate interface code, including component getters and setters, audio channel count, etc. """ try: description_file = Path('resources', f'{board_name}.json') daisy_description = Path(Path(__file__).parent, description_file) daisy_description_dict = json.loads(daisy_description.read_bytes()) except FileNotFoundError: raise FileNotFoundError(f'Unknown Daisy board "{board_name}"') return generate_header(daisy_description_dict) hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/LICENSE0000644000000000000000000000205500000000000021150 0ustar00MIT License Copyright (c) 2021 Electrosmith Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/component_defs.json0000644000000000000000000007022400000000000024044 0ustar00{ "UserLed": { "map_init": "", "typename": "", "direction": "out", "mapping": [ { "name": "{name}", "set": "{class_name}.som.SetLed({value});", "where": "hook" } ] }, "Switch": { "map_init": "{name}.Init(som.GetPin({pin}), som.AudioCallbackRate(), {type}, {polarity});", "typename": "daisy::Switch", "direction": "in", "pin": "a", "type": "daisy::Switch::TYPE_MOMENTARY", "polarity": "daisy::Switch::POLARITY_INVERTED", "process": "{name}.Debounce();", "updaterate": "{name}.SetUpdateRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}_press", "get": "({class_name}.{name}.Pressed()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}", "get": "({class_name}.{name}.RisingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_fall", "get": "({class_name}.{name}.FallingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_seconds", "get": "({class_name}.{name}.TimeHeldMs()*0.001f)", "range": null, "bool": false } ] }, "Switch3": { "map_init": "{name}.Init(som.GetPin({pin_a}), som.GetPin({pin_b}));", "typename": "daisy::Switch3", "direction": "in", "pin": "a,b", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Read()*0.5f+0.5f)", "range": [ 0, 2 ], "bool": false } ] }, "Encoder": { "map_init": "{name}.Init(som.GetPin({pin_a}), som.GetPin({pin_b}), som.GetPin({pin_click}), som.AudioCallbackRate());", "typename": "daisy::Encoder", "direction": "in", "pin": "a,b,click", "process": "{name}.Debounce();", "updaterate": "{name}.SetUpdateRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Increment())", "range": [ -1, 1 ], "bool": false }, { "name": "{name}_press", "get": "({class_name}.{name}.Pressed()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}_rise", "get": "({class_name}.{name}.RisingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_fall", "get": "({class_name}.{name}.FallingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_seconds", "get": "({class_name}.{name}.TimeHeldMs()*0.001f)", "range": null, "bool": false } ] }, "GateIn": { "map_init": "{name}.Init(som.GetPin({pin}), {invert});", "typename": "daisy::GateIn", "direction": "in", "pin": "a", "invert": "true", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.State()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}_trig", "get": "({class_name}.{name}.Trig()?1.f:0.f)", "range": [ 0, 1 ], "bool": true } ] }, "AnalogControl": { "init_single": "cfg[{i}].InitSingle(som.GetPin({pin}));", "map_init": "{name}.Init(som.adc.GetPtr({i}), som.AudioCallbackRate(), {flip}, {invert});", "typename": "daisy::AnalogControl", "direction": "in", "pin": "a", "flip": "false", "invert": "false", "slew": "1.0/som.AudioCallbackRate()", "process": "{name}.Process();", "updaterate": "{name}.SetSampleRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Value())", "range": [ 0, 1 ], "bool": false } ] }, "Led": { "map_init": "{name}.Init(som.GetPin({pin}), {invert});\n {name}.Set(0.0f);", "typename": "daisy::Led", "direction": "out", "pin": "a", "invert": "true", "postprocess": "{name}.Update();", "mapping": [ { "name": "{name}", "set": "{class_name}.{name}.Set({value});" } ] }, "RgbLed": { "map_init": "{name}.Init(som.GetPin({pin_r}), som.GetPin({pin_g}), som.GetPin({pin_b}), {invert});\n {name}.Set(0.0f, 0.0f, 0.0f);", "typename": "daisy::RgbLed", "direction": "out", "pin": "r,g,b", "invert": "true", "postprocess": "{name}.Update();", "mapping": [ { "name": "{name}_red", "set": "{class_name}.{name}.SetRed({value});" }, { "name": "{name}_green", "set": "{class_name}.{name}.SetGreen({value});" }, { "name": "{name}_blue", "set": "{class_name}.{name}.SetBlue({value});" }, { "name": "{name}", "set": "{class_name}.{name}.Set({value},{value},{value});" }, { "name": "{name}_white", "set": "{class_name}.{name}.Set({value},{value},{value});" } ] }, "GateOut": { "map_init": "{name}.Init(som.GetPin({pin}), {mode}, {pull});", "typename": "daisy::GPIO", "direction": "out", "pin": "a", "mode": "daisy::GPIO::Mode::OUTPUT", "pull": "daisy::GPIO::Pull::NOPULL", "mapping": [ { "name": "{name}", "set": "{class_name}.{name}.Write({value});", "where": "hook" } ] }, "CVOuts": { "map_init": "{name}.bitdepth = {bitdepth};\n {name}.buff_state = {buff_state};\n {name}.mode = {mode};\n {name}.chn = {channel};\n som.dac.Init({name});\n som.dac.WriteValue({channel}, 0);", "typename": "daisy::DacHandle::Config", "direction": "out", "pin": "", "bitdepth": "daisy::DacHandle::BitDepth::BITS_12", "buff_state": "daisy::DacHandle::BufferState::ENABLED", "mode": "daisy::DacHandle::Mode::POLLING", "channel": "daisy::DacHandle::Channel::BOTH", "mapping": [ { "name": "{name}1", "set": "{class_name}.som.dac.WriteValue(daisy::DacHandle::Channel::ONE, {value} * 4095);", "where": "main" }, { "name": "{name}2", "set": "{class_name}.som.dac.WriteValue(daisy::DacHandle::Channel::TWO, {value} * 4095);", "where": "main" } ] }, "i2c": { "map_init": "{name}.Init({{{peripheral}, {{som.GetPin({pin_scl}), som.GetPin({pin_sda})}}, {speed}, {mode}}});", "typename": "daisy::I2CHandle", "pin": "scl,sda", "peripheral": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_1MHZ", "mode": "daisy::I2CHandle::Config::Mode::I2C_MASTER", "mapping": [] }, "PCA9685": { "map_init": "{name}.Init({parent}, {address}, {name}_dma_buffer_a, {name}_dma_buffer_b);", "typename": "daisy::LedDriverPca9685<{driver_count}, true>", "non_class_decl": "daisy::LedDriverPca9685<{driver_count}, true>::DmaBuffer DMA_BUFFER_MEM_SECTION {name}_dma_buffer_a, {name}_dma_buffer_b;", "driver_count": 1, "address": "{0x00}", "parent": "", "pin": "", "loopprocess": "{name}.SwapBuffersAndTransmit();", "mapping": [] }, "PCA9685Led": { "map_init": "", "pin": "", "typename": "", "parent": "", "direction": "out", "index": 0, "mapping": [ { "name": "{name}", "set": "{class_name}.{parent}.SetLed({index}, {value});" } ] }, "PCA9685RgbLed": { "map_init": "", "typename": "", "direction": "out", "parent": "", "pin": "", "index": { "red": 0, "green": 1, "blue": 2 }, "mapping": [ { "name": "{name}_red", "set": "{class_name}.{parent}.SetLed({index_red}, {value});" }, { "name": "{name}_green", "set": "{class_name}.{parent}.SetLed({index_green}, {value});" }, { "name": "{name}_blue", "set": "{class_name}.{parent}.SetLed({index_blue}, {value});" }, { "name": "{name}", "set": "{class_name}.{parent}.SetLed({index_red}, {value});\n {class_name}.{parent}.SetLed({index_green}, {value});\n {class_name}.{parent}.SetLed({index_blue}, {value});" }, { "name": "{name}_white", "set": "{class_name}.{parent}.SetLed({index_red}, {value});\n {class_name}.{parent}.SetLed({index_green}, {value});\n {class_name}.{parent}.SetLed({index_blue}, {value});" } ] }, "CD4021": { "map_init": "{name}.Init({{ som.GetPin({pin_clk}), som.GetPin({pin_cs}), {{ som.GetPin({pin_data}) }} }});", "typename": "daisy::ShiftRegister4021<{driver_count}>", "non_class_decl": "uint8_t {name}_debounced[8*{driver_count}];", "driver_count": 1, "pin": "clk,cs,data", "postprocess": "{name}.Update();", "mapping": [] }, "CD4021Switch": { "map_init": "", "typename": "", "direction": "in", "parent": "", "index": 0, "postprocess": "{parent}_debounced[{index}] = {parent}.State({index}) | ({parent}_debounced[{index}] << 1);", "mapping": [ { "name": "{name}", "get": "(json2daisy::{parent}_debounced[{index}] == 0xFE)", "bool": true }, { "name": "{name}_press", "get": "(json2daisy::{parent}_debounced[{index}] != 0xFF)", "bool": false }, { "name": "{name}_fall", "get": "(json2daisy::{parent}_debounced[{index}] == 0x7F)", "bool": true } ] }, "CD4051": { "init_single": "size_t {name}_index = {i};\n cfg[{name}_index].InitMux(som.GetPin({pin_adc}), {mux_count}, som.GetPin({pin_sel0}), som.GetPin({pin_sel1}), som.GetPin({pin_sel2}));", "typename": "", "mux_count": 1, "pin": "adc,sel0,sel1,sel2", "mapping": [] }, "CD4051AnalogControl": { "map_init": "{name}.Init(som.adc.GetMuxPtr({parent}_index, {index}), som.AudioCallbackRate(), {flip}, {invert});", "parent": "", "index": 0, "typename": "daisy::AnalogControl", "direction": "in", "flip": "false", "invert": "false", "slew": "1.0/som.AudioCallbackRate()", "process": "{name}.Process();", "updaterate": "{name}.SetSampleRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Value())", "range": [ 0, 1 ], "bool": false } ] }, "AnalogControlBipolar": { "init_single": "cfg[{i}].InitSingle(som.GetPin({pin}));", "map_init": "{name}.InitBipolarCv(som.adc.GetPtr({i}), som.AudioCallbackRate());", "typename": "daisy::AnalogControl", "direction": "in", "pin": "a", "slew": "1.0/som.AudioCallbackRate()", "process": "{name}.Process();", "updaterate": "{name}.SetSampleRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Value())", "range": [ 0, 1 ], "bool": false } ] }, "Tlv493d": { "map_init": "daisy::Tlv493dI2CTransport::Config {name}_config;\n {name}_config.address = {address};\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n daisy::Tlv493dI2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}.Init({name}_main_conf);", "typename": "daisy::Tlv493dI2C", "direction": "in", "pin": "scl,sda", "address": "TLV493D_ADDRESS1", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "loopprocess": "{name}.UpdateData();", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.GetAmount()" }, { "name": "{name}_x", "get": "{class_name}.{name}.GetX()" }, { "name": "{name}_y", "get": "{class_name}.{name}.GetY()" }, { "name": "{name}_z", "get": "{class_name}.{name}.GetZ()" }, { "name": "{name}_amount", "get": "{class_name}.{name}.GetAmount()" }, { "name": "{name}_azimuth", "get": "{class_name}.{name}.GetAzimuth()" }, { "name": "{name}_polar", "get": "{class_name}.{name}.GetPolar()" } ] }, "Mpr121": { "map_init": "daisy::Mpr121I2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.dev_addr = {address};\n daisy::Mpr121I2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}_main_conf.touch_threshold = {touch_threshold};\n {name}_main_conf.release_threshold = {release_threshold};\n {name}.Init({name}_main_conf);", "typename": "daisy::Mpr121I2C", "direction": "in", "pin": "scl,sda", "address": "MPR121_I2CADDR_DEFAULT", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "touch_threshold": "MPR121_TOUCH_THRESHOLD_DEFAULT", "release_threshold": "MPR121_RELEASE_THRESHOLD_DEFAULT", "mapping": [ { "name": "{name}", "get": "(({class_name}.{name}.Touched() & 0x001) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch0", "get": "(({class_name}.{name}.Touched() & 0x001) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch1", "get": "(({class_name}.{name}.Touched() & 0x002) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch2", "get": "(({class_name}.{name}.Touched() & 0x004) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch3", "get": "(({class_name}.{name}.Touched() & 0x008) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch4", "get": "(({class_name}.{name}.Touched() & 0x010) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch5", "get": "(({class_name}.{name}.Touched() & 0x020) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch6", "get": "(({class_name}.{name}.Touched() & 0x040) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch7", "get": "(({class_name}.{name}.Touched() & 0x080) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch8", "get": "(({class_name}.{name}.Touched() & 0x100) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch9", "get": "(({class_name}.{name}.Touched() & 0x200) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch10", "get": "(({class_name}.{name}.Touched() & 0x400) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch11", "get": "(({class_name}.{name}.Touched() & 0x800) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch0_raw", "get": "{class_name}.{name}.FilteredData(0)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch1_raw", "get": "{class_name}.{name}.FilteredData(1)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch2_raw", "get": "{class_name}.{name}.FilteredData(2)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch3_raw", "get": "{class_name}.{name}.FilteredData(3)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch4_raw", "get": "{class_name}.{name}.FilteredData(4)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch5_raw", "get": "{class_name}.{name}.FilteredData(5)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch6_raw", "get": "{class_name}.{name}.FilteredData(6)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch7_raw", "get": "{class_name}.{name}.FilteredData(7)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch8_raw", "get": "{class_name}.{name}.FilteredData(8)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch9_raw", "get": "{class_name}.{name}.FilteredData(9)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch10_raw", "get": "{class_name}.{name}.FilteredData(10)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch11_raw", "get": "{class_name}.{name}.FilteredData(11)", "where": "main", "range": [ 0, 1023 ] } ] }, "Apds9960": { "map_init": "daisy::Apds9960I2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n daisy::Apds9960I2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}.Init({name}_main_conf);", "typename": "daisy::Apds9960I2C", "direction": "in", "pin": "scl,sda", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.ReadGesture()", "where": "main" }, { "name": "{name}_gest", "get": "{class_name}.{name}.ReadGesture()", "where": "main" }, { "name": "{name}_prox", "get": "{class_name}.{name}.ReadProximity()", "where": "main" }, { "name": "{name}_red", "get": "{class_name}.{name}.GetColorDataRed()", "where": "main" }, { "name": "{name}_green", "get": "{class_name}.{name}.GetColorDataGreen()", "where": "main" }, { "name": "{name}_blue", "get": "{class_name}.{name}.GetColorDataBlue()", "where": "main" }, { "name": "{name}_clear", "get": "{class_name}.{name}.GetColorDataClear()", "where": "main" } ] }, "NeoTrellis": { "map_init": "daisy::NeoTrellisI2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n {name}_config.address = {address};\n daisy::NeoTrellisI2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}.Init({name}_main_conf);", "typename": "daisy::NeoTrellisI2C", "direction": "in", "pin": "scl,sda", "address": "NEO_TRELLIS_ADDR", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "loopprocess": "{name}.Process();", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.GetRising(0)", "bool": true }, { "name": "{name}_0", "get": "{class_name}.{name}.GetRising(0)", "bool": true }, { "name": "{name}_1", "get": "{class_name}.{name}.GetRising(1)", "bool": true }, { "name": "{name}_2", "get": "{class_name}.{name}.GetRising(2)", "bool": true }, { "name": "{name}_3", "get": "{class_name}.{name}.GetRising(3)", "bool": true }, { "name": "{name}_4", "get": "{class_name}.{name}.GetRising(4)", "bool": true }, { "name": "{name}_5", "get": "{class_name}.{name}.GetRising(5)", "bool": true }, { "name": "{name}_6", "get": "{class_name}.{name}.GetRising(6)", "bool": true }, { "name": "{name}_7", "get": "{class_name}.{name}.GetRising(7)", "bool": true }, { "name": "{name}_8", "get": "{class_name}.{name}.GetRising(8)", "bool": true }, { "name": "{name}_9", "get": "{class_name}.{name}.GetRising(9)", "bool": true }, { "name": "{name}_10", "get": "{class_name}.{name}.GetRising(10)", "bool": true }, { "name": "{name}_11", "get": "{class_name}.{name}.GetRising(11)", "bool": true }, { "name": "{name}_12", "get": "{class_name}.{name}.GetRising(12)", "bool": true }, { "name": "{name}_13", "get": "{class_name}.{name}.GetRising(13)", "bool": true }, { "name": "{name}_14", "get": "{class_name}.{name}.GetRising(14)", "bool": true }, { "name": "{name}_15", "get": "{class_name}.{name}.GetRising(15)", "bool": true }, { "name": "{name}_0_falling", "get": "{class_name}.{name}.GetFalling(0)", "bool": true }, { "name": "{name}_1_falling", "get": "{class_name}.{name}.GetFalling(1)", "bool": true }, { "name": "{name}_2_falling", "get": "{class_name}.{name}.GetFalling(2)", "bool": true }, { "name": "{name}_3_falling", "get": "{class_name}.{name}.GetFalling(3)", "bool": true }, { "name": "{name}_4_falling", "get": "{class_name}.{name}.GetFalling(4)", "bool": true }, { "name": "{name}_5_falling", "get": "{class_name}.{name}.GetFalling(5)", "bool": true }, { "name": "{name}_6_falling", "get": "{class_name}.{name}.GetFalling(6)", "bool": true }, { "name": "{name}_7_falling", "get": "{class_name}.{name}.GetFalling(7)", "bool": true }, { "name": "{name}_8_falling", "get": "{class_name}.{name}.GetFalling(8)", "bool": true }, { "name": "{name}_9_falling", "get": "{class_name}.{name}.GetFalling(9)", "bool": true }, { "name": "{name}_10_falling", "get": "{class_name}.{name}.GetFalling(10)", "bool": true }, { "name": "{name}_11_falling", "get": "{class_name}.{name}.GetFalling(11)", "bool": true }, { "name": "{name}_12_falling", "get": "{class_name}.{name}.GetFalling(12)", "bool": true }, { "name": "{name}_13_falling", "get": "{class_name}.{name}.GetFalling(13)", "bool": true }, { "name": "{name}_14_falling", "get": "{class_name}.{name}.GetFalling(14)", "bool": true }, { "name": "{name}_15_falling", "get": "{class_name}.{name}.GetFalling(15)", "bool": true }, { "name": "{name}_0_state", "get": "({class_name}.{name}.GetState(0) ? 1.0f : 0.0f)" }, { "name": "{name}_1_state", "get": "({class_name}.{name}.GetState(1) ? 1.0f : 0.0f)" }, { "name": "{name}_2_state", "get": "({class_name}.{name}.GetState(2) ? 1.0f : 0.0f)" }, { "name": "{name}_3_state", "get": "({class_name}.{name}.GetState(3) ? 1.0f : 0.0f)" }, { "name": "{name}_4_state", "get": "({class_name}.{name}.GetState(4) ? 1.0f : 0.0f)" }, { "name": "{name}_5_state", "get": "({class_name}.{name}.GetState(5) ? 1.0f : 0.0f)" }, { "name": "{name}_6_state", "get": "({class_name}.{name}.GetState(6) ? 1.0f : 0.0f)" }, { "name": "{name}_7_state", "get": "({class_name}.{name}.GetState(7) ? 1.0f : 0.0f)" }, { "name": "{name}_8_state", "get": "({class_name}.{name}.GetState(8) ? 1.0f : 0.0f)" }, { "name": "{name}_9_state", "get": "({class_name}.{name}.GetState(9) ? 1.0f : 0.0f)" }, { "name": "{name}_10_state", "get": "({class_name}.{name}.GetState(10) ? 1.0f : 0.0f)" }, { "name": "{name}_11_state", "get": "({class_name}.{name}.GetState(11) ? 1.0f : 0.0f)" }, { "name": "{name}_12_state", "get": "({class_name}.{name}.GetState(12) ? 1.0f : 0.0f)" }, { "name": "{name}_13_state", "get": "({class_name}.{name}.GetState(13) ? 1.0f : 0.0f)" }, { "name": "{name}_14_state", "get": "({class_name}.{name}.GetState(14) ? 1.0f : 0.0f)" }, { "name": "{name}_15_state", "get": "({class_name}.{name}.GetState(15) ? 1.0f : 0.0f)" } ] }, "NeoTrellisLeds": { "map_init": "", "parent": "", "direction": "out", "loopprocess": "{parent}.pixels.Show();", "mapping": [ { "name": "{name}", "set": "{class_name}.{parent}.pixels.SetPixelColor(0, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_0", "set": "{class_name}.{parent}.pixels.SetPixelColor(0, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_1", "set": "{class_name}.{parent}.pixels.SetPixelColor(1, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_2", "set": "{class_name}.{parent}.pixels.SetPixelColor(2, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_3", "set": "{class_name}.{parent}.pixels.SetPixelColor(3, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_4", "set": "{class_name}.{parent}.pixels.SetPixelColor(4, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_5", "set": "{class_name}.{parent}.pixels.SetPixelColor(5, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_6", "set": "{class_name}.{parent}.pixels.SetPixelColor(6, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_7", "set": "{class_name}.{parent}.pixels.SetPixelColor(7, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_8", "set": "{class_name}.{parent}.pixels.SetPixelColor(8, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_9", "set": "{class_name}.{parent}.pixels.SetPixelColor(9, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_10", "set": "{class_name}.{parent}.pixels.SetPixelColor(10, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_11", "set": "{class_name}.{parent}.pixels.SetPixelColor(11, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_12", "set": "{class_name}.{parent}.pixels.SetPixelColor(12, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_13", "set": "{class_name}.{parent}.pixels.SetPixelColor(13, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_14", "set": "{class_name}.{parent}.pixels.SetPixelColor(14, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_15", "set": "{class_name}.{parent}.pixels.SetPixelColor(15, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" } ] }, "Icm20948": { "map_init": "daisy::Icm20948I2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n {name}_config.address = {address};\n daisy::Icm20948I2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}.Init({name}_main_conf);", "typename": "daisy::Icm20948I2C", "direction": "in", "pin": "scl,sda", "address": "ICM20948_I2CADDR_DEFAULT", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "loopprocess": "{name}.Process();", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.GetAccelVect().x" }, { "name": "{name}_accel_x", "get": "{class_name}.{name}.GetAccelVect().x" }, { "name": "{name}_accel_y", "get": "{class_name}.{name}.GetAccelVect().y" }, { "name": "{name}_accel_z", "get": "{class_name}.{name}.GetAccelVect().z" }, { "name": "{name}_magnet_x", "get": "{class_name}.{name}.GetMagVect().x" }, { "name": "{name}_magnet_y", "get": "{class_name}.{name}.GetMagVect().y" }, { "name": "{name}_magnet_z", "get": "{class_name}.{name}.GetMagVect().z" }, { "name": "{name}_gyro_x", "get": "{class_name}.{name}.GetGyroVect().x" }, { "name": "{name}_gyro_y", "get": "{class_name}.{name}.GetGyroVect().y" }, { "name": "{name}_gyro_z", "get": "{class_name}.{name}.GetGyroVect().z" } ] }, "Dps310": { "map_init": "daisy::Dps310I2CTransport::Config {name}_config;\n {name}_config.address = {address};\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n daisy::Dps310I2C::Config {name}_config_main;\n {name}_config_main.transport_config = {name}_config;\n {name}.Init({name}_config_main);", "typename": "daisy::Dps310I2C", "direction": "in", "pin": "scl,sda", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "address": "DPS310_I2CADDR_DEFAULT", "pressure": 1013, "loopprocess": "{name}.Process();", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.GetTemperature()" }, { "name": "{name}_temp", "get": "{class_name}.{name}.GetTemperature()" }, { "name": "{name}_press", "get": "{class_name}.{name}.GetPressure()" }, { "name": "{name}_alt", "get": "{class_name}.{name}.GetAltitude({pressure})" } ] } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/component_defs_patchsm.json0000644000000000000000000005274200000000000025570 0ustar00{ "UserLed": { "map_init": "", "typename": "", "direction": "out", "mapping": [ { "name": "{name}", "set": "{class_name}.som.SetLed({value});", "where": "hook" } ] }, "Switch": { "map_init": "{name}.Init(daisy::patch_sm::DaisyPatchSM::{pin}, som.AudioCallbackRate(), {type}, {polarity});", "typename": "daisy::Switch", "direction": "in", "pin": "a", "type": "daisy::Switch::TYPE_MOMENTARY", "polarity": "daisy::Switch::POLARITY_INVERTED", "process": "{name}.Debounce();", "updaterate": "{name}.SetUpdateRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}_press", "get": "({class_name}.{name}.Pressed()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}", "get": "({class_name}.{name}.RisingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_fall", "get": "({class_name}.{name}.FallingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_seconds", "get": "({class_name}.{name}.TimeHeldMs()*0.001f)", "range": null, "bool": false } ] }, "Switch3": { "map_init": "{name}.Init(daisy::patch_sm::DaisyPatchSM::{pin_a}, daisy::patch_sm::DaisyPatchSM::{pin_b}));", "typename": "daisy::Switch3", "direction": "in", "pin": "a,b", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Read()*0.5f+0.5f)", "range": [ 0, 2 ], "bool": false } ] }, "Encoder": { "map_init": "{name}.Init(daisy::patch_sm::DaisyPatchSM::{pin_a}, daisy::patch_sm::DaisyPatchSM::{pin_b}, daisy::patch_sm::DaisyPatchSM::{pin_click}, som.AudioCallbackRate());", "typename": "daisy::Encoder", "direction": "in", "pin": "a,b,click", "process": "{name}.Debounce();", "updaterate": "{name}.SetUpdateRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}", "get": "({class_name}.{name}.Increment())", "range": [ -1, 1 ], "bool": false }, { "name": "{name}_press", "get": "({class_name}.{name}.Pressed()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}_rise", "get": "({class_name}.{name}.RisingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_fall", "get": "({class_name}.{name}.FallingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_seconds", "get": "({class_name}.{name}.TimeHeldMs()*0.001f)", "range": null, "bool": false } ] }, "GateIn": { "map_init": "{name}.Init(&daisy::patch_sm::DaisyPatchSM::{pin});", "typename": "daisy::GateIn", "direction": "in", "pin": "a", "default_prefix": "som.", "mapping": [ { "name": "{name}", "get": "({class_name}.{default_prefix}{name}.State()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}_trig", "get": "({class_name}.{default_prefix}{name}.Trig()?1.f:0.f)", "range": [ 0, 1 ], "bool": true } ] }, "AnalogControl": { "init_single": "cfg[{i}].InitSingle(daisy::patch_sm::DaisyPatchSM::{pin});", "map_init": "{name}.Init(som.adc.GetPtr({i}), som.AudioCallbackRate(), {flip}, {invert});", "typename": "daisy::AnalogControl", "direction": "in", "pin": "a", "flip": "false", "invert": "false", "slew": "1.0/som.AudioCallbackRate()", "process": "{name}.Process();", "updaterate": "{name}.SetSampleRate(som.AudioCallbackRate());", "mapping": [ { "name": "{name}", "get": "({class_name}.som.GetAdcValue((int)daisy::patch_sm::{name_upper}))", "range": [ 0, 1 ], "bool": false } ] }, "Led": { "map_init": "{name}.Init(daisy::patch_sm::DaisyPatchSM::{pin}, {invert});\n\t\t{name}.Set(0.0f);", "typename": "daisy::Led", "direction": "out", "pin": "a", "invert": "true", "postprocess": "{name}.Update();", "mapping": [ { "name": "{name}", "set": "{class_name}.{name}.Set({value});" } ] }, "RgbLed": { "map_init": "{name}.Init(daisy::patch_sm::DaisyPatchSM::{pin_r}, daisy::patch_sm::DaisyPatchSM::{pin_g}, daisy::patch_sm::DaisyPatchSM::{pin_b}, {invert});\n\t\t{name}.Set(0.0f, 0.0f, 0.0f);", "typename": "daisy::RgbLed", "direction": "out", "pin": "r,g,b", "invert": "true", "postprocess": "{name}.Update();", "mapping": [ { "name": "{name}_red", "set": "{class_name}.{name}.SetRed({value});" }, { "name": "{name}_green", "set": "{class_name}.{name}.SetGreen({value});" }, { "name": "{name}_blue", "set": "{class_name}.{name}.SetBlue({value});" }, { "name": "{name}", "set": "{class_name}.{name}.Set(clamp(-{value}, 0.f, 1.f), 0.f, clamp({value}, 0.f, 1.f));" }, { "name": "{name}_white", "set": "{class_name}.{name}.Set({value},{value},{value});" } ] }, "GateOut": { "map_init": "{name}.Init(daisy::patch_sm::DaisyPatchSM::{pin}, {mode}, {pull});", "typename": "daisy::GPIO", "direction": "out", "pin": "a", "default_prefix": "som.", "mode": "daisy::GPIO::Mode::OUTPUT", "pull": "daisy::GPIO::Pull::NOPULL", "mapping": [ { "name": "{name}", "set": "{class_name}.{default_prefix}{name}.Write({value});" } ] }, "CVOuts": { "map_init": "{name}.bitdepth = {bitdepth};\n\t\t{name}.buff_state = {buff_state};\n\t\t{name}.mode = {mode};\n\t\t{name}.chn = {channel};\n\t\tsom.dac.Init({name});\n\t\tsom.dac.WriteValue({channel}, 0);", "typename": "daisy::DacHandle::Config", "direction": "out", "pin": "", "bitdepth": "daisy::DacHandle::BitDepth::BITS_12", "buff_state": "daisy::DacHandle::BufferState::ENABLED", "mode": "daisy::DacHandle::Mode::POLLING", "channel": "daisy::DacHandle::Channel::BOTH", "mapping": [ { "name": "{name}1", "set": "{class_name}.som.WriteCvOut(daisy::patch_sm::CV_OUT_1, {value} * 5.f);", "where": "main" }, { "name": "{name}2", "set": "{class_name}.som.WriteCvOut(daisy::patch_sm::CV_OUT_2, {value} * 5.f);", "where": "main" } ] }, "Tlv493d": { "map_init": "daisy::Tlv493dI2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n daisy::Tlv493dI2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}_main_conf.address = {address};\n {name}.Init({name}_main_conf);", "typename": "daisy::Tlv493dI2C", "direction": "in", "pin": "scl,sda", "address": "TLV493D_ADDRESS1", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "loopprocess": "{name}.UpdateData();", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.GetAmount()" }, { "name": "{name}_x", "get": "{class_name}.{name}.GetX()" }, { "name": "{name}_y", "get": "{class_name}.{name}.GetY()" }, { "name": "{name}_z", "get": "{class_name}.{name}.GetZ()" }, { "name": "{name}_amount", "get": "{class_name}.{name}.GetAmount()" }, { "name": "{name}_azimuth", "get": "{class_name}.{name}.GetAzimuth()" }, { "name": "{name}_polar", "get": "{class_name}.{name}.GetPolar()" } ] }, "Mpr121": { "map_init": "daisy::Mpr121I2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.dev_addr = {address};\n daisy::Mpr121I2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}_main_conf.touch_threshold = {touch_threshold};\n {name}_main_conf.release_threshold = {release_threshold};\n {name}.Init({name}_main_conf);", "typename": "daisy::Mpr121I2C", "direction": "in", "pin": "scl,sda", "address": "MPR121_I2CADDR_DEFAULT", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "touch_threshold": "MPR121_TOUCH_THRESHOLD_DEFAULT", "release_threshold": "MPR121_RELEASE_THRESHOLD_DEFAULT", "mapping": [ { "name": "{name}", "get": "(({class_name}.{name}.Touched() & 0x001) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch0", "get": "(({class_name}.{name}.Touched() & 0x001) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch1", "get": "(({class_name}.{name}.Touched() & 0x002) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch2", "get": "(({class_name}.{name}.Touched() & 0x004) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch3", "get": "(({class_name}.{name}.Touched() & 0x008) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch4", "get": "(({class_name}.{name}.Touched() & 0x010) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch5", "get": "(({class_name}.{name}.Touched() & 0x020) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch6", "get": "(({class_name}.{name}.Touched() & 0x040) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch7", "get": "(({class_name}.{name}.Touched() & 0x080) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch8", "get": "(({class_name}.{name}.Touched() & 0x100) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch9", "get": "(({class_name}.{name}.Touched() & 0x200) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch10", "get": "(({class_name}.{name}.Touched() & 0x400) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch11", "get": "(({class_name}.{name}.Touched() & 0x800) ? 1.0f : 0.f)", "where": "main" }, { "name": "{name}_ch0_raw", "get": "{class_name}.{name}.FilteredData(0)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch1_raw", "get": "{class_name}.{name}.FilteredData(1)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch2_raw", "get": "{class_name}.{name}.FilteredData(2)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch3_raw", "get": "{class_name}.{name}.FilteredData(3)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch4_raw", "get": "{class_name}.{name}.FilteredData(4)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch5_raw", "get": "{class_name}.{name}.FilteredData(5)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch6_raw", "get": "{class_name}.{name}.FilteredData(6)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch7_raw", "get": "{class_name}.{name}.FilteredData(7)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch8_raw", "get": "{class_name}.{name}.FilteredData(8)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch9_raw", "get": "{class_name}.{name}.FilteredData(9)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch10_raw", "get": "{class_name}.{name}.FilteredData(10)", "where": "main", "range": [ 0, 1023 ] }, { "name": "{name}_ch11_raw", "get": "{class_name}.{name}.FilteredData(11)", "where": "main", "range": [ 0, 1023 ] } ] }, "Apds9960": { "map_init": "daisy::Apds9960I2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n daisy::Apds9960I2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}.Init({name}_main_conf);", "typename": "daisy::Apds9960I2C", "direction": "in", "pin": "scl,sda", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.ReadGesture()", "where": "main" }, { "name": "{name}_gest", "get": "{class_name}.{name}.ReadGesture()", "where": "main" }, { "name": "{name}_prox", "get": "{class_name}.{name}.ReadProximity()", "where": "main" }, { "name": "{name}_red", "get": "{class_name}.{name}.GetColorDataRed()", "where": "main" }, { "name": "{name}_green", "get": "{class_name}.{name}.GetColorDataGreen()", "where": "main" }, { "name": "{name}_blue", "get": "{class_name}.{name}.GetColorDataBlue()", "where": "main" }, { "name": "{name}_clear", "get": "{class_name}.{name}.GetColorDataClear()", "where": "main" } ] }, "NeoTrellis": { "map_init": "daisy::NeoTrellisI2CTransport::Config {name}_config;\n {name}_config.periph = {periph};\n {name}_config.speed = {speed};\n {name}_config.scl = som.GetPin({pin_scl});\n {name}_config.sda = som.GetPin({pin_sda});\n {name}_config.address = {address};\n daisy::NeoTrellisI2C::Config {name}_main_conf;\n {name}_main_conf.transport_config = {name}_config;\n {name}.Init({name}_main_conf);", "typename": "daisy::NeoTrellisI2C", "direction": "in", "pin": "scl,sda", "address": "NEO_TRELLIS_ADDR", "periph": "daisy::I2CHandle::Config::Peripheral::I2C_1", "speed": "daisy::I2CHandle::Config::Speed::I2C_400KHZ", "loopprocess": "{name}.Process();", "mapping": [ { "name": "{name}", "get": "{class_name}.{name}.GetRising(0)", "bool": true }, { "name": "{name}_0", "get": "{class_name}.{name}.GetRising(0)", "bool": true }, { "name": "{name}_1", "get": "{class_name}.{name}.GetRising(1)", "bool": true }, { "name": "{name}_2", "get": "{class_name}.{name}.GetRising(2)", "bool": true }, { "name": "{name}_3", "get": "{class_name}.{name}.GetRising(3)", "bool": true }, { "name": "{name}_4", "get": "{class_name}.{name}.GetRising(4)", "bool": true }, { "name": "{name}_5", "get": "{class_name}.{name}.GetRising(5)", "bool": true }, { "name": "{name}_6", "get": "{class_name}.{name}.GetRising(6)", "bool": true }, { "name": "{name}_7", "get": "{class_name}.{name}.GetRising(7)", "bool": true }, { "name": "{name}_8", "get": "{class_name}.{name}.GetRising(8)", "bool": true }, { "name": "{name}_9", "get": "{class_name}.{name}.GetRising(9)", "bool": true }, { "name": "{name}_10", "get": "{class_name}.{name}.GetRising(10)", "bool": true }, { "name": "{name}_11", "get": "{class_name}.{name}.GetRising(11)", "bool": true }, { "name": "{name}_12", "get": "{class_name}.{name}.GetRising(12)", "bool": true }, { "name": "{name}_13", "get": "{class_name}.{name}.GetRising(13)", "bool": true }, { "name": "{name}_14", "get": "{class_name}.{name}.GetRising(14)", "bool": true }, { "name": "{name}_15", "get": "{class_name}.{name}.GetRising(15)", "bool": true }, { "name": "{name}_0_falling", "get": "{class_name}.{name}.GetFalling(0)", "bool": true }, { "name": "{name}_1_falling", "get": "{class_name}.{name}.GetFalling(1)", "bool": true }, { "name": "{name}_2_falling", "get": "{class_name}.{name}.GetFalling(2)", "bool": true }, { "name": "{name}_3_falling", "get": "{class_name}.{name}.GetFalling(3)", "bool": true }, { "name": "{name}_4_falling", "get": "{class_name}.{name}.GetFalling(4)", "bool": true }, { "name": "{name}_5_falling", "get": "{class_name}.{name}.GetFalling(5)", "bool": true }, { "name": "{name}_6_falling", "get": "{class_name}.{name}.GetFalling(6)", "bool": true }, { "name": "{name}_7_falling", "get": "{class_name}.{name}.GetFalling(7)", "bool": true }, { "name": "{name}_8_falling", "get": "{class_name}.{name}.GetFalling(8)", "bool": true }, { "name": "{name}_9_falling", "get": "{class_name}.{name}.GetFalling(9)", "bool": true }, { "name": "{name}_10_falling", "get": "{class_name}.{name}.GetFalling(10)", "bool": true }, { "name": "{name}_11_falling", "get": "{class_name}.{name}.GetFalling(11)", "bool": true }, { "name": "{name}_12_falling", "get": "{class_name}.{name}.GetFalling(12)", "bool": true }, { "name": "{name}_13_falling", "get": "{class_name}.{name}.GetFalling(13)", "bool": true }, { "name": "{name}_14_falling", "get": "{class_name}.{name}.GetFalling(14)", "bool": true }, { "name": "{name}_15_falling", "get": "{class_name}.{name}.GetFalling(15)", "bool": true }, { "name": "{name}_0_state", "get": "({class_name}.{name}.GetState(0) ? 1.0f : 0.0f)" }, { "name": "{name}_1_state", "get": "({class_name}.{name}.GetState(1) ? 1.0f : 0.0f)" }, { "name": "{name}_2_state", "get": "({class_name}.{name}.GetState(2) ? 1.0f : 0.0f)" }, { "name": "{name}_3_state", "get": "({class_name}.{name}.GetState(3) ? 1.0f : 0.0f)" }, { "name": "{name}_4_state", "get": "({class_name}.{name}.GetState(4) ? 1.0f : 0.0f)" }, { "name": "{name}_5_state", "get": "({class_name}.{name}.GetState(5) ? 1.0f : 0.0f)" }, { "name": "{name}_6_state", "get": "({class_name}.{name}.GetState(6) ? 1.0f : 0.0f)" }, { "name": "{name}_7_state", "get": "({class_name}.{name}.GetState(7) ? 1.0f : 0.0f)" }, { "name": "{name}_8_state", "get": "({class_name}.{name}.GetState(8) ? 1.0f : 0.0f)" }, { "name": "{name}_9_state", "get": "({class_name}.{name}.GetState(9) ? 1.0f : 0.0f)" }, { "name": "{name}_10_state", "get": "({class_name}.{name}.GetState(10) ? 1.0f : 0.0f)" }, { "name": "{name}_11_state", "get": "({class_name}.{name}.GetState(11) ? 1.0f : 0.0f)" }, { "name": "{name}_12_state", "get": "({class_name}.{name}.GetState(12) ? 1.0f : 0.0f)" }, { "name": "{name}_13_state", "get": "({class_name}.{name}.GetState(13) ? 1.0f : 0.0f)" }, { "name": "{name}_14_state", "get": "({class_name}.{name}.GetState(14) ? 1.0f : 0.0f)" }, { "name": "{name}_15_state", "get": "({class_name}.{name}.GetState(15) ? 1.0f : 0.0f)" } ] }, "NeoTrellisLeds": { "map_init": "", "parent": "", "direction": "out", "loopprocess": "{parent}.Show();", "mapping": [ { "name": "{name}", "set": "{class_name}.{parent}.SetPixelColor(0, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_0", "set": "{class_name}.{parent}.SetPixelColor(0, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_1", "set": "{class_name}.{parent}.SetPixelColor(1, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_2", "set": "{class_name}.{parent}.SetPixelColor(2, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_3", "set": "{class_name}.{parent}.SetPixelColor(3, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_4", "set": "{class_name}.{parent}.SetPixelColor(4, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_5", "set": "{class_name}.{parent}.SetPixelColor(5, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_6", "set": "{class_name}.{parent}.SetPixelColor(6, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_7", "set": "{class_name}.{parent}.SetPixelColor(7, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_8", "set": "{class_name}.{parent}.SetPixelColor(8, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_9", "set": "{class_name}.{parent}.SetPixelColor(9, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_10", "set": "{class_name}.{parent}.SetPixelColor(10, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_11", "set": "{class_name}.{parent}.SetPixelColor(11, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_12", "set": "{class_name}.{parent}.SetPixelColor(12, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_13", "set": "{class_name}.{parent}.SetPixelColor(13, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_14", "set": "{class_name}.{parent}.SetPixelColor(14, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" }, { "name": "{name}_15", "set": "{class_name}.{parent}.SetPixelColor(15, {class_name}.{parent}.pixels.Color({value}, {value}, {value}));", "where": "main" } ] } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/component_defs_petalsm.json0000644000000000000000000000515400000000000025571 0ustar00{ "Switch": { "map_init": "", "typename": "", "direction": "in", "index": 1, "updaterate": "", "mapping": [ { "name": "{name}_press", "get": "({class_name}.som.footswitch{index}.Pressed()?1.f:0.f)", "range": [ 0, 1 ], "bool": false }, { "name": "{name}", "get": "({class_name}.som.footswitch{index}.RisingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_fall", "get": "({class_name}.som.footswitch{index}.FallingEdge()?1.f:0.f)", "range": [ 0, 1 ], "bool": true }, { "name": "{name}_seconds", "get": "({class_name}.som.footswitch{index}.TimeHeldMs()*0.001f)", "bool": false } ] }, "Switch3": { "map_init": "", "typename": "", "direction": "in", "index": 0, "mapping": [ { "name": "{name}", "get": "({class_name}.som.toggle[{index}].Read())", "range": [ 0, 2 ], "bool": false } ] }, "AnalogControl": { "init_single": "", "map_init": "", "typename": "", "direction": "in", "index": 0, "updaterate": "", "mapping": [ { "name": "{name}", "get": "({class_name}.som.knob[{index}].Value())", "range": [ 0, 1 ], "bool": false } ] }, "Expression": { "map_init": "", "typename": "", "direction": "in", "mapping": [ { "name": "{name}", "get": "({class_name}.som.GetExpressionValue())" } ] }, "Led": { "map_init": "", "typename": "", "direction": "out", "index": 2, "postprocess": "", "mapping": [ { "name": "{name}", "set": "{class_name}.som.led[{index}].Set({value});" } ] }, "RgbLed": { "map_init": "", "typename": "", "direction": "out", "index": "r,g,b", "mapping": [ { "name": "{name}", "set": "{class_name}.som.led[{index_r}].Set({value}); \n{class_name}.som.led[{index_g}].Set({value}); \n{class_name}.som.led[{index_b}].Set({value});" }, { "name": "{name}_red", "set": "{class_name}.som.led[{index_r}].Set({value});" }, { "name": "{name}_green", "set": "{class_name}.som.led[{index_g}].Set({value});" }, { "name": "{name}_blue", "set": "{class_name}.som.led[{index_b}].Set({value});" }, { "name": "{name}_white", "set": "{class_name}.som.led[{index_r}].Set({value}); \n{class_name}.som.led[{index_g}].Set({value}); \n{class_name}.som.led[{index_b}].Set({value});" } ] }, "Relay": { "map_init": "", "typename": "", "direction": "out", "mapping": [ { "name": "{name}", "set": "{class_name}.som.SetBypassState({value});" } ] } }hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/field.json0000644000000000000000000001542500000000000022126 0ustar00{ "name": "field", "som": "seed", "defines": { "HAS_MIDI": 1 }, "display": {}, "audio": { "channels": 2 }, "parents": { "i2c": { "component": "i2c", "pin": { "scl": 11, "sda": 12 } }, "led_driver": { "component": "PCA9685", "address": "{0x00, 0x02}", "parent": "i2c", "driver_count": 2 }, "pad_shift": { "component": "CD4021", "driver_count": 2, "pin": { "clk": 28, "cs": 27, "data": 26 } }, "pot_mux": { "component": "CD4051", "mux_count": 8, "pin": { "adc": 16, "sel0": 21, "sel1": 20, "sel2": 19 } } }, "components": { "sw1": { "component": "Switch", "pin": 30 }, "sw2": { "component": "Switch", "pin": 29 }, "cv1": { "component": "AnalogControlBipolar", "pin": 17 }, "cv2": { "component": "AnalogControlBipolar", "pin": 18 }, "cv3": { "component": "AnalogControlBipolar", "pin": 25 }, "cv4": { "component": "AnalogControlBipolar", "pin": 24 }, "knob1": { "component": "CD4051AnalogControl", "index": 0, "parent": "pot_mux" }, "knob2": { "component": "CD4051AnalogControl", "index": 3, "parent": "pot_mux" }, "knob3": { "component": "CD4051AnalogControl", "index": 1, "parent": "pot_mux" }, "knob4": { "component": "CD4051AnalogControl", "index": 4, "parent": "pot_mux" }, "knob5": { "component": "CD4051AnalogControl", "index": 2, "parent": "pot_mux" }, "knob6": { "component": "CD4051AnalogControl", "index": 5, "parent": "pot_mux" }, "knob7": { "component": "CD4051AnalogControl", "index": 6, "parent": "pot_mux" }, "knob8": { "component": "CD4051AnalogControl", "index": 7, "parent": "pot_mux" }, "cvout1": { "component": "CVOuts" }, "cvout2": { "component": "CVOuts" }, "gatein": { "component": "GateIn", "pin": 0 }, "gateout": { "component": "GateOut", "pin": 15 }, "pada1": { "component": "CD4021Switch", "parent": "pad_shift", "index": 15 }, "pada2": { "component": "CD4021Switch", "parent": "pad_shift", "index": 14 }, "pada3": { "component": "CD4021Switch", "parent": "pad_shift", "index": 13 }, "pada4": { "component": "CD4021Switch", "parent": "pad_shift", "index": 12 }, "pada5": { "component": "CD4021Switch", "parent": "pad_shift", "index": 11 }, "pada6": { "component": "CD4021Switch", "parent": "pad_shift", "index": 10 }, "pada7": { "component": "CD4021Switch", "parent": "pad_shift", "index": 9 }, "pada8": { "component": "CD4021Switch", "parent": "pad_shift", "index": 8 }, "padb1": { "component": "CD4021Switch", "parent": "pad_shift", "index": 7 }, "padb2": { "component": "CD4021Switch", "parent": "pad_shift", "index": 6 }, "padb3": { "component": "CD4021Switch", "parent": "pad_shift", "index": 5 }, "padb4": { "component": "CD4021Switch", "parent": "pad_shift", "index": 4 }, "padb5": { "component": "CD4021Switch", "parent": "pad_shift", "index": 3 }, "padb6": { "component": "CD4021Switch", "parent": "pad_shift", "index": 2 }, "padb7": { "component": "CD4021Switch", "parent": "pad_shift", "index": 1 }, "padb8": { "component": "CD4021Switch", "parent": "pad_shift", "index": 0 }, "led_key_b1": { "component": "PCA9685Led", "index": 15, "parent": "led_driver" }, "led_key_b2": { "component": "PCA9685Led", "index": 14, "parent": "led_driver" }, "led_key_b3": { "component": "PCA9685Led", "index": 13, "parent": "led_driver" }, "led_key_b4": { "component": "PCA9685Led", "index": 12, "parent": "led_driver" }, "led_key_b5": { "component": "PCA9685Led", "index": 11, "parent": "led_driver" }, "led_key_b6": { "component": "PCA9685Led", "index": 10, "parent": "led_driver" }, "led_key_b7": { "component": "PCA9685Led", "index": 9, "parent": "led_driver" }, "led_key_b8": { "component": "PCA9685Led", "index": 8, "parent": "led_driver" }, "led_key_a1": { "component": "PCA9685Led", "index": 0, "parent": "led_driver" }, "led_key_a2": { "component": "PCA9685Led", "index": 1, "parent": "led_driver" }, "led_key_a3": { "component": "PCA9685Led", "index": 2, "parent": "led_driver" }, "led_key_a4": { "component": "PCA9685Led", "index": 3, "parent": "led_driver" }, "led_key_a5": { "component": "PCA9685Led", "index": 4, "parent": "led_driver" }, "led_key_a6": { "component": "PCA9685Led", "index": 5, "parent": "led_driver" }, "led_key_a7": { "component": "PCA9685Led", "index": 6, "parent": "led_driver" }, "led_key_a8": { "component": "PCA9685Led", "index": 7, "parent": "led_driver" }, "led_knob_1": { "component": "PCA9685Led", "index": 16, "parent": "led_driver" }, "led_knob_2": { "component": "PCA9685Led", "index": 17, "parent": "led_driver" }, "led_knob_3": { "component": "PCA9685Led", "index": 18, "parent": "led_driver" }, "led_knob_4": { "component": "PCA9685Led", "index": 19, "parent": "led_driver" }, "led_knob_5": { "component": "PCA9685Led", "index": 20, "parent": "led_driver" }, "led_knob_6": { "component": "PCA9685Led", "index": 21, "parent": "led_driver" }, "led_knob_7": { "component": "PCA9685Led", "index": 22, "parent": "led_driver" }, "led_knob_8": { "component": "PCA9685Led", "index": 23, "parent": "led_driver" } }, "aliases": { "cvout": "cvout1", "switch": "sw1", "button": "sw1", "switch1": "sw1", "button1": "sw1", "switch2": "sw2", "button2": "sw2", "encswitch": "encoder_rise", "enp": "encoder_press", "switch3": "encoder_rise", "press": "encoder_press", "knob": "knob1", "ctrl": "knob1", "ctrl1": "knob1", "ctrl2": "knob2", "led": "led1" } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/patch.json0000644000000000000000000000257300000000000022142 0ustar00{ "name": "patch", "som": "seed", "defines": { "HAS_MIDI": 1 }, "display": {}, "audio": { "channels": 4 }, "external_codecs": [ { "periph": "SAI_2", "a_sync": "SLAVE", "b_sync": "MASTER", "a_dir": "TRANSMIT", "b_dir": "RECEIVE", "pin": { "fs": 27, "mclk": 24, "sck": 28, "sb": 25, "sa": 26 } } ], "components": { "knob1": { "component": "AnalogControl", "pin": 15, "flip": "true" }, "knob2": { "component": "AnalogControl", "pin": 16, "flip": "true" }, "knob3": { "component": "AnalogControl", "pin": 21, "flip": "true" }, "knob4": { "component": "AnalogControl", "pin": 18, "flip": "true" }, "encoder": { "component": "Encoder", "pin": { "a": 12, "b": 11, "click": 0 } }, "gateout": { "component": "GateOut", "pin": 17, "display": "" }, "cvout1": { "component": "CVOuts" }, "cvout2": { "component": "CVOuts" }, "gatein1": { "component": "GateIn", "pin": 20 }, "gatein2": { "component": "GateIn", "pin": 19 } }, "aliases": { "gate": "gatein1", "gate1": "gatein1", "gate2": "gatein2", "cvout": "cvout1", "encswitch": "encoder_rise", "enp": "encoder_press", "press": "encoder_press", "knob": "knob1", "ctrl": "knob1", "ctrl1": "knob1", "ctrl2": "knob2", "ctrl3": "knob3", "ctrl4": "knob4" } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/patch_init.json0000644000000000000000000000460100000000000023157 0ustar00{ "name": "patch_init", "som": "patch_sm", "defines": {}, "audio": { "channels": 2 }, "components": { "cv_1": { "component": "AnalogControl", "pin": "C5", "default": true }, "cv_2": { "component": "AnalogControl", "pin": "C4", "default": true }, "cv_3": { "component": "AnalogControl", "pin": "C3", "default": true }, "cv_4": { "component": "AnalogControl", "pin": "C2", "default": true }, "cv_5": { "component": "AnalogControl", "pin": "C6", "default": true }, "cv_6": { "component": "AnalogControl", "pin": "C7", "default": true }, "cv_7": { "component": "AnalogControl", "pin": "C8", "default": true }, "cv_8": { "component": "AnalogControl", "pin": "C9", "default": true }, "adc_9": { "component": "AnalogControl", "pin": "A2", "default": true }, "adc_10": { "component": "AnalogControl", "pin": "A3", "default": true }, "adc_11": { "component": "AnalogControl", "pin": "D9", "default": true }, "adc_12": { "component": "AnalogControl", "pin": "D8", "default": true }, "gate_out_1": { "component": "GateOut", "pin": "B5", "display": "", "default": true }, "gate_out_2": { "component": "GateOut", "pin": "B6", "display": "", "default": true }, "cvout1": { "component": "CVOuts", "default": true }, "cvout2": { "component": "CVOuts", "default": true }, "gate_in_1": { "component": "GateIn", "pin": "B10", "default": true }, "gate_in_2": { "component": "GateIn", "pin": "B9", "default": true }, "sw1": { "component": "Switch", "pin": "B7" }, "sw2": { "component": "Switch", "pin": "B8" } }, "aliases": { "switch": "sw1", "switch1": "sw1", "switch2": "sw2", "button": "sw1", "toggle": "sw2", "gate": "gate_in_1", "gate1": "gate_in_1", "gate2": "gate_in_2", "gateout": "gate_out_1", "gateout1": "gate_out_1", "gateout2": "gate_out_2", "cvout": "cvout1", "cv_out_1": "cvout1", "cv_out_2": "cvout2", "knob": "cv_1", "knob1": "cv_1", "knob2": "cv_2", "knob3": "cv_3", "knob4": "cv_4", "knob5": "cv_5", "knob6": "cv_6", "knob7": "cv_7", "knob8": "cv_8", "ctrl": "cv_1", "ctrl1": "cv_1", "ctrl2": "cv_2", "ctrl3": "cv_3", "ctrl4": "cv_4", "ctrl5": "cv_5", "ctrl6": "cv_6", "ctrl7": "cv_7", "ctrl8": "cv_8" } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/petal.json0000644000000000000000000000725200000000000022147 0ustar00{ "name": "petal", "som": "seed", "parents": { "i2c": { "component": "i2c", "pin": { "scl": 11, "sda": 12 } }, "led_driver": { "component": "PCA9685", "address": "{0x00, 0x01}", "parent": "i2c", "driver_count": 2 } }, "audio": { "channels": 2 }, "components": { "sw1": { "component": "Switch", "pin": 8 }, "sw2": { "component": "Switch", "pin": 9 }, "sw3": { "component": "Switch", "pin": 10 }, "sw4": { "component": "Switch", "pin": 13 }, "sw5": { "component": "Switch", "pin": 25 }, "sw6": { "component": "Switch", "pin": 26 }, "sw7": { "component": "Switch", "pin": 7 }, "encoder": { "component": "Encoder", "pin": { "a": 28, "b": 27, "click": 14 } }, "knob1": { "component": "AnalogControl", "pin": 16 }, "knob2": { "component": "AnalogControl", "pin": 19 }, "knob3": { "component": "AnalogControl", "pin": 17 }, "knob4": { "component": "AnalogControl", "pin": 20 }, "knob5": { "component": "AnalogControl", "pin": 18 }, "knob6": { "component": "AnalogControl", "pin": 21 }, "expression": { "component": "AnalogControl", "pin": 15 }, "led_ring_1": { "component": "PCA9685RgbLed", "index": { "red": 0, "green": 1, "blue": 2 }, "parent": "led_driver" }, "led_ring_2": { "component": "PCA9685RgbLed", "index": { "red": 6, "green": 7, "blue": 8 }, "parent": "led_driver" }, "led_ring_3": { "component": "PCA9685RgbLed", "index": { "red": 12, "green": 13, "blue": 14 }, "parent": "led_driver" }, "led_ring_4": { "component": "PCA9685RgbLed", "index": { "red": 16, "green": 17, "blue": 18 }, "parent": "led_driver" }, "led_ring_5": { "component": "PCA9685RgbLed", "index": { "red": 3, "green": 4, "blue": 5 }, "parent": "led_driver" }, "led_ring_6": { "component": "PCA9685RgbLed", "index": { "red": 9, "green": 10, "blue": 11 }, "parent": "led_driver" }, "led_ring_7": { "component": "PCA9685RgbLed", "index": { "red": 19, "green": 20, "blue": 21 }, "parent": "led_driver" }, "led_ring_8": { "component": "PCA9685RgbLed", "index": { "red": 22, "green": 23, "blue": 24 }, "parent": "led_driver" }, "led_fs_1": { "component": "PCA9685Led", "index": 15, "parent": "led_driver" }, "led_fs_2": { "component": "PCA9685Led", "index": 25, "parent": "led_driver" }, "led_fs_3": { "component": "PCA9685Led", "index": 26, "parent": "led_driver" }, "led_fs_4": { "component": "PCA9685Led", "index": 27, "parent": "led_driver" } }, "aliases": { "switch": "sw1", "switch1": "sw1", "switch2": "sw2", "switch3": "sw3", "switch4": "sw4", "switch5": "sw5", "switch6": "sw6", "switch7": "sw7", "encswitch": "encoder_rise", "enp": "encoder_press", "press": "encoder_press", "knob": "knob1", "ctrl": "knob1", "ctrl1": "knob1", "ctrl2": "knob2", "ctrl3": "knob3", "ctrl4": "knob4", "ctrl5": "knob5", "ctrl6": "knob6" } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/petal_125b_sm.json0000644000000000000000000000361200000000000023373 0ustar00{ "name": "petal_125b_sm", "som": "petal_125b_sm", "audio": { "channels": 2 }, "components": { "knob_1": { "component": "AnalogControl", "index": 0, "is_default": true }, "knob_2": { "component": "AnalogControl", "index": 1, "is_default": true }, "knob_3": { "component": "AnalogControl", "index": 2, "is_default": true }, "knob_4": { "component": "AnalogControl", "index": 3, "is_default": true }, "knob_5": { "component": "AnalogControl", "index": 4, "is_default": true }, "knob_6": { "component": "AnalogControl", "index": 5, "is_default": true }, "expression": { "component": "Expression", "is_default": true }, "toggle_1": { "component": "Switch3", "index": 0, "is_default": true }, "toggle_2": { "component": "Switch3", "index": 1, "is_default": true }, "toggle_3": { "component": "Switch3", "index": 2, "is_default": true }, "footswitch_1": { "component": "Switch", "index": 1, "is_default": true }, "footswitch_2": { "component": "Switch", "index": 2, "is_default": true }, "led1": { "component": "RgbLed", "index": {"r": 0, "g": 1, "b": 2}, "is_default": true }, "led2": { "component": "Led", "index": 3, "is_default": true }, "led3": { "component": "RgbLed", "index": {"r": 4, "g": 5, "b": 6}, "is_default": true }, "relay": { "component": "Relay", "is_default": true } }, "aliases": { "knob1": "knob_1", "knob2": "knob_2", "knob3": "knob_3", "knob4": "knob_4", "knob5": "knob_5", "knob6": "knob_6", "sw1": "toggle_1", "sw2": "toggle_2", "sw3": "toggle_3" } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/resources/pod.json0000644000000000000000000000174300000000000021623 0ustar00{ "name": "pod", "som": "seed", "defines": { "HAS_MIDI": 1 }, "display": {}, "audio": { "channels": 2 }, "components": { "sw1": { "component": "Switch", "pin": 27 }, "sw2": { "component": "Switch", "pin": 28 }, "knob1": { "component": "AnalogControl", "pin": 21 }, "knob2": { "component": "AnalogControl", "pin": 15 }, "encoder": { "component": "Encoder", "pin": { "a": 26, "b": 25, "click": 13 } }, "led1": { "component": "RgbLed", "pin": { "r": 20, "g": 19, "b": 18 } }, "led2": { "component": "RgbLed", "pin": { "r": 17, "g": 24, "b": 23 } } }, "aliases": { "switch": "sw1", "button": "sw1", "switch1": "sw1", "button1": "sw1", "switch2": "sw2", "button2": "sw2", "encswitch": "encoder_rise", "enp": "encoder_press", "press": "encoder_press", "knob": "knob1", "ctrl": "knob1", "ctrl1": "knob1", "ctrl2": "knob2", "led": "led1" } } hvcc-0.16.0/hvcc/generators/c2daisy/json2daisy/templates/daisy.h0000644000000000000000000001736000000000000021416 0ustar00{{license}} #ifndef __JSON2DAISY_{{name|upper}}_H__ #define __JSON2DAISY_{{name|upper}}_H__ {% if som == 'seed' %} #include "daisy_seed.h" #include "dev/codec_ak4556.h" {% elif som == 'patch_sm' %} #include "daisy_patch_sm.h" {% elif som == 'petal_125b_sm' %} #include "daisy_petal_125b_sm.h" {% endif %} {{display_conditional}} #define ANALOG_COUNT {{analogcount}} namespace json2daisy { {{non_class_declarations}} struct Daisy{{ name|capitalize }} { /** Initializes the board according to the JSON board description * \param boost boosts the clock speed from 400 to 480 MHz */ void Init(bool boost=true) { {% if som == 'seed' %} som.Configure(); som.Init(boost); {% else %} som.Init(); {% endif %} {% if init != '' %} {{init}} {% endif %} {% if i2c != '' %} // i2c {{ i2c }} {% endif %} {% if PCA9685 != '' %} // LED Drivers {{ PCA9685 }} {% endif %} {% if Switch != '' %} // Switches {{ Switch }} {% endif %} {% if Switch3 != '' %} // SPDT Switches {{ Switch3 }} {% endif %} {% if CD4021 != '' %} // Muxes {{ CD4021 }} {% endif %} {% if GateIn != '' %} // Gate ins {{ GateIn }} {% endif %} {% if Encoder != '' %} // Rotary encoders {{ Encoder }} {% endif %} {% if init_single != '' %} // Single channel ADC initialization {{ init_single }} {% endif %} {% if som == 'seed' %} {% if analogcount > 0 %} som.adc.Init(cfg, ANALOG_COUNT); {% endif %} {% endif %} {% if ctrl_init != '' %} // AnalogControl objects {{ ctrl_init }} {% endif %} {% if CD4051AnalogControl != '' %} // Multiplexed AnlogControl objects {{ CD4051AnalogControl }} {% endif %} {% if Led != '' %} // LEDs {{ Led }} {% endif %} {% if RgbLed != '' %} // RBG LEDs {{ RgbLed }} {% endif %} {% if GateOut != '' %} // Gate outs {{ GateOut }} {% endif %} {% if CVOuts != '' %} // DAC {{ CVOuts }} {% endif %} {% if display != '' %} // Display {{ display }} {% endif %} {% if Tlv493d != '' %} // Accelerometer {{ Tlv493d }} {% endif %} {% if Mpr121 != '' %} // Capacitive sensor {{ Mpr121 }} {% endif %} {% if Apds9960 != '' %} // Gesture / color sensor {{ Apds9960 }} {% endif %} {% if Dps310 != '' %} // Dps310 pressure / temperature sensor {{ Dps310 }} {% endif %} {% if NeoTrellis != '' %} // Adafruit Neo Trellis {{ NeoTrellis }} {% endif %} {% if Icm20948 != '' %} // Icm20948 9-DOF sensor {{ Icm20948 }} {% endif %} {% if som == 'seed' and external_codecs|length > 0 %} // External Codec Initialization daisy::SaiHandle::Config sai_config[{{ 1 + external_codecs|length }}]; // Internal Codec sai_config[0].periph = daisy::SaiHandle::Config::Peripheral::SAI_1; sai_config[0].sr = daisy::SaiHandle::Config::SampleRate::SAI_48KHZ; sai_config[0].bit_depth = daisy::SaiHandle::Config::BitDepth::SAI_24BIT; sai_config[0].a_sync = daisy::SaiHandle::Config::Sync::MASTER; sai_config[0].b_sync = daisy::SaiHandle::Config::Sync::SLAVE; sai_config[0].a_dir = daisy::SaiHandle::Config::Direction::TRANSMIT; sai_config[0].b_dir = daisy::SaiHandle::Config::Direction::RECEIVE; sai_config[0].pin_config.fs = daisy::Pin(daisy::PORTE, 4); sai_config[0].pin_config.mclk = daisy::Pin(daisy::PORTE, 2); sai_config[0].pin_config.sck = daisy::Pin(daisy::PORTE, 5); sai_config[0].pin_config.sa = daisy::Pin(daisy::PORTE, 6); sai_config[0].pin_config.sb = daisy::Pin(daisy::PORTE, 3); {% for codec in external_codecs %} sai_config[{{loop.index}}].periph = daisy::SaiHandle::Config::Peripheral::{{codec.periph}}; sai_config[{{loop.index}}].sr = daisy::SaiHandle::Config::SampleRate::SAI_48KHZ; sai_config[{{loop.index}}].bit_depth = daisy::SaiHandle::Config::BitDepth::SAI_24BIT; sai_config[{{loop.index}}].a_sync = daisy::SaiHandle::Config::Sync::{{codec.a_sync}}; sai_config[{{loop.index}}].b_sync = daisy::SaiHandle::Config::Sync::{{codec.b_sync}}; sai_config[{{loop.index}}].a_dir = daisy::SaiHandle::Config::Direction::{{codec.a_dir}}; sai_config[{{loop.index}}].b_dir = daisy::SaiHandle::Config::Direction::{{codec.b_dir}}; sai_config[{{loop.index}}].pin_config.fs = som.GetPin({{codec.pin.fs}}); sai_config[{{loop.index}}].pin_config.mclk = som.GetPin({{codec.pin.mclk}}); sai_config[{{loop.index}}].pin_config.sck = som.GetPin({{codec.pin.sck}}); sai_config[{{loop.index}}].pin_config.sa = som.GetPin({{codec.pin.sa}}); sai_config[{{loop.index}}].pin_config.sb = som.GetPin({{codec.pin.sb}}); {% endfor %} daisy::SaiHandle sai_handle[{{ 1 + external_codecs|length }}]; sai_handle[0].Init(sai_config[0]); {% for codec in external_codecs %} sai_handle[{{loop.index}}].Init(sai_config[{{loop.index}}]); {% endfor %} daisy::Pin codec_reset_pin = som.GetPin(29); daisy::Ak4556 codec; codec.Init(codec_reset_pin); daisy::AudioHandle::Config cfg; cfg.blocksize = 48; cfg.samplerate = daisy::SaiHandle::Config::SampleRate::SAI_48KHZ; cfg.postgain = 0.5f; som.audio_handle.Init( cfg, sai_handle[0] {% for codec in external_codecs %} ,sai_handle[{{loop.index}}] {% endfor %} ); {% endif %} {% if som == 'seed' %} {% if analogcount > 0 %} som.adc.Start(); {% endif %} {% endif %} } /** Handles all the controls processing that needs to occur at the block rate * */ void ProcessAllControls() { {% if process != '' %} {{ process }} {% endif %} {% if som != 'seed' %} som.ProcessAllControls(); {% endif %} } /** Handles all the maintenance processing. This should be run last within the audio callback. * */ void PostProcess() { {{postprocess}} {% if som == 'petal_125b_sm' %} som.UpdateLeds(); {% endif %} } /** Handles processing that shouldn't occur in the audio block, such as blocking transfers * */ void LoopProcess() { {{loopprocess}} } /** Sets the audio sample rate * \param sample_rate the new sample rate in Hz */ void SetAudioSampleRate(size_t sample_rate) { {% if som == 'seed' or som == 'petal_125b_sm' %} daisy::SaiHandle::Config::SampleRate enum_rate; if (sample_rate >= 96000) enum_rate = daisy::SaiHandle::Config::SampleRate::SAI_96KHZ; else if (sample_rate >= 48000) enum_rate = daisy::SaiHandle::Config::SampleRate::SAI_48KHZ; else if (sample_rate >= 32000) enum_rate = daisy::SaiHandle::Config::SampleRate::SAI_32KHZ; else if (sample_rate >= 16000) enum_rate = daisy::SaiHandle::Config::SampleRate::SAI_16KHZ; else enum_rate = daisy::SaiHandle::Config::SampleRate::SAI_8KHZ; som.SetAudioSampleRate(enum_rate); {% elif som == 'patch_sm' %} som.SetAudioSampleRate(sample_rate); {% endif %} {{hidupdaterates}} } /** Sets the audio block size * \param block_size the new block size in words */ inline void SetAudioBlockSize(size_t block_size) { som.SetAudioBlockSize(block_size); } /** Starts up the audio callback process with the given callback * */ inline void StartAudio(daisy::AudioHandle::AudioCallback cb) { som.StartAudio(cb); } /** This is the board's "System On Module" */ {{som_class}} som; {% if som == 'seed' %} daisy::AdcChannelConfig cfg[ANALOG_COUNT]; {% endif %} // I/O Components {{comps}} {{dispdec}} {{midi}} }; } // namspace json2daisy #endif // __JSON2DAISY_{{name|upper}}_H__ hvcc-0.16.0/hvcc/generators/c2daisy/parameters.py0000644000000000000000000002456600000000000016574 0ustar00import json from copy import deepcopy from typing import Any, Dict, Optional from hvcc.core.hv2ir.HeavyLangObject import HeavyLangObject from hvcc.types.compiler import ExternParams def filter_match( set: Dict, key: str, match: str, key_exclude: Optional[str] = None, match_exclude: Optional[str] = None ) -> filter: if (key_exclude is not None and match_exclude is not None): return filter(lambda x: x.get(key, '') == match and x.get(key_exclude, '') != match_exclude, set) else: return filter(lambda x: x.get(key, '') == match, set) def verify_param_exists(name: str, original_name: str, components: Dict, input: bool = True) -> Any: for comp in components: # Dealing with the cvouts the way we have it set up is really annoying if comp['component'] == 'CVOuts': if name == comp['name']: if input: raise TypeError( f'Parameter "{original_name}" cannot be used as an {"input" if input else "output"}') return else: variants = [mapping['name'].format_map( {'name': comp['name']}) for mapping in comp['mapping']] if name in variants: if input and comp['direction'] == 'output' or not input and comp['direction'] == 'input': raise TypeError( f'Parameter "{original_name}" cannot be used as an {"input" if input else "output"}') return raise NameError(f'Unknown parameter "{original_name}"') def verify_param_direction(name: str, components: Dict) -> bool: for comp in components: if comp['component'] == 'CVOuts': if name == comp['name']: return True else: variants = [mapping['name'].format_map( {'name': comp['name']}) for mapping in comp['mapping']] if name in variants: return True return False def get_root_component(variant: str, original_name: str, components: Dict) -> str: for comp in components: if comp['component'] == 'CVOuts': if variant == comp['name']: return variant else: variants = [mapping['name'].format_map( {'name': comp['name']}) for mapping in comp['mapping']] if variant in variants: return comp['name'] raise NameError(f'Unknown parameter "{original_name}"') def get_component_mapping( component_variant: str, original_name: str, component: Dict, components: Dict ) -> Dict: for variant in component['mapping']: if component['component'] == 'CVOuts': stripped = variant['name'].format_map({'name': ''}) if stripped in component['name']: return variant elif variant['name'].format_map({'name': component['name']}) == component_variant: return variant raise NameError(f'Unknown parameter "{original_name}"') def verify_param_used( component: Dict, params_in: Dict, params_out: Dict, params_in_original_name: Dict, params_out_original_name: Dict, components: Dict ) -> bool: # Exclude parents, since they don't have 1-1 i/o mapping if component.get('is_parent', False): return True for param in {**params_in, **params_out}: root = get_root_component( param, ({**params_in_original_name, **params_out_original_name})[param], components) if root == component['name']: return True return False def de_alias( name: str, aliases: Dict, components: Dict ) -> str: low = name.lower() # simple case if low in aliases: return aliases[low] # aliased variant potential_aliases = list(filter(lambda x: x in low, aliases)) for alias in potential_aliases: try: target_component = list(filter_match( components, 'name', aliases[alias]))[0] # The CVOuts setup really bothers me if target_component['component'] != 'CVOuts': for mapping in target_component['mapping']: if mapping['name'].format_map({'name': alias}) == low: return mapping['name'].format_map({'name': aliases[alias]}) except IndexError: # No matching alias from filter pass # otherwise, it's a direct parameter or unkown one return low def parse_parameters( parameters: ExternParams, components: Dict, aliases: Dict, object_name: str ) -> Dict: """ Parses the `parameters` passed from hvcc and generates getters and setters according to the info in `components`. The `aliases` help disambiguate parameters and the `object_name` sets the identifier for the generated Daisy hardware class, in this case `hardware`. """ # Verify that the params are valid and remove unused components replacements: Dict = {} params_in: Dict = {} params_in_original_names: Dict = {} for key, recv in parameters.inParam: de_aliased = de_alias(key, aliases, components) params_in[de_aliased] = recv params_in_original_names[de_aliased] = key params_out = {} params_out_original_names = {} for key, msg in parameters.outParam: de_aliased = de_alias(key, aliases, components) params_out[de_aliased] = msg params_out_original_names[de_aliased] = key [verify_param_exists(key, params_in_original_names[key], components, input=True) for key in params_in] [verify_param_exists(key, params_out_original_names[key], components, input=False) for key in params_out] for i in range(len(components) - 1, -1, -1): if not verify_param_used( components[i], params_in, params_out, params_in_original_names, params_out_original_names, components): components.pop(i) out_idx = 0 replacements['parameters'] = [] replacements['output_parameters'] = [] replacements['loop_write_in'] = [] replacements['callback_write_out'] = [] replacements['loop_write_out'] = [] replacements['hook_write_out'] = [] replacements['callback_write_in'] = [] for param_name, param in params_in.items(): root = get_root_component( param_name, params_in_original_names[param_name], components) component = list(filter_match(components, 'name', root))[0] param_struct = { "hash_enum": params_in_original_names[param_name], 'name': root, 'type': component['component'].upper()} replacements['parameters'].append(param_struct) mapping = get_component_mapping( param_name, params_in_original_names[param_name], component, components) write_location = 'callback_write_in' if mapping.get( 'where', 'callback') == 'callback' else 'loop_write_in' component_info = deepcopy(component) component_info['name'] = root component_info['class_name'] = object_name # A bit of a hack to get cv_1, etc to be written as CV_1 component_info['name_upper'] = root.upper() component_info['value'] = f'output_data[{out_idx}]' component_info['default_prefix'] = component.get( "default_prefix", '') if component.get('default', False) else '' process = mapping["get"].format_map(component_info) replacements[write_location].append( {"process": process, "bool": mapping.get('bool', False), "hash_enum": params_in_original_names[param_name]}) for param_name, param in params_out.items(): root = get_root_component( param_name, params_out_original_names[param_name], components) component = list(filter_match(components, 'name', root))[0] mapping = get_component_mapping( param_name, params_out_original_names[param_name], component, components) default_prefix = component.get( "default_prefix", '') if component.get('default', False) else '' write_locations = {'callback': 'callback_write_out', 'loop': 'loop_write_out', 'hook': 'hook_write_out'} write_location = write_locations.get(mapping.get('where', 'callback'), 'callback_write_out') param_struct = { 'hash_enum': params_out_original_names[param_name], 'index': out_idx, 'name': param_name, 'hook': write_location == 'hook_write_out'} replacements['output_parameters'].append(param_struct) component_info = deepcopy(component) component_info['hash_enum'] = params_out_original_names[param_name] component_info['name'] = root component_info['class_name'] = object_name component_info['value'] = f'output_data[{out_idx}]' if \ write_location != 'hook_write_out' else 'sig' component_info['default_prefix'] = default_prefix write = mapping["set"].format_map(component_info) replacements[write_location].append( {"name": param_name, "process": write, "bool": mapping.get('bool', False), "value": component_info['value']}) out_idx += 1 replacements['output_comps'] = len(replacements['output_parameters']) return replacements def display_parameters(description_file: str) -> dict[str, str]: """ Optional list of externed parameters that will be filtered out of the hardware configuration. These will be passed on to the sendHook callback and can be used by the Display function. """ with open(description_file, 'rb') as file: daisy_description = json.load(file) try: params = { param: "0x{0:X}".format(HeavyLangObject.get_hash(param)) for param in daisy_description['display']['params'] } except KeyError: return {} return params def display_processor(description_file: Optional[str] = None) -> str: """ Try to load display processing code from file. """ if description_file is None: raise ValueError('description_file not provided') with open(description_file, 'rb') as file: daisy_description = json.load(file) process_file = daisy_description['display']['process_file'] with open(process_file, 'rb') as f: return f.read().decode('utf-8') hvcc-0.16.0/hvcc/generators/c2daisy/static/README.md0000644000000000000000000001725300000000000016620 0ustar00# Daisy To build this code, navigate into the source folder and run `make`. Flashing can be done over USB with `make program-dfu`. Make sure your Daisy is in DFU mode ([check this out if you're not sure how to do that](https://github.com/electro-smith/DaisyWiki/wiki/1.-Setting-Up-Your-Development-Environment#4-Run-the-Blink-Example)). If you have an ST-Link or other JTAG programmer, you can use `make program`. If you've made hardware based on the Daisy Seed or Patch Submodule, you can supply custom json for the board description. # Interacting with the Daisy I/O Each board has a selection of physical I/O that can interact with your PD patch. Most components have an _alias_, which allows you to refer to the same input/output by different names if you have a preference. All names and aliases are _case insensitive_, so you can style them however you like (e.g. `GateIn`). Some components have _variants_, which allow you to interact with them in multiple ways. For example, you can receive a bang from a `Gate In` instead of a float if you add `_trig` to the end of the gate's name (or any of its aliases). So, if a `Gate In`'s name is `gatein1`, you would use `gatein1_trig`. Here's what each component expects for its default behavior and variants: | Type (_variant) | Behavior | | --- | --- | | **Inputs** | --- | | Voltage Input | Returns a floating point representation of the voltage at its input. The typical range is 0-5 V, which is represented as 0-1. | | Bipolar Voltage Input | Similar to a regular voltage input, but can represent negative voltages. | | Switch | Returns a bang on the signal's rising edge (i.e. when the switch is actuated). | | Switch (_press) | Returns a float representing the current state (1 = pressed, 0 = not pressed) | | Switch (_fall) | Returns a bang on the signal's falling edge (i.e. when the switch is released). | | Switch (_seconds) | Returns a float representing the number of seconds the switch has been held down. | | SPDT Switch | Returns a float representing the current state, either 0 or 1. | | Encoder | Returns a 1 if turned one direction, -1 if turned in the other, and 0 otherwise. | | Encoder (\_rise) | Returns a bang when the encoder is pressed. The special alias _EncSwitch_ is always bound to this. | | Encoder (_press) | Same as switch _press. | | Encoder (_fall) | Same as switch _fall. | | Encoder (_seconds) | Same as switch _seconds. | | Gate In | Returns a float representing the current gate voltage, where a _high_ voltage is 1 and a _low_ voltage is 0. | | Gate In (_trig) | Returns a bang on the rising edge of the gate signal. | | **Outputs** | --- | | CV Out | Expects a floating point value from 0-1, usually converted to 0-5V. | | Gate Out | Expects a floating point value from 0-1. 0 sets the output low, and 1 sets it high. | | LED | Expects a floating point value from 0-1. The brightness is PWM modulated to match the input. | | RGB LED | Expects a floating point value from 0-1. The default behavior sets all three colors to the same brightness. | | RGB LED (_white) | Same as default. | | RGB LED (_red) | Expects a floating point value from 0-1. Sets the brightness of the red LED only. | | RGB LED (_green) | Expects a floating point value from 0-1. Sets the brightness of the green LED only. | | RGB LED (_blue) | Expects a floating point value from 0-1. Sets the brightness of the blue LED only. | # Daisy Board I/O ## patch | Name | Aliases | Type | Variants | | --- | --- | --- | --- | | knob1 | knob, ctrl, ctrl1 | Voltage Input | --- | | knob2 | ctrl2 | Voltage Input | --- | | knob3 | ctrl3 | Voltage Input | --- | | knob4 | ctrl4 | Voltage Input | --- | | encoder | --- | Encoder | encoder_press, encoder_rise, encoder_fall, encoder_seconds | | gateout | --- | Gate Out | --- | | cvout1 | cvout | CV Out | --- | | cvout2 | --- | CV Out | --- | | gatein1 | gate, gate1 | Gate In | gatein1_trig | | gatein2 | gate2 | Gate In | gatein2_trig | ## patch_init | Name | Aliases | Type | Variants | | --- | --- | --- | --- | | cv_1 | knob, knob1, ctrl, ctrl1 | Voltage Input | --- | | cv_2 | knob2, ctrl2 | Voltage Input | --- | | cv_3 | knob3, ctrl3 | Voltage Input | --- | | cv_4 | knob4, ctrl4 | Voltage Input | --- | | cv_5 | knob5, ctrl5 | Voltage Input | --- | | cv_6 | knob6, ctrl6 | Voltage Input | --- | | cv_7 | knob7, ctrl7 | Voltage Input | --- | | cv_8 | knob8, ctrl8 | Voltage Input | --- | | adc_9 | --- | Voltage Input | --- | | adc_10 | --- | Voltage Input | --- | | adc_11 | --- | Voltage Input | --- | | adc_12 | --- | Voltage Input | --- | | gate_out_1 | gateout, gateout1 | Gate Out | --- | | gate_out_2 | gateout2 | Gate Out | --- | | cvout1 | cvout, cv_out_1 | CV Out | --- | | cvout2 | cv_out_2 | CV Out | --- | | gate_in_1 | gate, gate1 | Gate In | gate_in_1_trig | | gate_in_2 | gate2 | Gate In | gate_in_2_trig | | sw1 | switch, switch1, button | Switch | sw1_press, sw1_fall, sw1_seconds | | sw2 | switch2, toggle | Switch | sw2_press, sw2_fall, sw2_seconds | ## petal | Name | Aliases | Type | Variants | | --- | --- | --- | --- | | sw1 | switch, switch1 | Switch | sw1_press, sw1_fall, sw1_seconds | | sw2 | switch2 | Switch | sw2_press, sw2_fall, sw2_seconds | | sw3 | switch3 | Switch | sw3_press, sw3_fall, sw3_seconds | | sw4 | switch4 | Switch | sw4_press, sw4_fall, sw4_seconds | | sw5 | switch5 | Switch | sw5_press, sw5_fall, sw5_seconds | | sw6 | switch6 | Switch | sw6_press, sw6_fall, sw6_seconds | | sw7 | switch7 | Switch | sw7_press, sw7_fall, sw7_seconds | | encoder | --- | Encoder | encoder_press, encoder_rise, encoder_fall, encoder_seconds | | knob1 | knob, ctrl, ctrl1 | Voltage Input | --- | | knob2 | ctrl2 | Voltage Input | --- | | knob3 | ctrl3 | Voltage Input | --- | | knob4 | ctrl4 | Voltage Input | --- | | knob5 | ctrl5 | Voltage Input | --- | | knob6 | ctrl6 | Voltage Input | --- | | expression | --- | Voltage Input | --- | | led_ring_1 ... led_ring_8 | --- | RGB LED | led_ring_1_red, led_ring_1_green, led_ring_1_blue, led_ring_1_white | | led_fs_1 | --- | LED | --- | | led_fs_2 | --- | LED | --- | | led_fs_3 | --- | LED | --- | | led_fs_4 | --- | LED | --- | ## pod | Name | Aliases | Type | Variants | | --- | --- | --- | --- | | sw1 | switch, button, switch1, button1 | Switch | sw1_press, sw1_fall, sw1_seconds | | sw2 | switch2, button2 | Switch | sw2_press, sw2_fall, sw2_seconds | | knob1 | knob, ctrl, ctrl1 | Voltage Input | --- | | knob2 | ctrl2 | Voltage Input | --- | | encoder | --- | Encoder | encoder_press, encoder_rise, encoder_fall, encoder_seconds | | led1 | led | RGB LED | led1_red, led1_green, led1_blue, led1_white | | led2 | --- | RGB LED | led2_red, led2_green, led2_blue, led2_white | | led3 | --- | LED | --- | | cvout1 | cvout | CV Out | --- | | gatein | gate, gate1 | Gate In | gatein_trig | | sw3 | switch3 | SPDT Switch | --- | ## field | Name | Aliases | Type | Variants | | --- | --- | --- | --- | | sw1 | switch, button, switch1, button1 | Switch | sw1_press, sw1_fall, sw1_seconds | | sw2 | switch2, button2 | Switch | sw2_press, sw2_fall, sw2_seconds | | cv1 | --- | Bipolar Voltage Input | --- | | cv2 | --- | Bipolar Voltage Input | --- | | cv3 | --- | Bipolar Voltage Input | --- | | cv4 | --- | Bipolar Voltage Input | --- | | knob1 | knob, ctrl, ctrl1 | Voltage Input | --- | | knob2 | ctrl2 | Voltage Input | --- | | knob3 ... knob8 | --- | Voltage Input | --- | | cvout1 | cvout | CV Out | --- | | cvout2 | --- | CV Out | --- | | gatein | --- | Gate In | gatein_trig | | gateout | --- | Gate Out | --- | | pada1 ... pada8 | --- | Switch | pada1_press, pada1_fall | | padb1 ... padb8 | --- | Switch | padb1_press, padb1_fall | | led_key_a1 ... led_key_a8 | --- | LED | --- | | led_key_b1 ... led_key_b8 | --- | LED | --- | | led_knob_1 ... led_knob_8 | --- | LED | --- | | led_sw_1 | --- | LED | --- | | led_sw_2 | --- | LED | --- | hvcc-0.16.0/hvcc/generators/c2daisy/templates/HeavyDaisy.cpp0000644000000000000000000003762600000000000020630 0ustar00{{copyright}} #include "Heavy_{{patch_name}}.h" #include "Heavy_{{patch_name}}.hpp" #include "HeavyDaisy_{{patch_name}}.hpp" #define SAMPLE_RATE {{samplerate}}.f {% if (has_midi is sameas true) or (usb_midi is sameas true) %} #define HV_HASH_NOTEIN 0x67E37CA3 #define HV_HASH_CTLIN 0x41BE0f9C #define HV_HASH_POLYTOUCHIN 0xBC530F59 #define HV_HASH_PGMIN 0x2E1EA03D #define HV_HASH_TOUCHIN 0x553925BD #define HV_HASH_BENDIN 0x3083F0F7 #define HV_HASH_MIDIIN 0x149631bE #define HV_HASH_MIDIREALTIMEIN 0x6FFF0BCF #define HV_HASH_NOTEOUT 0xD1D4AC2 #define HV_HASH_CTLOUT 0xE5e2A040 #define HV_HASH_POLYTOUCHOUT 0xD5ACA9D1 #define HV_HASH_PGMOUT 0x8753E39E #define HV_HASH_TOUCHOUT 0x476D4387 #define HV_HASH_BENDOUT 0xE8458013 #define HV_HASH_MIDIOUT 0x6511DE55 #define HV_HASH_MIDIOUTPORT 0x165707E4 #define MIDI_RT_CLOCK 0xF8 #define MIDI_RT_START 0xFA #define MIDI_RT_CONTINUE 0xFB #define MIDI_RT_STOP 0xFC #define MIDI_RT_ACTIVESENSE 0xFE #define MIDI_RT_RESET 0xFF #define MIDI_OUT_FIFO_SIZE 128 {% endif %} {% for k, v in display_params.items() %} #define HV_HASH_{{k|upper}} {{v}} {% endfor %} using namespace daisy; json2daisy::Daisy{{ class_name|capitalize }} hardware; Heavy_{{patch_name}}* hv; void audiocallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size); static void sendHook(HeavyContextInterface *c, const char *receiverName, uint32_t receiverHash, const HvMessage * m); {% if debug_printing is sameas true %} static void printHook(HeavyContextInterface *c, const char *printLabel, const char *msgString, const HvMessage *m); /** FIFO to hold messages as we're ready to print them */ FIFO, 64> event_log; {% elif usb_midi is sameas true %} daisy::MidiUsbHandler midiusb; {% endif %} {% if (has_midi is sameas true) or (usb_midi is sameas true) %} FIFO midi_tx_fifo; {% endif %} // int midiOutCount; // uint8_t* midiOutData; void CallbackWriteIn(Heavy_{{patch_name}}* hv); void LoopWriteIn(Heavy_{{patch_name}}* hv); void CallbackWriteOut(); void LoopWriteOut(); void PostProcess(); void Display(); {% if output_parameters|length > 0 %} constexpr int DaisyNumOutputParameters = {{output_parameters|length}}; /** This array holds the output values received from PD hooks. These values are * then written at the appropriate time in the following callback or loop. */ float output_data[DaisyNumOutputParameters]; struct DaisyHvParamOut { uint32_t hash; uint32_t index; void (*hook_write_out)(float); void Process(float sig) { output_data[index] = sig; if (hook_write_out) (*hook_write_out)(sig); } }; {% for param in hook_write_out %} void {{param.name}}_hook(float sig) { {{param.process}} }; {% endfor %} DaisyHvParamOut DaisyOutputParameters[DaisyNumOutputParameters] = { {% for param in output_parameters %} {% if param.hook %} { (uint32_t) HV_{{patch_name|upper}}_PARAM_OUT_{{param.hash_enum|upper}}, {{param.index}}, &{{param.name}}_hook }, // {{param.name}} {% else %} { (uint32_t) HV_{{patch_name|upper}}_PARAM_OUT_{{param.hash_enum|upper}}, {{param.index}}, nullptr }, // {{param.name}} {% endif %} {% endfor %} }; {% endif %} {% for k, v in display_params.items() %} float f{{k}}; {% endfor %} {% if (has_midi is sameas true) or (usb_midi is sameas true) %} // Typical Switch case for Message Type. void HandleMidiMessage(MidiEvent m) { ScopedIrqBlocker block; //< Disables interrupts while in scope for (int i = 0; i <= 2; ++i) { hv->sendMessageToReceiverV(HV_HASH_MIDIIN, 0, "ff", (float) m.data[i], (float) m.channel); } switch(m.type) { case SystemRealTime: { float srtType; switch(m.srt_type) { case TimingClock: srtType = MIDI_RT_CLOCK; break; case Start: srtType = MIDI_RT_START; break; case Continue: srtType = MIDI_RT_CONTINUE; break; case Stop: srtType = MIDI_RT_STOP; break; case ActiveSensing: srtType = MIDI_RT_ACTIVESENSE; break; case Reset: srtType = MIDI_RT_RESET; break; } hv->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, "ff", (float) srtType); break; } case NoteOff: { NoteOnEvent p = m.AsNoteOn(); hv->sendMessageToReceiverV(HV_HASH_NOTEIN, 0, "fff", (float) p.note, // pitch (float) 0, // velocity (float) p.channel); break; } case NoteOn: { NoteOnEvent p = m.AsNoteOn(); hv->sendMessageToReceiverV(HV_HASH_NOTEIN, 0, "fff", (float) p.note, // pitch (float) p.velocity, // velocity (float) p.channel); break; } case PolyphonicKeyPressure: { // polyphonic aftertouch PolyphonicKeyPressureEvent p = m.AsPolyphonicKeyPressure(); hv->sendMessageToReceiverV(HV_HASH_POLYTOUCHIN, 0, "fff", (float) p.pressure, // pressure (float) p.note, // note (float) p.channel); break; } case ControlChange: { ControlChangeEvent p = m.AsControlChange(); hv->sendMessageToReceiverV(HV_HASH_CTLIN, 0, "fff", (float) p.value, // value (float) p.control_number, // cc number (float) p.channel); break; } case ProgramChange: { ProgramChangeEvent p = m.AsProgramChange(); hv->sendMessageToReceiverV(HV_HASH_PGMIN, 0, "ff", (float) p.program, (float) p.channel); break; } case ChannelPressure: { ChannelPressureEvent p = m.AsChannelPressure(); hv->sendMessageToReceiverV(HV_HASH_TOUCHIN, 0, "ff", (float) p.pressure, (float) p.channel); break; } case PitchBend: { PitchBendEvent p = m.AsPitchBend(); // combine 7bit lsb and msb into 32bit int hv_uint32_t value = (((hv_uint32_t) m.data[1]) << 7) | ((hv_uint32_t) m.data[0]); hv->sendMessageToReceiverV(HV_HASH_BENDIN, 0, "ff", (float) value, (float) p.channel); break; } default: break; } } {% endif %} int main(void) { hardware.Init(true); hv = new Heavy_{{patch_name}}(SAMPLE_RATE, {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); {% if samplerate %} hardware.SetAudioSampleRate({{samplerate}}); {% endif %} {% if blocksize %} hardware.SetAudioBlockSize({{blocksize}}); {% endif %} {% if has_midi is sameas true %} MidiUartHandler::Config midi_config; hardware.midi.Init(midi_config); hardware.midi.StartReceive(); {% endif %} {% if (debug_printing is not sameas true) and (usb_midi is sameas true) %} MidiUsbHandler::Config midiusb_config; midiusb.Init(midiusb_config); midiusb.StartReceive(); {% endif %} hardware.StartAudio(audiocallback); {% if debug_printing is sameas true %} hardware.som.StartLog(); hv->setPrintHook(printHook); uint32_t now = System::GetNow(); uint32_t log_time = System::GetNow(); {% endif %} hv->setSendHook(sendHook); for(;;) { {% if debug_printing %} now = System::GetNow(); {% endif %} hardware.LoopProcess(); {% if has_midi %} hardware.midi.Listen(); while(hardware.midi.HasEvents()) { HandleMidiMessage(hardware.midi.PopEvent()); } {% endif %} {% if (debug_printing is not sameas true) and (usb_midi is sameas true) %} midiusb.Listen(); while(midiusb.HasEvents()) { HandleMidiMessage(midiusb.PopEvent()); } {% endif %} Display(); {% if loop_write_in|length > 0 %} LoopWriteIn(hv); {% endif %} {% if output_parameters|length > 0 %} LoopWriteOut(); {% endif %} {% if (has_midi is sameas true) or (usb_midi is sameas true) %} uint8_t midiData[MIDI_OUT_FIFO_SIZE]; size_t numElements = 0; while(!midi_tx_fifo.IsEmpty() && numElements < MIDI_OUT_FIFO_SIZE) { midiData[numElements++] = midi_tx_fifo.PopFront(); } if(numElements > 0) { {% if has_midi is sameas true %} hardware.midi.SendMessage(midiData, numElements); {% endif %} {% if (debug_printing is not sameas true) and (usb_midi is sameas true) %} midiusb.SendMessage(midiData, numElements); {% endif %} } {% endif %} {% if debug_printing is sameas true %} /** Now separately, every 5ms we'll print the top message in our queue if there is one */ if(now - log_time > 5) { log_time = now; if(!event_log.IsEmpty()) { auto msg = event_log.PopFront(); hardware.som.PrintLine(msg); } } {% endif %} } } /** The audio processing function. At the standard 48KHz sample rate and a block * size of 48, this will fire every millisecond. */ void audiocallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size) { {% if num_output_channels == 0 %} // A zero fill to keep I/O quiet for a patch lacking ADC~/DAC~ for (size_t chn = 0; chn < {{max_channels}}; chn++) { for (size_t i = 0; i < size; i++) out[chn][i] = 0; } {% endif %} {% if parameters|length > 0 %} hardware.ProcessAllControls(); CallbackWriteIn(hv); {% endif %} hv->process((float**)in, (float**)out, size); {% if output_parameters|length > 0 %} CallbackWriteOut(); {% endif %} hardware.PostProcess(); } {% if (has_midi is sameas true) or (usb_midi is sameas true) %} void HandleMidiOut(uint8_t *midiData, const uint8_t numElements) { for (int i = 0; i < numElements; i++) { midi_tx_fifo.PushBack(midiData[i]); } } void HandleMidiSend(uint32_t sendHash, const HvMessage *m) { switch(sendHash){ case HV_HASH_NOTEOUT: // __hv_noteout { uint8_t note = hv_msg_getFloat(m, 0); uint8_t velocity = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; // drop any pd "ports" const uint8_t numElements = 3; uint8_t midiData[numElements]; if (velocity > 0){ midiData[0] = 0x90 | ch; // noteon } else { midiData[0] = 0x80 | ch; // noteoff } midiData[1] = note; midiData[2] = velocity; HandleMidiOut(midiData, numElements); break; } case HV_HASH_POLYTOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t note = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; // drop any pd "ports" const uint8_t numElements = 3; uint8_t midiData[numElements]; midiData[0] = 0xA0 | ch; // send Poly Aftertouch midiData[1] = note; midiData[2] = value; HandleMidiOut(midiData, numElements); break; } case HV_HASH_CTLOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t cc = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; const uint8_t numElements = 3; uint8_t midiData[numElements]; midiData[0] = 0xB0 | ch; // send CC midiData[1] = cc; midiData[2] = value; HandleMidiOut(midiData, numElements); break; } case HV_HASH_PGMOUT: { uint8_t pgm = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; const uint8_t numElements = 2; uint8_t midiData[numElements]; midiData[0] = 0xC0 | ch; // send Program Change midiData[1] = pgm; HandleMidiOut(midiData, numElements); break; } case HV_HASH_TOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; const uint8_t numElements = 2; uint8_t midiData[numElements]; midiData[0] = 0xD0 | ch; // send Touch midiData[1] = value; HandleMidiOut(midiData, numElements); break; } case HV_HASH_BENDOUT: { uint16_t value = hv_msg_getFloat(m, 0); uint8_t lsb = value & 0x7F; uint8_t msb = (value >> 7) & 0x7F; uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; const uint8_t numElements = 3; uint8_t midiData[numElements]; midiData[0] = 0xE0 | ch; // send Bend midiData[1] = lsb; midiData[2] = msb; HandleMidiOut(midiData, numElements); break; } // not functional yet // case HV_HASH_MIDIOUT: // __hv_midiout // { // if (midiOutCount == 0 ) { // uint8_t midiOutData[3]; // } // midiOutData[midiOutCount] = hv_msg_getFloat(m, 0); // if (midiOutCount < 2) { // midiOutCount++; // break; // } // HandleMidiOut(midiOutData, 3); // midiOutCount = 0; // break; // } default: break; } } {% endif %} {% if display_params|length > 0 %} void HandleDisplayParams(uint32_t sendHash, const HvMessage *m) { switch(sendHash){ {% for k, v in display_params.items() %} case HV_HASH_{{k|upper}}: f{{k}} = msg_getFloat(m, 0); break; {% endfor %} default: break; } } {% endif %} /** Receives messages from PD and writes them to the appropriate * index in the `output_data` array, to be written later. */ static void sendHook(HeavyContextInterface *c, const char *receiverName, uint32_t receiverHash, const HvMessage * m) { {% if output_parameters|length > 0 %} for (int i = 0; i < DaisyNumOutputParameters; i++) { if (DaisyOutputParameters[i].hash == receiverHash) { DaisyOutputParameters[i].Process(msg_getFloat(m, 0)); } } {% endif %} {% if (has_midi is sameas true) or (usb_midi is sameas true) %} HandleMidiSend(receiverHash, m); {% endif %} {% if display_params|length > 0 %} HandleDisplayParams(receiverHash, m); {% endif %} } {% if debug_printing is sameas true %} /** Receives messages from the PD [print] object and writes them to the serial console. * */ static void printHook(HeavyContextInterface *c, const char *printLabel, const char *msgString, const HvMessage *m) { char buf[64]; char *dst = buf; int len = strnlen(printLabel, 48); dst = stpncpy(dst, printLabel, len); dst = stpcpy(dst, " "); dst = stpncpy(dst, msgString, 63-len); /** Regardless of message, let's add the message data to our queue to output */ event_log.PushBack(buf); } {% endif %} /** Sends signals from the Daisy hardware to the PD patch via the receive objects during the main loop * */ void LoopWriteIn(Heavy_{{patch_name}}* hv) { ScopedIrqBlocker block; //< Disables interrupts while in scope {% for param in loop_write_in %} {% if param.bool %} if ({{param.process}}) hv->sendBangToReceiver((uint32_t) HV_{{patch_name|upper}}_PARAM_IN_{{param.hash_enum|upper}}); {% else %} hv->sendFloatToReceiver((uint32_t) HV_{{patch_name|upper}}_PARAM_IN_{{param.hash_enum|upper}}, {{param.process}}); {% endif %} {% endfor %} } /** Sends signals from the Daisy hardware to the PD patch via the receive objects during the audio callback * */ void CallbackWriteIn(Heavy_{{patch_name}}* hv) { {% for param in callback_write_in %} {% if param.bool %} if ({{param.process}}) hv->sendBangToReceiver((uint32_t) HV_{{patch_name|upper}}_PARAM_IN_{{param.hash_enum|upper}}); {% else %} hv->sendFloatToReceiver((uint32_t) HV_{{patch_name|upper}}_PARAM_IN_{{param.hash_enum|upper}}, {{param.process}}); {% endif %} {% endfor %} } /** Writes the values sent to PD's receive objects to the Daisy hardware during the main loop * */ void LoopWriteOut() { ScopedIrqBlocker block; //< Disables interrupts while in scope {% for param in loop_write_out %} {% if param.bool %} if ({{param.value}}) {{param.process}} {% else %} {{param.process}} {% endif %} {% endfor %} } /** Writes the values sent to PD's receive objects to the Daisy hardware during the audio callback * */ void CallbackWriteOut() { {% for param in callback_write_out %} {% if param.bool %} if ({{param.value}}) {{param.process}} {% else %} {{param.process}} {% endif %} {% endfor %} } /** Handles the display code if the hardware defines a display * */ void Display() { {{display_process}} } hvcc-0.16.0/hvcc/generators/c2daisy/templates/Makefile0000644000000000000000000000103200000000000017474 0ustar00# Project Name TARGET = HeavyDaisy_{{name}} # Library Locations LIBDAISY_DIR = {{libdaisy_path}} {% if linker_script != '' %} LDSCRIPT = {{linker_script}} {% endif %} {% if bootloader != None %} APP_TYPE = {{bootloader}} {% endif %} {% if debug_printing is sameas true %} LDFLAGS += -u _printf_float {% endif %} # Project Source C_SOURCES = $(wildcard *.c) CPP_SOURCES = $(wildcard *.cpp) # Core location, and generic makefile. SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core include $(SYSTEM_FILES_DIR)/Makefile CFLAGS += -DHV_BARE_METAL hvcc-0.16.0/hvcc/generators/c2dpf/__init__.py0000644000000000000000000000000000000000000015601 0ustar00hvcc-0.16.0/hvcc/generators/c2dpf/c2dpf.py0000644000000000000000000002021500000000000015052 0ustar00# Copyright (C) 2021-2026 Wasted Audio # # 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 . import jinja2 import shutil import time from typing import Optional from pathlib import Path from ..copyright import copyright_manager from ..filters import filter_uniqueid from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerMsg, CompilerNotif, ExternInfo from hvcc.types.meta import Meta, DPF, DPFUIType, DPFUISize from .nanovg_render import open_gui_json, nanovg_render class c2dpf(Generator): """ Generates a DPF wrapper for a given patch. """ @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() out_dir = Path(out_dir, "plugin") receiver_list = externs.parameters.inParam sender_list = externs.parameters.outParam event_list = externs.events.inEvent out_event_list = externs.events.outEvent dpf_meta: DPF = patch_meta.dpf dpf_path = dpf_meta.dpf_path copyright_c = copyright_manager.get_copyright_for_c(copyright) try: # ensure that the output directory does not exist out_dir = out_dir.absolute() if out_dir.exists(): shutil.rmtree(out_dir) # copy over static files shutil.copytree(Path(Path(__file__).parent, "static"), out_dir) shutil.copy(Path(Path(__file__).parent, "static/README.md"), f'{out_dir}/../') # copy over generated C source files source_dir = Path(out_dir, "source") shutil.copytree(c_src_dir, source_dir) if dpf_meta.enable_ui == DPFUIType.NANOVG: gui_json = open_gui_json(patch_name, c_src_dir) dpf_meta.ui_size = DPFUISize( width=gui_json.size.x, height=gui_json.size.y ) # initialize the jinja template environment env = jinja2.Environment() env.filters["uniqueid"] = filter_uniqueid env.loader = jinja2.FileSystemLoader( Path(Path(__file__).parent, "templates")) # generate DPF wrapper from template dpf_h_path = Path(source_dir, f"HeavyDPF_{patch_name}.hpp") with open(dpf_h_path, "w") as f: f.write(env.get_template("HeavyDPF.hpp").render( name=patch_name, meta=dpf_meta, class_name=f"HeavyDPF_{patch_name}", num_input_channels=num_input_channels, num_output_channels=num_output_channels, receivers=receiver_list, senders=sender_list, events=event_list, out_events=out_event_list, copyright=copyright_c)) dpf_cpp_path = Path(source_dir, f"HeavyDPF_{patch_name}.cpp") with open(dpf_cpp_path, "w") as f: f.write(env.get_template("HeavyDPF.cpp").render( name=patch_name, meta=dpf_meta, class_name=f"HeavyDPF_{patch_name}", num_input_channels=num_input_channels, num_output_channels=num_output_channels, receivers=receiver_list, senders=sender_list, events=event_list, out_events=out_event_list, pool_sizes_kb=externs.memoryPoolSizesKb, copyright=copyright_c)) if dpf_meta.enable_ui == DPFUIType.IMGUI: dpf_ui_path = Path(source_dir, f"HeavyDPF_{patch_name}_UI.cpp") with open(dpf_ui_path, "w") as f: f.write(env.get_template("HeavyDPF_ImGui_UI.cpp").render( name=patch_name, meta=dpf_meta, class_name=f"HeavyDPF_{patch_name}", receivers=receiver_list, senders=sender_list, copyright=copyright_c)) elif dpf_meta.enable_ui == DPFUIType.NANOVG: gui_json, widgets, gui_objects_render = nanovg_render( patch_name, c_src_dir, env, receiver_list, sender_list ) dpf_ui_header = Path(source_dir, f"HeavyDPF_{patch_name}_UI.hpp") with open(dpf_ui_header, "w") as f: f.write(env.get_template("HeavyDPF_NanoVG_UI.hpp").render( name=patch_name, meta=dpf_meta, class_name=f"HeavyDPF_{patch_name}_UI", gui_json=gui_json, widgets=widgets, copyright=copyright_c)) dpf_ui_path = Path(source_dir, f"HeavyDPF_{patch_name}_UI.cpp") with open(dpf_ui_path, "w") as f: f.write(env.get_template("HeavyDPF_NanoVG_UI.cpp").render( name=patch_name, meta=dpf_meta, class_name=f"HeavyDPF_{patch_name}_UI", gui_json=gui_json, widgets=widgets, gui_objects=gui_objects_render, receivers=receiver_list, senders=sender_list, events=event_list, copyright=copyright_c)) dpf_h_path = Path(source_dir, "DistrhoPluginInfo.h") with open(dpf_h_path, "w") as f: f.write(env.get_template("DistrhoPluginInfo.h").render( name=patch_name, meta=dpf_meta, class_name=f"HeavyDPF_{patch_name}", num_input_channels=num_input_channels, num_output_channels=num_output_channels, pool_sizes_kb=externs.memoryPoolSizesKb, copyright=copyright_c)) # plugin makefile with open(Path(source_dir, "Makefile"), "w") as f: f.write(env.get_template("Makefile_plugin").render( name=patch_name, meta=dpf_meta, nosimd=patch_meta.nosimd, dpf_path=dpf_path)) # project makefile with open(Path(source_dir, "../../Makefile"), "w") as f: f.write(env.get_template("Makefile_project").render( name=patch_name, meta=dpf_meta, dpf_path=dpf_path)) return CompilerResp( stage="c2dpf", in_dir=c_src_dir, out_dir=out_dir, out_file=dpf_h_path, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2dpf", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2dpf/nanovg_render.py0000644000000000000000000000424500000000000016710 0ustar00import json from pathlib import Path import jinja2 from hvcc.types.GUI import Canvas, Comment, GraphRoot, Graph, GUIObjects def open_gui_json( patch_name: str, c_src_dir: Path, ) -> GraphRoot: # load GUI from json file gui_json_path = Path(c_src_dir, "../ir/", f"{patch_name}.heavy.gui.json") with open(gui_json_path, "r") as f: gui_json = GraphRoot(**json.load(f)) return gui_json def nanovg_render( patch_name: str, c_src_dir: Path, env: jinja2.Environment, recv_list: list, send_list: list ) -> tuple[ GraphRoot, dict[str, list[str]], list[str] ]: """ Generate nanovg components from the GUI json """ gui_json = open_gui_json(patch_name, c_src_dir) # widget overview widgets: dict[str, list[str]] = { "graph": [], "canvas": [], "comment": [], "bang": [], "toggle": [], "vradio": [], "hradio": [], "vslider": [], "hslider": [], "knob": [], "number": [], "float": [] } # render gui objects gui_objects_render = [] def generate_gui_objects(graphs: list[Graph], objects: list[GUIObjects], parent: str): for w in objects: widgets[w.type].append(w.id if isinstance(w, (Canvas, Comment)) else w.parameter) gui_objects_render.append(env.get_template("gui_objects.cpp").render( parent=parent, gui_objects=objects, receivers=recv_list, senders=send_list )) for graph in graphs: widgets["graph"].append(graph.id) gui_objects_render.append( f""" // subpatch {graph.id} = new PDSubpatch({parent}); {graph.id}->setSize({graph.gop_size.x} * scaleFactor, {graph.gop_size.y} * scaleFactor); {graph.id}->setAbsolutePos({graph.position.x} * scaleFactor, {graph.position.y} * scaleFactor); {parent}->addManagedChild({graph.id}); """ ) generate_gui_objects(graph.graphs, graph.objects, graph.id) generate_gui_objects(gui_json.graphs, gui_json.objects, "mainPatch") return gui_json, widgets, gui_objects_render hvcc-0.16.0/hvcc/generators/c2dpf/static/README.md0000644000000000000000000000205700000000000016254 0ustar00# Distrho Plugin Format This output is for the Distrho Plugin Format ([DPF](https://github.com/DISTRHO/DPF)), and can be used to build LV2, VST2 and jack standalone versions of your Heavy code. # Build Instructions Make sure you have a (recent) DPF in the root of your output directory ```bash $ cd $ git clone https://github.com/DISTRHO/DPF.git dpf ``` Then compile the plugins from the source folder: ```bash $ make ``` This will result in an `bin/` folder with all binary assets. * LV2 - move `bin/.lv2/` folder to your local `~/.lv2/` dir * VST2 - move `bin/-vst.so`, can be placed directly into your `~/.vst/` dir ## Metadata You will likely want to add more configuration options to your project. Create a json file as described in the [documentation](https://wasted-audio.github.io/hvcc/docs/03.gen.dpf.html#metadata). ## Jack The Jack binary can be executed in place and used to test functionality `./bin/`. Currently there is no UI, so this is not recommended. You will have to be running jack in order to use this. hvcc-0.16.0/hvcc/generators/c2dpf/templates/DistrhoPluginInfo.h0000644000000000000000000000567300000000000021273 0ustar00{{copyright}} #pragma once #define DISTRHO_PLUGIN_NAME "{{name.replace('_', ' ')}}" {%- if meta.plugin_uri != None %} #define DISTRHO_PLUGIN_URI "{{meta.plugin_uri}}" {% else %} #define DISTRHO_PLUGIN_URI "urn:hvcc:{{name}}" {%- endif %} {%- if meta.maker != None %} #define DISTRHO_PLUGIN_BRAND "{{meta.maker}}" {% else %} #define DISTRHO_PLUGIN_BRAND "Heavy" {%- endif %} {%- if meta.brand_id != None %} #define DISTRHO_PLUGIN_BRAND_ID {{meta.brand_id}} {%- endif %} {%- if meta.brand_id_no_vst3 is sameas true %} #define DPF_VST3_DONT_USE_BRAND_ID 1 {%- endif %} {%- if meta.unique_id != None %} #define DISTRHO_PLUGIN_UNIQUE_ID {{meta.unique_id}} {%- endif %} {%- if meta.plugin_clap_id != None %} #define DISTRHO_PLUGIN_CLAP_ID "{{meta.plugin_clap_id}}" {% else %} #define DISTRHO_PLUGIN_CLAP_ID "urn.hvcc.{{name}}" {%- endif %} #define DISTRHO_PLUGIN_NUM_INPUTS {{num_input_channels}} #define DISTRHO_PLUGIN_NUM_OUTPUTS {{num_output_channels}} #define DISTRHO_PLUGIN_IS_SYNTH {{1 if num_output_channels > 0 and meta.midi_input > 0 else 0}} #define DISTRHO_PLUGIN_HAS_UI {{1 if meta.enable_ui > 0 else 0}} #define DISTRHO_PLUGIN_IS_RT_SAFE 1 #define DISTRHO_PLUGIN_WANT_PROGRAMS 0 #define DISTRHO_PLUGIN_WANT_STATE 0 #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 #define DISTRHO_PLUGIN_WANT_FULL_STATE 0 #define DISTRHO_PLUGIN_WANT_MIDI_INPUT {{1 if meta.midi_input is sameas true else 0}} #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT {{1 if meta.midi_output is sameas true else 0}} {%- if meta.lv2_info != None %} #define DISTRHO_PLUGIN_LV2_CATEGORY "{{meta.lv2_info}}" {%- endif %} {%- if meta.vst3_info != None %} #define DISTRHO_PLUGIN_VST3_CATEGORIES "{{meta.vst3_info}}" {%- endif %} {%- if meta.clap_info|length > 0 %} #define DISTRHO_PLUGIN_CLAP_FEATURES "{{ meta.clap_info|join('", "') }}" {%- endif %} // for level monitoring #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 {% if meta.enable_ui > 0 %} // if you are using a UI you'll probably want to modify these settings to your needs {%- if meta.enable_ui == 1 %} #define DISTRHO_UI_USE_CUSTOM 1 #define DISTRHO_UI_CUSTOM_INCLUDE_PATH "DearImGui.hpp" #define DISTRHO_UI_CUSTOM_WIDGET_TYPE DGL_NAMESPACE::ImGuiTopLevelWidget {%- elif meta.enable_ui == 2 %} #define DISTRHO_UI_USE_NANOVG 1 {%- endif %} {%- if meta.ui_size != None %} #define DISTRHO_UI_DEFAULT_WIDTH {{meta.ui_size.width}} #define DISTRHO_UI_DEFAULT_HEIGHT {{meta.ui_size.height}} {% else %} #define DISTRHO_UI_DEFAULT_WIDTH 400 #define DISTRHO_UI_DEFAULT_HEIGHT 400 {%- endif %} {%- endif %} {%- if meta.enable_modgui is sameas true %} #undef DISTRHO_PLUGIN_USES_MODGUI #define DISTRHO_PLUGIN_USES_MODGUI 1 {%- endif %} hvcc-0.16.0/hvcc/generators/c2dpf/templates/HeavyDPF.cpp0000644000000000000000000001553500000000000017623 0ustar00{{copyright}} #include "Heavy_{{name}}.h" #include "{{class_name}}.hpp" #include {% if meta.denormals is sameas false %} #include "extra/ScopedDenormalDisable.hpp" {% endif %} #define HV_HASH_NOTEIN 0x67E37CA3 #define HV_HASH_CTLIN 0x41BE0f9C #define HV_HASH_POLYTOUCHIN 0xBC530F59 #define HV_HASH_PGMIN 0x2E1EA03D #define HV_HASH_TOUCHIN 0x553925BD #define HV_HASH_BENDIN 0x3083F0F7 #define HV_HASH_MIDIIN 0x149631bE #define HV_HASH_MIDIREALTIMEIN 0x6FFF0BCF #define HV_HASH_NOTEOUT 0xD1D4AC2 #define HV_HASH_CTLOUT 0xE5e2A040 #define HV_HASH_POLYTOUCHOUT 0xD5ACA9D1 #define HV_HASH_PGMOUT 0x8753E39E #define HV_HASH_TOUCHOUT 0x476D4387 #define HV_HASH_BENDOUT 0xE8458013 #define HV_HASH_MIDIOUT 0x6511DE55 #define HV_HASH_MIDIOUTPORT 0x165707E4 #define MIDI_RT_CLOCK 0xF8 #define MIDI_RT_START 0xFA #define MIDI_RT_CONTINUE 0xFB #define MIDI_RT_STOP 0xFC #define MIDI_RT_ACTIVESENSE 0xFE #define MIDI_RT_RESET 0xFF #define HV_HASH_DPF_BPM 0xDF8C2721 // midi realtime messages std::set mrtSet { MIDI_RT_CLOCK, MIDI_RT_START, MIDI_RT_CONTINUE, MIDI_RT_STOP, MIDI_RT_RESET }; START_NAMESPACE_DISTRHO // ------------------------------------------------------------------- // Heavy Send and Print hooks static void hvSendHookFunc(HeavyContextInterface *c, const char *sendName, uint32_t sendHash, const HvMessage *m) { {{class_name}}* plugin = ({{class_name}}*)c->getUserData(); if (plugin != nullptr) { plugin->setOutputParameter(sendHash, m); {%- if meta.midi_output is sameas true %} #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT plugin->handleMidiSend(sendHash, m); #endif {% endif %} } } static void hvPrintHookFunc(HeavyContextInterface *c, const char *printLabel, const char *msgString, const HvMessage *m) { char buf[64]; char* dst = buf; int len = strnlen(printLabel, 48); dst = strncpy(dst, printLabel, len); dst = strcpy(dst, " "); dst = strncpy(dst, msgString, 63-len); printf("> %s \n", buf); } // ------------------------------------------------------------------- // Main DPF plugin class {{class_name}}::{{class_name}}() : Plugin(HV_DPF_NUM_PARAMETER, 0, 0) { {% for k, v in receivers + senders + events -%} {%- if v.attributes %} _parameters[{{loop.index-1}}] = {{v.attributes.default}}f; {%- else %} _parameters[{{loop.index-1}}] = 0.0f; {%- endif %} {%- endfor %} _context = hv_{{name}}_new_with_options(getSampleRate(), {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); _context->setUserData(this); _context->setSendHook(&hvSendHookFunc); _context->setPrintHook(&hvPrintHookFunc); {% if receivers|length > 0 %} // ensure that the new context has the current parameters for (int i = 0; i < HV_DPF_NUM_PARAMETER; ++i) { setParameterValue(i, _parameters[i]); } {%- endif %} } {{class_name}}::~{{class_name}}() { hv_{{name}}_free(_context); } {%- if meta.port_groups != None %} {% include 'portGroups.cpp' %} {%- endif %} void {{class_name}}::initParameter(uint32_t index, Parameter& parameter) { {%- if (receivers|length > 0) or (senders|length > 0) -%} // initialise parameters with defaults switch (index) { {% for k, v in receivers + senders + events %} {% include 'initParameter.cpp' %} {% endfor -%} } {% endif %} } // ------------------------------------------------------------------- // Internal data float {{class_name}}::getParameterValue(uint32_t index) const { {%- if (receivers|length > 0) or (senders|length > 0) %} return _parameters[index]; {% else %} return 0.0f; {%- endif %} } void {{class_name}}::setParameterValue(uint32_t index, float value) { {%- if (receivers|length > 0) or (events|length > 0) %} switch (index) { {%- for k, v in receivers + senders + events %} case {{loop.index-1}}: { {%- if v.type == "send" %} // do nothing for {{k|upper}} {%- elif v.extern == "event" %} if (value == 1) _context->sendBangToReceiver(Heavy_{{name}}::Event::In::{{k|upper}}); {%- else %} _context->sendFloatToReceiver( Heavy_{{name}}::Parameter::In::{{k|upper}}, value); {%- endif %} break; } {% endfor %} default: return; } _parameters[index] = value; {% else %} // nothing to do {%- endif %} } void {{class_name}}::setOutputParameter(uint32_t sendHash, const HvMessage *m) { {%- if senders|length > 0 %} switch (sendHash) { {% for k, v in senders -%} case {{v.hash}}: // {{v.display}} _parameters[param{{v.display}}] = hv_msg_getFloat(m, 0); break; {% endfor %} } {%- endif %} } // ------------------------------------------------------------------- // Process // void {{class_name}}::activate() // { // } // void {{class_name}}::deactivate() // { // } {%- if meta.midi_input is sameas true %} #if DISTRHO_PLUGIN_WANT_MIDI_INPUT {% include 'midiInput.cpp' %} #endif {% endif %} {%- if meta.midi_output is sameas true %} #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT {% include 'midiOutput.cpp' %} #endif {% endif %} {% include 'hostTransportEvents.cpp' %} // ------------------------------------------------------------------- // DPF Plugin run() loop #if DISTRHO_PLUGIN_WANT_MIDI_INPUT void {{class_name}}::run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) { handleMidiInput(frames, midiEvents, midiEventCount); #else void {{class_name}}::run(const float** inputs, float** outputs, uint32_t frames) { #endif hostTransportEvents(frames); {% if meta.denormals is sameas false %} const ScopedDenormalDisable sdd; {% endif %} const TimePosition& timePos(getTimePosition()); if (timePos.bbt.valid) _context->sendMessageToReceiverV(HV_HASH_DPF_BPM, 0, "f", timePos.bbt.beatsPerMinute); _context->process((float**)inputs, outputs, frames); } // ------------------------------------------------------------------- // Callbacks void {{class_name}}::sampleRateChanged(double newSampleRate) { hv_{{name}}_free(_context); _context = hv_{{name}}_new_with_options(getSampleRate(), {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); _context->setUserData(this); _context->setSendHook(&hvSendHookFunc); _context->setPrintHook(&hvPrintHookFunc); {% if receivers|length > 0 -%} // ensure that the new context has the current parameters for (int i = 0; i < HV_DPF_NUM_PARAMETER; ++i) { setParameterValue(i, _parameters[i]); } {%- endif %} } // ----------------------------------------------------------------------- /* Plugin entry point, called by DPF to create a new plugin instance. */ Plugin* createPlugin() { return new {{class_name}}(); } // ----------------------------------------------------------------------- END_NAMESPACE_DISTRHO hvcc-0.16.0/hvcc/generators/c2dpf/templates/HeavyDPF.hpp0000644000000000000000000001040200000000000017614 0ustar00{{copyright}} #ifndef _HEAVY_LV2_{{name|upper}}_ #define _HEAVY_LV2_{{name|upper}}_ #include "DistrhoPlugin.hpp" #include "DistrhoPluginInfo.h" #include "Heavy_{{name}}.hpp" START_NAMESPACE_DISTRHO #define HV_DPF_NUM_PARAMETER {{receivers|length + senders|length + events|length}} static void hvSendHookFunc(HeavyContextInterface *c, const char *sendName, uint32_t sendHash, const HvMessage *m); static void hvPrintHookFunc(HeavyContextInterface *c, const char *printLabel, const char *msgString, const HvMessage *m); class {{class_name}} : public Plugin { public: enum Parameters { {%- for k, v in receivers + senders + events %} param{{v.display}}, {%- endfor %} }; {% if meta.port_groups != None %} enum PortGroups { {%- if meta.port_groups.input|length %} {%- for group, value in meta.port_groups.input.items() %} kPortGroup{{group}}, {%- endfor %} {%- endif %} {%- if meta.port_groups.output|length %} {%- for group, value in meta.port_groups.output.items() %} kPortGroup{{group}}, {%- endfor %} {%- endif %} kPortGroupCount }; {%- endif %} {{class_name}}(); ~{{class_name}}() override; void handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount); void handleMidiSend(uint32_t sendHash, const HvMessage *m); void hostTransportEvents(uint32_t frames); void setOutputParameter(uint32_t sendHash, const HvMessage *m); protected: // ------------------------------------------------------------------- // Information const char* getLabel() const noexcept override { return "{{name}}"; } {%- if meta.description != None %} const char* getDescription() const override { return "{{meta.description}}"; } {%- endif %} const char* getMaker() const noexcept override { {%- if meta.maker != None %} return "{{meta.maker}}"; {% else %} return "Wasted Audio"; {%- endif %} } {%- if meta.homepage != None %} const char* getHomePage() const override { return "{{meta.homepage}}"; } {%- endif %} const char* getLicense() const noexcept override { {%- if meta.license != None %} return "{{meta.license}}"; {% else %} return "GPL v3+"; {%- endif %} } uint32_t getVersion() const noexcept override { {%- if meta.version != None %} return d_version({{meta.version}}); {% else %} return d_version(0, 0, 1); {%- endif %} } int64_t getUniqueId() const noexcept override { return int64_t( {{class_name|uniqueid}} ); } // ------------------------------------------------------------------- // Init void initParameter(uint32_t index, Parameter& parameter) override; {% if meta.port_groups != None %} void initAudioPort(bool input, uint32_t index, AudioPort& port) override; void initPortGroup(uint32_t groupId, PortGroup& portGroup) override; {%- endif %} // ------------------------------------------------------------------- // Internal data float getParameterValue(uint32_t index) const override; void setParameterValue(uint32_t index, float value) override; // ------------------------------------------------------------------- // Process // void activate() override; // void deactivate() override; #if DISTRHO_PLUGIN_WANT_MIDI_INPUT void run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override; #else void run(const float** inputs, float** outputs, uint32_t frames) override; #endif // ------------------------------------------------------------------- // Callbacks void sampleRateChanged(double newSampleRate) override; // ------------------------------------------------------------------- private: {%- if (receivers|length > 0) or (senders|length > 0) or (events|length > 0) %} // parameters float _parameters[HV_DPF_NUM_PARAMETER]; {%- endif %} // transport values bool wasPlaying = false; double nextClockTick = 0.0; double sampleAtCycleStart = 0.0; // midi out buffer int midiOutCount; MidiEvent midiOutEvent; // heavy context HeavyContextInterface *_context; // {{class_name}} f{{name}}; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR({{class_name}}) }; // ----------------------------------------------------------------------- END_NAMESPACE_DISTRHO #endif // _HEAVY_LV2_{{name|upper}}_ {# newline #} hvcc-0.16.0/hvcc/generators/c2dpf/templates/HeavyDPF_ImGui_UI.cpp0000644000000000000000000001313600000000000021305 0ustar00{{copyright}} #include "DistrhoUI.hpp" #include "ResizeHandle.hpp" START_NAMESPACE_DISTRHO // -------------------------------------------------------------------------------------------------------------------- {%- if (receivers|length > 0) or (senders|length > 0) %} enum HeavyParams { {%- for k, v in receivers + senders %} {{v.display|upper}}, {%- endfor %} }; {%- endif %} class ImGuiPluginUI : public UI { {% for k, v in receivers + senders -%} {%- if v.attributes.type == 'bool': %} bool f{{v.display|lower}} = {{v.attributes.default}}f != 0.0f; {%- elif v.attributes.type == 'int': %} int f{{v.display|lower}} = {{v.attributes.default}}; {%- else %} float f{{v.display|lower}} = {{v.attributes.default}}f; {%- endif %} {%- endfor %} ResizeHandle fResizeHandle; // ---------------------------------------------------------------------------------------------------------------- public: /** UI class constructor. The UI should be initialized to a default state that matches the plugin side. */ ImGuiPluginUI() : UI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT), fResizeHandle(this) { setGeometryConstraints(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT, true); // hide handle if UI is resizable if (isResizable()) fResizeHandle.hide(); } protected: // ---------------------------------------------------------------------------------------------------------------- // DSP/Plugin Callbacks /** A parameter has changed on the plugin side.@n This is called by the host to inform the UI about parameter changes. */ void parameterChanged(uint32_t index, float value) override { {%- if (receivers|length > 0) or (senders|length > 0) %} switch (index) { {% for k, v in receivers + senders -%} case {{v.display|upper}}: {%- if v.attributes.type == 'bool': %} f{{v.display|lower}} = value != 0.0f; {%- else %} f{{v.display|lower}} = value; {%- endif %} break; {% endfor %} default: return; } {% else %} // nothing to do {%- endif %} repaint(); } // ---------------------------------------------------------------------------------------------------------------- // Widget Callbacks /** ImGui specific onDisplay function. */ void onImGuiDisplay() override { const float width = getWidth(); const float height = getHeight(); const float margin = 20.0f * getScaleFactor(); ImGui::SetNextWindowPos(ImVec2(margin, margin)); ImGui::SetNextWindowSize(ImVec2(width - 2 * margin, height - 2 * margin)); if (ImGui::Begin("{{name.replace('_', ' ')}}", nullptr, ImGuiWindowFlags_NoResize + ImGuiWindowFlags_NoCollapse)) { {%- for k, v in receivers + senders %} {%- set v_display = v.display|lower %} {%- if meta.enumerators != None and meta.enumerators[v.display] is defined -%} {%- set enums = meta.enumerators[v.display] -%} {%- set enumlen = enums|length %} {%- set enum_list = v_display + "_list" %} const char* {{enum_list}}[{{enumlen}}] = { {%- for i in enums %} "{{i}}", {%- endfor %} }; if (ImGui::BeginCombo("{{v.display.replace('_', ' ')}}", {{enum_list}}[f{{v_display}}])) { for (int n = 0; n < {{enumlen}}; n++) { bool is_selected = (f{{v_display}} == n); if (ImGui::Selectable({{enum_list}}[n], is_selected)) { f{{v_display}} = n; editParameter({{v.display|upper}}, true); setParameterValue({{v.display|upper}}, f{{v_display}}); } if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } {%- else %} {%- if v.attributes.type == 'bool': %} if (ImGui::Toggle("{{v.display.replace('_', ' ')}}", &f{{v_display}})) {%- elif v.attributes.type == 'int' %} if (ImGui::SliderInt("{{v.display.replace('_', ' ')}}", &f{{v_display}}, {{v.attributes.min}}f, {{v.attributes.max}}f)) {%- else %} if (ImGui::SliderFloat("{{v.display.replace('_', ' ')}}", &f{{v_display}}, {{v.attributes.min}}f, {{v.attributes.max}}f)) {%- endif %} { {%- if not v.type == "send" %} if (ImGui::IsItemActivated()) { editParameter({{v.display|upper}}, true); } setParameterValue({{v.display|upper}}, f{{v_display}}); {%- endif %} } {%- endif %} {% endfor %} if (ImGui::IsItemDeactivated()) { {% for k, v in receivers + senders -%} editParameter({{v.display|upper}}, false); {% endfor -%} } } ImGui::End(); } DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImGuiPluginUI) }; // -------------------------------------------------------------------------------------------------------------------- UI* createUI() { return new ImGuiPluginUI(); } // -------------------------------------------------------------------------------------------------------------------- END_NAMESPACE_DISTRHO hvcc-0.16.0/hvcc/generators/c2dpf/templates/HeavyDPF_NanoVG_UI.cpp0000644000000000000000000000612300000000000021421 0ustar00{{copyright}} #include "DistrhoUI.hpp" #include "DistrhoPluginInfo.h" #include "nanovg.h" #include "{{class_name}}.hpp" START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------------------------------------------- {%- if (receivers|length > 0) or (senders|length > 0) or (events|length > 0) %} enum HeavyParams { {%- for k, v in receivers + senders + events %} k{{v.display|capitalize}}, {%- endfor %} kParameterCount }; {%- endif %} {{class_name}}::{{class_name}}() : UI(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT) { const float width = getWidth(); const float height = getHeight(); const double scaleFactor = getScaleFactor(); // mainpatch mainPatch = new PDMainpatch(this); mainPatch->setSize(width * scaleFactor, height * scaleFactor); {%- for i in gui_objects -%} {{i}} {%- endfor %} } {{class_name}}::~{{class_name}}() { } void {{class_name}}::onNanoDisplay() { const float width = getWidth(); const float height = getHeight(); const double scaleFactor = getScaleFactor(); NVGcontext* nvg = getContext(); nvgFillColor(nvg, Colors::cnvColor); nvgBeginPath(nvg); nvgRect(nvg, 0, 0, width * scaleFactor, height * scaleFactor); nvgFill(nvg); nvgStroke(nvg); } void {{class_name}}::parameterChanged(uint32_t index, float value) { switch (index) { {%- for k, v in receivers %} case k{{v.display|capitalize}}: {%- if v.attributes.type == "bool" %} {{v.display|lower}}->setDown(static_cast(value)); {%- else %} {{v.display|lower}}->setValue(value); {%- endif %} break; {%- endfor %} default: break; } repaint(); } void {{class_name}}::sliderValueChanged(SubWidget *const widget, float value) { // printf("value changed: %f\n", value); const uint id = widget->getId(); setParameterValue(id, value); } void {{class_name}}::switchClicked(SubWidget *const widget, bool down) { // printf("switch clicked: %d\n", down); const uint id = widget->getId(); setParameterValue(id, static_cast(down)); } void {{class_name}}::bangClicked(SubWidget *const widget) { // printf("bang clicked\n"); const uint id = widget->getId(); setParameterValue(id, 1.0f); } void {{class_name}}::radioValueChanged(SubWidget *const widget, uint index) { // printf("radio clicked: %d\n", index); const uint id = widget->getId(); setParameterValue(id, static_cast(index)); } void {{class_name}}::numberValueChanged(SubWidget *const widget, float value) { // printf("number value changed: %f\n", value); const uint id = widget->getId(); setParameterValue(id, value); } void {{class_name}}::knobValueChanged(SubWidget *const widget, float value) { // printf("knob value changed: %f\n", value); const uint id = widget->getId(); setParameterValue(id, value); } UI *createUI() { return new {{class_name}}(); } // ----------------------------------------------------------------------------------------------------------- END_NAMESPACE_DISTRHO hvcc-0.16.0/hvcc/generators/c2dpf/templates/HeavyDPF_NanoVG_UI.hpp0000644000000000000000000000453600000000000021434 0ustar00{{copyright}} #include "DistrhoUI.hpp" #include "DistrhoPluginInfo.h" #include "nanovg.h" #include "pdvg.hpp" START_NAMESPACE_DISTRHO class {{class_name}} : public UI, public PDSliderEventHandler::Callback, public PDToggleEventHandler::Callback, public PDRadioEventHandler::Callback, public PDNumberEventHandler::Callback, public PDKnobEventHandler::Callback, public PDBangEventHandler::Callback { public: {{class_name}}(); ~{{class_name}}(); protected: void parameterChanged(uint32_t index, float value) override; void onNanoDisplay() override; void sliderValueChanged(SubWidget *const widget, float value) override; void switchClicked(SubWidget *const widget, bool down) override; void bangClicked(SubWidget *const widget) override; void radioValueChanged(SubWidget *const widget, uint index) override; void numberValueChanged(SubWidget *const widget, float value) override; void knobValueChanged(SubWidget *const widget, float value) override; private: ScopedPointer mainPatch; {%- for type in widgets.keys() %} {%- for widget in widgets[type] %} {%- if type == 'graph' %} {%- set object = 'PDSubpatch' %} {%- elif type == 'canvas' %} {%- set object = 'PDCanvas' %} {%- elif type == 'comment' %} {%- set object = 'PDComment' %} {%- elif type == 'bang' %} {%- set object = 'PDBang' %} {%- elif type == 'toggle' %} {%- set object = 'PDToggle' %} {%- elif type in ['vradio', 'hradio'] %} {%- set object = 'PDRadio' %} {%- elif type in ['vslider', 'hslider'] %} {%- set object = 'PDSlider' %} {%- elif type == 'knob' %} {%- set object = 'PDKnob' %} {%- elif type == 'number' %} {%- set object = 'PDNumber' %} {%- elif type == 'float' %} {%- set object = 'PDFloat' %} {%- endif %} ScopedPointer<{{object}}> {{widget}}; {%- endfor %} {%- endfor %} DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR({{class_name}}) }; END_NAMESPACE_DISTRHO hvcc-0.16.0/hvcc/generators/c2dpf/templates/Makefile_plugin0000644000000000000000000000326600000000000020525 0ustar00NAME = {{name}} {%- if meta.enable_modgui is sameas true %} MODGUI_CLASS_NAME = hv_{{name}} {%- endif %} {%- if meta.enable_ui > 0 %} FILES_DSP = $(filter-out HeavyDPF_{{name}}_UI.cpp, $(wildcard *.cpp)) {%- else %} FILES_DSP = $(wildcard *.cpp) {%- endif %} FILES_DSP += $(wildcard *.c) {%- if meta.enable_ui > 0 %} FILES_UI = HeavyDPF_{{name}}_UI.cpp {%- if meta.enable_ui == 1 %} FILES_UI += ../../{{dpf_path}}dpf-widgets/opengl/DearImGui.cpp {%- elif meta.enable_ui == 2 %} FILES_UI += $(wildcard ../../{{dpf_path}}pdvg/src/*.cpp) FILES_UI += ../../{{dpf_path}}pdvg/src/Fonts/*.cpp {%- endif %} {%- endif %} DPF_TARGET_DIR = ../../bin DPF_BUILD_DIR = ../../build DPF_PATH = ../../{{dpf_path}}dpf include ../../{{dpf_path}}dpf/Makefile.plugins.mk {%- if meta.enable_ui == 1 %} BUILD_CXX_FLAGS += -I ../../{{dpf_path}}dpf-widgets/generic BUILD_CXX_FLAGS += -I ../../{{dpf_path}}dpf-widgets/opengl {%- elif meta.enable_ui == 2 %} BUILD_CXX_FLAGS += -I ../../{{dpf_path}}dpf/dgl/src/nanovg BUILD_CXX_FLAGS += -I ../../{{dpf_path}}pdvg {%- endif %} {%- if meta.makefile_dep|length > 0 %} {%- for dependency in meta.makefile_dep %} BUILD_CXX_FLAGS += -I ../../{{dpf_path}}{{dependency}} {%- endfor %} {%- endif %} BUILD_C_FLAGS += -Wno-unused-parameter -std=c11 -fno-strict-aliasing -pthread BUILD_CXX_FLAGS += -Wno-unused-parameter -fno-strict-aliasing -pthread LINK_FLAGS += -pthread {%- if nosimd is sameas true %} BUILD_C_FLAGS += -DHV_SIMD_NONE BUILD_CXX_FLAGS += -DHV_SIMD_NONE {%- endif %} {% if meta.plugin_formats|length > 0 %} {%- for format in meta.plugin_formats %} TARGETS += {{format}} {%- endfor %} {% else %} TARGETS += jack TARGETS += lv2_dsp TARGETS += vst {%- endif %} all: $(TARGETS) hvcc-0.16.0/hvcc/generators/c2dpf/templates/Makefile_project0000644000000000000000000000156200000000000020672 0ustar00#!/usr/bin/make -f # Makefile for DISTRHO Plugins # # ---------------------------- # # Created by falkTX # # Modified by Wasted Audio # include {{dpf_path}}dpf/Makefile.base.mk all: plugin gen # -------------------------------------------------------------- dgl: # ifeq ($(HAVE_CAIRO_OR_OPENGL),true) # $(MAKE) -C {{dpf_path}}dpf/dgl FILE_BROWSER_DISABLED=true # endif plugin: dgl $(MAKE) all -C plugin/source ifneq ($(CROSS_COMPILING),true) gen: plugin lv2_ttl_generator @$(CURDIR)/{{dpf_path}}dpf/utils/generate-ttl.sh lv2_ttl_generator: $(MAKE) -C {{dpf_path}}dpf/utils/lv2-ttl-generator else gen: endif # -------------------------------------------------------------- clean: $(MAKE) clean -C {{dpf_path}}dpf/utils/lv2-ttl-generator $(MAKE) clean -C plugin/source rm -rf bin build # -------------------------------------------------------------- .PHONY: plugin hvcc-0.16.0/hvcc/generators/c2dpf/templates/gui_objects.cpp0000644000000000000000000002335100000000000020505 0ustar00 {%- for object in gui_objects -%} {%- if object.type == 'canvas' %} // canvas {{object.id}} = new PDCanvas({{parent}}); {{object.id}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.id}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.id}}->setColors(nvgRGB{{object.bg_color.as_rgb_tuple()}}); {%- if object.label != None %} {{object.id}}->setLabel("{{object.label.text}}", nvgRGB{{object.label.color.as_rgb_tuple()}}, {{object.label.position.x}} * scaleFactor, {{object.label.position.y}} * scaleFactor, {{object.label.font_size}} * scaleFactor); {%- endif %} {%- elif object.type == 'comment' %} // comment {{object.id}} = new PDComment({{parent}}); std::string {{object.id}}String = "{{object.text}}"; {{object.id}}->setText({{object.id}}String); {{object.id}}->setFontSize(15 * scaleFactor); {{object.id}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {%- if object.width != None %} {{object.id}}->setSize((7.4 * {{object.width}}) * scaleFactor, 15 * scaleFactor); {%- else %} {{object.id}}->setSize((7.4 * {{object.id}}String.length()) * scaleFactor, 15 * scaleFactor); {%- endif -%} {%- elif object.type == 'bang' %} // bang {{object.parameter}} = new PDBang({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setColors( nvgRGB{{object.bg_color.as_rgb_tuple()}}, nvgRGB{{object.fg_color.as_rgb_tuple()}} ); {{object.parameter}}->setInterval({{object.flash_time}}); {%- if object.label != None %} {{object.parameter}}->setLabel("{{object.label.text}}", nvgRGB{{object.label.color.as_rgb_tuple()}}, {{object.label.position.x}} * scaleFactor, {{object.label.position.y}} * scaleFactor, {{object.label.font_size}} * scaleFactor); {%- endif %} {{parent}}->addManagedChild({{object.parameter}}); {%- elif object.type == 'toggle' %} // toggle {{object.parameter}} = new PDToggle({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setColors( nvgRGB{{object.bg_color.as_rgb_tuple()}}, nvgRGB{{object.fg_color.as_rgb_tuple()}} ); {{parent}}->addManagedChild({{object.parameter}}); {%- elif object.type in ['vradio', 'hradio'] %} // {{object.type}} {{object.parameter}} = new PDRadio({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setStep({{object.options}}); {%- if object.type == "hradio" %} {{object.parameter}}->setHorizontal(); {%- endif %} {{object.parameter}}->setColors( nvgRGB{{object.bg_color.as_rgb_tuple()}}, nvgRGB{{object.fg_color.as_rgb_tuple()}} ); {%- if object.label != None %} {{object.parameter}}->setLabel("{{object.label.text}}", nvgRGB{{object.label.color.as_rgb_tuple()}}, {{object.label.position.x}} * scaleFactor, {{object.label.position.y}} * scaleFactor, {{object.label.font_size}} * scaleFactor); {%- endif %} {{parent}}->addManagedChild({{object.parameter}}); {%- elif object.type in ['vslider', 'hslider'] %} // {{object.type}} {{object.parameter}} = new PDSlider({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setSliderArea(0, 0, {{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {%- if object.type == "vslider" %} {{object.parameter}}->setStartPos(0, {{object.size.y}} * scaleFactor); {{object.parameter}}->setEndPos(0, 0); {{object.parameter}}->setInverted(true); {%- elif object.type == "hslider" %} {{object.parameter}}->setStartPos(0, 0); {{object.parameter}}->setEndPos({{object.size.x}} * scaleFactor, 0); {{object.parameter}}->setHorizontal(); {%- endif %} {{object.parameter}}->setRange({{object.min}}f, {{object.max}}f); {%- for k, v in receivers + senders %} {%- if v.display == object.parameter %} {{object.parameter}}->setDefault({{v.attributes.default}}f); {%- endif %} {%- endfor %} {{object.parameter}}->setUsingLogScale({{object.logarithmic|lower}}); {{object.parameter}}->setSteadyOnClick({{object.steady|lower}}); {{object.parameter}}->setColors( nvgRGB{{object.bg_color.as_rgb_tuple()}}, nvgRGB{{object.fg_color.as_rgb_tuple()}} ); {%- if object.label != None %} {{object.parameter}}->setLabel("{{object.label.text}}", nvgRGB{{object.label.color.as_rgb_tuple()}}, {{object.label.position.x}} * scaleFactor, {{object.label.position.y}} * scaleFactor, {{object.label.font_size}} * scaleFactor); {%- endif %} {{parent}}->addManagedChild({{object.parameter}}); {%- elif object.type == 'knob' %} // knob {{object.parameter}} = new PDKnob({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setKnobArea(0.0f, 0.0f, {{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setRange({{object.min}}f, {{object.max}}f); {%- for k, v in receivers + senders %} {%- if v.display == object.parameter %} {{object.parameter}}->setDefault({{v.attributes.default}}f); {%- endif %} {%- endfor %} {{object.parameter}}->setShowArc({{object.arc_show|lower}}); {{object.parameter}}->setAngular({{object.ang_range}}, {{object.ang_offset}}); {{object.parameter}}->setDrawSquare({{object.square|lower}}); {{object.parameter}}->setShowTicks({{object.ticks|lower}}); {{object.parameter}}->setSteps({{object.steps}}); {{object.parameter}}->setShowArc({{object.arc_show|lower}}); {{object.parameter}}->setJumpOnClick({{object.jump|lower}}); {{object.parameter}}->setDiscrete({{object.discrete|lower}}); {{object.parameter}}->setUsingLogScale(PDKnobEventHandler::LogMode::{{object.log_mode|upper}}); {{object.parameter}}->setColors( nvgRGB{{object.bg_color.as_rgb_tuple()}}, nvgRGB{{object.fg_color.as_rgb_tuple()}}, nvgRGB{{object.arc_color.as_rgb_tuple()}} ); {{object.parameter}}->setLabelStyle({{object.label_pos.x}} * scaleFactor, {{object.label_pos.y}} * scaleFactor, {{object.label_size}} * scaleFactor); {{object.parameter}}->setShowLabel(LabelShow::{{object.label_show.name|upper}}); {{parent}}->addManagedChild({{object.parameter}}); {%- elif object.type == 'number' %} // number {{object.parameter}} = new PDNumber({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, {{object.size.y}} * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setRange({{object.min}}f, {{object.max}}f); {%- for k, v in receivers + senders %} {%- if v.display == object.parameter %} {{object.parameter}}->setDefault({{v.attributes.default}}f); {%- endif %} {%- endfor %} {{object.parameter}}->setColors( nvgRGB{{object.bg_color.as_rgb_tuple()}}, nvgRGB{{object.fg_color.as_rgb_tuple()}} ); {%- if object.label != None %} {{object.parameter}}->setLabel("{{object.label.text}}", nvgRGB{{object.label.color.as_rgb_tuple()}}, {{object.label.position.x}} * scaleFactor, {{object.label.position.y}} * scaleFactor, {{object.label.font_size}} * scaleFactor); {%- endif %} {{parent}}->addManagedChild({{object.parameter}}); {%- elif object.type == 'float' %} // float {{object.parameter}} = new PDFloat({{parent}}, this); {{object.parameter}}->setId(k{{object.parameter|capitalize}}); {{object.parameter}}->setSize({{object.size.x}} * scaleFactor, ({{object.size.y}} * 1.5f) * scaleFactor); {{object.parameter}}->setAbsolutePos({{object.position.x}} * scaleFactor, {{object.position.y}} * scaleFactor); {{object.parameter}}->setRange({{object.min}}f, {{object.max}}f); {%- for k, v in receivers + senders %} {%- if v.display == object.parameter %} {{object.parameter}}->setDefault({{v.attributes.default}}f); {%- endif %} {%- endfor %} {{object.parameter}}->setLabel("{{object.label_text}}", ({{object.font_height}} + 2) * scaleFactor, LabelPos::{{object.label_pos.name|capitalize}}); {{parent}}->addManagedChild({{object.parameter}}); {%- endif %} {%- endfor %} hvcc-0.16.0/hvcc/generators/c2dpf/templates/hostTransportEvents.cpp0000644000000000000000000000365400000000000022273 0ustar00// ------------------------------------------------------------------- // Host Transport Events handler void {{class_name}}::hostTransportEvents(uint32_t frames) { // Realtime events const TimePosition& timePos(getTimePosition()); bool reset = false; if (timePos.playing) { if (timePos.frame == 0) { _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, "ff", (float) MIDI_RT_RESET, 0.0); reset = true; } if (! this->wasPlaying) { if (timePos.frame == 0) { _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, "ff", (float) MIDI_RT_START, 0.0); } if (! reset) { _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, "ff", (float) MIDI_RT_CONTINUE, 0.0); } } } else if (this->wasPlaying) { _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0, "ff", (float) MIDI_RT_STOP, 0.0); } this->wasPlaying = timePos.playing; // sending clock ticks if (timePos.playing && timePos.bbt.valid) { float samplesPerBeat = 60 * getSampleRate() / timePos.bbt.beatsPerMinute; float samplesPerTick = samplesPerBeat / 24.0; /* get state */ double nextClockTick = this->nextClockTick; double sampleAtCycleStart = this->sampleAtCycleStart; double sampleAtCycleEnd = sampleAtCycleStart + frames; if (nextClockTick >= 0 && sampleAtCycleStart >= 0 && sampleAtCycleEnd > sampleAtCycleStart) { while (nextClockTick < sampleAtCycleEnd) { double delayMs = 1000*(nextClockTick - sampleAtCycleStart)/getSampleRate(); if (delayMs >= 0.0) { _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, delayMs, "ff", (float) MIDI_RT_CLOCK, 0.0); } nextClockTick += samplesPerTick; } } /* save variables for next cycle */ this->sampleAtCycleStart = sampleAtCycleEnd; this->nextClockTick = nextClockTick; } } hvcc-0.16.0/hvcc/generators/c2dpf/templates/initParameter.cpp0000644000000000000000000000436400000000000021017 0ustar00 case param{{v.display}}: parameter.name = "{{v.display.replace('_', ' ')}}"; parameter.symbol = "{{v.display|lower}}"; {%- if v.attributes.type == 'db': %} parameter.unit = "dB"; {%- elif v.attributes.type in ['hz', 'log_hz']: %} parameter.unit = "Hz"; {%- endif %} {%- if v.type == "send" %} parameter.hints = kParameterIsOutput {%- else %} parameter.hints = kParameterIsAutomatable {%- endif %} {%- if v.attributes.type == 'bool': %} | kParameterIsBoolean {%- elif v.attributes.type == 'trig' or v.extern == "event": -%} | kParameterIsTrigger {%- elif v.attributes.type == 'int': -%} | kParameterIsInteger {%- elif v.attributes.type in ['log', 'log_hz']: -%} | kParameterIsLogarithmic {%- endif %}; {%- if v.attributes %} parameter.ranges.min = {{v.attributes.min}}f; parameter.ranges.max = {{v.attributes.max}}f; parameter.ranges.def = {{v.attributes.default}}f; {%- else %} parameter.ranges.min = 0.0f; parameter.ranges.max = 1.0f; parameter.ranges.def = 0.0f; {%- endif %} {%- if v.attributes.type == 'db' and not (meta.enumerators != None and meta.enumerators[v.display] is defined): %} { ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[1]; enumValues[0].value = {{v.attributes.min}}f; enumValues[0].label = "-inf"; parameter.enumValues.count = 1; parameter.enumValues.values = enumValues; } {%- endif %} {%- if meta.enumerators != None and meta.enumerators[v.display] is defined %} {% set enums = meta.enumerators[v.display] %} {% set enumlen = enums|length %} if (ParameterEnumerationValue *values = new ParameterEnumerationValue[{{enumlen}}]) { parameter.enumValues.restrictedMode = true; {% for i in enums -%} values[{{loop.index - 1}}].value = {{loop.index - 1}}.0f; values[{{loop.index - 1}}].label = "{{i}}"; {% endfor -%} parameter.enumValues.count = {{enumlen}}; parameter.enumValues.values = values; } {%- endif %} break; hvcc-0.16.0/hvcc/generators/c2dpf/templates/midiInput.cpp0000644000000000000000000000550700000000000020155 0ustar00// ------------------------------------------------------------------- // Midi Input handler void {{class_name}}::handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) { // Midi events for (uint32_t i=0; i < midiEventCount; ++i) { int status = midiEvents[i].data[0]; int command = status & 0xF0; int channel = status & 0x0F; int data1 = midiEvents[i].data[1]; int data2 = midiEvents[i].data[2]; // raw [midiin] messages int dataSize = *(&midiEvents[i].data + 1) - midiEvents[i].data; for (int i = 0; i < dataSize; ++i) { _context->sendMessageToReceiverV(HV_HASH_MIDIIN, 1000.0*midiEvents->frame/getSampleRate(), "ff", (float) midiEvents[i].data[i], (float) channel); } if(mrtSet.find(status) != mrtSet.end()) { _context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 1000.0*midiEvents->frame/getSampleRate(), "ff", (float) status); } // typical midi messages switch (command) { case 0x80: { // note off _context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*midiEvents->frame/getSampleRate(), "fff", (float) data1, // pitch (float) 0, // velocity (float) channel); break; } case 0x90: { // note on _context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*midiEvents->frame/getSampleRate(), "fff", (float) data1, // pitch (float) data2, // velocity (float) channel); break; } case 0xA0: { // polyphonic aftertouch _context->sendMessageToReceiverV(HV_HASH_POLYTOUCHIN, 1000.0*midiEvents->frame/getSampleRate(), "fff", (float) data2, // pressure (float) data1, // note (float) channel); break; } case 0xB0: { // control change _context->sendMessageToReceiverV(HV_HASH_CTLIN, 1000.0*midiEvents->frame/getSampleRate(), "fff", (float) data2, // value (float) data1, // cc number (float) channel); break; } case 0xC0: { // program change _context->sendMessageToReceiverV(HV_HASH_PGMIN, 1000.0*midiEvents->frame/getSampleRate(), "ff", (float) data1, (float) channel); break; } case 0xD0: { // aftertouch _context->sendMessageToReceiverV(HV_HASH_TOUCHIN, 1000.0*midiEvents->frame/getSampleRate(), "ff", (float) data1, (float) channel); break; } case 0xE0: { // pitch bend // combine 7bit lsb and msb into 32bit int hv_uint32_t value = (((hv_uint32_t) data2) << 7) | ((hv_uint32_t) data1); _context->sendMessageToReceiverV(HV_HASH_BENDIN, 1000.0*midiEvents->frame/getSampleRate(), "ff", (float) value, (float) channel); break; } default: break; } } } hvcc-0.16.0/hvcc/generators/c2dpf/templates/midiOutput.cpp0000644000000000000000000000610400000000000020350 0ustar00// ------------------------------------------------------------------- // Midi Send handler void {{class_name}}::handleMidiSend(uint32_t sendHash, const HvMessage *m) { MidiEvent midiSendEvent; midiSendEvent.frame = 0; midiSendEvent.dataExt = nullptr; switch(sendHash){ case HV_HASH_NOTEOUT: // __hv_noteout { uint8_t note = hv_msg_getFloat(m, 0); uint8_t velocity = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; // drop any pd "ports" midiSendEvent.size = 3; if (velocity > 0){ midiSendEvent.data[0] = 0x90 | ch; // noteon } else { midiSendEvent.data[0] = 0x80 | ch; // noteoff } midiSendEvent.data[1] = note; midiSendEvent.data[2] = velocity; writeMidiEvent(midiSendEvent); break; } case HV_HASH_CTLOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t cc = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; midiSendEvent.size = 3; midiSendEvent.data[0] = 0xB0 | ch; // send CC midiSendEvent.data[1] = cc; midiSendEvent.data[2] = value; writeMidiEvent(midiSendEvent); break; } case HV_HASH_POLYTOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t note = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); midiSendEvent.size = 3; midiSendEvent.data[0] = 0xA0 | ch; // send Poly Aftertouch midiSendEvent.data[1] = note; midiSendEvent.data[2] = value; writeMidiEvent(midiSendEvent); break; } case HV_HASH_PGMOUT: { uint8_t pgm = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; midiSendEvent.size = 2; midiSendEvent.data[0] = 0xC0 | ch; // send Program Change midiSendEvent.data[1] = pgm; writeMidiEvent(midiSendEvent); break; } case HV_HASH_TOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; midiSendEvent.size = 2; midiSendEvent.data[0] = 0xD0 | ch; // send Touch midiSendEvent.data[1] = value; writeMidiEvent(midiSendEvent); break; } case HV_HASH_BENDOUT: { uint16_t value = hv_msg_getFloat(m, 0); uint8_t lsb = value & 0x7F; uint8_t msb = (value >> 7) & 0x7F; uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; midiSendEvent.size = 3; midiSendEvent.data[0] = 0xE0 | ch; // send Bend midiSendEvent.data[1] = lsb; midiSendEvent.data[2] = msb; writeMidiEvent(midiSendEvent); break; } case HV_HASH_MIDIOUT: // __hv_midiout { if (midiOutCount == 0) { midiOutEvent.frame = 0; midiOutEvent.dataExt = nullptr; // we don't support sysex midiOutEvent.size = 4; } midiOutEvent.data[midiOutCount] = hv_msg_getFloat(m, 0); if (midiOutCount < 3) { midiOutCount++; break; } writeMidiEvent(midiOutEvent); midiOutCount = 0; break; } default: break; } } hvcc-0.16.0/hvcc/generators/c2dpf/templates/portGroups.cpp0000644000000000000000000000514100000000000020371 0ustar00void {{class_name}}::initAudioPort(bool input, uint32_t index, AudioPort& port) { port.hints = 0x0; if (input) { switch (index) { {%- if meta.port_groups.input|length %} {%- for group, gConfig in meta.port_groups.input.items() %} {%- for port, value in gConfig.items() %} case {{value[0] if value[0] is number else value}}: port.name = "Input {{port}} ({{group}})"; port.symbol = "in_{{port|lower}}_{{group|lower}}"; port.groupId = kPortGroup{{group}}; {%- if value[1] is sameas true %} port.hints = kAudioPortIsCV | kCVPortHasPositiveUnipolarRange | kCVPortHasScaledRange | kCVPortIsOptional; {%- endif %} break; {%- endfor %} {%- endfor %} {%- else %} {%- if num_input_channels == 2 %} case 0: port.name = "Input Left"; port.symbol = "in_left"; break; case 1: port.name = "Input Right"; port.symbol = "in_right"; break; port.groupId = kPortGroupStereo; {%- endif %} {%- endif %} } } else { switch (index) { {%- if meta.port_groups.output|length %} {%- for group, gConfig in meta.port_groups.output.items() %} {%- for port, value in gConfig.items() %} case {{value[0] if value[0] is number else value}}: port.name = "Output {{port}} ({{group}})"; port.symbol = "out_{{port|lower}}_{{group|lower}}"; port.groupId = kPortGroup{{group}}; {%- if value[1] is sameas true %} port.hints = kAudioPortIsCV | kCVPortHasPositiveUnipolarRange | kCVPortHasScaledRange | kCVPortIsOptional; {%- endif %} break; {%- endfor %} {%- endfor %} {% else %} {%- if num_output_channels == 2 %} case 0: port.name = "Output Left"; port.symbol = "out_left"; break; case 1: port.name = "Output Right"; port.symbol = "out_right"; break; port.groupId = kPortGroupStereo; {%- endif %} {%- endif %} } } } void {{class_name}}::initPortGroup(uint32_t groupId, PortGroup& portGroup) { switch (groupId) { {%- if meta.port_groups.input|length %} {%- for group, value in meta.port_groups.input.items() %} case kPortGroup{{group}}: portGroup.name = "{{group}}"; portGroup.symbol = "{{group|lower}}"; break; {%- endfor %} {%- endif %} {%- if meta.port_groups.output|length %} {%- for group, value in meta.port_groups.output.items() %} case kPortGroup{{group}}: portGroup.name = "{{group}}"; portGroup.symbol = "{{group|lower}}"; break; {%- endfor %} {%- endif %} } } hvcc-0.16.0/hvcc/generators/c2fmod/__init__.py0000644000000000000000000000000000000000000015755 0ustar00hvcc-0.16.0/hvcc/generators/c2fmod/c2fmod.py0000644000000000000000000000762500000000000015414 0ustar00# Heavy Compiler Collection # Copyright (C) 2024-2026 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only import jinja2 import os import shutil import time from typing import Optional from pathlib import Path from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta from ..copyright import copyright_manager class c2fmod(Generator): """Generates a FMOD plugin wrapper for a given patch.""" @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False, ) -> CompilerResp: tick = time.time() patch_name = patch_name.lower() if patch_name is not None else "heavy" in_parameter_list = externs.parameters.inParam out_parameter_list = externs.parameters.outParam event_list = externs.events.inEvent out_event_list = externs.events.outEvent table_list = externs.tables copyright_c = copyright_manager.get_copyright_for_c(copyright) templates_dir = Path(Path(__file__).parent, "templates") is_source_plugin = num_input_channels == 0 out_dir = Path(out_dir, "fmod") if not out_dir.exists(): out_dir.mkdir(parents=True) env = jinja2.Environment() env.loader = jinja2.FileSystemLoader( encoding="utf-8-sig", searchpath=[templates_dir] ) try: patch_src_dir = Path(out_dir, "include", "Heavy") if patch_src_dir.exists(): shutil.rmtree(patch_src_dir) shutil.copytree(c_src_dir, patch_src_dir) heavy_src_files = [f for f in os.listdir(c_src_dir) if f.endswith(".c") or f.endswith(".cpp")] src_ext_list = ["h", "hpp", "c", "cpp", "js", "md", "txt"] for f in env.list_templates(extensions=src_ext_list): file = Path(f) file_dir = Path(out_dir, file.parent) file_name = file.name.replace("{{name}}", patch_name) file_path = Path(file_dir, file_name) if not file_path.parent.exists(): file_path.parent.mkdir(parents=True) with open(file_path, "w") as g: g.write(env.get_template(f).render( name=patch_name, in_params=in_parameter_list, out_params=out_parameter_list, out_events=out_event_list, events=event_list, tables=table_list, pool_sizes_kb=externs.memoryPoolSizesKb, is_source_plugin=is_source_plugin, num_input_channels=num_input_channels, num_output_channels=num_output_channels, heavy_src_files=heavy_src_files, copyright=copyright_c)) return CompilerResp( stage="c2fmod", in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2fmod", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2fmod/templates/CMakeLists.txt0000644000000000000000000000250500000000000020416 0ustar00cmake_minimum_required(VERSION 3.29.0) project({{name}}) if(NOT IS_DIRECTORY ${CMAKE_SOURCE_DIR}/include/fmod) message(FATAL_ERROR "FMOD SDK MISSING: ${CMAKE_SOURCE_DIR}/include/fmod") endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED 17) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_STATIC_LIBRARY_PREFIX "") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/$) set(CMAKE_SHARED_LIBRARY_PREFIX "") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/$) add_library( objlib OBJECT ${CMAKE_SOURCE_DIR}/src/{{name}}.cpp ) set_target_properties( objlib PROPERTIES POSITION_INDEPENDENT_CODE True ) target_sources( objlib PRIVATE {%- for file in heavy_src_files %} ${CMAKE_SOURCE_DIR}/include/Heavy/{{file}} {%- endfor %} ) target_include_directories( objlib PRIVATE ${CMAKE_SOURCE_DIR}/include/Heavy ${CMAKE_SOURCE_DIR}/include/fmod/core/inc ${CMAKE_SOURCE_DIR}/include/fmod/studio/inc ) add_library(${PROJECT_NAME} SHARED $) add_library(lib${PROJECT_NAME} STATIC $) add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${CMAKE_SOURCE_DIR}/src/{{name}}.plugin.js ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/{{name}}.plugin.js ) hvcc-0.16.0/hvcc/generators/c2fmod/templates/include/README.md0000644000000000000000000000041500000000000020556 0ustar00# FMOD SDK In order to build the project this folder needs to contain the [FMOD SDK](https://www.fmod.com/download#fmodengine) in the sub folder `fmod`. The directory structure should look like this. ``` include/fmod/core include/fmod/fsbank include/fmod/studio ``` hvcc-0.16.0/hvcc/generators/c2fmod/templates/src/{{name}}.cpp0000644000000000000000000002274000000000000021054 0ustar00{{copyright}} #include #include "fmod.hpp" #include "Heavy_{{name}}.hpp" //------------------------------------------------------------------------------ enum class PluginParameterType { Float, Int, Bool }; struct PluginParameter { PluginParameterType type; union { float f; int i; bool b; }; explicit PluginParameter(const float val) : type(PluginParameterType::Float), f(val) {} explicit PluginParameter(const int val) : type(PluginParameterType::Int), i(val) {} explicit PluginParameter(const bool val) : type(PluginParameterType::Bool), b(val) {} }; //------------------------------------------------------------------------------ struct Plugin{{name|capitalize}} { int numInputs, numOutputs; std::array paramArray; std::array hashArray; HeavyContextInterface *ctx; }; //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginCreate(FMOD_DSP_STATE *dspState) { dspState->plugindata = static_cast(FMOD_DSP_ALLOC(dspState, sizeof(Plugin{{name|capitalize}}))); if (!dspState->plugindata) { return FMOD_ERR_MEMORY; } int samplerate; dspState->functions->getsamplerate(dspState, &samplerate); auto *plugin = static_cast(dspState->plugindata); plugin->ctx = new Heavy_{{name}}(static_cast(samplerate), {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); plugin->numInputs = plugin->ctx->getNumInputChannels(); plugin->numOutputs = plugin->ctx->getNumOutputChannels(); {%- for param, i in in_params %} {%- if i.attributes.type == "float" %} plugin->paramArray[{{loop.index0}}] = PluginParameter({{i.attributes.default}}f); {%- elif i.attributes.type == "int" %} plugin->paramArray[{{loop.index0}}] = PluginParameter(static_cast({{i.attributes.default}})); {%- elif i.attributes.type == "bool" %} plugin->paramArray[{{loop.index0}}] = PluginParameter(static_cast({{i.attributes.default}})); {%- endif %} plugin->hashArray[{{loop.index0}}] = Heavy_{{name}}::Parameter::In::{{param|upper}}; {%- endfor %} return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginRelease(FMOD_DSP_STATE *dspState) { auto plugin = static_cast(dspState->plugindata); delete plugin->ctx; FMOD_DSP_FREE(dspState, plugin); return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginProcess ( FMOD_DSP_STATE *dspState, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inBuffers, FMOD_DSP_BUFFER_ARRAY *outBuffers, FMOD_BOOL inputsIdle, FMOD_DSP_PROCESS_OPERATION op ) { const auto plugin = static_cast(dspState->plugindata); switch (op) { case FMOD_DSP_PROCESS_QUERY: if (inBuffers && outBuffers) { outBuffers[0].bufferchannelmask[0] = inBuffers[0].bufferchannelmask[0]; outBuffers[0].speakermode = inBuffers[0].speakermode; {%- if is_source_plugin %} outBuffers[0].buffernumchannels[0] = plugin->numOutputs; return FMOD_OK; {%- else %} if (plugin->numInputs > 0) { if (inputsIdle) { return FMOD_ERR_DSP_DONTPROCESS; } if (inBuffers[0].buffernumchannels[0] != plugin->numInputs || outBuffers[0].buffernumchannels[0] != plugin->numOutputs) { return FMOD_ERR_DSP_SILENCE; } } {%- endif %} } break; case FMOD_DSP_PROCESS_PERFORM: if (inBuffers && outBuffers) { plugin->ctx->processInlineInterleaved(inBuffers[0].buffers[0], outBuffers[0].buffers[0], static_cast(length)); } break; } return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginReset(FMOD_DSP_STATE *dspState) { // NOTE: reset plugin state here if needed // auto plugin = static_cast(dspState->plugindata); return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginSetFloat ( FMOD_DSP_STATE *dspState, int idx, float val ) { auto plugin = static_cast(dspState->plugindata); if (idx >= plugin->paramArray.size() || plugin->paramArray[idx].type != PluginParameterType::Float) { return FMOD_ERR_INVALID_PARAM; } plugin->paramArray[idx].f = val; plugin->ctx->sendFloatToReceiver(plugin->hashArray[idx], val); return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginGetFloat ( FMOD_DSP_STATE *dspState, int idx, float *outVal, char *outValStr ) { auto plugin = static_cast(dspState->plugindata); if (idx >= plugin->paramArray.size() || plugin->paramArray[idx].type != PluginParameterType::Float) { return FMOD_ERR_INVALID_PARAM; } *outVal = plugin->paramArray[idx].f; if (outValStr) { snprintf(outValStr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%.1f", plugin->paramArray[idx].f); } return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginSetInt ( FMOD_DSP_STATE *dspState, int idx, int val ) { auto plugin = static_cast(dspState->plugindata); if (idx >= plugin->paramArray.size() || plugin->paramArray[idx].type != PluginParameterType::Int) { return FMOD_ERR_INVALID_PARAM; } plugin->paramArray[idx].i = val; plugin->ctx->sendFloatToReceiver(plugin->hashArray[idx], static_cast(val)); return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginGetInt ( FMOD_DSP_STATE *dspState, int idx, int *outVal, char *outValStr ) { auto plugin = static_cast(dspState->plugindata); if (idx >= plugin->paramArray.size() || plugin->paramArray[idx].type != PluginParameterType::Int) { return FMOD_ERR_INVALID_PARAM; } *outVal = plugin->paramArray[idx].i; if (outValStr) { snprintf(outValStr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%d", plugin->paramArray[idx].i); } return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginSetBool( FMOD_DSP_STATE *dspState, int idx, FMOD_BOOL val ) { auto plugin = static_cast(dspState->plugindata); if (idx >= plugin->paramArray.size() || plugin->paramArray[idx].type != PluginParameterType::Bool) { return FMOD_ERR_INVALID_PARAM; } plugin->paramArray[idx].b = static_cast(val); plugin->ctx->sendFloatToReceiver(plugin->hashArray[idx], static_cast(val)); return FMOD_OK; } //------------------------------------------------------------------------------ static FMOD_RESULT F_CALL PluginGetBool( FMOD_DSP_STATE *dspState, int idx, int *outVal, char *outValStr ) { auto plugin = static_cast(dspState->plugindata); if (idx >= plugin->paramArray.size() || plugin->paramArray[idx].type != PluginParameterType::Bool) { return FMOD_ERR_INVALID_PARAM; } *outVal = static_cast(plugin->paramArray[idx].b); if (outValStr) { snprintf(outValStr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%d", plugin->paramArray[idx].b); } return FMOD_OK; } //------------------------------------------------------------------------------ extern "C" { F_EXPORT FMOD_DSP_DESCRIPTION *F_CALL FMODGetDSPDescription() { {%- for param, i in in_params %} static FMOD_DSP_PARAMETER_DESC param_{{param}}; {%- endfor %} static FMOD_DSP_PARAMETER_DESC *param_desc[{{in_params|length}}] = { {%- for param, i in in_params %} ¶m_{{param}}, {%- endfor %} }; {%- for param, i in in_params %} {%- if i.attributes.type == "float" %} FMOD_DSP_INIT_PARAMDESC_FLOAT(param_{{param}}, "{{i.display}}", "", "{{i.display}}", {{i.attributes.min}}f, {{i.attributes.max}}f, {{i.attributes.default}}f); {%- elif i.attributes.type == "int" %} FMOD_DSP_INIT_PARAMDESC_INT(param_{{param}}, "{{i.display}}", "", "{{i.display}}", {{i.attributes.min}}, {{i.attributes.max}}, {{i.attributes.default}}, false, nullptr); {%- elif i.attributes.type == "bool" %} FMOD_DSP_INIT_PARAMDESC_BOOL(param_{{param}}, "{{i.display}}", "", "{{i.display}}", {{i.attributes.default}}, nullptr); {%- endif %} {%- endfor %} static FMOD_DSP_DESCRIPTION desc { FMOD_PLUGIN_SDK_VERSION, "{{name}}", 1}; desc.numinputbuffers = {{"0" if is_source_plugin else "1"}}; desc.numoutputbuffers = 1; desc.create = PluginCreate; desc.release = PluginRelease; desc.reset = PluginReset; desc.process = PluginProcess; desc.numparameters = {{in_params|length}}; desc.paramdesc = param_desc; desc.setparameterfloat = PluginSetFloat; desc.getparameterfloat = PluginGetFloat; desc.setparameterint = PluginSetInt; desc.getparameterint = PluginGetInt; desc.setparameterbool = PluginSetBool; desc.getparameterbool = PluginGetBool; return &desc; } } //------------------------------------------------------------------------------ hvcc-0.16.0/hvcc/generators/c2fmod/templates/src/{{name}}.plugin.js0000644000000000000000000000042000000000000022172 0ustar00studio.plugins.registerPluginDescription("{{name}}", { companyName: "Wasted Audio", productName: "{{name|capitalize}}", parameters: { {%- for param, i in in_params %} "{{param}}": { displayName: "{{param|capitalize}}" }, {%- endfor %} }, }); hvcc-0.16.0/hvcc/generators/c2js/README.md0000644000000000000000000000025500000000000014626 0ustar00# c2js Generator Note: make sure emscripten sdk is sourced and `emcc` command is in your PATH: http://kripken.github.io/emscripten-site/docs/getting_started/downloads.htmlhvcc-0.16.0/hvcc/generators/c2js/__init__.py0000644000000000000000000000000000000000000015444 0ustar00hvcc-0.16.0/hvcc/generators/c2js/c2js.py0000644000000000000000000002514700000000000014571 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import os import subprocess import time import jinja2 from shutil import which from typing import Optional from pathlib import Path from hvcc.core.hv2ir.HeavyException import HeavyException from ..copyright import copyright_manager from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta class c2js(Generator): """Compiles a directory of C source files into javascript. Requires the emscripten library to be installed - https://github.com/kripken/emscripten """ __HV_API = [ "_hv_{0}_new", "_hv_{0}_new_with_options", "_hv_delete", "_hv_processInline", "_hv_getNumInputChannels", "_hv_getNumOutputChannels", "_hv_samplesToMilliseconds", "_hv_setPrintHook", "_hv_setSendHook", "_hv_sendFloatToReceiver", "_hv_sendBangToReceiver", "_hv_sendSymbolToReceiver", "_hv_stringToHash", "_hv_msg_getByteSize", "_hv_msg_init", "_hv_msg_hasFormat", "_hv_msg_setFloat", "_hv_msg_getFloat", "_hv_msg_getTimestamp", "_hv_table_getLength", "_hv_table_setLength", "_hv_table_getBuffer", "_hv_sendMessageToReceiverV", "_hv_sendMessageToReceiverFF", "_hv_sendMessageToReceiverFFF", "_malloc" # Rationale: https://github.com/emscripten-core/emscripten/issues/6882#issuecomment-406745898 ] @classmethod def run_emscripten( cls, c_src_dir: Path, out_dir: Path, patch_name: str, output_name: str, post_js_path: Path, should_modularize: int, environment: str, pre_js_path: Path = Path(), binaryen_async: int = 1 ) -> Path: """Run the emcc command to compile C source files to a javascript library. """ # Detect Windows OS, but ignore if running in MingW if os.name == 'nt' and os.environ.get('MSYSTEM') is None: emcc_path = which("emcc.bat") else: emcc_path = which("emcc") if emcc_path is None: raise HeavyException("emcc is not in the PATH") c_flags = [ f"-I {c_src_dir}", "-DHV_SIMD_NONE", "-DHV_BARE_METAL", "-ffast-math", "-DNDEBUG", "-Wall" ] c_src_paths = [Path(c_src_dir, c) for c in os.listdir(c_src_dir) if c.endswith((".c"))] cpp_src_paths = [Path(c_src_dir, cpp) for cpp in os.listdir(c_src_dir) if cpp.endswith((".cpp"))] obj_paths = [] cmd = "" # compile C files for c in c_src_paths: obj_path = f"{os.path.splitext(c)[0]}.o" cmd = [emcc_path] + c_flags + ["-c", "-o", obj_path, c] # type: ignore subprocess.check_output(cmd) # run emscripten obj_paths += [obj_path] # compile C++ files for cpp in cpp_src_paths: obj_path = f"{os.path.splitext(cpp)[0]}.o" cmd = [emcc_path] + c_flags + ["-std=c++11"] + ["-c", "-o", obj_path, cpp] # type: ignore subprocess.check_output(cmd) # run emscripten obj_paths += [obj_path] # exported heavy api methods hv_api_defs = ", ".join([f"\"{x.format(patch_name)}\"" for x in cls.__HV_API]) # output path wasm_js_path = Path(out_dir, f"{output_name}.js") linker_flags = [ "-O3", "-s", "RESERVED_FUNCTION_POINTERS=2", "-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$addFunction", "-s", f"EXPORTED_FUNCTIONS=[{hv_api_defs.format(patch_name)}]", "-s", "EXPORTED_RUNTIME_METHODS=HEAPF32", "-s", f"MODULARIZE={should_modularize}", "-s", "ASSERTIONS=1", "-s", f"ENVIRONMENT={environment}", "-s", "SINGLE_FILE=1", "-s", "ALLOW_TABLE_GROWTH=1", "-s", f"BINARYEN_ASYNC_COMPILATION={binaryen_async}", # Set this to 0 for the worklet so we don't # wait for promises when instantiating "--post-js", post_js_path ] if pre_js_path != Path(): linker_flags = linker_flags + [ "--pre-js", pre_js_path ] # include C/C++ obj files in js library cmd = [emcc_path] + obj_paths + linker_flags # type: ignore subprocess.check_output( # WASM cmd + [ # type: ignore "-s", "WASM=1", "-s", f"EXPORT_NAME='{output_name}_Module'", "-o", wasm_js_path ]) # clean up for o in obj_paths: os.remove(o) return wasm_js_path @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() parameter_list = externs.parameters.inParam parameter_out_list = externs.parameters.outParam event_list = externs.events.inEvent event_out_list = externs.events.outEvent midi_list = externs.midi.inMidi midi_out_list = externs.midi.outMidi out_dir = Path(out_dir, "js") patch_name = patch_name or "heavy" copyright_js = copyright_manager.get_copyright_for_c(copyright) copyright_html = copyright_manager.get_copyright_for_xml(copyright) if not out_dir.exists(): os.makedirs(out_dir) out_dir = out_dir.absolute() try: # initialise the jinja template environment env = jinja2.Environment() env.loader = jinja2.FileSystemLoader(Path( Path(__file__).parent, "template")) # generate heavy js wrapper from template # Note: this file will be incorporated into the emscripten output # and removed afterwards post_js_path = Path(out_dir, "hv_wrapper.js") with open(post_js_path, "w") as f: f.write(env.get_template("hv_wrapper.js").render( name=patch_name, copyright=copyright_js, externs=externs, pool_sizes_kb=externs.memoryPoolSizesKb)) js_path = cls.run_emscripten(c_src_dir=c_src_dir, out_dir=out_dir, patch_name=patch_name, output_name=patch_name, post_js_path=post_js_path, should_modularize=1, environment="web") # delete temporary files os.remove(post_js_path) js_out_file = js_path.name # generate index.html from template with open(Path(out_dir, "index.html"), "w") as f: f.write(env.get_template("index.html").render( name=patch_name, includes=[f"./{js_out_file}"], parameters=parameter_list, parameters_out=parameter_out_list, events=event_list, events_out=event_out_list, midi=midi_list, midi_out=midi_out_list, copyright=copyright_html)) # generate heavy js worklet from template # Note: this file will be incorporated into the emscripten output # and removed afterwards post_js_path = Path(out_dir, "hv_worklet.js") with open(post_js_path, "w") as f: f.write(env.get_template("hv_worklet.js").render( name=patch_name, copyright=copyright_js, externs=externs, pool_sizes_kb=externs.memoryPoolSizesKb)) pre_js_path = Path(out_dir, "hv_worklet_start.js") with open(pre_js_path, "w") as f: f.write(env.get_template("hv_worklet_start.js").render( name=patch_name, copyright=copyright_js, externs=externs, pool_sizes_kb=externs.memoryPoolSizesKb)) js_path = cls.run_emscripten(c_src_dir=c_src_dir, out_dir=out_dir, patch_name=patch_name, output_name=f"{patch_name}_AudioLibWorklet", post_js_path=post_js_path, should_modularize=0, environment="shell,worker", pre_js_path=pre_js_path, binaryen_async=0) # delete temporary files os.remove(post_js_path) os.remove(pre_js_path) return CompilerResp( stage="c2js", in_dir=c_src_dir, out_dir=out_dir, out_file=js_out_file, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2js", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2js/template/hv_worklet.js0000644000000000000000000003024400000000000017705 0ustar00{{copyright}} /* * AudioLibWorklet - Processes the audio through the Heavy C API */ class {{name}}_AudioLibWorklet extends AudioWorkletProcessor { constructor({ processorOptions }) { super(); this.sampleRate = processorOptions.sampleRate || 44100.0; // As of right now (June 2022), blockSize is always 128. // In the future, it could become dynamic, // and we'll have to read the lengths of incoming outputs and re-alloc the outputBuffer if it changes. this.blockSize = 128; // instantiate heavy context this.heavyContext = _hv_{{name}}_new_with_options(this.sampleRate, {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); this.setPrintHook(); this.setSendHook(); // allocate temporary buffers (pointer size is 4 bytes in javascript) var lengthOutSamples = this.blockSize * this.getNumOutputChannels(); var lengthInSamples = this.blockSize * this.getNumInputChannels(); this.outputBuffer = new Float32Array( Module.HEAPF32.buffer, Module._malloc(lengthOutSamples * Float32Array.BYTES_PER_ELEMENT), lengthOutSamples); this.inputBuffer = new Float32Array( Module.HEAPF32.buffer, Module._malloc(lengthInSamples * Float32Array.BYTES_PER_ELEMENT), lengthInSamples); this.port.onmessage = (e) => { console.log(e.data); switch(e.data.type){ case 'setFloatParameter': this.setFloatParameter(e.data.name, e.data.value); break; case 'sendEvent': this.sendEvent(e.data.name); break; case 'sendMidi': this.sendMidi(e.data.message); break; case 'fillTableWithFloatBuffer': this.fillTableWithFloatBuffer(e.data.name, e.data.buffer); break; default: console.error('No handler for message of type: ', e.data.type); } } } process(inputs, outputs, parameters) { // Currently only supports one output connection and one input connection (inputs[0] and outputs[0]) try{ var inputChannelCount = this.getNumInputChannels(); if (inputs.length > 0 && inputs[0].length && inputChannelCount > 0) { for (let c = 0; c < inputChannelCount; c++) { if (!inputs[0][c]) { continue; } this.inputBuffer.set(inputs[0][c], c * this.blockSize); } } else { this.inputBuffer.set(0); //clear buffer when no inputs are connected } _hv_processInline(this.heavyContext, this.inputBuffer.byteOffset, this.outputBuffer.byteOffset, this.blockSize); var output = outputs[0]; var outputChannelCount = this.getNumOutputChannels(); for (var i = 0; i < outputChannelCount; ++i) { output[i].set(this.outputBuffer.subarray(i * this.blockSize, (i + 1) * this.blockSize)) } } catch(e){ this.port.postMessage({ type:'error', error: e.toString() }); } return true; } getNumInputChannels() { return (this.heavyContext) ? _hv_getNumInputChannels(this.heavyContext) : -1; } getNumOutputChannels() { return (this.heavyContext) ? _hv_getNumOutputChannels(this.heavyContext) : -1; } setPrintHook() { if (!this.heavyContext) { console.error("heavy: Can't set Print Hook, no Heavy Context instantiated"); return; } var self = this; // typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg); var printHook = addFunction(function(context, printName, str, msg) { // Converts Heavy print callback to a printable message var timeInSecs =_hv_samplesToMilliseconds(context, _hv_msg_getTimestamp(msg)) / 1000.0; var m = UTF8ToString(printName) + " [" + timeInSecs.toFixed(3) + "]: " + UTF8ToString(str); self.port.postMessage({ type: 'printHook', payload: m }); }, "viiii" ); _hv_setPrintHook(this.heavyContext, printHook); } setSendHook() { if (!this.heavyContext) { console.error("heavy: Can't set Send Hook, no Heavy Context instantiated"); return; } var self = this; // typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg); var sendHook = addFunction(function(context, sendName, sendHash, msg) { // Filter out MIDI messages const midiMessage = sendMidiOut(UTF8ToString(sendName), msg); if (midiMessage.length > 0) { self.port.postMessage({ type: 'midiOut', payload: midiMessage }); } else { // Converts sendhook callback to (sendName, float) message self.port.postMessage({ type: 'sendHook', payload: [UTF8ToString(sendName), _hv_msg_getFloat(msg, 0)] }); } }, "viiii" ); _hv_setSendHook(this.heavyContext, sendHook); } sendEvent(name) { if (this.heavyContext) { _hv_sendBangToReceiver(this.heavyContext, eventInHashes[name]); } } setFloatParameter(name, floatValue) { if (this.heavyContext) { _hv_sendFloatToReceiver(this.heavyContext, parameterInHashes[name], parseFloat(floatValue)); } } sendMidi(message) { sendMidiIn(this.heavyContext, message); } sendStringToReceiver(name, message) { // Note(joe): it's not a good idea to call this frequently it is possible for // the stack memory to run out over time. if (this.heavyContext) { var r = allocate(intArrayFromString(name), 'i8', ALLOC_STACK); var m = allocate(intArrayFromString(message), 'i8', ALLOC_STACK); _hv_sendSymbolToReceiver(this.heavyContext, _hv_stringToHash(r), m); } } fillTableWithFloatBuffer(name, buffer) { var tableHash = tableHashes[name]; if (_hv_table_getBuffer(this.heavyContext, tableHash) !== 0) { // resize current table to new buffer length _hv_table_setLength(this.heavyContext, tableHash, buffer.length); // access internal float buffer from table let tableBuffer = new Float32Array( Module.HEAPF32.buffer, _hv_table_getBuffer(this.heavyContext, tableHash), buffer.length); // set the table buffer with the data from the 1st channel (mono) tableBuffer.set(buffer); } else { console.error("heavy: Table '" + name + "' doesn't exist in the patch context."); } } } var parameterInHashes = { {%- for k,v in externs.parameters.inParam %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var parameterOutHashes = { {%- for k,v in externs.parameters.outParam %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var eventInHashes = { {%- for k,v in externs.events.inEvent %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var eventOutHashes = { {%- for k,v in externs.events.outEvent %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var tableHashes = { {%- for k,v in externs.tables %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; registerProcessor("{{name}}_AudioLibWorklet", {{name}}_AudioLibWorklet); // midi_utils function sendMidiIn(hv_context, message) { if (hv_context) { var command = message[0] & 0xF0; var channel = message[0] & 0x0F; var data1 = message[1]; var data2 = message[2]; // all events to [midiin] for (var i = 1; i <= 2; i++) { _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIIN, 0, message[i], channel ); } // realtime events to [midirealtimein] if (MIDI_REALTIME.includes(message[0])) { _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIREALTIMEIN, 0, message[0] ); } switch(command) { case 0x80: // note off _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, data1, 0, channel); break; case 0x90: // note on _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, data1, data2, channel); break; case 0xA0: // polyphonic aftertouch _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_POLYTOUCHIN, 0, data2, // pressure data1, // note channel); break; case 0xB0: // control change _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_CTLIN, 0, data2, // value data1, // cc number channel); break; case 0xC0: // program change _hv_sendMessageToReceiverFF(hv_context, HV_HASH_PGMIN, 0, data1, channel); break; case 0xD0: // aftertouch _hv_sendMessageToReceiverFF(hv_context, HV_HASH_TOUCHIN, 0, data1, channel); break; case 0xE0: // pitch bend // combine 7bit lsb and msb into 32bit int var value = (data2 << 7) | data1; _hv_sendMessageToReceiverFF(hv_context, HV_HASH_BENDIN, 0, value, channel); break; default: // console.error('No handler for midi message: ', message); } } } function sendMidiOut(sendName, msg) { switch (sendName) { case "__hv_noteout": var note = _hv_msg_getFloat(msg, 0); var velocity = _hv_msg_getFloat(msg, 1); var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports return [ ((velocity > 0) ? 144 : 128) | channel, note, velocity ] case "__hv_ctlout": var value = _hv_msg_getFloat(msg, 0); var cc = _hv_msg_getFloat(msg, 1); var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports return [ 176 | channel, cc, value ] case "__hv_pgmout": var program = _hv_msg_getFloat(msg, 0); var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports return [ 192 | channel, program ] case "__hv_touchout": var pressure = _hv_msg_getFloat(msg, 0); var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports return [ 208 | channel, pressure, ] case "__hv_polytouchout": var value = _hv_msg_getFloat(msg, 0); var note = _hv_msg_getFloat(msg, 1); var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports return[ 160 | channel, note, value ] case "__hv_bendout": var value = _hv_msg_getFloat(msg, 0); let lsb = value & 0x7F; let msb = (value >> 7) & 0x7F; var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports return [ 224 | channel, lsb, msb ] case "__hv_midiout": let firstByte = _hv_msg_getFloat(msg, 0); return (firstByte === 192 || firstByte === 208) ? [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1)] : [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1), _hv_msg_getFloat(msg, 2)]; default: console.warn(`Unhandled sendName: ${sendName}`); return []; } } /* * MIDI Constants */ const HV_HASH_NOTEIN = 0x67E37CA3; const HV_HASH_CTLIN = 0x41BE0f9C; const HV_HASH_POLYTOUCHIN = 0xBC530F59; const HV_HASH_PGMIN = 0x2E1EA03D; const HV_HASH_TOUCHIN = 0x553925BD; const HV_HASH_BENDIN = 0x3083F0F7; const HV_HASH_MIDIIN = 0x149631bE; const HV_HASH_MIDIREALTIMEIN = 0x6FFF0BCF; const MIDI_REALTIME = [0xF8, 0xFA, 0xFB, 0xFC, 0xFE, 0xFF]; hvcc-0.16.0/hvcc/generators/c2js/template/hv_worklet_start.js0000644000000000000000000000050400000000000021116 0ustar00 // Some hacks gathered from this thread: https://github.com/emscripten-core/emscripten/issues/6230 var self = { location: { href: "http://localhost:3000/" // URL where the module was loaded from } }; function importScripts(){ console.warn('importScripts should not be called in an AudioWorklet', arguments); } hvcc-0.16.0/hvcc/generators/c2js/template/hv_wrapper.js0000644000000000000000000003723300000000000017703 0ustar00{{copyright}} var audioWorkletSupported = (typeof AudioWorklet === 'function'); /* * AudioLibLoader - Convenience functions for setting up the web audio context * and initialising the AudioLib context */ var AudioLibLoader = function() { this.isPlaying = false; this.webAudioContext = null; this.webAudioProcessor = null; this.webAudioWorklet = null; this.audiolib = null; } /* * @param (Object) options * @param options.blockSize (Number) number of samples to process in each iteration * @param options.printHook (Function) callback that gets triggered on each print message * @param options.sendHook (Function) callback that gets triggered for messages sent via @hv_param/@hv_event */ AudioLibLoader.prototype.init = function(options) { // use provided web audio context or create a new one this.webAudioContext = options.webAudioContext || (new (window.AudioContext || window.webkitAudioContext || null)); if (this.webAudioContext) { return (async() => { var blockSize = options.blockSize || 2048; if (audioWorkletSupported) { await this.webAudioContext.audioWorklet.addModule("{{name}}_AudioLibWorklet.js"); this.webAudioWorklet = new AudioWorkletNode(this.webAudioContext, "{{name}}_AudioLibWorklet", { outputChannelCount: [2], processorOptions: { sampleRate: this.webAudioContext.sampleRate, blockSize, } }); this.webAudioWorklet.port.onmessage = (event) => { if (event.data.type === 'printHook' && options.printHook) { options.printHook(event.data.payload); } else if (event.data.type === 'sendHook' && options.sendHook) { options.sendHook(event.data.payload[0], event.data.payload[1]); } else if (event.data.type === 'midiOut' && options.sendHook) { options.sendHook("midiOutMessage", event.data.payload); } else { console.log('Unhandled message from {{name}}_AudioLibWorklet:', event.data); } }; this.webAudioWorklet.connect(this.webAudioContext.destination); } else { console.warn('heavy: AudioWorklet not supported, reverting to ScriptProcessorNode'); var instance = new {{name}}_AudioLib({ sampleRate: this.webAudioContext.sampleRate, blockSize: blockSize, printHook: options.printHook, sendHook: options.sendHook }); this.audiolib = instance; this.webAudioProcessor = this.webAudioContext.createScriptProcessor(blockSize, instance.getNumInputChannels(), Math.max(instance.getNumOutputChannels(), 1)); this.webAudioProcessor.onaudioprocess = (function(e) { instance.process(e) }) } })(); } else { console.error("heavy: failed to load - WebAudio API not available in this browser") } } AudioLibLoader.prototype.start = function() { if (this.audiolib) { this.webAudioProcessor.connect(this.webAudioContext.destination); } else { this.webAudioContext.resume(); } this.isPlaying = true; } AudioLibLoader.prototype.stop = function() { if (this.audiolib) { this.webAudioProcessor.disconnect(this.webAudioContext.destination); } else { this.webAudioContext.suspend(); } this.isPlaying = false; } AudioLibLoader.prototype.sendFloatParameterToWorklet = function(name, value) { if (this.audiolib) { this.audiolib.sendEvent(name, value); } else { this.webAudioWorklet.port.postMessage({ type:'setFloatParameter', name, value }); } } AudioLibLoader.prototype.sendEvent = function(name, value) { if (this.audiolib) { this.audiolib.sendEvent(name, value); } else { this.webAudioWorklet.port.postMessage({ type:'sendEvent', name, value }); } } AudioLibLoader.prototype.sendMidi = function(message) { if (this.audiolib) { this.audiolib.sendMidi(message); } else { this.webAudioWorklet.port.postMessage({ type:'sendMidi', message:message }); } } AudioLibLoader.prototype.fillTableWithFloatBuffer = function(name, buffer) { if (this.audiolib) { this.audiolib.fillTableWithFloatBuffer(name, buffer); } else { this.webAudioWorklet.port.postMessage({ type:'fillTableWithFloatBuffer', name, buffer }); } } Module.AudioLibLoader = AudioLibLoader; /* * Heavy Javascript AudioLib - Wraps over the Heavy C API */ /* * @param (Object) options * @param options.sampleRate (Number) audio sample rate * @param options.blockSize (Number) number of samples to process in each iteration * @param options.printHook (Function) callback that gets triggered on each print message * @param options.sendHook (Function) callback that gets triggered for messages sent via @hv_param/@hv_event */ var {{name}}_AudioLib = function(options) { this.sampleRate = options.sampleRate || 44100.0; this.blockSize = options.blockSize || 2048; // instantiate heavy context this.heavyContext = _hv_{{name}}_new_with_options(this.sampleRate, {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); this.setPrintHook(options.printHook); this.setSendHook(options.sendHook); // allocate temporary buffers (pointer size is 4 bytes in javascript) var lengthOutSamples = this.blockSize * this.getNumOutputChannels(); var lengthInSamples = this.blockSize * this.getNumInputChannels(); this.outputBuffer = new Float32Array( Module.HEAPF32.buffer, Module._malloc(lengthOutSamples * Float32Array.BYTES_PER_ELEMENT), lengthOutSamples); this.inputBuffer = new Float32Array( Module.HEAPF32.buffer, Module._malloc(lengthInSamples * Float32Array.BYTES_PER_ELEMENT), lengthInSamples); } var parameterInHashes = { {%- for k,v in externs.parameters.inParam %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var parameterOutHashes = { {%- for k,v in externs.parameters.outParam %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var eventInHashes = { {%- for k,v in externs.events.inEvent %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var eventOutHashes = { {%- for k,v in externs.events.outEvent %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; var tableHashes = { {%- for k,v in externs.tables %} "{{v.display}}": {{v.hash}}, // {{v.display}} {%- endfor %} }; {{name}}_AudioLib.prototype.process = function(event) { // Currently only supports one output connection and one input connection on the worklet/scriptprocessor. (unlimited channels though) // Note(ZXMushroom63): calling getNumXXXChannels() every iteration of the for loop is slightly less efficient than calling once and storing the result var inputChannelCount = this.getNumInputChannels(); if (inputChannelCount > 0) { for (let i = 0; i < inputChannelCount; i++) { if ((event.inputBuffer.numberOfChannels - 2) < i) { continue; } this.inputBuffer.set(event.inputBuffer.getChannelData(i), i * this.blockSize); } } else { this.inputBuffer.set(0); //clear buffer when no inputs are connected } _hv_processInline(this.heavyContext, this.inputBuffer.byteOffset, this.outputBuffer.byteOffset, this.blockSize); var outputChannelCount = this.getNumOutputChannels(); for (var i = 0; i < outputChannelCount; ++i) { var output = event.outputBuffer.getChannelData(i); output.set(this.outputBuffer.subarray(i * this.blockSize, (i + 1) * this.blockSize)); } } {{name}}_AudioLib.prototype.getNumInputChannels = function() { return (this.heavyContext) ? _hv_getNumInputChannels(this.heavyContext) : -1; } {{name}}_AudioLib.prototype.getNumOutputChannels = function() { return (this.heavyContext) ? _hv_getNumOutputChannels(this.heavyContext) : -1; } {{name}}_AudioLib.prototype.setPrintHook = function(hook) { if (!this.heavyContext) { console.error("heavy: Can't set Print Hook, no Heavy Context instantiated"); return; } if (hook) { // typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg); var printHook = addFunction(function(context, printName, str, msg) { // Converts Heavy print callback to a printable message var timeInSecs =_hv_samplesToMilliseconds(context, _hv_msg_getTimestamp(msg)) / 1000.0; var m = UTF8ToString(printName) + " [" + timeInSecs.toFixed(3) + "]: " + UTF8ToString(str); hook(m); }, "viiii" ); _hv_setPrintHook(this.heavyContext, printHook); } } {{name}}_AudioLib.prototype.setSendHook = function(hook) { if (!this.heavyContext) { console.error("heavy: Can't set Send Hook, no Heavy Context instantiated"); return; } if (hook) { // typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg); var sendHook = addFunction(function(context, sendName, sendHash, msg) { const midiMessage = sendMidiOut(UTF8ToString(sendName), msg); if (midiMessage.length > 0) { hook("midiOutMessage", midiMessage); } else { // Converts sendhook callback to (sendName, float) message hook(UTF8ToString(sendName), _hv_msg_getFloat(msg, 0)); } }, "viiii" ); _hv_setSendHook(this.heavyContext, sendHook); } } {{name}}_AudioLib.prototype.sendEvent = function(name) { if (this.heavyContext) { _hv_sendBangToReceiver(this.heavyContext, eventInHashes[name]); } } {{name}}_AudioLib.prototype.sendMidi = function(message) { sendMidiIn(this.heavyContext, message); } {{name}}_AudioLib.prototype.setFloatParameter = function(name, floatValue) { if (this.heavyContext) { _hv_sendFloatToReceiver(this.heavyContext, parameterInHashes[name], parseFloat(floatValue)); } } {{name}}_AudioLib.prototype.sendStringToReceiver = function(name, message) { // Note(joe): it's not a good idea to call this frequently it is possible for // the stack memory to run out over time. if (this.heavyContext) { var r = allocate(intArrayFromString(name), 'i8', ALLOC_STACK); var m = allocate(intArrayFromString(message), 'i8', ALLOC_STACK); _hv_sendSymbolToReceiver(this.heavyContext, _hv_stringToHash(r), m); } } {{name}}_AudioLib.prototype.fillTableWithFloatBuffer = function(name, buffer) { var tableHash = tableHashes[name]; if (_hv_table_getBuffer(this.heavyContext, tableHash) !== 0) { // resize current table to new buffer length _hv_table_setLength(this.heavyContext, tableHash, buffer.length); // access internal float buffer from table tableBuffer = new Float32Array( Module.HEAPF32.buffer, _hv_table_getBuffer(this.heavyContext, tableHash), buffer.length); // set the table buffer with the data from the 1st channel (mono) tableBuffer.set(buffer); } else { console.error("heavy: Table '" + name + "' doesn't exist in the patch context."); } } Module.{{name}}_AudioLib = {{name}}_AudioLib; // midi_utils function sendMidiIn(hv_context, message) { if (hv_context) { var command = message[0] & 0xF0; var channel = message[0] & 0x0F; var data1 = message[1]; var data2 = message[2]; // all events to [midiin] for (var i = 1; i <= 2; i++) { _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIIN, 0, message[i], channel ); } // realtime events to [midirealtimein] if (MIDI_REALTIME.includes(message[0])) { _hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIREALTIMEIN, 0, message[0] ); } switch(command) { case 0x80: // note off _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, data1, 0, channel); break; case 0x90: // note on _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0, data1, data2, channel); break; case 0xA0: // polyphonic aftertouch _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_POLYTOUCHIN, 0, data2, // pressure data1, // note channel); break; case 0xB0: // control change _hv_sendMessageToReceiverFFF(hv_context, HV_HASH_CTLIN, 0, data2, // value data1, // cc number channel); break; case 0xC0: // program change _hv_sendMessageToReceiverFF(hv_context, HV_HASH_PGMIN, 0, data1, channel); break; case 0xD0: // aftertouch _hv_sendMessageToReceiverFF(hv_context, HV_HASH_TOUCHIN, 0, data1, channel); break; case 0xE0: // pitch bend // combine 7bit lsb and msb into 32bit int var value = (data2 << 7) | data1; _hv_sendMessageToReceiverFF(hv_context, HV_HASH_BENDIN, 0, value, channel); break; default: // console.error('No handler for midi message: ', message); } } } function sendMidiOut(sendName, msg) { switch (sendName) { case "__hv_noteout": var note = _hv_msg_getFloat(msg, 0); var velocity = _hv_msg_getFloat(msg, 1); var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports return [ ((velocity > 0) ? 144 : 128) | channel, note, velocity ] case "__hv_ctlout": var value = _hv_msg_getFloat(msg, 0); var cc = _hv_msg_getFloat(msg, 1); var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports return [ 176 | channel, cc, value ] case "__hv_pgmout": var program = _hv_msg_getFloat(msg, 0); var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports return [ 192 | channel, program ] case "__hv_touchout": var pressure = _hv_msg_getFloat(msg, 0); var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports return [ 208 | channel, pressure, ] case "__hv_polytouchout": var value = _hv_msg_getFloat(msg, 0); var note = _hv_msg_getFloat(msg, 1); var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports return[ 160 | channel, note, value ] case "__hv_bendout": var value = _hv_msg_getFloat(msg, 0); let lsb = value & 0x7F; let msb = (value >> 7) & 0x7F; var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports return [ 224 | channel, lsb, msb ] case "__hv_midiout": let firstByte = _hv_msg_getFloat(msg, 0); return (firstByte === 192 || firstByte === 208) ? [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1)] : [_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1), _hv_msg_getFloat(msg, 2)]; default: console.warn(`Unhandled sendName: ${sendName}`); return []; } } /* * MIDI Constants */ const HV_HASH_NOTEIN = 0x67E37CA3; const HV_HASH_CTLIN = 0x41BE0f9C; const HV_HASH_POLYTOUCHIN = 0xBC530F59; const HV_HASH_PGMIN = 0x2E1EA03D; const HV_HASH_TOUCHIN = 0x553925BD; const HV_HASH_BENDIN = 0x3083F0F7; const HV_HASH_MIDIIN = 0x149631bE; const HV_HASH_MIDIREALTIMEIN = 0x6FFF0BCF; const MIDI_REALTIME = [0xF8, 0xFA, 0xFB, 0xFC, 0xFE, 0xFF]; hvcc-0.16.0/hvcc/generators/c2js/template/index.html0000644000000000000000000002475300000000000017170 0ustar00 {{name}} {% for path in includes -%} {% endfor -%}

{{name}}

{%- if events | length %}
Input Events:
{%- for k, v in events %}
{%- endfor %}
{%- endif %} {%- if events_out | length %}
Output Events:
{%- for k, v in events_out %} {{k}}: 0
{%- endfor %}
{%- endif %}
{%- if parameters | length %}
Input Parameters:
{%- for k, v in parameters %}
{{k}}
{{v.attributes.default}}
{%- endfor %} {%- endif %} {%- if parameters_out | length %}
Output Parameters:
{%- for k, v in parameters_out %}
{{k}}
{{v.attributes.default}}
{%- endfor %} {%- endif %} {%- if midi | length or midi_out | length%}
{%- if midi | length %}
MIDI inputs:
{%- endif %} {%- if midi_out | length %}
MIDI outputs:
{%- endif %}
{%- endif %}
powered by heavy
hvcc-0.16.0/hvcc/generators/c2owl/__init__.py0000644000000000000000000000000000000000000015631 0ustar00hvcc-0.16.0/hvcc/generators/c2owl/c2owl.py0000644000000000000000000001277700000000000015150 0ustar00import shutil import time import jinja2 import json from typing import List, Optional from pathlib import Path import hvcc.core.hv2ir.HeavyLangObject as HeavyLangObject from ..copyright import copyright_manager from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta from hvcc.types.IR import IRGraph heavy_hash = HeavyLangObject.HeavyLangObject.get_hash OWL_BUTTONS = ['Push', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'Red', 'Green'] class c2owl(Generator): """ Generates a OWL wrapper for a given patch. """ @classmethod def make_jdata(cls, patch_ir: Path) -> List: jdata = list() with open(patch_ir, mode="r") as f: ir = IRGraph(**json.load(f)) for name, recv in ir.control.receivers.items(): # skip __hv_init and similar if name.startswith("__"): continue # If a name has been specified if recv.attributes.get('raw'): key = recv.attributes['raw'] jdata.append((key, name, 'RECV', f"0x{heavy_hash(name):X}", recv.attributes['min'], recv.attributes['max'], recv.attributes['default'], key in OWL_BUTTONS)) elif name.startswith('Channel-'): key = name.split('Channel-', 1)[1] jdata.append((key, name, 'RECV', f"0x{heavy_hash(name):X}", 0, 1, None, key in OWL_BUTTONS)) for _, obj in ir.objects.items(): try: if obj.type == '__send': name = obj.args['name'] if obj.args['attributes'].get('raw'): key = obj.args['attributes']['raw'] jdata.append((key, f'{name}>', 'SEND', f"0x{heavy_hash(name):X}", obj.args['attributes']['min'], obj.args['attributes']['max'], obj.args['attributes']['default'], key in OWL_BUTTONS)) elif name.startswith('Channel-'): key = name.split('Channel-', 1)[1] jdata.append((key, f'{name}>', 'SEND', f"0x{heavy_hash(name):X}", 0, 1, None, key in OWL_BUTTONS)) except Exception: pass return jdata @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() out_dir = Path(out_dir, "Source") patch_name = patch_name or "heavy" copyright_c = copyright_manager.get_copyright_for_c(copyright) try: # ensure that the output directory does not exist out_dir = out_dir.absolute() if out_dir.exists(): shutil.rmtree(out_dir) # copy over generated C source files shutil.copytree(c_src_dir, out_dir) # copy over deps shutil.copytree(Path(Path(__file__).parent, "deps"), out_dir, dirs_exist_ok=True) # initialize the jinja template environment env = jinja2.Environment() env.loader = jinja2.FileSystemLoader(Path(Path(__file__).parent), "templates") # construct jdata from ir ir_dir = Path(c_src_dir, "../ir") patch_ir = Path(ir_dir, f"{patch_name}.heavy.ir.json") jdata = cls.make_jdata(patch_ir) # generate OWL wrapper from template owl_hpp_path = Path(out_dir, f"HeavyOWL_{patch_name}.hpp") with open(owl_hpp_path, "w") as f: f.write(env.get_template("HeavyOwl.hpp").render( jdata=jdata, name=patch_name, copyright=copyright_c)) owl_h_path = Path(out_dir, "HeavyOwlConstants.h") with open(owl_h_path, "w") as f: f.write(env.get_template("HeavyOwlConstants.h").render( jdata=jdata, copyright=copyright_c)) # ====================================================================================== return CompilerResp( stage="c2owl", in_dir=c_src_dir, out_dir=out_dir, out_file=owl_h_path, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2owl", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2owl/deps/HvMessage.c0000644000000000000000000001621500000000000016520 0ustar00/** * Copyright (c) 2014,2015,2016 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvMessage.h" #include "message.h" #include HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) { m->timestamp = timestamp; m->numElements = (hv_uint16_t) numElements; m->numBytes = (hv_uint16_t) msg_getCoreSize(numElements); return m; } HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage); msg_setFloat(m, 0, f); return m; } HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage); msg_setBang(m, 0); return m; } HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage) + (hv_uint16_t) hv_strlen(s); msg_setSymbol(m, 0, s); return m; } HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage); msg_setHash(m, 0, h); return m; } void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) { HvMessage *r = (HvMessage *) buffer; hv_size_t len_r = msg_getCoreSize(msg_getNumElements(m)); // assert that the message is not already larger than the length of the buffer hv_assert(len_r <= len); // copy the basic message to the buffer hv_memcpy(r, m, len_r); char *p = buffer + len_r; // points to the end of the base message for (int i = 0; i < msg_getNumElements(m); ++i) { if (msg_isSymbol(m,i)) { const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char hv_assert(len_r + symLen <= len); // stay safe! hv_strncpy(p, msg_getSymbol(m,i), symLen); msg_setSymbol(r, i, p); p += symLen; len_r += symLen; } } r->numBytes = (hv_uint16_t) len_r; // update the message size in memory } // the message is serialised such that all symbol elements are placed in order at the end of the buffer HvMessage *msg_copy(const HvMessage *m) { const hv_uint32_t heapSize = msg_getSize(m); char *r = (char *) hv_malloc(heapSize); hv_assert(r != NULL); msg_copyToBuffer(m, r, heapSize); return (HvMessage *) r; } void msg_free(HvMessage *m) { hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message } bool msg_hasFormat(const HvMessage *m, const char *fmt) { hv_assert(fmt != NULL); const int n = msg_getNumElements(m); for (int i = 0; i < n; ++i) { switch (fmt[i]) { case 'b': if (!msg_isBang(m, i)) return false; break; case 'f': if (!msg_isFloat(m, i)) return false; break; case 'h': if (!msg_isHash(m, i)) return false; break; case 's': if (!msg_isSymbol(m, i)) return false; break; default: return false; } } return (fmt[n] == '\0'); } bool msg_compareSymbol(const HvMessage *m, int i, const char *s) { switch (msg_getType(m,i)) { case HV_MSG_SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s); case HV_MSG_HASH: return (msg_getHash(m,i) == hv_string_to_hash(s)); default: return false; } } bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) { if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) { if (msg_getType(m, i_m) == msg_getType(n, i_n)) { switch (msg_getType(m, i_m)) { case HV_MSG_BANG: return true; case HV_MSG_FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n)); case HV_MSG_SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n)); case HV_MSG_HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n); default: break; } } } return false; } void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) { switch (msg_getType(m, i_m)) { case HV_MSG_BANG: msg_setBang(n, i_n); break; case HV_MSG_FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break; case HV_MSG_SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break; case HV_MSG_HASH: msg_setHash(n, i_n, msg_getHash(m, i_m)); default: break; } } hv_uint32_t msg_getHash(const HvMessage *const m, int i) { hv_assert(i < msg_getNumElements(m)); // invalid index switch (msg_getType(m,i)) { case HV_MSG_BANG: return 0xFFFFFFFF; case HV_MSG_FLOAT: { float f = msg_getFloat(m,i); return *((hv_uint32_t *) &f); } case HV_MSG_SYMBOL: return hv_string_to_hash(msg_getSymbol(m,i)); case HV_MSG_HASH: return (&(m->elem)+i)->data.h; default: return 0; } } char *msg_toString(const HvMessage *m) { hv_assert(msg_getNumElements(m) > 0); int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int)); int size = 0; // the total length of our final buffer // loop through every element in our list of atoms // first loop figures out how long our buffer should be for (int i = 0; i < msg_getNumElements(m); i++) { // length of our string is each atom plus a space, or \0 on the end switch (msg_getType(m, i)) { case HV_MSG_BANG: len[i] = 5; break; case HV_MSG_FLOAT: len[i] = strnlen(msg_ftoa(msg_getFloat(m, i), 10), 16)+1; break; case HV_MSG_SYMBOL: len[i] = strnlen(msg_getSymbol(m, i), 16)+1; break; case HV_MSG_HASH: len[i] = strnlen(msg_itoa(msg_getHash(m, i), 16), 8)+3; break; default: break; } size += len[i]; } hv_assert(size > 0); // now we do the piecewise concatenation into our final string // the final buffer we will pass back after concatenating all strings - user should free it char *finalString = (char *) hv_malloc(size*sizeof(char)); char* dst = finalString; for (int i = 0; i < msg_getNumElements(m); i++) { // put a string representation of each atom into the final string char* ptr; switch (msg_getType(m, i)) { case HV_MSG_BANG: dst = stpcpy(dst, "bang"); break; case HV_MSG_FLOAT: ptr = msg_ftoa(msg_getFloat(m, i), 10); dst = stpcpy(dst, ptr); break; case HV_MSG_SYMBOL: ptr = (char*)msg_getSymbol(m, i); dst = stpcpy(dst, ptr); break; case HV_MSG_HASH: ptr = msg_itoa(msg_getHash(m, i), 16); dst = stpcpy(dst, "0x"); dst = stpcpy(dst, ptr); break; default: break; } dst = stpcpy(dst, " "); } hv_assert(dst - finalString == size); finalString[size-1] = '\0'; // ensure that the string is null terminated return finalString; } hvcc-0.16.0/hvcc/generators/c2owl/deps/HvUtils.h0000644000000000000000000002632300000000000016242 0ustar00/** * Copyright (c) 2014,2015,2016 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_UTILS_H_ #define _HEAVY_UTILS_H_ // platform definitions #if _WIN32 || _WIN64 #define HV_WIN 1 #ifdef _MSC_VER #define HV_MSVC 1 #endif #elif __APPLE__ #define HV_APPLE 1 #elif __ANDROID__ #define HV_ANDROID 1 #elif __unix__ || __unix #define HV_UNIX 1 #else #ifndef HV_BARE_METAL #warning Could not detect platform. Assuming Unix-like. #endif #endif #ifdef EMSCRIPTEN #define HV_EMSCRIPTEN 1 #endif // basic includes #include #ifdef ARM_CORTEX #include #else #include #include #endif // type definitions #include #include #define hv_uint8_t uint8_t #define hv_int16_t int16_t #define hv_uint16_t uint16_t #define hv_int32_t int32_t #define hv_uint32_t uint32_t #define hv_uint64_t uint64_t #define hv_size_t size_t #define hv_uintptr_t uintptr_t // SIMD-specific includes #if !(HV_SIMD_NONE || HV_SIMD_NEON || HV_SIMD_SSE || HV_SIMD_AVX) #define HV_SIMD_NEON __ARM_NEON__ #define HV_SIMD_SSE (__SSE__ && __SSE2__ && __SSE3__ && __SSSE3__ && __SSE4_1__) #define HV_SIMD_AVX (__AVX__ && HV_SIMD_SSE) #endif #ifndef HV_SIMD_FMA #define HV_SIMD_FMA __FMA__ #endif #if HV_SIMD_AVX || HV_SIMD_SSE #include #elif HV_SIMD_NEON #include #endif #if HV_SIMD_NEON // NEON #define HV_N_SIMD 4 #define hv_bufferf_t float32x4_t #define hv_bufferi_t int32x4_t #define hv_bInf_t float32x4_t #define hv_bOutf_t float32x4_t* #define hv_bIni_t int32x4_t #define hv_bOuti_t int32x4_t* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #elif HV_SIMD_AVX // AVX #define HV_N_SIMD 8 #define hv_bufferf_t __m256 #define hv_bufferi_t __m256i #define hv_bInf_t __m256 #define hv_bOutf_t __m256* #define hv_bIni_t __m256i #define hv_bOuti_t __m256i* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #elif HV_SIMD_SSE // SSE #define HV_N_SIMD 4 #define hv_bufferf_t __m128 #define hv_bufferi_t __m128i #define hv_bInf_t __m128 #define hv_bOutf_t __m128* #define hv_bIni_t __m128i #define hv_bOuti_t __m128i* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #else // DEFAULT #define HV_N_SIMD 1 #undef HV_SIMD_NONE #define HV_SIMD_NONE 1 #define hv_bufferf_t float #define hv_bufferi_t int #define hv_bInf_t float #define hv_bOutf_t float* #define hv_bIni_t int #define hv_bOuti_t int* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #endif #define HV_N_SIMD_MASK (HV_N_SIMD-1) // Strings #include #define hv_strlen(a) strlen(a) #define hv_strncpy(a, b, c) strncpy(a, b, c) #define hv_strcmp(a, b) strcmp(a, b) #define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) // Memory management #ifndef ARM_CORTEX #define hv_realloc(a, b) realloc(a, b) #endif // ARM_CORTEX #define hv_memcpy(a, b, c) memcpy(a, b, c) #define hv_memclear(a, b) memset(a, 0, b) #if HV_MSVC #include #define hv_alloca(_n) _alloca(_n) #if HV_SIMD_AVX #define hv_malloc(_n) _aligned_malloc(_n, 32) #define hv_realloc(a, b) _aligned_realloc(a, b, 32) #define hv_free(x) _aligned_free(x) #elif HV_SIMD_SSE || HV_SIMD_NEON #define hv_malloc(_n) _aligned_malloc(_n, 16) #define hv_realloc(a, b) _aligned_realloc(a, b, 16) #define hv_free(x) _aligned_free(x) #else // HV_SIMD_NONE #define hv_malloc(_n) malloc(_n) #define hv_free(_n) free(_n) #endif #elif HV_APPLE #define hv_alloca(_n) alloca(_n) #define hv_realloc(a, b) realloc(a, b) #if HV_SIMD_AVX #include #define hv_malloc(_n) _mm_malloc(_n, 32) #define hv_free(x) _mm_free(x) #elif HV_SIMD_SSE #include #define hv_malloc(_n) _mm_malloc(_n, 16) #define hv_free(x) _mm_free(x) #elif HV_SIMD_NEON // malloc on ios always has 16-byte alignment #define hv_malloc(_n) malloc(_n) #define hv_free(x) free(x) #else // HV_SIMD_NONE #define hv_malloc(_n) malloc(_n) #define hv_free(x) free(x) #endif #elif defined ARM_CORTEX #include #define hv_alloca(_n) alloca(_n) #define hv_malloc(_n) pvPortMalloc(_n) #define hv_free(_n) vPortFree(_n) #define hv_realloc(a, b) pvPortRealloc(a, b) #else #include #define hv_alloca(_n) alloca(_n) #if HV_SIMD_AVX #define hv_malloc(_n) aligned_alloc(32, _n) #define hv_free(x) free(x) #elif HV_SIMD_SSE || HV_SIMD_NEON #define hv_malloc(_n) aligned_alloc(16, _n) #define hv_free(x) free(x) #else // HV_SIMD_NONE #define hv_malloc(_n) malloc(_n) #define hv_free(_n) free(_n) #endif #endif // Assert #ifdef ARM_CORTEX #include "message.h" #define hv_assert(e) ASSERT((e), "Heavy assertion failed") #else #include #define hv_assert(e) assert(e) #endif // Export and Inline #if HV_MSVC #define HV_EXPORT __declspec(dllexport) #define inline __inline #define HV_FORCE_INLINE __forceinline #else #define HV_EXPORT #define HV_FORCE_INLINE inline __attribute__((always_inline)) #endif #ifdef __cplusplus extern "C" { #endif // Returns a 32-bit hash of any string. Returns 0 if string is NULL. hv_uint32_t hv_string_to_hash(const char *str); #ifdef __cplusplus } #endif // Math #ifndef ARM_CORTEX #include #endif static inline hv_size_t __hv_utils_max_ui(hv_size_t x, hv_size_t y) { return (x > y) ? x : y; } static inline hv_size_t __hv_utils_min_ui(hv_size_t x, hv_size_t y) { return (x < y) ? x : y; } static inline hv_int32_t __hv_utils_max_i(hv_int32_t x, hv_int32_t y) { return (x > y) ? x : y; } static inline hv_int32_t __hv_utils_min_i(hv_int32_t x, hv_int32_t y) { return (x < y) ? x : y; } #define hv_max_ui(a, b) __hv_utils_max_ui(a, b) #define hv_min_ui(a, b) __hv_utils_min_ui(a, b) #define hv_max_i(a, b) __hv_utils_max_i(a, b) #define hv_min_i(a, b) __hv_utils_min_i(a, b) #define hv_max_f(a, b) fmaxf(a, b) #define hv_min_f(a, b) fminf(a, b) #define hv_max_d(a, b) fmax(a, b) #define hv_min_d(a, b) fmin(a, b) #ifdef ARM_CORTEX #define hv_sin_f(a) arm_sin_f32(a) #define hv_cos_f(a) arm_cos_f32(a) #define hv_sqrt_f(a) arm_sqrtf(a) #define hv_pow_f(a, b) fast_powf(a, b) #define hv_exp_f(a) fast_expf(a) #define hv_log_f(a) fast_logf(a) #else #define hv_sin_f(a) sinf(a) #define hv_cos_f(a) cosf(a) #define hv_sqrt_f(a) sqrtf(a) #define hv_pow_f(a, b) powf(a, b) #define hv_exp_f(a) expf(a) #define hv_log_f(a) logf(a) #endif #define hv_sinh_f(a) sinhf(a) #define hv_cosh_f(a) coshf(a) #define hv_tan_f(a) tanf(a) #define hv_tanh_f(a) tanhf(a) #define hv_asin_f(a) asinf(a) #define hv_asinh_f(a) asinhf(a) #define hv_acos_f(a) acosf(a) #define hv_acosh_f(a) acoshf(a) #define hv_atan_f(a) atanf(a) #define hv_atanh_f(a) atanhf(a) #define hv_atan2_f(a, b) atan2f(a, b) #define hv_abs_f(a) fabsf(a) #if HV_ANDROID // NOTE(mhroth): for whatever silly reason, log2f is not defined! #define hv_log2_f(a) (1.44269504088896f*logf(a)) #else #define hv_log2_f(a) log2f(a) #endif // HV_ANDROID #define hv_log10_f(a) log10f(a) #define hv_ceil_f(a) ceilf(a) #define hv_floor_f(a) floorf(a) #define hv_round_f(a) roundf(a) #if HV_EMSCRIPTEN || defined ARM_CORTEX #define hv_fma_f(a, b, c) ((a*b)+c) // emscripten does not support fmaf (yet?). Inefficient on ARM Cortex M #else #define hv_fma_f(a, b, c) fmaf(a, b, c) #endif #if HV_MSVC // finds ceil(log2(x)) #include static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) { unsigned long z = 0; _BitScanReverse(&z, x); return (hv_uint32_t) (z+1); } #else static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) { return (hv_uint32_t) (32 - __builtin_clz(x-1)); } #endif #define hv_min_max_log2(a) __hv_utils_min_max_log2(a) #define hv_if_f(a, b, c) ((a) ? (b) : (c)) #define hv_modf_f(a) fmodf(a, 1.0f) #define hv_cbrt_f(a) cbrtf(a) #define hv_copysign_f(a, b) copysignf(a, b) #define hv_remainder_f(a, b) remainderf(a, b) #define hv_erf_f(a) erff(a) #define hv_erfc_f(a) erfcf(a) #define hv_expm1_f(a) expm1f(a) #define hv_finite_f(a) isfinite(a) #define hv_fmod_f(a, b) fmodf(a, b) #define hv_ldexp_f(a, b) ldexpf(a, b) #define hv_isinf_f(a) isinf(a) #define hv_isnan_f(a) isnan(a) #define hv_ln_f(a) logf(a) #define hv_log10_f(a) log10f(a) #define hv_log1p_f(a) log1pf(a) #define hv_rint_f(a) rintf(a) #define hv_shl_i(a, b) ((a) << (b)) #define hv_shr_i(a, b) ((a) >> (b)) #define hv_bit_not_i(a) ~a #define hv_not_f(a) !a // Atomics #if HV_WIN #include #define hv_atomic_bool volatile LONG #define HV_SPINLOCK_ACQUIRE(_x) while (InterlockedCompareExchange(&_x, true, false)) { } #define HV_SPINLOCK_TRY(_x) return !InterlockedCompareExchange(&_x, true, false) #define HV_SPINLOCK_RELEASE(_x) (_x = false) #elif HV_ANDROID // Android support for atomics isn't that great, we'll do it manually // https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html #define hv_atomic_bool hv_uint8_t #define HV_SPINLOCK_ACQUIRE(_x) while (__sync_lock_test_and_set(&_x, 1)) #define HV_SPINLOCK_TRY(_x) return !__sync_lock_test_and_set(&_x, 1) #define HV_SPINLOCK_RELEASE(_x) __sync_lock_release(&_x) #elif defined ARM_CORTEX || HV_EMSCRIPTEN /* no spinlock if we don't have pre-emptive scheduling */ #define hv_atomic_bool volatile bool #define HV_SPINLOCK_ACQUIRE(_x) { extern volatile bool _msgLock; _msgLock = true; } #define HV_SPINLOCK_TRY(_x) { extern volatile bool _msgLock; return !_msgLock; } #define HV_SPINLOCK_RELEASE(_x) { extern volatile bool _msgLock; _msgLock = false; } #elif __cplusplus #include #define hv_atomic_bool std::atomic_flag #define HV_SPINLOCK_ACQUIRE(_x) while (_x.test_and_set(std::memory_order_acquire)) #define HV_SPINLOCK_TRY(_x) return !_x.test_and_set(std::memory_order_acquire) #define HV_SPINLOCK_RELEASE(_x) _x.clear(std::memory_order_release) #elif defined(__has_include) #if __has_include() #include #define hv_atomic_bool atomic_flag #define HV_SPINLOCK_ACQUIRE(_x) while (atomic_flag_test_and_set_explicit(&_x, memory_order_acquire)) #define HV_SPINLOCK_TRY(_x) return !atomic_flag_test_and_set_explicit(&_x, memory_order_acquire) #define HV_SPINLOCK_RELEASE(_x) atomic_flag_clear_explicit(memory_order_release) #endif #endif #ifndef hv_atomic_bool #define hv_atomic_bool volatile bool #define HV_SPINLOCK_ACQUIRE(_x) \ while (_x) {} \ _x = true; #define HV_SPINLOCK_TRY(_x) \ if (!_x) { \ _x = true; \ return true; \ } else return false; #define HV_SPINLOCK_RELEASE(_x) (_x = false) #endif #endif // _HEAVY_UTILS_H_ hvcc-0.16.0/hvcc/generators/c2owl/templates/HeavyOwl.hpp0000644000000000000000000002056300000000000020005 0ustar00{{copyright}} #ifndef __HeavyPatch_hpp__ #define __HeavyPatch_hpp__ #include "Patch.h" #include "basicmaths.h" #include "HvHeavy.h" #include "Heavy_{{name}}.hpp" #include "HeavyOwlConstants.h" #define BUTTON_Push PUSHBUTTON #define BUTTON_Green GREEN_BUTTON #define BUTTON_Red RED_BUTTON #define BUTTON_B1 BUTTON_A #define BUTTON_B2 BUTTON_B #define BUTTON_B3 BUTTON_C #define BUTTON_B4 BUTTON_D #define BUTTON_B5 BUTTON_E #define BUTTON_B6 BUTTON_F #define BUTTON_B7 BUTTON_G #define BUTTON_B8 BUTTON_H #define BUTTON_B9 BUTTON_I #define BUTTON_B10 BUTTON_J #define BUTTON_B11 BUTTON_K #define HV_HASH_NOTEIN 0x67E37CA3 #define HV_HASH_CTLIN 0x41BE0f9C #define HV_HASH_POLYTOUCHIN 0xBC530F59 #define HV_HASH_PGMIN 0x2E1EA03D #define HV_HASH_TOUCHIN 0x553925BD #define HV_HASH_BENDIN 0x3083F0F7 #define HV_HASH_MIDIIN 0x149631bE #define HV_HASH_MIDIREALTIMEIN 0x6FFF0BCF #define HV_HASH_NOTEOUT 0xD1D4AC2 #define HV_HASH_CTLOUT 0xE5e2A040 #define HV_HASH_POLYTOUCHOUT 0xD5ACA9D1 #define HV_HASH_PGMOUT 0x8753E39E #define HV_HASH_TOUCHOUT 0x476D4387 #define HV_HASH_BENDOUT 0xE8458013 #define HV_HASH_MIDIOUT 0x6511DE55 #define HV_HASH_MIDIOUTPORT 0x165707E4 #define HEAVY_MESSAGE_POOL_SIZE 4 // in kB (default 10kB) #define HEAVY_MESSAGE_IN_QUEUE_SIZE 1 // in kB (default 2kB) #define HEAVY_MESSAGE_OUT_QUEUE_SIZE 0 // in kB (default 0kB) extern "C" { volatile bool _msgLock = false; static bool isButtonPressed(PatchButtonId bid){ return getProgramVector()->buttons & (1<buttons |= 1<buttons &= ~(1<setUserData(this); context->setPrintHook(&owlPrintHook); context->setSendHook(&owlSendHook); {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if button == False %} // {{name}} registerParameter(PARAMETER_{{param}}, HV_NAME_CHANNEL_{{param}}); setParameterValue(PARAMETER_{{param}}, HV_DEFAULT_CHANNEL_{{param}}); {% endfor %} } ~HeavyPatch() { delete context; } uint16_t getButtonValue(PatchButtonId bid, const HvMessage *m){ if(hv_msg_getNumElements(m) > 0 && hv_msg_isFloat(m, 0)) return hv_msg_getFloat(m, 0) > 0.5 ? 4095 : 0; else return isButtonPressed(bid) ? 0 : 4095; // toggle } void sendCallback(uint32_t sendHash, const HvMessage *m){ switch(sendHash){ case HV_HASH_NOTEOUT: { uint8_t note = hv_msg_getFloat(m, 0); uint8_t velocity = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; // drop any pd "ports" // debugMessage("noteout", note, velocity, ch); sendMidi(MidiMessage::note(ch, note, velocity)); } break; case HV_HASH_CTLOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t cc = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; // debugMessage("ctlout", value, cc, ch); sendMidi(MidiMessage::cc(ch, cc, value)); } break; case HV_HASH_BENDOUT: { uint16_t value = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; // debugMessage("bendout", value, ch); sendMidi(MidiMessage::pb(ch, value)); } break; case HV_HASH_POLYTOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t note = hv_msg_getFloat(m, 1); uint8_t ch = hv_msg_getFloat(m, 2); ch %= 16; sendMidi(MidiMessage::at(ch, note, value)); } break; case HV_HASH_TOUCHOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; sendMidi(MidiMessage::cp(ch, value)); } break; case HV_HASH_PGMOUT: { uint8_t value = hv_msg_getFloat(m, 0); uint8_t ch = hv_msg_getFloat(m, 1); ch %= 16; sendMidi(MidiMessage::pc(ch, value)); } break; {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if typ == 'SEND'%} {% if button == True %} // Button {{name}} case HV_HASH_{{typ}}_CHANNEL_{{param}}: setButton(BUTTON_{{param}}, (hv_msg_getFloat(m, 0)-HV_MIN_CHANNEL_{{param}})/ (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}}) > 0.5); {% else %} // Parameter {{name}} case HV_HASH_{{typ}}_CHANNEL_{{param}}: setParameterValue(PARAMETER_{{param}}, (hv_msg_getFloat(m, 0)-HV_MIN_CHANNEL_{{param}})/ (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}})); {% endif %} break; {% endfor %} default: break; } } void processMidi(MidiMessage msg){ // sendMessageToReceiverV parses format and loops over args, see HeavyContext.cpp switch(msg.getStatus()){ case CONTROL_CHANGE: context->sendMessageToReceiverV(HV_HASH_CTLIN, 0, "fff", (float)msg.getControllerValue(), // value (float)msg.getControllerNumber(), // controller number (float)msg.getChannel()); break; case NOTE_ON: context->sendMessageToReceiverV(HV_HASH_NOTEIN, 0, "fff", (float)msg.getNote(), // pitch (float)msg.getVelocity(), // velocity (float)msg.getChannel()); break; case NOTE_OFF: context->sendMessageToReceiverV(HV_HASH_NOTEIN, 0, "fff", (float)msg.getNote(), // pitch 0.0f, // velocity (float)msg.getChannel()); break; case POLY_KEY_PRESSURE: context->sendMessageToReceiverV(HV_HASH_POLYTOUCHIN, 0, "fff", (float)msg.getPolyKeyPressure(), (float)msg.getNote(), (float)msg.getChannel()); break; case CHANNEL_PRESSURE: context->sendMessageToReceiverV(HV_HASH_TOUCHIN, 0, "ff", (float)msg.getChannelPressure(), (float)msg.getChannel()); break; case PITCH_BEND_CHANGE: context->sendMessageToReceiverV(HV_HASH_BENDIN, 0, "ff", (float)msg.getPitchBend(), (float)msg.getChannel()); break; case PROGRAM_CHANGE: context->sendMessageToReceiverV(HV_HASH_PGMIN, 0, "ff", (float)msg.getProgramChange(), (float)msg.getChannel()); break; default: break; } } void buttonChanged(PatchButtonId bid, uint16_t value, uint16_t samples){ if(_msgLock) return; switch(bid){ {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if typ == 'RECV' and button == True %} // {{name}} case BUTTON_{{param}}: context->sendFloatToReceiver(HV_HASH_{{typ}}_CHANNEL_{{param}}, isButtonPressed(BUTTON_{{param}})* (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}})+HV_MIN_CHANNEL_{{param}}); break; {% endfor %} default: break; } } void processAudio(AudioBuffer &buffer) { _msgLock = true; {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if typ == 'RECV' and button == False %} // {{name}} context->sendFloatToReceiver(HV_HASH_{{typ}}_CHANNEL_{{param}}, getParameterValue(PARAMETER_{{param}})* (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}})+HV_MIN_CHANNEL_{{param}}); {% endfor %} _msgLock = false; float* outputs[] = {buffer.getSamples(LEFT_CHANNEL), buffer.getSamples(RIGHT_CHANNEL)}; context->process(outputs, outputs, getBlockSize()); } private: HeavyContext* context; }; static void owlSendHook(HeavyContextInterface* ctxt, const char *receiverName, uint32_t sendHash, const HvMessage *m){ HeavyPatch* patch = (HeavyPatch*)ctxt->getUserData(); patch->sendCallback(sendHash, m); } #endif // __HeavyPatch_hpp__ hvcc-0.16.0/hvcc/generators/c2owl/templates/HeavyOwlConstants.h0000644000000000000000000000077700000000000021347 0ustar00{{copyright}} {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata %} // {{param}} {{name}} {{typ}} {{namehash}} {{minvalue}} {{maxvalue}} {{defvalue}} {{(defvalue-minvalue)/(maxvalue-minvalue)}} #define HV_NAME_CHANNEL_{{param}} "{{name}}" #define HV_HASH_{{typ}}_CHANNEL_{{param}} {{namehash}} #define HV_MIN_CHANNEL_{{param}} {{minvalue}} #define HV_MAX_CHANNEL_{{param}} {{maxvalue}} #define HV_DEFAULT_CHANNEL_{{param}} {{(defvalue-minvalue)/(maxvalue-minvalue)}} {% endfor %} hvcc-0.16.0/hvcc/generators/c2pdext/__init__.py0000644000000000000000000000000000000000000016154 0ustar00hvcc-0.16.0/hvcc/generators/c2pdext/c2pdext.py0000644000000000000000000001021700000000000016001 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import shutil import time import jinja2 from typing import Optional from pathlib import Path from ..copyright import copyright_manager from ..filters import filter_max from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta class c2pdext(Generator): """Generates a Pure Data external wrapper for a given patch. """ @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() out_dir = Path(out_dir, "pdext") receiver_list = externs.parameters.inParam copyright = copyright_manager.get_copyright_for_c(copyright) patch_name = patch_name or "heavy" ext_name = f"{patch_name}~" struct_name = f"{patch_name}_tilde" # ensure that the output directory does not exist out_dir = out_dir.absolute() if out_dir.exists(): shutil.rmtree(out_dir) # copy over generated C source files shutil.copytree(c_src_dir, out_dir) # copy over static files shutil.copy( Path(Path(__file__).parent, "static", "m_pd.h"), f"{out_dir}/") shutil.copy( Path(Path(__file__).parent, "static", "Makefile.pdlibbuilder"), f"{out_dir}/../") try: # initialise the jinja template environment env = jinja2.Environment() env.filters["max"] = filter_max env.loader = jinja2.FileSystemLoader( Path(Path(__file__).parent, "templates")) # generate Pd external wrapper from template pdext_path = Path(out_dir, f"{ext_name}.c") with open(pdext_path, "w") as f: f.write(env.get_template("pd_external.c").render( name=patch_name, struct_name=struct_name, display_name=ext_name, num_input_channels=num_input_channels, num_output_channels=num_output_channels, receivers=receiver_list, copyright=copyright)) # generate Makefile from template pdext_path = Path(out_dir, "../Makefile") with open(pdext_path, "w") as f: f.write(env.get_template("Makefile").render( name=patch_name)) return CompilerResp( stage="c2pdext", in_dir=c_src_dir, out_dir=out_dir, out_file=pdext_path, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2pdext", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2pdext/static/Makefile.pdlibbuilder0000644000000000000000000013145100000000000021451 0ustar00# Makefile.pdlibbuilder dated 2019-12-21 version = 0.7.0 # Helper makefile for Pure Data external libraries. # Written by Katja Vetter March-June 2015 for the public domain. No warranties. # Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's # ShakeNMake. # # Grab the newest version of Makefile.pdlibbuilder from # https://github.com/pure-data/pd-lib-builder/ # # GNU make version >= 3.81 required. # # #=== characteristics =========================================================== # # # - defines build settings based on autodetected OS and architecture # - defines rules to build Pd class- or lib executables from C or C++ sources # - defines rules for libdir installation # - defines convenience targets for developer and user # - evaluates implicit dependencies for non-clean builds # # #=== basic usage =============================================================== # # # In your Makefile, define your Pd lib name and class files, and include # Makefile.pdlibbuilder at the end of the Makefile. Like so: # # ________________________________________________________________________ # # # Makefile for mylib # # lib.name = mylib # # class.sources = myclass1.c myclass2.c # # datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt # # include Makefile.pdlibbuilder # ________________________________________________________________________ # # # For files in class.sources it is assumed that class basename == source file # basename. The default target builds all classes as individual executables # with Pd's default extension for the platform. For anything more than the # most basic usage, continue reading. # # #=== list of Makefile.pdlibbuilder API variables =============================== # # # Variables available for definition in your library Makefile: # # - lib.name # - lib.setup.sources # - class.sources # - common.sources # - shared.sources # - .class.sources # - .class.ldflags # - .class.ldlibs # - cflags # - ldflags # - ldlibs # - datafiles # - datadirs # - makefiles # - makefiledirs # - externalsdir # # Optional multiline defines evaluated per operating system: # # - forLinux # - forDarwin # - forWindows # # Variables available for your makefile or make command line: # # - make-lib-executable # - suppress-wunused # # Path variables for make command line or environment: # # - PDDIR # - PDINCLUDEDIR # - PDBINDIR # - PDLIBDIR # # Standard make variables for make command line or environment: # # - CPPFLAGS # - CFLAGS # - LDFLAGS # - CC # - CXX # - INSTALL # - STRIP # - DESTDIR # # Optional user variables for make command line or environment: # # - PLATFORM # - extension # - floatsize # # Deprecated path variables: # # - pdincludepath # - pdbinpath # - objectsdir # # #=== descriptions of Makefile.pdlibbuilder API variables ======================= # # # lib.name: # Name of the library directory as it will be installed / distributed. Also the # name of the lib executable in the case where all classes are linked into # a single binary. # # lib.setup.sources: # Source file(s) (C or C++) which must be compiled only when linking all classes # into a single lib binary. # # class.sources: # All sources files (C or C++) for which the condition holds that # class name == source file basename. # # .class.sources: # Source file(s) (C or C++) specific to class . Use this for # multiple-source classes or when class name != source file basename. # # common.sources: # Source file(s) which must be statically linked to each class in the library. # # shared.sources: # Source file(s) (C or C++) to build a shared dynamic link lib, to be linked # with all class executables. # # cflags, ldflags, ldlibs: # Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic # link libs) for the whole library. These flags are added to platform-specific # flags defined by Makefile.pdlibbuilder. # # .class.ldflags and .class.ldlibs: # Define ldflags resp. ldlibs specific to class . These flags are # added to platform-specific flags defined by Makefile.pdlibbuilder, and flags # defined in your Makefile for the whole library. Note: cflags can not be # defined per class in the current implementation. # # datafiles and datadirs: # All extra files you want to include in binary distributions of the # library: abstractions and help patches, example patches, meta patch, readme # and license texts, manuals, sound files, etcetera. Use 'datafiles' for all # files that should go into your lib rootdir and 'datadirs' for complete # directories you want to copy from source to distribution. # # forLinux, forDarwin, forWindows: # Shorthand for 'variable definitions for Linux only' etc. Use like: # define forLinux # cflags += -DLINUX # class.sources += linuxthing.c # endef # # makefiles and makefiledirs: # Extra makefiles or directories with makefiles that should be made in sub-make # processes. # # make-lib-executable: # When this variable is defined 'yes' in your makefile or as command argument, # Makefile.pdlibbuilder will try to build all classes into a single library # executable (but it will force exit if lib.setup.sources is undefined). # If your makefile defines 'make-lib-executable=yes' as the library default, # this can still be overridden with 'make-lib-executable=no' as command argument # to build individual class executables (the Makefile.pdlibbuilder default.) # # suppress-wunused: # When this variable is defined ('yes' or any other value), -Wunused-variable, # -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed, # but the other warnings from -Wall are retained. # # PDDIR: # Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and # PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin. # # PDINCLUDEDIR: # Directory where Pd API m_pd.h should be found, and other Pd header files. # Overrides the default search path. # # PDBINDIR: # Directory where pd.dll should be found for linking (Windows only). Overrides # the default search path. # # PDLIBDIR: # Root directory for installation of Pd library directories. Overrides the # default install location. # # DESTDIR: # Prepended path component for staged install. # # PLATFORM: # Target platform for cross compilation in the form of GNU triplet: # cpu-vendor-os. Example: x86_64-w64-mingw32. This specifies the tool chain that # pdlibbuilder will use, if installed and locatable. System and architecture # will then be autodefined accordingly. In most cases no other variables need to # be overridden. # # extension: # Extension for the external to use. Example: m_amd64 # A sane default is picked, but it is useful if you want to provide # co-installable externals for multiple platforms (for the same operating # systems) # # floatsize: # the size of the t_float in bits. Example: 32 # t_float are usually single precision (32bit), which is the default. # For double precision use floatsize=64 # When building double precision externals, you will want to set the extension # as well, e.g. extension=windows-amd64-64.dll (--.) # # CPPFLAGS: # Preprocessor flags which are not strictly required for building. # # CFLAGS: # Compiler flags which are not strictly required for building. Compiler flags # defined by Makefile.pdlibbuilder for warning, optimization and architecture # specification are overriden by CFLAGS. # # LDFLAGS: # Linker flags which are not strictly required for building. Linker flags # defined by Makefile.pdlibbuilder for architecture specification are overriden # by LDFLAGS. # # CC and CXX: # C and C++ compiler programs as defined in your build environment. # # INSTALL # Definition of install program. # # STRIP # Name of strip program. Default 'strip' can be overridden in cross compilation # environments. # # objectsdir: # Root directory for installation of Pd library directories, like PDLIBDIR but # not overridable by environment. Supported for compatibility with pd-extended # central makefile, but deprecated otherwise. # # pdincludepath, pdbinpath: # As PDINCLUDEDIR and PDBINDIR but not overridable by environment. Deprecated # as user variables. # # #=== paths ===================================================================== # # # Source files in directories other than current working directory must be # prefixed with their relative path. Do not rely on VPATH or vpath. # Object (.o) files are built in the directory of their source files. # Executables are built in current working directory. # # Default search path for m_pd.h and other API header files is platform # dependent, and overridable by PDINCLUDEDIR: # # Linux: /usr/include/pd # # OSX: /Applications/Pd*.app/Contents/Resources/src # # Windows: %PROGRAMFILES%/Pd/src # %PROGRAMFILES(X86)%/Pd/src (32 bit builds on 64 bit Windows) # # Default search path for binary pd.dll (Windows), overridable by PDBINDIR # # %PROGRAMFILES%/Pd/bin # %PROGRAMFILES(X86)%/Pd/bin (32 bit builds on 64 bit Windows) # # Default location to install pd libraries is platform dependent, and # overridable by PDLIBDIR: # # Linux: /usr/local/lib/pd-externals # OSX: ~/Library/Pd # Windows: %APPDATA%/Pd # # https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files # The rationale for not installing to ~/pd-externals by default on Linux # is that some people share the home dir between 32 and 64 bit installations. # # #=== targets =================================================================== # # # all: build $(executables) plus optional post target # post: target to build after $(executables) # alldebug: build all with -g option turned on for debug symbols # : force clean build of an individual class # .pre: make preprocessor output file in current working directory # .lst: make asm/source output file in current working directory # # install: install executables and data files # clean: remove build products from source tree # # help: print help text # vars: print makefile variables # allvars: print all variables # depend: print generated prerequisites # dumpmachine: print compiler output of option '-dumpmachine' # coffee: dummy target # # Variable $(executables) expands to class executables plus optional shared lib, # or alternatively to single lib executable when make-lib-executable=true. # Targets pre and post can be defined by library makefile. Make sure to include # Makefile.pdlibbuilder first so default target all will not be redefined. # # #=== Pd-extended libdir concept ================================================ # # # For libdir layout as conceived by Hans-Christoph Steiner, see: # # https://puredata.info/docs/developer/Libdir # # Files README.txt, LICENSE.txt and -meta.pd are part of the libdir # convention. Help patches for each class and abstraction are supposed to be # available. Makefile.pdlibbuilder does not force the presence of these files # however. It does not automatically include such files in libdir installations. # Data files you want to include in distributions must be defined explicitly in # your Makefile. # # #=== Makefile.pdlibbuilder syntax conventions ================================== # # # Makefile.pdlibbuilder variable names are lower case. Default make variables, # environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR) # are upper case. Use target 'allvars' to print all variables and their values. # # 'Fields' in data variables are separated by dots, like in 'foo.class.sources'. # Words in variables expressing a function or command are separated by dashes, # like in 'make-lib-executable'. # # #=== useful make options ======================================================= # # # Use 'make -d ' to print debug details of the make process. # Use 'make -p ' to print make's database. # # #=== TODO ====================================================================== # # # - decide whether to use -static-libgcc or shared dll in MinGW # - cygwin support # - android support # - figure out how to handle '$' in filenames # - add makefile template targets dpkg-source dist libdir distclean tags? # # #=== end of documentation sections ============================================= # # ################################################################################ ################################################################################ ################################################################################ # GNU make version 3.81 (2006) or higher is required because of the following: # - function 'info' # - variable '.DEFAULT_GOAL' # force exit when make version is < 3.81 ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81) $(error GNU make version 3.81 or higher is required) endif # Relative path to externals root dir in multi-lib source tree like # pd-extended SVN. Default is parent of current working directory. May be # defined differently in including makefile. externalsdir ?= .. # variable you can use to check if Makefile.pdlibbuilder is already included Makefile.pdlibbuilder = true ################################################################################ ### target platform detection ################################################## ################################################################################ #=== target platform =========================================================== # PLATFORM: optional user variable to define target platform for cross # compilation. Redefine build tools accordingly. PLATFORM should match # the exact target prefix of tools present in $PATH, like x86_64-w64-mingw32, # x86_64-apple-darwin12 etc. Tool definitions are exported to ensure submakes # will get the same. ifneq ($(PLATFORM),) ifneq ($(findstring darwin, $(PLATFORM)),) export CC = $(PLATFORM)-cc export CXX = $(PLATFORM)-c++ export CPP = $(PLATFORM)-cc else export CC = $(PLATFORM)-gcc export CXX = $(PLATFORM)-g++ export CPP = $(PLATFORM)-cpp endif STRIP = $(PLATFORM)-strip endif # Let (native or cross-) compiler report target triplet and isolate individual # words therein to facilitate later processing. target.triplet := $(subst -, ,$(shell $(CC) -dumpmachine)) #=== operating system ========================================================== # The following systems are defined: Linux, Darwin, Windows. GNU and # GNU/kFreeBSD are treated as Linux to get the same options. ifneq ($(filter linux gnu% kfreebsd, $(target.triplet)),) system = Linux endif ifneq ($(filter darwin%, $(target.triplet)),) system = Darwin endif ifneq ($(filter mingw% cygwin%, $(target.triplet)),) system = Windows endif # evaluate possible system-specific multiline defines from library makefile $(eval $(for$(system))) # TODO: Cygwin, Android #=== architecture ============================================================== # The following CPU names can be processed by pdlibbuilder: # i*86 Intel 32 bit # x86_64 Intel 64 bit # arm ARM 32 bit # aarch64 ARM 64 bit target.arch := $(firstword $(target.triplet)) ################################################################################ ### variables per platform ##################################################### ################################################################################ #=== flags per floatsize == ==================================================== floatsize = 32 ifneq ($(filter-out 32,$(floatsize)),) floatsize.flags = -DPD_FLOATSIZE=$(floatsize) else floatsize.flags = endif #=== flags per architecture ==================================================== # Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, # arch.c.flags are overriden below. To see gcc's default architecture flags: # $ gcc -Q --help=target # ARMv6: Raspberry Pi 1st gen, not detectable from target.arch ifeq ($(shell uname -m), armv6l) arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard # ARMv7: Beagle, Udoo, RPi2 etc. else ifeq ($(target.arch), arm) arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard # ARMv8 64 bit, not tested yet else ifeq ($(target.arch), aarch64) arch.c.flags = -mcpu=cortex-a53 # Intel 32 bit, build with SSE and SSE2 instructions else ifneq ($(filter i%86, $(target.arch)),) arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2 # Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions else ifeq ($(target.arch), x86_64) arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 # if none of the above architectures detected else arch.c.flags = endif #=== flags and paths for Linux ================================================= ifeq ($(system), Linux) prefix = /usr/local libdir := $(prefix)/lib pkglibdir = $(libdir)/pd-externals pdincludepath := $(wildcard /usr/include/pd) extension = pd_linux cpp.flags := -DUNIX c.flags := -fPIC c.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags c.ldlibs := -lc -lm cxx.flags := -fPIC -fcheck-new cxx.ldflags := -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags cxx.ldlibs := -lc -lm -lstdc++ shared.extension = so shared.ldflags = -rdynamic -fPIC -shared -Wl,-soname,$(shared.lib) endif #=== flags and paths for Darwin ================================================ # LLVM-clang doesn't support -fcheck-new, therefore this flag is only used when # compiling with g++. ifeq ($(system), Darwin) pkglibdir = $(HOME)/Library/Pd pdincludepath := $(firstword $(wildcard \ /Applications/Pd*.app/Contents/Resources/src)) extension = pd_darwin cpp.flags := -DUNIX -DMACOSX -I /sw/include c.flags := c.ldflags := -undefined suppress -flat_namespace -bundle c.ldlibs := -lc cxx.ldflags := -undefined suppress -flat_namespace -bundle cxx.ldlibs := -lc shared.extension = dylib shared.ldflags = -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(shared.lib) \ -compatibility_version 1 -current_version 1.0 ifneq ($(filter %g++, $(CXX)),) cxx.flags := -fcheck-new endif ifeq ($(extension), d_fat) arch := i386 x86_64 else arch := $(target.arch) endif ifneq ($(filter -mmacosx-version-min=%, $(cflags)),) version.flag := $(filter -mmacosx-version-min=%, $(cflags)) else version.flag = -mmacosx-version-min=10.6 endif arch.c.flags := $(addprefix -arch , $(arch)) $(version.flag) arch.ld.flags := $(arch.c.flags) endif #=== flags and paths for Windows =============================================== # Standard paths on Windows contain spaces, and GNU make functions treat such # paths as lists, with unintended effects. Therefore we must use shell function # ls instead of make's wildcard when probing for a path, and use double quotes # when specifying a path in a command argument. # Default paths in Mingw / Mingw-w64 environments. 'PROGRAMFILES' is standard # location for builds with native architecture, 'ProgramFiles(x86)' for i686 # builds on x86_64 Windows (detection method by Lucas Cordiviola). Curly braces # required because of parentheses in variable name. ifeq ($(system), Windows) pkglibdir := $(APPDATA)/Pd ifeq ($(target.arch), i686) programfiles := ${ProgramFiles(x86)} else programfiles := $(PROGRAMFILES) endif pdbinpath := $(programfiles)/Pd/bin pdincludepath := $(programfiles)/Pd/src endif # Store default path to pd.dll in PDBINDIR if the latter is not user-defined. # For include path this is done in the platform-independent paths section below, # but for PDBINDIR it is done here so ld flags can be evaluated as immediate # variables. ifeq ($(system), Windows) ifdef PDDIR PDBINDIR := $(PDDIR)/bin endif PDBINDIR ?= $(pdbinpath) endif # TODO: decide whether -mms-bitfields should be specified. ifeq ($(system), Windows) cpp.flags := -DMSW -DNT ifeq ($(target.arch), i686) arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse else ifeq ($(target.arch), x86_64) cpp.flags := -DMSW -DNT -DPD_LONGINTTYPE=__int64 arch.c.flags := -march=core2 -msse -msse2 -msse3 -mfpmath=sse else arch.c.flags = endif extension = dll c.flags := c.ldflags := -static-libgcc -shared \ -Wl,--enable-auto-import "$(PDBINDIR)/pd$(filter-out 32,$(floatsize)).dll" c.ldlibs := cxx.flags := -fcheck-new cxx.ldflags := -static-libgcc -static-libstdc++ -shared \ -Wl,--enable-auto-import "$(PDBINDIR)/pd$(filter-out 32,$(floatsize)).dll" cxx.ldlibs := shared.extension = dll shared.ldflags := -static-libgcc -shared "$(PDBINDIR)/pd$(filter-out 32,$(floatsize)).dll" stripflags = --strip-all endif #=== paths ===================================================================== # Platform-dependent default paths are specified above, but overridable. # Path variables in upper case can be defined as make command argument or in the # environment. Variable 'objectsdir' is supported for compatibility with # the build system that pd-l2ork has inherited from pd-extended. PDINCLUDEDIR ?= $(pdincludepath) PDLIBDIR ?= $(firstword $(objectsdir) $(pkglibdir)) ifdef PDDIR PDINCLUDEDIR := $(wildcard $(PDDIR)/src) endif # base path where all components of the lib will be installed by default installpath := $(DESTDIR)$(PDLIBDIR)/$(lib.name) # check if include path contains spaces (as is often the case on Windows) # if so, store the path so we can later do checks with it pdincludepathwithspaces := $(if $(word 2, $(PDINCLUDEDIR)), $(PDINCLUDEDIR)) #=== accumulated build flags =================================================== # From GNU make docs: 'Users expect to be able to specify CFLAGS freely # themselves.' So we use CFLAGS to define options which are not strictly # required for compilation: optimizations, architecture specifications, and # warnings. CFLAGS can be safely overriden using a make command argument. # Variables cflags, ldflags and ldlibs may be defined in including makefile. optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing # suppress -Wunused-variable & Co if you don't want to clutter a build log ifdef suppress-wunused warn.flags += $(addprefix -Wno-unused-, function parameter value variable) endif CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags) # preprocessor flags cpp.flags := -DPD -I "$(PDINCLUDEDIR)" $(floatsize.flags) $(cpp.flags) $(CPPFLAGS) # flags for dependency checking (cflags from makefile may define -I options) depcheck.flags := $(cpp.flags) $(cflags) # architecture specifications for linker are overridable by LDFLAGS LDFLAGS := $(arch.ld.flags) # now add the same ld flags to shared dynamic lib shared.ldflags += $(LDFLAGS) # accumulated flags for C compiler / linker c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS) c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS) c.ldlibs := $(c.ldlibs) $(ldlibs) # accumulated flags for C++ compiler / linker cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS) cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS) cxx.ldlibs := $(cxx.ldlibs) $(ldlibs) ################################################################################ ### variables: library name and version ######################################## ################################################################################ # strip possibles spaces from lib.name, they mess up calculated file names lib.name := $(strip $(lib.name)) # if meta file exists, check library version metafile := $(wildcard $(lib.name)-meta.pd) ifdef metafile lib.version := $(shell sed -n \ 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \ $(metafile)) endif ################################################################################ ### variables: files ########################################################### ################################################################################ object.extension = $(extension).o #=== sources =================================================================== # (re)define .class.sources using file names in class.sources define add-class-source $(notdir $(basename $v)).class.sources += $v endef $(foreach v, $(class.sources), $(eval $(add-class-source))) # derive class names from .class.sources variables sourcevariables := $(filter %.class.sources, $(.VARIABLES)) classes := $(basename $(basename $(sourcevariables))) # accumulate all source files specified in makefile classes.sources := $(sort $(foreach v, $(sourcevariables), $($v))) all.sources := $(classes.sources) $(lib.setup.sources) \ $(shared.sources) $(common.sources) #=== object files ============================================================== # construct object filenames from all C and C++ source file names classes.objects := $(addsuffix .$(object.extension), $(basename $(classes.sources))) common.objects := $(addsuffix .$(object.extension), $(basename $(common.sources))) shared.objects := $(addsuffix .$(object.extension), $(basename $(shared.sources))) lib.setup.objects := $(addsuffix .$(object.extension), $(basename $(lib.setup.sources))) all.objects = $(classes.objects) $(common.objects) $(shared.objects) \ $(lib.setup.objects) #=== executables =============================================================== # construct class executable names from class names classes.executables := $(addsuffix .$(extension), $(classes)) # Construct shared lib executable name if shared sources are defined. # If extension does not end with shared extension, use both to facilitate co- # installation for different platforms, like .m_i386.dll and .linux-amd64-32.so ifdef shared.sources ifneq ($(filter %.$(shared.extension), .$(extension)), ) # $(extension) already ends with $(shared.extension), no need to duplicate it shared.lib = lib$(lib.name).$(extension) else shared.lib = lib$(lib.name).$(extension).$(shared.extension) endif else shared.lib := endif ################################################################################ ### variables: tools ########################################################### ################################################################################ # aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument compile-c := $(CC) compile-cxx := $(CXX) ################################################################################ ### checks ##################################################################### ################################################################################ # At this point most variables are defined. Now do some checks and info's # before rules begin. # print Makefile.pdlibbuilder version before possible termination $(info ++++ info: using Makefile.pdlibbuilder version $(version)) # Terminate if target triplet remained empty, to avoid all sorts of confusing # scenarios and spurious bugs. ifeq ($(target.triplet),) $(error Command "$(CC) -dumpmachine" did not return a target triplet, \ needed for a build. \ Is compiler "$(CC)" installed in your PATH? ($(PATH)). \ Does compiler "$(CC)" support option "-dumpmachine"?) endif # 'forward declaration' of default target, needed to do checks all: # To avoid unpredictable results, make sure the default target is not redefined # by including makefile. ifneq ($(.DEFAULT_GOAL), all) $(error Default target must be 'all'.) endif # find out which target(s) will be made ifdef MAKECMDGOALS goals := $(MAKECMDGOALS) else goals := all endif # store path to Pd API m_pd.h if it is found ifdef PDINCLUDEDIR mpdh := $(shell ls "$(PDINCLUDEDIR)/m_pd.h") endif # store path to pd.dll; if not found, ls will give a useful error ifeq ($(system), Windows) pddll := $(shell ls "$(PDBINDIR)/pd$(filter-out 32,$(floatsize)).dll") endif # when making target all, check if m_pd.h is found and print info about it ifeq ($(goals), all) $(if $(mpdh), \ $(info ++++ info: using Pd API $(mpdh)), \ $(warning Where is Pd API m_pd.h? Do 'make help' for info.)) endif # print target info $(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name))) # when installing, print installpath info $(if $(filter install install-lib, $(goals)), $(info ++++ info: \ installpath is '$(installpath)')) #=== define executables ======================================================== # By default we build class executables, and optionally a shared dynamic link # lib. When make-lib-executable=yes we build all classes into a single lib # executable, on the condition that variable lib.setup.sources is defined. ifeq ($(make-lib-executable),yes) $(if $(lib.setup.sources), ,\ $(error Can not build library blob because lib.setup.sources is undefined)) executables := $(lib.name).$(extension) else executables := $(classes.executables) $(shared.lib) endif ################################################################################ ### rules: special targets ##################################################### ################################################################################ # Disable built-in rules. If some target can't be built with the specified # rules, it should not be built at all. MAKEFLAGS += --no-builtin-rules .PRECIOUS: .SUFFIXES: .PHONY: all post build-lib \ $(classes) $(makefiledirs) $(makefiles) \ install install-executables install-datafiles install-datadirs \ force clean vars allvars depend help ################################################################################ ### rules: build targets ####################################################### ################################################################################ # Target all forces the build of targets [$(executables) post] in # deterministic order. Target $(executables) builds class executables plus # optional shared lib or alternatively a single lib executable when # make-lib-executable=true. Target post is optionally defined by # library makefile. all: post post: $(executables) all: $(info ++++info: target all in lib $(lib.name) completed) # build all with -g option turned on for debug symbols alldebug: c.flags += -g alldebug: cxx.flags += -g alldebug: all #=== class executable ========================================================== # recipe for linking objects in class executable # argument $1 = compiler type (c or cxx) # argument $2 = class basename define link-class $(compile-$1) \ $($1.ldflags) $($2.class.ldflags) \ -o $2.$(extension) \ $(addsuffix .$(object.extension), $(basename $($2.class.sources))) \ $(addsuffix .$(object.extension), $(basename $(common.sources))) \ $($1.ldlibs) $($2.class.ldlibs) $(shared.lib) endef # general rule for linking object files in class executable %.$(extension): $(shared.lib) $(info ++++ info: linking objects in $@ for lib $(lib.name)) $(if $(filter %.cc %.cpp, $($*.class.sources)), \ $(call link-class,cxx,$*), \ $(call link-class,c,$*)) #=== library blob ============================================================== # build all classes into single executable build-lib: $(lib.name).$(extension) $(info ++++ info: library blob $(lib.name).$(extension) completed) # recipe for linking objects in lib executable # argument $1 = compiler type (c or cxx) define link-lib $(compile-$1) \ $($1.ldflags) $(lib.ldflags) \ -o $(lib.name).$(extension) $(all.objects) \ $($1.ldlibs) $(lib.ldlibs) endef # rule for linking objects in lib executable # declared conditionally to avoid name clashes ifeq ($(make-lib-executable),yes) $(lib.name).$(extension): $(all.objects) $(if $(filter %.cc %.cpp, $(all.sources)), \ $(call link-lib,cxx), \ $(call link-lib,c)) endif #=== shared dynamic lib ======================================================== # recipe for linking objects in shared executable # argument $1 = compiler type (c or cxx) define link-shared $(compile-$1) \ $(shared.ldflags) \ -o $(shared.lib) $(shared.objects) \ $($1.ldlibs) $(shared.ldlibs) endef # rule for linking objects in shared executable # build recipe is in macro 'link-shared' $(shared.lib): $(shared.objects) $(info ++++ info: linking objects in shared lib $@) $(if $(filter %.cc %.cpp, $(shared.sources)), \ $(call link-shared,cxx), \ $(call link-shared,c)) #=== object files ============================================================== # recipe to make .o file from source # argument $1 is compiler type (c or cxx) define make-object-file $(info ++++ info: making $@ in lib $(lib.name)) $(compile-$1) \ $($1.flags) \ -o $@ -c $< endef # Three rules to create .o files. These are double colon 'terminal' rules, # meaning they are the last in a rules chain. %.$(object.extension):: %.c $(call make-object-file,c) %.$(object.extension):: %.cc $(call make-object-file,cxx) %.$(object.extension):: %.cpp $(call make-object-file,cxx) #=== explicit prerequisites for class executables ============================== # For class executables, prerequisite rules are declared in run time. Target # 'depend' prints these rules for debugging purposes. # declare explicit prerequisites rule like 'class: class.extension' # argument $v is class basename define declare-class-target $v: $v.$(extension) endef # declare explicit prerequisites rule like 'class.extension: object1.o object2.o' # argument $v is class basename define declare-class-executable-target $v.$(extension): $(addsuffix .$(object.extension), $(basename $($v.class.sources))) \ $(addsuffix .$(object.extension), $(basename $(common.sources))) endef # evaluate explicit prerequisite rules for all classes $(foreach v, $(classes), $(eval $(declare-class-target))) $(foreach v, $(classes), $(eval $(declare-class-executable-target))) #=== implicit prerequisites for class executables ============================== # Evaluating implicit prerequisites (header files) with help from the # preprocessor is 'expensive' so this is done conditionally and selectively. # Note that it is also possible to trigger a build via install targets, in # which case implicit prerequisites are not checked. # When the Pd include path contains spaces it will mess up the implicit # prerequisites rules. disable-dependency-tracking := $(strip $(pdincludepathwithspaces)) ifndef disable-dependency-tracking must-build-everything := $(filter all, $(goals)) must-build-class := $(filter $(classes), $(goals)) must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources)) endif # declare implicit prerequisites rule like 'object.o: header1.h header2.h ...' # argument $1 is input source file(s) # dir is explicitly added because option -MM strips it by default define declare-object-target $(dir $1)$(patsubst %.o:,%.$(object.extension):,$(filter %.o: %.h, $(shell $(CPP) $(depcheck.flags) -MM $1))) $(MAKEFILE_LIST) endef # evaluate implicit prerequisite rules when rebuilding everything ifdef must-build-everything $(if $(wildcard $(all.objects)), \ $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \ $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v)))) endif # evaluate implicit prerequisite rules when selectively building classes ifdef must-build-class $(foreach v, $(must-build-sources), \ $(eval $(call declare-object-target, $v))) $(foreach v, $(shared.sources), \ $(eval $(call declare-object-target, $v))) endif ################################################################################ ### rules: preprocessor and assembly files ##################################### ################################################################################ # Preprocessor and assembly output files for bug tracing etc. They are not part # of the build processes for executables. By default these files are created in # the current working directory. Dependency tracking is not performed, the build # is forced instead to make sure it's up to date. force: #=== preprocessor file ========================================================= # make preprocessor output file with extension .pre # argument $1 = compiler type (c or cxx) define make-preprocessor-file $(info ++++ info: making preprocessor output file $(notdir $*.pre) \ in current working directory) $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre) endef %.pre:: %.c force $(call make-preprocessor-file,c) %.pre:: %.cc force $(call make-preprocessor-file,cxx) %.pre:: %.cpp force $(call make-preprocessor-file,cxx) #=== assembly file ============================================================= # make C / assembly interleaved output file with extension .lst # argument $1 = compiler type (c or cxx) define make-assembly-file $(info ++++ info: making assembly output file $(notdir $*.lst) \ in current working directory) $(compile-$1) \ -c -Wa,-a,-ad -fverbose-asm \ $($1.flags) \ $< > $(notdir $*.lst) endef %.lst:: %.c force $(call make-assembly-file,c) %.lst:: %.cc force $(call make-assembly-file,cxx) %.lst:: %.cpp force $(call make-assembly-file,cxx) ################################################################################ ### rules: installation targets ################################################ ################################################################################ #=== strip ===================================================================== # Stripping of installed binaries will only be done when variable 'stripflags' # is defined non-empty. No default definition is provided except for Windows # where the unstripped binaries are large, especially in the case of Mingw-w64. # Note: while stripping all symbols ('-s' or '--strip-all') is possible for # Linux and Windows, in the case of OSX only non-global symbols can be stripped # (option '-x' or '--discard-all'). # Make definition of strip command overridable so it can be defined in an # environment for cross-compilation. STRIP ?= strip # Commands in 'strip-executables' will be executed conditionally in the rule for # target 'install-executables'. strip-executables = cd "$(installpath)" && \ $(foreach v, $(executables), $(STRIP) $(stripflags) '$v';) #=== install =================================================================== # Install targets depend on successful exit status of target all because nothing # must be installed in case of a build error. # -p = preserve time stamps # -m = set permission mode (as in chmod) # -d = create all components of specified directories INSTALL = install INSTALL_PROGRAM := $(INSTALL) -p -m 644 INSTALL_DATA := $(INSTALL) -p -m 644 INSTALL_DIR := $(INSTALL) -m 755 -d # strip spaces from file names executables := $(strip $(executables)) datafiles := $(strip $(datafiles)) datadirs := $(strip $(datadirs)) # Do not make any install sub-target with empty variable definition because the # install program would exit with an error. install: $(if $(executables), install-executables) install: $(if $(datafiles), install-datafiles) install: $(if $(datadirs), install-datadirs) install-executables: all $(INSTALL_DIR) -v "$(installpath)" $(foreach v, $(executables), \ $(INSTALL_PROGRAM) '$v' "$(installpath)";) $(info ++++ info: executables of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) $(if $(stripflags), $(strip-executables),) install-datafiles: all $(INSTALL_DIR) -v "$(installpath)" $(foreach v, $(datafiles), \ $(INSTALL_DATA) '$(v)' "$(installpath)";) $(info ++++ info: data files of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) install-datadirs: all $(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";) $(foreach v, $(datadirs), \ $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";) $(info ++++ info: data directories of lib $(lib.name) installed \ from $(CURDIR) to $(installpath)) ################################################################################ ### rules: distribution targets ################################################ ################################################################################ # TODO # These targets are implemented in Makefile Template, but I have to figure out # how to do it under the not-so-strict conditions of Makefile.pdlibbuilder. # make source package dist: @echo "target dist not yet implemented" # make Debian source package dpkg-source: @echo "target dpkg-source not yet implemented" $(ORIGDIR): $(DISTDIR): ################################################################################ ### rules: clean targets ####################################################### ################################################################################ # delete build products from build tree clean: rm -f $(all.objects) rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib) rm -f *.pre *.lst # remove distribution directories and tarballs from build tree distclean: clean @echo "target distclean not yet implemented" ################################################################################ ### rules: submake targets ##################################################### ################################################################################ # Iterate over sub-makefiles or makefiles in other directories. # When 'continue-make=yes' is set, sub-makes will report 'true' to the parent # process regardless of their real exit status. This prevents the parent make # from being aborted by a sub-make error. Useful when you want to quickly find # out which sub-makes from a large set will succeed. ifeq ($(continue-make),yes) continue = || true endif # These targets will trigger sub-make processes for entries in 'makefiledirs' # and 'makefiles'. all alldebug install clean distclean dist dkpg-source: \ $(makefiledirs) $(makefiles) # this expands to identical rules for each entry in 'makefiledirs' $(makefiledirs): $(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue) # this expands to identical rules for each entry in 'makefiles' $(makefiles): $(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue) ################################################################################ ### rules: convenience targets ################################################# ################################################################################ #=== show variables ============================================================ # Several 'function' macro's cause errors when expanded within a rule or without # proper arguments. Variables which are set with the define directive are only # shown by name for that reason. functions = \ add-class-source \ declare-class-target \ declare-class-executable-target \ declare-object-target \ link-class \ link-lib \ link-shared \ make-object-file \ make-preprocessor-file \ make-assembly-file # show variables from makefiles vars: $(info ++++ info: showing makefile variables:) $(foreach v,\ $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\ $(if $(filter file, $(origin $v)),\ $(info variable $v = $($v)))) $(foreach v, $(functions), $(info 'function' name: $v)) @echo # show all variables allvars: $(info ++++ info: showing default, automatic and makefile variables:) $(foreach v, \ $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \ $(info variable ($(origin $v)) $v = $($v))) $(foreach v, $(functions), $(info 'function' name: $v)) @echo #=== show dependencies ========================================================= # show generated prerequisites rules depend: $(info ++++ info: generated prerequisite rules) $(foreach v, $(classes), $(info $(declare-class-target))) $(foreach v, $(classes), $(info $(declare-class-executable-target))) $(foreach v, $(all.sources), $(info $(call declare-object-target, $v))) @echo #=== show help text ============================================================ # brief info about targets and paths ifdef mpdh mpdhinfo := $(mpdh) else mpdhinfo := m_pd.h was not found. Is Pd installed? endif help: @echo @echo " Main targets:" @echo " all: build executables (default target)" @echo " install: install all components of the library" @echo " vars: print makefile variables for troubleshooting" @echo " allvars: print all variables for troubleshooting" @echo " help: print this help text" @echo @echo " Pd API m_pd.h:" @echo " $(mpdhinfo)" @echo " You may specify your preferred Pd include directory as argument" @echo " to the make command, like 'PDINCLUDEDIR=path/to/pd/src'." @echo @echo " Path for installation of your libdir(s):" @echo " $(PDLIBDIR)" @echo " Alternatively you may specify your path for installation as argument" @echo " to the make command, like 'PDLIBDIR=path/to/pd-externals'." @echo @echo " Default paths are listed in the doc sections in Makefile.pdlibbuilder." @echo #=== platform test ============================================================= # This target can be used to test if the compiler for specified PLATFORM is # correctly defined and available. dumpmachine: @$(CC) -dumpmachine #=== dummy target ============================================================== coffee: @echo "Makefile.pdlibbuilder: Can not make coffee. Sorry." ################################################################################ ### end of rules sections ###################################################### ################################################################################ # for syntax highlighting in vim and github # vim: set filetype=make: hvcc-0.16.0/hvcc/generators/c2pdext/static/m_pd.h0000644000000000000000000011301200000000000016432 0ustar00/* Copyright (c) 1997-1999 Miller Puckette. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ #ifndef __m_pd_h_ #if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) extern "C" { #endif #define PD_MAJOR_VERSION 0 #define PD_MINOR_VERSION 54 #define PD_BUGFIX_VERSION 0 #define PD_TEST_VERSION "" extern int pd_compatibilitylevel; /* e.g., 43 for pd 0.43 compatibility */ /* old name for "MSW" flag -- we have to take it for the sake of many old "nmakefiles" for externs, which will define NT and not MSW */ #if defined(NT) && !defined(MSW) #define MSW #endif /* These pragmas are only used for MSVC, not MinGW or Cygwin */ #ifdef _MSC_VER /* #pragma warning( disable : 4091 ) */ #pragma warning( disable : 4305 ) /* uncast const double to float */ #pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */ #pragma warning( disable : 4101 ) /* unused automatic variables */ #endif /* _MSC_VER */ /* the external storage class is "extern" in UNIX; in MSW it's ugly. */ #ifndef EXTERN #ifdef _WIN32 #ifdef PD_INTERNAL #define EXTERN __declspec(dllexport) extern #else #define EXTERN __declspec(dllimport) extern #endif /* PD_INTERNAL */ #else #define EXTERN extern #endif /* _WIN32 */ #endif /* EXTERN */ /* On most c compilers, you can just say "struct foo;" to declare a structure whose elements are defined elsewhere. On very old MSVC versions, when compiling C (but not C++) code, you have to say "extern struct foo;". So we make a stupid macro: */ #if defined(_MSC_VER) && !defined(_LANGUAGE_C_PLUS_PLUS) \ && !defined(__cplusplus) && (_MSC_VER < 1700) #define EXTERN_STRUCT extern struct #else #define EXTERN_STRUCT struct #endif /* Define some attributes, specific to the compiler */ #if defined(__GNUC__) #define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__ ((format (printf, a, b))) #else #define ATTRIBUTE_FORMAT_PRINTF(a, b) #endif #if !defined(_SIZE_T) && !defined(_SIZE_T_) #include /* just for size_t -- how lame! */ #endif /* Microsoft Visual Studio is not C99, but since VS2015 has included most C99 headers: https://docs.microsoft.com/en-us/previous-versions/hh409293(v=vs.140)#c-runtime-library These definitions recreate stdint.h types, but only in pre-2015 Visual Studio: */ #if defined(_MSC_VER) && _MSC_VER < 1900 typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef signed __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #else # include #endif /* for FILE, needed by sys_fopen() and sys_fclose() only */ #include #define MAXPDSTRING 1000 /* use this for anything you want */ #define MAXPDARG 5 /* max number of args we can typecheck today */ /* signed and unsigned integer types the size of a pointer: */ #if !defined(PD_LONGINTTYPE) #if defined(_WIN32) && defined(_WIN64) #define PD_LONGINTTYPE long long #else #define PD_LONGINTTYPE long #endif #endif #if !defined(PD_FLOATSIZE) /* normally, our floats (t_float, t_sample,...) are 32bit */ # define PD_FLOATSIZE 32 #endif #if PD_FLOATSIZE == 32 # define PD_FLOATTYPE float /* an unsigned int of the same size as FLOATTYPE: */ # define PD_FLOATUINTTYPE uint32_t #elif PD_FLOATSIZE == 64 # define PD_FLOATTYPE double # define PD_FLOATUINTTYPE uint64_t #else # error invalid FLOATSIZE: must be 32 or 64 #endif typedef PD_LONGINTTYPE t_int; /* pointer-size integer */ typedef PD_FLOATTYPE t_float; /* a float type at most the same size */ typedef PD_FLOATTYPE t_floatarg; /* float type for function calls */ typedef struct _symbol { const char *s_name; struct _class **s_thing; struct _symbol *s_next; } t_symbol; EXTERN_STRUCT _array; #define t_array struct _array /* g_canvas.h */ /* pointers to glist and array elements go through a "stub" which sticks around after the glist or array is freed. The stub itself is deleted when both the glist/array is gone and the refcount is zero, ensuring that no gpointers are pointing here. */ #define GP_NONE 0 /* the stub points nowhere (has been cut off) */ #define GP_GLIST 1 /* the stub points to a glist element */ #define GP_ARRAY 2 /* ... or array */ typedef struct _gstub { union { struct _glist *gs_glist; /* glist we're in */ struct _array *gs_array; /* array we're in */ } gs_un; int gs_which; /* GP_GLIST/GP_ARRAY */ int gs_refcount; /* number of gpointers pointing here */ } t_gstub; typedef struct _gpointer /* pointer to a gobj in a glist */ { union { struct _scalar *gp_scalar; /* scalar we're in (if glist) */ union word *gp_w; /* raw data (if array) */ } gp_un; int gp_valid; /* number which must match gpointee */ t_gstub *gp_stub; /* stub which points to glist/array */ } t_gpointer; typedef union word { t_float w_float; t_symbol *w_symbol; t_gpointer *w_gpointer; t_array *w_array; struct _binbuf *w_binbuf; int w_index; } t_word; typedef enum { A_NULL, A_FLOAT, A_SYMBOL, A_POINTER, A_SEMI, A_COMMA, A_DEFFLOAT, A_DEFSYM, A_DOLLAR, A_DOLLSYM, A_GIMME, A_CANT } t_atomtype; #define A_DEFSYMBOL A_DEFSYM /* better name for this */ typedef struct _atom { t_atomtype a_type; union word a_w; } t_atom; EXTERN_STRUCT _class; #define t_class struct _class EXTERN_STRUCT _outlet; #define t_outlet struct _outlet EXTERN_STRUCT _inlet; #define t_inlet struct _inlet EXTERN_STRUCT _binbuf; #define t_binbuf struct _binbuf EXTERN_STRUCT _clock; #define t_clock struct _clock EXTERN_STRUCT _outconnect; #define t_outconnect struct _outconnect EXTERN_STRUCT _glist; #define t_glist struct _glist #define t_canvas struct _glist /* LATER lose this */ EXTERN_STRUCT _template; typedef t_class *t_pd; /* pure datum: nothing but a class pointer */ typedef struct _gobj /* a graphical object */ { t_pd g_pd; /* pure datum header (class) */ struct _gobj *g_next; /* next in list */ } t_gobj; typedef struct _scalar /* a graphical object holding data */ { t_gobj sc_gobj; /* header for graphical object */ t_symbol *sc_template; /* template name (LATER replace with pointer) */ t_word sc_vec[1]; /* indeterminate-length array of words */ } t_scalar; typedef struct _text /* patchable object - graphical, with text */ { t_gobj te_g; /* header for graphical object */ t_binbuf *te_binbuf; /* holder for the text */ t_outlet *te_outlet; /* linked list of outlets */ t_inlet *te_inlet; /* linked list of inlets */ short te_xpix; /* x&y location (within the toplevel) */ short te_ypix; short te_width; /* requested width in chars, 0 if auto */ unsigned int te_type:2; /* from defs below */ } t_text; #define T_TEXT 0 /* just a textual comment */ #define T_OBJECT 1 /* a MAX style patchable object */ #define T_MESSAGE 2 /* a MAX type message */ #define T_ATOM 3 /* a cell to display a number or symbol */ #define te_pd te_g.g_pd /* t_object is synonym for t_text (LATER unify them) */ typedef struct _text t_object; #define ob_outlet te_outlet #define ob_inlet te_inlet #define ob_binbuf te_binbuf #define ob_pd te_g.g_pd #define ob_g te_g typedef void (*t_method)(void); typedef void *(*t_newmethod)(void); /* in ARM 64 a varargs prototype generates a different function call sequence from a fixed one, so in that special case we make a more restrictive definition for t_gotfn. This will break some code in the "chaos" package in Pd extended. (that code will run incorrectly anyhow so why not catch it at compile time anyhow.) */ #if defined(__APPLE__) && defined(__aarch64__) typedef void (*t_gotfn)(void *x); #else typedef void (*t_gotfn)(void *x, ...); #endif /* ---------------- pre-defined objects and symbols --------------*/ EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */ EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */ /* --------- prototypes from the central message system ----------- */ EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv); EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv); EXTERN t_symbol *gensym(const char *s); EXTERN t_gotfn getfn(const t_pd *x, t_symbol *s); EXTERN t_gotfn zgetfn(const t_pd *x, t_symbol *s); EXTERN void nullfn(void); EXTERN void pd_vmess(t_pd *x, t_symbol *s, const char *fmt, ...); /* the following macros are for sending non-type-checkable messages, i.e., using function lookup but circumventing type checking on arguments. Only use for internal messaging protected by A_CANT so that the message can't be generated at patch level. */ #define mess0(x, s) ((*getfn((x), (s)))((x))) typedef void (*t_gotfn1)(void *x, void *arg1); #define mess1(x, s, a) ((*(t_gotfn1)getfn((x), (s)))((x), (a))) typedef void (*t_gotfn2)(void *x, void *arg1, void *arg2); #define mess2(x, s, a,b) ((*(t_gotfn2)getfn((x), (s)))((x), (a),(b))) typedef void (*t_gotfn3)(void *x, void *arg1, void *arg2, void *arg3); #define mess3(x, s, a,b,c) ((*(t_gotfn3)getfn((x), (s)))((x), (a),(b),(c))) typedef void (*t_gotfn4)(void *x, void *arg1, void *arg2, void *arg3, void *arg4); #define mess4(x, s, a,b,c,d) \ ((*(t_gotfn4)getfn((x), (s)))((x), (a),(b),(c),(d))) typedef void (*t_gotfn5)(void *x, void *arg1, void *arg2, void *arg3, void *arg4, void *arg5); #define mess5(x, s, a,b,c,d,e) \ ((*(t_gotfn5)getfn((x), (s)))((x), (a),(b),(c),(d),(e))) EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); EXTERN t_pd *pd_newest(void); /* --------------- memory management -------------------- */ EXTERN void *getbytes(size_t nbytes); EXTERN void *getzbytes(size_t nbytes); EXTERN void *copybytes(const void *src, size_t nbytes); EXTERN void freebytes(void *x, size_t nbytes); EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize); /* -------------------- atoms ----------------------------- */ #define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0) #define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0) #define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \ (atom)->a_w.w_gpointer = (gp)) #define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f)) #define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \ (atom)->a_w.w_symbol = (s)) #define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \ (atom)->a_w.w_index = (n)) #define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \ (atom)->a_w.w_symbol= (s)) EXTERN t_float atom_getfloat(const t_atom *a); EXTERN t_int atom_getint(const t_atom *a); EXTERN t_symbol *atom_getsymbol(const t_atom *a); EXTERN t_symbol *atom_gensym(const t_atom *a); EXTERN t_float atom_getfloatarg(int which, int argc, const t_atom *argv); EXTERN t_int atom_getintarg(int which, int argc, const t_atom *argv); EXTERN t_symbol *atom_getsymbolarg(int which, int argc, const t_atom *argv); EXTERN void atom_string(const t_atom *a, char *buf, unsigned int bufsize); /* ------------------ binbufs --------------- */ EXTERN t_binbuf *binbuf_new(void); EXTERN void binbuf_free(t_binbuf *x); EXTERN t_binbuf *binbuf_duplicate(const t_binbuf *y); EXTERN void binbuf_text(t_binbuf *x, const char *text, size_t size); EXTERN void binbuf_gettext(const t_binbuf *x, char **bufp, int *lengthp); EXTERN void binbuf_clear(t_binbuf *x); EXTERN void binbuf_add(t_binbuf *x, int argc, const t_atom *argv); EXTERN void binbuf_addv(t_binbuf *x, const char *fmt, ...); EXTERN void binbuf_addbinbuf(t_binbuf *x, const t_binbuf *y); EXTERN void binbuf_addsemi(t_binbuf *x); EXTERN void binbuf_restore(t_binbuf *x, int argc, const t_atom *argv); EXTERN void binbuf_print(const t_binbuf *x); EXTERN int binbuf_getnatom(const t_binbuf *x); EXTERN t_atom *binbuf_getvec(const t_binbuf *x); EXTERN int binbuf_resize(t_binbuf *x, int newsize); EXTERN void binbuf_eval(const t_binbuf *x, t_pd *target, int argc, const t_atom *argv); EXTERN int binbuf_read(t_binbuf *b, const char *filename, const char *dirname, int crflag); EXTERN int binbuf_read_via_canvas(t_binbuf *b, const char *filename, const t_canvas *canvas, int crflag); EXTERN int binbuf_read_via_path(t_binbuf *b, const char *filename, const char *dirname, int crflag); EXTERN int binbuf_write(const t_binbuf *x, const char *filename, const char *dir, int crflag); EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir); EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, const t_atom *av, int tonew); /* ------------------ clocks --------------- */ EXTERN t_clock *clock_new(void *owner, t_method fn); EXTERN void clock_set(t_clock *x, double systime); EXTERN void clock_delay(t_clock *x, double delaytime); EXTERN void clock_unset(t_clock *x); EXTERN void clock_setunit(t_clock *x, double timeunit, int sampflag); EXTERN double clock_getlogicaltime(void); EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */ EXTERN double clock_gettimesince(double prevsystime); EXTERN double clock_gettimesincewithunits(double prevsystime, double units, int sampflag); EXTERN double clock_getsystimeafter(double delaytime); EXTERN void clock_free(t_clock *x); /* ----------------- pure data ---------------- */ EXTERN t_pd *pd_new(t_class *cls); EXTERN void pd_free(t_pd *x); EXTERN void pd_bind(t_pd *x, t_symbol *s); EXTERN void pd_unbind(t_pd *x, t_symbol *s); EXTERN t_pd *pd_findbyclass(t_symbol *s, const t_class *c); EXTERN void pd_pushsym(t_pd *x); EXTERN void pd_popsym(t_pd *x); EXTERN void pd_bang(t_pd *x); EXTERN void pd_pointer(t_pd *x, t_gpointer *gp); EXTERN void pd_float(t_pd *x, t_float f); EXTERN void pd_symbol(t_pd *x, t_symbol *s); EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv); EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv); #define pd_class(x) (*(x)) /* ----------------- pointers ---------------- */ EXTERN void gpointer_init(t_gpointer *gp); EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto); EXTERN void gpointer_unset(t_gpointer *gp); EXTERN int gpointer_check(const t_gpointer *gp, int headok); /* ----------------- patchable "objects" -------------- */ EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2); EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp); EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp); EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp); EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f); EXTERN void inlet_free(t_inlet *x); EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s); EXTERN void outlet_bang(t_outlet *x); EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp); EXTERN void outlet_float(t_outlet *x, t_float f); EXTERN void outlet_symbol(t_outlet *x, t_symbol *s); EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv); EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv); EXTERN t_symbol *outlet_getsymbol(t_outlet *x); EXTERN void outlet_free(t_outlet *x); EXTERN t_object *pd_checkobject(t_pd *x); /* -------------------- canvases -------------- */ EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir); EXTERN void canvas_setargs(int argc, const t_atom *argv); EXTERN void canvas_getargs(int *argcp, t_atom **argvp); EXTERN t_symbol *canvas_getcurrentdir(void); EXTERN t_glist *canvas_getcurrent(void); EXTERN void canvas_makefilename(const t_glist *c, const char *file, char *result, int resultsize); EXTERN t_symbol *canvas_getdir(const t_glist *x); EXTERN char sys_font[]; /* default typeface set in s_main.c */ EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */ EXTERN int sys_hostfontsize(int fontsize, int zoom); EXTERN int sys_zoomfontwidth(int fontsize, int zoom, int worstcase); EXTERN int sys_zoomfontheight(int fontsize, int zoom, int worstcase); EXTERN int sys_fontwidth(int fontsize); EXTERN int sys_fontheight(int fontsize); EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b); EXTERN int canvas_open(const t_canvas *x, const char *name, const char *ext, char *dirresult, char **nameresult, unsigned int size, int bin); EXTERN t_float canvas_getsr(t_canvas *x); EXTERN int canvas_getsignallength(t_canvas *x); /* ---------------- widget behaviors ---------------------- */ EXTERN_STRUCT _widgetbehavior; #define t_widgetbehavior struct _widgetbehavior EXTERN_STRUCT _parentwidgetbehavior; #define t_parentwidgetbehavior struct _parentwidgetbehavior EXTERN const t_parentwidgetbehavior *pd_getparentwidget(t_pd *x); /* -------------------- classes -------------- */ #define CLASS_DEFAULT 0 /* flags for new classes below */ #define CLASS_PD 1 /* non-canvasable (bare) pd such as an inlet */ #define CLASS_GOBJ 2 /* pd that can belong to a canvas */ #define CLASS_PATCHABLE 3 /* pd that also can have inlets and outlets */ #define CLASS_TYPEMASK 3 #define CLASS_NOINLET 8 /* suppress left inlet */ #define CLASS_MULTICHANNEL 0x10 /* can deal with multichannel sigs */ #define CLASS_NOPROMOTESIG 0x20 /* don't promote scalars to signals */ #define CLASS_NOPROMOTELEFT 0x40 /* not even the main (left) inlet */ /* Setting a tilde object's CLASS_MULTICHANNEL flag declares that it can deal with multichannel inputs. In this case the channel counts of the inputs might not match; it's up to the dsp method to figure out what to do. Also, the output signal vectors aren't allocated. The output channel counts have to be specified by the object at DSP time. If the object can't put itself on the DSP chain it then has to create outputs anyway and arrange to zero them. By default, if a tilde object's inputs are unconnected, Pd fills them in by adding scalar-to-vector conversions to the DSP chain as needed before calling the dsp method. This behavior can be suppressed for the left (main) inlet by setting CLASS_NOPROMOTELEFT and for one or more non-main inlets by setting CLASS_NOPROMOTESIG. Seeing this, the object can then opt to supply a faster routine; for example, "+" can do a vector-scalar add. In any case, signal outputs are all vectors, and are allocated automatically unless the CLASS_MULTICHANNEL flag is also set. */ EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod, t_method freemethod, size_t size, int flags, t_atomtype arg1, ...); EXTERN t_class *class_new64(t_symbol *name, t_newmethod newmethod, t_method freemethod, size_t size, int flags, t_atomtype arg1, ...); EXTERN void class_free(t_class *c); #ifdef PDINSTANCE EXTERN t_class *class_getfirst(void); #endif EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s, t_atomtype type1, ...); EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel, t_atomtype arg1, ...); EXTERN void class_addbang(t_class *c, t_method fn); EXTERN void class_addpointer(t_class *c, t_method fn); EXTERN void class_doaddfloat(t_class *c, t_method fn); EXTERN void class_addsymbol(t_class *c, t_method fn); EXTERN void class_addlist(t_class *c, t_method fn); EXTERN void class_addanything(t_class *c, t_method fn); EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s); EXTERN void class_setwidget(t_class *c, const t_widgetbehavior *w); EXTERN void class_setparentwidget(t_class *c, const t_parentwidgetbehavior *w); EXTERN const char *class_getname(const t_class *c); EXTERN const char *class_gethelpname(const t_class *c); EXTERN const char *class_gethelpdir(const t_class *c); EXTERN void class_setdrawcommand(t_class *c); EXTERN int class_isdrawcommand(const t_class *c); EXTERN void class_set_extern_dir(t_symbol *s); EXTERN void class_domainsignalin(t_class *c, int onset); #define CLASS_MAINSIGNALIN(c, type, field) \ class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0) /* prototype for functions to save Pd's to a binbuf */ typedef void (*t_savefn)(t_gobj *x, t_binbuf *b); EXTERN void class_setsavefn(t_class *c, t_savefn f); EXTERN t_savefn class_getsavefn(const t_class *c); EXTERN void obj_saveformat(const t_object *x, t_binbuf *bb); /* add format to bb */ /* prototype for functions to open properties dialogs */ typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist); EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f); EXTERN t_propertiesfn class_getpropertiesfn(const t_class *c); typedef void (*t_classfreefn)(t_class *); EXTERN void class_setfreefn(t_class *c, t_classfreefn fn); #ifndef PD_CLASS_DEF #define class_addbang(x, y) class_addbang((x), (t_method)(y)) #define class_addpointer(x, y) class_addpointer((x), (t_method)(y)) #define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y)) #define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y)) #define class_addlist(x, y) class_addlist((x), (t_method)(y)) #define class_addanything(x, y) class_addanything((x), (t_method)(y)) #endif #if PD_FLOATSIZE == 64 # define class_new class_new64 #endif /* ------------ printing --------------------------------- */ EXTERN void post(const char *fmt, ...); EXTERN void startpost(const char *fmt, ...); EXTERN void poststring(const char *s); EXTERN void postfloat(t_floatarg f); EXTERN void postatom(int argc, const t_atom *argv); EXTERN void endpost(void); EXTERN void bug(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2); EXTERN void pd_error(const void *object, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); /* for logpost(); does *not* work with verbose()! */ typedef enum { PD_CRITICAL = 0, PD_ERROR, PD_NORMAL, PD_DEBUG, PD_VERBOSE } t_loglevel; EXTERN void logpost(const void *object, int level, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(3, 4); /* deprecated, use logpost() instead. */ EXTERN void verbose(int level, const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); /* ------------ system interface routines ------------------- */ EXTERN int sys_isabsolutepath(const char *dir); EXTERN void sys_bashfilename(const char *from, char *to); EXTERN void sys_unbashfilename(const char *from, char *to); EXTERN int open_via_path(const char *dir, const char *name, const char *ext, char *dirresult, char **nameresult, unsigned int size, int bin); EXTERN int sched_geteventno(void); EXTERN double sys_getrealtime(void); EXTERN int (*sys_idlehook)(void); /* hook to add idle time computation */ /* Win32's open()/fopen() do not handle UTF-8 filenames so we need * these internal versions that handle UTF-8 filenames the same across * all platforms. They are recommended for use in external * objectclasses as well so they work with Unicode filenames on Windows */ EXTERN int sys_open(const char *path, int oflag, ...); EXTERN int sys_close(int fd); EXTERN FILE *sys_fopen(const char *filename, const char *mode); EXTERN int sys_fclose(FILE *stream); /* ------------ threading ------------------- */ EXTERN void sys_lock(void); EXTERN void sys_unlock(void); EXTERN int sys_trylock(void); /* --------------- signals ----------------------------------- */ typedef PD_FLOATTYPE t_sample; typedef union _sampleint_union { t_sample f; PD_FLOATUINTTYPE i; } t_sampleint_union; #define MAXLOGSIG 32 #define MAXSIGSIZE (1 << MAXLOGSIG) typedef struct _signal { union { int s_length; /* number of items per channel */ int s_n; /* for source compatibility: pre-0.54 name */ }; t_sample *s_vec; /* the samples, s_nchans vectors of s_length */ t_float s_sr; /* samples per second per channel */ int s_nchans; /* number of channels */ int s_overlap; /* number of times each sample appears */ int s_refcount; /* number of times signal is referenced */ int s_isborrowed; /* whether we're going to borrow our array */ int s_isscalar; /* scalar for an unconnected signal input */ struct _signal *s_borrowedfrom; /* signal to borrow it from */ struct _signal *s_nextfree; /* next in freelist */ struct _signal *s_nextused; /* next in used list */ int s_nalloc; /* allocated size of array in points */ } t_signal; typedef t_int *(*t_perfroutine)(t_int *args); EXTERN t_signal *signal_new(int length, int nchans, t_float sr, t_sample *scalarptr); EXTERN void signal_setmultiout(t_signal **sig, int nchans); EXTERN t_int *plus_perform(t_int *args); EXTERN t_int *plus_perf8(t_int *args); EXTERN t_int *zero_perform(t_int *args); EXTERN t_int *zero_perf8(t_int *args); EXTERN t_int *copy_perform(t_int *args); EXTERN t_int *copy_perf8(t_int *args); EXTERN t_int *scalarcopy_perform(t_int *args); EXTERN t_int *scalarcopy_perf8(t_int *args); EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n); EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n); EXTERN void dsp_add_scalarcopy(t_float *in, t_sample *out, int n); EXTERN void dsp_add_zero(t_sample *out, int n); EXTERN int sys_getblksize(void); EXTERN t_float sys_getsr(void); EXTERN int sys_get_inchannels(void); EXTERN int sys_get_outchannels(void); EXTERN void dsp_add(t_perfroutine f, int n, ...); EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec); EXTERN void pd_fft(t_float *buf, int npoints, int inverse); EXTERN int ilog2(int n); EXTERN void mayer_fht(t_sample *fz, int n); EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag); EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag); EXTERN void mayer_realfft(int n, t_sample *real); EXTERN void mayer_realifft(int n, t_sample *real); EXTERN float *cos_table; #define LOGCOSTABSIZE 9 #define COSTABSIZE (1<: receiver on the GUI side (e.g. a Tcl/Tk 'proc') * : string of format specifiers * <...>: values according to the format specifiers * * the can be a NULL pointer (in which case it is ignored) * the user of NULL as a is discouraged * depending on the format specifiers, one or more values are passed * 'f' : : a floating point number * 'i' : : an integer number * 's' : : a string * 'r' : : a raw string * 'x' : : a generic pointer * 'o' : : an graphical object * '^' : : a toplevel window (legacy) * 'c' : : a canvas (on a window) * 'F' : : array of t_float's * 'S' : : array of strings * 'R' : : array of raw strings * 'a' : : list of atoms * 'A' : : array of atoms * 'w' : : list of floatwords * 'W' : : array of floatwords * 'm' : : a Pd message * 'p' : : a pascal string (explicit size; not \0-terminated) * 'k' : : a color (or kolor, if you prefer) * ' ' : none : ignored * the use of the specifiers 'x^' is discouraged * raw-strings ('rR') should only be used for constant, well-known strings */ EXTERN void pdgui_vmess(const char* destination, const char* fmt, ...); /* improved dialog window creation * this will insert a first argument to based on * which the GUI can then use to callback. * gfxstub_new() ensures that the given receiver will be available, * even if the has been removed in the meantime. * see pdgui_vmess() for a description of and the varargs */ EXTERN void pdgui_stub_vnew(t_pd *owner, const char* destination, void *key, const char* fmt, ...); EXTERN void pdgui_stub_deleteforkey(void *key); extern t_class *glob_pdobject; /* object to send "pd" messages */ /*------------- Max 0.26 compatibility --------------------*/ /* the following reflects the new way classes are laid out, with the class pointing to the messlist and not vice versa. Externs shouldn't feel it. */ typedef t_class *t_externclass; EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine, t_method freeroutine, t_symbol *name, size_t size, int tiny, \ t_atomtype arg1, ...); EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...); #define t_getbytes getbytes #define t_freebytes freebytes #define t_resizebytes resizebytes #define typedmess pd_typedmess #define vmess pd_vmess /* A definition to help gui objects straddle 0.34-0.35 changes. If this is defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */ #define PD_USE_TE_XPIX #ifndef _MSC_VER /* Microoft compiler can't handle "inline" function/macros */ #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) /* a test for NANs and denormals. Should only be necessary on i386. */ #if PD_FLOATSIZE == 32 typedef union { t_float f; unsigned int ui; } t_bigorsmall32; static inline int PD_BADFLOAT(t_float f) /* malformed float */ { t_bigorsmall32 pun; pun.f = f; pun.ui &= 0x7f800000; return((pun.ui == 0) | (pun.ui == 0x7f800000)); } static inline int PD_BIGORSMALL(t_float f) /* exponent outside (-64,64) */ { t_bigorsmall32 pun; pun.f = f; return((pun.ui & 0x20000000) == ((pun.ui >> 1) & 0x20000000)); } #elif PD_FLOATSIZE == 64 typedef union { t_float f; unsigned int ui[2]; } t_bigorsmall64; static inline int PD_BADFLOAT(t_float f) /* malformed double */ { t_bigorsmall64 pun; pun.f = f; pun.ui[1] &= 0x7ff00000; return((pun.ui[1] == 0) | (pun.ui[1] == 0x7ff00000)); } static inline int PD_BIGORSMALL(t_float f) /* exponent outside (-512,512) */ { t_bigorsmall64 pun; pun.f = f; return((pun.ui[1] & 0x20000000) == ((pun.ui[1] >> 1) & 0x20000000)); } #endif /* PD_FLOATSIZE */ #else /* not INTEL or ARM */ #define PD_BADFLOAT(f) 0 #define PD_BIGORSMALL(f) 0 #endif #else /* _MSC_VER */ #if PD_FLOATSIZE == 32 #define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \ (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000)) /* more stringent test: anything not between 1e-19 and 1e19 in absolute val */ #define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \ (((*(unsigned int*)&(f))&0x60000000)==0x60000000)) #else /* 64 bits... don't know what to do here */ #define PD_BADFLOAT(f) (!(((f) >= 0) || ((f) <= 0))) #define PD_BIGORSMALL(f) ((f) > 1e150 || (f) < -1e150 \ || (f) > -1e-150 && (f) < 1e-150 ) #endif #endif /* _MSC_VER */ /* get version number at run time */ EXTERN void sys_getversion(int *major, int *minor, int *bugfix); /* get floatsize at run time */ EXTERN unsigned int sys_getfloatsize(void); EXTERN_STRUCT _instancemidi; #define t_instancemidi struct _instancemidi EXTERN_STRUCT _instanceinter; #define t_instanceinter struct _instanceinter EXTERN_STRUCT _instancecanvas; #define t_instancecanvas struct _instancecanvas EXTERN_STRUCT _instanceugen; #define t_instanceugen struct _instanceugen EXTERN_STRUCT _instancestuff; #define t_instancestuff struct _instancestuff #ifndef PDTHREADS #define PDTHREADS 1 #endif struct _pdinstance { double pd_systime; /* global time in Pd ticks */ t_clock *pd_clock_setlist; /* list of set clocks */ t_canvas *pd_canvaslist; /* list of all root canvases */ struct _template *pd_templatelist; /* list of all templates */ int pd_instanceno; /* ordinal number of this instance */ t_symbol **pd_symhash; /* symbol table hash table */ t_instancemidi *pd_midi; /* private stuff for x_midi.c */ t_instanceinter *pd_inter; /* private stuff for s_inter.c */ t_instanceugen *pd_ugen; /* private stuff for d_ugen.c */ t_instancecanvas *pd_gui; /* semi-private stuff in g_canvas.h */ t_instancestuff *pd_stuff; /* semi-private stuff in s_stuff.h */ t_pd *pd_newest; /* most recently created object */ #ifdef PDINSTANCE t_symbol pd_s_pointer; t_symbol pd_s_float; t_symbol pd_s_symbol; t_symbol pd_s_bang; t_symbol pd_s_list; t_symbol pd_s_anything; t_symbol pd_s_signal; t_symbol pd_s__N; t_symbol pd_s__X; t_symbol pd_s_x; t_symbol pd_s_y; t_symbol pd_s_; #endif #if PDTHREADS int pd_islocked; #endif }; #define t_pdinstance struct _pdinstance EXTERN t_pdinstance pd_maininstance; /* m_pd.c */ #ifdef PDINSTANCE EXTERN t_pdinstance *pdinstance_new(void); EXTERN void pd_setinstance(t_pdinstance *x); EXTERN void pdinstance_free(t_pdinstance *x); #endif /* PDINSTANCE */ #if defined(PDTHREADS) && defined(PDINSTANCE) #ifdef _MSC_VER #define PERTHREAD __declspec(thread) #else #define PERTHREAD __thread #endif /* _MSC_VER */ #else #define PERTHREAD #endif #ifdef PDINSTANCE extern PERTHREAD t_pdinstance *pd_this; EXTERN t_pdinstance **pd_instances; EXTERN int pd_ninstances; #else #define pd_this (&pd_maininstance) #endif /* PDINSTANCE */ #ifdef PDINSTANCE #define s_pointer (pd_this->pd_s_pointer) #define s_float (pd_this->pd_s_float) #define s_symbol (pd_this->pd_s_symbol) #define s_bang (pd_this->pd_s_bang) #define s_list (pd_this->pd_s_list) #define s_anything (pd_this->pd_s_anything) #define s_signal (pd_this->pd_s_signal) #define s__N (pd_this->pd_s__N) #define s__X (pd_this->pd_s__X) #define s_x (pd_this->pd_s_x) #define s_y (pd_this->pd_s_y) #define s_ (pd_this->pd_s_) #else EXTERN t_symbol s_pointer, s_float, s_symbol, s_bang, s_list, s_anything, s_signal, s__N, s__X, s_x, s_y, s_; #endif EXTERN t_canvas *pd_getcanvaslist(void); EXTERN int pd_getdspstate(void); /* x_text.c */ EXTERN t_binbuf *text_getbufbyname(t_symbol *s); /* get binbuf from text obj */ EXTERN void text_notifybyname(t_symbol *s); /* notify it was modified */ /* g_undo.c */ /* store two message-sets to be sent to the object's method for 'undo'ing * resp. 'redo'ing the current state of an object. * this creates an internal copy of the atom-lists (so the caller is responsible * for freeing any dynamically allocated data) * this is a no-op if called during 'undo' (resp. 'redo'). */ EXTERN void pd_undo_set_objectstate(t_canvas*canvas, t_pd*x, t_symbol*s, int undo_argc, t_atom*undo_argv, int redo_argc, t_atom*redo_argv); #if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus) } #endif #define __m_pd_h_ #endif /* __m_pd_h_ */ hvcc-0.16.0/hvcc/generators/c2pdext/templates/Makefile0000644000000000000000000000114700000000000017516 0ustar00# Makefile to build class '{name}' for Pure Data. # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. # library name lib.name = {{name}} ldlibs += -lstdc++ # input source file (class name == source file basename) class.sources = pdext/{{name}}~.c common.sources = $(filter-out pdext/{{name}}~.c, $(wildcard pdext/*.c)) common.sources += $(wildcard pdext/*.cpp) # all extra files to be included in binary distribution of the library #datafiles = helloworld-help.pd helloworld-meta.pd README.md PDLIBBUILDER_DIR=. include $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder hvcc-0.16.0/hvcc/generators/c2pdext/templates/pd_external.c0000644000000000000000000001224300000000000020526 0ustar00{{copyright}} #if _MSC_VER || _WIN32 || _WIN64 #include #define DLL_EXPORT __declspec(dllexport) extern #else #include #define DLL_EXPORT #endif #include #include "m_pd.h" #include "Heavy_{{name}}.h" static t_class *{{struct_name}}_class; typedef struct _{{struct_name}} { t_object x_obj; {# declare inlets and outlets #} {%- for i in range(1, num_input_channels) %} t_inlet *inlet{{i}}; {%- endfor %} {%- for i in range(num_output_channels) %} t_outlet *outlet{{i}}; {%- endfor %} t_outlet *msgOutlet; HeavyContextInterface *hv; t_float f; // dummy } t_{{struct_name}}; static void printHook(HeavyContextInterface *c, const char *receiverName, const char *msgString, const HvMessage *m) { double timestampMs = 1000.0 * ((double) hv_msg_getTimestamp(m)) / hv_getSampleRate(c); post("[{{display_name}} @ %0.3gms] %s: %s", timestampMs, receiverName, msgString); } static void sendHook(HeavyContextInterface *c, const char *receiverName, unsigned int receiverHash, const HvMessage * m) { if (!strcmp(receiverName, "HV_TO_PD")) { t_outlet *const outlet = ((t_{{struct_name}} *) hv_getUserData(c))->msgOutlet; if (hv_msg_getNumElements(m) == 1) { if (hv_msg_isFloat(m, 0)) { outlet_float(outlet, hv_msg_getFloat(m, 0)); } else if (hv_msg_isBang(m, 0)) { outlet_bang(outlet); } else if (hv_msg_isSymbol(m, 0)) { outlet_symbol(outlet, gensym(hv_msg_getSymbol(m, 0))); } else return; } else { const int argc = (int) hv_msg_getNumElements(m); t_atom *argv = (t_atom *) alloca(argc*sizeof(t_atom)); for (int i = 0; i < argc; i++) { if (hv_msg_isFloat(m, i)) { SETFLOAT(argv+i, hv_msg_getFloat(m, i)); } else if (hv_msg_isSymbol(m, i)) { SETSYMBOL(argv+i, gensym(hv_msg_getSymbol(m, i))); } else return; } outlet_list(outlet, NULL, argc, argv); } } } static void *{{struct_name}}_new(t_symbol *s, int argc, t_atom *argv) { t_{{struct_name}} *x = (t_{{struct_name}} *) pd_new({{struct_name}}_class); {%- for i in range(1, num_input_channels) %} x->inlet{{i}} = signalinlet_new(&x->x_obj, 0.0f); {%- endfor %} {%- for i in range(num_output_channels) %} x->outlet{{i}} = outlet_new(&x->x_obj, &s_signal); {%- endfor %} x->msgOutlet = outlet_new(&x->x_obj, &s_anything); x->hv = hv_{{name}}_new((double) sys_getsr()); hv_setUserData(x->hv, x); hv_setPrintHook(x->hv, printHook); hv_setSendHook(x->hv, sendHook); return (void *) x; } static void {{struct_name}}_free(t_{{struct_name}} *x) { {%- for i in range(num_input_channels-1) %} inlet_free(x->inlet{{i+1}}); {%- endfor %} {%- for i in range(num_output_channels) %} outlet_free(x->outlet{{i}}); {%- endfor %} outlet_free(x->msgOutlet); hv_delete(x->hv); } static t_int *{{struct_name}}_perform(t_int *w) { t_{{struct_name}} *x = (t_{{struct_name}} *) w[1]; {%- if num_input_channels > 0 %} float *inputChannels[{{num_input_channels}}] = { {%- for i in range(num_input_channels) %} (t_sample *) w[{{i+2}}], {%- endfor %} }; {%- else %} float **inputChannels = NULL; {%- endif %} {%- if num_output_channels > 0 %} float *outputChannels[{{num_output_channels}}] = { {%- for i in range(num_output_channels) %} (t_sample *) w[{{num_input_channels+i+2}}], {%- endfor %} }; {%- else %} float **outputChannels = NULL; {%- endif %} int n = (int) (w[{{num_input_channels+num_output_channels+2}}]); hv_process(x->hv, inputChannels, outputChannels, n); return (w+{{num_input_channels+num_output_channels+3}}); } static void {{struct_name}}_dsp(t_{{struct_name}} *x, t_signal **sp) { dsp_add({{struct_name}}_perform, {{num_input_channels+num_output_channels+2}}, x, {%- for i in range(num_input_channels) %} sp[{{i}}]->s_vec, {%- endfor %} {%- for i in range(num_input_channels|max(1), num_input_channels|max(1)+num_output_channels) %} sp[{{i}}]->s_vec, {%- endfor %} sp[0]->s_n); } static void {{struct_name}}_onMessage(t_{{struct_name}} *x, t_symbol *s0, int argc, t_atom* argv) { // convert a Pd message into a Heavy message HvMessage *msg = (HvMessage *) alloca(hv_msg_getByteSize(argc > 0 ? argc : 1)); if (argc > 0) { hv_msg_init(msg, argc, 0); for (int i = 0; i < argc; i++) { switch (argv[i].a_type) { case A_FLOAT: hv_msg_setFloat(msg, i, atom_getfloat(argv+i)); break; case A_SYMBOL: hv_msg_setSymbol(msg, i, atom_getsymbol(argv+i)->s_name); break; default: return; } } } else { hv_msg_init(msg, 1, 0); hv_msg_setBang(msg, 0); } hv_sendMessageToReceiver(x->hv, hv_stringToHash(s0->s_name), 0.0, msg); } DLL_EXPORT void {{struct_name}}_setup() { {{struct_name}}_class = class_new(gensym("{{display_name}}"), (t_newmethod) {{struct_name}}_new, (t_method) {{struct_name}}_free, sizeof(t_{{struct_name}}), CLASS_DEFAULT, A_GIMME, 0); class_addmethod({{struct_name}}_class, (t_method) {{struct_name}}_dsp, gensym("dsp"), 0); class_addanything({{struct_name}}_class, (t_method) {{struct_name}}_onMessage); CLASS_MAINSIGNALIN({{struct_name}}_class, t_{{struct_name}}, f); } {# force new line #} hvcc-0.16.0/hvcc/generators/c2unity/__init__.py0000644000000000000000000000000000000000000016200 0ustar00hvcc-0.16.0/hvcc/generators/c2unity/c2unity.py0000644000000000000000000001074400000000000016056 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import jinja2 import os import shutil import time from typing import Optional from pathlib import Path from ..copyright import copyright_manager from ..filters import filter_templates from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta class c2unity(Generator): """Generates a Audio Native Plugin wrapper for Unity 5. """ @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() in_parameter_list = externs.parameters.inParam out_parameter_list = externs.parameters.outParam event_list = externs.events.inEvent out_event_list = externs.events.outEvent table_list = externs.tables out_dir = Path(out_dir, "unity") patch_name = patch_name.lower() if patch_name is not None else "heavy" copyright_c = copyright_manager.get_copyright_for_c(copyright) templates_dir = Path(Path(__file__).parent, "templates") # initialise the jinja template environment env = jinja2.Environment() env.loader = jinja2.FileSystemLoader( encoding="utf-8-sig", searchpath=[templates_dir] ) try: # ensure that the output directory does not exist out_dir = out_dir.absolute() if out_dir.exists(): shutil.rmtree(out_dir) patch_src_dir = Path(out_dir, "include", "Heavy") if patch_src_dir.exists(): shutil.rmtree(patch_src_dir) shutil.copytree(c_src_dir, patch_src_dir) heavy_src_files = [f for f in os.listdir(c_src_dir) if f.endswith(".c") or f.endswith(".cpp")] # generate files from templates for f in env.list_templates(filter_func=filter_templates): file_path = Path(out_dir, f) file_path = Path(str(file_path).replace("{{name}}", patch_name)) if not file_path.parent.exists(): os.makedirs(file_path.parent) with open(file_path, "w") as g: g.write(env.get_template(f).render( name=patch_name, in_params=in_parameter_list, out_params=out_parameter_list, out_events=out_event_list, events=event_list, tables=table_list, pool_sizes_kb=externs.memoryPoolSizesKb, num_input_channels=num_input_channels, num_output_channels=num_output_channels, heavy_src_files=heavy_src_files, copyright=copyright_c)) return CompilerResp( stage="c2unity", in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2unity", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2unity/static/source/unity/AudioPluginInterface.h0000644000000000000000000002637400000000000024266 0ustar00#pragma once #define UNITY_AUDIO_PLUGIN_API_VERSION 0x010000 #ifndef UNITY_PREFIX_CONFIGURE_H #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) # define UNITY_WIN 1 #elif defined(__MACH__) || defined(__APPLE__) # define UNITY_OSX 1 #elif defined(__ANDROID__) # define UNITY_ANDROID 1 #elif defined(__linux__) # define UNITY_LINUX 1 #elif defined(__PS3__) # define UNITY_PS3 1 #elif defined(__SPU__) # define UNITY_SPU 1 #endif #if defined(_AMD64_) || defined(__LP64__) # define UNITY_64 1 # define UNITY_32 0 #else # define UNITY_64 0 # define UNITY_32 1 #endif #ifndef SInt16_defined # define SInt16_defined typedef signed short SInt16; #endif #ifndef UInt16_defined # define UInt16_defined typedef unsigned short UInt16; #endif #ifndef UInt8_defined # define UInt8_defined typedef unsigned char UInt8; #endif #ifndef SInt8_defined # define SInt8_defined typedef signed char SInt8; #endif #if UNITY_64 # if UNITY_LINUX # ifndef SInt32_defined # define SInt32_defined typedef signed int SInt32; # endif # ifndef UInt32_defined # define UInt32_defined typedef unsigned int UInt32; # endif # ifndef UInt64_defined # define UInt64_defined typedef unsigned long UInt64; # endif # ifndef SInt64_defined # define SInt64_defined typedef signed long SInt64; # endif # elif UNITY_OSX # ifndef SInt32_defined # define SInt32_defined typedef signed int SInt32; # endif # ifndef UInt32_defined # define UInt32_defined typedef unsigned int UInt32; # endif # ifndef UInt64_defined # define UInt64_defined typedef unsigned long long UInt64; # endif # ifndef SInt64_defined # define SInt64_defined typedef signed long long SInt64; # endif # elif UNITY_WIN # ifndef SInt32_defined # define SInt32_defined typedef signed long SInt32; # endif # ifndef UInt32_defined # define UInt32_defined typedef unsigned long UInt32; # endif # ifndef UInt64_defined # define UInt64_defined typedef unsigned long long UInt64; # endif # ifndef SInt64_defined # define SInt64_defined typedef signed long long SInt64; # endif # elif UNITY_ANDROID # ifndef SInt32_defined # define SInt32_defined typedef signed int SInt32; # endif # ifndef UInt32_defined # define UInt32_defined typedef unsigned int UInt32; # endif # ifndef UInt64_defined # define UInt64_defined typedef unsigned long long UInt64; # endif # ifndef SInt64_defined # define SInt64_defined typedef signed long long SInt64; # endif #endif #else # ifndef SInt32_defined # define SInt32_defined typedef signed int SInt32; # endif # ifndef UInt32_defined # define UInt32_defined typedef unsigned int UInt32; # endif # ifndef UInt64_defined # define UInt64_defined typedef unsigned long long UInt64; # endif # ifndef SInt64_defined # define SInt64_defined typedef signed long long SInt64; # endif #endif #endif #if UNITY_WIN #define UNITY_AUDIODSP_CALLBACK __stdcall #elif UNITY_OSX #define UNITY_AUDIODSP_CALLBACK #else #define UNITY_AUDIODSP_CALLBACK #endif // Attribute to make function be exported from a plugin #if UNITY_WIN #define UNITY_AUDIODSP_EXPORT_API __declspec(dllexport) #else #define UNITY_AUDIODSP_EXPORT_API #endif #if defined(__CYGWIN32__) #define UNITY_AUDIODSP_CALLBACK __stdcall #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) #define UNITY_AUDIODSP_CALLBACK __stdcall #elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) #define UNITY_AUDIODSP_CALLBACK #else #define UNITY_AUDIODSP_CALLBACK #endif #define UNITY_AUDIODSP_RESULT int #if !UNITY_SPU // asserts require _exit() to be defined #include #endif enum { UNITY_AUDIODSP_OK = 0, UNITY_AUDIODSP_ERR_UNSUPPORTED = 1, }; struct UnityAudioEffectState; typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_CreateCallback)(UnityAudioEffectState* state); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_ReleaseCallback)(UnityAudioEffectState* state); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_ResetCallback)(UnityAudioEffectState* state); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_ProcessCallback)(UnityAudioEffectState* state, float* inbuffer, float* outbuffer, unsigned int length, int inchannels, int outchannels); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_SetPositionCallback)(UnityAudioEffectState* state, unsigned int pos); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_SetFloatParameterCallback)(UnityAudioEffectState* state, int index, float value); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_GetFloatParameterCallback)(UnityAudioEffectState* state, int index, float* value, char *valuestr); typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK * UnityAudioEffect_GetFloatBufferCallback)(UnityAudioEffectState* state, const char* name, float* buffer, int numsamples); enum UnityAudioEffectDefinitionFlags { UnityAudioEffectDefinitionFlags_IsSideChainTarget = 1 << 0, // Does this effect need a side chain buffer and can it be targeted by a Send? }; enum UnityAudioEffectStateFlags { UnityAudioEffectStateFlags_IsPlaying = 1 << 0, // Set when engine is in play mode. Also true while paused. UnityAudioEffectStateFlags_IsPaused = 1 << 1, // Set when engine is paused mode. UnityAudioEffectStateFlags_IsMuted = 1 << 2, // Set when effect is being muted (only available in the editor) UnityAudioEffectStateFlags_IsSideChainTarget = 1 << 3, // Does this effect need a side chain buffer and can it be targeted by a Send? }; struct UnityAudioEffectState { union { struct { UInt32 structsize; // Size of this struct UInt32 samplerate; // System sample rate UInt64 currdsptick; // Pointer to a sample counter marking the start of the current block being processed UInt64 prevdsptick; // Used for determining when DSPs are bypassed and so sidechain info becomes invalid float* sidechainbuffer; // Side-chain buffers to read from void* effectdata; // Internal data for the effect UInt32 flags; // Various flags through which information can be queried from the host void* internal; // Internal data, do not touch! }; unsigned char pad[64]; // This entire structure must be a multiple of 16 bytes (and and instance 16 byte aligned) for PS3 SPU DMA requirements }; #ifdef __cplusplus template inline T* GetEffectData() const { #if !UNITY_SPU // asserts require _exit() to be defined assert(effectdata); assert(internal); #endif return (T*)effectdata; } #endif }; struct UnityAudioParameterDefinition { char name[16]; // Display name on the GUI char unit[16]; // Scientific unit of parameter to be appended after the value in textboxes const char* description; // Description of parameter (displayed in tool tips, automatically generated documentation, etc.) float min; // Minimum value of the parameter float max; // Maximum value of the parameter float defaultval; // Default and initial value of the parameter float displayscale; // Scale factor used only for the display of parameters (i.e. 100 for a percentage value ranging from 0 to 1) float displayexponent; // Exponent for mapping parameters to sliders }; struct UnityAudioEffectDefinition { UInt32 structsize; // Size of this struct UInt32 paramstructsize; // Size of paramdesc fields UInt32 apiversion; // Plugin API version UInt32 pluginversion; // Version of this plugin UInt32 channels; // Number of channels. Effects should set this to 0 and process any number of input/output channels they get in the process callback. Generator elements should specify a >0 value here. UInt32 numparameters; // The number of parameters exposed by this plugin. UInt64 flags; // Various capabilities and requirements of the plugin. char name[32]; // Name used for registration of the effect. This name will also be displayed in the GUI. UnityAudioEffect_CreateCallback create; // The create callback is called when DSP unit is created and can be null. UnityAudioEffect_ReleaseCallback release; // The release callback is called just before the plugin is freed and should free any data associated with this specific instance of the plugin. No further callbacks related to the instance will happen after this function has been called. UnityAudioEffect_ResetCallback reset; // The reset callback is called by the user to bring back the plugin instance into its initial state. Use to avoid clicks or artifacts. UnityAudioEffect_ProcessCallback process; // The processing callback is repeatedly called with a block of input audio to read from and an output block to write to. UnityAudioEffect_SetPositionCallback setposition; // The position callback can be used for implementing seek operations. UnityAudioParameterDefinition* paramdefs; // A pointer to the definitions of the parameters exposed by this plugin. This data pointed to must remain valid for the whole lifetime of the dynamic library (ideally it's static). UnityAudioEffect_SetFloatParameterCallback setfloatparameter; // This is called whenever one of the exposed parameters is changed. UnityAudioEffect_GetFloatParameterCallback getfloatparameter; // This is called to query parameter values. UnityAudioEffect_GetFloatBufferCallback getfloatbuffer; // Get N samples of named buffer. Used for displaying analysis data from the runtime. }; // This function fills in N pointers for the N effects contained in the library and returns N. extern "C" UNITY_AUDIODSP_EXPORT_API int UnityGetAudioEffectDefinitions(UnityAudioEffectDefinition*** descptr); hvcc-0.16.0/hvcc/generators/c2unity/static/source/unity/AudioPluginUtil.cpp0000644000000000000000000001264200000000000023627 0ustar00#include "AudioPluginUtil.h" char* strnew(const char* src) { char* newstr = new char[strlen(src) + 1]; strcpy(newstr, src); return newstr; } void RegisterParameter( UnityAudioEffectDefinition& definition, const char* name, const char* unit, float minval, float maxval, float defaultval, float displayscale, float displayexponent, int enumvalue, const char* description ) { assert(defaultval >= minval); assert(defaultval <= maxval); strcpy_s(definition.paramdefs[enumvalue].name, name); strcpy_s(definition.paramdefs[enumvalue].unit, unit); definition.paramdefs[enumvalue].description = (description != NULL) ? strnew(description) : (name != NULL) ? strnew(name) : NULL; definition.paramdefs[enumvalue].defaultval = defaultval; definition.paramdefs[enumvalue].displayscale = displayscale; definition.paramdefs[enumvalue].displayexponent = displayexponent; definition.paramdefs[enumvalue].min = minval; definition.paramdefs[enumvalue].max = maxval; if (enumvalue >= (int)definition.numparameters) definition.numparameters = enumvalue + 1; } // Helper function to fill default values from the effect definition into the params array -- called by Create callbacks void InitParametersFromDefinitions( InternalEffectDefinitionRegistrationCallback registereffectdefcallback, float* params ) { UnityAudioEffectDefinition definition; memset(&definition, 0, sizeof(definition)); registereffectdefcallback(definition); for (UInt32 n = 0; n < definition.numparameters; n++) { params[n] = definition.paramdefs[n].defaultval; delete[] definition.paramdefs[n].description; } delete[] definition.paramdefs; // assumes that definition.paramdefs was allocated by registereffectdefcallback or is NULL } void DeclareEffect( UnityAudioEffectDefinition& definition, const char* name, UnityAudioEffect_CreateCallback createcallback, UnityAudioEffect_ReleaseCallback releasecallback, UnityAudioEffect_ProcessCallback processcallback, UnityAudioEffect_SetFloatParameterCallback setfloatparametercallback, UnityAudioEffect_GetFloatParameterCallback getfloatparametercallback, UnityAudioEffect_GetFloatBufferCallback getfloatbuffercallback, InternalEffectDefinitionRegistrationCallback registereffectdefcallback ) { memset(&definition, 0, sizeof(definition)); strcpy_s(definition.name, name); definition.structsize = sizeof(UnityAudioEffectDefinition); definition.paramstructsize = sizeof(UnityAudioParameterDefinition); definition.apiversion = UNITY_AUDIO_PLUGIN_API_VERSION; definition.pluginversion = 0x010000; definition.create = createcallback; definition.release = releasecallback; definition.process = processcallback; definition.setfloatparameter = setfloatparametercallback; definition.getfloatparameter = getfloatparametercallback; definition.getfloatbuffer = getfloatbuffercallback; registereffectdefcallback(definition); } #if UNITY_PS3 #define DECLARE_EFFECT(namestr,ns) \ extern char _binary_spu_ ## ns ## _spu_elf_start[]; #include "PluginList.h" #undef DECLARE_EFFECT #endif #define DECLARE_EFFECT(namestr,ns) \ namespace ns \ { \ UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK CreateCallback (UnityAudioEffectState* state); \ UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ReleaseCallback (UnityAudioEffectState* state); \ UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ProcessCallback (UnityAudioEffectState* state, float* inbuffer, float* outbuffer, unsigned int length, int inchannels, int outchannels); \ UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK SetFloatParameterCallback (UnityAudioEffectState* state, int index, float value); \ UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK GetFloatParameterCallback (UnityAudioEffectState* state, int index, float* value, char *valuestr); \ UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK GetFloatBufferCallback (UnityAudioEffectState* state, const char* name, float* buffer, int numsamples); \ int InternalRegisterEffectDefinition(UnityAudioEffectDefinition& definition); \ } #include "PluginList.h" #undef DECLARE_EFFECT #if UNITY_PS3 #define DECLARE_EFFECT(namestr,ns) \ DeclareEffect( \ definition[numeffects++], \ namestr, \ ns::CreateCallback, \ ns::ReleaseCallback, \ (UnityAudioEffect_ProcessCallback)_binary_spu_ ## ns ## _spu_elf_start, \ ns::SetFloatParameterCallback, \ ns::GetFloatParameterCallback, \ ns::GetFloatBufferCallback, \ ns::InternalRegisterEffectDefinition); #else #define DECLARE_EFFECT(namestr,ns) \ DeclareEffect( \ definition[numeffects++], \ namestr, \ ns::CreateCallback, \ ns::ReleaseCallback, \ ns::ProcessCallback, \ ns::SetFloatParameterCallback, \ ns::GetFloatParameterCallback, \ ns::GetFloatBufferCallback, \ ns::InternalRegisterEffectDefinition); #endif extern "C" UNITY_AUDIODSP_EXPORT_API int UnityGetAudioEffectDefinitions(UnityAudioEffectDefinition*** definitionptr) { static UnityAudioEffectDefinition definition[256]; static UnityAudioEffectDefinition* definitionp[256]; static int numeffects = 0; if (numeffects == 0) { #include "PluginList.h" } for (int n = 0; n < numeffects; n++) definitionp[n] = &definition[n]; *definitionptr = definitionp; return numeffects; } hvcc-0.16.0/hvcc/generators/c2unity/static/source/unity/AudioPluginUtil.h0000644000000000000000000000256700000000000023301 0ustar00#pragma once #include "AudioPluginInterface.h" #include #include #include #include #include #if UNITY_WIN # include #else # if UNITY_SPU # include # include "ps3/AudioPluginInterfacePS3.h" # else # include # endif # define strcpy_s strcpy #endif typedef int (*InternalEffectDefinitionRegistrationCallback)(UnityAudioEffectDefinition& desc); void RegisterParameter( UnityAudioEffectDefinition& desc, const char* name, const char* unit, float minval, float maxval, float defaultval, float displayscale, float displayexponent, int enumvalue, const char* description = NULL); void InitParametersFromDefinitions( InternalEffectDefinitionRegistrationCallback registereffectdefcallback, float* params); void DeclareEffect( UnityAudioEffectDefinition& desc, const char* name, UnityAudioEffect_CreateCallback createcallback, UnityAudioEffect_ReleaseCallback releasecallback, UnityAudioEffect_ProcessCallback processcallback, UnityAudioEffect_SetFloatParameterCallback setfloatparametercallback, UnityAudioEffect_GetFloatParameterCallback getfloatparametercallback, UnityAudioEffect_GetFloatBufferCallback getfloatbuffercallback, InternalEffectDefinitionRegistrationCallback registereffectdefcallback); hvcc-0.16.0/hvcc/generators/c2unity/static/xcode/Info.plist0000644000000000000000000000236500000000000020450 0ustar00 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 CFPlugInDynamicRegisterFunction CFPlugInDynamicRegistration NO CFPlugInFactories 00000000-0000-0000-0000-000000000000 MyFactoryFunction CFPlugInTypes 00000000-0000-0000-0000-000000000000 00000000-0000-0000-0000-000000000000 CFPlugInUnloadFunction hvcc-0.16.0/hvcc/generators/c2unity/templates/CMakeLists.txt0000644000000000000000000000373700000000000020651 0ustar00cmake_minimum_required(VERSION 3.29.0) project(Hv_{{name}}) set(TARGET_NAME_LIB ${PROJECT_NAME}_AudioLib) set(TARGET_NAME_PLUGIN ${PROJECT_NAME}_AudioPlugin) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED 17) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_STATIC_LIBRARY_PREFIX "") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/$) set(CMAKE_SHARED_LIBRARY_PREFIX "") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/$) include(FetchContent) FetchContent_Declare( unitysdk DOWNLOAD_EXTRACT_TIMESTAMP OFF URL https://github.com/Unity-Technologies/NativeAudioPlugins/archive/refs/heads/master.zip SOURCE_DIR "${CMAKE_SOURCE_DIR}/vendor/UnityAudioSDK" PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/src/PluginList.h ${CMAKE_SOURCE_DIR}/vendor/UnityAudioSDK/NativeCode ) FetchContent_GetProperties(unitysdk) if (NOT unitysdk_POPULATED) FetchContent_MakeAvailable(unitysdk) endif() add_library( objlib OBJECT ) set_target_properties( objlib PROPERTIES POSITION_INDEPENDENT_CODE True ) target_sources( objlib PRIVATE {%- for file in heavy_src_files %} ${CMAKE_SOURCE_DIR}/include/Heavy/{{file}} {%- endfor %} ) target_include_directories( objlib PRIVATE ${CMAKE_SOURCE_DIR}/include/Heavy ) add_library(${TARGET_NAME_LIB} SHARED $) add_custom_command( TARGET ${TARGET_NAME_LIB} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${CMAKE_SOURCE_DIR}/src/Hv_{{name}}_AudioLib.cs ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/Hv_{{name}}_AudioLib.cs ) add_library(${TARGET_NAME_PLUGIN} SHARED $) target_sources( ${TARGET_NAME_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}/src/{{name}}.cpp ${CMAKE_SOURCE_DIR}/vendor/UnityAudioSDK/NativeCode/AudioPluginUtil.cpp ) target_include_directories( ${TARGET_NAME_PLUGIN} PRIVATE ${CMAKE_SOURCE_DIR}/include/Heavy ${CMAKE_SOURCE_DIR}/vendor/UnityAudioSDK/NativeCode ) hvcc-0.16.0/hvcc/generators/c2unity/templates/src/Hv_{{name}}_AudioLib.cs0000644000000000000000000003602200000000000023325 0ustar00{%- set hasParams = true if in_params | length > 0 -%} {%- set hasEvents = true if events|length > 0 -%} {%- set hasTables = true if tables|length > 0 -%} {{copyright}} using System; using System.Collections.Generic; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Assertions; using AOT; #if UNITY_EDITOR using UnityEditor; [CustomEditor(typeof(Hv_{{name}}_AudioLib))] public class Hv_{{name}}_Editor : Editor { [MenuItem("Heavy/{{name}}")] static void CreateHv_{{name}}() { GameObject target = Selection.activeGameObject; if (target != null) { target.AddComponent(); } } {%- if hasParams or hasEvents or hasTables %} private Hv_{{name}}_AudioLib _dsp; private void OnEnable() { _dsp = target as Hv_{{name}}_AudioLib; } public override void OnInspectorGUI() { bool isEnabled = _dsp.IsInstantiated(); if (!isEnabled) { EditorGUILayout.LabelField("Press Play!", EditorStyles.centeredGreyMiniLabel); } GUILayout.BeginVertical(); {% if hasEvents -%} // EVENTS GUI.enabled = isEnabled; EditorGUILayout.Space(); {%- for k, v in events %} // {{v.display}} if (GUILayout.Button("{{v.display}}")) { _dsp.SendEvent(Hv_{{name}}_AudioLib.Event.{{k|title}}); } {%- endfor %} {%- endif %} {% if hasParams -%} // PARAMETERS GUI.enabled = true; EditorGUILayout.Space(); EditorGUI.indentLevel++; {%- for k, v in in_params %} // {{v.display}} GUILayout.BeginHorizontal(); float {{k}} = _dsp.GetFloatParameter(Hv_{{name}}_AudioLib.Parameter.{{k|title}}); float new{{k|title}} = EditorGUILayout.Slider("{{v.display}}", {{k}}, {{v.attributes.min}}f, {{v.attributes.max}}f); if ({{k}} != new{{k|title}}) { _dsp.SetFloatParameter(Hv_{{name}}_AudioLib.Parameter.{{k|title}}, new{{k|title}}); } GUILayout.EndHorizontal(); {%- endfor %} EditorGUI.indentLevel--; {%- endif %} {% if hasTables -%} // TABLES GUI.enabled = true; EditorGUILayout.Space(); EditorGUI.indentLevel++; {%- for k, v in tables %} // {{v.display}} EditorGUI.BeginChangeCheck(); AudioClip {{k}}Clip = EditorGUILayout.ObjectField("{{v.display}}", _dsp.{{k}}Clip, typeof(AudioClip), false) as AudioClip; if (EditorGUI.EndChangeCheck()) { _dsp.{{k}}Clip = {{k}}Clip; } {%- endfor %} EditorGUI.indentLevel--; {%- endif %} GUILayout.EndVertical(); } {%- endif %} } #endif // UNITY_EDITOR [RequireComponent (typeof (AudioSource))] public class Hv_{{name}}_AudioLib : MonoBehaviour { {% if hasEvents %} // Events are used to trigger bangs in the patch context (thread-safe). // Example usage: /* void Start () { Hv_{{name}}_AudioLib script = GetComponent(); script.SendEvent(Hv_{{name}}_AudioLib.Event.{{events[0][0]|title}}); } */ public enum Event : uint { {%- for k, v in events %} {{k|title}} = {{v.hash}}, {%- endfor %} } {% endif %} {%- if hasParams %} // Parameters are used to send float messages into the patch context (thread-safe). // Example usage: /* void Start () { Hv_{{name}}_AudioLib script = GetComponent(); // Get and set a parameter float {{in_params[0][0]}} = script.GetFloatParameter(Hv_{{name}}_AudioLib.Parameter.{{in_params[0][0]|title}}); script.SetFloatParameter(Hv_{{name}}_AudioLib.Parameter.{{in_params[0][0]|title}}, {{in_params[0][0]}} + 0.1f); } */ public enum Parameter : uint { {%- for k,v in in_params %} {{k|title}} = {{v.hash}}, {%- endfor %} } {% endif %} {%- if hasTables %} // Tables within the patch context can be filled directly with audio content // Example usage: /* public AudioClip clip; void Start () { Hv_{{name}}_AudioLib script = GetComponent(); // copy clip contents into a temporary buffer float[] buffer = new float[clip.samples]; clip.GetData(buffer, 0); // fill a buffer called "channelL" looper.FillTableWithFloatBuffer((uint) Hv_{{name}}_AudioLib.Table.Channell, buffer); // notify a (non-exposed) receiver of the buffer size looper.SendFloatToReceiver("setTableSize-channelL", clip.samples); } */ public enum Table : uint { {%- for k,v in tables %} {{k|title}} = {{v.hash}}, {%- endfor %} } {% endif %} // Delegate method for receiving float messages from the patch context (thread-safe). // Example usage: /* void Start () { Hv_{{name}}_AudioLib script = GetComponent(); script.RegisterSendHook(); script.FloatReceivedCallback += OnFloatMessage; } void OnFloatMessage(Hv_{{name}}_AudioLib.FloatMessage message) { Debug.Log(message.receiverName + ": " + message.value); } */ public class FloatMessage { public string receiverName; public float value; public FloatMessage(string name, float x) { receiverName = name; value = x; } } public delegate void FloatMessageReceived(FloatMessage message); public FloatMessageReceived FloatReceivedCallback; {%- for k, v in in_params %} public float {{k}} = {{v.attributes.default}}f; {%- endfor %} {%- for k, v in tables %} public AudioClip {{k}}Clip = null; {%- endfor %} // internal state private Hv_{{name}}_Context _context; public bool IsInstantiated() { return (_context != null); } public void RegisterSendHook() { _context.RegisterSendHook(); } {% if hasEvents %} // see Hv_{{name}}_AudioLib.Event for definitions public void SendEvent(Hv_{{name}}_AudioLib.Event e) { if (IsInstantiated()) _context.SendBangToReceiver((uint) e); } {% endif %} {%- if hasParams %} // see Hv_{{name}}_AudioLib.Parameter for definitions public float GetFloatParameter(Hv_{{name}}_AudioLib.Parameter param) { switch (param) { {%- for k, v in in_params %} case Parameter.{{k|title}}: return {{k}}; {%- endfor %} default: return 0.0f; } } public void SetFloatParameter(Hv_{{name}}_AudioLib.Parameter param, float x) { switch (param) { {%- for k, v in in_params %} case Parameter.{{k|title}}: { x = Mathf.Clamp(x, {{v.attributes.min}}f, {{v.attributes.max}}f); {{k}} = x; break; } {%- endfor %} default: return; } if (IsInstantiated()) _context.SendFloatToReceiver((uint) param, x); } {% endif %} public void SendFloatToReceiver(string receiverName, float x) { _context.SendFloatToReceiver(StringToHash(receiverName), x); } public void FillTableWithMonoAudioClip(string tableName, AudioClip clip) { if (clip.channels > 1) { Debug.LogWarning("Hv_{{name}}_AudioLib: Only loading first channel of '" + clip.name + "' into table '" + tableName + "'. Multi-channel files are not supported."); } float[] buffer = new float[clip.samples]; // copy only the 1st channel clip.GetData(buffer, 0); _context.FillTableWithFloatBuffer(StringToHash(tableName), buffer); } public void FillTableWithMonoAudioClip(uint tableHash, AudioClip clip) { if (clip.channels > 1) { Debug.LogWarning("Hv_{{name}}_AudioLib: Only loading first channel of '" + clip.name + "' into table '" + tableHash + "'. Multi-channel files are not supported."); } float[] buffer = new float[clip.samples]; // copy only the 1st channel clip.GetData(buffer, 0); _context.FillTableWithFloatBuffer(tableHash, buffer); } public void FillTableWithFloatBuffer(string tableName, float[] buffer) { _context.FillTableWithFloatBuffer(StringToHash(tableName), buffer); } public void FillTableWithFloatBuffer(uint tableHash, float[] buffer) { _context.FillTableWithFloatBuffer(tableHash, buffer); } public uint StringToHash(string str) { return _context.StringToHash(str); } private void Awake() { _context = new Hv_{{name}}_Context((double) AudioSettings.outputSampleRate); {% if hasTables -%} // Note: only copies first channel from audio clips {%- for k, v in tables %} if ({{k}}Clip != null) { // load buffer {{v.display}} int length = {{k}}Clip.samples; float[] buffer = new float[length]; {{k}}Clip.GetData(buffer, 0); _context.FillTableWithFloatBuffer((uint) Hv_{{name}}_AudioLib.Table.{{k|title}}, buffer); _context.SendFloatToReceiver(_context.StringToHash("setTableSize-{{v.display}}"), length); } {%- endfor %} {%- endif %} } {% if hasParams %} private void Start() { {%- for k, v in in_params %} _context.SendFloatToReceiver((uint) Parameter.{{k|title}}, {{k}}); {%- endfor %} } {% endif %} private void Update() { // retreive sent messages if (_context.IsSendHookRegistered()) { Hv_{{name}}_AudioLib.FloatMessage tempMessage; while ((tempMessage = _context.msgQueue.GetNextMessage()) != null) { FloatReceivedCallback(tempMessage); } } } private void OnAudioFilterRead(float[] buffer, int numChannels) { Assert.AreEqual(numChannels, _context.GetNumOutputChannels()); // invalid channel configuration _context.Process(buffer, buffer.Length / numChannels); // process dsp } } class Hv_{{name}}_Context { #if UNITY_IOS && !UNITY_EDITOR private const string _dllName = "__Internal"; #else private const string _dllName = "Hv_{{name}}_AudioLib"; #endif // Thread-safe message queue public class SendMessageQueue { private readonly object _msgQueueSync = new object(); private readonly Queue _msgQueue = new Queue(); public Hv_{{name}}_AudioLib.FloatMessage GetNextMessage() { lock (_msgQueueSync) { return (_msgQueue.Count != 0) ? _msgQueue.Dequeue() : null; } } public void AddMessage(string receiverName, float value) { Hv_{{name}}_AudioLib.FloatMessage msg = new Hv_{{name}}_AudioLib.FloatMessage(receiverName, value); lock (_msgQueueSync) { _msgQueue.Enqueue(msg); } } } public readonly SendMessageQueue msgQueue = new SendMessageQueue(); private readonly GCHandle gch; private readonly IntPtr _context; // handle into unmanaged memory private SendHook _sendHook = null; [DllImport (_dllName)] private static extern IntPtr hv_{{name}}_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb); [DllImport (_dllName)] private static extern int hv_processInlineInterleaved(IntPtr ctx, [In] float[] inBuffer, [Out] float[] outBuffer, int numSamples); [DllImport (_dllName)] private static extern void hv_delete(IntPtr ctx); [DllImport (_dllName)] private static extern double hv_getSampleRate(IntPtr ctx); [DllImport (_dllName)] private static extern int hv_getNumInputChannels(IntPtr ctx); [DllImport (_dllName)] private static extern int hv_getNumOutputChannels(IntPtr ctx); [DllImport (_dllName)] private static extern void hv_setSendHook(IntPtr ctx, SendHook sendHook); [DllImport (_dllName)] private static extern void hv_setPrintHook(IntPtr ctx, PrintHook printHook); [DllImport (_dllName)] private static extern int hv_setUserData(IntPtr ctx, IntPtr userData); [DllImport (_dllName)] private static extern IntPtr hv_getUserData(IntPtr ctx); [DllImport (_dllName)] private static extern void hv_sendBangToReceiver(IntPtr ctx, uint receiverHash); [DllImport (_dllName)] private static extern void hv_sendFloatToReceiver(IntPtr ctx, uint receiverHash, float x); [DllImport (_dllName)] private static extern uint hv_msg_getTimestamp(IntPtr message); [DllImport (_dllName)] private static extern bool hv_msg_hasFormat(IntPtr message, string format); [DllImport (_dllName)] private static extern float hv_msg_getFloat(IntPtr message, int index); [DllImport (_dllName)] private static extern bool hv_table_setLength(IntPtr ctx, uint tableHash, uint newSampleLength); [DllImport (_dllName)] private static extern IntPtr hv_table_getBuffer(IntPtr ctx, uint tableHash); [DllImport (_dllName)] private static extern float hv_samplesToMilliseconds(IntPtr ctx, uint numSamples); [DllImport (_dllName)] private static extern uint hv_stringToHash(string s); private delegate void PrintHook(IntPtr context, string printName, string str, IntPtr message); private delegate void SendHook(IntPtr context, string sendName, uint sendHash, IntPtr message); public Hv_{{name}}_Context(double sampleRate, int poolKb={{pool_sizes_kb.internal}}, int inQueueKb={{pool_sizes_kb.inputQueue}}, int outQueueKb={{pool_sizes_kb.outputQueue}}) { gch = GCHandle.Alloc(msgQueue); _context = hv_{{name}}_new_with_options(sampleRate, poolKb, inQueueKb, outQueueKb); hv_setPrintHook(_context, new PrintHook(OnPrint)); hv_setUserData(_context, GCHandle.ToIntPtr(gch)); } ~Hv_{{name}}_Context() { hv_delete(_context); GC.KeepAlive(_context); GC.KeepAlive(_sendHook); gch.Free(); } public void RegisterSendHook() { // Note: send hook functionality only applies to messages containing a single float value if (_sendHook == null) { _sendHook = new SendHook(OnMessageSent); hv_setSendHook(_context, _sendHook); } } public bool IsSendHookRegistered() { return (_sendHook != null); } public double GetSampleRate() { return hv_getSampleRate(_context); } public int GetNumInputChannels() { return hv_getNumInputChannels(_context); } public int GetNumOutputChannels() { return hv_getNumOutputChannels(_context); } public void SendBangToReceiver(uint receiverHash) { hv_sendBangToReceiver(_context, receiverHash); } public void SendFloatToReceiver(uint receiverHash, float x) { hv_sendFloatToReceiver(_context, receiverHash, x); } public void FillTableWithFloatBuffer(uint tableHash, float[] buffer) { if (hv_table_getBuffer(_context, tableHash) != IntPtr.Zero) { hv_table_setLength(_context, tableHash, (uint) buffer.Length); Marshal.Copy(buffer, 0, hv_table_getBuffer(_context, tableHash), buffer.Length); } else { Debug.Log(string.Format("Table '{0}' doesn't exist in the patch context.", tableHash)); } } public uint StringToHash(string s) { return hv_stringToHash(s); } public int Process(float[] buffer, int numFrames) { return hv_processInlineInterleaved(_context, buffer, buffer, numFrames); } [MonoPInvokeCallback(typeof(PrintHook))] private static void OnPrint(IntPtr context, string printName, string str, IntPtr message) { float timeInSecs = hv_samplesToMilliseconds(context, hv_msg_getTimestamp(message)) / 1000.0f; Debug.Log(string.Format("{0} [{1:0.000}]: {2}", printName, timeInSecs, str)); } [MonoPInvokeCallback(typeof(SendHook))] private static void OnMessageSent(IntPtr context, string sendName, uint sendHash, IntPtr message) { if (hv_msg_hasFormat(message, "f")) { SendMessageQueue msgQueue = (SendMessageQueue) GCHandle.FromIntPtr(hv_getUserData(context)).Target; msgQueue.AddMessage(sendName, hv_msg_getFloat(message, 0)); } } } {# force new line #} hvcc-0.16.0/hvcc/generators/c2unity/templates/src/PluginList.h0000644000000000000000000000006400000000000021131 0ustar00DECLARE_EFFECT("{{name}}", Hv_{{name}}_UnityPlugin) hvcc-0.16.0/hvcc/generators/c2unity/templates/src/{{name}}.cpp0000644000000000000000000001010100000000000021263 0ustar00{{copyright}} // http://docs.unity3d.com/500/Documentation/Manual/AudioMixerNativeAudioPlugin.html #include "AudioPluginUtil.h" #include "Heavy_{{name}}.hpp" namespace Hv_{{name}}_UnityPlugin { enum Param { {%- for k, v in in_params %} P_{{k|upper}}, {%- endfor %} P_NUM_HV_PARAMS_ }; struct EffectData { struct Data { float p[{{in_params|length if in_params|length > 0 else 1}}]; HeavyContextInterface *context; } data; }; int InternalRegisterEffectDefinition(UnityAudioEffectDefinition& definition) { int numparams = P_NUM_HV_PARAMS_; definition.paramdefs = new UnityAudioParameterDefinition[numparams]; // channels will be set to 0 if numInputChannels > 0 else it will be set to numOutputChannels definition.channels = {{0 if num_input_channels else num_output_channels}}; {%- for k, v in in_params %} {%- if v.display|length > 15 %} #if HV_WIN // Unity Windows doesn't seem to like parameter names that are longer than 15 chars AudioPluginUtil::RegisterParameter(definition, "{{v.display|cap(15)}}", "", {{v.attributes.min}}f, {{v.attributes.max}}f, {{v.attributes.default}}f, 1.0f, 1.0f, P_{{k|upper}}, "{{v.display}}"); #else AudioPluginUtil::RegisterParameter(definition, "{{v.display}}", "", {{v.attributes.min}}f, {{v.attributes.max}}f, {{v.attributes.default}}f, 1.0f, 1.0f, P_{{k|upper}}, "{{v.display}}"); #endif {%- else %} AudioPluginUtil::RegisterParameter(definition, "{{v.display}}", "", {{v.attributes.min}}f, {{v.attributes.max}}f, {{v.attributes.default}}f, 1.0f, 1.0f, P_{{k|upper}}, "{{v.display}}"); {%- endif %} {%- endfor %} return numparams; } UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK CreateCallback(UnityAudioEffectState* state) { EffectData* effectdata = new EffectData; effectdata->data.context = new Heavy_{{name}}((double) state->samplerate, {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}}); state->effectdata = effectdata; AudioPluginUtil::InitParametersFromDefinitions(InternalRegisterEffectDefinition, effectdata->data.p); return UNITY_AUDIODSP_OK; } UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ReleaseCallback(UnityAudioEffectState* state) { EffectData::Data* data = &state->GetEffectData()->data; delete data->context; delete data; return UNITY_AUDIODSP_OK; } UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK SetFloatParameterCallback( UnityAudioEffectState* state, int index, float value) { EffectData::Data *data = &state->GetEffectData()->data; switch (index) { {%- for k, v in in_params %} case P_{{k|upper}}: data->context->sendFloatToReceiver(Heavy_{{name}}::Parameter::In::{{k|upper}}, value); break; {%- endfor %} default: return UNITY_AUDIODSP_ERR_UNSUPPORTED; } data->p[index] = value; return UNITY_AUDIODSP_OK; } UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK GetFloatParameterCallback( UnityAudioEffectState* state, int index, float* value, char *valuestr) { EffectData::Data* data = &state->GetEffectData()->data; if (index < 0 || index >= P_NUM_HV_PARAMS_) return UNITY_AUDIODSP_ERR_UNSUPPORTED; if (value != NULL) *value = data->p[index]; if (valuestr != NULL) valuestr[0] = 0; return UNITY_AUDIODSP_OK; } int UNITY_AUDIODSP_CALLBACK GetFloatBufferCallback(UnityAudioEffectState* state, const char* name, float* buffer, int numsamples) { return UNITY_AUDIODSP_OK; } UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ProcessCallback( UnityAudioEffectState* state, float* inbuffer, float* outbuffer, unsigned int length, int inchannels, int outchannels) { EffectData::Data* data = &state->GetEffectData()->data; if (state->flags & UnityAudioEffectStateFlags_IsPaused) return UNITY_AUDIODSP_OK; hv_assert(inchannels == data->context->getNumInputChannels()); hv_assert(outchannels == data->context->getNumOutputChannels()); data->context->processInlineInterleaved(inbuffer, outbuffer, length); return UNITY_AUDIODSP_OK; } } hvcc-0.16.0/hvcc/generators/c2wwise/__init__.py0000644000000000000000000000000000000000000016166 0ustar00hvcc-0.16.0/hvcc/generators/c2wwise/c2wwise.py0000644000000000000000000001414100000000000016025 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import shutil import time import jinja2 from typing import Optional from pathlib import Path from ..copyright import copyright_manager from ..filters import filter_plugin_id from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.compiler import Generator, CompilerResp, CompilerNotif, CompilerMsg, ExternInfo from hvcc.types.meta import Meta class c2wwise(Generator): """Generates a plugin wrapper for Audiokinetic's Wwise game audio middleware platform. """ @classmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: Optional[str] = None, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: tick = time.time() in_parameter_list = externs.parameters.inParam out_parameter_list = externs.parameters.outParam event_list = externs.events.inEvent out_event_list = externs.events.outEvent table_list = externs.tables patch_name = patch_name or "heavy" copyright_c = copyright_manager.get_copyright_for_c(copyright) copyright_xml = copyright_manager.get_copyright_for_xml(copyright) templates_dir = Path(Path(__file__).parent, "templates") is_source_plugin = num_input_channels == 0 plugin_type = "Source" if is_source_plugin else "FX" plugin_id = filter_plugin_id(patch_name) out_dir = Path(out_dir, "wwise") if not out_dir.exists(): out_dir.mkdir() env = jinja2.Environment() env.loader = jinja2.FileSystemLoader( encoding="utf-8-sig", searchpath=[templates_dir]) try: channel_config = None if num_output_channels == 0: # Workaround to support patches that don't have any outputs, # e.g. that only ever set RTPCs or post events channel_config = "AK_SPEAKER_SETUP_MONO" elif num_output_channels == 1: channel_config = "AK_SPEAKER_SETUP_MONO" elif num_output_channels == 2: channel_config = "AK_SPEAKER_SETUP_STEREO" elif num_output_channels == 6: channel_config = "AK_SPEAKER_SETUP_5POINT1" elif num_output_channels == 8: channel_config = "AK_SPEAKER_SETUP_7POINT1" elif num_output_channels == 12: channel_config = "AK_SPEAKER_SETUP_DOLBY_7_1_4" else: raise Exception("Wwise plugins support only mono, stereo, 5.1, 7.1, " "and 7.1.4 (Atmos) configurations, number of [dac~] channels should be appropriate") if plugin_type == "FX": if num_input_channels != num_output_channels: raise Exception("Wwise FX plugins require the same input/output channel" "configuration (i.e. [adc~ 1] -> [dac~ 1]).") patch_src_dir = Path(out_dir, "SoundEnginePlugin", "Heavy") if patch_src_dir.exists(): shutil.rmtree(patch_src_dir) shutil.copytree(c_src_dir, patch_src_dir) src_ext_list = ["h", "hpp", "c", "cpp", "xml", "def", "rc", "lua", "json"] for f in env.list_templates(extensions=src_ext_list): file = Path(f) file_dir = Path(out_dir, file.parent) file_name = file.name.replace("{{name}}", patch_name) file_name = file_name.replace("{{plugin_type}}", plugin_type) file_path = Path(file_dir, file_name) if not file_path.parent.exists(): file_path.parent.mkdir(parents=True) with open(file_path, "w") as g: g.write(env.get_template(f).render( name=patch_name, parameters=in_parameter_list, out_params=out_parameter_list, out_events=out_event_list, events=event_list, tables=table_list, pool_sizes_kb=externs.memoryPoolSizesKb, is_source=is_source_plugin, num_input_channels=num_input_channels, num_output_channels=num_output_channels, channel_config=channel_config, plugin_type=plugin_type, plugin_id=plugin_id, copyright=copyright_xml if file_name.endswith(".xml") else copyright_c)) return CompilerResp( stage="c2wwise", in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) except Exception as e: return CompilerResp( stage="c2wwise", notifs=CompilerNotif( has_error=True, exception=e, warnings=[], errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), in_dir=c_src_dir, out_dir=out_dir, compile_time=time.time() - tick ) hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/AudioDecoder.h0000644000000000000000000000557300000000000024550 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef AUDIO_DECODER_H #define AUDIO_DECODER_H #include "Common.h" #include #include #include #include namespace nqr { struct UnsupportedExtensionEx : public std::runtime_error { UnsupportedExtensionEx() : std::runtime_error("Unsupported file extension") {} }; struct LoadPathNotImplEx : public std::runtime_error { LoadPathNotImplEx() : std::runtime_error("Loading from path not implemented") {} }; struct LoadBufferNotImplEx : public std::runtime_error { LoadBufferNotImplEx() : std::runtime_error("Loading from buffer not implemented") {} }; struct BaseDecoder { virtual void LoadFromPath(nqr::AudioData * data, const std::string & path) = 0; virtual void LoadFromBuffer(nqr::AudioData * data, const std::vector & memory) = 0; virtual std::vector GetSupportedFileExtensions() = 0; }; typedef std::pair> DecoderPair; class NyquistIO { public: NyquistIO(); ~NyquistIO(); void Load(AudioData * data, const std::string & path); void Load(AudioData *data, std::string extension, const std::vector & buffer); bool IsFileSupported(const std::string path) const; private: std::string ParsePathForExtension(const std::string & path) const; std::shared_ptr GetDecoderForExtension(const std::string ext); void BuildDecoderTable(); void AddDecoderToTable(std::shared_ptr decoder); std::map> decoderTable; NO_MOVE(NyquistIO); }; } // end namespace nqr #endifhvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/Common.h0000644000000000000000000002036000000000000023440 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LIBNYQUIST_COMMON_H #define LIBNYQUIST_COMMON_H #include #include #include #include #include #include #include #include #include #include #include #include "PostProcess.h" #include "Dither.h" namespace nqr { ///////////////// // Util Macros // ///////////////// #define F_ROUND(x) ((x) > 0 ? (x) + 0.5f : (x) - 0.5f) #define D_ROUND(x) ((x) > 0 ? (x) + 0.5 : (x) - 0.5) #define NO_COPY(C) C(const C &) = delete; C & operator = (const C &) = delete #define NO_MOVE(C) NO_COPY(C); C(C &&) = delete; C & operator = (const C &&) = delete /////////////////////// // Endian Operations // /////////////////////// #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) #define CPU_X86 1 #endif #if defined(__arm__) || defined(_M_ARM) #define CPU_ARM 1 #endif #if defined(CPU_X86) && defined(CPU_ARM) #error CPU_X86 and CPU_ARM both defined. #endif #if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN) #if CPU_X86 || CPU_ARM || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #define ARCH_CPU_LITTLE_ENDIAN #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define ARCH_CPU_BIG_ENDIAN #else #error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined. #endif #endif #if defined(ARCH_CPU_BIG_ENDIAN) && defined(ARCH_CPU_LITTLE_ENDIAN) #error ARCH_CPU_BIG_ENDIAN and ARCH_CPU_LITTLE_ENDIAN both defined. #endif static inline uint16_t Swap16(uint16_t value) { return (uint16_t)((value >> 8) | (value << 8)); } static inline uint32_t Swap24(uint32_t value) { return (((value & 0x00ff0000) >> 16) | ((value & 0x0000ff00)) | ((value & 0x000000ff) << 16)) & 0x00FFFFFF; } static inline uint32_t Swap32(uint32_t value) { return (((value & 0x000000ff) << 24) | ((value & 0x0000ff00) << 8) | ((value & 0x00ff0000) >> 8) | ((value & 0xff000000) >> 24)); } static inline uint64_t Swap64(uint64_t value) { return (((value & 0x00000000000000ffLL) << 56) | ((value & 0x000000000000ff00LL) << 40) | ((value & 0x0000000000ff0000LL) << 24) | ((value & 0x00000000ff000000LL) << 8) | ((value & 0x000000ff00000000LL) >> 8) | ((value & 0x0000ff0000000000LL) >> 24) | ((value & 0x00ff000000000000LL) >> 40) | ((value & 0xff00000000000000LL) >> 56)); } template inline bool isOdd(const T x) { return (x & 0x1); } #ifdef ARCH_CPU_LITTLE_ENDIAN #define Read16(n) (n) #define Read24(n) (n) #define Read32(n) (n) #define Read64(n) (n) #define Write16(n) (n) #define Write24(n) (n) #define Write32(n) (n) #define Write64(n) (n) #else #define Read16(n) Swap16(n) #define Read24(n) Swap24(n) #define Read32(n) Swap32(n) #define Read64(n) Swap64(n) #define Write16(n) Swap16(n) #define Write24(n) Swap24(n) #define Write32(n) Swap32(n) #define Write64(n) Swap64(n) #endif inline uint64_t Pack(uint32_t a, uint32_t b) { uint64_t tmp = (uint64_t) b << 32 | (uint64_t) a; #ifdef ARCH_CPU_LITTLE_ENDIAN return tmp; #else return Swap64(tmp); #endif } inline uint32_t Pack(uint16_t a, uint16_t b) { uint32_t tmp = (uint32_t) b << 16 | (uint32_t) a; #ifdef ARCH_CPU_LITTLE_ENDIAN return tmp; #else return Swap32(tmp); #endif } inline uint16_t Pack(uint8_t a, uint8_t b) { uint16_t tmp = (uint16_t) b << 8 | (uint16_t) a; #ifdef ARCH_CPU_LITTLE_ENDIAN return tmp; #else return Swap16(tmp); #endif } // http://www.dsprelated.com/showthread/comp.dsp/136689-1.php inline int32_t Pack(uint8_t a, uint8_t b, uint8_t c) { // uint32_t tmp = ((c & 0x80) ? (0xFF << 24) : 0x00 << 24) | (c << 16) | (b << 8) | (a << 0); // alternate method int32_t x = (c << 16) | (b << 8) | (a << 0); auto sign_extended = (x) | (!!((x) & 0x800000) * 0xff000000); #ifdef ARCH_CPU_LITTLE_ENDIAN return sign_extended; #else Swap32(sign_extended); #endif } inline std::array Unpack(uint32_t a) { static std::array output; #ifdef ARCH_CPU_LITTLE_ENDIAN output[0] = a >> 0; output[1] = a >> 8; output[2] = a >> 16; #else output[0] = a >> 16; output[1] = a >> 8; output[2] = a >> 0; #endif return output; } ////////////////////////// // Conversion Utilities // ////////////////////////// // Signed maxes, defined for readabilty/convenience #define NQR_INT16_MAX 32767.f #define NQR_INT24_MAX 8388608.f #define NQR_INT32_MAX 2147483648.f static const float NQR_BYTE_2_FLT = 1.0f / 127.0f; #define int8_to_float32(s) ((float) (s) * NQR_BYTE_2_FLT) #define uint8_to_float32(s)(((float) (s) - 128) * NQR_BYTE_2_FLT) #define int16_to_float32(s) ((float) (s) / NQR_INT16_MAX) #define int24_to_float32(s) ((float) (s) / NQR_INT24_MAX) #define int32_to_float32(s) ((float) (s) / NQR_INT32_MAX) #define float32_to_int8(s) (float) (s * 127.f) #define float32_to_uint8(s) (float) ((s * 127.f) + 128) #define float32_to_int16(s) (float) (s * NQR_INT16_MAX) #define float32_to_int24(s) (float) (s * NQR_INT24_MAX) #define float32_to_int32(s) (float) (s * NQR_INT32_MAX) //@todo add 12, 20 for flac enum PCMFormat { PCM_U8, PCM_S8, PCM_16, PCM_24, PCM_32, PCM_64, PCM_FLT, PCM_DBL, PCM_END }; template T clamp(T a, T mn, T mx) { return std::max(std::min(a, mx), mn); } // Src data is aligned to PCMFormat // @todo normalize? void ConvertToFloat32(float * dst, const uint8_t * src, const size_t N, PCMFormat f); // Src data is always aligned to 4 bytes (WavPack, primarily) void ConvertToFloat32(float * dst, const int32_t * src, const size_t N, PCMFormat f); // Src data is always aligned to 2 bytes (IMA ADPCM, primarily) void ConvertToFloat32(float * dst, const int16_t * src, const size_t N, PCMFormat f); void ConvertFromFloat32(uint8_t * dst, const float * src, const size_t N, PCMFormat f, DitherType t = DITHER_NONE); ////////////////////////// // User Data + File Ops // ////////////////////////// struct AudioData { int channelCount; int sampleRate; double lengthSeconds; size_t frameSize; // channels * bits per sample std::vector samples; PCMFormat sourceFormat; //@todo: add field: channel layout //@todo: add field: lossy / lossless //@todo: audio data loaded (for metadata only) //@todo: bitrate (if applicable) //@todo: original sample rate (if applicable) }; struct StreamableAudioData : public AudioData { //@todo: add field: is this format streamable? //@todo: hold file handle }; struct NyquistFileBuffer { std::vector buffer; size_t size; }; NyquistFileBuffer ReadFile(std::string pathToFile); int GetFormatBitsPerSample(PCMFormat f); PCMFormat MakeFormatForBits(int bits, bool floatingPt, bool isSigned); } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/Dither.h0000644000000000000000000000371200000000000023431 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef DITHER_OPERATIONS_H #define DITHER_OPERATIONS_H #include namespace nqr { enum DitherType { DITHER_NONE, DITHER_TRIANGLE }; class Dither { std::uniform_real_distribution distribution; std::mt19937 rndGen; float prev = 0.0f; DitherType d; public: Dither(DitherType d) : distribution(-0.5f, +0.5f), d(d) {} float operator()(float s) { if (d == DITHER_TRIANGLE) { const float value = distribution(rndGen); s = s + value - prev; prev = value; return s; } else { return s; } } }; } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/IMA4Util.h0000644000000000000000000001163300000000000023543 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef IMA4_UTIL_H #define IMA4_UTIL_H #include "AudioDecoder.h" namespace nqr { struct ADPCMState { int frame_size; int firstDataBlockByte; int dataSize; int currentByte; const uint8_t * inBuffer; }; static const int ima_index_table[16] = { -1, -1, -1, -1, // +0 / +3 : - the step 2, 4, 6, 8, // +4 / +7 : + the step -1, -1, -1, -1, // -0 / -3 : - the step 2, 4, 6, 8, // -4 / -7 : + the step }; static inline int ima_clamp_index(int index) { if (index < 0) return 0; else if (index > 88) return 88; return index; } static inline int16_t ima_clamp_predict(int16_t predict) { if (predict < -32768) return -32768; else if (predict > 32767) return 32767; return predict; } static const int ima_step_table[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; // Decodes an IMA ADPCM nibble to a 16 bit pcm sample static inline int16_t decode_nibble(uint8_t nibble, int16_t & p, int & s) { // Compute a delta to add to the predictor value int diff = ima_step_table[s] >> 3; if (nibble & 4) diff += ima_step_table[s]; if (nibble & 2) diff += ima_step_table[s] >> 1; if (nibble & 1) diff += ima_step_table[s] >> 2; // Sign if (nibble & 8) diff = -diff; // Add delta p += diff; s += ima_index_table[nibble]; s = ima_clamp_index(s); return ima_clamp_predict(p); } void decode_ima_adpcm(ADPCMState & state, int16_t * outBuffer, uint32_t num_channels) { const uint8_t * data = state.inBuffer; // Loop over the interleaved channels for (uint32_t ch = 0; ch < num_channels; ch++) { const int byteOffset = ch * 4; // Header Structure: // Byte0: packed low byte of the initial predictor // Byte1: packed high byte of the initial predictor // Byte2: initial step index // Byte3: Reserved empty value int16_t predictor = ((int16_t)data[byteOffset + 1] << 8) | data[byteOffset]; int stepIndex = data[byteOffset + 2]; uint8_t reserved = data[byteOffset + 3]; if (reserved != 0) throw std::runtime_error("adpcm decode error"); int byteIdx = num_channels * 4 + byteOffset; //the byte index of the first data word for this channel int idx = ch; // Decode nibbles of the remaining data while (byteIdx < state.frame_size) { for (int j = 0; j < 4; j++) { outBuffer[idx] = decode_nibble(data[byteIdx] & 0xf, predictor, stepIndex); // low nibble idx += num_channels; outBuffer[idx] = decode_nibble(data[byteIdx] >> 4, predictor, stepIndex); // high nibble idx += num_channels; byteIdx++; } byteIdx += (num_channels - 1) << 2; // Jump to the next data word for the current channel } } } } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/ModplugDecoder.h0000644000000000000000000000343000000000000025104 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MODPLUG_DECODER_H #define MODPLUG_DECODER_H #include "AudioDecoder.h" namespace nqr { struct ModplugDecoder : public nqr::BaseDecoder { ModplugDecoder() {}; virtual ~ModplugDecoder() {}; virtual void LoadFromPath(nqr::AudioData * data, const std::string & path) override; virtual void LoadFromBuffer(nqr::AudioData * data, const std::vector & memory) override; virtual std::vector GetSupportedFileExtensions() override; }; } // end namespace nqr #endifhvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/PostProcess.h0000644000000000000000000000570700000000000024504 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef POSTPROCESS_H #define POSTPROCESS_H #include namespace nqr { template inline void DeinterleaveStereo(T * c1, T * c2, T const * src, size_t count) { auto src_end = src + count; while (src != src_end) { *c1 = src[0]; *c2 = src[1]; c1++; c2++; src += 2; } } template void InterleaveChannels(const T * src, T * dest, size_t numFramesPerChannel, size_t numChannels, size_t N) { for (size_t ch = 0; ch < numChannels; ch++) { size_t x = ch; const T * srcChannel = &src[ch * numFramesPerChannel]; for(size_t i = 0; i < N; i++) { dest[x] = srcChannel[i]; x += numChannels; } } } template void DeinterleaveChannels(const T * src, T * dest, size_t numFramesPerChannel, size_t numChannels, size_t N) { for(size_t ch = 0; ch < numChannels; ch++) { size_t x = ch; T *destChannel = &dest[ch * numFramesPerChannel]; for (size_t i = 0; i < N; i++) { destChannel[i] = (T) src[x]; x += numChannels; } } } template void StereoToMono(const T * src, T * dest, size_t N) { for (size_t i = 0, j = 0; i < N; i += 2, ++j) { dest[j] = (src[i] + src[i + 1]) / 2.0f; } } template void MonoToStereo(const T * src, T * dest, size_t N) { for(size_t i = 0, j = 0; i < N; ++i, j += 2) { dest[j] = src[i]; dest[j + 1] = src[i]; } } inline void TrimSilenceInterleaved(std::vector & buffer, float v, bool fromFront, bool fromEnd) { //@todo implement me! } } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/RiffUtils.h0000644000000000000000000000502500000000000024120 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef RIFF_UTILS_H #define RIFF_UTILS_H #include "Common.h" #include "WavDecoder.h" #include "Dither.h" namespace nqr { ///////////////////// // Chunk utilities // ///////////////////// struct EncoderParams { int channelCount; PCMFormat targetFormat; DitherType dither; }; struct ChunkHeaderInfo { uint32_t offset; // Byte offset into chunk uint32_t size; // Size of the chunk in bytes }; inline uint32_t GenerateChunkCode(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { #ifdef ARCH_CPU_LITTLE_ENDIAN return ((uint32_t) ((a) | ((b) << 8) | ((c) << 16) | (((uint32_t) (d)) << 24))); #else return ((uint32_t) ((((uint32_t) (a)) << 24) | ((b) << 16) | ((c) << 8) | (d))); #endif } inline char * GenerateChunkCodeChar(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { auto chunk = GenerateChunkCode(a, b, c, d); char * outArr = new char[4]; uint32_t t = 0x000000FF; for(size_t i = 0; i < 4; i++) { outArr[i] = chunk & t; chunk >>= 8; } return outArr; } ChunkHeaderInfo ScanForChunk(const std::vector & fileData, uint32_t chunkMarker); WaveChunkHeader MakeWaveHeader(const EncoderParams param, const int sampleRate); } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/WavDecoder.h0000644000000000000000000001576500000000000024250 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WAVE_DECODER_H #define WAVE_DECODER_H #include "AudioDecoder.h" namespace nqr { enum WaveFormatCode { FORMAT_UNKNOWN = 0x0, // Unknown Wave Format FORMAT_PCM = 0x1, // PCM Format FORMAT_ADPCM = 0x2, // Microsoft ADPCM Format FORMAT_IEEE = 0x3, // IEEE float/double FORMAT_ALAW = 0x6, // 8-bit ITU-T G.711 A-law FORMAT_MULAW = 0x7, // 8-bit ITU-T G.711 mu-law FORMAT_IMA_ADPCM = 0x11, // IMA ADPCM Format FORMAT_EXT = 0xFFFE // Set via subformat }; struct RiffChunkHeader { uint32_t id_riff; // Chunk ID: 'RIFF' uint32_t file_size; // Entire file in bytes uint32_t id_wave; // Chunk ID: 'WAVE' }; struct WaveChunkHeader { uint32_t fmt_id; // Chunk ID: 'fmt ' uint32_t chunk_size; // Size in bytes uint16_t format; // Format code uint16_t channel_count; // Num interleaved channels uint32_t sample_rate; // SR uint32_t data_rate; // Data rate uint16_t frame_size; // 1 frame = channels * bits per sample (also known as block align) uint16_t bit_depth; // Bits per sample }; struct BextChunk { uint32_t fmt_id; // Chunk ID: 'bext' uint32_t chunk_size; // Size in bytes uint8_t description[256]; // Description of the sound (ascii) uint8_t origin[32]; // Name of the originator (ascii) uint8_t origin_ref[32]; // Reference of the originator (ascii) uint8_t orgin_date[10]; // yyyy-mm-dd (ascii) uint8_t origin_time[8]; // hh-mm-ss (ascii) uint64_t time_ref; // First sample count since midnight uint32_t version; // Version of the BWF uint8_t uimd[64]; // Byte 0 of SMPTE UMID uint8_t reserved[188]; // 190 bytes, reserved for future use & set to NULL }; struct FactChunk { uint32_t fact_id; // Chunk ID: 'fact' uint32_t chunk_size; // Size in bytes uint32_t sample_length; // number of samples per channel }; struct ExtensibleData { uint16_t size; uint16_t valid_bits_per_sample; uint32_t channel_mask; struct GUID { uint32_t data0; uint16_t data1; uint16_t data2; uint16_t data3; uint8_t data4[6]; }; }; template std::basic_ostream & operator << (std::basic_ostream & a, const WaveChunkHeader & b) { return a << "Format ID:\t\t" << b.fmt_id << "\nChunk Size:\t\t" << b.chunk_size << "\nFormat Code:\t\t" << b.format << "\nChannels:\t\t" << b.channel_count << "\nSample Rate:\t\t" << b.sample_rate << "\nData Rate:\t\t" << b.data_rate << "\nFrame Size:\t\t" << b.frame_size << "\nBit Depth:\t\t" << b.bit_depth << std::endl; } //@todo expose speaker/channel/layout masks in the API: enum SpeakerChannelMask { SPEAKER_FRONT_LEFT = 0x00000001, SPEAKER_FRONT_RIGHT = 0x00000002, SPEAKER_FRONT_CENTER = 0x00000004, SPEAKER_LOW_FREQUENCY = 0x00000008, SPEAKER_BACK_LEFT = 0x00000010, SPEAKER_BACK_RIGHT = 0x00000020, SPEAKER_FRONT_LEFT_OF_CENTER = 0x00000040, SPEAKER_FRONT_RIGHT_OF_CENTER = 0x00000080, SPEAKER_BACK_CENTER = 0x00000100, SPEAKER_SIDE_LEFT = 0x00000200, SPEAKER_SIDE_RIGHT = 0x00000400, SPEAKER_TOP_CENTER = 0x00000800, SPEAKER_TOP_FRONT_LEFT = 0x00001000, SPEAKER_TOP_FRONT_CENTER = 0x00002000, SPEAKER_TOP_FRONT_RIGHT = 0x00004000, SPEAKER_TOP_BACK_LEFT = 0x00008000, SPEAKER_TOP_BACK_CENTER = 0x00010000, SPEAKER_TOP_BACK_RIGHT = 0x00020000, SPEAKER_RESERVED = 0x7FFC0000, SPEAKER_ALL = 0x80000000 }; enum SpeakerLayoutMask { SPEAKER_MONO = (SPEAKER_FRONT_CENTER), SPEAKER_STEREO = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), SPEAKER_2POINT1 = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY), SPEAKER_SURROUND = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER), SPEAKER_QUAD = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT), SPEAKER_4POINT1 = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT), SPEAKER_5POINT1 = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT), SPEAKER_7POINT1 = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER), SPEAKER_5POINT1_SURROUND = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT), SPEAKER_7POINT1_SURROUND = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT), }; //@todo verify mask values inline int ComputeChannelMask(const size_t channels) { switch (channels) { case 1: return SPEAKER_MONO; case 2: return SPEAKER_STEREO; case 3: return SPEAKER_2POINT1; case 4: return SPEAKER_QUAD; case 5: return SPEAKER_4POINT1; case 6: return SPEAKER_5POINT1; default: return -1; } } struct WavDecoder : public nqr::BaseDecoder { WavDecoder() {} virtual ~WavDecoder() {} virtual void LoadFromPath(nqr::AudioData * data, const std::string & path) override; virtual void LoadFromBuffer(nqr::AudioData * data, const std::vector & memory) override; virtual std::vector GetSupportedFileExtensions() override; }; } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/Includes/libnyquist/WavEncoder.h0000644000000000000000000001004100000000000024240 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef WAVE_ENCODER_H #define WAVE_ENCODER_H #include "libnyquist/Common.h" #include "libnyquist/WavDecoder.h" #include "libnyquist/RiffUtils.h" namespace nqr { // This is a naieve implementation of a resampling filter where a lerp is used as a bad low-pass. // It very far from the ideal case and should be used with caution (or not at all) on signals that matter. // It is included here to upsample 44.1k to 48k for the purposes of microphone input => Opus, where the the // nominal frequencies of speech are particularly far from Nyquist. static inline void linear_resample(const double rate, const std::vector & input, std::vector & output, size_t samplesToProcess) { double virtualReadIndex = 0; double a, b, i, sample; uint32_t n = (uint32_t) (samplesToProcess - 1); while (n--) { uint32_t readIndex = static_cast(virtualReadIndex); i = virtualReadIndex - readIndex; a = input[readIndex + 0]; b = input[readIndex + 1]; sample = (1.0 - i) * a + i * b; // linear interpolate output.push_back((float) sample); virtualReadIndex += rate; } } static inline double sample_hermite_4p_3o(double x, double * y) { static double c0, c1, c2, c3; c0 = y[1]; c1 = (1.0/2.0)*(y[2]-y[0]); c2 = (y[0] - (5.0/2.0)*y[1]) + (2.0*y[2] - (1.0/2.0)*y[3]); c3 = (1.0/2.0)*(y[3]-y[0]) + (3.0/2.0)*(y[1]-y[2]); return ((c3*x+c2)*x+c1)*x+c0; } static inline void hermite_resample(const double rate, const std::vector & input, std::vector & output, size_t samplesToProcess) { double virtualReadIndex = 1; double i, sample; uint32_t n = (uint32_t) (samplesToProcess - 1); while (n--) { uint32_t readIndex = static_cast(virtualReadIndex); i = virtualReadIndex - readIndex; double samps[4] = {input[readIndex - 1], input[readIndex], input[readIndex + 1], input[readIndex + 2]}; sample = sample_hermite_4p_3o(i, samps); // cubic hermite interpolate over 4 samples output.push_back((float) sample); virtualReadIndex += rate; } } enum EncoderError { NoError, InsufficientSampleData, FileIOError, UnsupportedSamplerate, UnsupportedChannelConfiguration, UnsupportedBitdepth, UnsupportedChannelMix, BufferTooBig, }; // A simplistic encoder that takes a blob of data, conforms it to the user's // EncoderParams preference, and writes to disk. Be warned, does not support resampling! // @todo support dithering, samplerate conversion, etc. struct WavEncoder { // Assume data adheres to EncoderParams, except for bit depth and fmt static int WriteFile(const EncoderParams p, const AudioData * d, const std::string & path); }; struct OggOpusEncoder { static int WriteFile(const EncoderParams p, const AudioData * d, const std::string & path); }; } // end namespace nqr #endif hvcc-0.16.0/hvcc/generators/c2wwise/templates/PremakePlugin.lua0000644000000000000000000000313100000000000021331 0ustar00if not _AK_PREMAKE then error('You must use the custom Premake5 scripts by adding the following parameter: --scripts="Scripts\\Premake"', 1) end local Plugin = {} Plugin.name = "{{name}}" Plugin.factoryheader = "../SoundEnginePlugin/{{name}}{{plugin_type}}Factory.h" Plugin.sdk = {} Plugin.sdk.static = {} Plugin.sdk.shared = {} Plugin.authoring = {} Plugin.sdk.static.includedirs = {} Plugin.sdk.static.files = { "**.cpp", "**.h", "**.hpp", "**.c", } Plugin.sdk.static.excludes = { "{{name}}{{plugin_type}}Shared.cpp" } Plugin.sdk.static.links = {} Plugin.sdk.static.libsuffix = "{{plugin_type}}" Plugin.sdk.static.libdirs = {} Plugin.sdk.static.defines = {} Plugin.sdk.static.custom = function() filter "system:Windows" systemversion "latest" end Plugin.sdk.shared.includedirs = {} Plugin.sdk.shared.files = { "{{name}}{{plugin_type}}Shared.cpp", "{{name}}{{plugin_type}}Factory.h", } Plugin.sdk.shared.excludes = {} Plugin.sdk.shared.links = {} Plugin.sdk.shared.libdirs = {} Plugin.sdk.shared.defines = {} Plugin.sdk.shared.custom = function() filter "system:Windows" systemversion "latest" end Plugin.authoring.includedirs = { "../Includes", path.join(_AK_SDK_ROOT, "samples/Common/") } Plugin.authoring.files = { "**.cpp", "**.h", "**.hpp", "**.c", "{{name}}.def", "{{name}}.xml", "{{name}}.rc", } Plugin.authoring.excludes = {} Plugin.authoring.links = {} Plugin.authoring.libdirs = {} Plugin.authoring.defines = {} Plugin.authoring.custom = function() filter "system:Windows" systemversion "latest" end return Plugin hvcc-0.16.0/hvcc/generators/c2wwise/templates/SoundEnginePlugin/{{name}}{{plugin_type}}.cpp0000644000000000000000000002603200000000000027331 0ustar00{%- set register_send_hook = out_params|length > 0 or out_events|length > 0 -%} {{copyright}} #include "{{name}}{{plugin_type}}.h" #include "{{name}}{{plugin_type}}Params.h" #include "../{{name}}Config.h" #include "Heavy/Heavy_{{name}}.hpp" #include #include #include namespace {{name}}_Private { typedef struct WavHeader { uint32_t ChunkID; // 0 uint32_t ChunkSize; // 4 uint32_t Format; // 8 uint32_t Subchunk1ID; // 12 uint32_t Subchunk1Size; // 16 uint16_t AudioFormat; // 20 uint16_t NumChannels; // 22 uint32_t SampleRate; // 24 uint32_t ByteRate; // 28 uint16_t BlockAlign; // 32 uint16_t BitsPerSample; // 34 uint32_t Subchunk2ID; // 36 uint32_t Subchunk2Size; // 40 uint32_t Subchunk2Data; // 44 uint32_t Subchunk3ID; // 48 uint32_t Subchunk3Size; // 52 // data -> 56 } WavHeader; void LoadPluginMediaToHeavyTable(AK::IAkPluginContextBase* in_pWwiseCtx, HeavyContextInterface* in_pHeavyCtx, uint32_t in_uMediaIndex, uint32_t in_uTableHash, uint32_t in_uTableSizeReceiverHash) { AkUInt8* pPluginData = NULL; AkUInt32 uPluginDataSize; in_pWwiseCtx->GetPluginMedia(in_uMediaIndex, pPluginData, uPluginDataSize); // retrieve stored plugin data if (pPluginData != NULL) { // determine wav header format WavHeader h; hv_memcpy(&h, pPluginData, sizeof(WavHeader)); uint32_t offsetBytes = 0; const uint32_t dataID = 0x61746164; // 'data' const uint32_t factID = 0x74636166; // 'fact' if (h.Subchunk2ID == dataID) { offsetBytes = 44; } else if (h.Subchunk2ID == factID && h.Subchunk3ID == dataID) { offsetBytes = 56; } uint32_t newSizeBytes = uPluginDataSize - offsetBytes; if (offsetBytes > 0 && newSizeBytes > 0) { // adjust table size const uint32_t numSamples = newSizeBytes * 8 / h.BitsPerSample; in_pHeavyCtx->setLengthForTable(in_uTableHash, numSamples); float* buffer = in_pHeavyCtx->getBufferForTable(in_uTableHash); if (buffer != NULL && newSizeBytes > 0) { // copy contents and notify respective receiver hv_memcpy(buffer, (float*)(pPluginData + offsetBytes), newSizeBytes); in_pHeavyCtx->sendFloatToReceiver(in_uTableSizeReceiverHash, (float)numSamples); } } } } static void SetOutRTPC(AK::IAkPluginContextBase* in_pCtx, const char* in_szRtpcName, const uint32_t& in_uNameLen, const float& in_fValue) { AK::FNVHash32 HashFunc; const uint32_t RtpcID = HashFunc.Compute(in_szRtpcName, sizeof(char) * in_uNameLen); const AkGameObjectID ObjectID = in_pCtx->GetGameObjectInfo()->GetGameObjectID(); in_pCtx->GlobalContext()->SetRTPCValue(RtpcID, in_fValue, ObjectID, 0, AkCurveInterpolation_Linear, false); } {% if out_events|length > 0 %} static void PostOutEvent({{name}}{{plugin_type}}* in_pPlugin, const char* in_szEventName, const uint32_t& in_uNameLen) { AK::FNVHash32 HashFunc; const uint32_t EventID = HashFunc.Compute(in_szEventName, sizeof(char) * in_uNameLen); in_pPlugin->m_EventQueue.Enqueue(EventID); } {% endif %} static void OnHeavyPrint(HeavyContextInterface* in_pHeavyCtx, const char* in_szPrintName, const char* in_szMessage, const HvMessage* in_pHvMessage) { auto* pPlugin = reinterpret_cast<{{name}}{{plugin_type}}*>(in_pHeavyCtx->getUserData()); pPlugin->m_pWwiseCtx->PostMonitorMessage(in_szMessage, AK::Monitor::ErrorLevel::ErrorLevel_Message); } {% if register_send_hook %} static void OnSendMessageCallback(HeavyContextInterface *in_pHeavyCtx, const char *in_szSendName, uint32_t in_uSendHash, const HvMessage *in_pHvMessage) { auto* pPlugin = reinterpret_cast<{{name}}{{plugin_type}}*>(in_pHeavyCtx->getUserData()); if (pPlugin != nullptr && (hv_msg_isFloat(in_pHvMessage, 0) || hv_msg_isBang(in_pHvMessage, 0))) { switch (in_uSendHash) { {%- for k, v in out_params %} case {{v.hash}}: SetOutRTPC(pPlugin->m_pWwiseCtx, "{{k|lower}}", {{k|length}}, hv_msg_getFloat(in_pHvMessage, 0)); break; {%- endfor %} {%- for k, v in out_events %} case {{v.hash}}: PostOutEvent(pPlugin, "{{k|lower}}", {{k|length}}); break; {%- endfor %} default: return; } } } {%- endif %} {% if out_events|length > 0 %} static void OnGlobalCallback(AK::IAkGlobalPluginContext* in_pContext, AkGlobalCallbackLocation in_eLocation, void* in_pCookie) { if (in_eLocation != AkGlobalCallbackLocation_BeginRender) return; auto* pPlugin = reinterpret_cast<{{name}}{{plugin_type}}*>(in_pCookie); if (!pPlugin) return; const AkGameObjectID GameObjectID = pPlugin->m_pWwiseCtx->GetGameObjectInfo()->GetGameObjectID(); uint32_t uEventID = 0; while (pPlugin->m_EventQueue.Dequeue(uEventID)) { in_pContext->PostEventSync(uEventID, GameObjectID); } } {%- endif %} } AK::IAkPlugin* Create{{name}}{{plugin_type}}(AK::IAkPluginMemAlloc* in_pAllocator) { return AK_PLUGIN_NEW(in_pAllocator, {{name}}{{plugin_type}}()); } AK::IAkPluginParam* Create{{name}}{{plugin_type}}Params(AK::IAkPluginMemAlloc* in_pAllocator) { return AK_PLUGIN_NEW(in_pAllocator, {{name}}{{plugin_type}}Params()); } AK_IMPLEMENT_PLUGIN_FACTORY({{name}}{{plugin_type}}, {{"AkPluginTypeSource" if is_source else "AkPluginTypeEffect"}}, {{name}}Config::CompanyID, {{name}}Config::PluginID) {{name}}{{plugin_type}}::{{name}}{{plugin_type}}() : m_pWwiseCtx(nullptr) , m_pHeavyCtx(nullptr) , m_pParams(nullptr) , m_uSampleRate(0) { } AKRESULT {{name}}{{plugin_type}}::Init(AK::IAkPluginMemAlloc* in_pAllocator, ContextType* in_pContext, AK::IAkPluginParam* in_pParams, AkAudioFormat& in_rFormat) { using namespace {{name}}_Private; m_pParams = ({{name}}{{plugin_type}}Params*)in_pParams; m_pWwiseCtx = in_pContext; m_uSampleRate = in_rFormat.uSampleRate; // Initialise Heavy context m_pHeavyCtx = AK_PLUGIN_NEW(in_pAllocator, Heavy_{{name}}((double) m_uSampleRate, {{pool_sizes_kb.internal}}, {{pool_sizes_kb.inputQueue}}, {{pool_sizes_kb.outputQueue}})); m_pHeavyCtx->setUserData(this); {%- if register_send_hook %} m_pHeavyCtx->setSendHook(&OnSendMessageCallback); {% endif %} #ifndef AK_OPTIMIZED m_pHeavyCtx->setPrintHook(&OnHeavyPrint); #endif {% if is_source %} // Notify pipeline of chosen output format change. in_rFormat.channelConfig.SetStandard({{channel_config}}); {% if num_output_channels > 0 %} if (in_rFormat.GetNumChannels() != hv_getNumOutputChannels(m_pHeavyCtx)) { return AK_UnsupportedChannelConfig; } {% endif %} {% else %} {% if num_output_channels > 2 %} // Multi-channel plugins have string channel configuration requirementkk if (in_rFormat.channelConfig.uChannelMask != {{channel_config}}) { m_pWwiseCtx->PostMonitorMessage("{{name}} only supports the following channel configuration {{channel_config}}", AK::Monitor::ErrorLevel_Error); return AK_UnsupportedChannelConfig; } {% else %} if (in_rFormat.GetNumChannels() > 2) { m_pWwiseCtx->PostMonitorMessage("{{name}} only supports one and two channel bus configurations", AK::Monitor::ErrorLevel_Error); return AK_UnsupportedChannelConfig; } {% endif %} {% endif %} {%- for k, v in parameters %} hv_sendFloatToReceiver(m_pHeavyCtx, Heavy_{{name}}::Parameter::In::{{k|upper}}, m_pParams->RTPC.{{k}}); {%- endfor %} {% if out_events|length > 0 %} m_EventQueue.Init(4); m_pWwiseCtx->GlobalContext()->RegisterGlobalCallback( {{"AkPluginTypeSource" if is_source else "AkPluginTypeEffect"}}, {{name}}Config::CompanyID, {{name}}Config::PluginID, &OnGlobalCallback, AkGlobalCallbackLocation_BeginRender, this); {%- endif %} {% if tables|length > 0 %} // Initialise tables with media {%- for k, v in tables %} LoadPluginMediaToHeavyTable(m_pWwiseCtx, m_pHeavyCtx, {{loop.index-1}}, {{v.hash}}, hv_stringToHash("setTableSize-{{v.display}}")); // table '{{v.display}}' {%- endfor %} {% endif %} return AK_Success; } AKRESULT {{name}}{{plugin_type}}::Term(AK::IAkPluginMemAlloc* in_pAllocator) { using namespace {{name}}_Private; {% if out_events|length > 0 %} uint32_t EventID = 0; while (m_EventQueue.Dequeue(EventID)) { // the queue must be empty before termination } m_EventQueue.Term(); m_pWwiseCtx->GlobalContext()->UnregisterGlobalCallback(OnGlobalCallback, AkGlobalCallbackLocation_BeginRender); {% endif %} AK_PLUGIN_DELETE(in_pAllocator, m_pHeavyCtx); AK_PLUGIN_DELETE(in_pAllocator, this); return AK_Success; } AKRESULT {{name}}{{plugin_type}}::Reset() { return AK_Success; } AKRESULT {{name}}{{plugin_type}}::GetPluginInfo(AkPluginInfo& out_rPluginInfo) { out_rPluginInfo.eType = {{"AkPluginTypeSource" if is_source else "AkPluginTypeEffect"}}; out_rPluginInfo.bIsInPlace = true; out_rPluginInfo.bCanProcessObjects = false; out_rPluginInfo.uBuildVersion = AK_WWISESDK_VERSION_COMBINED; return AK_Success; } void {{name}}{{plugin_type}}::Execute(AkAudioBuffer* io_pBuffer) { // Retrieve RTPC values and send in as a message to context {%- for k, v in parameters %} if (m_pParams->m_paramChangeHandler.HasChanged({{loop.index-1}})) { hv_sendFloatToReceiver(m_pHeavyCtx, Heavy_{{name}}::Parameter::In::{{k|upper}}, m_pParams->RTPC.{{k}}); m_pParams->m_paramChangeHandler.ResetParamChange({{loop.index-1}}); } {%- endfor %} {% if not is_source %} // zero-pad the rest of the buffer in case the numFrames is not a multiple of 4 io_pBuffer->ZeroPadToMaxFrames(); {%- endif %} // Calculate num frames to process and retrieve buffer AkUInt16 numFramesToProcess = io_pBuffer->MaxFrames(); float *pBuffer = (float *) io_pBuffer->GetChannel(0); {% if is_source %} m_pHeavyCtx->processInline(nullptr, pBuffer, numFramesToProcess); io_pBuffer->eState = AK_DataReady; {% else %} // Check for channel configuration mismatch if (io_pBuffer->NumChannels() == 1 && ((m_pHeavyCtx->getNumInputChannels() == 2) || (m_pHeavyCtx->getNumOutputChannels() == 2))) { float *pTempBuffer[2] = { pBuffer, pBuffer }; m_pHeavyCtx->process(pTempBuffer, pTempBuffer, numFramesToProcess); } else { m_pHeavyCtx->processInline(pBuffer, pBuffer, numFramesToProcess); } {% endif %} {% if num_output_channels > 0 %} io_pBuffer->uValidFrames = numFramesToProcess; {% else %} // Edge case - a control-only plugin was built, outputting silence io_pBuffer->ZeroPadToMaxFrames(); {% endif %} } hvcc-0.16.0/hvcc/generators/c2wwise/templates/SoundEnginePlugin/{{name}}{{plugin_type}}.h0000644000000000000000000000421400000000000026774 0ustar00{{copyright}} #ifndef {{name}}{{plugin_type}}_H #define {{name}}{{plugin_type}}_H #include {%- if out_events|length > 0 %} #include {%- endif %} class HeavyContextInterface; struct {{name}}{{plugin_type}}Params; class {{name}}{{plugin_type}} : public {{"AK::IAkSourcePlugin" if is_source else "AK::IAkInPlaceEffectPlugin"}} { public: using ContextType = {{"AK::IAkSourcePluginContext" if is_source else "AK::IAkEffectPluginContext"}}; {% if out_events|length > 0 %} // Note(ech): AkFifoQueue requires an allocator from AkMemoryMgr at compile time which we don't link against // We need a queue implementation that can inject AK::IAkPluginMemAlloc at runtime to avoid using default OS allocator struct SysAlloc { static AkForceInline void* Alloc(size_t in_uSize) { return malloc(in_uSize); } static AkForceInline void Free(void* in_pAddress) { free(in_pAddress); } }; {%- endif %} {{name}}{{plugin_type}}(); ~{{name}}{{plugin_type}}() = default; AKRESULT Init(AK::IAkPluginMemAlloc* in_pAllocator, ContextType* in_pContext, AK::IAkPluginParam* in_pParams, AkAudioFormat& in_rFormat) override; AKRESULT Term(AK::IAkPluginMemAlloc* in_pAllocator) override; AKRESULT Reset() override; AKRESULT GetPluginInfo(AkPluginInfo& out_rPluginInfo) override; void Execute(AkAudioBuffer* io_pBuffer) override; {%- if is_source %} virtual AkReal32 GetDuration() const override { return 0.f; } virtual AkReal32 GetEnvelope() const override { return 1.f; } virtual AKRESULT StopLooping() override { return AK_Success; } {%- else %} AKRESULT TimeSkip(AkUInt32 in_uFrames) override { return AK_Success; } {%- endif %} {% if out_events|length > 0 %} // Holds event IDs until global callback AkFifoQueue m_EventQueue; {%- endif %} AK::IAkPluginContextBase* m_pWwiseCtx; HeavyContextInterface *m_pHeavyCtx; // Main Heavy patch context {{name}}{{plugin_type}}Params* m_pParams; uint32_t m_uSampleRate; }; #endif // {{name}}{{plugin_type}}_H hvcc-0.16.0/hvcc/generators/c2wwise/templates/SoundEnginePlugin/{{name}}{{plugin_type}}Factory.h0000644000000000000000000000027500000000000030327 0ustar00{{copyright}} #ifndef {{name}}{{plugin_type}}Factory_H #define {{name}}{{plugin_type}}Factory_H AK_STATIC_LINK_PLUGIN({{name}}{{plugin_type}}) #endif // {{name}}{{plugin_type}}Factory_H hvcc-0.16.0/hvcc/generators/c2wwise/templates/SoundEnginePlugin/{{name}}{{plugin_type}}Params.cpp0000644000000000000000000000436400000000000030501 0ustar00{{copyright}} #include "{{name}}{{plugin_type}}Params.h" #include {{name}}{{plugin_type}}Params::{{name}}{{plugin_type}}Params(const {{name}}{{plugin_type}}Params& in_rParams) { {% if parameters|length > 0 %} RTPC = in_rParams.RTPC; m_paramChangeHandler.SetAllParamChanges(); {% endif %} } AK::IAkPluginParam* {{name}}{{plugin_type}}Params::Clone(AK::IAkPluginMemAlloc* in_pAllocator) { return AK_PLUGIN_NEW(in_pAllocator, {{name}}{{plugin_type}}Params(*this)); } AKRESULT {{name}}{{plugin_type}}Params::Init(AK::IAkPluginMemAlloc* in_pAllocator, const void* in_pParamsBlock, AkUInt32 in_ulBlockSize) { if (in_ulBlockSize == 0) { {%- for k, v in parameters %} RTPC.{{k}} = {{v.attributes.default}}; {%- endfor %} {% if parameters|length > 0 %} m_paramChangeHandler.SetAllParamChanges(); {% endif %} return AK_Success; } return SetParamsBlock(in_pParamsBlock, in_ulBlockSize); } AKRESULT {{name}}{{plugin_type}}Params::Term(AK::IAkPluginMemAlloc* in_pAllocator) { AK_PLUGIN_DELETE(in_pAllocator, this); return AK_Success; } AKRESULT {{name}}{{plugin_type}}Params::SetParamsBlock(const void* in_pParamsBlock, AkUInt32 in_ulBlockSize) { AKRESULT eResult = AK_Success; AkUInt8* pParamsBlock = (AkUInt8*)in_pParamsBlock; {%- for k, v in parameters %} RTPC.{{k}} = READBANKDATA(AkReal32, pParamsBlock, in_ulBlockSize); {%- endfor %} CHECKBANKDATASIZE(in_ulBlockSize, eResult); {% if parameters|length > 0 %} m_paramChangeHandler.SetAllParamChanges(); {%- endif %} return eResult; } AKRESULT {{name}}{{plugin_type}}Params::SetParam(AkPluginParamID in_paramID, const void* in_pValue, AkUInt32 in_ulParamSize) { AKRESULT eResult = AK_Success; {% if parameters|length > 0 %} switch (in_paramID) { {%- for k, v in parameters %} case {{loop.index-1}}: { const float fNewValue = *((AkReal32*)in_pValue); const bool bChanged = RTPC.{{k}} != fNewValue; RTPC.{{k}} = fNewValue; if (bChanged) m_paramChangeHandler.SetParamChange({{loop.index-1}}); } break; {%- endfor %} default: eResult = AK_InvalidParameter; break; } {% endif %} return eResult; } hvcc-0.16.0/hvcc/generators/c2wwise/templates/SoundEnginePlugin/{{name}}{{plugin_type}}Params.h0000644000000000000000000000244000000000000030137 0ustar00{{copyright}} {# force new line #} #ifndef {{name}}{{plugin_type}}Params_H #define {{name}}{{plugin_type}}Params_H #include #include {% if parameters|length > 0 %} struct {{name}}RTPCParams { {%- for k, v in parameters %} AkReal32 {{k}} = {{v.attributes.default}}; {%- endfor %} }; {% endif %} struct {{name}}{{plugin_type}}Params : public AK::IAkPluginParam { {{name}}{{plugin_type}}Params() = default; {{name}}{{plugin_type}}Params(const {{name}}{{plugin_type}}Params& in_rParams); ~{{name}}{{plugin_type}}Params() = default; IAkPluginParam* Clone(AK::IAkPluginMemAlloc* in_pAllocator) override; AKRESULT Init(AK::IAkPluginMemAlloc* in_pAllocator, const void* in_pParamsBlock, AkUInt32 in_ulBlockSize) override; AKRESULT Term(AK::IAkPluginMemAlloc* in_pAllocator) override; AKRESULT SetParamsBlock(const void* in_pParamsBlock, AkUInt32 in_ulBlockSize) override; AKRESULT SetParam(AkPluginParamID in_paramID, const void* in_pValue, AkUInt32 in_ulParamSize) override; {% if parameters|length > 0 %} AK::AkFXParameterChangeHandler<{{parameters|length}}> m_paramChangeHandler; {{name}}RTPCParams RTPC; {% endif %} }; #endif // {{name}}{{plugin_type}}Params_H hvcc-0.16.0/hvcc/generators/c2wwise/templates/SoundEnginePlugin/{{name}}{{plugin_type}}Shared.cpp0000644000000000000000000000030400000000000030452 0ustar00{{copyright}} #include #include "{{name}}{{plugin_type}}Factory.h" #include DEFINEDUMMYASSERTHOOK; DEFINE_PLUGIN_REGISTER_HOOK; hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/Win32/stdafx.h0000644000000000000000000000423100000000000022706 0ustar00/** * Copyright (c) 2015 Enzien Audio, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef _HV_WWISE_STDAFX_H_ #define _HV_WWISE_STDAFX_H_ #ifndef VC_EXTRALEAN #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers #endif #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #include // MFC core and standard components #include // MFC extensions #ifndef _AFX_NO_OLE_SUPPORT #include // MFC OLE classes #include // MFC OLE dialog classes #include // MFC Automation classes #endif // _AFX_NO_OLE_SUPPORT #ifndef _AFX_NO_DB_SUPPORT #include // MFC ODBC database classes #endif // _AFX_NO_DB_SUPPORT #ifndef _AFX_NO_DAO_SUPPORT #include // MFC DAO database classes #endif // _AFX_NO_DAO_SUPPORT #include // MFC support for Internet Explorer 4 Common Controls #ifndef _AFX_NO_AFXCMN_SUPPORT #include // MFC support for Windows Common Controls #endif // _AFX_NO_AFXCMN_SUPPORT #include "shlwapi.h" #endif // _HV_WWISE_STDAFX_H_ hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/Win32/{{name}}PluginGUI.cpp0000644000000000000000000001217200000000000025377 0ustar00{{copyright}} #include "{{name}}PluginGUI.h" #include "../resource.h" #include "stdafx.h" using namespace AK::Wwise::Plugin; namespace {{name}}_Private { static bool SaveAudioFileToTableId(ObjectMedia& in_pObjectMedia, const uint32_t& in_uTableId) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); static TCHAR BASED_CODE szFilter[] = _T("Audio Files (*.wav)|*.wav|"); CFileDialog Dialog(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter); if (Dialog.DoModal() == IDOK) { const bool bOk = in_pObjectMedia.SetMediaSource(Dialog.GetPathName(), in_uTableId, true); if (bOk) { in_pObjectMedia.InvalidateMediaSource(in_uTableId); return true; } } return false; }; } {{name}}PluginGUI::{{name}}PluginGUI() : m_hwndPropView(nullptr) , m_hwndObjPane(nullptr) , m_uiBigDialogID(IDD_HV_{{name|upper}}_PLUGIN_BIG) , m_uiSmallDialogID(IDD_HV_{{name|upper}}_PLUGIN_SMALL) {%- if (parameters|length + sends|length + tables|length) > 10 %} , m_iScrollPos(0) {% endif -%} { } bool {{name}}PluginGUI::GetDialog(eDialog in_eDialog, uint32_t& out_uiDialogID, PopulateTableItem*& out_pTable) const { switch (in_eDialog) { case SettingsDialog: out_uiDialogID = m_uiBigDialogID; out_pTable = nullptr; return true; case ContentsEditorDialog: out_uiDialogID = m_uiSmallDialogID; out_pTable = nullptr; return true; } return false; } bool {{name}}PluginGUI::WindowProc(eDialog in_eDialog, HWND in_hWnd, uint32_t in_message, WPARAM in_wParam, LPARAM in_lParam, LRESULT& out_lResult) { using namespace {{name}}_Private; switch (in_message) { case WM_INITDIALOG: { if (in_eDialog == ContentsEditorDialog) { m_hwndObjPane = in_hWnd; } else if (in_eDialog == SettingsDialog) { m_hwndPropView = in_hWnd; {% if (parameters|length + sends|length + tables|length) > 10 -%} RECT rect; if (GetClientRect(in_hWnd, &rect)) { // Create Scrollbar CreateWindowEx(0, L"SCROLLBAR", (PTSTR) NULL, WS_CHILD | WS_VISIBLE | SBS_VERT | SBS_RIGHTALIGN, rect.left, rect.top, rect.right, rect.bottom - GetSystemMetrics(SM_CYVTHUMB), // thumbwidth in_hWnd, (HMENU) NULL, GetResourceHandle(), (PVOID) NULL); SCROLLINFO si = {0}; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nMin = 0; si.nMax = 2500; si.nPage = (rect.bottom - rect.top); si.nPos = 0; si.nTrackPos = 0; SetScrollInfo(in_hWnd, SB_VERT, &si, true); m_iScrollPos = 0; } {%- endif %} } break; } {% if (parameters|length + sends|length + tables|length) > 10 -%} case WM_SIZE: { break; } case WM_VSCROLL: { auto action = LOWORD(in_wParam); HWND hScroll = (HWND) in_lParam; int pos = -1; if (action == SB_THUMBPOSITION || action == SB_THUMBTRACK) { pos = HIWORD(in_wParam); } else if (action == SB_LINEDOWN) { pos = m_iScrollPos + 30; } else if (action == SB_LINEUP) { pos = m_iScrollPos - 30; } if (pos == -1) { break; } SCROLLINFO si = {0}; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; si.nPos = pos; si.nTrackPos = 0; SetScrollInfo(in_hWnd, SB_VERT, &si, true); GetScrollInfo(in_hWnd, SB_VERT, &si); pos = si.nPos; POINT pt; pt.x = 0; pt.y = pos - m_iScrollPos; auto hdc = GetDC(in_hWnd); LPtoDP(hdc, &pt, 1); ReleaseDC(in_hWnd, hdc); ScrollWindow(in_hWnd, 0, -pt.y, NULL, NULL); m_iScrollPos = pos; break; } {%- endif %} case WM_DESTROY: { if (in_eDialog == SettingsDialog) { m_hwndPropView = nullptr; } else if ( in_eDialog == ContentsEditorDialog ) { m_hwndObjPane = nullptr; } break; } // Catch window command actions (regardless if it is object pane or property // view) to enable/disable controls case WM_COMMAND: { {%- if tables|length > 0 %} // catch button clicks switch (HIWORD(in_wParam)) { case BN_CLICKED: { switch (LOWORD(in_wParam)) { {%- for k, v in tables %} case IDC_BUTTON_HV_TABLE_{{k|upper}}: return SaveAudioFileToTableId(m_objectMedia, {{loop.index-1}}); // {{v.display}} {%- endfor %} default: break; } } default: break; } {%- endif %} break; } case WM_ENABLE: { // Enable/Disable all child controls HWND hWnd = ::GetWindow(in_hWnd, GW_CHILD); while(hWnd) { ::EnableWindow(hWnd, in_wParam == TRUE); hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); } return true; } } out_lResult = 0; return false; } ADD_AUDIOPLUGIN_CLASS_TO_CONTAINER( {{name}}, {{name}}PluginGUI, {{name}}{{plugin_type}} ); hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/Win32/{{name}}PluginGUI.h0000644000000000000000000000151400000000000025042 0ustar00{{copyright}} #pragma once #include "../{{name}}Plugin.h" class {{name}}PluginGUI final : public AK::Wwise::Plugin::PluginMFCWindows<> , public AK::Wwise::Plugin::GUIWindows , public AK::Wwise::Plugin::RequestObjectMedia { public: {{name}}PluginGUI(); bool GetDialog(AK::Wwise::Plugin::eDialog in_eDialog, uint32_t& out_uiDialogID, AK::Wwise::Plugin::PopulateTableItem*& out_pTable) const override; bool WindowProc(AK::Wwise::Plugin::eDialog in_eDialog, HWND in_hWnd, uint32_t in_message, WPARAM in_wParam, LPARAM in_lParam, LRESULT& out_lResult ) override; private: HWND m_hwndPropView; HWND m_hwndObjPane; const uint32_t m_uiBigDialogID; const uint32_t m_uiSmallDialogID; {% if (parameters|length + sends|length + tables|length) > 10 -%} int32_t m_iScrollPos; {% endif -%} }; hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/libnyquist/AudioDecoder.cpp0000644000000000000000000001077100000000000025606 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libnyquist/AudioDecoder.h" #include "libnyquist/WavDecoder.h" //#include "WavPackDecoder.h" //#include "FlacDecoder.h" //#include "VorbisDecoder.h" //#include "OpusDecoder.h" //#include "CafDecoder.h" //#include "MusepackDecoder.h" //#include "ModplugDecoder.h" using namespace nqr; NyquistIO::NyquistIO() { BuildDecoderTable(); } NyquistIO::~NyquistIO() { } void NyquistIO::Load(AudioData * data, const std::string & path) { if (IsFileSupported(path)) { if (decoderTable.size()) { auto fileExtension = ParsePathForExtension(path); auto decoder = GetDecoderForExtension(fileExtension); try { decoder->LoadFromPath(data, path); } catch (const std::exception & e) { std::cerr << "Caught internal exception: " << e.what() << std::endl; } } else throw std::runtime_error("No available decoders."); } else { throw UnsupportedExtensionEx(); } } void NyquistIO::Load(AudioData * data, std::string extension, const std::vector & buffer) { if (decoderTable.find(extension) == decoderTable.end()) { throw UnsupportedExtensionEx(); } if (decoderTable.size()) { auto decoder = GetDecoderForExtension(extension); try { decoder->LoadFromBuffer(data, buffer); } catch (const std::exception & e) { std::cerr << "Caught internal exception: " << e.what() << std::endl; } } else { throw std::runtime_error("No available decoders."); } } bool NyquistIO::IsFileSupported(const std::string path) const { auto fileExtension = ParsePathForExtension(path); if (decoderTable.find(fileExtension) == decoderTable.end()) { return false; } else { return true; } } std::string NyquistIO::ParsePathForExtension(const std::string & path) const { if (path.find_last_of(".") != std::string::npos) return path.substr(path.find_last_of(".") + 1); return std::string(""); } std::shared_ptr NyquistIO::GetDecoderForExtension(const std::string ext) { if (decoderTable.size()) { return decoderTable[ext]; } else throw std::runtime_error("No available decoders."); return nullptr; } void NyquistIO::AddDecoderToTable(std::shared_ptr decoder) { auto supportedExtensions = decoder->GetSupportedFileExtensions(); for (const auto ext : supportedExtensions) { if (decoderTable.count(ext) >= 1) throw std::runtime_error("decoder already exists for extension."); decoderTable.insert(DecoderPair(ext, decoder)); } } void NyquistIO::BuildDecoderTable() { AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); //AddDecoderToTable(std::make_shared()); }hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/libnyquist/Common.cpp0000644000000000000000000001626700000000000024515 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libnyquist/Common.h" using namespace nqr; NyquistFileBuffer nqr::ReadFile(std::string pathToFile) { //std::cout << "[Debug] Open: " << pathToFile << std::endl; FILE * audioFile = fopen(pathToFile.c_str(), "rb"); if (!audioFile) { throw std::runtime_error("file not found"); } fseek(audioFile, 0, SEEK_END); size_t lengthInBytes = ftell(audioFile); fseek(audioFile, 0, SEEK_SET); // Allocate temporary buffer std::vector fileBuffer(lengthInBytes); size_t elementsRead = fread(fileBuffer.data(), 1, lengthInBytes, audioFile); if (elementsRead == 0 || fileBuffer.size() < 64) { throw std::runtime_error("error reading file or file too small"); } NyquistFileBuffer data = {std::move(fileBuffer), elementsRead}; fclose(audioFile); // Copy out to user return data; } // Src data is aligned to PCMFormat // @todo normalize? void nqr::ConvertToFloat32(float * dst, const uint8_t * src, const size_t N, PCMFormat f) { assert(f != PCM_END); if (f == PCM_U8) { const uint8_t * dataPtr = reinterpret_cast(src); for (size_t i = 0; i < N; ++i) dst[i] = uint8_to_float32(dataPtr[i]); } else if (f == PCM_S8) { const int8_t * dataPtr = reinterpret_cast(src); for (size_t i = 0; i < N; ++i) dst[i] = int8_to_float32(dataPtr[i]); } else if (f == PCM_16) { const int16_t * dataPtr = reinterpret_cast(src); for (size_t i = 0; i < N; ++i) dst[i] = int16_to_float32(Read16(dataPtr[i])); } else if (f == PCM_24) { const uint8_t * dataPtr = reinterpret_cast(src); size_t c = 0; for (size_t i = 0; i < N; ++i) { int32_t sample = Pack(dataPtr[c], dataPtr[c+1], dataPtr[c+2]); dst[i] = int24_to_float32(sample); // Packed types don't need addtional endian helpers c += 3; } } else if (f == PCM_32) { const int32_t * dataPtr = reinterpret_cast(src); for (size_t i = 0; i < N; ++i) dst[i] = int32_to_float32(Read32(dataPtr[i])); } //@todo add int64 format else if (f == PCM_FLT) { const float * dataPtr = reinterpret_cast(src); for (size_t i = 0; i < N; ++i) dst[i] = (float) Read32(dataPtr[i]); } else if (f == PCM_DBL) { const double * dataPtr = reinterpret_cast(src); for (size_t i = 0; i < N; ++i) dst[i] = (float) Read64(dataPtr[i]); } } // Src data is always aligned to 4 bytes (WavPack, primarily) void nqr::ConvertToFloat32(float * dst, const int32_t * src, const size_t N, PCMFormat f) { assert(f != PCM_END); if (f == PCM_16) { for (size_t i = 0; i < N; ++i) dst[i] = int16_to_float32(Read32(src[i])); } else if (f == PCM_24) { const uint8_t * dataPtr = reinterpret_cast(src); size_t c = 0; for (size_t i = 0; i < N; ++i) { int32_t sample = Pack(dataPtr[c], dataPtr[c+1], dataPtr[c+2]); dst[i] = int24_to_float32(sample); c += 4; // +4 for next 4 byte boundary } } else if (f == PCM_32) { for (size_t i = 0; i < N; ++i) dst[i] = int32_to_float32(Read32(src[i])); } } void nqr::ConvertToFloat32(float * dst, const int16_t * src, const size_t N, PCMFormat f) { assert(f != PCM_END); if (f == PCM_16) { for (size_t i = 0; i < N; ++i) dst[i] = int16_to_float32(Read16(src[i])); } } void nqr::ConvertFromFloat32(uint8_t * dst, const float * src, const size_t N, PCMFormat f, DitherType t) { assert(f != PCM_END); Dither dither(t); if (f == PCM_U8) { uint8_t * destPtr = reinterpret_cast(dst); for (size_t i = 0; i < N; ++i) destPtr[i] = (uint8_t) dither((float) lroundf(float32_to_uint8(src[i]))); } else if (f == PCM_S8) { int8_t * destPtr = reinterpret_cast(dst); for (size_t i = 0; i < N; ++i) destPtr[i] = (int8_t) dither((float) lroundf(float32_to_int8(src[i]))); } else if (f == PCM_16) { int16_t * destPtr = reinterpret_cast(dst); for (size_t i = 0; i < N; ++i) destPtr[i] =(int16_t) dither((float) lroundf(float32_to_int16(src[i]))); } else if (f == PCM_24) { uint8_t * destPtr = reinterpret_cast(dst); size_t c = 0; for (size_t i = 0; i < N; ++i) { int32_t sample = (int32_t) dither((float) lroundf(float32_to_int24(src[i]))); auto unpacked = Unpack(sample); // Handles endian swap destPtr[c] = unpacked[0]; destPtr[c+1] = unpacked[1]; destPtr[c+2] = unpacked[2]; c += 3; } } else if (f == PCM_32) { int32_t * destPtr = reinterpret_cast(dst); for (size_t i = 0; i < N; ++i) destPtr[i] = (int32_t) dither((float) lroundf(float32_to_int32(src[i]))); } } int nqr::GetFormatBitsPerSample(PCMFormat f) { switch(f) { case PCM_U8: case PCM_S8: return 8; case PCM_16: return 16; case PCM_24: return 24; case PCM_32: case PCM_FLT: return 32; case PCM_64: case PCM_DBL: return 64; default: return 0; } } PCMFormat nqr::MakeFormatForBits(int bits, bool floatingPt, bool isSigned) { switch(bits) { case 8: return (isSigned) ? PCM_S8 : PCM_U8; case 16: return PCM_16; case 24: return PCM_24; case 32: return (floatingPt) ? PCM_FLT : PCM_32; case 64: return (floatingPt) ? PCM_DBL : PCM_64; default: return PCM_END; } } hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/libnyquist/RiffUtils.cpp0000644000000000000000000000520300000000000025160 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libnyquist/RiffUtils.h" using namespace nqr; ChunkHeaderInfo nqr::ScanForChunk(const std::vector & fileData, uint32_t chunkMarker) { // D[n] aligned to 16 bytes now const uint16_t * d = reinterpret_cast(fileData.data()); for (size_t i = 0; i < fileData.size() / sizeof(uint16_t); i++) { // This will be in machine endianess uint32_t m = Pack(Read16(d[i]), Read16(d[i+1])); if (m == chunkMarker) { uint32_t cSz = Pack(Read16(d[i+2]), Read16(d[i+3])); return {(uint32_t (i * sizeof(uint16_t))), cSz}; // return i in bytes to the start of the data } else continue; } return {0, 0}; }; WaveChunkHeader nqr::MakeWaveHeader(const EncoderParams param, const int sampleRate) { WaveChunkHeader header; int bitdepth = GetFormatBitsPerSample(param.targetFormat); header.fmt_id = GenerateChunkCode('f', 'm', 't', ' '); header.chunk_size = 16; header.format = (param.targetFormat <= PCMFormat::PCM_32) ? WaveFormatCode::FORMAT_PCM : WaveFormatCode::FORMAT_IEEE; header.channel_count = param.channelCount; header.sample_rate = sampleRate; header.data_rate = sampleRate * param.channelCount * (bitdepth / 8); header.frame_size = param.channelCount * (bitdepth / 8); header.bit_depth = bitdepth; return header; } hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/libnyquist/WavDecoder.cpp0000644000000000000000000002044500000000000025301 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libnyquist/WavDecoder.h" #include "libnyquist/RiffUtils.h" #include "libnyquist/IMA4Util.h" using namespace nqr; ////////////////////// // Public Interface // ////////////////////// void WavDecoder::LoadFromPath(AudioData * data, const std::string & path) { auto fileBuffer = nqr::ReadFile(path); return LoadFromBuffer(data, fileBuffer.buffer); } void WavDecoder::LoadFromBuffer(AudioData * data, const std::vector & memory) { ////////////////////// // Read RIFF Header // ////////////////////// //@todo swap methods for rifx RiffChunkHeader riffHeader = {}; memcpy(&riffHeader, memory.data(), 12); // Files should be 2-byte aligned // @tofix: enforce this // bool usePaddingShort = ((riffHeader.file_size % sizeof(uint16_t)) == 1) ? true : false; // Check RIFF if (riffHeader.id_riff != GenerateChunkCode('R', 'I', 'F', 'F')) { // Check RIFX + FFIR if (riffHeader.id_riff == GenerateChunkCode('R', 'I', 'F', 'X') || riffHeader.id_riff == GenerateChunkCode('F', 'F', 'I', 'R')) { // We're not RIFF, and we don't match RIFX or FFIR either throw std::runtime_error("libnyquist doesn't support big endian files"); } else { throw std::runtime_error("bad RIFF/RIFX/FFIR file header"); } } if (riffHeader.id_wave != GenerateChunkCode('W', 'A', 'V', 'E')) throw std::runtime_error("bad WAVE header"); auto expectedSize = (memory.size() - riffHeader.file_size); if (expectedSize != sizeof(uint32_t) * 2) { throw std::runtime_error("declared size of file less than file size"); //@todo warning instead of runtime_error } ////////////////////// // Read WAVE Header // ////////////////////// auto WaveChunkInfo = ScanForChunk(memory, GenerateChunkCode('f', 'm', 't', ' ')); if (WaveChunkInfo.offset == 0) throw std::runtime_error("couldn't find fmt chunk"); assert(WaveChunkInfo.size == 16 || WaveChunkInfo.size == 18 || WaveChunkInfo.size == 20 || WaveChunkInfo.size == 40); WaveChunkHeader wavHeader = {}; memcpy(&wavHeader, memory.data() + WaveChunkInfo.offset, sizeof(WaveChunkHeader)); if (wavHeader.chunk_size < 16) throw std::runtime_error("format chunk too small"); //@todo validate wav header (sane sample rate, bit depth, etc) data->channelCount = wavHeader.channel_count; data->sampleRate = wavHeader.sample_rate; data->frameSize = wavHeader.frame_size; auto bit_depth = wavHeader.bit_depth; switch (bit_depth) { case 4: data->sourceFormat = PCMFormat::PCM_16; break; // for IMA ADPCM case 8: data->sourceFormat = PCMFormat::PCM_U8; break; case 16: data->sourceFormat = PCMFormat::PCM_16; break; case 24: data->sourceFormat = PCMFormat::PCM_24; break; case 32: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_FLT : PCMFormat::PCM_32; break; case 64: data->sourceFormat = (wavHeader.format == WaveFormatCode::FORMAT_IEEE) ? PCMFormat::PCM_DBL : PCMFormat::PCM_64; break; } //std::cout << wavHeader << std::endl; bool scanForFact = false; bool grabExtensibleData = false; bool adpcmEncoded = false; if (wavHeader.format == WaveFormatCode::FORMAT_PCM) { } else if (wavHeader.format == WaveFormatCode::FORMAT_IEEE) { scanForFact = true; } else if (wavHeader.format == WaveFormatCode::FORMAT_IMA_ADPCM) { adpcmEncoded = true; scanForFact = true; } else if (wavHeader.format == WaveFormatCode::FORMAT_EXT) { // Used when (1) PCM data has more than 16 bits; (2) channels > 2; (3) bits/sample !== container size; (4) channel/speaker mapping specified //std::cout << "[format id] extended" << std::endl; scanForFact = true; grabExtensibleData = true; } else if (wavHeader.format == WaveFormatCode::FORMAT_UNKNOWN) { throw std::runtime_error("unknown wave format"); } //////////////////////////// // Read Additional Chunks // //////////////////////////// FactChunk factChunk; if (scanForFact) { auto FactChunkInfo = ScanForChunk(memory, GenerateChunkCode('f', 'a', 'c', 't')); if (FactChunkInfo.size) memcpy(&factChunk, memory.data() + FactChunkInfo.offset, sizeof(FactChunk)); } if (grabExtensibleData) { ExtensibleData extData = {}; memcpy(&extData, memory.data() + WaveChunkInfo.offset + sizeof(WaveChunkHeader), sizeof(ExtensibleData)); // extData can be compared against the multi-channel masks defined in the header // eg. extData.channel_mask == SPEAKER_5POINT1 } //@todo smpl chunk could be useful ///////////////////// // Read Bext Chunk // ///////////////////// auto BextChunkInfo = ScanForChunk(memory, GenerateChunkCode('b', 'e', 'x', 't')); BextChunk bextChunk = {}; if (BextChunkInfo.size) { memcpy(&bextChunk, memory.data() + BextChunkInfo.offset, sizeof(BextChunk)); } ///////////////////// // Read DATA Chunk // ///////////////////// auto DataChunkInfo = ScanForChunk(memory, GenerateChunkCode('d', 'a', 't', 'a')); if (DataChunkInfo.offset == 0) throw std::runtime_error("couldn't find data chunk"); DataChunkInfo.offset += 2 * sizeof(uint32_t); // ignore the header and size fields if (adpcmEncoded) { ADPCMState s; s.frame_size = wavHeader.frame_size; s.firstDataBlockByte = 0; s.dataSize = DataChunkInfo.size; s.currentByte = 0; s.inBuffer = const_cast(memory.data() + DataChunkInfo.offset); size_t totalSamples = (factChunk.sample_length * wavHeader.channel_count); // Samples per channel times channel count std::vector adpcm_pcm16(totalSamples * 2, 0); // Each frame decodes into twice as many pcm samples uint32_t frameOffset = 0; uint32_t frameCount = DataChunkInfo.size / s.frame_size; for (uint32_t i = 0; i < frameCount; ++i) { decode_ima_adpcm(s, adpcm_pcm16.data() + frameOffset, wavHeader.channel_count); s.inBuffer += s.frame_size; frameOffset += (s.frame_size * 2) - (8 * wavHeader.channel_count); } data->lengthSeconds = ((float) totalSamples / (float) wavHeader.sample_rate) / wavHeader.channel_count; data->samples.resize(totalSamples); ConvertToFloat32(data->samples.data(), adpcm_pcm16.data(), totalSamples, data->sourceFormat); } else { data->lengthSeconds = ((float) DataChunkInfo.size / (float) wavHeader.sample_rate) / wavHeader.frame_size; size_t totalSamples = (DataChunkInfo.size / wavHeader.frame_size) * wavHeader.channel_count; data->samples.resize(totalSamples); ConvertToFloat32(data->samples.data(), memory.data() + DataChunkInfo.offset, totalSamples, data->sourceFormat); } } std::vector WavDecoder::GetSupportedFileExtensions() { return {"wav", "wave"}; } hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/libnyquist/WavEncoder.cpp0000644000000000000000000003420200000000000025307 0ustar00/* Copyright (c) 2015, Dimitri Diakopoulos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "libnyquist/WavEncoder.h" using namespace nqr; static inline void to_bytes(uint8_t value, char * arr) { arr[0] = (value)& 0xFF; } static inline void to_bytes(uint16_t value, char * arr) { arr[0] = (value)& 0xFF; arr[1] = (value >> 8) & 0xFF; } static inline void to_bytes(uint32_t value, char * arr) { arr[0] = (value)& 0xFF; arr[1] = (value >> 8) & 0xFF; arr[2] = (value >> 16) & 0xFF; arr[3] = (value >> 24) & 0xFF; } //////////////////////////// // Wave File Encoding // //////////////////////////// int WavEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std::string & path) { assert(d->samples.size() > 0); // Cast away const because we know what we are doing (Hopefully?) float * sampleData = const_cast(d->samples.data()); size_t sampleDataSize = d->samples.size(); std::vector sampleDataOptionalMix; if (sampleDataSize <= 32) { return EncoderError::InsufficientSampleData; } if (d->channelCount < 1 || d->channelCount > 8) { return EncoderError::UnsupportedChannelConfiguration; } // Handle Channel Mixing -- // Mono => Stereo if (d->channelCount == 1 && p.channelCount == 2) { sampleDataOptionalMix.resize(sampleDataSize * 2); MonoToStereo(sampleData, sampleDataOptionalMix.data(), sampleDataSize); // Mix // Re-point data sampleData = sampleDataOptionalMix.data(); sampleDataSize = sampleDataOptionalMix.size(); } // Stereo => Mono else if (d->channelCount == 2 && p.channelCount == 1) { sampleDataOptionalMix.resize(sampleDataSize / 2); StereoToMono(sampleData, sampleDataOptionalMix.data(), sampleDataSize); // Mix // Re-point data sampleData = sampleDataOptionalMix.data(); sampleDataSize = sampleDataOptionalMix.size(); } else if (d->channelCount == p.channelCount) { // No op } else { return EncoderError::UnsupportedChannelMix; } // -- End Channel Mixing auto maxFileSizeInBytes = std::numeric_limits::max(); auto samplesSizeInBytes = (sampleDataSize * GetFormatBitsPerSample(p.targetFormat)) / 8; // 64 arbitrary if ((samplesSizeInBytes - 64) >= maxFileSizeInBytes) { return EncoderError::BufferTooBig; } // Don't support PC64 or PCDBL if (GetFormatBitsPerSample(p.targetFormat) > 32) { return EncoderError::UnsupportedBitdepth; } std::ofstream fout(path.c_str(), std::ios::out | std::ios::binary); if (!fout.is_open()) { return EncoderError::FileIOError; } char * chunkSizeBuff = new char[4]; // Initial size (this is changed after we're done writing the file) to_bytes(uint32_t(36), chunkSizeBuff); // RIFF file header fout.write(GenerateChunkCodeChar('R', 'I', 'F', 'F'), 4); fout.write(chunkSizeBuff, 4); fout.write(GenerateChunkCodeChar('W', 'A', 'V', 'E'), 4); // Fmt header auto header = MakeWaveHeader(p, d->sampleRate); fout.write(reinterpret_cast(&header), sizeof(WaveChunkHeader)); auto sourceBits = GetFormatBitsPerSample(d->sourceFormat); auto targetBits = GetFormatBitsPerSample(p.targetFormat); //////////////////////////// //@todo - channel mixing! // //////////////////////////// // Write out fact chunk if (p.targetFormat == PCM_FLT) { uint32_t four = 4; uint32_t dataSz = int(sampleDataSize / p.channelCount); fout.write(GenerateChunkCodeChar('f', 'a', 'c', 't'), 4); fout.write(reinterpret_cast(&four), 4); fout.write(reinterpret_cast(&dataSz), 4); // Number of samples (per channel) } // Data header fout.write(GenerateChunkCodeChar('d', 'a', 't', 'a'), 4); // + data chunk size to_bytes(uint32_t(samplesSizeInBytes), chunkSizeBuff); fout.write(chunkSizeBuff, 4); if (targetBits <= sourceBits && p.targetFormat != PCM_FLT) { // At most need this number of bytes in our copy std::vector samplesCopy(samplesSizeInBytes); ConvertFromFloat32(samplesCopy.data(), sampleData, sampleDataSize, p.targetFormat, p.dither); fout.write(reinterpret_cast(samplesCopy.data()), samplesSizeInBytes); } else { // Handle PCFLT. Coming in from AudioData ensures we start with 32 bits, so we're fine // since we've also rejected formats with more than 32 bits above. fout.write(reinterpret_cast(sampleData), samplesSizeInBytes); } // Padding byte if (isOdd(samplesSizeInBytes)) { const char * zero = ""; fout.write(zero, 1); } // Find size long totalSize = (long) fout.tellp(); // Modify RIFF header fout.seekp(4); // Total size of the file, less 8 bytes for the RIFF header to_bytes(uint32_t(totalSize - 8), chunkSizeBuff); fout.write(chunkSizeBuff, 4); delete[] chunkSizeBuff; return EncoderError::NoError; } ////////////////////////////// //// Opus File Encoding // ////////////////////////////// // //#include "opus/opusfile/include/opusfile.h" //#include "ogg/ogg.h" // //typedef std::pair metadata_t; // //class OggWriter //{ // void write_to_ostream(bool flush) // { // while (ogg_stream_pageout(&oss, &page)) // { // ostream->write(reinterpret_cast(page.header), static_cast(page.header_len)); // ostream->write(reinterpret_cast(page.body), static_cast(page.body_len)); // } // if (flush && ogg_stream_flush(&oss, &page)) // { // ostream->write(reinterpret_cast(page.header), static_cast(page.header_len)); // ostream->write(reinterpret_cast(page.body), static_cast(page.body_len)); // } // } // // std::vector make_header(int channel_count, int preskip, long sample_rate, int gain) // { // std::vector header; // // std::array steam_count = { { 0x0, 0x1, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x5 } }; // std::array coupled_streacount = { { 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x3 } }; // // std::array chan_map_1 = { { 0x0 } }; // std::array chan_map_2 = { { 0x0, 0x1 } }; // // std::array _preamble = { { 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd', 0x1 } }; // std::array _channel_count; // std::array _preskip; // std::array _sample_rate; // std::array _gain; // std::array _channel_family = { { 0x1 } }; // // to_bytes(uint8_t(channel_count), _channel_count.data()); // to_bytes(uint16_t(preskip), _preskip.data()); // to_bytes(uint32_t(sample_rate), _sample_rate.data()); // to_bytes(uint16_t(gain), _gain.data()); // // header.insert(header.end(), _preamble.cbegin(), _preamble.cend()); // header.insert(header.end(), _channel_count.cbegin(), _channel_count.cend()); // header.insert(header.end(), _preskip.cbegin(), _preskip.cend()); // header.insert(header.end(), _sample_rate.cbegin(), _sample_rate.cend()); // header.insert(header.end(), _gain.cbegin(), _gain.cend()); // header.insert(header.end(), _channel_family.cbegin(), _channel_family.cend()); // header.push_back(steam_count[channel_count]); // header.push_back(coupled_streacount[channel_count]); // // switch (channel_count) // { // case 1: header.insert(header.end(), chan_map_1.cbegin(), chan_map_1.cend()); break; // case 2: header.insert(header.end(), chan_map_2.cbegin(), chan_map_2.cend()); break; // default: throw std::runtime_error("couldn't map channel data"); // } // // return header; // } // // std::vector make_tags(const std::string & vendor, const std::vector & metadata) // { // std::vector tags; // // std::array _preamble = { { 'O', 'p', 'u', 's', 'T', 'a', 'g', 's' } }; // std::array _vendor_length; // std::array _metadata_count; // // to_bytes(uint32_t(vendor.size()), _vendor_length.data()); // to_bytes(uint32_t(metadata.size()), _metadata_count.data()); // // tags.insert(tags.end(), _preamble.cbegin(), _preamble.cend()); // tags.insert(tags.end(), _vendor_length.cbegin(), _vendor_length.cend()); // tags.insert(tags.end(), vendor.cbegin(), vendor.cend()); // tags.insert(tags.end(), _metadata_count.cbegin(), _metadata_count.cend()); // // // Process metadata. // for (const auto & metadata_entry : metadata) // { // std::array _metadata_entry_length; // std::string entry = metadata_entry.first + "=" + metadata_entry.second; // to_bytes(uint32_t(entry.size()), _metadata_entry_length.data()); // tags.insert(tags.end(), _metadata_entry_length.cbegin(), _metadata_entry_length.cend()); // tags.insert(tags.end(), entry.cbegin(), entry.cend()); // } // // return tags; // } // // ogg_int64_t packet_number; // ogg_int64_t granule; // ogg_page page; // ogg_stream_state oss; // // int channel_count; // long sample_rate; // int bits_per_sample; // std::ofstream * ostream; // std::string description; // std::vector metadata; // //public: // // OggWriter(int channel_count, long sample_rate, int bits_per_sample, std::ofstream & stream, const std::vector & md) // { // this->channel_count = channel_count; // this->sample_rate = sample_rate; // this->bits_per_sample = bits_per_sample; // this->ostream = &stream; // this->metadata = md; // // int oggInitErr, packetErr; // // ogg_packet header_packet; // ogg_packet tags_packet; // std::vector header_vector; // std::vector tags_vector; // // description = "Ogg"; // packet_number = 0; // granule = 0; // // // Validate parameters // if (channel_count < 1 && channel_count > 255) throw std::runtime_error("Channel count must be between 1 and 255."); // // // Initialize the Ogg stream. // oggInitErr = ogg_stream_init(&oss, 12345); // if (oggInitErr) throw std::runtime_error("Could not initialize the Ogg stream state."); // // // Initialize the header packet. // header_vector = make_header(channel_count, 3840, sample_rate, 0); // header_packet.packet = reinterpret_cast(header_vector.data()); // header_packet.bytes = header_vector.size(); // header_packet.b_o_s = 1; // header_packet.e_o_s = 0; // header_packet.granulepos = 0; // header_packet.packetno = packet_number++; // // // Initialize tags // tags_vector = make_tags("libnyquist", metadata); // tags_packet.packet = reinterpret_cast(tags_vector.data()); // tags_packet.bytes = tags_vector.size(); // tags_packet.b_o_s = 0; // tags_packet.e_o_s = 0; // tags_packet.granulepos = 0; // tags_packet.packetno = packet_number++; // // // Write header page // packetErr = ogg_stream_packetin(&oss, &header_packet); // if (packetErr) throw std::runtime_error("Could not write header packet to the Ogg stream."); // write_to_ostream(true); // // // Write tags page // packetErr = ogg_stream_packetin(&oss, &tags_packet); // if (packetErr) throw std::runtime_error("Could not write tags packet to the Ogg stream."); // write_to_ostream(true); // } // // ~OggWriter() // { // write_to_ostream(true); // ogg_stream_clear(&oss); // } // // bool write(char * data, std::streamsize length, size_t sampleCount, bool end) // { // int err; // ogg_packet packet; // // granule += sampleCount; // // packet.packet = reinterpret_cast(data); // packet.bytes = static_cast(length); // packet.b_o_s = 0; // packet.e_o_s = end ? 1 : 0; // packet.granulepos = granule; // packet.packetno = packet_number++; // // err = ogg_stream_packetin(&oss, &packet); // // if (err) throw std::runtime_error("could not write packet to stream"); // // write_to_ostream(false); // // return true; // } // //}; // //#define OPUS_MAX_PACKET_SIZE (1024 * 8) //#define OPUS_FRAME_SIZE 960 // //// Opus only supports a 48k samplerate... M //// This encoder only supports mono for the time being //int OggOpusEncoder::WriteFile(const EncoderParams p, const AudioData * d, const std::string & path) //{ // assert(d->samples.size() > 0); // //assert(d->sampleRate == 48000); // // float * sampleData = const_cast(d->samples.data()); // const size_t sampleDataSize = d->samples.size(); // // int opus_error; // OpusEncoder * enc; // enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &opus_error); // if (!enc) throw std::runtime_error("opus_encoder_create caused an error!"); // // std::ofstream fout(path.c_str(), std::ios::out | std::ios::binary); // // std::vector oggMetadata = { { "artist", "dimitri" } }; // OggWriter writer(d->channelCount, d->sampleRate, GetFormatBitsPerSample(d->sourceFormat), fout, oggMetadata); // // std::vector outBuffer(OPUS_MAX_PACKET_SIZE); // // int framesToEncode = (sampleDataSize / OPUS_FRAME_SIZE) - 1; // fixme // // while (framesToEncode >= 0) // { // auto encoded_size = opus_encode_float(enc, sampleData, OPUS_FRAME_SIZE, outBuffer.data(), OPUS_MAX_PACKET_SIZE); // // if (encoded_size < 0) // { // std::cerr << "Bad Opus Status: " << encoded_size << std::endl; // return EncoderError::FileIOError; // } // // writer.write((char*)outBuffer.data(), encoded_size, OPUS_FRAME_SIZE, (framesToEncode == 0) ? true : false); // // framesToEncode--; // sampleData += OPUS_FRAME_SIZE; // } // // fout.close(); // // opus_encoder_destroy(enc); // // return EncoderError::NoError; //} // //#undef OPUS_MAX_PACKET_SIZEhvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/resource.h0000644000000000000000000000235500000000000022347 0ustar00{{copyright}} #ifndef _HV_{{name|upper}}_WWISE_RESOURCE_H_ #define _HV_{{name|upper}}_WWISE_RESOURCE_H_ #define IDD_HV_{{name|upper}}_PLUGIN_SMALL 15 #define IDD_HV_{{name|upper}}_PLUGIN_BIG 16 #define IDC_STATIC_PARAMETER_IN_GROUP 4000 #define IDC_STATIC_PARAMETER_OUT_GROUP 5000 #define IDC_STATIC_TABLE_GROUP 6000 // Auto-generated Heavy parameters {% for k, v in parameters %} #define IDC_STATIC_HV_PARAM_{{k|upper}} {{4000 + (loop.index*3)}} #define IDC_RANGE_HV_PARAM_{{k|upper}} {{4001 + (loop.index*3)}} #define IDS_HV_PARAM_{{k|upper}} {{4002 + (loop.index*3)}} {%- endfor %} {% for k, v in sends %} #define IDC_STATIC_HV_PARAM_OUT_{{k|upper}} {{5000 + (loop.index*3)}} {%- endfor %} {% for k, v in tables %} #define IDC_STATIC_HV_TABLE_{{k|upper}} {{6000 + (loop.index*2)}} #define IDC_BUTTON_HV_TABLE_{{k|upper}} {{6001 + (loop.index*2)}} {%- endfor %} // Next default values for new objects #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 4015 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 4037 #define _APS_NEXT_SYMED_VALUE 4004 #endif #endif #endif // _HV_{{name|upper}}_WWISE_RESOURCE_H_ {# force new line #} hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/{{name}}.def0000644000000000000000000000002400000000000022716 0ustar00LIBRARY "" EXPORTS hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/{{name}}.rc0000644000000000000000000001411400000000000022571 0ustar00// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // // String Table // {%- if parameters|length > 0 %} STRINGTABLE BEGIN {%- for k, v in parameters %} IDS_HV_PARAM_{{k|upper}} "{{v.display}}" {%- endfor %} END {%- endif %} #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // English (Canada) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN #pragma code_page(1252) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "#define AK_WWISESDK_SAMPLE_FILEDESC ""{{name}} Wwise plug-in generated by Heavy""\r\n" "#define AK_WWISESDK_SAMPLE_INTERNALNAME ""{{name}}.dll""\r\n" "#define AK_WWISESDK_SAMPLE_ORIGINALFILE ""{{name}}.dll""\r\n" "#include ""AkWwiseSDKVersion.rc""\r\n" "#define _AFX_NO_SPLITTER_RESOURCES\r\n" "#define _AFX_NO_OLE_RESOURCES\r\n" "#define _AFX_NO_TRACKER_RESOURCES\r\n" "#define _AFX_NO_PROPERTY_RESOURCES\r\n" "\r\n" "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" "LANGUAGE 9, 1\r\n" "#pragma code_page(1252)\r\n" "#include ""afxres.rc"" // Standard components\r\n" "#endif\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_HV_{{name|upper}}_PLUGIN_BIG DIALOGEX 0, 0, 518, 280 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CLIPCHILDREN FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN {%- set maxParamNameLength = 15 %} {%- set offset = 0 %} {%- if parameters|length > 0 %} {%- set offset = parameters|length*20+25 %} {%- for k, v in parameters %} {%- if k|length > maxParamNameLength %} {%- set maxParamNameLength = k|length %} {%- endif %} {%- endfor %} GROUPBOX "In Parameters", IDC_STATIC_PARAMETER_IN_GROUP, 5, 3, {{maxParamNameLength*10+65}}, {{parameters|length*20+20}} {%- for k, v in parameters %} LTEXT "{{v.display}}", IDC_STATIC_HV_PARAM_{{k|upper}}, 25, {{((loop.index-1)*20)+20}}, {{maxParamNameLength*5}}, 13, WS_TABSTOP LTEXT "Class=SuperRange;Prop={{k}}", IDC_RANGE_HV_PARAM_{{k|upper}}, {{maxParamNameLength*5}}+45, {{((loop.index-1)*20)+20}}, 80, 13, WS_BORDER | WS_TABSTOP {%- endfor %} {%- endif %} {%- if sends|length > 0 %} GROUPBOX "Out Parameters", IDC_STATIC_PARAMETER_OUT_GROUP, 5, {{offset+5}}, {{maxParamNameLength*10+65}}, {{sends|length*20+20}} {%- for k, v in sends %} LTEXT "{{k|lower}}", IDC_STATIC_HV_PARAM_OUT_{{k|upper}}, 25, {{((loop.index-1)*20)+offset+20}}, {{maxParamNameLength*5}}, 13, WS_TABSTOP {%- endfor %} {%- set offset = offset + sends|length*20+25 %} {%- endif %} {%- if tables|length > 0 %} {%- for k, v in tables %} {%- if k|length > maxParamNameLength %} {%- set maxParamNameLength = k|length %} {%- endif %} {%- endfor %} GROUPBOX "Tables", IDC_STATIC_TABLE_GROUP, 5, {{offset+5}}, {{maxParamNameLength*10+65}}, {{tables|length*20+20}} {%- for k, v in tables %} LTEXT "{{v.display}}", IDC_STATIC_HV_TABLE_{{k|upper}}, 25, {{((loop.index-1)*20)+offset+20}}, {{maxParamNameLength*5}}, 13, WS_TABSTOP PUSHBUTTON "Load Sample", IDC_BUTTON_HV_TABLE_{{k|upper}}, {{maxParamNameLength*5}}+45, {{((loop.index-1)*20)+offset+20}}, 50, 13 {%- endfor %} {%- endif %} END IDD_HV_{{name|upper}}_PLUGIN_SMALL DIALOGEX 0, 0, {{(parameters|length) * 50}}, 13 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN {%- for k, v in parameters %} {% if loop.index < 4 -%} LTEXT "Class=SuperRange;Prop={{k}};Title={{v.display}};", IDC_RANGE_HV_PARAM_{{k|upper}}, {{((loop.index-1)*50)}}, 0, 50, 13, WS_BORDER | WS_TABSTOP {%- endif %} {%- endfor %} END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_HV_{{name|upper}}_PLUGIN_BIG, DIALOG BEGIN END IDD_HV_{{name|upper}}_PLUGIN_SMALL, DIALOG BEGIN RIGHTMARGIN, 196 VERTGUIDE, 2 END END #endif // APSTUDIO_INVOKED #endif // English (Canada) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // #define AK_WWISESDK_SAMPLE_FILEDESC "{{name}} Wwise plug-in generated by Heavy" #define AK_WWISESDK_SAMPLE_INTERNALNAME "{{name}}.dll" #define AK_WWISESDK_SAMPLE_ORIGINALFILE "{{name}}.dll" #include "AkWwiseSDKVersion.rc" #define _AFX_NO_SPLITTER_RESOURCES #define _AFX_NO_OLE_RESOURCES #define _AFX_NO_TRACKER_RESOURCES #define _AFX_NO_PROPERTY_RESOURCES #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE 9, 1 #pragma code_page(1252) #include "afxres.rc" // Standard components #endif ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED {# force new line #} hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/{{name}}.xml0000644000000000000000000000457000000000000022772 0ustar00 {{copyright}} {%- if plugin_type == "Source" %} {% if tables|length > 0 -%} true {% endif -%} {%- if parameters|length > 0 %} {%- for k, v in parameters %} {{v.attributes.default}} {{loop.index-1}} {{v.attributes.min}} {{v.attributes.max}} {%- endfor %} {%- endif %} {%- elif plugin_type == "FX" %} true true true {%- if parameters|length > 0 %} {%- for k, v in parameters %} {{v.attributes.default}} {{loop.index-1}} {{v.attributes.min}} {{v.attributes.max}} {%- endfor %} {%- endif %} {%- endif %} {# force new line #} hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/{{name}}Plugin.cpp0000644000000000000000000000600700000000000024130 0ustar00{{copyright}} #include "{{name}}Plugin.h" #include "../SoundEnginePlugin/{{name}}{{plugin_type}}Factory.h" #include "libnyquist/WavDecoder.h" #include "libnyquist/WavEncoder.h" #include #include #include #include #include bool {{name}}Plugin::GetBankParameters(const GUID & in_guidPlatform, AK::Wwise::Plugin::DataWriter& in_dataWriter) const { {%- for k, v in parameters %} in_dataWriter.WriteReal32(m_propertySet.GetReal32(in_guidPlatform, "{{k}}")); {%- endfor %} return true; } void {{name}}Plugin::NotifyPluginMediaChanged() { m_host.NotifyInternalDataChanged(AK::IAkPluginParam::ALL_PLUGIN_DATA_ID, true); } AK::Wwise::Plugin::ConversionResult {{name}}Plugin::ConvertFile( const GUID& in_guidPlatform, const BasePlatformID& in_basePlatform, const AkOSChar* in_szSourceFile, const AkOSChar* in_szDestFile, AkUInt32 in_uSampleRate, AkUInt32 in_uBlockLength, AK::Wwise::Plugin::IProgress* in_pProgress, AK::Wwise::Plugin::IWriteString* io_pError) const { if (wcslen(in_szSourceFile) > 0) { // convert input file to 32bit floating point wav nqr::NyquistIO loader; std::shared_ptr fileData = std::make_shared(); std::string inPath = std::wstring_convert>().to_bytes(in_szSourceFile); loader.Load(fileData.get(), inPath); std::string outPath = std::wstring_convert>().to_bytes(in_szDestFile); nqr::WavEncoder::WriteFile({ 1, nqr::PCM_FLT, nqr::DITHER_NONE }, fileData.get(), outPath); } else { // Note(joe): because we create dummy media sources for the patch tables the input file here doesn't exist // but we still need to create a dummy output file to avoid errors std::ofstream outFile(in_szDestFile); outFile.close(); } return AK::Wwise::Plugin::ConversionSuccess; } uint32_t {{name}}Plugin::GetCurrentConversionSettingsHash( const GUID& in_guidPlatform, AkUInt32 in_uSampleRate, AkUInt32 in_uBlockLength) const { const auto numMedia = m_objectMedia.GetMediaSourceCount(); uint32_t hash = in_uSampleRate ^ in_uBlockLength; AK::FNVHash32 hashFunc; AkOSChar szMediaFileName[_MAX_PATH]; for (int32_t mediaIdx = 0; mediaIdx < numMedia; ++mediaIdx) { const uint32_t fileNameSize = m_objectMedia.GetMediaSourceFileName(szMediaFileName, _MAX_PATH, mediaIdx); if (fileNameSize > 0) { for (int i = 0; i < fileNameSize; ++i) { szMediaFileName[i] = tolower(szMediaFileName[i]); } hash = hash * 31 + static_cast(hashFunc.Compute(szMediaFileName, fileNameSize)); } } return hash; } DEFINE_AUDIOPLUGIN_CONTAINER({{name}}); EXPORT_AUDIOPLUGIN_CONTAINER({{name}}); ADD_AUDIOPLUGIN_CLASS_TO_CONTAINER({{name}}, {{name}}Plugin, {{name}}{{plugin_type}}); DEFINE_PLUGIN_REGISTER_HOOK DEFINEDUMMYASSERTHOOK; hvcc-0.16.0/hvcc/generators/c2wwise/templates/WwisePlugin/{{name}}Plugin.h0000644000000000000000000000231400000000000023572 0ustar00{{copyright}} #pragma once #include class {{name}}Plugin final : public AK::Wwise::Plugin::AudioPlugin , public AK::Wwise::Plugin::RequestHost , public AK::Wwise::Plugin::RequestObjectMedia , public AK::Wwise::Plugin::MediaConverter { public: {{name}}Plugin() = default; ~{{name}}Plugin() = default; bool GetBankParameters(const GUID & in_guidPlatform, AK::Wwise::Plugin::DataWriter& in_dataWriter) const override; void NotifyPluginMediaChanged() override; AK::Wwise::Plugin::ConversionResult ConvertFile( const GUID& in_guidPlatform, const BasePlatformID& in_basePlatform, const AkOSChar* in_szSourceFile, const AkOSChar* in_szDestFile, AkUInt32 in_uSampleRate, AkUInt32 in_uBlockLength, AK::Wwise::Plugin::IProgress* in_pProgress, AK::Wwise::Plugin::IWriteString* io_pError ) const override; uint32_t GetCurrentConversionSettingsHash( const GUID& in_guidPlatform, AkUInt32 in_uSampleRate = 0, AkUInt32 in_uBlockLength = 0 ) const override; }; DECLARE_AUDIOPLUGIN_CONTAINER({{name}}); // Exposes our PluginContainer structure that contains the info for our plugin hvcc-0.16.0/hvcc/generators/c2wwise/templates/bundle_template.json0000644000000000000000000000122000000000000022117 0ustar00{ "id": "Heavy.{{name}}.${year}_${major}_${minor}_${build}", "name": "{{name}}", "tag": "{{name}}", "description": "", "vendor": "Heavy", "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=", "type": "plugin", "productDependentData": { "targetWwiseVersion": { "year": ${year}, "major": ${major} } }, "version": { "year": ${year}, "major": ${major}, "minor": ${minor}, "build": ${build} }, "eulas": [], "labels": [], "links": [], "documentation": [] } hvcc-0.16.0/hvcc/generators/c2wwise/templates/{{name}}Config.h0000644000000000000000000000034500000000000021266 0ustar00{{copyright}} #ifndef {{name}}Config_H #define {{name}}Config_H namespace {{name}}Config { static const unsigned short CompanyID = 64; static const unsigned short PluginID = {{plugin_id}}; } #endif // {{name}}Config_H hvcc-0.16.0/hvcc/generators/copyright/__init__.py0000644000000000000000000000000000000000000016613 0ustar00hvcc-0.16.0/hvcc/generators/copyright/copyright_manager.py0000644000000000000000000000405700000000000020576 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import datetime from typing import Optional from pathlib import Path def get_default_copyright_text() -> str: with open(Path(Path(__file__).parent, "default_template.txt"), "r") as f: copyright = f.read().format(datetime.datetime.now().year) return copyright def get_copyright_for_c(copyright_text: Optional[str] = None) -> str: """ Returns an input string as a C-formatted comment, otherwise a default copyright statement if the input is None. """ return comment_for_c(copyright_text or get_default_copyright_text()) def get_copyright_for_xml(copyright_text: Optional[str] = None) -> str: """ Returns an input string as an xml comment, otherwise a default copyright statement if the input is None. """ return comment_for_xml(copyright_text or get_default_copyright_text()) def comment_for_c(comment: str) -> str: """ Returns the input string as a C-formatted comment, suitable for copyright statements. """ if "\n" in comment: return "/**\n * {0}\n */".format("\n * ".join(comment.split("\n"))) else: return f"/** {comment} */" def comment_for_xml(comment: str) -> str: """ Returns the input string as a XML comment, suitable for copyright statements. """ if "\n" in comment: return f"" else: return f"" hvcc-0.16.0/hvcc/generators/copyright/default_template.txt0000644000000000000000000000304200000000000020573 0ustar00Copyright (c) {0} Enzien Audio, Ltd. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the phrase "powered by heavy", the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible form. 2.1 If the Application is distributed in a store system (for example, the Apple "App Store" or "Google Play"), the phrase "powered by heavy" shall be included in the app description or the copyright text as well as the in the app itself. The heavy logo will shall be visible in the app itself as well. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. hvcc-0.16.0/hvcc/generators/filters.py0000644000000000000000000000435500000000000014535 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2023 Wasted Audio # # 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 . import hashlib import os def filter_max(i: int, j: int) -> int: """Calculate the maximum of two integers. """ return max(int(i), int(j)) def filter_plugin_id(s: str) -> int: """ Return a unique id from patch name [0...32767 """ sh = hashlib.md5(s.encode('utf-8')) sd = sh.hexdigest()[:4] return int(sd, 16) & 0x7FFF def filter_string_cap(s: str, li: int) -> str: """Returns a truncated string with ellipsis if it exceeds a certain length. """ return s if (len(s) <= li) else f"{s[0:li - 3]}..." def filter_templates(template_name: str) -> bool: return False if os.path.basename(template_name) in [".DS_Store"] else True def filter_uniqueid(s: str) -> str: """ Return a unique id (in hexadecimal) for the Plugin interface. """ sh = hashlib.md5(s.encode('utf-8')) sd = sh.hexdigest().upper()[0:8] return f"0x{sd}" def filter_xcode_build(s: str) -> str: """Return a build hash suitable for use in an Xcode project file. """ s = f"{s}_build" sh = hashlib.md5(s.encode('utf-8')) return sh.hexdigest().upper()[0:24] def filter_xcode_copy(s: str) -> str: """Return a copyref hash suitable for use in an Xcode project file. """ s = f"{s}_copy" sh = hashlib.md5(s.encode('utf-8')) return sh.hexdigest().upper()[0:24] def filter_xcode_fileref(s: str) -> str: """Return a fileref hash suitable for use in an Xcode project file. """ s = f"{s}_fileref" sh = hashlib.md5(s.encode('utf-8')) return sh.hexdigest().upper()[0:24] hvcc-0.16.0/hvcc/generators/ir2c/ControlBinop.py0000644000000000000000000001064200000000000016330 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlBinop(HeavyObject): # a dictionary translating from the operation argument to the C case __OPERATION_DICT = { "__add": "HV_BINOP_ADD", "__add_k": "HV_BINOP_ADD", "__sub": "HV_BINOP_SUBTRACT", "__sub_k": "HV_BINOP_SUBTRACT", "__mul": "HV_BINOP_MULTIPLY", "__mul_k": "HV_BINOP_MULTIPLY", "__div": "HV_BINOP_DIVIDE", "__div_k": "HV_BINOP_DIVIDE", "__intdiv": "HV_BINOP_INT_DIV", "__intdiv_k": "HV_BINOP_INT_DIV", "__shiftleft": "HV_BINOP_BIT_LEFTSHIFT", "__shiftleft_k": "HV_BINOP_BIT_LEFTSHIFT", "__shiftright": "HV_BINOP_BIT_RIGHTSHIFT", "__shiftright_k": "HV_BINOP_BIT_RIGHTSHIFT", "__and": "HV_BINOP_BIT_AND", "__and_k": "HV_BINOP_BIT_AND", "__or": "HV_BINOP_BIT_OR", "__or_k": "HV_BINOP_BIT_OR", "__^": "HV_BINOP_BIT_XOR", "__==": "HV_BINOP_EQL_EQL", "__!=": "HV_BINOP_NOT_EQL", "__logand": "HV_BINOP_LOGICAL_AND", "__logand_k": "HV_BINOP_LOGICAL_AND", "__logor": "HV_BINOP_LOGICAL_OR", "__logor_k": "HV_BINOP_LOGICAL_OR", "__eq": "HV_BINOP_EQ", "__eq_k": "HV_BINOP_EQ", "__neq": "HV_BINOP_NEQ", "__neq_k": "HV_BINOP_NEQ", "__lt": "HV_BINOP_LESS_THAN", "__lt_k": "HV_BINOP_LESS_THAN", "__lte": "HV_BINOP_LESS_THAN_EQL", "__lte_k": "HV_BINOP_LESS_THAN_EQL", "__gt": "HV_BINOP_GREATER_THAN", "__gt_k": "HV_BINOP_GREATER_THAN", "__gte": "HV_BINOP_GREATER_THAN_EQL", "__gte_k": "HV_BINOP_GREATER_THAN_EQL", "__max": "HV_BINOP_MAX", "__max_k": "HV_BINOP_MAX", "__min": "HV_BINOP_MIN", "__min_k": "HV_BINOP_MIN", "__pow": "HV_BINOP_POW", "__pow_k": "HV_BINOP_POW", "__atan2": "HV_BINOP_ATAN2", "__atan2_k": "HV_BINOP_ATAN2", "__unimod": "HV_BINOP_MOD_UNIPOLAR", "__unimod_k": "HV_BINOP_MOD_UNIPOLAR", "__bimod": "HV_BINOP_MOD_BIPOLAR", "__bimod_k": "HV_BINOP_MOD_BIPOLAR" } c_struct = "ControlBinop" preamble = "cBinop" @classmethod def handles_type(cls, obj_type: str) -> bool: """Returns true if the object type can be handled by this class """ return obj_type in cls.__OPERATION_DICT @classmethod def get_C_header_set(cls) -> set: return {"HvControlBinop.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlBinop.h", "HvControlBinop.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type.endswith("_k"): return [] else: obj_arg = float(list(args.values())[0]) return [f"cBinop_init(&cBinop_{obj_id}, {obj_arg}f); // {obj_type}"] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # no need to free any control binop objects @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: if obj_type.endswith("_k"): return [ "cBinop_k_onMessage(_c, NULL, {0}, {1}f, {2}, m, &cBinop_{3}_sendMessage);".format( cls.__OPERATION_DICT[obj_type[:-2]], float(args["k"]), inlet_index, obj_id) ] else: return [ "cBinop_onMessage(_c, &Context(_c)->cBinop_{0}, {1}, {2}, m, &cBinop_{0}_sendMessage);".format( obj_id, cls.__OPERATION_DICT[obj_type], inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlCast.py0000644000000000000000000000275000000000000016154 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlCast(HeavyObject): __OPERATION_DICT = { "__cast_b": "HV_CAST_BANG", "__cast_f": "HV_CAST_FLOAT", "__cast_s": "HV_CAST_SYMBOL" } c_struct = "ControlCast" preamble = "cCast" @classmethod def get_C_header_set(cls) -> set: return {"HvControlCast.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlCast.h", "HvControlCast.c"} @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "cCast_onMessage(_c, {1}, 0, m, &cCast_{0}_sendMessage);".format( obj_id, cls.__OPERATION_DICT[obj_type]) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlDelay.py0000644000000000000000000000507700000000000016325 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Callable, Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IROnMessage, IRObjectdict class ControlDelay(HeavyObject): c_struct = "ControlDelay" preamble = "cDelay" @classmethod def get_C_header_set(cls) -> set: return {"HvControlDelay.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlDelay.h", "HvControlDelay.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "{0}_init(this, &{0}_{1}, {2}f);".format( cls.preamble, obj_id, float(args["delay"])) ] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # no need to free any control binop objects @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "{0}_onMessage(_c, &Context(_c)->{0}_{1}, {2}, m, " "&{0}_{1}_sendMessage);".format( cls.preamble, obj_id, inlet_index) ] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List[List[IROnMessage]], get_obj_class: Callable, objects: Dict[str, IRObjectdict], args: Dict ) -> List[str]: send_message_list = [ f"cDelay_{obj_id}_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {{" ] send_message_list.append(f"cDelay_clearExecutingMessage(&Context(_c)->cDelay_{obj_id}, m);") send_message_list.extend( cls._get_on_message_list(on_message_list[0], get_obj_class, objects)) send_message_list.append("}") # end function return send_message_list hvcc-0.16.0/hvcc/generators/ir2c/ControlExpr.py0000644000000000000000000001357100000000000016203 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . import re from typing import Callable, Dict, List, Tuple from .HeavyObject import HeavyObject class ControlExpr(HeavyObject): c_struct = "ControlExpr" preamble = "cExpr" @classmethod def get_C_header_set(cls) -> set: return {"HvControlExpr.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlExpr.h", "HvControlExpr.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: """ (Per object) code that gets inserted into from the Heavy_heavy ctor. Only if "ir[init]" == true """ eval_f = f"&Heavy_{{{{name}}}}::{cls.preamble}_{obj_id}_evaluate" return [f"cExpr_init(&cExpr_{obj_id}, {eval_f});"] @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: """ (Per object) code that gets inserted into the header file Only if "ir[init]" == true """ lines = super().get_C_def(obj_type, obj_id) lines.append(f"static float {cls.preamble}_{obj_id}_evaluate(const float* args);") return lines @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: """ (Per object) code that gets inserted into the c__sendMessage method in the .cpp file The get_C_onMessage method returns the code that will get inserted into the cReceive__sendMessage method """ return [ "cExpr_onMessage(_c, &Context(_c)->cExpr_{0}, {1}, m, &cExpr_{0}_sendMessage);".format( obj_id, inlet_index) ] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List, get_obj_class: Callable, objects: Dict, args: Dict ) -> List[str]: """ (Per object) this creates the _sendMessage function that other objects use to send messages to this object. """ lines = super().get_C_impl(obj_type, obj_id, on_message_list, get_obj_class, objects, args) expr = args["expressions"][0] bound_expr = bind_expr(expr, "args") lines.extend([ "", f"float Heavy_{{{{name}}}}::{cls.preamble}_{obj_id}_evaluate(const float* args) {{", f"\treturn {bound_expr};", "}", ]) return lines def var_n(a_name: str, var: str) -> str: """ Rewrite the input expression into one that uses local variables that have been cast to either float or int todo(dgb): need to handle the 's' type """ parts = re.match(r"\$([fi])(\d+)", var) assert parts type = "float" if parts[1] == "f" else "int" return f"(({type})({a_name}[{int(parts[2])-1}]))" def internal_expr(exp: str) -> str: """ Convert function names to C or internal names """ internal: List[Tuple[str, str]] = [ (r"\\,", ","), (r"\bfact(?=\()", "expr_fact"), (r"\bimodf(?=\()", "expr_imodf"), ] for r in internal + hv_utils: exp = re.sub(r[0], r[1], exp) return exp def bind_expr(exp: str = "$f1+2", a_name: str = "a") -> str: vars = re.findall(r"\$[fis]\d+", exp) exp = internal_expr(exp) if vars: # reverse list so we start replacing the bigger variables # and don't get conflicts. eg. $f11 vs $f1 vars.sort(reverse=True) for var in vars: exp = exp.replace(var, var_n(a_name, var)) return exp hv_utils: List[Tuple[str, str]] = [ (r"\babs(?=\()", "hv_abs_f"), (r"\bacos(?=\()", "hv_acos_f"), (r"\bacosh(?=\()", "hv_acosh_f"), (r"\basin(?=\()", "hv_asin_f"), (r"\basinh(?=\()", "hv_asinh_f"), (r"\batan(?=\()", "hv_atan_f"), (r"\batanh(?=\()", "hv_atanh_f"), (r"\batan2(?=\()", "hv_atan2_f"), (r"\bcbrt(?=\()", "hv_cbrt_f"), (r"\bceil(?=\()", "hv_ceil_f"), (r"\bcopysign(?=\()", "hv_copysign_f"), (r"\bcos(?=\()", "hv_cos_f"), (r"\bcosh(?=\()", "hv_cosh_f"), (r"\berf(?=\()", "hv_erf_f"), (r"\berfc(?=\()", "hv_erfc_f"), (r"\bexp(?=\()", "hv_exp_f"), (r"\bexpm1(?=\()", "hv_expm1_f"), (r"\bfinite(?=\()", "hv_finite_f"), (r"\bfloor(?=\()", "hv_floor_f"), (r"\bif(?=\()", "hv_if_f"), (r"\bisinf(?=\()", "hv_isinf_f"), (r"\bisnan(?=\()", "hv_isnan_f"), (r"\bfmod(?=\()", "hv_fmod_f"), (r"\bldexp(?=\()", "hv_ldexp_f"), (r"\bln(?=\()", "hv_ln_f"), (r"\blog(?=\()", "hv_log_f"), (r"\blog10(?=\()", "hv_log10_f"), (r"\blog1p(?=\()", "hv_log1p_f"), (r"\bmax(?=\()", "hv_max_f"), (r"\bmin(?=\()", "hv_min_f"), (r"\bmodf(?=\()", "hv_modf_f"), (r"\bpow(?=\()", "hv_pow_f"), (r"\bremainder(?=\()", "hv_remainder_f"), (r"\brint(?=\()", "hv_rint_f"), (r"\bround(?=\()", "hv_round_f"), (r"\bsin(?=\()", "hv_sin_f"), (r"\bsinh(?=\()", "hv_sinh_f"), (r"\bsqrt(?=\()", "hv_sqrt_f"), (r"\btan(?=\()", "hv_tan_f"), (r"\btanh(?=\()", "hv_tanh_f"), ] hvcc-0.16.0/hvcc/generators/ir2c/ControlIf.py0000644000000000000000000000341300000000000015615 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlIf(HeavyObject): c_struct = "ControlIf" preamble = "cIf" @classmethod def get_C_header_set(cls) -> set: return {"HvControlIf.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlIf.h", "HvControlIf.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "{0}_init(&{0}_{1}, {2});".format( cls.preamble, obj_id, "true" if float(args["k"]) != 0.0 else "false" )] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # no need to free any control binop objects @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "{0}_onMessage(_c, &Context(_c)->{0}_{1}, {2}, m, " "&{0}_{1}_sendMessage);".format(cls.preamble, obj_id, inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlMessage.py0000644000000000000000000000654300000000000016652 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . import re from typing import Callable, Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRObjectdict, IROnMessage class ControlMessage(HeavyObject): preamble = "cMsg" @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cMsg_{obj_id}_sendMessage(_c, 0, m);"] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List[List[IROnMessage]], get_obj_class: Callable, objects: Dict[str, IRObjectdict], args: Dict ) -> List[str]: send_message_list = [ f"cMsg_{obj_id}_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {{" ] if len(objects[obj_id].args["local"]) > 0: # declare the outgoing messages (if there are any) send_message_list.append("HvMessage *m = nullptr;") # for each message for m in objects[obj_id].args["local"]: # construct the message send_message_list.append(f"m = HV_MESSAGE_ON_STACK({len(m)});") send_message_list.append(f"msg_init(m, {len(m)}, msg_getTimestamp(n));") for i in range(len(m)): e = m[i] # get the message element try: # is the message a float? send_message_list.append(f"msg_setFloat(m, {i}, {float(e)}f);") except Exception: if e in ["bang"]: # is the message a bang? send_message_list.append(f"msg_setBang(m, {i});") elif re.match(r"\$[\d]+", e): send_message_list.append(f"msg_setElementToFrom(m, {i}, n, {int(e[1:]) - 1});") elif e == "@HV_N_SIMD": # NOTE(mhroth): messages can contain special arguments # which are interpreted differently than other strings send_message_list.append(f"msg_setFloat(m, {i}, static_cast(HV_N_SIMD));") else: send_message_list.append(f"msg_setSymbol(m, {i}, \"{e}\");") # send the message to all receiving objects for om in on_message_list[0]: send_message_list.extend( get_obj_class(objects[om.id].type).get_C_onMessage( objects[om.id].type, om.id, om.inletIndex, objects[om.id].args)) send_message_list.append("}") # end function return send_message_list hvcc-0.16.0/hvcc/generators/ir2c/ControlPack.py0000644000000000000000000000333100000000000016134 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlPack(HeavyObject): """Prints the first value in a message to the console""" c_struct = "ControlPack" preamble = "cPack" @classmethod def get_C_header_set(cls) -> set: return {"HvControlPack.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlPack.h", "HvControlPack.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "cPack_init(&cPack_{0}, {1}, {2});".format( obj_id, len(args["values"]), ", ".join(["{0}f".format(float(x)) for x in args["values"]])) ] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "cPack_onMessage(_c, &Context(_c)->cPack_{0}, {1}, m, &cPack_{0}_sendMessage);".format( obj_id, inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlPrint.py0000644000000000000000000000367300000000000016363 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Callable, Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRObjectdict, IROnMessage class ControlPrint(HeavyObject): """Prints the first value in a message to the console""" preamble = "cPrint" @classmethod def get_C_header_set(cls) -> set: return {"HvControlPrint.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlPrint.h", "HvControlPrint.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cPrint_onMessage(_c, m, \"{args['label']}\");"] @classmethod def get_C_decl(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List[List[IROnMessage]], get_obj_class: Callable, objects: Dict[str, IRObjectdict], args: Dict ) -> List[str]: return [] hvcc-0.16.0/hvcc/generators/ir2c/ControlRandom.py0000644000000000000000000000334200000000000016500 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlRandom(HeavyObject): c_struct = "ControlRandom" preamble = "cRandom" @classmethod def get_C_header_set(cls) -> set: return {"HvControlRandom.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlRandom.h", "HvControlRandom.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "{0}_init(&{0}_{1}, {2});".format( cls.preamble, obj_id, int(args["seed"])) ] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # no need to free any control binop objects @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "{0}_onMessage(_c, &Context(_c)->{0}_{1}, {2}, m, " "&{0}_{1}_sendMessage);".format(cls.preamble, obj_id, inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlReceive.py0000644000000000000000000000205100000000000016636 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlReceive(HeavyObject): c_struct = "ControlReceive" preamble = "cReceive" @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cReceive_{obj_id}_sendMessage(_c, 0, m);"] hvcc-0.16.0/hvcc/generators/ir2c/ControlSend.py0000644000000000000000000000441700000000000016155 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Callable, Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRObjectdict, IROnMessage class ControlSend(HeavyObject): c_struct = "ControlSend" preamble = "cSend" @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cSend_{obj_id}_sendMessage(_c, 0, m);"] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List[List[IROnMessage]], get_obj_class: Callable, objects: Dict[str, IRObjectdict], args: Dict ) -> List[str]: # Note(joe): if no corresponding receivers exist and there's no extern indicator # then there is not much need to generate code stub send_message_list = [ "{0}_{1}_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {{".format( cls.get_preamble(obj_type), obj_id)] if objects[obj_id].args.get("extern", False): # call the send hook send_name = objects[obj_id].args["name"] send_message_list.append("if (_c->getSendHook() != nullptr) _c->getSendHook()(_c, \"{0}\", {1}, m);".format( send_name, cls.get_hash_string(send_name))) # a send has only one (implicit!) outlet send_message_list.extend( cls._get_on_message_list(on_message_list[0], get_obj_class, objects)) send_message_list.append("}") # end function return send_message_list hvcc-0.16.0/hvcc/generators/ir2c/ControlSlice.py0000644000000000000000000000332100000000000016314 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlSlice(HeavyObject): c_struct = "ControlSlice" preamble = "cSlice" @classmethod def get_C_header_set(cls) -> set: return {"HvControlSlice.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlSlice.h", "HvControlSlice.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "cSlice_init(&cSlice_{0}, {1}, {2});".format( obj_id, int(args["index"]), int(args["length"]))] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # nothing to free @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ f"cSlice_onMessage(_c, &Context(_c)->cSlice_{obj_id}, {inlet_index}, m, &cSlice_{obj_id}_sendMessage);" ] hvcc-0.16.0/hvcc/generators/ir2c/ControlSwitchcase.py0000644000000000000000000000630600000000000017360 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Callable, Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IROnMessage, IRObjectdict class ControlSwitchcase(HeavyObject): c_struct = "ControlSwitchase" preamble = "cSwichcase" @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: return [] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_decl(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ f"cSwitchcase_{obj_id}_onMessage(HeavyContextInterface *, void *, int letIn, " "const HvMessage *const, void *);" ] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cSwitchcase_{obj_id}_onMessage(_c, NULL, {inlet_index}, m, NULL);"] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List[List[IROnMessage]], get_obj_class: Callable, objects: Dict[str, IRObjectdict], args: Dict ) -> List[str]: # generate the onMessage implementation out_list = [ f"cSwitchcase_{obj_id}_onMessage(HeavyContextInterface *_c, void *o, int letIn, " f"const HvMessage *const m, void *sendMessage) {{" ] out_list.append("int msgIndex = 0;") out_list.append("switch (msg_getHash(m, msgIndex)) {") out_list.append(f"case {cls.get_hash_string('symbol')}: {{ // \"symbol\"") out_list.append("msgIndex = 1;") out_list.append("break;") out_list.append("}") # end symbol case out_list.append("}") # end type switch out_list.append("switch (msg_getHash(m, msgIndex)) {") cases = objects[obj_id].args["cases"] for i, c in enumerate(cases): hv_hash = cls.get_hash_string(c) out_list.append(f"case {hv_hash}: {{ // \"{c}\"") out_list.extend( cls._get_on_message_list(on_message_list[i], get_obj_class, objects)) out_list.append("break;") out_list.append("}") out_list.append("default: {") out_list.extend( cls._get_on_message_list(on_message_list[-1], get_obj_class, objects)) out_list.append("break;") out_list.append("}") # end default out_list.append("}") # end switch out_list.append("}") # end function return out_list hvcc-0.16.0/hvcc/generators/ir2c/ControlSystem.py0000644000000000000000000000243000000000000016541 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlSystem(HeavyObject): c_struct = "ControlSystem" preamble = "cSystem" @classmethod def get_C_header_set(cls) -> set: return {"HvControlSystem.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlSystem.h", "HvControlSystem.c"} @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cSystem_onMessage(_c, NULL, {inlet_index}, m, &cSystem_{obj_id}_sendMessage);"] hvcc-0.16.0/hvcc/generators/ir2c/ControlTabhead.py0000644000000000000000000000316500000000000016613 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlTabhead(HeavyObject): """Handles __tabhead """ c_struct = "ControlTabhead" preamble = "cTabhead" @classmethod def get_C_header_set(cls) -> set: return {"HvControlTabhead.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlTabhead.h", "HvControlTabhead.c"} @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"cTabhead_init(&cTabhead_{obj_id}, &hTable_{args['table_id']});"] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"cTabhead_onMessage(_c, &Context(_c)->cTabhead_{obj_id}, 0, m, &cTabhead_{obj_id}_sendMessage);"] hvcc-0.16.0/hvcc/generators/ir2c/ControlTabread.py0000644000000000000000000000340700000000000016624 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlTabread(HeavyObject): c_struct = "ControlTabread" preamble = "cTabread" @classmethod def get_C_header_set(cls) -> set: return {"HvControlTabread.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlTabread.h", "HvControlTabread.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "cTabread_init(&cTabread_{0}, &hTable_{1}); // {2}".format( obj_id, args["table_id"], args["table"]) ] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "cTabread_onMessage(_c, &Context(_c)->cTabread_{0}, {1}, m, &cTabread_{0}_sendMessage);".format( obj_id, inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlTabwrite.py0000644000000000000000000000342200000000000017040 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlTabwrite(HeavyObject): c_struct = "ControlTabwrite" preamble = "cTabwrite" @classmethod def get_C_header_set(cls) -> set: return {"HvControlTabwrite.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlTabwrite.h", "HvControlTabwrite.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "cTabwrite_init(&cTabwrite_{0}, &hTable_{1}); // {2}".format( obj_id, args["table_id"], args["table"]) ] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "cTabwrite_onMessage(_c, &Context(_c)->cTabwrite_{0}, {1}, m, &cTabwrite_{0}_sendMessage);".format( obj_id, inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlUnop.py0000644000000000000000000000506500000000000016205 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlUnop(HeavyObject): # a dictionary translating from the operation argument to the C case __OPERATION_DICT = { "__cos": "HV_UNOP_COS", "__acos": "HV_UNOP_ACOS", "__cosh": "HV_UNOP_COSH", "__acosh": "HV_UNOP_ACOSH", "__sin": "HV_UNOP_SIN", "__asin": "HV_UNOP_ASIN", "__sinh": "HV_UNOP_SINH", "__asinh": "HV_UNOP_ASINH", "__tan": "HV_UNOP_TAN", "__atan": "HV_UNOP_ATAN", "__tanh": "HV_UNOP_TANH", "__atanh": "HV_UNOP_ATANH", "__log": "HV_UNOP_LOG", "__log10": "HV_UNOP_LOG10", "__log2": "HV_UNOP_LOG2", "__exp": "HV_UNOP_EXP", "__abs": "HV_UNOP_ABS", "__sqrt": "HV_UNOP_SQRT", "__ceil": "HV_UNOP_CEIL", "__floor": "HV_UNOP_FLOOR", "__round": "HV_UNOP_ROUND" } c_struct = "ControlUnop" preamble = "cUnop" @classmethod def handles_type(cls, obj_type: str) -> bool: """Returns true if the object type can be handled by this class """ return obj_type in cls.__OPERATION_DICT @classmethod def get_C_header_set(cls) -> set: return {"HvControlUnop.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlUnop.h", "HvControlUnop.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "cUnop_onMessage(_c, {1}, m, &cUnop_{0}_sendMessage);".format( obj_id, cls.__OPERATION_DICT[obj_type]) ] hvcc-0.16.0/hvcc/generators/ir2c/ControlVar.py0000644000000000000000000000414200000000000016007 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class ControlVar(HeavyObject): """An object which holds a variable. In this case only a float. NOTE(mhroth): maybe in the future this can hold any data structure, such as a generic message. At the moment, the memory churn is deemed unnecessary. """ c_struct = "ControlVar" preamble = "cVar" @classmethod def get_C_header_set(cls) -> set: return {"HvControlVar.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvControlVar.h", "HvControlVar.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: if isinstance(args["k"], str): return [ "cVar_init_s(&cVar_{0}, \"{1}\");".format( obj_id, args["k"])] else: return [ "cVar_init_f(&cVar_{0}, {1}f);".format( obj_id, float(args["k"]))] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "cVar_onMessage(_c, &Context(_c)->cVar_{0}, {1}, m, &cVar_{0}_sendMessage);".format( obj_id, inlet_index) ] hvcc-0.16.0/hvcc/generators/ir2c/HeavyObject.py0000644000000000000000000001643500000000000016131 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2025 Daniel Billotte, Wasted Audio # # 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 . from struct import unpack, pack from typing import Callable, Dict, List, Union, Optional from hvcc.types.IR import IROnMessage, IRSignalList, IRBuffer, IRObjectdict class HeavyObject: c_struct = "" preamble = "" __C_BUFFER_DICT = { "~f>": "Bf", "~i>": "Bi", "input": "I", "output": "O", "zero": "ZERO" } @classmethod def get_C_struct(cls, obj_type: str = "") -> str: return cls.c_struct @classmethod def get_preamble(cls, obj_type: str) -> str: return cls.preamble @classmethod def get_C_header_set(cls) -> set: return set() @classmethod def get_C_file_set(cls) -> set: return set() @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: raise NotImplementedError("method get_C_init not implemented") @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: return ["{0} {1}_{2};".format( cls.get_C_struct(obj_type), cls.get_preamble(obj_type), obj_id)] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return ["{0}_free(&{0}_{1});".format( cls.get_preamble(obj_type), obj_id)] @classmethod def get_C_decl(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return ["{0}_{1}_sendMessage(HeavyContextInterface *, int, const HvMessage *);".format( cls.get_preamble(obj_type), obj_id)] @classmethod def get_C_impl( cls, obj_type: str, obj_id: str, on_message_list: List[List[IROnMessage]], get_obj_class: Callable, objects: Dict[str, IRObjectdict], args: Dict ) -> List[str]: send_message_list = [ "{0}_{1}_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {{".format( cls.get_preamble(obj_type), obj_id)] if len(on_message_list) == 1: # if there is only one outlet, skip the switch-case template send_message_list.extend( cls._get_on_message_list(on_message_list[0], get_obj_class, objects)) else: send_message_list.append("switch (letIn) {") for i in range(len(on_message_list)): send_message_list.append(f"case {i}: {{") send_message_list.extend( cls._get_on_message_list(on_message_list[i], get_obj_class, objects)) send_message_list.append("break;") send_message_list.append("}") # end case send_message_list.append("default: return;") send_message_list.append("}") # end switch send_message_list.append("}") # end function return send_message_list @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: raise NotImplementedError("method get_C_onMessage not implemented", cls, obj_type) @classmethod def get_C_obj_header_code(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_obj_impl_code(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_class_header_code(cls, obj_type: str, args: Dict) -> List[str]: return [] @classmethod def get_C_class_impl_code(cls, obj_type: str, args: Dict) -> List[str]: return [] @classmethod def get_C_gen_header_code(cls, obj_type: str, obj_id: str, args: Dict) -> Optional[tuple[str, str]]: return None @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: raise NotImplementedError("method get_C_process not implemented") @classmethod def get_table_data_decl(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: raise NotImplementedError("method get_table_data_decl not implemented") @classmethod def _get_on_message_list( cls, on_message_list: List[IROnMessage], get_obj_class: Callable, objects: Dict[str, IRObjectdict] ) -> List: out_list = [] for om in on_message_list: out_list.extend( get_obj_class(objects[om.id].type).get_C_onMessage( objects[om.id].type, om.id, om.inletIndex, objects[om.id].args)) return out_list @classmethod def _c_buffer(cls, buffer_dict: IRBuffer) -> str: """ Returns the C represenation of the given buffer. """ if buffer_dict.type == "zero": return cls.__C_BUFFER_DICT[buffer_dict.type] else: return "{0}{1}".format( cls.__C_BUFFER_DICT[buffer_dict.type], buffer_dict.index) @classmethod def get_hash(cls, x: Union[float, str]) -> int: """ Compute the message element hash used by msg_getHash(). Returns a 32-bit integer. """ if isinstance(x, float) or isinstance(x, int): # interpret the float bytes as an unsigned integer return unpack("@I", pack("@f", float(x)))[0] elif x == "bang": return 0xFFFFFFFF elif isinstance(x, str): # this hash is based MurmurHash2 # http://en.wikipedia.org/wiki/MurmurHash # https://sites.google.com/site/murmurhash/ x = str(x) m = 0x5bd1e995 r = 24 h = len(x) i = 0 while i < len(x) & ~0x3: k = unpack("@I", bytes(x[i:i + 4], encoding='utf-8'))[0] k = (k * m) & 0xFFFFFFFF k ^= k >> r k = (k * m) & 0xFFFFFFFF h = (h * m) & 0xFFFFFFFF h ^= k i += 4 n = len(x) & 0x3 x = x[i:i + n] if n >= 3: h ^= (ord(x[2]) << 16) & 0xFFFFFFFF if n >= 2: h ^= (ord(x[1]) << 8) & 0xFFFFFFFF if n >= 1: h ^= ord(x[0]) h = (h * m) & 0xFFFFFFFF h ^= h >> 13 h = (h * m) & 0xFFFFFFFF h ^= h >> 15 return h else: raise Exception("Message element hashes can only be computed for float and string types.") @classmethod def get_hash_string(cls, x: Union[float, str]) -> str: """ Returns the hash as a hex string. """ return f"0x{cls.get_hash(x):X}" hvcc-0.16.0/hvcc/generators/ir2c/HeavyTable.py0000644000000000000000000000466200000000000015751 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject class HeavyTable(HeavyObject): """Outputs code for the table object. """ c_struct = "HvTable" preamble = "hTable" @classmethod def get_C_header_set(cls) -> set: return {"HvTable.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvTable.h", "HvTable.c"} @classmethod def get_table_data_decl(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: if len(args.get("values", [])) > 0: return [ "float hTable_{0}_data[{1}] = {{{2}}};".format( obj_id, len(args["values"]), ", ".join([f"{float(v)}f" for v in args["values"]]))] else: return [] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: if len(args.get("values", [])) > 0: return [ "hTable_initWithData(&hTable_{0}, {1}, hTable_{0}_data);".format( obj_id, len(args["values"]))] else: return [ "hTable_init(&hTable_{0}, {1});".format( obj_id, int(args.get("size", 256)))] # 1KB default memory allocation @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return ["{0}_free(&{0}_{1});".format( cls.preamble, obj_id)] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ f"hTable_onMessage(_c, &Context(_c)->hTable_{obj_id}, {inlet_index}, m, &hTable_{obj_id}_sendMessage);" ] hvcc-0.16.0/hvcc/generators/ir2c/PrettyfyC.py0000644000000000000000000000327100000000000015651 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . import os from typing import List class PrettyfyC: @classmethod def prettyfy_file( cls, file_in: str, file_out: str, indent: int = 0, step: int = 2, delete_input_on_finish: bool = False ) -> None: with open(file_in, "r") as f: with open(file_out, "w") as g: for line in f: indent -= line.count("}") new_line = (" " * (step * indent)) + line g.write(new_line + os.linesep) indent += line.count("{") if delete_input_on_finish: os.remove(file_in) @classmethod def prettyfy_list( cls, list_in: List, indent: int = 0, step: int = 2 ) -> List: g = [] for line in list_in: indent -= line.count("}") new_line = (" " * (step * indent)) + line g.append(new_line) indent += line.count("{") return g hvcc-0.16.0/hvcc/generators/ir2c/SignalBiquad.py0000644000000000000000000000635200000000000016266 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalBiquad(HeavyObject): """Handles the biquad~ object. """ c_struct = "SignalBiquad" preamble = "sBiquad" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalBiquad.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalBiquad.h", "HvSignalBiquad.c"} @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: if obj_type == "__biquad_k~f": return [f"SignalBiquad_k sBiquad_k_{obj_id};"] elif obj_type == "__biquad~f": return [f"SignalBiquad sBiquad_s_{obj_id};"] else: raise Exception() @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type == "__biquad_k~f": return ["sBiquad_k_init(&sBiquad_k_{0}, {1}f, {2}f, {3}f, {4}f, {5}f);".format( obj_id, float(args["ff0"]), float(args["ff1"]), float(args["ff2"]), float(args["fb1"]), float(args["fb2"]))] elif obj_type == "__biquad~f": return [f"sBiquad_init(&sBiquad_s_{obj_id});"] else: raise Exception() @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"sBiquad_k_onMessage(&Context(_c)->sBiquad_k_{obj_id}, {inlet_index}, m);"] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type == "__biquad_k~f": return [ "__hv_biquad_k_f(&sBiquad_k_{0}, VIf({1}), VOf({2}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.outputBuffers[0]) )] elif obj_type == "__biquad~f": return [ "__hv_biquad_f(&sBiquad_s_{0}, {1}, {2});".format( process_dict.id, ", ".join([f"VIf({cls._c_buffer(b)})" for b in process_dict.inputBuffers]), ", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict.outputBuffers]) )] else: raise Exception(f"Incorrect obj_type {obj_type} for SignalBiquad") hvcc-0.16.0/hvcc/generators/ir2c/SignalCPole.py0000644000000000000000000000443500000000000016063 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalCPole(HeavyObject): """Handles the __cpole~f object. """ c_struct = "SignalCPole" preamble = "sCPole" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalCPole.h", "HvSignalDel1.h", "HvMath.h"} @classmethod def get_C_file_set(cls) -> set: return { "HvSignalCPole.h", "HvSignalCPole.c", "HvSignalDel1.h", "HvSignalDel1.c", "HvMath.h" } @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: return [f"SignalCPole sCPole_{obj_id};"] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sCPole_init(&sCPole_{obj_id});"] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_cpole_f(&sCPole_{0}, VIf({1}), VIf({2}), VIf({3}), VIf({4}), VOf({5}), VOf({6}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.inputBuffers[1]), cls._c_buffer(process_dict.inputBuffers[2]), cls._c_buffer(process_dict.inputBuffers[3]), cls._c_buffer(process_dict.outputBuffers[0]), cls._c_buffer(process_dict.outputBuffers[1]))] hvcc-0.16.0/hvcc/generators/ir2c/SignalConvolution.py0000644000000000000000000000406000000000000017372 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalConvolution(HeavyObject): c_struct = "SignalConvolution" preamble = "sConv" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalConvolution.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalConvolution.h", "HvSignalConvolution.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "sConv_init(&sConv_{0}, &hTable_{1}, {2});".format( obj_id, args["table_id"], int(args["size"])) ] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "sConv_onMessage(_c, &Context(_c)->sConv_{0}, {1}, m, NULL);".format( obj_id, inlet_index) ] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_conv_f(&sConv_{0}, VIf({1}), VOf({2}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.outputBuffers[0]) ) ] hvcc-0.16.0/hvcc/generators/ir2c/SignalDel1.py0000644000000000000000000000356700000000000015653 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalDel1(HeavyObject): """Handles the __del1~f object. """ c_struct = "SignalDel1" preamble = "sDel1" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalDel1.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalDel1.h", "HvSignalDel1.c"} @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: return [f"SignalDel1 sDel1_{obj_id};"] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sDel1_init(&sDel1_{obj_id});"] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_del1_f(&sDel1_{0}, VIf({1}), VOf({2}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.outputBuffers[0]))] hvcc-0.16.0/hvcc/generators/ir2c/SignalEnvelope.py0000644000000000000000000000333300000000000016632 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalEnvelope(HeavyObject): c_struct = "SignalEnvelope" preamble = "sEnv" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalEnvelope.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalEnvelope.h", "HvSignalEnvelope.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "sEnv_init(&sEnv_{0}, {1}, {2});".format( obj_id, int(args["windowSize"]), int(args["period"])) ] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "sEnv_process(this, &sEnv_{0}, VIf({1}), &sEnv_{0}_sendMessage);".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]) ) ] hvcc-0.16.0/hvcc/generators/ir2c/SignalExpr.py0000644000000000000000000000755400000000000016004 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . from typing import Dict, List from hvcc.types.IR import IRSignalList from .expr.expr_c_writer import ExprCWriter from .HeavyObject import HeavyObject class SignalExpr(HeavyObject): """ Handles the math objects. Note: obj_eval_functions dict accumulates until reset! """ preamble = "cExprSig" obj_eval_functions: Dict = {} @classmethod def handles_type(cls, obj_type: str) -> bool: """ Returns true if the object type can be handled by this class """ return obj_type == "_expr~" @classmethod def get_C_header_set(cls) -> set: return {"HvMath.h"} @classmethod def get_C_class_header_code(cls, obj_type: str, args: Dict) -> List[str]: eval_funcs = ",\n\t\t".join(cls.obj_eval_functions.values()) fptr_type = f"{cls.preamble}_evaluator" lines = [ f"typedef void(*{fptr_type})(hv_bInf_t*, hv_bOutf_t);", f"{fptr_type} {cls.preamble}_evaluators[{len(cls.obj_eval_functions)}] = {{\n\t\t{eval_funcs}\n\t}};", ] return lines @classmethod def get_C_obj_header_code(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: lines = [] func_name = f"{cls.preamble}_{obj_id}_evaluate" cls.obj_eval_functions[obj_id] = func_name lines.extend([ f"static inline void {func_name}(hv_bInf_t* bIns, hv_bOutf_t bOut);", ]) return lines @classmethod def get_C_obj_impl_code(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: """ (Per object) this creates the _sendMessage function that other objects use to send messages to this object. """ lines = [] expr = args["expressions"][0] expr_parser = ExprCWriter(expr) expr_lines = expr_parser.to_c_simd("bIns", "bOut")[:-1] expr_line = "\n".join( [f"\t{line}" for line in expr_lines] ) num_buffers = expr_parser.num_simd_buffers() buffer_declaration = "\t// no extra buffers needed" if num_buffers > 0: buffers = ", ".join([f"Bf{i}" for i in range(0, num_buffers)]) buffer_declaration = f"\thv_bufferf_t {buffers};" func_name = f"Heavy_{{{{name}}}}::{cls.preamble}_{obj_id}_evaluate" lines.extend([ "", f"void {func_name}(hv_bInf_t* bIns, hv_bOutf_t bOut) {{", buffer_declaration, expr_line, "}", ]) return lines @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: input_args = [] for b in process_dict.inputBuffers: buf = HeavyObject._c_buffer(b) input_args.append(f"VIf({buf})") out_buf = HeavyObject._c_buffer(process_dict.outputBuffers[0]) out_buf = f"VOf({out_buf})" call = [ "", "\t// !!! declare this buffer once outside the loop", f"\thv_bInf_t input_args_{obj_id}[{args['num_inlets']}] = {{{', '.join(input_args)}}};", f"\t{cls.preamble}_evaluators[{len(cls.obj_eval_functions)}](input_args_{obj_id}, {out_buf});" "", ] return call hvcc-0.16.0/hvcc/generators/ir2c/SignalLine.py0000644000000000000000000000365500000000000015753 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalLine(HeavyObject): c_struct = "SignalLine" preamble = "sLine" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalLine.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalLine.h", "HvSignalLine.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ f"sLine_init(&sLine_{obj_id});" ] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # nothing to free @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ f"sLine_onMessage(_c, &Context(_c)->sLine_{obj_id}, {inlet_index}, m, NULL);" ] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_line_f(&sLine_{0}, VOf({1}));".format( process_dict.id, cls._c_buffer(process_dict.outputBuffers[0]) ) ] hvcc-0.16.0/hvcc/generators/ir2c/SignalLorenz.py0000644000000000000000000000442700000000000016333 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalLorenz(HeavyObject): c_struct = "SignalLorenz" preamble = "sLorenz" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalLorenz.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalLorenz.h", "HvSignalLorenz.c", "HvMath.h"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "sLorenz_init(&sLorenz_{0}, {1}f, {2}f, {3}f);".format( obj_id, float(args["x"]), float(args["y"]), float(args["z"])) ] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # nothing to free @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "sLorenz_onMessage(_c, &Context(_c)->sLorenz_{0}, {1}, m);".format( obj_id, inlet_index) ] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_lorenz_f(&sLorenz_{0}, {1}, {2});".format( process_dict.id, ", ".join(["VIf({0})".format(cls._c_buffer(b)) for b in process_dict.inputBuffers]), ", ".join(["VOf({0})".format(cls._c_buffer(b)) for b in process_dict.outputBuffers]) ) ] hvcc-0.16.0/hvcc/generators/ir2c/SignalMath.py0000644000000000000000000000765600000000000015762 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalMath(HeavyObject): """Handles the math objects. """ # translation from operation to function preamble __OPERATION_DICT = { "__add~f": "__hv_add_f", "__add~i": "__hv_add_i", "__sub~f": "__hv_sub_f", "__sub~i": "__hv_sub_i", "__mul~f": "__hv_mul_f", "__mul~i": "__hv_mul_i", "__div~f": "__hv_div_f", "__div~i": "__hv_div_i", "__log2~f": "__hv_log2_f", "__cos~f": "__hv_cos_f", "__acos~f": "__hv_acos_f", "__cosh~f": "__hv_cosh_f", "__acosh~f": "__hv_acosh_f", "__sin~f": "__hv_sin_f", "__asin~f": "__hv_asin_f", "__sinh~f": "__hv_sinh_f", "__asinh~f": "__hv_asinh_f", "__tan~f": "__hv_tan_f", "__atan~f": "__hv_atan_f", "__atan2~f": "__hv_atan2_f", "__tanh~f": "__hv_tanh_f", "__atanh~f": "__hv_atanh_f", "__exp~f": "__hv_exp_f", "__exc_or~f": "__hv_exc_or_f", "__pow~f": "__hv_pow_f", "__pow~i": "__hv_pow_i", "__sqrt~f": "__hv_sqrt_f", "__rsqrt~f": "__hv_rsqrt_f", "__abs~f": "__hv_abs_f", "__abs~i": "__hv_abs_i", "__max~f": "__hv_max_f", "__max~i": "__hv_max_i", "__min~f": "__hv_min_f", "__min~i": "__hv_min_i", "__neg~f": "__hv_neg_f", "__gt~f": "__hv_gt_f", "__gt~i": "__hv_gt_i", "__gte~f": "__hv_gte_f", "__gte~i": "__hv_gte_i", "__lt~f": "__hv_lt_f", "__lt~i": "__hv_lt_i", "__lte~f": "__hv_lte_f", "__lte~i": "__hv_lte_i", "__eq~f": "__hv_eq_f", "__neq~f": "__hv_neq_f", "__fma~f": "__hv_fma_f", "__fms~f": "__hv_fms_f", "__floor~f": "__hv_floor_f", "__ceil~f": "__hv_ceil_f", "__cast~fi": "__hv_cast_fi", "__cast~if": "__hv_cast_if", "__and~f": "__hv_and_f", # binary and "__andnot~f": "__hv_andnot_f", # binary andnot "__or~f": "__hv_or_f", # binary or "__bitsafe~f": "__hv_bitsafe_f", # make inf and nan safe "__bit_or~f": "__hv_bit_or_f", # bitwise or "__bit_and~f": "__hv_bit_and_f", # bitwise and "__bit_not~f": "__hv_bit_not_f", # bitwise not } @classmethod def handles_type(cls, obj_type: str) -> bool: """Returns true if the object type can be handled by this class """ return obj_type in cls.__OPERATION_DICT @classmethod def get_C_header_set(cls) -> set: return {"HvMath.h"} @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "{0}({1}, {2});".format( cls.__OPERATION_DICT[obj_type], ", ".join(["VI{0}({1})".format( "i" if b.type == "~i>" else "f", cls._c_buffer(b)) for b in process_dict.inputBuffers]), ", ".join(["VO{0}({1})".format( "i" if b.type == "~i>" else "f", cls._c_buffer(b)) for b in process_dict.outputBuffers]) )] hvcc-0.16.0/hvcc/generators/ir2c/SignalNam.py0000644000000000000000000001045500000000000015573 0ustar00# Copyright (C) 2026 Wasted Audio # # 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 . from typing import Optional from pathlib import Path from .HeavyObject import HeavyObject from .SignalNamHeader import convert_nam_to_header, to_symbol_stem from hvcc.types.IR import IRSignalList class UnknownModelException(Exception): def __str__(self): return "Unknown NAM model used." class SignalNam(HeavyObject): preamble = "sNam" @classmethod def get_C_struct(cls, obj_type: str = "") -> str: if obj_type == '__nam_nano~f': return "SignalNamNano" elif obj_type == '__nam_feather~f': return "SignalNamFeather" elif obj_type == '__nam_lite~f': return "SignalNamLite" elif obj_type == '__nam_standard~f': return "SignalNamStandard" else: raise UnknownModelException() @classmethod def get_C_header_set(cls) -> set: return {"HvSignalNam.h"} @classmethod def get_C_file_set(cls) -> set: return { "HvSignalNam.h", "HvSignalNam.c", "MicroNAM_C.h", "MicroNAM_C.cpp", "MicroNam/MicroNAM.h", "MicroNam/include/StandardNet.h", "MicroNam/include/NanoNet.h", "MicroNam/include/LiteNet.h", "MicroNam/include/FeatherNet.h" } @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: dict) -> list[str]: nam_file = Path(args["nam"]) weights = to_symbol_stem(nam_file) if obj_type == '__nam_nano~f': return [f"sNam_nano_init(&sNam_{obj_id}, {weights}Weights);"] elif obj_type == '__nam_feather~f': return [f"sNam_feather_init(&sNam_{obj_id}, {weights}Weights);"] elif obj_type == '__nam_lite~f': return [f"sNam_lite_init(&sNam_{obj_id}, {weights}Weights);"] elif obj_type == '__nam_standard~f': return [f"sNam_standard_init(&sNam_{obj_id}, {weights}Weights);"] else: raise UnknownModelException() @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: dict) -> list[str]: if obj_type == '__nam_nano~f': return [f"sNam_nano_free(&sNam_{obj_id});"] elif obj_type == '__nam_feather~f': return [f"sNam_feather_free(&sNam_{obj_id});"] elif obj_type == '__nam_lite~f': return [f"sNam_lite_free(&sNam_{obj_id});"] elif obj_type == '__nam_standard~f': return [f"sNam_standard_free(&sNam_{obj_id});"] else: raise UnknownModelException() @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: dict) -> list[str]: if obj_type == '__nam_nano~f': function = "__hv_nam_nano_f(&sNam_{0}, VIf({1}), VOf({2}));" elif obj_type == '__nam_feather~f': function = "__hv_nam_feather_f(&sNam_{0}, VIf({1}), VOf({2}));" elif obj_type == '__nam_lite~f': function = "__hv_nam_lite_f(&sNam_{0}, VIf({1}), VOf({2}));" elif obj_type == '__nam_standard~f': function = "__hv_nam_standard_f(&sNam_{0}, VIf({1}), VOf({2}));" else: raise UnknownModelException() return [ function.format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.outputBuffers[0])) ] @classmethod def get_C_gen_header_code(cls, obj_type: str, obj_id: str, args: dict) -> Optional[tuple[str, str]]: nam_file = Path(args["nam"]) header_name = f"{to_symbol_stem(nam_file)}.h" header_str = convert_nam_to_header(nam_file) return header_name, header_str hvcc-0.16.0/hvcc/generators/ir2c/SignalNamHeader.py0000644000000000000000000000720100000000000016677 0ustar00# MIT License # # Copyright (c) 2026 Jaffx Audio Inc. # Copyright (c) 2026 Wasted Audio # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import re import json from enum import Enum from pathlib import Path """ Vendored and modified from MicroNAM https://github.com/jaffco/MicroNAM """ class ModelNet(Enum): Nano = 1 Feather = 2 Lite = 3 Standard = 4 def to_symbol_stem(nam_path: Path) -> str: stem = nam_path.stem.strip() if not stem: return "NamModel" # Split on non-alphanumeric boundaries, then form PascalCase. raw_parts = [p for p in re.split(r"[^A-Za-z0-9]+", stem) if p] if not raw_parts: return "NamModel" parts = [] for part in raw_parts: if part[0].isdigit(): part = f"M{part}" parts.append(part[0].upper() + part[1:]) return "".join(parts) def format_float(value: float) -> str: # Keep enough precision for model weights while staying compact. return f"{format(value, '.17g')}f" def load_nam_file(nam_file: Path) -> tuple[ModelNet, int, list[float]]: with nam_file.open("r", encoding="utf-8") as f: payload = json.load(f) if "weights" not in payload.keys() or not isinstance(payload["weights"], list): raise ValueError("Input .nam file must contain a 'weights' array") weights = payload["weights"] for idx, value in enumerate(weights): if not isinstance(value, (int, float)): raise ValueError(f"weights[{idx}] is not numeric") weights_len = len(weights) if weights_len == 842: model_net = ModelNet.Nano elif weights_len == 3026: model_net = ModelNet.Feather elif weights_len == 6554: model_net = ModelNet.Lite elif weights_len == 13802: model_net = ModelNet.Standard else: raise ValueError(f"Invalid weights length: {weights_len}") return model_net, weights_len, weights def convert_nam_to_header(nam_file: Path) -> str: symbol_stem = to_symbol_stem(nam_file) count_name = f"{symbol_stem}WeightsCount" weights_name = f"{symbol_stem}Weights" _, weights_len, weights = load_nam_file(nam_file) lines = [ "#pragma once", "", f"static const unsigned int {count_name} = {weights_len};", f"static const float {weights_name}[{count_name}] = {{", ] row = [] for idx, value in enumerate(weights, start=1): row.append(format_float(float(value))) if idx % 6 == 0: lines.append(" " + ", ".join(row) + ",") row = [] if row: lines.append(" " + ", ".join(row) + ",") lines.append("};") lines.append("") return "\n".join(lines) hvcc-0.16.0/hvcc/generators/ir2c/SignalPhasor.py0000644000000000000000000000545100000000000016314 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalPhasor(HeavyObject): c_struct = "SignalPhasor" preamble = "sPhasor" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalPhasor.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalPhasor.h", "HvSignalPhasor.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type == "__phasor~f": return [f"sPhasor_init(&sPhasor_{obj_id}, sampleRate);"] elif obj_type == "__phasor_k~f": return [f"sPhasor_k_init(&sPhasor_{obj_id}, {args['frequency']}f, sampleRate);"] else: raise Exception() @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: if obj_type == "__phasor~f": return [f"sPhasor_onMessage(_c, &Context(_c)->sPhasor_{obj_id}, {inlet_index}, m);"] elif obj_type == "__phasor_k~f": return [f"sPhasor_k_onMessage(_c, &Context(_c)->sPhasor_{obj_id}, {inlet_index}, m);"] else: raise Exception() @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type == "__phasor~f": return [ "__hv_phasor_f(&sPhasor_{0}, VIf({1}), VOf({2}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.outputBuffers[0]) ) ] elif obj_type == "__phasor_k~f": return [ "__hv_phasor_k_f(&sPhasor_{0}, VOf({1}));".format( process_dict.id, cls._c_buffer(process_dict.outputBuffers[0]) ) ] else: raise Exception(f"Unknown object type \"{obj_type}\".") hvcc-0.16.0/hvcc/generators/ir2c/SignalRPole.py0000644000000000000000000000410700000000000016076 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalRPole(HeavyObject): """Handles the __rpole~f object. """ c_struct = "SignalRpole" preamble = "sRPole" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalRPole.h", "HvSignalDel1.h", "HvMath.h"} @classmethod def get_C_file_set(cls) -> set: return { "HvSignalRPole.h", "HvSignalRPole.c", "HvSignalDel1.h", "HvSignalDel1.c", "HvMath.h" } @classmethod def get_C_def(cls, obj_type: str, obj_id: str) -> List[str]: return [f"SignalRPole sRPole_{obj_id};"] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sRPole_init(&sRPole_{obj_id});"] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_rpole_f(&sRPole_{0}, VIf({1}), VIf({2}), VOf({3}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.inputBuffers[1]), cls._c_buffer(process_dict.outputBuffers[0]))] hvcc-0.16.0/hvcc/generators/ir2c/SignalSamphold.py0000644000000000000000000000371100000000000016624 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalSamphold(HeavyObject): c_struct = "SignalSamphold" preamble = "sSamphold" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalSamphold.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalSamphold.h", "HvSignalSamphold.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sSamphold_init(&sSamphold_{obj_id});"] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: raise Exception() @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_samphold_f(&sSamphold_{0}, VIf({1}), VIf({2}), VOf({3}));".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls._c_buffer(process_dict.inputBuffers[1]), cls._c_buffer(process_dict.outputBuffers[0]))] hvcc-0.16.0/hvcc/generators/ir2c/SignalSample.py0000644000000000000000000000404500000000000016277 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalSample(HeavyObject): c_struct = "SignalSample" preamble = "sSample" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalSample.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalSample.h", "HvSignalSample.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sSample_init(&sSample_{obj_id});"] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] # nothing to free @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [ "{0}_onMessage(_c, &Context(_c)->{0}_{1}, {2}, m);".format( cls.preamble, obj_id, inlet_index) ] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_sample_f(this, &sSample_{0}, VIf({1}), &{2}_{0}_sendMessage);".format( process_dict.id, cls._c_buffer(process_dict.inputBuffers[0]), cls.preamble ) ] hvcc-0.16.0/hvcc/generators/ir2c/SignalTabhead.py0000644000000000000000000000366500000000000016415 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalTabhead(HeavyObject): """Handles __tabhead~f """ c_struct = "SignalTabhead" preamble = "sTabhead" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalTabread.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalTabread.h", "HvSignalTabread.c"} @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sTabhead_init(&sTabhead_{obj_id}, &hTable_{args['table_id']});"] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [] # TODO(mhroth): deal with this later @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "__hv_tabhead_f(&sTabhead_{0}, {1});".format( process_dict.id, ", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict.outputBuffers]) )] hvcc-0.16.0/hvcc/generators/ir2c/SignalTabread.py0000644000000000000000000000710400000000000016417 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalTabread(HeavyObject): """Handles __tabread~if, __tabread~f, __tabreadu~f, __tabread_stoppable~f """ c_struct = "SignalTabread" preamble = "sTabread" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalTabread.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalTabread.h", "HvSignalTabread.c"} @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [ "sTabread_init(&sTabread_{0}, &hTable_{1}, {2});".format( obj_id, args["table_id"], "true" if obj_type in {"__tabread~f", "__tabread_stoppable~f"} else "false")] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: if obj_type in ["__tabread~f", "__tabreadu~f", "__tabread_stoppable~f"]: return [ "sTabread_onMessage(_c, &Context(_c)->sTabread_{0}, {1}, m, &sTabread_{0}_sendMessage);".format( obj_id, inlet_index)] else: # "__tabread~if" return [f"sTabread_onMessage(_c, &Context(_c)->sTabread_{obj_id}, {inlet_index}, m, NULL);"] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type == "__tabread~if": return [ "__hv_tabread_if(&sTabread_{0}, {1}, {2});".format( process_dict.id, ", ".join([f"VIi({cls._c_buffer(b)})" for b in process_dict.inputBuffers]), ", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict.outputBuffers]) )] elif obj_type == "__tabread~f": return [ "__hv_tabread_f(&sTabread_{0}, {1});".format( process_dict.id, ", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict.outputBuffers]) )] elif obj_type == "__tabread_stoppable~f": return [ "__hv_tabread_stoppable_f(this, &sTabread_{0}, {1}, &{2}_{0}_sendMessage);".format( process_dict.id, ", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict.outputBuffers]), cls.preamble )] elif obj_type == "__tabreadu~f": return [ "__hv_tabreadu_f(&sTabread_{0}, {1});".format( process_dict.id, ", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict.outputBuffers]) )] else: raise Exception() hvcc-0.16.0/hvcc/generators/ir2c/SignalTabwrite.py0000644000000000000000000000457600000000000016650 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalTabwrite(HeavyObject): """Handles __tabwrite~f """ c_struct = "SignalTabwrite" preamble = "sTabwrite" @classmethod def get_C_header_set(cls) -> set: return {"HvSignalTabwrite.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalTabwrite.h", "HvSignalTabwrite.c"} @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [f"sTabwrite_init(&sTabwrite_{obj_id}, &hTable_{args['table_id']});"] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: return [f"sTabwrite_onMessage(_c, &Context(_c)->sTabwrite_{obj_id}, {inlet_index}, m, NULL);"] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: if obj_type == "__tabwrite~f": return [ "__hv_tabwrite_f(&sTabwrite_{0}, {1});".format( process_dict.id, ", ".join([f"VIf({cls._c_buffer(b)})" for b in process_dict.inputBuffers]) )] elif obj_type == "__tabwrite_stoppable~f": return [ "__hv_tabwrite_stoppable_f(&sTabwrite_{0}, {1});".format( process_dict.id, ", ".join([f"VIf({cls._c_buffer(b)})" for b in process_dict.inputBuffers]) )] else: raise Exception() hvcc-0.16.0/hvcc/generators/ir2c/SignalVar.py0000644000000000000000000001077200000000000015612 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, List from .HeavyObject import HeavyObject from hvcc.types.IR import IRSignalList class SignalVar(HeavyObject): __OPERATION_DICT = { "__var~f": "sVarf", "__var~i": "sVari", "__var_k~f": "__hv_var_k_f", "__var_k~i": "__hv_var_k_i", "__varwrite~f": "__hv_varwrite_f", "__varwrite~i": "__hv_varwrite_i", "__varread~f": "__hv_varread_f", "__varread~i": "__hv_varread_i" } @classmethod def get_C_struct(cls, obj_type: str = "") -> str: if obj_type == "__var~f": return "SignalVarf" elif obj_type == "__var~i": return "SignalVari" else: raise Exception() @classmethod def get_preamble(cls, obj_type: str) -> str: return cls.__OPERATION_DICT[obj_type] @classmethod def handles_type(cls, obj_type: str) -> bool: """Returns true if the object type can be handled by this class """ return obj_type in cls.__OPERATION_DICT @classmethod def get_C_header_set(cls) -> set: return {"HvSignalVar.h"} @classmethod def get_C_file_set(cls) -> set: return {"HvSignalVar.h", "HvSignalVar.c"} @classmethod def get_C_init(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: assert obj_type in ["__var~f", "__var~i"], obj_type return [ "{0}_init(&{0}_{1}, {2}, {3}, {4});".format( SignalVar.__OPERATION_DICT[obj_type], obj_id, f"{float(args['k'])}f" if obj_type.endswith("f") else int(args["k"]), f"{float(args['step'])}f" if obj_type.endswith("f") else int(args["step"]), "true" if args["reverse"] else "false")] @classmethod def get_C_free(cls, obj_type: str, obj_id: str, args: Dict) -> List[str]: return [] @classmethod def get_C_onMessage(cls, obj_type: str, obj_id: str, inlet_index: int, args: Dict) -> List[str]: assert obj_type in ["__var~f", "__var~i"] return [ "{0}_onMessage(_c, &Context(_c)->{0}_{1}, m);".format( cls.__OPERATION_DICT[obj_type], obj_id)] @classmethod def get_C_process(cls, process_dict: IRSignalList, obj_type: str, obj_id: str, args: Dict) -> List[str]: fmt = obj_type[-1] if obj_type in ["__var~f", "__var~i"]: # NOTE(mhroth): signal rate variables do not process anything return [] elif obj_type in ["__varwrite~f", "__varwrite~i"]: return [ "__hv_varwrite_{1}(&sVar{1}_{0}, VI{1}({2}));".format( args["var_id"], fmt, cls._c_buffer(process_dict.inputBuffers[0]) )] elif obj_type in ["__var_k~f", "__var_k~i"]: if args["k"] == 0.0 and args.get("step", 0.0) == 0.0: return ["__hv_zero_{0}(VO{0}({1}));".format( fmt, cls._c_buffer(process_dict.outputBuffers[0]))] else: c = [float(args["k"] + i * args.get("step", 0.0)) for i in range(8)] cx = ", ".join(["{0}f".format(f) for f in c]) if fmt == "f" else ", ".join([str(int(i)) for i in c]) return ["__hv_var_k_{0}{3}(VO{0}({1}), {2});".format( fmt, cls._c_buffer(process_dict.outputBuffers[0]), cx, "_r" if args.get("reverse", False) else "")] elif obj_type in ["__varread~f", "__varread~i"]: return [ "__hv_varread_{1}(&sVar{1}_{0}, VO{1}({2}));".format( args["var_id"], fmt, cls._c_buffer(process_dict.outputBuffers[0]) )] else: raise Exception("") hvcc-0.16.0/hvcc/generators/ir2c/__init__.py0000644000000000000000000000000000000000000015442 0ustar00hvcc-0.16.0/hvcc/generators/ir2c/expr/__init__.py0000644000000000000000000000000000000000000016420 0ustar00hvcc-0.16.0/hvcc/generators/ir2c/expr/expr_arpeggio_grammar.py0000644000000000000000000001355300000000000021243 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . from arpeggio import ParserPython, StrMatch # type: ignore from arpeggio import ZeroOrMore # type: ignore from arpeggio import RegExMatch as regex # type: ignore class SuppressStrMatch(StrMatch): suppress = True hide = SuppressStrMatch def expr(): return none # EOF # noqa def none(): return lor, ZeroOrMore(" ", lor) # needed for logical `or`: `||` # noqa def lor(): return land, ZeroOrMore("||", land) # noqa def land(): return bor, ZeroOrMore("&&", bor) # noqa def bor(): return xor, ZeroOrMore("|", xor) # noqa def xor(): return band, ZeroOrMore("^", band) # noqa def band(): return eq, ZeroOrMore("&", eq) # noqa def eq(): return gtlte, ZeroOrMore(["==","!="], gtlte) # noqa def gtlte(): return gtlt, ZeroOrMore(["<=",">="], gtlt) # noqa def gtlt(): return shift, ZeroOrMore(["<",">"], shift) # noqa def shift(): return term, ZeroOrMore(["<<",">>"], term) # noqa def term(): return factor, ZeroOrMore(["+","-"], factor) # RtoL # noqa def factor(): return unary, ZeroOrMore(["*","/","%"], unary) # noqa def unary(): return [(["-","~","!"], unary), primary] # RtoL # noqa def primary(): return [number, var, func, group] # noqa def number(): return [num_f, num_i] # noqa def var(): return regex(r"\$[fisv]\d+") # noqa def func(): return [ # noqa (f_name, hide("("), expr, hide(")")), # noqa (f_name, hide("("), expr, hide(r"\,"), expr, hide(")")), # noqa (f_name, hide("("), expr, hide(r"\,"), expr, hide(r"\,"), expr, hide(")")) # noqa ] # noqa def group(): return hide("("), expr, hide(")") # noqa def num_f(): return regex(r"\d+\.\d+") # prob need to cover exponential syntax, others? # noqa def num_i(): return regex(r"\d+") # need to cover bin/octal/hex? # noqa def f_name(): return [ # noqa regex(r"\babs(?=\()"), regex(r"\bacos(?=\()"), regex(r"\bacosh(?=\()"), regex(r"\basin(?=\()"), regex(r"\basinh(?=\()"), regex(r"\batan(?=\()"), regex(r"\batan2(?=\()"), regex(r"\batanh(?=\()"), regex(r"\bcbrt(?=\()"), regex(r"\bceil(?=\()"), regex(r"\bcopysign(?=\()"), regex(r"\bcos(?=\()"), regex(r"\bcosh(?=\()"), regex(r"\bdrem(?=\()"), regex(r"\berf(?=\()"), regex(r"\berfc(?=\()"), regex(r"\bexp(?=\()"), regex(r"\bexpm1(?=\()"), regex(r"\bfact(?=\()"), regex(r"\bfinite(?=\()"), regex(r"\bfloat(?=\()"), regex(r"\bfloor(?=\()"), regex(r"\bfmod(?=\()"), regex(r"\bif(?=\()"), regex(r"\bimodf(?=\()"), regex(r"\bint(?=\()"), regex(r"\bisinf(?=\()"), regex(r"\bisnan(?=\()"), regex(r"\bldexp(?=\()"), regex(r"\bln(?=\()"), regex(r"\blog(?=\()"), regex(r"\blog10(?=\()"), regex(r"\blog1p(?=\()"), regex(r"\bmax(?=\()"), regex(r"\bmin(?=\()"), regex(r"\bmodf(?=\()"), regex(r"\bpow(?=\()"), regex(r"\bremainder(?=\()"), regex(r"\brint(?=\()"), regex(r"\bround(?=\()"), regex(r"\bnearbyint(?=\()"), regex(r"\bsin(?=\()"), regex(r"\bsinh(?=\()"), # regex(r"\bsize(?=\()"), regex(r"\bsqrt(?=\()"), # regex(r"\bsum(?=\()"), # regex(r"\bSum(?=\()"), regex(r"\btan(?=\()"), regex(r"\btanh(?=\()"), ] expr_grammar = ParserPython(expr, reduce_tree=True) hvcc-0.16.0/hvcc/generators/ir2c/expr/expr_arpeggio_parser.py0000644000000000000000000000734500000000000021113 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . from typing import Literal, Union from arpeggio import ParsingExpression as ParseTreeNode, Terminal # type: ignore from .expr_arpeggio_grammar import expr_grammar ParseExpr = Union[ParseTreeNode, Terminal] NodeType = Literal["binary", "bound_var", "num_i", "num_f", "var", "func", "unary"] class ExprNode: def __init__( self, node_type: NodeType, value: str, nodes: list = [] ) -> None: self.type = node_type self.value = value self.nodes: list[ExprNode] = nodes def __str__(self, depth: int = 0) -> str: this = f"{' '*depth}{self.type}:{self.value}\n" for node in self.nodes: this += node.__str__(depth + 1) return this class ExprArpeggioParser(): """ These two methods are the "public" API """ @classmethod def parse(cls, expr) -> ParseExpr: """Parse the input expression and return a parse tree""" return expr_grammar.parse(expr) @classmethod def parse_to_ast(cls, expr: str) -> ExprNode: """Parse the input expression and return an AST""" return cls.to_expr_tree(cls.parse(expr)) """ Helper methods below """ @classmethod def to_expr_tree(cls, expr: ParseExpr) -> ExprNode: if expr.rule_name in ("num_i", "num_f", "var"): return ExprNode(expr.rule_name, expr.value) elif expr.rule_name == "func": return ExprNode("func", expr[0].value, [cls.to_expr_tree(p) for p in expr[1:]]) elif expr.rule_name == "unary": return ExprNode("unary", expr[0].value, [cls.to_expr_tree(expr[1])]) # elif expr.rule_name in (): # # Note: this rule is not used by any expression # # this is RtoL associativity # val = None # tmp = None # subtree = None # for i in range(len(expr)): # if i % 2 == 0: # val = cls.to_expr_tree(expr[i]) # else: # foo = ExprNode("binary", str(expr[i]), [val]) # if subtree is None: # subtree = foo # else: # assert tmp # tmp.nodes.append(foo) # tmp = foo # assert val and tmp and subtree # tmp.nodes.append(val) # return subtree elif expr.rule_name in ( "lor", "land", "bor", "xor", "band", "eq", "gtlte", "gtlt", "shift", "factor", "term" ): # this is LtoR associativity subtree = None for i in range(len(expr)): if i % 2 == 0: if subtree is None: subtree = cls.to_expr_tree(expr[i]) else: subtree.nodes.append(cls.to_expr_tree(expr[i])) else: subtree = ExprNode("binary", str(expr[i]), [subtree]) assert subtree return subtree else: raise ValueError(f"Unknown rule {expr.rule_name}") hvcc-0.16.0/hvcc/generators/ir2c/expr/expr_c_writer.py0000644000000000000000000002225300000000000017553 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . import re from typing import List, Union from .expr_arpeggio_parser import ExprArpeggioParser, ExprNode, ParseExpr class BufferAllocator: """ Class for managing the swapping of buffers from output to input in successive calls. """ def __init__(self) -> None: self._avail: set = set() self._next: int = 0 def next(self) -> int: """ If a buffer is available return it, otherwise allocate a new one and return it. """ if len(self._avail) > 0: return self._avail.pop() nxt = self._next self._next += 1 return nxt def free(self, n: int) -> None: """ Return a buffer back to the pool to be reused """ self._avail.add(n) def num_allocated(self) -> int: """ Return the buffers allocated in so far. """ return self._next class ExprCWriter: def __init__(self, expression: str): self.expression = expression self.expr_tree: ExprNode = ExprArpeggioParser.parse_to_ast(expression) self.parse_tree: ParseExpr = ExprArpeggioParser.parse(expression) self.num_buffers: Union[int, None] = None def to_ast(self) -> ExprNode: return self.expr_tree def to_parse_tree(self) -> ParseExpr: return self.parse_tree def to_c_simd( self, vv_in: Union[str, None] = None, v_out: str = "" ) -> List[str]: self._simd_bind_variables(vv_in) self._simd_replace_constants() return self._to_c_simd(v_out) def num_simd_buffers(self) -> int: if self.num_buffers is None: return len(self.to_c_simd()) return self.num_buffers def to_c_nested(self) -> str: return self._to_c_nested() def _simd_replace_constants(self) -> None: self._simd_replace_constants_R(self.expr_tree) def _simd_replace_constants_R(self, tree: ExprNode) -> None: if tree.type == "func" and tree.value.startswith("_load_"): return # don't re-replace anything for i in range(len(tree.nodes)): node = tree.nodes[i] if node.type == "num_i": tree.nodes[i] = ExprNode("func", "_load_i", [node]) elif node.type == "num_f": tree.nodes[i] = ExprNode("func", "_load_f", [node]) else: self._simd_replace_constants_R(node) def _simd_bind_variables(self, a_name: Union[str, None] = "A") -> None: assert a_name self._bind_vars_R(self.expr_tree, a_name) def _bind_vars_R(self, tree: ExprNode, a_name: str) -> None: if tree.type == "var": self._bind_var_node(tree, a_name) else: for node in tree.nodes: self._bind_vars_R(node, a_name) def _bind_var_node(self, node: ExprNode, a_name) -> None: if node.type != "var": pass parts = re.match(r"\$(v|f)(\d+)", node.value) assert parts node.value = f"{a_name}[{int(parts[2])-1}]" node.type = "bound_var" def _to_c_simd(self, v_out: str) -> List[str]: ba = BufferAllocator() lines: List[str] = [] def _to_c_simd_R(expr_tree: ExprNode, r_vec: Union[str, None] = None) -> str: if expr_tree.value == "-" and len(expr_tree.nodes) == 1: # Unary minus, treat as (0-arg) by inserting a 0-const node. zero_node = ExprNode("func", "_load_f", [ExprNode("num_f", "0.0f")]) expr_tree.nodes.insert(0, zero_node) if expr_tree.type in ("num_i", "num_f", "var", "bound_var"): return expr_tree.value args = [] buffers = [] if ( expr_tree.type == "func" and expr_tree.value.startswith("_load_") ): next_buf = f"Bf{ba.next()}" args.append(f"&{next_buf}") const_value = _to_c_simd_R(expr_tree.nodes[0]) for i in range(8): args.append(const_value) else: for node in expr_tree.nodes: val = _to_c_simd_R(node) args.append(val) if isinstance(val, str) and val.startswith("Bf"): buffers.append(val) if r_vec is not None: next_buf = r_vec args.append(next_buf) else: next_buf = f"Bf{ba.next()}" args.append(f"&{next_buf}") f_name = ExprOpMap.get_hv_func_simd(expr_tree.value) lines.append(f"{f_name}({', '.join(args)});") for b in buffers: ba.free(int(b[2])) return next_buf lines.append(_to_c_simd_R(self.expr_tree, v_out)) self.num_buffers = ba.num_allocated() return lines def _to_c_nested(self) -> str: """Output C-code as nested function calls""" def _to_c_nested_R(expr_tree: ExprNode) -> str: if expr_tree.type in ("num_i", "num_f", "var"): return expr_tree.value else: f_name = ExprOpMap.get_hv_func(expr_tree.value) args = [_to_c_nested_R(p) for p in expr_tree.nodes] return f"{f_name}({', '.join(args)})" return f"{_to_c_nested_R(self.expr_tree)};" class ExprOpMap: op_map = { "~": "hv_bit_not_f", "!": "hv_not_f", "*": "hv_mul_f", "/": "hv_div_f", "%": "hv_modulo_f", "+": "hv_add_f", "-": "hv_sub_f", "<": "hv_lt_f", "<=": "hv_lte_f", ">": "hv_gt_f", ">=": "hv_gte_f", "<<": "hv_shl_f", ">>": "hv_shr_f", "==": "hv_eq_f", "!=": "hv_neq_f", "^": "hv_exc_or_f", "&": "hv_bit_and_f", "&&": "hv_log_and_f", "|": "hv_bit_or_f", "||": "hv_log_or_f", "abs": "hv_abs_f", "acos": "hv_acos_f", "acosh": "hv_acosh_f", "asin": "hv_asin_f", "asinh": "hv_asinh_f", "atan": "hv_atan_f", "atan2": "hv_atan2_f", "atanh": "hv_atanh_f", # "avg": "hv_?_f", # averages all elements of a table # "Avg": "hv_?_f", # averages elements of a specified boundary of a table "cbrt": "hv_cbrt_f", "ceil": "hv_ceil_f", "copysign": "hv_copysign_f", "cos": "hv_cos_f", "cosh": "hv_cosh_f", "erf": "hv_erf_f", "erfc": "hv_erfc_f", "exp": "hv_exp_f", "expm1": "hv_expm1_f", "fact": "hv_fact_f", "finite": "hv_finite_f", "float": "hv_cast_if_expr", "floor": "hv_floor_f", "fmod": "hv_fmod_f", "if": "hv_if_f", "imodf": "hv_imod_f", "int": "hv_cast_fi_expr", "isinf": "hv_isinf_f", "isnan": "hv_isnan_f", "ldexp": "hv_ldexp_f", "ln": "hv_ln_f", "log": "hv_log_f", "log10": "hv_log10_f", "log1p": "hv_log1p_f", "max": "hv_max_f", "min": "hv_min_f", "modf": "hv_modf_f", "pow": "hv_pow_f", "remainder": "hv_remainder_f", "rint": "hv_rint_f", # round to nearest int "round": "hv_round_f", # round to nearest int "nearbyint": "hv_rint_f", # round to nearest int "sin": "hv_sin_f", "sinh": "hv_sinh_f", # "size": "hv_?_f", # size of a table "sqrt": "hv_sqrt_f", # "sum": "hv_?_f", # sum of all elements of a table # "Sum": "hv_?_f", # sum of elemnets of a specified boundary of a table "tan": "hv_tan_f", "tanh": "hv_tanh_f", "_load_f": "hv_var_k_f", "_load_i": "hv_var_k_i", } @classmethod def get_hv_func(cls, symbol: str) -> str: return cls.op_map[symbol] @classmethod def get_hv_func_simd(cls, symbol: str) -> str: return f"__{cls.op_map[symbol]}" hvcc-0.16.0/hvcc/generators/ir2c/ir2c.py0000644000000000000000000003606500000000000014566 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import argparse import jinja2 import json import shutil import time from collections import Counter from collections import OrderedDict from pathlib import Path from typing import Dict, List, Optional, Type, Union from hvcc.generators.ir2c.PrettyfyC import PrettyfyC from hvcc.generators.copyright import copyright_manager from hvcc.generators.ir2c.ControlBinop import ControlBinop from hvcc.generators.ir2c.ControlCast import ControlCast from hvcc.generators.ir2c.ControlDelay import ControlDelay from hvcc.generators.ir2c.ControlExpr import ControlExpr from hvcc.generators.ir2c.ControlIf import ControlIf from hvcc.generators.ir2c.ControlMessage import ControlMessage from hvcc.generators.ir2c.ControlPack import ControlPack from hvcc.generators.ir2c.ControlPrint import ControlPrint from hvcc.generators.ir2c.ControlReceive import ControlReceive from hvcc.generators.ir2c.ControlRandom import ControlRandom from hvcc.generators.ir2c.ControlSend import ControlSend from hvcc.generators.ir2c.ControlSlice import ControlSlice from hvcc.generators.ir2c.ControlSwitchcase import ControlSwitchcase from hvcc.generators.ir2c.ControlSystem import ControlSystem from hvcc.generators.ir2c.ControlTabhead import ControlTabhead from hvcc.generators.ir2c.ControlTabread import ControlTabread from hvcc.generators.ir2c.ControlTabwrite import ControlTabwrite from hvcc.generators.ir2c.ControlUnop import ControlUnop from hvcc.generators.ir2c.ControlVar import ControlVar from hvcc.generators.ir2c.HeavyObject import HeavyObject from hvcc.generators.ir2c.HeavyTable import HeavyTable from hvcc.generators.ir2c.SignalConvolution import SignalConvolution from hvcc.generators.ir2c.SignalBiquad import SignalBiquad from hvcc.generators.ir2c.SignalCPole import SignalCPole from hvcc.generators.ir2c.SignalDel1 import SignalDel1 from hvcc.generators.ir2c.SignalEnvelope import SignalEnvelope from hvcc.generators.ir2c.SignalExpr import SignalExpr from hvcc.generators.ir2c.SignalLine import SignalLine from hvcc.generators.ir2c.SignalLorenz import SignalLorenz from hvcc.generators.ir2c.SignalNam import SignalNam from hvcc.generators.ir2c.SignalMath import SignalMath from hvcc.generators.ir2c.SignalPhasor import SignalPhasor from hvcc.generators.ir2c.SignalRPole import SignalRPole from hvcc.generators.ir2c.SignalSample import SignalSample from hvcc.generators.ir2c.SignalSamphold import SignalSamphold from hvcc.generators.ir2c.SignalTabhead import SignalTabhead from hvcc.generators.ir2c.SignalTabread import SignalTabread from hvcc.generators.ir2c.SignalTabwrite import SignalTabwrite from hvcc.generators.ir2c.SignalVar import SignalVar from hvcc.types.compiler import CompilerResp, ExternInfo from hvcc.types.IR import IRGraph class ir2c: __OBJECT_CLASS_DICT = { "__delay": ControlDelay, "__if": ControlIf, "__print": ControlPrint, "__random": ControlRandom, "__var": ControlVar, "__table": HeavyTable, "__cast_b": ControlCast, "__cast_f": ControlCast, "__cast_s": ControlCast, "__expr": ControlExpr, "__expr~": SignalExpr, "__message": ControlMessage, "__system": ControlSystem, "__receive": ControlReceive, "__switchcase": ControlSwitchcase, "__conv~f": SignalConvolution, "__biquad~f": SignalBiquad, "__biquad_k~f": SignalBiquad, "__env~f": SignalEnvelope, "__line~f": SignalLine, "__lorenz~f": SignalLorenz, "__nam_nano~f": SignalNam, "__nam_feather~f": SignalNam, "__nam_lite~f": SignalNam, "__nam_standard~f": SignalNam, "__del1~f": SignalDel1, "__tabread~if": SignalTabread, "__tabread~f": SignalTabread, "__tabreadu~f": SignalTabread, "__tabread_stoppable~f": SignalTabread, "__tabhead~f": SignalTabhead, "__tabwrite~f": SignalTabwrite, "__tabwrite_stoppable~f": SignalTabwrite, "__phasor~f": SignalPhasor, "__phasor_k~f": SignalPhasor, "__sample~f": SignalSample, "__samphold~f": SignalSamphold, "__slice": ControlSlice, "__send": ControlSend, "__tabhead": ControlTabhead, "__tabread": ControlTabread, "__tabwrite": ControlTabwrite, "__pack": ControlPack, "__rpole~f": SignalRPole, "__cpole~f": SignalCPole } # the base set of C files necessary for the patch __BASE_FILE_SET = { "HeavyContextInterface.hpp", "HeavyContext.hpp", "HeavyContext.cpp", "HvHeavy.h", "HvHeavyInternal.h", "HvHeavy.cpp", "HvUtils.h", "HvUtils.c", "HvMath.h", "HvMessageQueue.h", "HvMessageQueue.c", "HvMessagePool.h", "HvMessagePool.c", "HvTable.h", "HvTable.c", "HvMessage.h", "HvMessage.c", "HvLightPipe.h", "HvLightPipe.c" } @classmethod def filter_hvhash(cls, x: Union[float, str]) -> str: """ Return the hash string of an object. """ return HeavyObject.get_hash_string(x) @classmethod def filter_extern(cls, d: Dict) -> Dict: """ Return a dictionary of objects that are externed. """ return {k: v for k, v in d.items() if v.extern} @classmethod def get_class(cls, obj_type: str) -> Type[HeavyObject]: if SignalMath.handles_type(obj_type): return SignalMath elif ControlBinop.handles_type(obj_type): return ControlBinop elif ControlUnop.handles_type(obj_type): return ControlUnop elif SignalVar.handles_type(obj_type): return SignalVar elif obj_type in ir2c.__OBJECT_CLASS_DICT: return ir2c.__OBJECT_CLASS_DICT[obj_type] else: raise Exception(f"No class found for object type \"{obj_type}\".") @classmethod def compile( cls, hv_ir_path: Path, static_dir: Path, output_dir: Path, externs: ExternInfo, copyright: Optional[str] = None, nodsp: Optional[bool] = False ) -> CompilerResp: """ Compiles a HeavyIR file into a C. Returns a tuple of compile time in seconds, a notification dictionary, and a HeavyIR object counter. """ # keep track of the total compile time tick = time.time() # establish the jinja environment env = jinja2.Environment() env.filters["hvhash"] = cls.filter_hvhash env.filters["extern"] = cls.filter_extern env.loader = jinja2.FileSystemLoader( Path(Path(__file__).parent, "templates")) # read the hv.ir.json file with open(hv_ir_path, "r") as f: ir = IRGraph(**json.load(f)) # the project name to be used as a part of file and function names name = ir.name.escaped # generate the copyright copyright = copyright_manager.get_copyright_for_c(copyright) # # Parse the hv.ir data structure and generate C-language strings. # # Reset the obj_eval_functions state SignalExpr.obj_eval_functions = {} # generate set of header files to include include_set = set([x for o in ir.objects.values() for x in ir2c.get_class(o.type).get_C_header_set()]) # generate set of files to add to project file_set = set([x for o in ir.objects.values() for x in ir2c.get_class(o.type).get_C_file_set()]) file_set.update(ir2c.__BASE_FILE_SET) # generate object definition and initialisation list init_list: List = [] free_list = [] def_list = [] decl_list = [] obj_header_lines = [] obj_impl_lines = [] class_header_lines = [] class_impl_lines = [] gen_header_files: list[tuple[str, str]] = [] for obj_id in ir.init.order: o = ir.objects[obj_id] obj_class = ir2c.get_class(o.type) init_raw = obj_class.get_C_init(o.type, obj_id, o.args) for init in init_raw: # render name into Expr inits init_render = env.from_string(init).render(name=name) init_list.append(init_render) def_list.extend(obj_class.get_C_def(o.type, obj_id)) free_list.extend(obj_class.get_C_free(o.type, obj_id, o.args)) impl_list = [] for x in ir.control.sendMessage: obj_id = x.id o = ir.objects[obj_id] obj_class = ir2c.get_class(o.type) impl = obj_class.get_C_impl( o.type, obj_id, x.onMessage, ir2c.get_class, ir.objects, o.args) impl_render = [] for imp in impl: # Render name into Expr impls imp_render = env.from_string(imp).render(name=name) impl_render.append(imp_render) impl_list.append("\n".join(PrettyfyC.prettyfy_list(impl_render))) decl_list.extend(obj_class.get_C_decl(o.type, obj_id, o.args)) # generate static table data initialisers table_data_list: List = [] for k, v in ir.tables.items(): o = ir.objects[v.id] obj_class = ir2c.get_class(o.type) table_data_list.extend(obj_class.get_table_data_decl( o.type, v.id, o.args)) # generate the list of functions to process process_list: List = [] process_classes: set[Type[HeavyObject]] = set() for y in ir.signal.processOrder: obj_id = y.id o = ir.objects[obj_id] obj_cls = ir2c.get_class(o.type) process_classes.add(obj_cls) process_list.extend(obj_cls.get_C_process( y, o.type, obj_id, o.args)) # Add Expr~ header and impl lines obj_header_lines.extend(obj_cls.get_C_obj_header_code( o.type, obj_id, o.args )) obj_impl_lines.extend(obj_cls.get_C_obj_impl_code( o.type, obj_id, o.args )) header = obj_cls.get_C_gen_header_code(o.type, obj_id, o.args) if header is not None: gen_header_files.append(header) include_set.add(header[0]) # Render name into Expr~ impls obj_impl_lines = [env.from_string(line).render(name=name) for line in obj_impl_lines] # once for each class for prc_cls in process_classes: class_header_lines.extend(prc_cls.get_C_class_header_code( o.type, o.args )) class_impl_lines.extend(prc_cls.get_C_class_impl_code( o.type, o.args )) # # Load the C-language template files and use the parsed strings to fill them in. # # make the output directory if necessary if not output_dir.exists(): output_dir.mkdir(parents=True) # ensure that send_receive dictionary is alphabetised by the receiver key send_receive = OrderedDict(sorted([(k, v) for k, v in ir.control.receivers.items()], key=lambda x: x[0])) # write HeavyContext.h with open(Path(output_dir, f"Heavy_{name}.hpp"), "w") as f: f.write(env.get_template("Heavy_NAME.hpp").render( name=name, include_set=include_set, decl_list=decl_list, def_list=def_list, signal=ir.signal, copyright=copyright, externs=externs, class_header_lines=class_header_lines, obj_header_lines=obj_header_lines)) # write C++ implementation with open(Path(output_dir, f"Heavy_{name}.cpp"), "w") as f: f.write(env.get_template("Heavy_NAME.cpp").render( name=name, signal=ir.signal, init_list=init_list, free_list=free_list, impl_list=impl_list, send_receive=send_receive, send_table=ir.tables, process_list=process_list, table_data_list=table_data_list, copyright=copyright, class_impl_lines=class_impl_lines, obj_impl_lines=obj_impl_lines, nodsp=nodsp)) # write C API, hv_NAME.h with open(Path(output_dir, f"Heavy_{name}.h"), "w") as f: f.write(env.get_template("Heavy_NAME.h").render( name=name, copyright=copyright, externs=externs)) # write extra headers for file, head in gen_header_files: with open(Path(output_dir, file), "w") as f: f.write(head) # copy static files to output directory for f in file_set: try: shutil.copy2( src=Path(static_dir, str(f)), dst=Path(output_dir, str(f))) except IOError: Path.mkdir(Path(output_dir, str(f)).parent, parents=True) shutil.copy2( src=Path(static_dir, str(f)), dst=Path(output_dir, str(f))) # generate HeavyIR object counter ir_counter = Counter([obj.type for obj in ir.objects.values()]) return CompilerResp( stage="ir2c", in_dir=hv_ir_path.parent, in_file=hv_ir_path, out_dir=output_dir, compile_time=(time.time() - tick), obj_counter=ir_counter ) def main() -> None: parser = argparse.ArgumentParser( description="A Heavy.IR to C-language translator.") parser.add_argument( "hv_ir_path", help="The path to the Heavy.IR file to read.") parser.add_argument( "--static_dir", default="./static", help="The path to the static C files.") parser.add_argument( "--output_dir", default="./out", help="") parser.add_argument( "--copyright", default=None, help="A string indicating the owner of the copyright.") parser.add_argument("-v", "--verbose", action="count") args = parser.parse_args() externs = ExternInfo() results = ir2c.compile( args.hv_ir_path, args.static_dir, args.output_dir, externs, args.copyright) if args.verbose: print("Total ir2c time: {0:.2f}ms".format(results.compile_time * 1000)) if __name__ == "__main__": main() hvcc-0.16.0/hvcc/generators/ir2c/ir2c_perf.py0000644000000000000000000001040300000000000015566 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import argparse import json from collections import Counter, defaultdict from typing import Dict from pathlib import Path from hvcc.types.IR import HeavyIRType, IRGraph class ir2c_perf: @classmethod def perf( cls, ir: IRGraph, blocksize: int = 512, mhz: int = 1000, verbose: bool = False ) -> Dict[str, Dict[str, float]]: # read the hv.ir.json file with open(Path(Path(__file__).parent, "../../core/json/heavy.ir.json"), "r") as f: HEAVY_IR_JSON = HeavyIRType(**json.load(f)).root objects: Counter = Counter() perf: Dict[str, float] = defaultdict(float) per_object_perf: Dict[str, Dict[str, float]] = defaultdict(lambda: defaultdict(float)) for o in ir.signal.processOrder: obj_id = o.id obj_type = ir.objects[obj_id].type if obj_type in HEAVY_IR_JSON.keys(): objects[obj_type] += 1 obj_perf = HEAVY_IR_JSON[obj_type].perf assert obj_perf is not None c = defaultdict(float, **obj_perf.model_dump()) for k, v in c.items(): perf[k] = perf[k] + v per_object_perf[obj_type][k] = per_object_perf[obj_type][k] + v else: print(f"ERROR: Unknown object type {obj_type}") if verbose: print("AVX: {0} cycles / {1} cycles per frame".format(perf["avx"], perf["avx"] / 8.0)) print(" {0} frames @ {1}MHz >= {2:.2f}us".format( blocksize, mhz, blocksize * perf["avx"] / 8.0 / mhz)) print() # new line print("SSE: {0} cycles / {1} cycles per frame".format(perf["sse"], perf["sse"] / 4.0)) print(" {0} frames @ {1}MHz >= {2:.2f}us".format( blocksize, mhz, blocksize * perf["sse"] / 4.0 / mhz)) print() # new line print("NEON: {0} cycles / {1} cycles per frame".format(perf["neon"], perf["neon"] / 4.0)) print(" {0} frames @ {1}MHz >= {2:.2f}us".format( blocksize, mhz, blocksize * perf["neon"] / 4.0 / mhz)) print() # new line print("{0:<4} {1:<5} {2:<16} {3}".format("CPU%", "#Objs", "Object Type", "Performance")) print("==== ===== ================ ===========") # print object in order of highest load items = per_object_perf.items() # items.sort(key=lambda o: o[1]["avx"], reverse=True) for k, v in items: if perf["avx"] > 0: print( "{2:>2.2g}% {3:<5} {0:<16} {1}".format( k, dict(v), int(100.0 * v["avx"] / perf["avx"]), objects[k]) ) return per_object_perf def main() -> None: parser = argparse.ArgumentParser( description="A Heavy.IR to C-language translator.") parser.add_argument( "hv_ir_path", help="The path to the Heavy.IR file to read.") parser.add_argument("--mhz", default=1000, type=float, help="the CPU clock frequency in MHz") parser.add_argument("--blocksize", default=64, type=int, help="the number of frames per block") parser.add_argument("-v", "--verbose", action="count") args = parser.parse_args() # read the hv.ir.json file with open(args.hv_ir_path, "r") as f: ir = json.load(f) ir2c_perf.perf(ir, args.blocksize, args.mhz, args.verbose) if __name__ == "__main__": main() hvcc-0.16.0/hvcc/generators/ir2c/static/HeavyContext.cpp0000644000000000000000000002217300000000000017764 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HeavyContext.hpp" #include "HvTable.h" void defaultSendHook(HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg) { HeavyContext *thisContext = reinterpret_cast(context); const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(msg) - sizeof(HvMessage); ReceiverMessagePair *p = reinterpret_cast(hLp_getWriteBuffer(&thisContext->outQueue, numBytes)); if (p != nullptr) { p->receiverHash = sendHash; msg_copyToBuffer(msg, (char *) &p->msg, msg_getSize(msg)); hLp_produce(&thisContext->outQueue, numBytes); } else { hv_assert(false && "::defaultSendHook - The out message queue is full and cannot accept more messages until they " "have been processed. Try increasing the outQueueKb size in the new_with_options() constructor."); } } HeavyContext::HeavyContext(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) : sampleRate(sampleRate) { hv_assert(sampleRate > 0.0); // sample rate must be positive hv_assert(poolKb > 0); hv_assert(inQueueKb > 0); hv_assert(outQueueKb >= 0); blockStartTimestamp = 0; printHook = nullptr; userData = nullptr; // if outQueueKb is positive, then the outQueue is allocated and the default sendhook is set. // Otherwise outQueue and the sendhook are set to NULL. sendHook = (outQueueKb > 0) ? &defaultSendHook : nullptr; HV_SPINLOCK_RELEASE(inQueueLock); HV_SPINLOCK_RELEASE(outQueueLock); numBytes = sizeof(HeavyContext); numBytes += mq_initWithPoolSize(&mq, poolKb); numBytes += hLp_init(&inQueue, inQueueKb * 1024); numBytes += hLp_init(&outQueue, outQueueKb * 1024); // outQueueKb value of 0 sets everything to NULL } HeavyContext::~HeavyContext() { mq_free(&mq); hLp_free(&inQueue); hLp_free(&outQueue); } bool HeavyContext::sendBangToReceiver(hv_uint32_t receiverHash) { HvMessage *m = HV_MESSAGE_ON_STACK(1); msg_initWithBang(m, 0); bool success = sendMessageToReceiver(receiverHash, 0.0, m); return success; } bool HeavyContext::sendFloatToReceiver(hv_uint32_t receiverHash, float f) { HvMessage *m = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(m, 0, f); bool success = sendMessageToReceiver(receiverHash, 0.0, m); return success; } bool HeavyContext::sendSymbolToReceiver(hv_uint32_t receiverHash, const char *s) { hv_assert(s != nullptr); HvMessage *m = HV_MESSAGE_ON_STACK(1); msg_initWithSymbol(m, 0, (char *) s); bool success = sendMessageToReceiver(receiverHash, 0.0, m); return success; } bool HeavyContext::sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *format, ...) { hv_assert(delayMs >= 0.0); hv_assert(format != nullptr); va_list ap; va_start(ap, format); const int numElem = (int) hv_strlen(format); HvMessage *m = HV_MESSAGE_ON_STACK(numElem); msg_init(m, numElem, blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*getSampleRate()/1000.0)); for (int i = 0; i < numElem; i++) { switch (format[i]) { case 'b': msg_setBang(m, i); break; case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break; case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; default: break; } } va_end(ap); bool success = sendMessageToReceiver(receiverHash, delayMs, m); return success; } bool HeavyContext::sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) { hv_assert(delayMs >= 0.0); hv_assert(m != nullptr); const hv_uint32_t timestamp = blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*(getSampleRate()/1000.0)); ReceiverMessagePair *p = nullptr; HV_SPINLOCK_ACQUIRE(inQueueLock); const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(m) - sizeof(HvMessage); p = (ReceiverMessagePair *) hLp_getWriteBuffer(&inQueue, numBytes); if (p != nullptr) { p->receiverHash = receiverHash; msg_copyToBuffer(m, (char *) &p->msg, msg_getSize(m)); msg_setTimestamp(&p->msg, timestamp); hLp_produce(&inQueue, numBytes); } else { hv_assert(false && "::sendMessageToReceiver - The input message queue is full and cannot accept more messages until they " "have been processed. Try increasing the inQueueKb size in the new_with_options() constructor."); } HV_SPINLOCK_RELEASE(inQueueLock); return (p != nullptr); } bool HeavyContext::cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { return mq_removeMessage(&mq, m, sendMessage); } HvMessage *HeavyContext::scheduleMessageForObject(const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *), int letIndex) { HvMessage *n = mq_addMessageByTimestamp(&mq, m, letIndex, sendMessage); return n; } float *HeavyContext::getBufferForTable(hv_uint32_t tableHash) { HvTable *t = getTableForHash(tableHash); if (t != nullptr) { return hTable_getBuffer(t); } else return nullptr; } int HeavyContext::getLengthForTable(hv_uint32_t tableHash) { HvTable *t = getTableForHash(tableHash); if (t != nullptr) { return hTable_getLength(t); } else return 0; } bool HeavyContext::setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) { HvTable *t = getTableForHash(tableHash); if (t != nullptr) { hTable_resize(t, newSampleLength); return true; } else return false; } void HeavyContext::lockAcquire() { HV_SPINLOCK_ACQUIRE(inQueueLock); } bool HeavyContext::lockTry() { HV_SPINLOCK_TRY(inQueueLock); } void HeavyContext::lockRelease() { HV_SPINLOCK_RELEASE(inQueueLock); } void HeavyContext::setInputMessageQueueSize(int inQueueKb) { hv_assert(inQueueKb > 0); hLp_free(&inQueue); hLp_init(&inQueue, inQueueKb*1024); } void HeavyContext::setOutputMessageQueueSize(int outQueueKb) { hv_assert(outQueueKb > 0); hLp_free(&outQueue); hLp_init(&outQueue, outQueueKb*1024); } bool HeavyContext::getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) { *destinationHash = 0; ReceiverMessagePair *p = nullptr; hv_assert((sendHook == &defaultSendHook) && "::getNextSentMessage - this function won't do anything if the msg outQueue " "size is 0, or you've overriden the default sendhook."); if (sendHook == &defaultSendHook) { HV_SPINLOCK_ACQUIRE(outQueueLock); if (hLp_hasData(&outQueue)) { hv_uint32_t numBytes = 0; p = reinterpret_cast(hLp_getReadBuffer(&outQueue, &numBytes)); hv_assert((p != nullptr) && "::getNextSentMessage - something bad happened."); hv_assert(numBytes >= sizeof(ReceiverMessagePair)); hv_assert((numBytes <= msgLengthBytes) && "::getNextSentMessage - the sent message is bigger than the message " "passed to handle it."); *destinationHash = p->receiverHash; hv_memcpy(outMsg, &p->msg, numBytes); hLp_consume(&outQueue); } HV_SPINLOCK_RELEASE(outQueueLock); } return (p != nullptr); } hv_uint32_t HeavyContext::getHashForString(const char *str) { return hv_string_to_hash(str); } HvTable *_hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) { hv_assert(c != nullptr); return reinterpret_cast(c)->getTableForHash(tableHash); } void _hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) { hv_assert(c != nullptr); reinterpret_cast(c)->scheduleMessageForReceiver(receiverHash, m); } HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *), int letIndex) { hv_assert(c != nullptr); HvMessage *n = reinterpret_cast(c)->scheduleMessageForObject( m, sendMessage, letIndex); return n; } #ifdef __cplusplus extern "C" { #endif HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) { return _hv_table_get(c, tableHash); } void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) { _hv_scheduleMessageForReceiver(c, receiverHash, m); } HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *), int letIndex) { return _hv_scheduleMessageForObject(c, m, sendMessage, letIndex); } #ifdef __cplusplus } #endif hvcc-0.16.0/hvcc/generators/ir2c/static/HeavyContext.hpp0000644000000000000000000001024600000000000017767 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTEXT_H_ #define _HEAVY_CONTEXT_H_ #include "HeavyContextInterface.hpp" #include "HvLightPipe.h" #include "HvMessageQueue.h" #include "HvMath.h" struct HvTable; class HeavyContext : public HeavyContextInterface { public: HeavyContext(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0); virtual ~HeavyContext(); int getSize() override { return (int) numBytes; } double getSampleRate() override { return sampleRate; } hv_uint32_t getCurrentSample() override { return blockStartTimestamp; } float samplesToMilliseconds(hv_uint32_t numSamples) override { return (float) (1000.0*numSamples/sampleRate); } hv_uint32_t millisecondsToSamples(float ms) override { return (hv_uint32_t) (hv_max_f(0.0f,ms)*sampleRate/1000.0); } void setUserData(void *x) override { userData = x; } void *getUserData() override { return userData; } // hook management void setSendHook(HvSendHook_t *f) override { sendHook = f; } HvSendHook_t *getSendHook() override { return sendHook; } void setPrintHook(HvPrintHook_t *f) override { printHook = f; } HvPrintHook_t *getPrintHook() override { return printHook; } // message scheduling bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) override; bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) override; bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) override; bool sendBangToReceiver(hv_uint32_t receiverHash) override; bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) override; bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) override; // table manipulation float *getBufferForTable(hv_uint32_t tableHash) override; int getLengthForTable(hv_uint32_t tableHash) override; bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) override; // lock control void lockAcquire() override; bool lockTry() override; void lockRelease() override; // message queue management void setInputMessageQueueSize(int inQueueKb) override; void setOutputMessageQueueSize(int outQueueKb) override; bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLength) override; // utility functions static hv_uint32_t getHashForString(const char *str); protected: virtual HvTable *getTableForHash(hv_uint32_t tableHash) = 0; friend HvTable *_hv_table_get(HeavyContextInterface *, hv_uint32_t); virtual void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) = 0; friend void _hv_scheduleMessageForReceiver(HeavyContextInterface *, hv_uint32_t, HvMessage *); HvMessage *scheduleMessageForObject(const HvMessage *, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *), int); friend HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *, const HvMessage *, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *), int); friend void defaultSendHook(HeavyContextInterface *, const char *, hv_uint32_t, const HvMessage *); // object state double sampleRate; hv_uint32_t blockStartTimestamp; hv_size_t numBytes; HvMessageQueue mq; HvSendHook_t *sendHook; HvPrintHook_t *printHook; void *userData; HvLightPipe inQueue; HvLightPipe outQueue; hv_atomic_bool inQueueLock; hv_atomic_bool outQueueLock; }; #endif // _HEAVY_CONTEXT_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HeavyContextInterface.hpp0000644000000000000000000002654600000000000021622 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTEXT_INTERFACE_H_ #define _HEAVY_CONTEXT_INTERFACE_H_ #include "HvUtils.h" #ifndef _HEAVY_DECLARATIONS_ #define _HEAVY_DECLARATIONS_ class HeavyContextInterface; struct HvMessage; typedef enum { HV_PARAM_TYPE_PARAMETER_IN, HV_PARAM_TYPE_PARAMETER_OUT, HV_PARAM_TYPE_EVENT_IN, HV_PARAM_TYPE_EVENT_OUT } HvParameterType; typedef struct HvParameterInfo { const char *name; // the human readable parameter name hv_uint32_t hash; // an integer identified used by heavy for this parameter HvParameterType type; // type of this parameter float minVal; // the minimum value of this parameter float maxVal; // the maximum value of this parameter float defaultVal; // the default value of this parameter } HvParameterInfo; typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg); typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg); #endif // _HEAVY_DECLARATIONS_ class HeavyContextInterface { public: HeavyContextInterface() {} virtual ~HeavyContextInterface() {}; /** Returns the read-only user-assigned name of this patch. */ virtual const char *getName() = 0; /** Returns the number of input channels with which this context has been configured. */ virtual int getNumInputChannels() = 0; /** Returns the number of output channels with which this context has been configured. */ virtual int getNumOutputChannels() = 0; /** * Returns the total size in bytes of the context. * This value may change if tables are resized. */ virtual int getSize() = 0; /** Returns the sample rate with which this context has been configured. */ virtual double getSampleRate() = 0; /** Returns the current patch time in samples. This value is always exact. */ virtual hv_uint32_t getCurrentSample() = 0; virtual float samplesToMilliseconds(hv_uint32_t numSamples) = 0; /** Converts milliseconds to samples. Input is limited to non-negative range. */ virtual hv_uint32_t millisecondsToSamples(float ms) = 0; /** Sets a user-definable value. This value is never manipulated by Heavy. */ virtual void setUserData(void *x) = 0; /** Returns the user-defined data. */ virtual void *getUserData() = 0; /** * Set the send hook. The function is called whenever a message is sent to any send object. * Messages returned by this function should NEVER be freed. If the message must persist, call * hv_msg_copy() first. */ virtual void setSendHook(HvSendHook_t *f) = 0; /** Returns the send hook, or NULL if unset. */ virtual HvSendHook_t *getSendHook() = 0; /** Set the print hook. The function is called whenever a message is sent to a print object. */ virtual void setPrintHook(HvPrintHook_t *f) = 0; /** Returns the print hook, or NULL if unset. */ virtual HvPrintHook_t *getPrintHook() = 0; /** * Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays. * If the context has not input or output channels, the respective argument may be NULL. * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if * no, SSE or NEON, or AVX optimisation is being used, respectively. * e.g. [[LLLL][RRRR]] * * @return The number of samples processed. * * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function. */ virtual int process(float **inputBuffers, float **outputBuffer, int n) = 0; /** * Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels. * If the context has not input or output channels, the respective argument may be NULL. * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if * no, SSE or NEON, or AVX optimisation is being used, respectively. * e.g. [LLLLRRRR] * * @return The number of samples processed. * * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function. */ virtual int processInline(float *inputBuffers, float *outputBuffer, int n) = 0; /** * Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels. * If the context has not input or output channels, the respective argument may be NULL. * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if * no, SSE or NEON, or AVX optimisation is being used, respectively. * e.g. [LRLRLRLR] * * @return The number of samples processed. * * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function. */ virtual int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) = 0; /** * Sends a formatted message to a receiver that can be scheduled for the future. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ virtual bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) = 0; /** * Sends a formatted message to a receiver that can be scheduled for the future. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ virtual bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) = 0; /** * A convenience function to send a float to a receiver to be processed immediately. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ virtual bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) = 0; /** * A convenience function to send a bang to a receiver to be processed immediately. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ virtual bool sendBangToReceiver(hv_uint32_t receiverHash) = 0; /** * A convenience function to send a symbol to a receiver to be processed immediately. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ virtual bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) = 0; /** * Cancels a previously scheduled message. * * @param sendMessage May be NULL. */ virtual bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)=nullptr) = 0; /** * Returns information about each parameter such as name, hash, and range. * The total number of parameters is always returned. * * @param index The parameter index. * @param info A pointer to a HvParameterInfo struct. May be null. * * @return The total number of parameters. */ virtual int getParameterInfo(int index, HvParameterInfo *info) = 0; /** Returns a pointer to the raw buffer backing this table. DO NOT free it. */ virtual float *getBufferForTable(hv_uint32_t tableHash) = 0; /** Returns the length of this table in samples. */ virtual int getLengthForTable(hv_uint32_t tableHash) = 0; /** * Resizes the table to the given length. * * Existing contents are copied to the new table. Remaining space is cleared * if the table is longer than the original, truncated otherwise. * * @param tableHash The table identifier. * @param newSampleLength The new length of the table, in samples. * * @return False if the table could not be found. True otherwise. */ virtual bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) = 0; /** * Acquire the input message queue lock. * * This function will block until the message lock as been acquired. * Typical applications will not require the use of this function. */ virtual void lockAcquire() = 0; /** * Try to acquire the input message queue lock. * * If the lock has been acquired, hv_lock_release() must be called to release it. * Typical applications will not require the use of this function. * * @return Returns true if the lock has been acquired, false otherwise. */ virtual bool lockTry() = 0; /** * Release the input message queue lock. * * Typical applications will not require the use of this function. */ virtual void lockRelease() = 0; /** * Set the size of the input message queue in kilobytes. * * The buffer is reset and all existing contents are lost on resize. * * @param inQueueKb Must be positive i.e. at least one. */ virtual void setInputMessageQueueSize(int inQueueKb) = 0; /** * Set the size of the output message queue in kilobytes. * * The buffer is reset and all existing contents are lost on resize. * Only the default sendhook uses the outgoing message queue. If the default * sendhook is not being used, then this function is not useful. * * @param outQueueKb Must be postive i.e. at least one. */ virtual void setOutputMessageQueueSize(int outQueueKb) = 0; /** * Get the next message in the outgoing queue, will also consume the message. * Returns false if there are no messages. * * @param destinationHash a hash of the name of the receiver the message was sent to. * @param outMsg message pointer that is filled by the next message contents. * @param msgLengthBytes max length of outMsg in bytes. * * @return True if there is a message in the outgoing queue. */ virtual bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) = 0; /** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */ static hv_uint32_t getHashForString(const char *str); }; #endif // _HEAVY_CONTEXT_INTERFACE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlBinop.c0000644000000000000000000000775000000000000017715 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlBinop.h" hv_size_t cBinop_init(ControlBinop *o, float k) { o->k = k; return 0; } static float cBinop_perform_op(BinopType op, float f, float k) { switch (op) { case HV_BINOP_ADD: return f + k; case HV_BINOP_SUBTRACT: return f - k; case HV_BINOP_MULTIPLY: return f * k; case HV_BINOP_DIVIDE: return (k != 0.0f) ? (f/k) : 0.0f; case HV_BINOP_INT_DIV: { const int ik = (int) k; return (ik != 0) ? (float) (((int) f) / ik) : 0.0f; } case HV_BINOP_MOD_BIPOLAR: { const int ik = (int) k; return (ik != 0) ? (float) (((int) f) % ik) : 0.0f; } case HV_BINOP_MOD_UNIPOLAR: { f = (k == 0.0f) ? 0.0f : (float) ((int) f % (int) k); return (f < 0.0f) ? f + hv_abs_f(k) : f; } case HV_BINOP_BIT_LEFTSHIFT: return (float) (((int) f) << ((int) k)); case HV_BINOP_BIT_RIGHTSHIFT: return (float) (((int) f) >> ((int) k)); case HV_BINOP_BIT_AND: return (float) ((int) f & (int) k); case HV_BINOP_BIT_XOR: return (float) ((int) f ^ (int) k); case HV_BINOP_BIT_OR: return (float) ((int) f | (int) k); case HV_BINOP_EQ: return (f == k) ? 1.0f : 0.0f; case HV_BINOP_NEQ: return (f != k) ? 1.0f : 0.0f; case HV_BINOP_LOGICAL_AND: return ((f == 0.0f) || (k == 0.0f)) ? 0.0f : 1.0f; case HV_BINOP_LOGICAL_OR: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : 1.0f; case HV_BINOP_LESS_THAN: return (f < k) ? 1.0f : 0.0f; case HV_BINOP_LESS_THAN_EQL: return (f <= k) ? 1.0f : 0.0f; case HV_BINOP_GREATER_THAN: return (f > k) ? 1.0f : 0.0f; case HV_BINOP_GREATER_THAN_EQL: return (f >= k) ? 1.0f : 0.0f; case HV_BINOP_MAX: return hv_max_f(f, k); case HV_BINOP_MIN: return hv_min_f(f, k); case HV_BINOP_POW: return (f > 0.0f) ? hv_pow_f(f, k) : 0.0f; case HV_BINOP_ATAN2: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : hv_atan2_f(f, k); default: return 0.0f; } } void cBinop_onMessage(HeavyContextInterface *_c, ControlBinop *o, BinopType op, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { if (msg_isFloat(m, 0)) { // Note(joe): supporting Pd's ability to perform operations of packs // of floats is likely to not be supported in the future. if (msg_isFloat(m, 1)) o->k = msg_getFloat(m, 1); HvMessage *n = HV_MESSAGE_ON_STACK(1); float f = cBinop_perform_op(op, msg_getFloat(m, 0), o->k); msg_initWithFloat(n, msg_getTimestamp(m), f); sendMessage(_c, 0, n); } break; } case 1: { if (msg_isFloat(m, 0)) { o->k = msg_getFloat(m, 0); } break; } default: break; } } void cBinop_k_onMessage(HeavyContextInterface *_c, void *o, BinopType op, float k, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { if (msg_isFloat(m, 0)) { // NOTE(mhroth): Heavy does not support sending bangs to binop objects to return the previous output float f = (msg_isFloat(m, 1)) ? msg_getFloat(m, 1) : k; HvMessage *n = HV_MESSAGE_ON_STACK(1); f = cBinop_perform_op(op, msg_getFloat(m, 0), f); msg_initWithFloat(n, msg_getTimestamp(m), f); sendMessage(_c, 0, n); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlBinop.h0000644000000000000000000000376100000000000017720 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_BINOP_H_ #define _HEAVY_CONTROL_BINOP_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef enum BinopType { HV_BINOP_ADD, HV_BINOP_SUBTRACT, HV_BINOP_MULTIPLY, HV_BINOP_DIVIDE, HV_BINOP_INT_DIV, HV_BINOP_MOD_BIPOLAR, HV_BINOP_MOD_UNIPOLAR, HV_BINOP_BIT_LEFTSHIFT, HV_BINOP_BIT_RIGHTSHIFT, HV_BINOP_BIT_AND, HV_BINOP_BIT_XOR, HV_BINOP_BIT_OR, HV_BINOP_EQ, HV_BINOP_NEQ, HV_BINOP_LOGICAL_AND, HV_BINOP_LOGICAL_OR, HV_BINOP_LESS_THAN, HV_BINOP_LESS_THAN_EQL, HV_BINOP_GREATER_THAN, HV_BINOP_GREATER_THAN_EQL, HV_BINOP_MAX, HV_BINOP_MIN, HV_BINOP_POW, HV_BINOP_ATAN2 } BinopType; typedef struct ControlBinop { float k; } ControlBinop; hv_size_t cBinop_init(ControlBinop *o, float k); void cBinop_onMessage(HeavyContextInterface *_c, ControlBinop *o, BinopType op, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); void cBinop_k_onMessage(HeavyContextInterface *_c, void *o, BinopType op, float k, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_BINOP_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlCast.c0000644000000000000000000000377000000000000017536 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlCast.h" void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (castType) { case HV_CAST_BANG: { HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithBang(n, msg_getTimestamp(m)); sendMessage(_c, 0, n); break; } case HV_CAST_FLOAT: { if (msg_isFloat(m, 0)) { HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, msg_getTimestamp(m), msg_getFloat(m, 0)); sendMessage(_c, 0, n); } break; } case HV_CAST_SYMBOL: { switch (msg_getType(m, 0)) { case HV_MSG_BANG: { HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithSymbol(n, msg_getTimestamp(m), "bang"); sendMessage(_c, 0, n); break; } case HV_MSG_FLOAT: { HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithSymbol(n, msg_getTimestamp(m), "float"); sendMessage(_c, 0, n); break; } case HV_MSG_SYMBOL: { sendMessage(_c, 0, m); break; } default: return; } break; } default: return; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlCast.h0000644000000000000000000000235000000000000017534 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_CAST_H_ #define _HEAVY_CONTROL_CAST_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef enum CastType { HV_CAST_BANG, HV_CAST_FLOAT, HV_CAST_SYMBOL } CastType; void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_CAST_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlDelay.c0000644000000000000000000000701500000000000017676 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlDelay.h" hv_size_t cDelay_init(HeavyContextInterface *_c, ControlDelay *o, float delayMs) { o->delay = hv_millisecondsToSamples(_c, delayMs); hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *)); return 0; } void cDelay_onMessage(HeavyContextInterface *_c, ControlDelay *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { if (msg_compareSymbol(m, 0, "flush")) { // send all messages immediately for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) { HvMessage *n = o->msgs[i]; if (n != NULL) { msg_setTimestamp(n, msg_getTimestamp(m)); // update the timestamp to now sendMessage(_c, 0, n); // send the message hv_cancelMessage(_c, n, sendMessage); // then clear it // NOTE(mhroth): there may be a problem here if a flushed message causes a clear message to return // to this object in the same step } } hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *)); } else if (msg_compareSymbol(m, 0, "clear")) { // cancel (clear) all (pending) messages for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) { HvMessage *n = o->msgs[i]; if (n != NULL) { hv_cancelMessage(_c, n, sendMessage); } } hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *)); } else { hv_uint32_t ts = msg_getTimestamp(m); msg_setTimestamp((HvMessage *) m, ts+o->delay); // update the timestamp to set the delay int i; for (i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) { if (o->msgs[i] == NULL) { o->msgs[i] = hv_scheduleMessageForObject(_c, m, sendMessage, 0); break; } } hv_assert((i < __HV_DELAY_MAX_MESSAGES) && // scheduled message limit reached "[__delay] cannot track any more messages. Try increasing the size of __HV_DELAY_MAX_MESSAGES."); msg_setTimestamp((HvMessage *) m, ts); // return to the original timestamp } break; } case 1: { if (msg_isFloat(m,0)) { // set delay in milliseconds (cannot be negative!) o->delay = hv_millisecondsToSamples(_c, msg_getFloat(m,0)); } break; } case 2: { if (msg_isFloat(m,0)) { // set delay in samples (cannot be negative!) o->delay = (hv_uint32_t) hv_max_f(0.0f, msg_getFloat(m,0)); } break; } default: break; } } void cDelay_clearExecutingMessage(ControlDelay *o, const HvMessage *m) { for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; ++i) { if (o->msgs[i] == m) { o->msgs[i] = NULL; break; } } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlDelay.h0000644000000000000000000000272600000000000017707 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_DELAY_H_ #define _HEAVY_CONTROL_DELAY_H_ #define __HV_DELAY_MAX_MESSAGES 8 #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlDelay { hv_uint32_t delay; // delay in samples HvMessage *msgs[__HV_DELAY_MAX_MESSAGES]; } ControlDelay; hv_size_t cDelay_init(HeavyContextInterface *_c, ControlDelay *o, float delayMs); void cDelay_onMessage(HeavyContextInterface *_c, ControlDelay *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); void cDelay_clearExecutingMessage(ControlDelay *o, const HvMessage *m); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_DELAY_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlExpr.c0000644000000000000000000000375300000000000017563 0ustar00/** * Copyright (c) 2022-2025 Daniel Billotte, Wasted Audio * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlExpr.h" hv_size_t cExpr_init(ControlExpr *o, float(*eval_fptr)(const float*)) { o->eval_fptr = eval_fptr; for(int i=0; i < MAX_EXPR_ARGS; i++) { o->args[i] = 0.0f; } return 0; } void cExpr_free(ControlExpr *o) { ; } void cExpr_onMessage(HeavyContextInterface *_c, ControlExpr *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { int numElements = msg_getNumElements(m); switch (letIn) { case 0: { // first inlet stores all values of input msg and triggers an output if (msg_isBang(m,0)) { ; // pass through to sending the msg below } else { for (int i = hv_min_i(numElements, MAX_EXPR_ARGS)-1; i >= 0; --i) { if (msg_isFloat(m, i)) { o->args[i] = msg_getFloat(m, i); } } } // send result of expression HvMessage *n = HV_MESSAGE_ON_STACK(1); float f = o->eval_fptr(o->args); msg_initWithFloat(n, msg_getTimestamp(m), f); sendMessage(_c, 0, n); break; } default: { // rest of inlets just store values if (msg_isFloat(m,0)) { o->args[letIn] = msg_getFloat(m, 0); } break; } } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlExpr.h0000644000000000000000000000347700000000000017573 0ustar00/** * Copyright (c) 2022-2025 Daniel Billotte, Wasted Audio * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_EXPR_H_ #define _HEAVY_CONTROL_EXPR_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif #define MAX_EXPR_ARGS 100 typedef struct ControlExpr { float args[MAX_EXPR_ARGS]; float(*eval_fptr)(const float*); } ControlExpr; hv_size_t cExpr_init(ControlExpr *o, float(*eval_fptr)(const float*)); void cExpr_free(ControlExpr *o); void cExpr_onMessage(HeavyContextInterface *_c, ControlExpr *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); static inline float expr_imodf(float mod) { float iptr; modff(mod, &iptr); return iptr; } static inline float expr_fact(float factor) { int n = (int) factor; if(n <= 1) { // follow Pure data convention return 1; } else if(n > 34) { // follow Pure data convention return INFINITY; // C99 constant } else { float f = 1.0f; for (int i = n; i > 1; --i) { f *= i; } return f; } } #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_EXPR_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlIf.c0000644000000000000000000000257500000000000017204 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlIf.h" hv_size_t cIf_init(ControlIf *o, bool k) { o->k = k; return 0; } void cIf_onMessage(HeavyContextInterface *_c, ControlIf *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { // a "true" if will send the message from the right outlet // a "false" if gets sent out of the left outlet sendMessage(_c, o->k ? 1 : 0, m); break; } case 1: { if (msg_isFloat(m, 0)) { o->k = (msg_getFloat(m, 0) != 0.0f); } break; } default: return; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlIf.h0000644000000000000000000000234200000000000017201 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_IF_H_ #define _HEAVY_CONTROL_IF_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlIf { bool k; } ControlIf; hv_size_t cIf_init(ControlIf *o, bool k); void cIf_onMessage(HeavyContextInterface *_c, ControlIf *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_IF_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlPack.c0000644000000000000000000000500300000000000017511 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlPack.h" hv_size_t cPack_init(ControlPack *o, int nargs, ...) { hv_size_t numBytes = msg_getCoreSize(nargs); o->msg = (HvMessage *) hv_malloc(numBytes); hv_assert(o->msg != NULL); msg_init(o->msg, nargs, 0); // variable arguments are used as float initialisers for the pack elements va_list ap; va_start(ap, nargs); for (int i = 0; i < nargs; ++i) { msg_setFloat(o->msg, i, (float) va_arg(ap, double)); } va_end(ap); return numBytes; } void cPack_free(ControlPack *o) { hv_free(o->msg); } void cPack_onMessage(HeavyContextInterface *_c, ControlPack *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { // ensure let index is less than number elements in internal msg int numElements = msg_getNumElements(o->msg); switch (letIn) { case 0: { // first inlet stores all values of input msg and triggers an output for (int i = hv_min_i(numElements, msg_getNumElements(m))-1; i >= 0; --i) { switch (msg_getType(m, i)) { case HV_MSG_FLOAT: msg_setFloat(o->msg, i, msg_getFloat(m, i)); break; case HV_MSG_SYMBOL: case HV_MSG_HASH: msg_setHash(o->msg, i, msg_getHash(m, i)); break; default: break; } } msg_setTimestamp(o->msg, msg_getTimestamp(m)); sendMessage(_c, 0, o->msg); break; } default: { // rest of inlets just store values switch (msg_getType(m, 0)) { case HV_MSG_FLOAT: msg_setFloat(o->msg, letIn, msg_getFloat(m, 0)); break; case HV_MSG_SYMBOL: msg_setSymbol(o->msg, letIn, msg_getSymbol(m, 1)); break; case HV_MSG_HASH: msg_setHash(o->msg, letIn, msg_getHash(m, 0)); break; default: break; } break; } } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlPack.h0000644000000000000000000000244600000000000017526 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_PACK_H_ #define _HEAVY_CONTROL_PACK_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlPack { HvMessage *msg; } ControlPack; hv_size_t cPack_init(ControlPack *o, int nargs, ...); void cPack_free(ControlPack *o); void cPack_onMessage(HeavyContextInterface *_c, ControlPack *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_PACK_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlPrint.c0000644000000000000000000000201300000000000017725 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlPrint.h" void cPrint_onMessage(HeavyContextInterface *_c, const HvMessage *m, const char *name) { if (hv_getPrintHook(_c) != NULL) { char *s = msg_toString(m); hv_getPrintHook(_c)(_c, name, s, m); hv_free(s); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlPrint.h0000644000000000000000000000210600000000000017735 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_PRINT_H_ #define _HEAVY_CONTROL_PRINT_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif void cPrint_onMessage(HeavyContextInterface *_c, const struct HvMessage *m, const char *name); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_PRINT_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlRandom.c0000644000000000000000000000324100000000000020055 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlRandom.h" // http://www.firstpr.com.au/dsp/rand31 // http://en.wikipedia.org/wiki/Lehmer_random_number_generator hv_size_t cRandom_init(ControlRandom *o, int seed) { o->state = (seed != 0) ? seed : 1; return 0; } void cRandom_onMessage(HeavyContextInterface *_c, ControlRandom *o, int inletIndex, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (inletIndex) { case 0: { HvMessage *n = HV_MESSAGE_ON_STACK(1); o->state = (hv_uint32_t) ((((unsigned long long) o->state) * 279470273UL) % 4294967291UL); float f = ((float) (o->state >> 9)) * 0.00000011920929f; msg_initWithFloat(n, msg_getTimestamp(m), f); sendMessage(_c, 0, n); break; } case 1: { if (msg_isFloat(m,0)) { o->state = (hv_uint32_t) msg_getFloat(m,0); } break; } default: break; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlRandom.h0000644000000000000000000000242400000000000020064 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_RANDOM_H_ #define _HEAVY_CONTROL_RANDOM_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlRandom { hv_uint32_t state; } ControlRandom; hv_size_t cRandom_init(ControlRandom *o, int seed); void cRandom_onMessage(HeavyContextInterface *_c, ControlRandom *o, int letIndex, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_RANDOM_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlSlice.c0000644000000000000000000000414700000000000017702 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlSlice.h" hv_size_t cSlice_init(ControlSlice *o, int i, int n) { o->i = i; o->n = n; return 0; } void cSlice_onMessage(HeavyContextInterface *_c, ControlSlice *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { // if the start point is greater than the number of elements in the source message, do nothing if (o->i < msg_getNumElements(m)) { int x = msg_getNumElements(m) - o->i; // number of elements in the new message if (o->n > 0) x = hv_min_i(x, o->n); HvMessage *n = HV_MESSAGE_ON_STACK(x); msg_init(n, x, msg_getTimestamp(m)); hv_memcpy(&n->elem, &m->elem+o->i, x*sizeof(Element)); sendMessage(_c, 0, n); } else { // if nothing can be sliced, send a bang out of the right outlet HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithBang(n, msg_getTimestamp(m)); sendMessage(_c, 1, n); } break; } case 1: { if (msg_isFloat(m,0)) { o->i = (int) msg_getFloat(m,0); if (msg_isFloat(m,1)) { o->n = (int) msg_getFloat(m,1); } } break; } case 2: { if (msg_isFloat(m,0)) { o->n = (int) msg_getFloat(m,0); } break; } default: break; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlSlice.h0000644000000000000000000000245500000000000017707 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_SLICE_H_ #define _HEAVY_CONTROL_SLICE_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlSlice { int i; // start index int n; // length of slice } ControlSlice; hv_size_t cSlice_init(ControlSlice *o, int i, int n); void cSlice_onMessage(HeavyContextInterface *_c, ControlSlice *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_SLICE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlSystem.c0000644000000000000000000000435300000000000020126 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlSystem.h" void cSystem_onMessage(HeavyContextInterface *_c, void *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { HvMessage *n = HV_MESSAGE_ON_STACK(1); if (msg_compareSymbol(m, 0, "samplerate")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getSampleRate(_c)); } else if (msg_compareSymbol(m, 0, "numInputChannels")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getNumInputChannels(_c)); } else if (msg_compareSymbol(m, 0, "numOutputChannels")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getNumOutputChannels(_c)); } else if (msg_compareSymbol(m, 0, "currentTime")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) msg_getTimestamp(m)); } else if (msg_compareSymbol(m, 0, "table")) { // NOTE(mhroth): no need to check message format for symbols as table lookup will fail otherwise HvTable *table = hv_table_get(_c, msg_getHash(m,1)); if (table != NULL) { if (msg_compareSymbol(m, 2, "length")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getLength(table)); } else if (msg_compareSymbol(m, 2, "size")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(table)); } else if (msg_compareSymbol(m, 2, "head")) { msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(table)); } else return; } else return; } else return; sendMessage(_c, 0, n); } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlSystem.h0000644000000000000000000000221700000000000020130 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_SYSTEM_H_ #define _HEAVY_CONTROL_SYSTEM_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif void cSystem_onMessage(HeavyContextInterface *_c, void *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_SYSTEM_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlTabhead.c0000644000000000000000000000305100000000000020164 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlTabhead.h" hv_size_t cTabhead_init(ControlTabhead *o, HvTable *table) { o->table = table; return 0; } void cTabhead_onMessage(HeavyContextInterface *_c, ControlTabhead *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { if (msg_getType(m,0) == HV_MSG_BANG) { // get current head of table HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(o->table)); sendMessage(_c, 0, n); } break; } case 1: { if (msg_isHashLike(m,0)) { // set a new table o->table = hv_table_get(_c, msg_getHash(m,0)); } break; } default: break; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlTabhead.h0000644000000000000000000000245500000000000020200 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_TABHEAD_H_ #define _HEAVY_CONTROL_TABHEAD_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlTabhead { struct HvTable *table; } ControlTabhead; hv_size_t cTabhead_init(ControlTabhead *o, struct HvTable *table); void cTabhead_onMessage(HeavyContextInterface *_c, ControlTabhead *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_TABHEAD_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlTabread.c0000644000000000000000000000321300000000000020176 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlTabread.h" hv_size_t cTabread_init(ControlTabread *o, struct HvTable *table) { o->table = table; return 0; } void cTabread_onMessage(HeavyContextInterface *_c, ControlTabread *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { if (msg_isFloat(m,0) && msg_getFloat(m,0) >= 0.0f && o->table != NULL) { const hv_uint32_t x = (hv_uint32_t) msg_getFloat(m,0); if (x < hTable_getSize(o->table)) { HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, msg_getTimestamp(m), hTable_getBuffer(o->table)[x]); sendMessage(_c, 0, n); } } break; } case 1: { if (msg_isHashLike(m,0)) { o->table = hv_table_get(_c, msg_getHash(m,0)); } break; } default: return; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlTabread.h0000644000000000000000000000244600000000000020212 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_TABREAD_H_ #define _HEAVY_CONTROL_TABREAD_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlTabread { HvTable *table; } ControlTabread; hv_size_t cTabread_init(ControlTabread *o, struct HvTable *table); void cTabread_onMessage(HeavyContextInterface *_c, ControlTabread *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_TABREAD_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlTabwrite.c0000644000000000000000000000332600000000000020422 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlTabwrite.h" hv_size_t cTabwrite_init(ControlTabwrite *o, struct HvTable *table) { o->table = table; o->x = 0; return 0; } void cTabwrite_onMessage(HeavyContextInterface *_c, ControlTabwrite *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { if (msg_isFloat(m,0) && o->table != NULL) { hTable_getBuffer(o->table)[o->x] = msg_getFloat(m,0); // update Y value } break; } case 1: { if (msg_isFloat(m,0) && msg_getFloat(m,0) >= 0.0f && o->table != NULL) { const hv_uint32_t x = (hv_uint32_t) msg_getFloat(m,0); if (x < hTable_getSize(o->table)) { o->x = x; // update X value } } break; } case 2: { if (msg_isHashLike(m,0)) { o->table = hv_table_get(_c,msg_getHash(m,0)); // update table } break; } default: return; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlTabwrite.h0000644000000000000000000000251200000000000020423 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_TABRWRITE_H_ #define _HEAVY_CONTROL_TABRWRITE_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlTabwrite { struct HvTable *table; hv_uint32_t x; } ControlTabwrite; hv_size_t cTabwrite_init(ControlTabwrite *o, struct HvTable *table); void cTabwrite_onMessage(HeavyContextInterface *_c, ControlTabwrite *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_TABRWRITE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlUnop.c0000644000000000000000000000447700000000000017572 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlUnop.h" void cUnop_onMessage(HeavyContextInterface *_c, UnopType op, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { if (msg_isFloat(m, 0)) { float f = msg_getFloat(m, 0); switch (op) { case HV_UNOP_SIN: f = hv_sin_f(f); break; case HV_UNOP_SINH: f = hv_sinh_f(f); break; case HV_UNOP_COS: f = hv_cos_f(f); break; case HV_UNOP_COSH: f = hv_cosh_f(f); break; case HV_UNOP_TAN: f = hv_tan_f(f); break; case HV_UNOP_TANH: f = hv_tanh_f(f); break; case HV_UNOP_ASIN: f = hv_asin_f(f); break; case HV_UNOP_ASINH: f = hv_asinh_f(f); break; case HV_UNOP_ACOS: f = hv_acos_f(f); break; case HV_UNOP_ACOSH: f = hv_acosh_f(f); break; case HV_UNOP_ATAN: f = hv_atan_f(f); break; case HV_UNOP_ATANH: f = hv_atanh_f(f); break; case HV_UNOP_EXP: f = hv_exp_f(f); break; case HV_UNOP_ABS: f = hv_abs_f(f); break; case HV_UNOP_SQRT: f = (f > 0.0f) ? hv_sqrt_f(f) : 0.0f; break; case HV_UNOP_LOG: f = (f > 0.0f) ? hv_log_f(f) : 0.0f; break; case HV_UNOP_LOG2: f = (f > 0.0f) ? (1.442695040888963f*hv_log_f(f)) : 0.0f; break; case HV_UNOP_LOG10: f = (f > 0.0f) ? (0.434294481903252f*hv_log_f(f)) : 0.0f; break; case HV_UNOP_CEIL: f = hv_ceil_f(f); break; case HV_UNOP_FLOOR: f = hv_floor_f(f); break; case HV_UNOP_ROUND: f = hv_round_f(f); break; default: return; } HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, m->timestamp, f); sendMessage(_c, 0, n); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlUnop.h0000644000000000000000000000300200000000000017556 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_UNOP_H_ #define _HEAVY_CONTROL_UNOP_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef enum UnopType { HV_UNOP_ASIN, HV_UNOP_ASINH, HV_UNOP_ACOS, HV_UNOP_ACOSH, HV_UNOP_ATAN, HV_UNOP_ATANH, HV_UNOP_SIN, HV_UNOP_SINH, HV_UNOP_COS, HV_UNOP_COSH, HV_UNOP_TAN, HV_UNOP_TANH, HV_UNOP_EXP, HV_UNOP_ABS, HV_UNOP_SQRT, HV_UNOP_LOG, HV_UNOP_LOG2, HV_UNOP_LOG10, HV_UNOP_CEIL, HV_UNOP_FLOOR, HV_UNOP_ROUND } UnopType; void cUnop_onMessage(HeavyContextInterface *_c, UnopType op, const struct HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const struct HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_UNOP_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlVar.c0000644000000000000000000000473500000000000017376 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvControlVar.h" hv_size_t cVar_init_f(ControlVar *o, float k) { o->e.type = HV_MSG_FLOAT; o->e.data.f = k; return 0; } hv_size_t cVar_init_s(ControlVar *o, const char *s) { o->e.type = HV_MSG_HASH; o->e.data.h = hv_string_to_hash(s); return 0; } void cVar_free(ControlVar *o) { // nothing to do } void cVar_onMessage(HeavyContextInterface *_c, ControlVar *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { switch (msg_getType(m,0)) { case HV_MSG_BANG: { HvMessage *n = HV_MESSAGE_ON_STACK(1); if (o->e.type == HV_MSG_FLOAT) msg_initWithFloat(n, msg_getTimestamp(m), o->e.data.f); else if (o->e.type == HV_MSG_HASH) msg_initWithHash(n, msg_getTimestamp(m), o->e.data.h); else return; sendMessage(_c, 0, n); break; } case HV_MSG_FLOAT: { o->e.type = HV_MSG_FLOAT; o->e.data.f = msg_getFloat(m,0); sendMessage(_c, 0, m); break; } case HV_MSG_SYMBOL: case HV_MSG_HASH: { o->e.type = HV_MSG_HASH; o->e.data.h = msg_getHash(m,0); sendMessage(_c, 0, m); break; } default: return; } break; } case 1: { switch (msg_getType(m,0)) { case HV_MSG_FLOAT: { o->e.type = HV_MSG_FLOAT; o->e.data.f = msg_getFloat(m,0); break; } case HV_MSG_SYMBOL: case HV_MSG_HASH: { o->e.type = HV_MSG_HASH; o->e.data.h = msg_getHash(m,0); break; } default: break; } } default: return; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvControlVar.h0000644000000000000000000000257000000000000017376 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_CONTROL_VAR_H_ #define _HEAVY_CONTROL_VAR_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct ControlVar { Element e; // type is only ever HV_MSG_FLOAT or HV_MSG_HASH } ControlVar; hv_size_t cVar_init_f(ControlVar *o, float k); hv_size_t cVar_init_s(ControlVar *o, const char *s); void cVar_free(ControlVar *o); void cVar_onMessage(HeavyContextInterface *_c, ControlVar *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_CONTROL_VAR_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvHeavy.cpp0000644000000000000000000002371000000000000016713 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HeavyContext.hpp" #ifdef __cplusplus extern "C" { #endif #if HV_APPLE #pragma mark - Heavy Table #endif HV_EXPORT bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength) { hv_assert(c != nullptr); return c->setLengthForTable(tableHash, newSampleLength); } HV_EXPORT float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash) { hv_assert(c != nullptr); return c->getBufferForTable(tableHash); } HV_EXPORT hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash) { hv_assert(c != nullptr); return c->getLengthForTable(tableHash); } #if HV_APPLE #pragma mark - Heavy Message #endif HV_EXPORT hv_size_t hv_msg_getByteSize(hv_uint32_t numElements) { return msg_getCoreSize(numElements); } HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) { msg_init(m, numElements, timestamp); } HV_EXPORT hv_size_t hv_msg_getNumElements(const HvMessage *m) { return msg_getNumElements(m); } HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *m) { return msg_getTimestamp(m); } HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) { msg_setTimestamp(m, timestamp); } HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i) { return msg_isBang(m,i); } HV_EXPORT void hv_msg_setBang(HvMessage *m, int i) { msg_setBang(m,i); } HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i) { return msg_isFloat(m, i); } HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i) { return msg_getFloat(m,i); } HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f) { msg_setFloat(m,i,f); } HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i) { return msg_isSymbol(m,i); } HV_EXPORT const char *hv_msg_getSymbol(const HvMessage *const m, int i) { return msg_getSymbol(m,i); } HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s) { msg_setSymbol(m,i,s); } HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i) { return msg_isHash(m, i); } HV_EXPORT hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i) { return msg_getHash(m, i); } HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) { return msg_hasFormat(m, fmt); } HV_EXPORT char *hv_msg_toString(const HvMessage *const m) { return msg_toString(m); } HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m) { return msg_copy(m); } HV_EXPORT void hv_msg_free(HvMessage *m) { msg_free(m); } #if HV_APPLE #pragma mark - Heavy Common #endif HV_EXPORT int hv_getSize(HeavyContextInterface *c) { hv_assert(c != nullptr); return (int) c->getSize(); } HV_EXPORT double hv_getSampleRate(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getSampleRate(); } HV_EXPORT int hv_getNumInputChannels(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getNumInputChannels(); } HV_EXPORT int hv_getNumOutputChannels(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getNumOutputChannels(); } HV_EXPORT void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f) { hv_assert(c != nullptr); c->setPrintHook(f); } HV_EXPORT HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getPrintHook(); } HV_EXPORT void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f) { hv_assert(c != nullptr); c->setSendHook(f); } HV_EXPORT hv_uint32_t hv_stringToHash(const char *s) { return hv_string_to_hash(s); } HV_EXPORT bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash) { hv_assert(c != nullptr); return c->sendBangToReceiver(receiverHash); } HV_EXPORT bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, float x) { hv_assert(c != nullptr); return c->sendFloatToReceiver(receiverHash, x); } HV_EXPORT bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s) { hv_assert(c != nullptr); return c->sendSymbolToReceiver(receiverHash, s); } HV_EXPORT bool hv_sendMessageToReceiverV( HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...) { hv_assert(c != nullptr); hv_assert(delayMs >= 0.0); hv_assert(format != nullptr); va_list ap; va_start(ap, format); const int numElem = (int) hv_strlen(format); HvMessage *m = HV_MESSAGE_ON_STACK(numElem); msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0)); for (int i = 0; i < numElem; i++) { switch (format[i]) { case 'b': msg_setBang(m, i); break; case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break; case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break; case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break; default: break; } } va_end(ap); return c->sendMessageToReceiver(receiverHash, delayMs, m); } HV_EXPORT bool hv_sendMessageToReceiverFF( HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, double data1, double data2) { hv_assert(c != nullptr); hv_assert(delayMs >= 0.0); const int numElem = (int) 2; HvMessage *m = HV_MESSAGE_ON_STACK(numElem); msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0)); msg_setFloat(m, 0, (float) data1); msg_setFloat(m, 1, (float) data2); return c->sendMessageToReceiver(receiverHash, delayMs, m); } HV_EXPORT bool hv_sendMessageToReceiverFFF( HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, double data1, double data2, double data3) { hv_assert(c != nullptr); hv_assert(delayMs >= 0.0); const int numElem = (int) 3; HvMessage *m = HV_MESSAGE_ON_STACK(numElem); msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0)); msg_setFloat(m, 0, (float) data1); msg_setFloat(m, 1, (float) data2); msg_setFloat(m, 2, (float) data3); return c->sendMessageToReceiver(receiverHash, delayMs, m); } HV_EXPORT bool hv_sendMessageToReceiver( HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m) { hv_assert(c != nullptr); return c->sendMessageToReceiver(receiverHash, delayMs, m); } HV_EXPORT void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { hv_assert(c != nullptr); c->cancelMessage(m, sendMessage); } HV_EXPORT const char *hv_getName(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getName(); } HV_EXPORT void hv_setUserData(HeavyContextInterface *c, void *userData) { hv_assert(c != nullptr); c->setUserData(userData); } HV_EXPORT void *hv_getUserData(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getUserData(); } HV_EXPORT double hv_getCurrentTime(HeavyContextInterface *c) { hv_assert(c != nullptr); return (double) c->samplesToMilliseconds(c->getCurrentSample()); } HV_EXPORT hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->getCurrentSample(); } HV_EXPORT float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples) { hv_assert(c != nullptr); return c->samplesToMilliseconds(numSamples); } HV_EXPORT hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms) { hv_assert(c != nullptr); return c->millisecondsToSamples(ms); } HV_EXPORT int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info) { hv_assert(c != nullptr); return c->getParameterInfo(index, info); } HV_EXPORT void hv_lock_acquire(HeavyContextInterface *c) { hv_assert(c != nullptr); c->lockAcquire(); } HV_EXPORT bool hv_lock_try(HeavyContextInterface *c) { hv_assert(c != nullptr); return c->lockTry(); } HV_EXPORT void hv_lock_release(HeavyContextInterface *c) { hv_assert(c != nullptr); c->lockRelease(); } HV_EXPORT void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb) { hv_assert(c != nullptr); c->setInputMessageQueueSize(inQueueKb); } HV_EXPORT void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb) { hv_assert(c != nullptr); c->setOutputMessageQueueSize(outQueueKb); } HV_EXPORT bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength) { hv_assert(c != nullptr); hv_assert(destinationHash != nullptr); hv_assert(outMsg != nullptr); return c->getNextSentMessage(destinationHash, outMsg, msgLength); } #if HV_APPLE #pragma mark - Heavy Common #endif HV_EXPORT int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n) { hv_assert(c != nullptr); return c->process(inputBuffers, outputBuffers, n); } HV_EXPORT int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) { hv_assert(c != nullptr); return c->processInline(inputBuffers, outputBuffers, n); } HV_EXPORT int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) { hv_assert(c != nullptr); return c->processInlineInterleaved(inputBuffers, outputBuffers, n); } HV_EXPORT void hv_delete(HeavyContextInterface *c) { delete c; } #ifdef __cplusplus } #endif hvcc-0.16.0/hvcc/generators/ir2c/static/HvHeavy.h0000644000000000000000000004015200000000000016357 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_H_ #define _HEAVY_H_ #include "HvUtils.h" #ifdef __cplusplus extern "C" { #endif #ifndef _HEAVY_DECLARATIONS_ #define _HEAVY_DECLARATIONS_ #ifdef __cplusplus class HeavyContextInterface; #else typedef struct HeavyContextInterface HeavyContextInterface; #endif typedef struct HvMessage HvMessage; typedef enum { HV_PARAM_TYPE_PARAMETER_IN, HV_PARAM_TYPE_PARAMETER_OUT, HV_PARAM_TYPE_EVENT_IN, HV_PARAM_TYPE_EVENT_OUT } HvParameterType; typedef struct HvParameterInfo { const char *name; // the human readable parameter name hv_uint32_t hash; // an integer identified used by heavy for this parameter HvParameterType type; // type of this parameter float minVal; // the minimum value of this parameter float maxVal; // the maximum value of this parameter float defaultVal; // the default value of this parameter } HvParameterInfo; typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg); typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg); #endif // _HEAVY_DECLARATIONS_ #if HV_APPLE #pragma mark - Heavy Context #endif /** Deletes a patch instance. */ void hv_delete(HeavyContextInterface *c); #if HV_APPLE #pragma mark - Heavy Process #endif /** * Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays. * If the context has not input or output channels, the respective argument may be NULL. * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if * no, SSE or NEON, or AVX optimisation is being used, respectively. * e.g. [[LLLL][RRRR]] * This function support in-place processing. * * @return The number of samples processed. * * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function. */ int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n); /** * Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels. * If the context has not input or output channels, the respective argument may be NULL. * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if * no, SSE or NEON, or AVX optimisation is being used, respectively. * e.g. [LLLLRRRR] * This function support in-place processing. * * @return The number of samples processed. * * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function. */ int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n); /** * Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels. * If the context has not input or output channels, the respective argument may be NULL. * The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if * no, SSE or NEON, or AVX optimisation is being used, respectively. * e.g. [LRLRLRLR] * This function support in-place processing. * * @return The number of samples processed. * * This function is NOT thread-safe. It is assumed that only the audio thread will execute this function. */ int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n); #if HV_APPLE #pragma mark - Heavy Common #endif /** * Returns the total size in bytes of the context. * This value may change if tables are resized. */ int hv_getSize(HeavyContextInterface *c); /** Returns the sample rate with which this context has been configured. */ double hv_getSampleRate(HeavyContextInterface *c); /** Returns the number of input channels with which this context has been configured. */ int hv_getNumInputChannels(HeavyContextInterface *c); /** Returns the number of output channels with which this context has been configured. */ int hv_getNumOutputChannels(HeavyContextInterface *c); /** Set the print hook. The function is called whenever a message is sent to a print object. */ void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f); /** Returns the print hook, or NULL. */ HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c); /** * Set the send hook. The function is called whenever a message is sent to any send object. * Messages returned by this function should NEVER be freed. If the message must persist, call * hv_msg_copy() first. */ void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f); /** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */ hv_uint32_t hv_stringToHash(const char *s); /** * A convenience function to send a bang to a receiver to be processed immediately. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash); /** * A convenience function to send a float to a receiver to be processed immediately. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, const float x); /** * A convenience function to send a symbol to a receiver to be processed immediately. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s); /** * Sends a formatted message to a receiver that can be scheduled for the future. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendMessageToReceiverV(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...); /** * Sends a fixed formatted message of two floats to a receiver that can be scheduled for the future. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendMessageToReceiverFF(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, double data1, double data2); /** * Sends a fixed formatted message of three floats to a receiver that can be scheduled for the future. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendMessageToReceiverFFF(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, double data1, double data2, double data3); /** * Sends a message to a receiver that can be scheduled for the future. * The receiver is addressed with its hash, which can also be determined using hv_stringToHash(). * This function is thread-safe. * * @return True if the message was accepted. False if the message could not fit onto * the message queue to be processed this block. */ bool hv_sendMessageToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m); /** * Cancels a previously scheduled message. * * @param sendMessage May be NULL. */ void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); /** Returns the read-only user-assigned name of this patch. */ const char *hv_getName(HeavyContextInterface *c); /** Sets a user-definable value. This value is never manipulated by Heavy. */ void hv_setUserData(HeavyContextInterface *c, void *userData); /** Returns the user-defined data. */ void *hv_getUserData(HeavyContextInterface *c); /** Returns the current patch time in milliseconds. This value may have rounding errors. */ double hv_getCurrentTime(HeavyContextInterface *c); /** Returns the current patch time in samples. This value is always exact. */ hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c); /** * Returns information about each parameter such as name, hash, and range. * The total number of parameters is always returned. * * @param index The parameter index. * @param info A pointer to a HvParameterInfo struct. May be null. * * @return The total number of parameters. */ int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info); /** */ float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples); /** Converts milliseconds to samples. Input is limited to non-negative range. */ hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms); /** * Acquire the input message queue lock. * * This function will block until the message lock as been acquired. * Typical applications will not require the use of this function. * * @param c A Heavy context. */ void hv_lock_acquire(HeavyContextInterface *c); /** * Try to acquire the input message queue lock. * * If the lock has been acquired, hv_lock_release() must be called to release it. * Typical applications will not require the use of this function. * * @param c A Heavy context. * * @return Returns true if the lock has been acquired, false otherwise. */ bool hv_lock_try(HeavyContextInterface *c); /** * Release the input message queue lock. * * Typical applications will not require the use of this function. * * @param c A Heavy context. */ void hv_lock_release(HeavyContextInterface *c); /** * Set the size of the input message queue in kilobytes. * * The buffer is reset and all existing contents are lost on resize. * * @param c A Heavy context. * @param inQueueKb Must be positive i.e. at least one. */ void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb); /** * Set the size of the output message queue in kilobytes. * * The buffer is reset and all existing contents are lost on resize. * Only the default sendhook uses the outgoing message queue. If the default * sendhook is not being used, then this function is not useful. * * @param c A Heavy context. * @param outQueueKb Must be postive i.e. at least one. */ void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb); /** * Get the next message in the outgoing queue, will also consume the message. * Returns false if there are no messages. * * @param c A Heavy context. * @param destinationHash a hash of the name of the receiver the message was sent to. * @param outMsg message pointer that is filled by the next message contents. * @param msgLength length of outMsg in bytes. * * @return True if there is a message in the outgoing queue. */ bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength); #if HV_APPLE #pragma mark - Heavy Message #endif typedef struct HvMessage HvMessage; /** Returns the total size in bytes of a HvMessage with a number of elements on the heap. */ unsigned long hv_msg_getByteSize(hv_uint32_t numElements); /** Initialise a HvMessage structure with the number of elements and a timestamp (in samples). */ void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp); /** Returns the number of elements in this message. */ unsigned long hv_msg_getNumElements(const HvMessage *m); /** Returns the time at which this message exists (in samples). */ hv_uint32_t hv_msg_getTimestamp(const HvMessage *m); /** Set the time at which this message should be executed (in samples). */ void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp); /** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */ bool hv_msg_isBang(const HvMessage *const m, int i); /** Sets the indexed element to a bang. Index is not bounds checked. */ void hv_msg_setBang(HvMessage *m, int i); /** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */ bool hv_msg_isFloat(const HvMessage *const m, int i); /** Returns the indexed element as a float value. Index is not bounds checked. */ float hv_msg_getFloat(const HvMessage *const m, int i); /** Sets the indexed element to float value. Index is not bounds checked. */ void hv_msg_setFloat(HvMessage *m, int i, float f); /** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */ bool hv_msg_isSymbol(const HvMessage *const m, int i); /** Returns the indexed element as a symbol value. Index is not bounds checked. */ const char *hv_msg_getSymbol(const HvMessage *const m, int i); /** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */ bool hv_msg_isHash(const HvMessage *const m, int i); /** Returns the indexed element as a hash value. Index is not bounds checked. */ hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i); /** Sets the indexed element to symbol value. Index is not bounds checked. */ void hv_msg_setSymbol(HvMessage *m, int i, const char *s); /** * Returns true if the message has the given format, in number of elements and type. False otherwise. * Valid element types are: * 'b': bang * 'f': float * 's': symbol * * For example, a message with three floats would have a format of "fff". A single bang is "b". * A message with two symbols is "ss". These types can be mixed and matched in any way. */ bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt); /** * Returns a basic string representation of the message. * The character array MUST be deallocated by the caller. */ char *hv_msg_toString(const HvMessage *const m); /** Copy a message onto the stack. The message persists. */ HvMessage *hv_msg_copy(const HvMessage *const m); /** Free a copied message. */ void hv_msg_free(HvMessage *m); #if HV_APPLE #pragma mark - Heavy Table #endif /** * Resizes the table to the given length. * * Existing contents are copied to the new table. Remaining space is cleared * if the table is longer than the original, truncated otherwise. * * @param tableHash The table identifier. * @param newSampleLength The new length of the table, in samples. Must be positive. * * @return False if the table could not be found. True otherwise. */ bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength); /** Returns a pointer to the raw buffer backing this table. DO NOT free it. */ float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash); /** Returns the length of this table in samples. */ hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvHeavyInternal.h0000644000000000000000000000260400000000000020054 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_INTERNAL_H_ #define _HEAVY_INTERNAL_H_ #include "HvHeavy.h" #include "HvUtils.h" #include "HvTable.h" #include "HvMessage.h" #include "HvMath.h" #ifdef __cplusplus extern "C" { #endif /** * */ HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash); /** * */ void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m); /** * */ HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *), int letIndex); #ifdef __cplusplus } #endif #endif hvcc-0.16.0/hvcc/generators/ir2c/static/HvLightPipe.c0000644000000000000000000001133000000000000017157 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvLightPipe.h" #if __SSE__ || HV_SIMD_SSE #include #define hv_sfence() _mm_sfence() #elif __arm__ || HV_SIMD_NEON #if __ARM_ACLE #include // https://msdn.microsoft.com/en-us/library/hh875058.aspx#BarrierRestrictions // http://doxygen.reactos.org/d8/d47/armintr_8h_a02be7ec76ca51842bc90d9b466b54752.html #define hv_sfence() __dmb(0xE) /* _ARM_BARRIER_ST */ #elif defined(__GNUC__) && (__ARM_ARCH >= 7) #define hv_sfence() __asm__ volatile ("dmb 0xE":::"memory") #else // http://stackoverflow.com/questions/19965076/gcc-memory-barrier-sync-synchronize-vs-asm-volatile-memory #define hv_sfence() __sync_synchronize() #endif #elif HV_WIN // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208(v=vs.85).aspx #define hv_sfence() _WriteBarrier() #else #define hv_sfence() __asm__ volatile("" : : : "memory") #endif #define HLP_STOP 0 #define HLP_LOOP 0xFFFFFFFF #define HLP_SET_UINT32_AT_BUFFER(a, b) (*((hv_uint32_t *) (a)) = (b)) #define HLP_GET_UINT32_AT_BUFFER(a) (*((hv_uint32_t *) (a))) hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes) { if (numBytes > 0) { q->buffer = (char *) hv_malloc(numBytes); hv_assert(q->buffer != NULL); HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP); } else { q->buffer = NULL; } q->writeHead = q->buffer; q->readHead = q->buffer; q->len = numBytes; q->remainingBytes = numBytes; return numBytes; } void hLp_free(HvLightPipe *q) { hv_free(q->buffer); } hv_uint32_t hLp_hasData(HvLightPipe *q) { hv_uint32_t x = HLP_GET_UINT32_AT_BUFFER(q->readHead); if (x == HLP_LOOP) { q->readHead = q->buffer; x = HLP_GET_UINT32_AT_BUFFER(q->readHead); } return x; } char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t bytesToWrite) { char *const readHead = q->readHead; char *const oldWriteHead = q->writeHead; const hv_uint32_t totalByteRequirement = bytesToWrite + 2*sizeof(hv_uint32_t); // check if there is enough space to write the data in the remaining // length of the buffer if (totalByteRequirement <= q->remainingBytes) { char *const newWriteHead = oldWriteHead + sizeof(hv_uint32_t) + bytesToWrite; // check if writing would overwrite existing data in the pipe (return NULL if so) if ((oldWriteHead < readHead) && (newWriteHead >= readHead)) return NULL; else return (oldWriteHead + sizeof(hv_uint32_t)); } else { // there isn't enough space, try looping around to the start if (totalByteRequirement <= q->len) { if ((oldWriteHead < readHead) || ((q->buffer + totalByteRequirement) > readHead)) { return NULL; // overwrite condition } else { q->writeHead = q->buffer; q->remainingBytes = q->len; HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP); hv_sfence(); HLP_SET_UINT32_AT_BUFFER(oldWriteHead, HLP_LOOP); return q->buffer + sizeof(hv_uint32_t); } } else { return NULL; // there isn't enough space to write the data } } } void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes) { hv_assert(q->remainingBytes >= (numBytes + 2*sizeof(hv_uint32_t))); q->remainingBytes -= (sizeof(hv_uint32_t) + numBytes); char *const oldWriteHead = q->writeHead; q->writeHead += (sizeof(hv_uint32_t) + numBytes); HLP_SET_UINT32_AT_BUFFER(q->writeHead, HLP_STOP); // save everything before this point to memory hv_sfence(); // then save this HLP_SET_UINT32_AT_BUFFER(oldWriteHead, numBytes); } char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes) { *numBytes = HLP_GET_UINT32_AT_BUFFER(q->readHead); char *const readBuffer = q->readHead + sizeof(hv_uint32_t); return readBuffer; } void hLp_consume(HvLightPipe *q) { hv_assert(HLP_GET_UINT32_AT_BUFFER(q->readHead) != HLP_STOP); q->readHead += sizeof(hv_uint32_t) + HLP_GET_UINT32_AT_BUFFER(q->readHead); } void hLp_reset(HvLightPipe *q) { q->writeHead = q->buffer; q->readHead = q->buffer; q->remainingBytes = q->len; memset(q->buffer, 0, q->len); } hvcc-0.16.0/hvcc/generators/ir2c/static/HvLightPipe.h0000644000000000000000000000631200000000000017170 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_LIGHTPIPE_H_ #define _HEAVY_LIGHTPIPE_H_ #include "HvUtils.h" #ifdef __cplusplus extern "C" { #endif /* * This pipe assumes that there is only one producer thread and one consumer * thread. This data structure does not support any other configuration. */ typedef struct HvLightPipe { char *buffer; char *writeHead; char *readHead; hv_uint32_t len; hv_uint32_t remainingBytes; // total bytes from write head to end } HvLightPipe; /** * Initialise the pipe with a given length, in bytes. * @return Returns the size of the pipe in bytes. */ hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes); /** * Frees the internal buffer. * @param q The light pipe. */ void hLp_free(HvLightPipe *q); /** * Indicates if data is available for reading. * @param q The light pipe. * * @return Returns the number of bytes available for reading. Zero if no bytes * are available. */ hv_uint32_t hLp_hasData(HvLightPipe *q); /** * Returns a pointer to a location in the pipe where numBytes can be written. * * @param numBytes The number of bytes to be written. * @return A pointer to a location where those bytes can be written. Returns * NULL if no more space is available. Successive calls to this * function may eventually return a valid pointer because the readhead * has been advanced on another thread. */ char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t numBytes); /** * Indicates to the pipe how many bytes have been written. * * @param numBytes The number of bytes written. In general this should be the * same value as was passed to the preceeding call to * hLp_getWriteBuffer(). */ void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes); /** * Returns the current read buffer, indicating the number of bytes available * for reading. * @param q The light pipe. * @param numBytes This value will be filled with the number of bytes available * for reading. * * @return A pointer to the read buffer. */ char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes); /** * Indicates that the next set of bytes have been read and are no longer needed. * @param q The light pipe. */ void hLp_consume(HvLightPipe *q); // resets the queue to it's initialised state // This should be done when only one thread is accessing the pipe. void hLp_reset(HvLightPipe *q); #ifdef __cplusplus } #endif #endif // _HEAVY_LIGHTPIPE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvMath.h0000644000000000000000000010240100000000000016170 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_MATH_H_ #define _HEAVY_MATH_H_ #include "HvUtils.h" #include // https://software.intel.com/sites/landingpage/IntrinsicsGuide/ // https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html // http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html static inline void __hv_zero_f(hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_setzero_ps(); #elif HV_SIMD_SSE *bOut = _mm_setzero_ps(); #elif HV_SIMD_NEON *bOut = vdupq_n_f32(0.0f); #else // HV_SIMD_NONE *bOut = 0.0f; #endif } static inline void __hv_zero_i(hv_bOuti_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_setzero_si256(); #elif HV_SIMD_SSE *bOut = _mm_setzero_si128(); #elif HV_SIMD_NEON *bOut = vdupq_n_s32(0); #else // HV_SIMD_NONE *bOut = 0; #endif } static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_load_ps(bIn); #elif HV_SIMD_SSE *bOut = _mm_load_ps(bIn); #elif HV_SIMD_NEON *bOut = vld1q_f32(bIn); #else // HV_SIMD_NONE *bOut = *bIn; #endif } static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) { #if HV_SIMD_AVX _mm256_store_ps(bOut, bIn); #elif HV_SIMD_SSE _mm_store_ps(bOut, bIn); #elif HV_SIMD_NEON vst1q_f32(bOut, bIn); #else // HV_SIMD_NONE *bOut = bIn; #endif } static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_log2_f() not implemented #elif HV_SIMD_SSE // https://en.wikipedia.org/wiki/Fast_inverse_square_root __m128i a = _mm_castps_si128(bIn); __m128i b = _mm_srli_epi32(a, 23); __m128i c = _mm_sub_epi32(b, _mm_set1_epi32(127)); // exponent (int) __m128 d = _mm_cvtepi32_ps(c); // exponent (float) __m128i e = _mm_or_si128(_mm_andnot_si128(_mm_set1_epi32(0xFF800000), a), _mm_set1_epi32(0x3F800000)); __m128 f = _mm_castsi128_ps(e); // 1+m (float) __m128 g = _mm_add_ps(d, f); // e + 1 + m __m128 h = _mm_add_ps(g, _mm_set1_ps(-0.9569643f)); // e + 1 + m + (sigma-1) *bOut = h; #elif HV_SIMD_NEON int32x4_t a = vreinterpretq_s32_f32(bIn); int32x4_t b = vshrq_n_s32(a, 23); int32x4_t c = vsubq_s32(b, vdupq_n_s32(127)); float32x4_t d = vcvtq_f32_s32(c); int32x4_t e = vorrq_s32(vbicq_s32(a, vdupq_n_s32(0xFF800000)), vdupq_n_s32(0x3F800000)); float32x4_t f = vreinterpretq_f32_s32(e); float32x4_t g = vaddq_f32(d, f); float32x4_t h = vaddq_f32(g, vdupq_n_f32(-0.9569643f)); *bOut = h; #else // HV_SIMD_NONE *bOut = 1.442695040888963f * hv_log_f(bIn); #endif } // NOTE(mhroth): this is a pretty ghetto implementation static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_set_ps( hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]), hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0])); #elif HV_SIMD_SSE const float *const b = (float *) &bIn; *bOut = _mm_set_ps(hv_cos_f(b[3]), hv_cos_f(b[2]), hv_cos_f(b[1]), hv_cos_f(b[0])); #elif HV_SIMD_NEON *bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])}; #else // HV_SIMD_NONE *bOut = hv_cos_f(bIn); #endif } static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_acos_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_acos_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_acos_f() not implemented #else // HV_SIMD_NONE *bOut = hv_acos_f(bIn); #endif } static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_cosh_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_cosh_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_cosh_f() not implemented #else // HV_SIMD_NONE *bOut = hv_cosh_f(bIn); #endif } static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_acosh_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_acosh_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_acosh_f() not implemented #else // HV_SIMD_NONE *bOut = hv_acosh_f(bIn); #endif } static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_sin_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_sin_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_sin_f() not implemented #else // HV_SIMD_NONE *bOut = hv_sin_f(bIn); #endif } static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_asin_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_asin_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_asin_f() not implemented #else // HV_SIMD_NONE *bOut = hv_asin_f(bIn); #endif } static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_sinh_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_sinh_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_sinh_f() not implemented #else // HV_SIMD_NONE *bOut = hv_sinh_f(bIn); #endif } static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_asinh_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_asinh_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_asinh_f() not implemented #else // HV_SIMD_NONE *bOut = hv_asinh_f(bIn); #endif } static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_tan_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_tan_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_tan_f() not implemented #else // HV_SIMD_NONE *bOut = hv_tan_f(bIn); #endif } static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_atan_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_atan_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_atan_f() not implemented #else // HV_SIMD_NONE *bOut = hv_atan_f(bIn); #endif } static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_atan2_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_atan2_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_atan2_f() not implemented #else // HV_SIMD_NONE *bOut = hv_atan2_f(bIn0, bIn1); #endif } static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_tanh_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_tanh_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_tanh_f() not implemented #else // HV_SIMD_NONE *bOut = hv_tanh_f(bIn); #endif } static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_atanh_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_atanh_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_atanh_f() not implemented #else // HV_SIMD_NONE *bOut = hv_atanh_f(bIn); #endif } static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_sqrt_ps(bIn); #elif HV_SIMD_SSE *bOut = _mm_sqrt_ps(bIn); #elif HV_SIMD_NEON const float32x4_t y = vrsqrteq_f32(bIn); *bOut = vmulq_f32(bIn, vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y)); // numerical results may be inexact #else // HV_SIMD_NONE *bOut = hv_sqrt_f(bIn); #endif } static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_rsqrt_ps(bIn); #elif HV_SIMD_SSE *bOut = _mm_rsqrt_ps(bIn); #elif HV_SIMD_NEON const float32x4_t y = vrsqrteq_f32(bIn); *bOut = vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y); // numerical results may be inexact #else // HV_SIMD_NONE *bOut = 1.0f/hv_sqrt_f(bIn); #endif } static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn); #elif HV_SIMD_SSE *bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31 #elif HV_SIMD_NEON *bOut = vabsq_f32(bIn); #else // HV_SIMD_NONE *bOut = hv_abs_f(bIn); #endif } static inline void __hv_neg_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_xor_ps(bIn, _mm256_set1_ps(-0.0f)); #elif HV_SIMD_SSE *bOut = _mm_xor_ps(bIn, _mm_set1_ps(-0.0f)); #elif HV_SIMD_NEON *bOut = vnegq_f32(bIn); #else // HV_SIMD_NONE *bOut = bIn * -1.0f; #endif } static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float)); _mm256_store_ps(b, bIn); *bOut = _mm256_set_ps( hv_exp_f(b[7]), hv_exp_f(b[6]), hv_exp_f(b[5]), hv_exp_f(b[4]), hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0])); #elif HV_SIMD_SSE float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float)); _mm_store_ps(b, bIn); *bOut = _mm_set_ps(hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0])); #elif HV_SIMD_NEON *bOut = (float32x4_t) { hv_exp_f(bIn[0]), hv_exp_f(bIn[1]), hv_exp_f(bIn[2]), hv_exp_f(bIn[3])}; #else // HV_SIMD_NONE *bOut = hv_exp_f(bIn); #endif } static inline void __hv_expm1_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_expm1_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_expm1_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_expm1_f() not implemented #else // HV_SIMD_NONE *bOut = hv_expm1_f(bIn); #endif } static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_ceil_ps(bIn); #elif HV_SIMD_SSE *bOut = _mm_ceil_ps(bIn); #elif HV_SIMD_NEON #if __ARM_ARCH >= 8 *bOut = vrndpq_f32(bIn); #else // A slow NEON implementation of __hv_ceil_f() is being used because // the necessary intrinsic cannot be found. It is only available in ARMv8. *bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])}; #endif // vrndpq_f32 #else // HV_SIMD_NONE *bOut = hv_ceil_f(bIn); #endif } static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_floor_ps(bIn); #elif HV_SIMD_SSE *bOut = _mm_floor_ps(bIn); #elif HV_SIMD_NEON #if __ARM_ARCH >= 8 *bOut = vrndmq_f32(bIn); #else // A slow implementation of __hv_floor_f() is being used because // the necessary intrinsic cannot be found. It is only available from ARMv8. *bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])}; #endif // vrndmq_f32 #else // HV_SIMD_NONE *bOut = hv_floor_f(bIn); #endif } // __add~f static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_add_ps(bIn0, bIn1); #elif HV_SIMD_SSE *bOut = _mm_add_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vaddq_f32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = bIn0 + bIn1; #endif } // __add~i static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { #if HV_SIMD_AVX __m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); __m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); #elif HV_SIMD_SSE *bOut = _mm_add_epi32(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vaddq_s32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = bIn0 + bIn1; #endif } // __sub~f static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_sub_ps(bIn0, bIn1); #elif HV_SIMD_SSE *bOut = _mm_sub_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vsubq_f32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = bIn0 - bIn1; #endif } // __mul~f static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_mul_ps(bIn0, bIn1); #elif HV_SIMD_SSE *bOut = _mm_mul_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vmulq_f32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = bIn0 * bIn1; #endif } // __*~i static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { #if HV_SIMD_AVX __m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); __m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); #elif HV_SIMD_SSE *bOut = _mm_mullo_epi32(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vmulq_s32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = bIn0 * bIn1; #endif } // __cast~if static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cvtepi32_ps(bIn); #elif HV_SIMD_SSE *bOut = _mm_cvtepi32_ps(bIn); #elif HV_SIMD_NEON *bOut = vcvtq_f32_s32(bIn); #else // HV_SIMD_NONE *bOut = (float) bIn; #endif } // __cast~fi static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cvtps_epi32(bIn); #elif HV_SIMD_SSE *bOut = _mm_cvtps_epi32(bIn); #elif HV_SIMD_NEON *bOut = vcvtq_s32_f32(bIn); #else // HV_SIMD_NONE *bOut = (int) bIn; #endif } // expr~ expects all float i/o static inline void __hv_cast_if_expr(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_cast_if_expr() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_cast_if_expr() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_cast_if_expr() not implemented #else // HV_SIMD_NONE *bOut = (float) bIn; #endif } // expr~ expects all float i/o static inline void __hv_cast_fi_expr(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_cast_fi_expr() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_cast_fi_expr() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_cast_fi_expr() not implemented #else // HV_SIMD_NONE if (bIn < 0.0f) *bOut = hv_rint_f(bIn); else if (bIn > 0.0f) *bOut = hv_floor_f(bIn); else *bOut = 0.0f; #endif } static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX __m256 a = _mm256_cmp_ps(bIn1, _mm256_setzero_ps(), _CMP_EQ_OQ); __m256 b = _mm256_div_ps(bIn0, bIn1); *bOut = _mm256_andnot_ps(a, b); #elif HV_SIMD_SSE __m128 a = _mm_cmpeq_ps(bIn1, _mm_setzero_ps()); __m128 b = _mm_div_ps(bIn0, bIn1); *bOut = _mm_andnot_ps(a, b); #elif HV_SIMD_NEON uint32x4_t a = vceqq_f32(bIn1, vdupq_n_f32(0.0f)); float32x4_t b = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); // NOTE(mhroth): numerical results may be inexact *bOut = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(b), a)); #else // HV_SIMD_NONE *bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f; #endif } static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_min_ps(bIn0, bIn1); #elif HV_SIMD_SSE *bOut = _mm_min_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vminq_f32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = hv_min_f(bIn0, bIn1); #endif } static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { #if HV_SIMD_AVX __m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); __m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); #elif HV_SIMD_SSE *bOut = _mm_min_epi32(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vminq_s32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = hv_min_i(bIn0, bIn1); #endif } static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_max_ps(bIn0, bIn1); #elif HV_SIMD_SSE *bOut = _mm_max_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vmaxq_f32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = hv_max_f(bIn0, bIn1); #endif } static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) { #if HV_SIMD_AVX __m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1)); __m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1)); *bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1); #elif HV_SIMD_SSE *bOut = _mm_max_epi32(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vmaxq_s32(bIn0, bIn1); #else // HV_SIMD_NONE *bOut = hv_max_i(bIn0, bIn1); #endif } static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX float *b = (float *) hv_alloca(16*sizeof(float)); _mm256_store_ps(b, bIn0); _mm256_store_ps(b+8, bIn1); *bOut = _mm256_set_ps( hv_pow_f(b[7], b[15]), hv_pow_f(b[6], b[14]), hv_pow_f(b[5], b[13]), hv_pow_f(b[4], b[12]), hv_pow_f(b[3], b[11]), hv_pow_f(b[2], b[10]), hv_pow_f(b[1], b[9]), hv_pow_f(b[0], b[8])); #elif HV_SIMD_SSE float *b = (float *) hv_alloca(8*sizeof(float)); _mm_store_ps(b, bIn0); _mm_store_ps(b+4, bIn1); *bOut = _mm_set_ps( hv_pow_f(b[3], b[7]), hv_pow_f(b[2], b[6]), hv_pow_f(b[1], b[5]), hv_pow_f(b[0], b[4])); #elif HV_SIMD_NEON *bOut = (float32x4_t) { hv_pow_f(bIn0[0], bIn1[0]), hv_pow_f(bIn0[1], bIn1[1]), hv_pow_f(bIn0[2], bIn1[2]), hv_pow_f(bIn0[3], bIn1[3])}; #else // HV_SIMD_NONE *bOut = hv_pow_f(bIn0, bIn1); #endif } static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ); #elif HV_SIMD_SSE *bOut = _mm_cmpgt_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1)); #else // HV_SIMD_NONE *bOut = (bIn0 > bIn1) ? 1.0f : 0.0f; #endif } static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ); #elif HV_SIMD_SSE *bOut = _mm_cmpge_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1)); #else // HV_SIMD_NONE *bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f; #endif } static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ); #elif HV_SIMD_SSE *bOut = _mm_cmplt_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1)); #else // HV_SIMD_NONE *bOut = (bIn0 < bIn1) ? 1.0f : 0.0f; #endif } static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ); #elif HV_SIMD_SSE *bOut = _mm_cmple_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1)); #else // HV_SIMD_NONE *bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f; #endif } static inline void __hv_eq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_EQ_OQ); #elif HV_SIMD_SSE *bOut = _mm_cmpeq_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vceqq_f32(bIn0, bIn1)); #else // HV_SIMD_NONE *bOut = (bIn0 == bIn1) ? 1.0f : 0.0f; #endif } static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ); #elif HV_SIMD_SSE *bOut = _mm_cmpneq_ps(bIn0, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1))); #else // HV_SIMD_NONE *bOut = (bIn0 != bIn1) ? 1.0f : 0.0f; #endif } static inline void __hv_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_or_ps(bIn1, bIn0); #elif HV_SIMD_SSE *bOut = _mm_or_ps(bIn1, bIn0); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0))); #else // HV_SIMD_NONE if (bIn0 == 0.0f && bIn1 == 0.0f) *bOut = 0.0f; else if (bIn0 == 0.0f) *bOut = bIn1; else if (bIn1 == 0.0f) *bOut = bIn0; else hv_assert(0); #endif } static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_and_ps(bIn1, bIn0); #elif HV_SIMD_SSE *bOut = _mm_and_ps(bIn1, bIn0); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0))); #else // HV_SIMD_NONE if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f; else if (bIn0 == 1.0f) *bOut = bIn1; else if (bIn1 == 1.0f) *bOut = bIn0; else hv_assert(0); #endif } static inline void __hv_not_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_not_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_not_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_not_f() not implemented #else // HV_SIMD_NONE *bOut = hv_not_f(bIn); #endif } static inline void __hv_andnot_f(hv_bInf_t bIn0_mask, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_andnot_ps(bIn0_mask, bIn1); #elif HV_SIMD_SSE *bOut = _mm_andnot_ps(bIn0_mask, bIn1); #elif HV_SIMD_NEON *bOut = vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(bIn1), vreinterpretq_s32_f32(bIn0_mask))); #else // HV_SIMD_NONE *bOut = (bIn0_mask == 0.0f) ? bIn1 : 0.0f; #endif } // bOut = (bIn0 * bIn1) + bIn2 static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) { #if HV_SIMD_AVX #if HV_SIMD_FMA *bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2); #else *bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2); #endif // HV_SIMD_FMA #elif HV_SIMD_SSE #if HV_SIMD_FMA *bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2); #else *bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2); #endif // HV_SIMD_FMA #elif HV_SIMD_NEON #if __ARM_ARCH >= 8 *bOut = vfmaq_f32(bIn2, bIn0, bIn1); #else // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures *bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2); #endif #else // HV_SIMD_NONE *bOut = hv_fma_f(bIn0, bIn1, bIn2); #endif } // bOut = (bIn0 * bIn1) - bIn2 static inline void __hv_fms_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) { #if HV_SIMD_AVX #if HV_SIMD_FMA *bOut = _mm256_fmsub_ps(bIn0, bIn1, bIn2); #else *bOut = _mm256_sub_ps(_mm256_mul_ps(bIn0, bIn1), bIn2); #endif // HV_SIMD_FMA #elif HV_SIMD_SSE #if HV_SIMD_FMA *bOut = _mm_fmsub_ps(bIn0, bIn1, bIn2); #else *bOut = _mm_sub_ps(_mm_mul_ps(bIn0, bIn1), bIn2); #endif // HV_SIMD_FMA #elif HV_SIMD_NEON #if __ARM_ARCH >= 8 *bOut = vfmsq_f32(bIn2, bIn0, bIn1); #else // NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures *bOut = vsubq_f32(vmulq_f32(bIn0, bIn1), bIn2); #endif #else // HV_SIMD_NONE *bOut = (bIn0 * bIn1) - bIn2; #endif } static inline void __hv_cbrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_cbrt_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_cbrt_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_cbrt_f() not implemented #else // HV_SIMD_NONE *bOut = hv_cbrt_f(bIn); #endif } static inline void __hv_erf_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_erf_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_erf_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_erf_f() not implemented #else // HV_SIMD_NONE *bOut = hv_erf_f(bIn); #endif } static inline void __hv_erfc_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_erfc_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_erfc_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_erfc_f() not implemented #else // HV_SIMD_NONE *bOut = hv_erfc_f(bIn); #endif } static inline void __hv_ln_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_ln_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_ln_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_ln_f() not implemented #else // HV_SIMD_NONE *bOut = hv_ln_f(bIn); #endif } static inline void __hv_log_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_log_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_log_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_log_f() not implemented #else // HV_SIMD_NONE *bOut = hv_log_f(bIn); #endif } static inline void __hv_log1p_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_log1p_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_log1p_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_log1p_f() not implemented #else // HV_SIMD_NONE *bOut = hv_log1p_f(bIn); #endif } static inline void __hv_log10_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_log10_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_log10_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_log10_f() not implemented #else // HV_SIMD_NONE *bOut = hv_log10_f(bIn); #endif } static inline void __hv_modf_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_modf_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_modf_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_modf_f() not implemented #else // HV_SIMD_NONE *bOut = hv_modf_f(bIn); #endif } static inline void __hv_modulo_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_modulo_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_modulo_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_modulo_f() not implemented #else // HV_SIMD_NONE float modded = hv_fmod_f(bIn0, bIn1); if (modded < 0.0f) *bOut = hv_rint_f(modded); else if (modded >= 0.0f) *bOut = hv_floor_f(modded); #endif } static inline void __hv_shl_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_shl_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_shl_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_shl_f() not implemented #else // HV_SIMD_NONE *bOut = (float) hv_shl_i((int) bIn0, (int) bIn1); #endif } static inline void __hv_shr_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_shr_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_shr_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_shr_f() not implemented #else // HV_SIMD_NONE *bOut = (float) hv_shr_i((int) bIn0, (int) bIn1); #endif } static inline void __hv_bit_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_bit_and_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_bit_and_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_bit_and_f() not implemented #else // HV_SIMD_NONE *bOut = (float) ((int) bIn0 & (int) bIn1); #endif } static inline void __hv_bit_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_bit_or_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_bit_or_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_bit_or_f() not implemented #else // HV_SIMD_NONE *bOut = (float) ((int) bIn0 | (int) bIn1); #endif } static inline void __hv_bit_not_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_bit_not_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_bit_not_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_bit_not_f() not implemented #else // HV_SIMD_NONE *bOut = (float) hv_bit_not_i((int) bIn); #endif } static inline void __hv_exc_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_exc_or_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_exc_or_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_exc_or_f() not implemented #else // HV_SIMD_NONE *bOut = (float) ((int) bIn0 ^ (int) bIn1); #endif } static inline void __hv_log_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_log_and_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_log_and_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_log_and_f() not implemented #else // HV_SIMD_NONE *bOut = bIn0 && bIn1; #endif } static inline void __hv_log_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_log_or_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_log_or_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_log_or_f() not implemented #else // HV_SIMD_NONE *bOut = bIn0 || bIn1; #endif } static inline void __hv_rint_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_rint_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_rint_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_rint_f() not implemented #else // HV_SIMD_NONE *bOut = hv_rint_f(bIn); #endif } static inline void __hv_round_f(hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_round_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_round_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_round_f() not implemented #else // HV_SIMD_NONE *bOut = hv_round_f(bIn); #endif } static inline void __hv_if_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_if_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_if_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_if_f() not implemented #else // HV_SIMD_NONE *bOut = hv_if_f(bIn0, bIn1, bIn2); #endif } static inline void __hv_isinf_f(hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_isinf_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_isinf_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_isinf_f() not implemented #else // HV_SIMD_NONE *bOut = hv_isinf_f(bIn0); #endif } static inline void __hv_finite_f(hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_finite_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_finite_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_finite_f() not implemented #else // HV_SIMD_NONE *bOut = hv_finite_f(bIn0); #endif } static inline void __hv_isnan_f(hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_isnan_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_isnan_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_isnan_f() not implemented #else // HV_SIMD_NONE *bOut = hv_isnan_f(bIn0); #endif } static inline void __hv_copysign_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_copysign_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_copysign_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_copysign_f() not implemented #else // HV_SIMD_NONE *bOut = hv_copysign_f(bIn0, bIn1); #endif } static inline void __hv_imod_f(hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_imod_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_imod_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_imod_f() not implemented #else // HV_SIMD_NONE float iptr; modff(bIn0, &iptr); *bOut = iptr; #endif } static inline void __hv_remainder_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_remainder_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_remainder_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_remainder_f() not implemented #else // HV_SIMD_NONE *bOut = hv_remainder_f(bIn0, bIn1); #endif } static inline void __hv_fmod_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_fmod_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_fmod_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_fmod_f() not implemented #else // HV_SIMD_NONE *bOut = hv_fmod_f(bIn0, bIn1); #endif } static inline void __hv_fact_f(hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_fact_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_fact_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_fact_f() not implemented #else // HV_SIMD_NONE int n = (int) bIn0; if(n <= 1) { // follow Pure data convention *bOut = 1; } else if(n > 34) { // follow Pure data convention *bOut = INFINITY; // C99 constant } else { float f = 1.0f; for (int i = n; i > 1; --i) { f *= i; } *bOut = f; } #endif } static inline void __hv_ldexp_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_ldexp_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_ldexp_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_ldexp_f() not implemented #else // HV_SIMD_NONE *bOut = hv_ldexp_f(bIn0, bIn1); #endif } static inline void __hv_bitsafe_f(hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_bitsafe_f() not implemented #elif HV_SIMD_SSE hv_assert(0); // __hv_bitsafe_f() not implemented #elif HV_SIMD_NEON hv_assert(0); // __hv_bitsafe_f() not implemented #else // HV_SIMD_NONE if (hv_isnan_f(bIn0) || hv_isinf_f(bIn0)) *bOut = 0.0f; else *bOut = bIn0; #endif } #endif // _HEAVY_MATH_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvMessage.c0000644000000000000000000001626600000000000016673 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvMessage.h" HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) { m->timestamp = timestamp; m->numElements = (hv_uint16_t) numElements; m->numBytes = (hv_uint16_t) msg_getCoreSize(numElements); return m; } HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage); msg_setFloat(m, 0, f); return m; } HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage); msg_setBang(m, 0); return m; } HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage) + (hv_uint16_t) hv_strlen(s); msg_setSymbol(m, 0, s); return m; } HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) { m->timestamp = timestamp; m->numElements = 1; m->numBytes = sizeof(HvMessage); msg_setHash(m, 0, h); return m; } void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) { HvMessage *r = (HvMessage *) buffer; hv_size_t len_r = msg_getCoreSize(msg_getNumElements(m)); // assert that the message is not already larger than the length of the buffer hv_assert(len_r <= len); // copy the basic message to the buffer hv_memcpy(r, m, len_r); char *p = buffer + len_r; // points to the end of the base message for (int i = 0; i < msg_getNumElements(m); ++i) { if (msg_isSymbol(m,i)) { const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char hv_assert(len_r + symLen <= len); // stay safe! hv_strncpy(p, msg_getSymbol(m,i), symLen); msg_setSymbol(r, i, p); p += symLen; len_r += symLen; } } r->numBytes = (hv_uint16_t) len_r; // update the message size in memory } // the message is serialised such that all symbol elements are placed in order at the end of the buffer HvMessage *msg_copy(const HvMessage *m) { const hv_uint32_t heapSize = msg_getSize(m); char *r = (char *) hv_malloc(heapSize); hv_assert(r != NULL); msg_copyToBuffer(m, r, heapSize); return (HvMessage *) r; } void msg_free(HvMessage *m) { hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message } bool msg_hasFormat(const HvMessage *m, const char *fmt) { hv_assert(fmt != NULL); const int n = msg_getNumElements(m); for (int i = 0; i < n; ++i) { switch (fmt[i]) { case 'b': if (!msg_isBang(m, i)) return false; break; case 'f': if (!msg_isFloat(m, i)) return false; break; case 'h': if (!msg_isHash(m, i)) return false; break; case 's': if (!msg_isSymbol(m, i)) return false; break; default: return false; } } return (fmt[n] == '\0'); } bool msg_compareSymbol(const HvMessage *m, int i, const char *s) { switch (msg_getType(m,i)) { case HV_MSG_SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s); case HV_MSG_HASH: return (msg_getHash(m,i) == hv_string_to_hash(s)); default: return false; } } bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) { if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) { if (msg_getType(m, i_m) == msg_getType(n, i_n)) { switch (msg_getType(m, i_m)) { case HV_MSG_BANG: return true; case HV_MSG_FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n)); case HV_MSG_SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n)); case HV_MSG_HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n); default: break; } } } return false; } void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) { switch (msg_getType(m, i_m)) { case HV_MSG_BANG: msg_setBang(n, i_n); break; case HV_MSG_FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break; case HV_MSG_SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break; case HV_MSG_HASH: msg_setHash(n, i_n, msg_getHash(m, i_m)); default: break; } } hv_uint32_t msg_getHash(const HvMessage *const m, int i) { hv_assert(i < msg_getNumElements(m)); // invalid index switch (msg_getType(m,i)) { case HV_MSG_BANG: return 0xFFFFFFFF; case HV_MSG_FLOAT: { union { float f; hv_uint32_t u; } fhash; fhash.f = msg_getFloat(m,i); return fhash.u; } case HV_MSG_SYMBOL: return hv_string_to_hash(msg_getSymbol(m,i)); case HV_MSG_HASH: return (&(m->elem)+i)->data.h; default: return 0; } } char *msg_toString(const HvMessage *m) { hv_assert(msg_getNumElements(m) > 0); int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int)); int size = 0; // the total length of our final buffer // loop through every element in our list of atoms // first loop figures out how long our buffer should be for (int i = 0; i < msg_getNumElements(m); i++) { // length of our string is each atom plus a space, or \0 on the end switch (msg_getType(m, i)) { case HV_MSG_BANG: len[i] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break; case HV_MSG_FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break; case HV_MSG_SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break; case HV_MSG_HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; break; default: break; } size += len[i]; } hv_assert(size > 0); // now we do the piecewise concatenation into our final string // the final buffer we will pass back after concatenating all strings - user should free it char *finalString = (char *) hv_malloc(size*sizeof(char)); hv_assert(finalString != NULL); int pos = 0; for (int i = 0; i < msg_getNumElements(m); i++) { // put a string representation of each atom into the final string switch (msg_getType(m, i)) { case HV_MSG_BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break; case HV_MSG_FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break; case HV_MSG_SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break; case HV_MSG_HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break; default: break; } pos += len[i]; finalString[pos-1] = 32; // ASCII space } finalString[size-1] = '\0'; // ensure that the string is null terminated return finalString; } hvcc-0.16.0/hvcc/generators/ir2c/static/HvMessage.h0000644000000000000000000001423600000000000016673 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_MESSAGE_H_ #define _HEAVY_MESSAGE_H_ #include "HvUtils.h" #ifdef __cplusplus extern "C" { #endif typedef enum ElementType { HV_MSG_BANG = 0, HV_MSG_FLOAT = 1, HV_MSG_SYMBOL = 2, HV_MSG_HASH = 3 } ElementType; typedef struct Element { ElementType type; union { float f; // float const char *s; // symbol hv_uint32_t h; // hash } data; } Element; typedef struct HvMessage { hv_uint32_t timestamp; // the sample at which this message should be processed hv_uint16_t numElements; hv_uint16_t numBytes; // the total number of bytes that this message occupies in memory, including strings Element elem; } HvMessage; typedef struct ReceiverMessagePair { hv_uint32_t receiverHash; HvMessage msg; } ReceiverMessagePair; #define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getCoreSize(_x)) /** Returns the number of bytes that this message consumes in memory, not including strings. */ static inline hv_size_t msg_getCoreSize(hv_size_t numElements) { hv_assert(numElements > 0); return sizeof(HvMessage) + ((numElements-1) * sizeof(Element)); } HvMessage *msg_copy(const HvMessage *m); /** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */ void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len); void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM); /** Frees a message on the heap. Does nothing if argument is NULL. */ void msg_free(HvMessage *m); HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp); HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f); HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp); HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s); HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h); static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) { return m->timestamp; } static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) { m->timestamp = timestamp; } static inline int msg_getNumElements(const HvMessage *m) { return (int) m->numElements; } /** Returns the total number of bytes this message consumes in memory. */ static inline hv_uint32_t msg_getSize(const HvMessage *m) { return m->numBytes; } static inline ElementType msg_getType(const HvMessage *m, int index) { hv_assert(index < msg_getNumElements(m)); // invalid index return (&(m->elem)+index)->type; } static inline void msg_setBang(HvMessage *m, int index) { hv_assert(index < msg_getNumElements(m)); // invalid index (&(m->elem)+index)->type = HV_MSG_BANG; (&(m->elem)+index)->data.s = NULL; } static inline bool msg_isBang(const HvMessage *m, int index) { return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_BANG) : false; } static inline void msg_setFloat(HvMessage *m, int index, float f) { hv_assert(index < msg_getNumElements(m)); // invalid index (&(m->elem)+index)->type = HV_MSG_FLOAT; (&(m->elem)+index)->data.f = f; } static inline float msg_getFloat(const HvMessage *const m, int index) { hv_assert(index < msg_getNumElements(m)); // invalid index return (&(m->elem)+index)->data.f; } static inline bool msg_isFloat(const HvMessage *const m, int index) { return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_FLOAT) : false; } static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) { hv_assert(index < msg_getNumElements(m)); // invalid index (&(m->elem)+index)->type = HV_MSG_HASH; (&(m->elem)+index)->data.h = h; } static inline bool msg_isHash(const HvMessage *m, int index) { return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_HASH) : false; } /** Returns true if the element is a hash or symbol. False otherwise. */ static inline bool msg_isHashLike(const HvMessage *m, int index) { return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HV_MSG_HASH) || (msg_getType(m, index) == HV_MSG_SYMBOL)) : false; } /** Returns a 32-bit hash of the given element. */ hv_uint32_t msg_getHash(const HvMessage *const m, int i); static inline void msg_setSymbol(HvMessage *m, int index, const char *s) { hv_assert(index < msg_getNumElements(m)); // invalid index hv_assert(s != NULL); (&(m->elem)+index)->type = HV_MSG_SYMBOL; (&(m->elem)+index)->data.s = s; // NOTE(mhroth): if the same message container is reused and string reset, // then the message size will be overcounted m->numBytes += (hv_uint16_t) (hv_strlen(s) + 1); // also count '\0' } static inline const char *msg_getSymbol(const HvMessage *m, int index) { hv_assert(index < msg_getNumElements(m)); // invalid index return (&(m->elem)+index)->data.s; } static inline bool msg_isSymbol(const HvMessage *m, int index) { return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_SYMBOL) : false; } bool msg_compareSymbol(const HvMessage *m, int i, const char *s); /** Returns 1 if the element i_m of message m is equal to element i_n of message n. */ bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n); bool msg_hasFormat(const HvMessage *m, const char *fmt); /** * Create a string representation of the message. Suitable for use by the print object. * The resulting string must be freed by the caller. */ char *msg_toString(const HvMessage *msg); #ifdef __cplusplus } #endif #endif // _HEAVY_MESSAGE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvMessagePool.c0000644000000000000000000001111000000000000017504 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvMessagePool.h" #include "HvMessage.h" // the number of bytes reserved at a time from the pool #define MP_BLOCK_SIZE_BYTES 512 #if HV_APPLE #pragma mark - MessageList #endif typedef struct MessageListNode { char *p; struct MessageListNode *next; } MessageListNode; static inline bool ml_hasAvailable(HvMessagePoolList *ml) { return (ml->head != NULL); } static char *ml_pop(HvMessagePoolList *ml) { MessageListNode *n = ml->head; ml->head = n->next; n->next = ml->pool; ml->pool = n; char *const p = n->p; n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer return p; } /** Push a MessageListNode with the given pointer onto the head of the queue. */ static void ml_push(HvMessagePoolList *ml, void *p) { MessageListNode *n = NULL; if (ml->pool != NULL) { // take an empty MessageListNode from the pool n = ml->pool; ml->pool = n->next; } else { // a MessageListNode is not available, allocate one n = (MessageListNode *) hv_malloc(sizeof(MessageListNode)); hv_assert(n != NULL); } n->p = (char *) p; n->next = ml->head; ml->head = n; // push to the front of the queue } static void ml_free(HvMessagePoolList *ml) { if (ml != NULL) { while (ml_hasAvailable(ml)) { ml_pop(ml); } while (ml->pool != NULL) { MessageListNode *n = ml->pool; ml->pool = n->next; hv_free(n); } } } #if HV_APPLE #pragma mark - HvMessagePool #endif static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) { return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0); } hv_size_t mp_init(HvMessagePool *mp, hv_size_t numKB) { mp->bufferSize = numKB * 1024; mp->buffer = (char *) hv_malloc(mp->bufferSize); hv_assert(mp->buffer != NULL); mp->bufferIndex = 0; // initialise all message lists for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) { mp->lists[i].head = NULL; mp->lists[i].pool = NULL; } return mp->bufferSize; } void mp_free(HvMessagePool *mp) { hv_free(mp->buffer); for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) { ml_free(&mp->lists[i]); } } void mp_freeMessage(HvMessagePool *mp, HvMessage *m) { const hv_size_t b = msg_getSize(m); // the number of bytes that a message occupies in memory const hv_size_t i = mp_messagelistIndexForSize(b); // the HvMessagePoolList index in the pool HvMessagePoolList *ml = &mp->lists[i]; const hv_size_t chunkSize = 32 << i; hv_memclear(m, chunkSize); // clear the chunk, just in case ml_push(ml, m); } HvMessage *mp_addMessage(HvMessagePool *mp, const HvMessage *m) { const hv_size_t b = msg_getSize(m); // determine the message list index to allocate data from based on the msg size // smallest chunk size is 32 bytes const hv_size_t i = mp_messagelistIndexForSize(b); hv_assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment HvMessagePoolList *ml = &mp->lists[i]; const hv_size_t chunkSize = 32 << i; if (ml_hasAvailable(ml)) { char *buf = ml_pop(ml); msg_copyToBuffer(m, buf, chunkSize); return (HvMessage *) buf; } else { // if no appropriately sized buffer is immediately available, increase the size of the used buffer const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES; hv_assert((newIndex <= mp->bufferSize) && "The message pool buffer size has been exceeded. The context cannot store more messages. " "Try using the new_with_options() initialiser with a larger pool size (default is 10KB)."); for (hv_size_t j = mp->bufferIndex; j < newIndex; j += chunkSize) { ml_push(ml, mp->buffer + j); // push new nodes onto the list with chunk pointers } mp->bufferIndex = newIndex; char *buf = ml_pop(ml); msg_copyToBuffer(m, buf, chunkSize); return (HvMessage *) buf; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvMessagePool.h0000644000000000000000000000507700000000000017530 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _MESSAGE_POOL_H_ #define _MESSAGE_POOL_H_ #include "HvUtils.h" #ifdef HV_MP_NUM_MESSAGE_LISTS #define MP_NUM_MESSAGE_LISTS HV_MP_NUM_MESSAGE_LISTS #else // HV_MP_NUM_MESSAGE_LISTS #define MP_NUM_MESSAGE_LISTS 4 #endif // HV_MP_NUM_MESSAGE_LISTS #ifdef __cplusplus extern "C" { #endif typedef struct HvMessagePoolList { struct MessageListNode *head; // list of currently available blocks struct MessageListNode *pool; // list of currently used blocks } HvMessagePoolList; typedef struct HvMessagePool { char *buffer; // the buffer of all messages hv_size_t bufferSize; // in bytes hv_size_t bufferIndex; // the number of total reserved bytes HvMessagePoolList lists[MP_NUM_MESSAGE_LISTS]; } HvMessagePool; /** * The HvMessagePool is a basic memory management system. It reserves a large block of memory at initialisation * and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are * further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a HvMessagePoolList (MPL). * An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes * that point at each subblock (e.g. each 32-byte block of a 512-block chunk). * * HvMessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html */ hv_size_t mp_init(struct HvMessagePool *mp, hv_size_t numKB); void mp_free(struct HvMessagePool *mp); /** * Adds a message to the pool and returns a pointer to the copy. Returns NULL * if no space was available in the pool. */ struct HvMessage *mp_addMessage(struct HvMessagePool *mp, const struct HvMessage *m); void mp_freeMessage(struct HvMessagePool *mp, struct HvMessage *m); #ifdef __cplusplus } #endif #endif // _MESSAGE_POOL_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvMessageQueue.c0000644000000000000000000001366700000000000017702 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvMessageQueue.h" hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB) { hv_assert(poolSizeKB > 0); q->head = NULL; q->tail = NULL; q->pool = NULL; return mp_init(&q->mp, poolSizeKB); } void mq_free(HvMessageQueue *q) { mq_clear(q); while (q->pool != NULL) { MessageNode *n = q->pool; q->pool = q->pool->next; hv_free(n); } mp_free(&q->mp); } static MessageNode *mq_getOrCreateNodeFromPool(HvMessageQueue *q) { if (q->pool == NULL) { // if necessary, create a new empty node q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode)); hv_assert(q->pool != NULL); q->pool->next = NULL; } MessageNode *node = q->pool; q->pool = q->pool->next; return node; } int mq_size(HvMessageQueue *q) { int size = 0; MessageNode *n = q->head; while (n != NULL) { ++size; n = n->next; } return size; } HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { MessageNode *node = mq_getOrCreateNodeFromPool(q); node->m = mp_addMessage(&q->mp, m); node->let = let; node->sendMessage = sendMessage; node->prev = NULL; node->next = NULL; if (q->tail != NULL) { // the list already contains elements q->tail->next = node; node->prev = q->tail; q->tail = node; } else { // the list is empty node->prev = NULL; q->head = node; q->tail = node; } return mq_node_getMessage(node); } HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { if (mq_hasMessage(q)) { MessageNode *n = mq_getOrCreateNodeFromPool(q); n->m = mp_addMessage(&q->mp, m); n->let = let; n->sendMessage = sendMessage; if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) { // the message occurs before the current head n->next = q->head; q->head->prev = n; n->prev = NULL; q->head = n; } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) { // the message occurs after the current tail n->next = NULL; n->prev = q->tail; q->tail->next = n; q->tail = n; } else { // the message occurs somewhere between the head and tail MessageNode *node = q->head; while (node != NULL) { if (msg_getTimestamp(m) < msg_getTimestamp(node->next->m)) { MessageNode *r = node->next; node->next = n; n->next = r; n->prev = node; r->prev = n; break; } node = node->next; } } return n->m; } else { // add a message to the head return mq_addMessage(q, m, let, sendMessage); } } void mq_pop(HvMessageQueue *q) { if (mq_hasMessage(q)) { MessageNode *n = q->head; mp_freeMessage(&q->mp, n->m); n->m = NULL; n->let = 0; n->sendMessage = NULL; q->head = n->next; if (q->head == NULL) { q->tail = NULL; } else { q->head->prev = NULL; } n->next = q->pool; n->prev = NULL; q->pool = n; } } bool mq_removeMessage(HvMessageQueue *q, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { if (mq_hasMessage(q)) { if (mq_node_getMessage(q->head) == m) { // msg in head node // only remove the message if sendMessage is the same as the stored one, // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer if (sendMessage == NULL || q->head->sendMessage == sendMessage) { mq_pop(q); return true; } } else { MessageNode *prevNode = q->head; MessageNode *currNode = q->head->next; while ((currNode != NULL) && (currNode->m != m)) { prevNode = currNode; currNode = currNode->next; } if (currNode != NULL) { if (sendMessage == NULL || currNode->sendMessage == sendMessage) { mp_freeMessage(&q->mp, m); currNode->m = NULL; currNode->let = 0; currNode->sendMessage = NULL; if (currNode == q->tail) { // msg in tail node prevNode->next = NULL; q->tail = prevNode; } else { // msg in middle node prevNode->next = currNode->next; currNode->next->prev = prevNode; } currNode->next = (q->pool == NULL) ? NULL : q->pool; currNode->prev = NULL; q->pool = currNode; return true; } } } } return false; } void mq_clear(HvMessageQueue *q) { while (mq_hasMessage(q)) { mq_pop(q); } } void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp) { MessageNode *n = q->tail; while (n != NULL && timestamp <= msg_getTimestamp(n->m)) { // free the node's message mp_freeMessage(&q->mp, n->m); n->m = NULL; n->let = 0; n->sendMessage = NULL; // the tail points at the previous node q->tail = n->prev; // put the node back in the pool n->next = q->pool; n->prev = NULL; if (q->pool != NULL) q->pool->prev = n; q->pool = n; // update the tail node n = q->tail; } if (q->tail == NULL) q->head = NULL; } hvcc-0.16.0/hvcc/generators/ir2c/static/HvMessageQueue.h0000644000000000000000000000630600000000000017677 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _MESSAGE_QUEUE_H_ #define _MESSAGE_QUEUE_H_ #include "HvMessage.h" #include "HvMessagePool.h" #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus class HeavyContextInterface; #else typedef struct HeavyContextInterface HeavyContextInterface; #endif typedef struct MessageNode { struct MessageNode *prev; // doubly linked list struct MessageNode *next; HvMessage *m; void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *); int let; } MessageNode; /** A doubly linked list containing scheduled messages. */ typedef struct HvMessageQueue { MessageNode *head; // the head of the queue MessageNode *tail; // the tail of the queue MessageNode *pool; // the head of the reserve pool HvMessagePool mp; } HvMessageQueue; hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB); void mq_free(HvMessageQueue *q); int mq_size(HvMessageQueue *q); static inline HvMessage *mq_node_getMessage(MessageNode *n) { return n->m; } static inline int mq_node_getLet(MessageNode *n) { return n->let; } static inline bool mq_hasMessage(HvMessageQueue *q) { return (q->head != NULL); } // true if there is a message and it occurs before (<) timestamp static inline bool mq_hasMessageBefore(HvMessageQueue *const q, const hv_uint32_t timestamp) { return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp); } static inline MessageNode *mq_peek(HvMessageQueue *q) { return q->head; } /** Appends the message to the end of the queue. */ HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); /** Insert in ascending order the message acccording to its timestamp. */ HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); /** Pop the message at the head of the queue (and free its memory). */ void mq_pop(HvMessageQueue *q); /** Remove a message from the queue (and free its memory) */ bool mq_removeMessage(HvMessageQueue *q, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); /** Clears (and frees) all messages in the queue. */ void mq_clear(HvMessageQueue *q); /** Removes all messages occuring at or after the given timestamp. */ void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp); #ifdef __cplusplus } #endif #endif // _MESSAGE_QUEUE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalBiquad.c0000644000000000000000000002212700000000000017643 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalBiquad.h" // http://reanimator-web.appspot.com/articles/simdiir // https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html hv_size_t sBiquad_init(SignalBiquad *o) { #if HV_SIMD_AVX o->x = _mm256_setzero_ps(); #elif HV_SIMD_SSE o->x = _mm_setzero_ps(); #elif HV_SIMD_NEON o->x = vdupq_n_f32(0.0f); #else // HV_SIMD_NONE o->xm1 = 0.0f; o->xm2 = 0.0f; #endif o->ym1 = 0.0f; o->ym2 = 0.0f; return 0; } #if _WIN32 && !_WIN64 void __hv_biquad_f_win32(SignalBiquad *o, hv_bInf_t *_bIn, hv_bInf_t *_bX0, hv_bInf_t *_bX1, hv_bInf_t *_bX2, hv_bInf_t *_bY1, hv_bInf_t *_bY2, hv_bOutf_t bOut) { hv_bInf_t bIn = *_bIn; hv_bInf_t bX0 = *_bX0; hv_bInf_t bX1 = *_bX1; hv_bInf_t bX2 = *_bX2; hv_bInf_t bY1 = *_bY1; hv_bInf_t bY2 = *_bY2; #else void __hv_biquad_f(SignalBiquad *o, hv_bInf_t bIn, hv_bInf_t bX0, hv_bInf_t bX1, hv_bInf_t bX2, hv_bInf_t bY1, hv_bInf_t bY2, hv_bOutf_t bOut) { #endif #if HV_SIMD_AVX __m256 x = _mm256_permute_ps(bIn, _MM_SHUFFLE(2,1,0,3)); // [3 0 1 2 7 4 5 6] __m256 y = _mm256_permute_ps(o->x, _MM_SHUFFLE(2,1,0,3)); // [d a b c h e f g] __m256 n = _mm256_permute2f128_ps(y,x,0x21); // [h e f g 3 0 1 2] __m256 xm1 = _mm256_blend_ps(x, n, 0x11); // [h 0 1 2 3 4 5 6] x = _mm256_permute_ps(bIn, _MM_SHUFFLE(1,0,3,2)); // [2 3 0 1 6 7 4 5] y = _mm256_permute_ps(o->x, _MM_SHUFFLE(1,0,3,2)); // [c d a b g h e f] n = _mm256_permute2f128_ps(y,x,0x21); // [g h e f 2 3 0 1] __m256 xm2 = _mm256_blend_ps(x, n, 0x33); // [g h 0 1 2 3 4 5] __m256 a = _mm256_mul_ps(bIn, bX0); __m256 b = _mm256_mul_ps(xm1, bX1); __m256 c = _mm256_mul_ps(xm2, bX2); __m256 d = _mm256_add_ps(a, b); __m256 e = _mm256_add_ps(c, d); // bIn*bX0 + o->x1*bX1 + o->x2*bX2 float y0 = e[0] - o->ym1*bY1[0] - o->ym2*bY2[0]; float y1 = e[1] - y0*bY1[1] - o->ym1*bY2[1]; float y2 = e[2] - y1*bY1[2] - y0*bY2[2]; float y3 = e[3] - y2*bY1[3] - y1*bY2[3]; float y4 = e[4] - y3*bY1[4] - y2*bY2[4]; float y5 = e[5] - y4*bY1[5] - y3*bY2[5]; float y6 = e[6] - y5*bY1[6] - y4*bY2[6]; float y7 = e[7] - y6*bY1[7] - y5*bY2[7]; o->x = bIn; o->ym1 = y7; o->ym2 = y6; *bOut = _mm256_set_ps(y7, y6, y5, y4, y3, y2, y1, y0); #elif HV_SIMD_SSE __m128 n = _mm_blend_ps(o->x, bIn, 0x7); // [a b c d] [e f g h] = [e f g d] __m128 xm1 = _mm_shuffle_ps(n, n, _MM_SHUFFLE(2,1,0,3)); // [d e f g] __m128 xm2 = _mm_shuffle_ps(o->x, bIn, _MM_SHUFFLE(1,0,3,2)); // [c d e f] __m128 a = _mm_mul_ps(bIn, bX0); __m128 b = _mm_mul_ps(xm1, bX1); __m128 c = _mm_mul_ps(xm2, bX2); __m128 d = _mm_add_ps(a, b); __m128 e = _mm_add_ps(c, d); const float *const bbe = (float *) &e; const float *const bbY1 = (float *) &bY1; const float *const bbY2 = (float *) &bY2; float y0 = bbe[0] - o->ym1*bbY1[0] - o->ym2*bbY2[0]; float y1 = bbe[1] - y0*bbY1[1] - o->ym1*bbY2[1]; float y2 = bbe[2] - y1*bbY1[2] - y0*bbY2[2]; float y3 = bbe[3] - y2*bbY1[3] - y1*bbY2[3]; o->x = bIn; o->ym1 = y3; o->ym2 = y2; *bOut = _mm_set_ps(y3, y2, y1, y0); #elif HV_SIMD_NEON float32x4_t xm1 = vextq_f32(o->x, bIn, 3); float32x4_t xm2 = vextq_f32(o->x, bIn, 2); float32x4_t a = vmulq_f32(bIn, bX0); float32x4_t b = vmulq_f32(xm1, bX1); float32x4_t c = vmulq_f32(xm2, bX2); float32x4_t d = vaddq_f32(a, b); float32x4_t e = vaddq_f32(c, d); float y0 = e[0] - o->ym1*bY1[0] - o->ym2*bY2[0]; float y1 = e[1] - y0*bY1[1] - o->ym1*bY2[1]; float y2 = e[2] - y1*bY1[2] - y0*bY2[2]; float y3 = e[3] - y2*bY1[3] - y1*bY2[3]; o->x = bIn; o->ym1 = y3; o->ym2 = y2; *bOut = (float32x4_t) {y0, y1, y2, y3}; #else const float y = bIn*bX0 + o->xm1*bX1 + o->xm2*bX2 - o->ym1*bY1 - o->ym2*bY2; o->xm2 = o->xm1; o->xm1 = bIn; o->ym2 = o->ym1; o->ym1 = y; *bOut = y; #endif } static void sBiquad_k_updateCoefficients(SignalBiquad_k *const o) { #if DEBUG // inspect the filter coefficients to ensure that the filter is stable // 1/((1-a*z^-1) * (1-b*z^-1)) float k = (o->a1*o->a1) - (4.0f*o->a2); float l = hv_sqrt_f(hv_abs_f(k)); float m_alpha = 0.0f; float m_beta = 0.0f; if (k < 0.0f) { // alpha is complex float r_alpha = o->a1 * 0.5f; float i_alpha = l * 0.5f; m_alpha = (r_alpha*r_alpha + i_alpha*i_alpha); // |alpha|^2 float r_beta = (o->a2 * r_alpha) / m_alpha; float i_beta = (o->a2 * -i_alpha) / m_alpha; m_alpha = hv_sqrt_f(m_alpha); m_beta = hv_sqrt_f(r_beta*r_beta + i_beta*i_beta); } else { // alpha is real float alpha = (o->a1 + l) * 0.5f; float beta = o->a2 / alpha; m_alpha = hv_abs_f(alpha); m_beta = hv_abs_f(beta); } hv_assert(m_alpha < 1.0f); hv_assert(m_beta < 1.0f); #endif // calculate all filter coefficients in the double domain #if HV_SIMD_AVX || HV_SIMD_SSE || HV_SIMD_NEON double b0 = (double) o->b0; double b1 = (double) o->b1; double b2 = (double) o->b2; double a1 = (double) -o->a1; double a2 = (double) -o->a2; double coeffs[4][8] = { { 0, 0, 0, b0, b1, b2, a1, a2 }, { 0, 0, b0, b1, b2, 0, a2, 0 }, { 0, b0, b1, b2, 0, 0, 0, 0 }, { b0, b1, b2, 0, 0, 0, 0, 0 }, }; for (int i = 0; i < 8; i++) { coeffs[1][i] += a1*coeffs[0][i]; coeffs[2][i] += a1*coeffs[1][i] + a2*coeffs[0][i]; coeffs[3][i] += a1*coeffs[2][i] + a2*coeffs[1][i]; } #if HV_SIMD_AVX || HV_SIMD_SSE o->coeff_xp3 = _mm_set_ps((float) coeffs[3][0], (float) coeffs[2][0], (float) coeffs[1][0], (float) coeffs[0][0]); o->coeff_xp2 = _mm_set_ps((float) coeffs[3][1], (float) coeffs[2][1], (float) coeffs[1][1], (float) coeffs[0][1]); o->coeff_xp1 = _mm_set_ps((float) coeffs[3][2], (float) coeffs[2][2], (float) coeffs[1][2], (float) coeffs[0][2]); o->coeff_x0 = _mm_set_ps((float) coeffs[3][3], (float) coeffs[2][3], (float) coeffs[1][3], (float) coeffs[0][3]); o->coeff_xm1 = _mm_set_ps((float) coeffs[3][4], (float) coeffs[2][4], (float) coeffs[1][4], (float) coeffs[0][4]); o->coeff_xm2 = _mm_set_ps((float) coeffs[3][5], (float) coeffs[2][5], (float) coeffs[1][5], (float) coeffs[0][5]); o->coeff_ym1 = _mm_set_ps((float) coeffs[3][6], (float) coeffs[2][6], (float) coeffs[1][6], (float) coeffs[0][6]); o->coeff_ym2 = _mm_set_ps((float) coeffs[3][7], (float) coeffs[2][7], (float) coeffs[1][7], (float) coeffs[0][7]); #else // HV_SIMD_NEON o->coeff_xp3 = (float32x4_t) {(float) coeffs[0][0], (float) coeffs[1][0], (float) coeffs[2][0], (float) coeffs[3][0]}; o->coeff_xp2 = (float32x4_t) {(float) coeffs[0][1], (float) coeffs[1][1], (float) coeffs[2][1], (float) coeffs[3][1]}; o->coeff_xp1 = (float32x4_t) {(float) coeffs[0][2], (float) coeffs[1][2], (float) coeffs[2][2], (float) coeffs[3][2]}; o->coeff_x0 = (float32x4_t) {(float) coeffs[0][3], (float) coeffs[1][3], (float) coeffs[2][3], (float) coeffs[3][3]}; o->coeff_xm1 = (float32x4_t) {(float) coeffs[0][4], (float) coeffs[1][4], (float) coeffs[2][4], (float) coeffs[3][4]}; o->coeff_xm2 = (float32x4_t) {(float) coeffs[0][5], (float) coeffs[1][5], (float) coeffs[2][5], (float) coeffs[3][5]}; o->coeff_ym1 = (float32x4_t) {(float) coeffs[0][6], (float) coeffs[1][6], (float) coeffs[2][6], (float) coeffs[3][6]}; o->coeff_ym2 = (float32x4_t) {(float) coeffs[0][7], (float) coeffs[1][7], (float) coeffs[2][7], (float) coeffs[3][7]}; #endif #endif // NOTE(mhroth): not necessary to calculate any coefficients for HV_SIMD_NONE case } hv_size_t sBiquad_k_init(SignalBiquad_k *o, float b0, float b1, float b2, float a1, float a2) { // initialise filter coefficients o->b0 = b0; o->b1 = b1; o->b2 = b2; o->a1 = a1; o->a2 = a2; sBiquad_k_updateCoefficients(o); // clear filter state #if HV_SIMD_AVX || HV_SIMD_SSE o->xm1 = _mm_setzero_ps(); o->xm2 = _mm_setzero_ps(); o->ym1 = _mm_setzero_ps(); o->ym2 = _mm_setzero_ps(); #elif HV_SIMD_NEON o->xm1 = vdupq_n_f32(0.0f); o->xm2 = vdupq_n_f32(0.0f); o->ym1 = vdupq_n_f32(0.0f); o->ym2 = vdupq_n_f32(0.0f); #else // HV_SIMD_NONE o->xm1 = 0.0f; o->xm2 = 0.0f; o->ym1 = 0.0f; o->ym2 = 0.0f; #endif return 0; } void sBiquad_k_onMessage(SignalBiquad_k *o, int letIn, const HvMessage *m) { if (msg_isFloat(m,0)) { switch (letIn) { case 1: o->b0 = msg_getFloat(m,0); break; case 2: o->b1 = msg_getFloat(m,0); break; case 3: o->b2 = msg_getFloat(m,0); break; case 4: o->a1 = msg_getFloat(m,0); break; case 5: o->a2 = msg_getFloat(m,0); break; default: return; } sBiquad_k_updateCoefficients(o); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalBiquad.h0000644000000000000000000001565500000000000017660 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_SIGNAL_BIQUAD_H_ #define _HEAVY_SIGNAL_BIQUAD_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif // http://en.wikipedia.org/wiki/Digital_biquad_filter typedef struct SignalBiquad { #if HV_SIMD_NONE hv_bufferf_t xm1; hv_bufferf_t xm2; #else hv_bufferf_t x; #endif float ym1; float ym2; } SignalBiquad; hv_size_t sBiquad_init(SignalBiquad *o); #if _WIN32 && !_WIN64 // NOTE(mhroth): unfortunately this specific definition of __hv_biquad_f for Win32 is necessary due to // the limited stack and alignment capabilities of the VS compiler in this mode #define __hv_biquad_f(o, bIn, bX0, bX1, bX2, bY1, bY2, bOut) __hv_biquad_f_win32(o, &bIn, &bX0, &bX1, &bX2, &bY1, &bY2, bOut) void __hv_biquad_f_win32(SignalBiquad *o, hv_bInf_t *bIn, hv_bInf_t *bX0, hv_bInf_t *bX1, hv_bInf_t *bX2, hv_bInf_t *bY1, hv_bInf_t *bY2, hv_bOutf_t bOut); #else void __hv_biquad_f(SignalBiquad *o, hv_bInf_t bIn, hv_bInf_t bX0, hv_bInf_t bX1, hv_bInf_t bX2, hv_bInf_t bY1, hv_bInf_t bY2, hv_bOutf_t bOut); #endif typedef struct SignalBiquad_k { #if HV_SIMD_AVX || HV_SIMD_SSE // preprocessed filter coefficients __m128 coeff_xp3; __m128 coeff_xp2; __m128 coeff_xp1; __m128 coeff_x0; __m128 coeff_xm1; __m128 coeff_xm2; __m128 coeff_ym1; __m128 coeff_ym2; // filter state __m128 xm1; __m128 xm2; __m128 ym1; __m128 ym2; #elif HV_SIMD_NEON float32x4_t coeff_xp3; float32x4_t coeff_xp2; float32x4_t coeff_xp1; float32x4_t coeff_x0; float32x4_t coeff_xm1; float32x4_t coeff_xm2; float32x4_t coeff_ym1; float32x4_t coeff_ym2; float32x4_t xm1; float32x4_t xm2; float32x4_t ym1; float32x4_t ym2; #else // HV_SIMD_NONE float xm1; float xm2; float ym1; float ym2; #endif // original filter coefficients float b0; // x[0] float b1; // x[-1] float b2; // x[-2] float a1; // y[-1] float a2; // y[-2] } SignalBiquad_k; hv_size_t sBiquad_k_init(SignalBiquad_k *o, float x0, float x1, float x2, float y1, float y2); void sBiquad_k_onMessage(SignalBiquad_k *o, int letIn, const HvMessage *m); static inline void __hv_biquad_k_f(SignalBiquad_k *o, hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX const __m128 c_xp3 = o->coeff_xp3; const __m128 c_xp2 = o->coeff_xp2; const __m128 c_xp1 = o->coeff_xp1; const __m128 c_x0 = o->coeff_x0; const __m128 c_xm1 = o->coeff_xm1; const __m128 c_xm2 = o->coeff_xm2; const __m128 c_ym1 = o->coeff_ym1; const __m128 c_ym2 = o->coeff_ym2; // lower half __m128 x3 = _mm_set1_ps(bIn[3]); __m128 x2 = _mm_set1_ps(bIn[2]); __m128 x1 = _mm_set1_ps(bIn[1]); __m128 x0 = _mm_set1_ps(bIn[0]); __m128 xm1 = o->xm1; __m128 xm2 = o->xm2; __m128 ym1 = o->ym1; __m128 ym2 = o->ym2; __m128 a = _mm_mul_ps(c_xp3, x3); __m128 b = _mm_mul_ps(c_xp2, x2); __m128 c = _mm_mul_ps(c_xp1, x1); __m128 d = _mm_mul_ps(c_x0, x0); __m128 e = _mm_mul_ps(c_xm1, xm1); __m128 f = _mm_mul_ps(c_xm2, xm2); __m128 g = _mm_mul_ps(c_ym1, ym1); __m128 h = _mm_mul_ps(c_ym2, ym2); __m128 i = _mm_add_ps(a, b); __m128 j = _mm_add_ps(c, d); __m128 k = _mm_add_ps(e, f); __m128 l = _mm_add_ps(g, h); __m128 m = _mm_add_ps(i, j); __m128 n = _mm_add_ps(k, l); __m128 lo_y = _mm_add_ps(m, n); // lower part of output buffer // upper half xm1 = x3; xm2 = x2; x3 = _mm_set1_ps(bIn[7]); x2 = _mm_set1_ps(bIn[6]); x1 = _mm_set1_ps(bIn[5]); x0 = _mm_set1_ps(bIn[4]); ym1 = _mm_set1_ps(lo_y[3]); ym2 = _mm_set1_ps(lo_y[2]); a = _mm_mul_ps(c_xp3, x3); b = _mm_mul_ps(c_xp2, x2); c = _mm_mul_ps(c_xp1, x1); d = _mm_mul_ps(c_x0, x0); e = _mm_mul_ps(c_xm1, xm1); f = _mm_mul_ps(c_xm2, xm2); g = _mm_mul_ps(c_ym1, ym1); h = _mm_mul_ps(c_ym2, ym2); i = _mm_add_ps(a, b); j = _mm_add_ps(c, d); k = _mm_add_ps(e, f); l = _mm_add_ps(g, h); m = _mm_add_ps(i, j); n = _mm_add_ps(k, l); __m128 up_y = _mm_add_ps(m, n); // upper part of output buffer o->xm1 = x3; o->xm2 = x2; o->ym1 = _mm_set1_ps(up_y[3]); o->ym2 = _mm_set1_ps(up_y[2]); *bOut = _mm256_insertf128_ps(_mm256_castps128_ps256(lo_y), up_y, 1); #elif HV_SIMD_SSE __m128 x3 = _mm_shuffle_ps(bIn, bIn, _MM_SHUFFLE(3,3,3,3)); __m128 x2 = _mm_shuffle_ps(bIn, bIn, _MM_SHUFFLE(2,2,2,2)); __m128 x1 = _mm_shuffle_ps(bIn, bIn, _MM_SHUFFLE(1,1,1,1)); __m128 x0 = _mm_shuffle_ps(bIn, bIn, _MM_SHUFFLE(0,0,0,0)); __m128 a = _mm_mul_ps(o->coeff_xp3, x3); __m128 b = _mm_mul_ps(o->coeff_xp2, x2); __m128 c = _mm_mul_ps(o->coeff_xp1, x1); __m128 d = _mm_mul_ps(o->coeff_x0, x0); __m128 e = _mm_mul_ps(o->coeff_xm1, o->xm1); __m128 f = _mm_mul_ps(o->coeff_xm2, o->xm2); __m128 g = _mm_mul_ps(o->coeff_ym1, o->ym1); __m128 h = _mm_mul_ps(o->coeff_ym2, o->ym2); __m128 i = _mm_add_ps(a, b); __m128 j = _mm_add_ps(c, d); __m128 k = _mm_add_ps(e, f); __m128 l = _mm_add_ps(g, h); __m128 m = _mm_add_ps(i, j); __m128 n = _mm_add_ps(k, l); __m128 y = _mm_add_ps(m, n); o->xm1 = x3; o->xm2 = x2; o->ym1 = _mm_shuffle_ps(y, y, _MM_SHUFFLE(3,3,3,3)); o->ym2 = _mm_shuffle_ps(y, y, _MM_SHUFFLE(2,2,2,2)); *bOut = y; #elif HV_SIMD_NEON float32x4_t x3 = vdupq_n_f32(bIn[3]); float32x4_t x2 = vdupq_n_f32(bIn[2]); float32x4_t x1 = vdupq_n_f32(bIn[1]); float32x4_t x0 = vdupq_n_f32(bIn[0]); float32x4_t a = vmulq_f32(o->coeff_xp3, x3); float32x4_t b = vmulq_f32(o->coeff_xp2, x2); float32x4_t c = vmulq_f32(o->coeff_xp1, x1); float32x4_t d = vmulq_f32(o->coeff_x0, x0); float32x4_t e = vmulq_f32(o->coeff_xm1, o->xm1); float32x4_t f = vmulq_f32(o->coeff_xm2, o->xm2); float32x4_t g = vmulq_f32(o->coeff_ym1, o->ym1); float32x4_t h = vmulq_f32(o->coeff_ym2, o->ym2); float32x4_t i = vaddq_f32(a, b); float32x4_t j = vaddq_f32(c, d); float32x4_t k = vaddq_f32(e, f); float32x4_t l = vaddq_f32(g, h); float32x4_t m = vaddq_f32(i, j); float32x4_t n = vaddq_f32(k, l); float32x4_t y = vaddq_f32(m, n); o->xm1 = x3; o->xm2 = x2; o->ym1 = vdupq_n_f32(y[3]); o->ym2 = vdupq_n_f32(y[2]); *bOut = y; #else // HV_SIMD_NONE float y = o->b0*bIn + o->b1*o->xm1 + o->b2*o->xm2 - o->a1*o->ym1 - o->a2*o->ym2; o->xm2 = o->xm1; o->xm1 = bIn; o->ym2 = o->ym1; o->ym1 = y; *bOut = y; #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_SIGNAL_BIQUAD_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalCPole.c0000644000000000000000000000455400000000000017444 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalCPole.h" hv_size_t sCPole_init(SignalCPole *o) { #if HV_SIMD_AVX sDel1_init(&o->sDel1_8kZ3w); sDel1_init(&o->sDel1_sy3YC); sDel1_init(&o->sDel1_GjjjE); sDel1_init(&o->sDel1_52HYk); sDel1_init(&o->sDel1_lXpu3); sDel1_init(&o->sDel1_orza7); sDel1_init(&o->sDel1_K7tpr); sDel1_init(&o->sDel1_yfNee); sDel1_init(&o->sDel1_hl63z); sDel1_init(&o->sDel1_etJkN); sDel1_init(&o->sDel1_BW4zg); sDel1_init(&o->sDel1_0z8gy); sDel1_init(&o->sDel1_0F5sm); sDel1_init(&o->sDel1_i4rAW); sDel1_init(&o->sDel1_ux1Jv); sDel1_init(&o->sDel1_FVaak); sDel1_init(&o->sDel1_oEc0p); sDel1_init(&o->sDel1_1AVVz); sDel1_init(&o->sDel1_qp6ty); sDel1_init(&o->sDel1_bkttO); sDel1_init(&o->sDel1_60VsH); sDel1_init(&o->sDel1_TbY4f); sDel1_init(&o->sDel1_bNHHm); sDel1_init(&o->sDel1_mijYH); sDel1_init(&o->sDel1_anxSw); sDel1_init(&o->sDel1_YiP2h); sDel1_init(&o->sDel1_anyeH); sDel1_init(&o->sDel1_Vtq0Y); __hv_zero_f(&o->ymr); __hv_zero_f(&o->ymi); #elif HV_SIMD_SSE || HV_SIMD_NEON sDel1_init(&o->sDel1_j0EQa); sDel1_init(&o->sDel1_4REN6); sDel1_init(&o->sDel1_5z88r); sDel1_init(&o->sDel1_CxDdp); sDel1_init(&o->sDel1_8zCWF); sDel1_init(&o->sDel1_1A4op); sDel1_init(&o->sDel1_ldSdM); sDel1_init(&o->sDel1_sOZ64); sDel1_init(&o->sDel1_mpbqn); sDel1_init(&o->sDel1_sBC7F); sDel1_init(&o->sDel1_bZG8k); sDel1_init(&o->sDel1_Wtjof); __hv_zero_f(&o->ymr); __hv_zero_f(&o->ymi); #else o->ymr = 0.0f; o->ymi = 0.0f; #endif return 0; } void sCPole_onMessage(HeavyContextInterface *_c, SignalCPole *o, int letIn, const HvMessage *m) { // TODO } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalCPole.h0000644000000000000000000002673400000000000017455 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_CPOLE_H_ #define _SIGNAL_CPOLE_H_ #include "HvHeavyInternal.h" #include "HvSignalDel1.h" #ifdef __cplusplus extern "C" { #endif // implements y[n] = x[n] - a*y[n-1] // H(z) = 1/(1+a*z^-1) typedef struct SignalCPole { #if HV_SIMD_AVX SignalDel1 sDel1_8kZ3w; SignalDel1 sDel1_sy3YC; SignalDel1 sDel1_GjjjE; SignalDel1 sDel1_52HYk; SignalDel1 sDel1_lXpu3; SignalDel1 sDel1_orza7; SignalDel1 sDel1_K7tpr; SignalDel1 sDel1_yfNee; SignalDel1 sDel1_hl63z; SignalDel1 sDel1_etJkN; SignalDel1 sDel1_BW4zg; SignalDel1 sDel1_0z8gy; SignalDel1 sDel1_0F5sm; SignalDel1 sDel1_i4rAW; SignalDel1 sDel1_ux1Jv; SignalDel1 sDel1_FVaak; SignalDel1 sDel1_oEc0p; SignalDel1 sDel1_1AVVz; SignalDel1 sDel1_qp6ty; SignalDel1 sDel1_bkttO; SignalDel1 sDel1_60VsH; SignalDel1 sDel1_TbY4f; SignalDel1 sDel1_bNHHm; SignalDel1 sDel1_mijYH; SignalDel1 sDel1_anxSw; SignalDel1 sDel1_YiP2h; SignalDel1 sDel1_anyeH; SignalDel1 sDel1_Vtq0Y; hv_bufferf_t ymr; hv_bufferf_t ymi; #elif HV_SIMD_SSE || HV_SIMD_NEON SignalDel1 sDel1_j0EQa; SignalDel1 sDel1_4REN6; SignalDel1 sDel1_5z88r; SignalDel1 sDel1_CxDdp; SignalDel1 sDel1_8zCWF; SignalDel1 sDel1_1A4op; SignalDel1 sDel1_ldSdM; SignalDel1 sDel1_sOZ64; SignalDel1 sDel1_mpbqn; SignalDel1 sDel1_sBC7F; SignalDel1 sDel1_bZG8k; SignalDel1 sDel1_Wtjof; hv_bufferf_t ymr; hv_bufferf_t ymi; #else hv_bufferf_t ymr; hv_bufferf_t ymi; #endif } SignalCPole; hv_size_t sCPole_init(SignalCPole *o); void sCPole_onMessage(HeavyContextInterface *_c, SignalCPole *o, int letIn, const HvMessage *m); #if _WIN32 && !_WIN64 #define __hv_cpole_f(o, bIn0, bIn1, bIn2, bIn3, bOut0, bOut1) __hv_cpole_f_win32(o, &bIn0, &bIn1, &bIn2, &bIn3, bOut0, bOut1) static inline void __hv_cpole_f_win32(SignalCPole *o, hv_bInf_t *_bIn0, hv_bInf_t *_bIn1, hv_bInf_t *_bIn2, hv_bInf_t *_bIn3, hv_bOutf_t bOut0, hv_bOutf_t bOut1) { hv_bInf_t bIn0 = *_bIn0; hv_bInf_t bIn1 = *_bIn1; hv_bInf_t bIn2 = *_bIn2; hv_bInf_t bIn3 = *_bIn3; #else static inline void __hv_cpole_f(SignalCPole *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bInf_t bIn3, hv_bOutf_t bOut0, hv_bOutf_t bOut1) { #endif #if HV_SIMD_AVX hv_bufferf_t Bf0, Bf1, Bf2, Bf3, Bf4, Bf5, Bf6, Bf7, Bf8, Bf9, Bf10, Bf11, Bf12, Bf13, Bf14; __hv_del1_f(&o->sDel1_8kZ3w, bIn0, VOf(Bf0)); __hv_del1_f(&o->sDel1_sy3YC, bIn1, VOf(Bf1)); __hv_mul_f(VIf(Bf1), bIn2, VOf(Bf2)); __hv_fma_f(VIf(Bf0), bIn3, VIf(Bf2), VOf(Bf2)); __hv_mul_f(VIf(Bf0), bIn2, VOf(Bf3)); __hv_mul_f(VIf(Bf1), bIn3, VOf(Bf4)); __hv_sub_f(VIf(Bf3), VIf(Bf4), VOf(Bf4)); __hv_sub_f(bIn1, VIf(Bf2), VOf(Bf2)); __hv_del1_f(&o->sDel1_GjjjE, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_52HYk, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_lXpu3, bIn2, VOf(Bf3)); __hv_del1_f(&o->sDel1_orza7, bIn3, VOf(Bf5)); __hv_mul_f(bIn2, VIf(Bf3), VOf(Bf6)); __hv_mul_f(bIn3, VIf(Bf5), VOf(Bf7)); __hv_sub_f(VIf(Bf6), VIf(Bf7), VOf(Bf7)); __hv_mul_f(bIn3, VIf(Bf3), VOf(Bf6)); __hv_fma_f(bIn2, VIf(Bf5), VIf(Bf6), VOf(Bf6)); __hv_mul_f(VIf(Bf0), VIf(Bf6), VOf(Bf8)); __hv_fma_f(VIf(Bf1), VIf(Bf7), VIf(Bf8), VOf(Bf8)); __hv_mul_f(VIf(Bf0), VIf(Bf7), VOf(Bf9)); __hv_mul_f(VIf(Bf1), VIf(Bf6), VOf(Bf10)); __hv_sub_f(VIf(Bf9), VIf(Bf10), VOf(Bf10)); __hv_add_f(VIf(Bf2), VIf(Bf8), VOf(Bf8)); __hv_del1_f(&o->sDel1_K7tpr, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_yfNee, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_hl63z, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_etJkN, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf7), VIf(Bf3), VOf(Bf2)); __hv_mul_f(VIf(Bf6), VIf(Bf5), VOf(Bf9)); __hv_sub_f(VIf(Bf2), VIf(Bf9), VOf(Bf9)); __hv_mul_f(VIf(Bf7), VIf(Bf5), VOf(Bf7)); __hv_fma_f(VIf(Bf6), VIf(Bf3), VIf(Bf7), VOf(Bf7)); __hv_mul_f(VIf(Bf1), VIf(Bf9), VOf(Bf6)); __hv_fma_f(VIf(Bf0), VIf(Bf7), VIf(Bf6), VOf(Bf6)); __hv_mul_f(VIf(Bf0), VIf(Bf9), VOf(Bf2)); __hv_mul_f(VIf(Bf1), VIf(Bf7), VOf(Bf11)); __hv_sub_f(VIf(Bf2), VIf(Bf11), VOf(Bf11)); __hv_sub_f(VIf(Bf8), VIf(Bf6), VOf(Bf6)); __hv_del1_f(&o->sDel1_BW4zg, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_0z8gy, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_0F5sm, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_i4rAW, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf7), VIf(Bf3), VOf(Bf8)); __hv_fma_f(VIf(Bf9), VIf(Bf5), VIf(Bf8), VOf(Bf8)); __hv_mul_f(VIf(Bf9), VIf(Bf3), VOf(Bf9)); __hv_mul_f(VIf(Bf7), VIf(Bf5), VOf(Bf7)); __hv_sub_f(VIf(Bf9), VIf(Bf7), VOf(Bf7)); __hv_mul_f(VIf(Bf0), VIf(Bf7), VOf(Bf9)); __hv_mul_f(VIf(Bf1), VIf(Bf8), VOf(Bf2)); __hv_sub_f(VIf(Bf9), VIf(Bf2), VOf(Bf2)); __hv_mul_f(VIf(Bf0), VIf(Bf8), VOf(Bf9)); __hv_fma_f(VIf(Bf1), VIf(Bf7), VIf(Bf9), VOf(Bf9)); __hv_add_f(VIf(Bf6), VIf(Bf9), VOf(Bf9)); __hv_del1_f(&o->sDel1_ux1Jv, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_FVaak, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_oEc0p, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_1AVVz, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf8), VIf(Bf3), VOf(Bf6)); __hv_fma_f(VIf(Bf7), VIf(Bf5), VIf(Bf6), VOf(Bf6)); __hv_mul_f(VIf(Bf7), VIf(Bf3), VOf(Bf7)); __hv_mul_f(VIf(Bf8), VIf(Bf5), VOf(Bf8)); __hv_sub_f(VIf(Bf7), VIf(Bf8), VOf(Bf8)); __hv_mul_f(VIf(Bf0), VIf(Bf8), VOf(Bf7)); __hv_mul_f(VIf(Bf1), VIf(Bf6), VOf(Bf12)); __hv_sub_f(VIf(Bf7), VIf(Bf12), VOf(Bf12)); __hv_mul_f(VIf(Bf1), VIf(Bf8), VOf(Bf7)); __hv_fma_f(VIf(Bf0), VIf(Bf6), VIf(Bf7), VOf(Bf7)); __hv_sub_f(VIf(Bf9), VIf(Bf7), VOf(Bf7)); __hv_del1_f(&o->sDel1_qp6ty, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_bkttO, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_60VsH, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_TbY4f, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf6), VIf(Bf3), VOf(Bf9)); __hv_fma_f(VIf(Bf8), VIf(Bf5), VIf(Bf9), VOf(Bf9)); __hv_mul_f(VIf(Bf8), VIf(Bf3), VOf(Bf8)); __hv_mul_f(VIf(Bf6), VIf(Bf5), VOf(Bf6)); __hv_sub_f(VIf(Bf8), VIf(Bf6), VOf(Bf6)); __hv_mul_f(VIf(Bf0), VIf(Bf9), VOf(Bf8)); __hv_fma_f(VIf(Bf1), VIf(Bf6), VIf(Bf8), VOf(Bf8)); __hv_mul_f(VIf(Bf0), VIf(Bf6), VOf(Bf13)); __hv_mul_f(VIf(Bf1), VIf(Bf9), VOf(Bf14)); __hv_sub_f(VIf(Bf13), VIf(Bf14), VOf(Bf14)); __hv_add_f(VIf(Bf7), VIf(Bf8), VOf(Bf8)); __hv_del1_f(&o->sDel1_bNHHm, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_mijYH, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_anxSw, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_YiP2h, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf6), VIf(Bf5), VOf(Bf7)); __hv_fma_f(VIf(Bf9), VIf(Bf3), VIf(Bf7), VOf(Bf7)); __hv_mul_f(VIf(Bf6), VIf(Bf3), VOf(Bf6)); __hv_mul_f(VIf(Bf9), VIf(Bf5), VOf(Bf9)); __hv_sub_f(VIf(Bf6), VIf(Bf9), VOf(Bf9)); __hv_mul_f(VIf(Bf0), VIf(Bf9), VOf(Bf6)); __hv_mul_f(VIf(Bf1), VIf(Bf7), VOf(Bf13)); __hv_sub_f(VIf(Bf6), VIf(Bf13), VOf(Bf13)); __hv_mul_f(VIf(Bf0), VIf(Bf7), VOf(Bf0)); __hv_fma_f(VIf(Bf1), VIf(Bf9), VIf(Bf0), VOf(Bf0)); __hv_sub_f(VIf(Bf8), VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_anyeH, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_Vtq0Y, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf9), VIf(Bf3), VOf(Bf8)); __hv_mul_f(VIf(Bf7), VIf(Bf5), VOf(Bf1)); __hv_sub_f(VIf(Bf8), VIf(Bf1), VOf(Bf1)); __hv_mul_f(VIf(Bf9), VIf(Bf5), VOf(Bf5)); __hv_fma_f(VIf(Bf7), VIf(Bf3), VIf(Bf5), VOf(Bf5)); Bf3 = o->ymr; Bf4 = o->ymi; __hv_mul_f(VIf(Bf1), VIf(Bf3), VOf(Bf9)); __hv_mul_f(VIf(Bf5), VIf(Bf7), VOf(Bf8)); __hv_sub_f(VIf(Bf9), VIf(Bf8), VOf(Bf8)); __hv_mul_f(VIf(Bf1), VIf(Bf7), VOf(Bf7)); __hv_fma_f(VIf(Bf5), VIf(Bf3), VIf(Bf7), VOf(Bf7)); __hv_add_f(VIf(Bf0), VIf(Bf7), VOf(Bf7)); o->ymi = Bf7; __hv_sub_f(bIn0, VIf(Bf4), VOf(Bf4)); __hv_add_f(VIf(Bf4), VIf(Bf10), VOf(Bf10)); __hv_sub_f(VIf(Bf10), VIf(Bf11), VOf(Bf11)); __hv_add_f(VIf(Bf11), VIf(Bf2), VOf(Bf2)); __hv_sub_f(VIf(Bf2), VIf(Bf12), VOf(Bf12)); __hv_add_f(VIf(Bf12), VIf(Bf14), VOf(Bf14)); __hv_sub_f(VIf(Bf14), VIf(Bf13), VOf(Bf13)); __hv_add_f(VIf(Bf13), VIf(Bf8), VOf(Bf8)); *bOut0 = Bf8; *bOut0 = Bf7; o->ymr = Bf8; #elif HV_SIMD_SSE || HV_SIMD_NEON hv_bufferf_t Bf0, Bf1, Bf2, Bf3, Bf4, Bf5, Bf6, Bf7, Bf8, Bf9, Bf10; __hv_del1_f(&o->sDel1_j0EQa, bIn0, VOf(Bf0)); __hv_del1_f(&o->sDel1_4REN6, bIn1, VOf(Bf1)); __hv_mul_f(VIf(Bf0), bIn3, VOf(Bf2)); __hv_fma_f(VIf(Bf1), bIn2, VIf(Bf2), VOf(Bf2)); __hv_mul_f(VIf(Bf0), bIn2, VOf(Bf3)); __hv_mul_f(VIf(Bf1), bIn3, VOf(Bf4)); __hv_sub_f(VIf(Bf3), VIf(Bf4), VOf(Bf4)); __hv_sub_f(bIn1, VIf(Bf2), VOf(Bf2)); __hv_del1_f(&o->sDel1_5z88r, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_CxDdp, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_8zCWF, bIn2, VOf(Bf3)); __hv_del1_f(&o->sDel1_1A4op, bIn3, VOf(Bf5)); __hv_mul_f(bIn3, VIf(Bf3), VOf(Bf6)); __hv_fma_f(bIn2, VIf(Bf5), VIf(Bf6), VOf(Bf6)); __hv_mul_f(bIn2, VIf(Bf3), VOf(Bf7)); __hv_mul_f(bIn3, VIf(Bf5), VOf(Bf8)); __hv_sub_f(VIf(Bf7), VIf(Bf8), VOf(Bf8)); __hv_mul_f(VIf(Bf0), VIf(Bf8), VOf(Bf7)); __hv_mul_f(VIf(Bf1), VIf(Bf6), VOf(Bf9)); __hv_sub_f(VIf(Bf7), VIf(Bf9), VOf(Bf9)); __hv_mul_f(VIf(Bf0), VIf(Bf6), VOf(Bf7)); __hv_fma_f(VIf(Bf1), VIf(Bf8), VIf(Bf7), VOf(Bf7)); __hv_add_f(VIf(Bf2), VIf(Bf7), VOf(Bf7)); __hv_del1_f(&o->sDel1_ldSdM, VIf(Bf0), VOf(Bf0)); __hv_del1_f(&o->sDel1_sOZ64, VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_mpbqn, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_sBC7F, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf6), VIf(Bf3), VOf(Bf2)); __hv_fma_f(VIf(Bf8), VIf(Bf5), VIf(Bf2), VOf(Bf2)); __hv_mul_f(VIf(Bf8), VIf(Bf3), VOf(Bf8)); __hv_mul_f(VIf(Bf6), VIf(Bf5), VOf(Bf6)); __hv_sub_f(VIf(Bf8), VIf(Bf6), VOf(Bf6)); __hv_mul_f(VIf(Bf0), VIf(Bf6), VOf(Bf8)); __hv_mul_f(VIf(Bf1), VIf(Bf2), VOf(Bf10)); __hv_sub_f(VIf(Bf8), VIf(Bf10), VOf(Bf10)); __hv_mul_f(VIf(Bf1), VIf(Bf6), VOf(Bf1)); __hv_fma_f(VIf(Bf0), VIf(Bf2), VIf(Bf1), VOf(Bf1)); __hv_sub_f(VIf(Bf7), VIf(Bf1), VOf(Bf1)); __hv_del1_f(&o->sDel1_bZG8k, VIf(Bf3), VOf(Bf3)); __hv_del1_f(&o->sDel1_Wtjof, VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf6), VIf(Bf3), VOf(Bf7)); __hv_mul_f(VIf(Bf2), VIf(Bf5), VOf(Bf0)); __hv_sub_f(VIf(Bf7), VIf(Bf0), VOf(Bf0)); __hv_mul_f(VIf(Bf2), VIf(Bf3), VOf(Bf3)); __hv_fma_f(VIf(Bf6), VIf(Bf5), VIf(Bf3), VOf(Bf3)); Bf5 = o->ymr; Bf6 = o->ymi; __hv_mul_f(VIf(Bf3), VIf(Bf5), VOf(Bf2)); __hv_fma_f(VIf(Bf0), VIf(Bf6), VIf(Bf2), VOf(Bf2)); __hv_mul_f(VIf(Bf0), VIf(Bf5), VOf(Bf5)); __hv_mul_f(VIf(Bf3), VIf(Bf6), VOf(Bf6)); __hv_sub_f(VIf(Bf5), VIf(Bf6), VOf(Bf6)); __hv_add_f(VIf(Bf1), VIf(Bf2), VOf(Bf2)); *bOut1 = Bf2; __hv_sub_f(bIn0, VIf(Bf4), VOf(Bf4)); __hv_add_f(VIf(Bf4), VIf(Bf9), VOf(Bf9)); __hv_sub_f(VIf(Bf9), VIf(Bf10), VOf(Bf10)); __hv_add_f(VIf(Bf10), VIf(Bf6), VOf(Bf6)); *bOut0 = Bf6; o->ymr = Bf6; o->ymi = Bf2; #else *bOut0 = bIn0 - (bIn2*o->ymr - bIn3*o->ymi); *bOut1 = bIn1 - (bIn2*o->ymi + bIn3*o->ymr); o->ymr = *bOut0; o->ymi = *bOut1; #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_CPOLE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalConvolution.c0000644000000000000000000001132500000000000020753 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalConvolution.h" hv_size_t sConv_init(SignalConvolution *o, struct HvTable *table, const int size) { o->table = table; hv_size_t numBytes = hTable_init(&o->inputs, size); return numBytes; } void sConv_free(SignalConvolution *o) { o->table = NULL; hTable_free(&o->inputs); } void sConv_onMessage(HeavyContextInterface *_c, SignalConvolution *o, int letIndex, const HvMessage *m, void *sendMessage) { switch (letIndex) { case 1: { if (msg_isHashLike(m,0)) { HvTable *table = hv_table_get(_c, msg_getHash(m,0)); if (table != NULL) { o->table = table; if (hTable_getSize(&o->inputs) != hTable_getSize(table)) { hTable_resize(&o->inputs, (hv_uint32_t) hv_min_ui(hTable_getSize(&o->inputs), hTable_getSize(table))); } } } break; } case 2: { if (msg_isFloat(m,0)) { // convolution size should never exceed the coefficient table size hTable_resize(&o->inputs, (hv_uint32_t) msg_getFloat(m,0)); } break; } default: return; } } static hv_bInf_t sConv_kernel(hv_bInf_t bIn, hv_bInf_t bInPrev, hv_bInf_t bInCoeff) { #if HV_SIMD_AVX hv_assert(false & "There is no AVX implementation of __hv_conv_f"); hv_bufferf_t d = _mm256_setzero_ps(); #elif HV_SIMD_SSE __m128 c0 = _mm_shuffle_ps(bInCoeff, bInCoeff, _MM_SHUFFLE(0,0,0,0)); __m128 c1 = _mm_shuffle_ps(bInCoeff, bInCoeff, _MM_SHUFFLE(1,1,1,1)); __m128 c2 = _mm_shuffle_ps(bInCoeff, bInCoeff, _MM_SHUFFLE(2,2,2,2)); __m128 c3 = _mm_shuffle_ps(bInCoeff, bInCoeff, _MM_SHUFFLE(3,3,3,3)); __m128 m0 = bIn; __m128 m2 = _mm_shuffle_ps(bInPrev, bIn, _MM_SHUFFLE(1,0,3,2)); __m128 m1 = _mm_shuffle_ps(m2, bIn, _MM_SHUFFLE(2,1,2,1)); __m128 m3 = _mm_shuffle_ps(bInPrev, m2, _MM_SHUFFLE(2,1,2,1)); hv_bufferf_t a, b, c, d; __hv_mul_f(c0, m0, &a); __hv_fma_f(c1, m1, a, &b); __hv_fma_f(c2, m2, b, &c); __hv_fma_f(c3, m3, c, &d); #elif HV_SIMD_NEON float32x4_t c0 = vdupq_lane_f32(vget_low_f32(bInCoeff), 0); float32x4_t c1 = vdupq_lane_f32(vget_low_f32(bInCoeff), 1); float32x4_t c2 = vdupq_lane_f32(vget_high_f32(bInCoeff), 0); float32x4_t c3 = vdupq_lane_f32(vget_high_f32(bInCoeff), 1); float32x4_t m0 = bIn; float32x4_t m1 = vextq_f32(bInPrev, bIn, 0x3); float32x4_t m2 = vextq_f32(bInPrev, bIn, 0x2); float32x4_t m3 = vextq_f32(bInPrev, bIn, 0x1); hv_bufferf_t a, b, c, d; __hv_mul_f(c0, m0, &a); __hv_fma_f(c1, m1, a, &b); __hv_fma_f(c2, m2, b, &c); __hv_fma_f(c3, m3, c, &d); #else // HV_SIMD_NONE hv_bufferf_t d = bIn * bInCoeff; #endif return d; } static inline int wrap(const int i, const int n) { if (i < 0) return (i+n); if (i >= n) return (i-n); return i; } void __hv_conv_f(SignalConvolution *o, hv_bInf_t bIn, hv_bOutf_t bOut) { hv_assert(o->table != NULL); float *const coeffs = hTable_getBuffer(o->table); hv_assert(coeffs != NULL); const int n = hTable_getSize(o->table); // length fir filter hv_assert((n&HV_N_SIMD_MASK) == 0); // n is a multiple of HV_N_SIMD float *const inputs = hTable_getBuffer(&o->inputs); hv_assert(inputs != NULL); const int m = hTable_getSize(&o->inputs); // length of input buffer. hv_assert(m >= n); const int h_orig = hTable_getHead(&o->inputs); hv_bufferf_t x0, out; x0 = bIn; __hv_zero_f(&out); int i = 0; int h = wrap(h_orig-HV_N_SIMD, m); for (; h >= 0; i+=HV_N_SIMD, h-=HV_N_SIMD) { hv_bufferf_t x1, c, o; __hv_load_f(inputs+h, &x1); __hv_load_f(coeffs+i, &c); o = sConv_kernel(x0, x1, c); __hv_add_f(o, out, &out); x0 = x1; } h += m; // h = m-HV_N_SIMD; for (; i < n; i+=HV_N_SIMD, h-=HV_N_SIMD) { hv_bufferf_t x1, c, o; __hv_load_f(inputs+h, &x1); __hv_load_f(coeffs+i, &c); o = sConv_kernel(x0, x1, c); __hv_add_f(o, out, &out); x0 = x1; } *bOut = out; __hv_store_f(inputs+h_orig, bIn); // store the new input to the inputs buffer hTable_setHead(&o->inputs, wrap(h_orig+HV_N_SIMD, m)); } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalConvolution.h0000644000000000000000000000262500000000000020763 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_CONVOLUTION_H_ #define _SIGNAL_CONVOLUTION_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalConvolution { struct HvTable *table; struct HvTable inputs; } SignalConvolution; hv_size_t sConv_init(SignalConvolution *o, struct HvTable *coeffs, const int size); void sConv_free(SignalConvolution *o); void sConv_onMessage(HeavyContextInterface *_c, SignalConvolution *o, int letIndex, const HvMessage *m, void *sendMessage); void __hv_conv_f(SignalConvolution *o, hv_bInf_t bIn, hv_bOutf_t bOut); #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_CONVOLUTION_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalDel1.c0000644000000000000000000000255200000000000017223 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalDel1.h" hv_size_t sDel1_init(SignalDel1 *o) { #if HV_SIMD_AVX o->x = _mm256_setzero_ps(); #elif HV_SIMD_SSE o->x = _mm_setzero_ps(); #elif HV_SIMD_NEON o->x = vdupq_n_f32(0.0f); #else o->x = 0.0f; #endif return 0; } void sDel1_onMessage(HeavyContextInterface *_c, SignalDel1 *o, int letIn, const HvMessage *m) { if (letIn == 2) { if (msg_compareSymbol(m, 0, "clear")) { #if HV_SIMD_AVX o->x = _mm256_setzero_ps(); #elif HV_SIMD_SSE o->x = _mm_setzero_ps(); #elif HV_SIMD_NEON o->x = vdupq_n_f32(0.0f); #else o->x = 0.0f; #endif } } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalDel1.h0000644000000000000000000000335100000000000017226 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_DEL1_H_ #define _SIGNAL_DEL1_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalDel1 { hv_bufferf_t x; } SignalDel1; hv_size_t sDel1_init(SignalDel1 *o); void sDel1_onMessage(HeavyContextInterface *_c, SignalDel1 *o, int letIn, const HvMessage *m); static inline void __hv_del1_f(SignalDel1 *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX __m256 x = _mm256_permute_ps(bIn0, _MM_SHUFFLE(2,1,0,3)); // [3 0 1 2 7 4 5 6] __m256 n = _mm256_permute2f128_ps(o->x,x,0x1); // [h e f g 3 0 1 2] *bOut = _mm256_blend_ps(x, n, 0x11); // [h 0 1 2 3 4 5 6] o->x = x; #elif HV_SIMD_SSE __m128 n = _mm_blend_ps(o->x, bIn0, 0x7); *bOut = _mm_shuffle_ps(n, n, _MM_SHUFFLE(2,1,0,3)); o->x = bIn0; #elif HV_SIMD_NEON *bOut = vextq_f32(o->x, bIn0, 3); o->x = bIn0; #else *bOut = o->x; o->x = bIn0; #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_DEL1_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalEnvelope.c0000644000000000000000000001333400000000000020213 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalEnvelope.h" #ifndef M_PI #define M_PI 3.14159265358979323846 // in case math.h doesn't include this defintion #endif static int ceilToNearestBlock(int x, int n) { return (int) (ceilf(((float) x) / ((float) n)) * n); } hv_size_t sEnv_init(SignalEnvelope *o, int windowSize, int period) { // 0 < BLOCK_SIZE <= period <= windowSize // NOTE(mhroth): this is an artificial limit, but it greatly simplifies development o->windowSize = (windowSize <= HV_N_SIMD) ? HV_N_SIMD : ceilToNearestBlock(windowSize, HV_N_SIMD); o->period = (period <= HV_N_SIMD) ? HV_N_SIMD : (period > o->windowSize) ? o->windowSize : ceilToNearestBlock(period, HV_N_SIMD); o->numSamplesInBuffer = 0; hv_size_t numBytes = 0; // allocate the signal buffer // the buffer is overdimensioned in this way (up to double), but not by much and so what const int bufferLength = 2 * o->windowSize; o->buffer = (float *) hv_malloc(bufferLength*sizeof(float)); hv_assert(o->buffer != NULL); numBytes += bufferLength*sizeof(float); // allocate and calculate the hanning weights o->hanningWeights = (float *) hv_malloc(o->windowSize*sizeof(float)); hv_assert(o->hanningWeights != NULL); numBytes += o->windowSize*sizeof(float); float hanningSum = 0.0f; for (int i = 0; i < o->windowSize; i++) { const float w = 0.5f * (1.0f - cosf(((float) (2.0 * M_PI * i)) / ((float) (o->windowSize - 1)))); o->hanningWeights[i] = w; hanningSum += w; } for (int i = 0; i < o->windowSize; i++) { // normalise the hanning coefficients such that they represent a normalised weighted averaging o->hanningWeights[i] /= hanningSum; } return numBytes; } void sEnv_free(SignalEnvelope *o) { hv_free(o->hanningWeights); hv_free(o->buffer); } static void sEnv_sendMessage(HeavyContextInterface *_c, SignalEnvelope *o, float rms, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { // finish RMS calculation. sqrt is removed as it can be combined with the log operation. // result is normalised such that 1 RMS == 100 dB rms = (4.342944819032518f * hv_log_f(rms)) + 100.0f; // prepare the outgoing message. Schedule it at the beginning of the next block. HvMessage *const m = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(m, hv_getCurrentSample(_c) + HV_N_SIMD, (rms < 0.0f) ? 0.0f : rms); hv_scheduleMessageForObject(_c, m, sendMessage, 0); hv_memcpy(o->buffer, o->buffer+o->period, sizeof(float)*(o->numSamplesInBuffer - o->period)); o->numSamplesInBuffer -= o->period; } void sEnv_process(HeavyContextInterface *_c, SignalEnvelope *o, hv_bInf_t bIn, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { #if HV_SIMD_AVX _mm256_stream_ps(o->buffer+o->numSamplesInBuffer, _mm256_mul_ps(bIn,bIn)); // store bIn^2, no need to cache block o->numSamplesInBuffer += HV_N_SIMD; if (o->numSamplesInBuffer >= o->windowSize) { int n4 = o->windowSize & ~HV_N_SIMD_MASK; __m256 sum = _mm256_setzero_ps(); while (n4) { __m256 x = _mm256_load_ps(o->buffer + n4 - HV_N_SIMD); __m256 h = _mm256_load_ps(o->hanningWeights + n4 - HV_N_SIMD); x = _mm256_mul_ps(x, h); sum = _mm256_add_ps(sum, x); n4 -= HV_N_SIMD; } sum = _mm256_hadd_ps(sum,sum); // horizontal sum sum = _mm256_hadd_ps(sum,sum); sEnv_sendMessage(_c, o, sum[0]+sum[4], sendMessage); // updates numSamplesInBuffer } #elif HV_SIMD_SSE _mm_stream_ps(o->buffer+o->numSamplesInBuffer, _mm_mul_ps(bIn,bIn)); // store bIn^2, no need to cache block o->numSamplesInBuffer += HV_N_SIMD; if (o->numSamplesInBuffer >= o->windowSize) { int n4 = o->windowSize & ~HV_N_SIMD_MASK; __m128 sum = _mm_setzero_ps(); while (n4) { __m128 x = _mm_load_ps(o->buffer + n4 - HV_N_SIMD); __m128 h = _mm_load_ps(o->hanningWeights + n4 - HV_N_SIMD); x = _mm_mul_ps(x, h); sum = _mm_add_ps(sum, x); n4 -= HV_N_SIMD; } sum = _mm_hadd_ps(sum,sum); // horizontal sum sum = _mm_hadd_ps(sum,sum); float f; _mm_store_ss(&f, sum); sEnv_sendMessage(_c, o, f, sendMessage); } #elif HV_SIMD_NEON vst1q_f32(o->buffer+o->numSamplesInBuffer, vmulq_f32(bIn,bIn)); // store bIn^2, no need to cache block o->numSamplesInBuffer += HV_N_SIMD; if (o->numSamplesInBuffer >= o->windowSize) { int n4 = o->windowSize & ~HV_N_SIMD_MASK; float32x4_t sum = vdupq_n_f32(0.0f); while (n4) { float32x4_t x = vld1q_f32(o->buffer + n4 - HV_N_SIMD); float32x4_t h = vld1q_f32(o->hanningWeights + n4 - HV_N_SIMD); x = vmulq_f32(x, h); sum = vaddq_f32(sum, x); n4 -= HV_N_SIMD; } sEnv_sendMessage(_c, o, sum[0]+sum[1]+sum[2]+sum[3], sendMessage); } #else // HV_SIMD_NONE o->buffer[o->numSamplesInBuffer] = (bIn*bIn); o->numSamplesInBuffer += HV_N_SIMD; if (o->numSamplesInBuffer >= o->windowSize) { float sum = 0.0f; for (int i = 0; i < o->windowSize; ++i) { sum += (o->hanningWeights[i] * o->buffer[i]); } sEnv_sendMessage(_c, o, sum, sendMessage); } #endif } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalEnvelope.h0000644000000000000000000000256000000000000020217 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_ENVELOPE_H_ #define _SIGNAL_ENVELOPE_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalEnvelope { int windowSize; int period; int numSamplesInBuffer; float *hanningWeights; float *buffer; } SignalEnvelope; hv_size_t sEnv_init(SignalEnvelope *o, int windowSize, int period); void sEnv_free(SignalEnvelope *o); void sEnv_process(HeavyContextInterface *_c, SignalEnvelope *o, hv_bInf_t bIn, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_ENVELOPE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalLine.c0000644000000000000000000001163000000000000017322 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalLine.h" hv_size_t sLine_init(SignalLine *o) { #if HV_SIMD_AVX o->n = _mm_setzero_si128(); o->x = _mm256_setzero_ps(); o->m = _mm256_setzero_ps(); o->t = _mm256_setzero_ps(); #elif HV_SIMD_SSE o->n = _mm_setzero_si128(); o->x = _mm_setzero_ps(); o->m = _mm_setzero_ps(); o->t = _mm_setzero_ps(); #elif HV_SIMD_NEON o->n = vdupq_n_s32(0); o->x = vdupq_n_f32(0.0f); o->m = vdupq_n_f32(0.0f); o->t = vdupq_n_f32(0.0f); #else // HV_SIMD_NONE o->n = 0; o->x = 0.0f; o->m = 0.0f; o->t = 0.0f; #endif return 0; } void sLine_onMessage(HeavyContextInterface *_c, SignalLine *o, int letIn, const HvMessage *m, void *sendMessage) { if (msg_isFloat(m,0)) { if (msg_isFloat(m,1)) { // new ramp int n = (int) hv_millisecondsToSamples(_c, msg_getFloat(m,1)); #if HV_SIMD_AVX float x = (o->n[1] > 0) ? (o->x[7] + (o->m[7]/8.0f)) : o->t[7]; // current output value float s = (msg_getFloat(m,0) - x) / ((float) n); // slope per sample o->n = _mm_set_epi32(n-3, n-2, n-1, n); o->x = _mm256_set_ps(x+7.0f*s, x+6.0f*s, x+5.0f*s, x+4.0f*s, x+3.0f*s, x+2.0f*s, x+s, x); o->m = _mm256_set1_ps(8.0f*s); o->t = _mm256_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_SSE const hv_int32_t *const on = (hv_int32_t *) &o->n; const float *const ox = (float *) &o->x; const float *const om = (float *) &o->m; const float *const ot = (float *) &o->t; float x = (on[3] > 0) ? (ox[3] + (om[3]/4.0f)) : ot[3]; float s = (msg_getFloat(m,0) - x) / ((float) n); // slope per sample o->n = _mm_set_epi32(n-3, n-2, n-1, n); o->x = _mm_set_ps(x+3.0f*s, x+2.0f*s, x+s, x); o->m = _mm_set1_ps(4.0f*s); o->t = _mm_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_NEON float x = (o->n[3] > 0) ? (o->x[3] + (o->m[3]/4.0f)) : o->t[3]; float s = (msg_getFloat(m,0) - x) / ((float) n); o->n = (int32x4_t) {n, n-1, n-2, n-3}; o->x = (float32x4_t) {x, x+s, x+2.0f*s, x+3.0f*s}; o->m = vdupq_n_f32(4.0f*s); o->t = vdupq_n_f32(msg_getFloat(m,0)); #else // HV_SIMD_NONE o->x = (o->n > 0) ? (o->x + o->m) : o->t; // new current value o->n = n; // new distance to target o->m = (msg_getFloat(m,0) - o->x) / ((float) n); // slope per sample o->t = msg_getFloat(m,0); #endif } else { // Jump to value #if HV_SIMD_AVX o->n = _mm_setzero_si128(); o->x = _mm256_set1_ps(msg_getFloat(m,0)); o->m = _mm256_setzero_ps(); o->t = _mm256_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_SSE o->n = _mm_setzero_si128(); o->x = _mm_set1_ps(msg_getFloat(m,0)); o->m = _mm_setzero_ps(); o->t = _mm_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_NEON o->n = vdupq_n_s32(0); o->x = vdupq_n_f32(msg_getFloat(m,0)); o->m = vdupq_n_f32(0.0f); o->t = vdupq_n_f32(msg_getFloat(m,0)); #else // HV_SIMD_NONE o->n = 0; o->x = msg_getFloat(m,0); o->m = 0.0f; o->t = msg_getFloat(m,0); #endif } } else if (msg_compareSymbol(m,0,"stop")) { // Stop line at current position #if HV_SIMD_AVX // note o->n[1] is a 64-bit integer; two packed 32-bit ints. We only want to know if the high int is positive, // which can be done simply by testing the long int for positiveness. float x = (o->n[1] > 0) ? (o->x[7] + (o->m[7]/8.0f)) : o->t[7]; o->n = _mm_setzero_si128(); o->x = _mm256_set1_ps(x); o->m = _mm256_setzero_ps(); o->t = _mm256_set1_ps(x); #elif HV_SIMD_SSE const hv_int32_t *const on = (hv_int32_t *) &o->n; const float *const ox = (float *) &o->x; const float *const om = (float *) &o->m; const float *const ot = (float *) &o->t; float x = (on[3] > 0) ? (ox[3] + (om[3]/4.0f)) : ot[3]; o->n = _mm_setzero_si128(); o->x = _mm_set1_ps(x); o->m = _mm_setzero_ps(); o->t = _mm_set1_ps(x); #elif HV_SIMD_NEON float x = (o->n[3] > 0) ? (o->x[3] + (o->m[3]/4.0f)) : o->t[3]; o->n = vdupq_n_s32(0); o->x = vdupq_n_f32(x); o->m = vdupq_n_f32(0.0f); o->t = vdupq_n_f32(x); #else // HV_SIMD_NONE float x = (o->n > 0) ? (o->x + o->m) : o->t; o->n = 0; o->x = x; o->m = 0.0f; o->t = x; #endif } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalLine.h0000644000000000000000000000551300000000000017332 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_LINE_H_ #define _SIGNAL_LINE_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalLine { #if HV_SIMD_AVX __m128i n; // remaining samples to target #else hv_bufferi_t n; // remaining samples to target #endif hv_bufferf_t x; // current output hv_bufferf_t m; // increment hv_bufferf_t t; // target value } SignalLine; hv_size_t sLine_init(SignalLine *o); static inline void __hv_line_f(SignalLine *o, hv_bOutf_t bOut) { #if HV_SIMD_AVX __m128i n = o->n; __m128i masklo = _mm_cmplt_epi32(n, _mm_setzero_si128()); // n < 0 n = _mm_sub_epi32(n, _mm_set1_epi32(4)); // subtract HV_N_SIMD from remaining samples __m128i maskhi = _mm_cmplt_epi32(n, _mm_setzero_si128()); o->n = _mm_sub_epi32(n, _mm_set1_epi32(4)); __m256 mask = _mm256_insertf128_ps(_mm256_castps128_ps256(_mm_castsi128_ps(masklo)), _mm_castsi128_ps(maskhi), 1); __m256 x = o->x; *bOut = _mm256_or_ps(_mm256_and_ps(mask, o->t), _mm256_andnot_ps(mask, x)); // add slope from sloped samples o->x = _mm256_add_ps(x, o->m); #elif HV_SIMD_SSE __m128i n = o->n; __m128 mask = _mm_castsi128_ps(_mm_cmplt_epi32(n, _mm_setzero_si128())); // n < 0 __m128 x = o->x; *bOut = _mm_or_ps(_mm_and_ps(mask, o->t), _mm_andnot_ps(mask, x)); // subtract HV_N_SIMD from remaining samples o->n = _mm_sub_epi32(n, _mm_set1_epi32(HV_N_SIMD)); // add slope from sloped samples o->x = _mm_add_ps(x, o->m); #elif HV_SIMD_NEON int32x4_t n = o->n; int32x4_t mask = vreinterpretq_s32_u32(vcltq_s32(n, vdupq_n_s32(0))); float32x4_t x = o->x; *bOut = vreinterpretq_f32_s32(vorrq_s32( vandq_s32(mask, vreinterpretq_s32_f32(o->t)), vbicq_s32(vreinterpretq_s32_f32(x), mask))); o->n = vsubq_s32(n, vdupq_n_s32(HV_N_SIMD)); o->x = vaddq_f32(x, o->m); #else // HV_SIMD_NONE *bOut = (o->n < 0) ? o->t : o->x; o->n -= HV_N_SIMD; o->x += o->m; #endif } void sLine_onMessage(HeavyContextInterface *_c, SignalLine *o, int letIndex, const HvMessage *m, void *sendMessage); #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_LINE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalLorenz.c0000644000000000000000000000224500000000000017706 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalLorenz.h" hv_size_t sLorenz_init(SignalLorenz *o, float x, float y, float z) { o->xm1 = x; o->ym1 = y; o->zm1 = z; return 0; } void sLorenz_onMessage(HeavyContextInterface *_c, SignalLorenz *o, int letIndex, const HvMessage *const m) { if (msg_hasFormat(m, "fff")) { o->xm1 = msg_getFloat(m,0); o->ym1 = msg_getFloat(m,1); o->zm1 = msg_getFloat(m,2); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalLorenz.h0000644000000000000000000001156000000000000017713 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_LORENZ_H_ #define _SIGNAL_LORENZ_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalLorenz { float xm1; float ym1; float zm1; } SignalLorenz; hv_size_t sLorenz_init(SignalLorenz *o, float x, float y, float z); // https://en.wikipedia.org/wiki/Lorenz_system#Overview // x = x'+hstep*s*(y'-x') // y = y'+hstep*(-x'*z'+r*x'-y') // z = z'+hstep*(x'*y'-b*z') static inline void __hv_lorenz_scalar_f( float xm1, float ym1, float zm1, float bInStep, float bInS, float bInR, float bInB, float *bOutX, float *bOutY, float *bOutZ) { *bOutX = hv_max_f(-100.0f, hv_min_f(xm1 + bInStep * bInS * (ym1 - xm1), 100.0f)); *bOutY = hv_max_f(-100.0f, hv_min_f(ym1 + bInStep * (-xm1 * zm1 + (bInR * xm1) - ym1), 100.0f)); *bOutZ = hv_max_f(-100.0f, hv_min_f(zm1 + bInStep * (xm1 * ym1 - bInB * zm1), 100.0f)); } static inline void __hv_lorenz_f(SignalLorenz *o, hv_bInf_t bInStep, hv_bInf_t bInS, hv_bInf_t bInR, hv_bInf_t bInB, hv_bOutf_t bOutX, hv_bOutf_t bOutY, hv_bOutf_t bOutZ) { #if HV_SIMD_AVX const float *const h = (float *) &bInStep; const float *const s = (float *) &bInS; const float *const r = (float *) &bInR; const float *const b = (float *) &bInB; float *const x = (float *) hv_alloca(3 * 8 * sizeof(float)); float *const y = x + 8; float *const z = x + 16; __hv_lorenz_scalar_f(o->xm1, o->ym1, o->zm1, h[0], s[0], r[0], b[0], x, y, z); __hv_lorenz_scalar_f(x[0], y[0], z[0], h[1], s[1], r[1], b[1], x+1, y+1, z+1); __hv_lorenz_scalar_f(x[1], y[1], z[1], h[2], s[2], r[2], b[2], x+2, y+2, z+2); __hv_lorenz_scalar_f(x[2], y[2], z[2], h[3], s[3], r[3], b[3], x+3, y+3, z+3); __hv_lorenz_scalar_f(x[3], y[3], z[3], h[4], s[4], r[4], b[4], x+4, y+4, z+4); __hv_lorenz_scalar_f(x[4], y[4], z[4], h[5], s[5], r[5], b[5], x+5, y+5, z+5); __hv_lorenz_scalar_f(x[5], y[5], z[5], h[6], s[6], r[6], b[6], x+6, y+6, z+6); __hv_lorenz_scalar_f(x[6], y[6], z[6], h[7], s[7], r[7], b[7], x+7, y+7, z+7); o->xm1 = x[7]; o->ym1 = y[7]; o->zm1 = z[7]; __hv_load_f(x, bOutX); __hv_load_f(y, bOutY); __hv_load_f(z, bOutZ); #elif HV_SIMD_SSE const float *const h = (float *) &bInStep; const float *const s = (float *) &bInS; const float *const r = (float *) &bInR; const float *const b = (float *) &bInB; float *const x = (float *) hv_alloca(3 * 4 * sizeof(float)); float *const y = x + 4; float *const z = x + 8; __hv_lorenz_scalar_f(o->xm1, o->ym1, o->zm1, h[0], s[0], r[0], b[0], x, y, z); __hv_lorenz_scalar_f(x[0], y[0], z[0], h[1], s[1], r[1], b[1], x+1, y+1, z+1); __hv_lorenz_scalar_f(x[1], y[1], z[1], h[2], s[2], r[2], b[2], x+2, y+2, z+2); __hv_lorenz_scalar_f(x[2], y[2], z[2], h[3], s[3], r[3], b[3], x+3, y+3, z+3); o->xm1 = x[3]; o->ym1 = y[3]; o->zm1 = z[3]; __hv_load_f(x, bOutX); __hv_load_f(y, bOutY); __hv_load_f(z, bOutZ); #elif HV_SIMD_NEON float *const x = (float *) hv_alloca(3 * 4 * sizeof(float)); float *const y = x + 4; float *const z = x + 8; __hv_lorenz_scalar_f(o->xm1, o->ym1, o->zm1, vgetq_lane_f32(bInStep,0), vgetq_lane_f32(bInS,0), vgetq_lane_f32(bInR,0), vgetq_lane_f32(bInB,0), x, y, z); __hv_lorenz_scalar_f(x[0], y[0], z[0], vgetq_lane_f32(bInStep,1), vgetq_lane_f32(bInS,1), vgetq_lane_f32(bInR,1), vgetq_lane_f32(bInB,1), x+1, y+1, z+1); __hv_lorenz_scalar_f(x[1], y[1], z[1], vgetq_lane_f32(bInStep,2), vgetq_lane_f32(bInS,2), vgetq_lane_f32(bInR,2), vgetq_lane_f32(bInB,2), x+2, y+2, z+2); __hv_lorenz_scalar_f(x[2], y[2], z[2], vgetq_lane_f32(bInStep,3), vgetq_lane_f32(bInS,3), vgetq_lane_f32(bInR,3), vgetq_lane_f32(bInB,3), x+3, y+3, z+3); o->xm1 = x[3]; o->ym1 = y[3]; o->zm1 = z[3]; __hv_load_f(x, bOutX); __hv_load_f(y, bOutY); __hv_load_f(z, bOutZ); #else // HV_SIMD_NONE __hv_lorenz_scalar_f(o->xm1, o->ym1, o->zm1, bInStep, bInS, bInR, bInB, bOutX, bOutY, bOutZ); o->xm1 = *bOutX; o->ym1 = *bOutY; o->zm1 = *bOutZ; #endif } void sLorenz_onMessage(HeavyContextInterface *_c, SignalLorenz *o, int letIndex, const HvMessage *m); #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_LORENZ_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalNam.c0000644000000000000000000000415300000000000017150 0ustar00/** * Copyright (c) 2026 Wasted Audio * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalNam.h" hv_size_t sNam_nano_init(SignalNamNano *o, const float* weights) { MicroNAM_NanoNet* nanonet = MicroNAM_NanoNet_Create(); MicroNAM_NanoNet_LoadWeights(nanonet, weights); o->nanonet = nanonet; return sizeof(float) * 842; } void sNam_nano_free(SignalNamNano *o) { MicroNAM_NanoNet_Destroy(o->nanonet); } hv_size_t sNam_feather_init(SignalNamFeather *o, const float* weights) { MicroNAM_FeatherNet* feathernet = MicroNAM_FeatherNet_Create(); MicroNAM_FeatherNet_LoadWeights(feathernet, weights); o->feathernet = feathernet; return sizeof(float) * 3026; } void sNam_feather_free(SignalNamFeather *o) { MicroNAM_FeatherNet_Destroy(o->feathernet); } hv_size_t sNam_lite_init(SignalNamLite *o, const float* weights) { MicroNAM_LiteNet* litenet = MicroNAM_LiteNet_Create(); MicroNAM_LiteNet_LoadWeights(litenet, weights); o->litenet = litenet; return sizeof(float) * 6554; } void sNam_lite_free(SignalNamLite *o) { MicroNAM_LiteNet_Destroy(o->litenet); } hv_size_t sNam_standard_init(SignalNamStandard *o, const float* weights) { MicroNAM_StandardNet* standardnet = MicroNAM_StandardNet_Create(); MicroNAM_StandardNet_LoadWeights(standardnet, weights); o->standardnet = standardnet; return sizeof(float) * 13802; } void sNam_standard_free(SignalNamStandard *o) { MicroNAM_StandardNet_Destroy(o->standardnet); } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalNam.h0000644000000000000000000000554400000000000017162 0ustar00/** * Copyright (c) 2026 Wasted Audio * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_LORENZ_H_ #define _SIGNAL_LORENZ_H_ #include "HvHeavyInternal.h" #include "MicroNAM_C.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalNamNano { MicroNAM_NanoNet* nanonet; } SignalNamNano; hv_size_t sNam_nano_init(SignalNamNano *o, const float* weights); void sNam_nano_free(SignalNamNano *o); static inline void __hv_nam_nano_f(SignalNamNano *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); #elif HV_SIMD_SSE hv_assert(0); #elif HV_SIMD_NEON hv_assert(0); #else // HV_SIMD_NONE MicroNAM_NanoNet_Process(o->nanonet, &bIn0, bOut); #endif } typedef struct SignalNamFeather { MicroNAM_FeatherNet* feathernet; } SignalNamFeather; hv_size_t sNam_feather_init(SignalNamFeather *o, const float* weights); void sNam_feather_free(SignalNamFeather *o); static inline void __hv_nam_feather_f(SignalNamFeather *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); #elif HV_SIMD_SSE hv_assert(0); #elif HV_SIMD_NEON hv_assert(0); #else // HV_SIMD_NONE MicroNAM_FeatherNet_Process(o->feathernet, &bIn0, bOut); #endif } typedef struct SignalNamLite { MicroNAM_LiteNet* litenet; } SignalNamLite; hv_size_t sNam_lite_init(SignalNamLite *o, const float* weights); void sNam_lite_free(SignalNamLite *o); static inline void __hv_nam_lite_f(SignalNamLite *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); #elif HV_SIMD_SSE hv_assert(0); #elif HV_SIMD_NEON hv_assert(0); #else // HV_SIMD_NONE MicroNAM_LiteNet_Process(o->litenet, &bIn0, bOut); #endif } typedef struct SignalNamStandard { MicroNAM_StandardNet* standardnet; } SignalNamStandard; hv_size_t sNam_standard_init(SignalNamStandard *o, const float* weights); void sNam_standard_free(SignalNamStandard *o); static inline void __hv_nam_standard_f(SignalNamStandard *o, hv_bInf_t bIn0, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); #elif HV_SIMD_SSE hv_assert(0); #elif HV_SIMD_NEON hv_assert(0); #else // HV_SIMD_NONE MicroNAM_StandardNet_Process(o->standardnet, &bIn0, bOut); #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_LORENZ_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalPhasor.c0000644000000000000000000001146500000000000017675 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalPhasor.h" #define HV_PHASOR_2_32 4294967296.0 #if HV_SIMD_AVX static void sPhasor_updatePhase(SignalPhasor *o, float p) { o->phase = _mm256_set1_ps(p+1.0f); // o->phase is in range [1,2] #elif HV_SIMD_SSE static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { o->phase = _mm_set1_epi32(p); #elif HV_SIMD_NEON static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { o->phase = vdupq_n_u32(p); #else // HV_SIMD_NONE static void sPhasor_updatePhase(SignalPhasor *o, hv_uint32_t p) { o->phase = p; #endif } // input phase is in the range of [0,1]. It is independent of o->phase. #if HV_SIMD_AVX static void sPhasor_k_updatePhase(SignalPhasor *o, float p) { o->phase = _mm256_set_ps( p+1.0f+7.0f*o->step.f2sc, p+1.0f+6.0f*o->step.f2sc, p+1.0f+5.0f*o->step.f2sc, p+1.0f+4.0f*o->step.f2sc, p+1.0f+3.0f*o->step.f2sc, p+1.0f+2.0f*o->step.f2sc, p+1.0f+o->step.f2sc, p+1.0f); // ensure that o->phase is still in range [1,2] o->phase = _mm256_or_ps(_mm256_andnot_ps( _mm256_set1_ps(-INFINITY), o->phase), _mm256_set1_ps(1.0f)); #elif HV_SIMD_SSE static void sPhasor_k_updatePhase(SignalPhasor *o, hv_uint32_t p) { o->phase = _mm_set_epi32(3*o->step.s+p, 2*o->step.s+p, o->step.s+p, p); #elif HV_SIMD_NEON static void sPhasor_k_updatePhase(SignalPhasor *o, hv_uint32_t p) { o->phase = (uint32x4_t) {p, o->step.s+p, 2*o->step.s+p, 3*o->step.s+p}; #else // HV_SIMD_NONE static void sPhasor_k_updatePhase(SignalPhasor *o, hv_uint32_t p) { o->phase = p; #endif } static void sPhasor_k_updateFrequency(SignalPhasor *o, float f, double r) { #if HV_SIMD_AVX o->step.f2sc = (float) (f/r); o->inc = _mm256_set1_ps((float) (8.0f*f/r)); sPhasor_k_updatePhase(o, o->phase[0]); #elif HV_SIMD_SSE o->step.s = (hv_int32_t) (f*(HV_PHASOR_2_32/r)); o->inc = _mm_set1_epi32(4*o->step.s); const hv_uint32_t *const p = (hv_uint32_t *) &o->phase; sPhasor_k_updatePhase(o, p[0]); #elif HV_SIMD_NEON o->step.s = (hv_int32_t) (f*(HV_PHASOR_2_32/r)); o->inc = vdupq_n_s32(4*o->step.s); sPhasor_k_updatePhase(o, vgetq_lane_u32(o->phase, 0)); #else // HV_SIMD_NONE o->step.s = (hv_int32_t) (f*(HV_PHASOR_2_32/r)); o->inc = o->step.s; // no need to update phase #endif } hv_size_t sPhasor_init(SignalPhasor *o, double samplerate) { #if HV_SIMD_AVX o->phase = _mm256_set1_ps(1.0f); o->inc = _mm256_setzero_ps(); o->step.f2sc = (float) (1.0/samplerate); #elif HV_SIMD_SSE o->phase = _mm_setzero_si128(); o->inc = _mm_setzero_si128(); o->step.f2sc = (float) (HV_PHASOR_2_32/samplerate); #elif HV_SIMD_NEON o->phase = vdupq_n_u32(0); o->inc = vdupq_n_s32(0); o->step.f2sc = (float) (HV_PHASOR_2_32/samplerate); #else // HV_SIMD_NONE o->phase = 0; o->inc = 0; o->step.f2sc = (float) (HV_PHASOR_2_32/samplerate); #endif return 0; } void sPhasor_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m) { if (letIn == 1) { if (msg_isFloat(m,0)) { float p = msg_getFloat(m,0); while (p < 0.0f) p += 1.0f; // wrap phase to [0,1] while (p > 1.0f) p -= 1.0f; #if HV_SIMD_AVX sPhasor_updatePhase(o, p); #else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE sPhasor_updatePhase(o, (hv_uint32_t) (p * HV_PHASOR_2_32)); #endif } } } hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate) { __hv_zero_i((hv_bOuti_t) &o->phase); sPhasor_k_updateFrequency(o, frequency, samplerate); return 0; } void sPhasor_k_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m) { if (msg_isFloat(m,0)) { switch (letIn) { case 0: sPhasor_k_updateFrequency(o, msg_getFloat(m,0), hv_getSampleRate(_c)); break; case 1: { float p = msg_getFloat(m,0); while (p < 0.0f) p += 1.0f; // wrap phase to [0,1] while (p > 1.0f) p -= 1.0f; #if HV_SIMD_AVX sPhasor_k_updatePhase(o, p); #else // HV_SIMD_SSE || HV_SIMD_NEON || HV_SIMD_NONE sPhasor_k_updatePhase(o, (hv_uint32_t) (p * HV_PHASOR_2_32)); #endif break; } default: break; } } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalPhasor.h0000644000000000000000000001313700000000000017700 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_SIGNAL_PHASOR_H_ #define _HEAVY_SIGNAL_PHASOR_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalPhasor { #if HV_SIMD_AVX __m256 phase; // current phase __m256 inc; // phase increment #elif HV_SIMD_SSE __m128i phase; __m128i inc; #elif HV_SIMD_NEON uint32x4_t phase; int32x4_t inc; #else // HV_SIMD_NONE hv_uint32_t phase; hv_int32_t inc; #endif union { float f2sc; // float to step conversion (used for __phasor~f) hv_int32_t s; // step value (used for __phasor_k~f) } step; } SignalPhasor; hv_size_t sPhasor_init(SignalPhasor *o, double samplerate); hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate); void sPhasor_k_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m); void sPhasor_onMessage(HeavyContextInterface *_c, SignalPhasor *o, int letIn, const HvMessage *m); static inline void __hv_phasor_f(SignalPhasor *o, hv_bInf_t bIn, hv_bOutf_t bOut) { #if HV_SIMD_AVX __m256 p = _mm256_mul_ps(bIn, _mm256_set1_ps(o->step.f2sc)); // a b c d e f g h __m256 z = _mm256_setzero_ps(); // http://stackoverflow.com/questions/11906814/how-to-rotate-an-sse-avx-vector __m256 a = _mm256_permute_ps(p, _MM_SHUFFLE(2,1,0,3)); // d a b c h e f g __m256 b = _mm256_permute2f128_ps(a, a, 0x01); // h e f g d a b c __m256 c = _mm256_blend_ps(a, b, 0x10); // d a b c d e f g __m256 d = _mm256_blend_ps(c, z, 0x01); // 0 a b c d e f g __m256 e = _mm256_add_ps(p, d); // a (a+b) (b+c) (c+d) (d+e) (e+f) (f+g) (g+h) __m256 f = _mm256_permute_ps(e, _MM_SHUFFLE(1,0,3,2)); // (b+c) (c+d) a (a+b) (f+g) (g+h) (d+e) (e+f) __m256 g = _mm256_permute2f128_ps(f, f, 0x01); // (f+g) (g+h) (d+e) (e+f) (b+c) (c+d) a (a+b) __m256 h = _mm256_blend_ps(f, g, 0x33); // (b+c) (c+d) a (a+b) (b+c) (c+d) (d+e) (e+f) __m256 i = _mm256_blend_ps(h, z, 0x03); // 0 0 a (a+b) (b+c) (c+d) (d+e) (e+f) __m256 j = _mm256_add_ps(e, i); // a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) (c+d+e+f) (d+e+f+g) (e+f+g+h) __m256 k = _mm256_permute2f128_ps(j, z, 0x02); // 0 0 0 0 a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) __m256 m = _mm256_add_ps(j, k); // a (a+b) (a+b+c) (a+b+c+d) (a+b+c+d+e) (a+b+c+d+e+f) (a+b+c+d+e+f+g) (a+b+c+d+e+f+g+h) __m256 n = _mm256_or_ps(_mm256_andnot_ps( _mm256_set1_ps(-INFINITY), _mm256_add_ps(o->phase, m)), _mm256_set1_ps(1.0f)); *bOut = _mm256_sub_ps(n, _mm256_set1_ps(1.0f)); __m256 x = _mm256_permute_ps(n, _MM_SHUFFLE(3,3,3,3)); o->phase = _mm256_permute2f128_ps(x, x, 0x11); #elif HV_SIMD_SSE __m128i p = _mm_cvtps_epi32(_mm_mul_ps(bIn, _mm_set1_ps(o->step.f2sc))); // convert frequency to step p = _mm_add_epi32(p, _mm_slli_si128(p, 4)); // add incremental steps to phase (prefix sum) p = _mm_add_epi32(p, _mm_slli_si128(p, 8)); // http://stackoverflow.com/questions/10587598/simd-prefix-sum-on-intel-cpu?rq=1 p = _mm_add_epi32(o->phase, p); *bOut = _mm_sub_ps(_mm_castsi128_ps( _mm_or_si128(_mm_srli_epi32(p, 9), _mm_set_epi32(0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000))), _mm_set1_ps(1.0f)); o->phase = _mm_shuffle_epi32(p, _MM_SHUFFLE(3,3,3,3)); #elif HV_SIMD_NEON int32x4_t p = vcvtq_s32_f32(vmulq_n_f32(bIn, o->step.f2sc)); p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 3)); // http://stackoverflow.com/questions/11259596/arm-neon-intrinsics-rotation p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 2)); uint32x4_t pp = vaddq_u32(o->phase, vreinterpretq_u32_s32(p)); *bOut = vsubq_f32(vreinterpretq_f32_u32(vorrq_u32(vshrq_n_u32(pp, 9), vdupq_n_u32(0x3F800000))), vdupq_n_f32(1.0f)); o->phase = vdupq_n_u32(pp[3]); #else // HV_SIMD_NONE union { float f; hv_uint32_t u; } uphase; uphase.u = (o->phase >> 9) | 0x3F800000; *bOut = uphase.f - 1.0f; o->phase += ((int) (bIn * o->step.f2sc)); #endif } static inline void __hv_phasor_k_f(SignalPhasor *o, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_sub_ps(o->phase, _mm256_set1_ps(1.0f)); o->phase = _mm256_or_ps(_mm256_andnot_ps( _mm256_set1_ps(-INFINITY), _mm256_add_ps(o->phase, o->inc)), _mm256_set1_ps(1.0f)); #elif HV_SIMD_SSE *bOut = _mm_sub_ps(_mm_castsi128_ps( _mm_or_si128(_mm_srli_epi32(o->phase, 9), _mm_set_epi32(0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000))), _mm_set1_ps(1.0f)); o->phase = _mm_add_epi32(o->phase, o->inc); #elif HV_SIMD_NEON *bOut = vsubq_f32(vreinterpretq_f32_u32( vorrq_u32(vshrq_n_u32(o->phase, 9), vdupq_n_u32(0x3F800000))), vdupq_n_f32(1.0f)); o->phase = vaddq_u32(o->phase, vreinterpretq_u32_s32(o->inc)); #else // HV_SIMD_NONE union { float f; hv_uint32_t u; } uphase; uphase.u = (o->phase >> 9) | 0x3F800000; *bOut = uphase.f - 1.0f; o->phase += o->inc; #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_SIGNAL_PHASOR_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalRPole.c0000644000000000000000000000327400000000000017461 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalRPole.h" hv_size_t sRPole_init(SignalRPole *o) { #if HV_SIMD_AVX sDel1_init(&o->sDel1_fxiLN); sDel1_init(&o->sDel1_kjkpV); sDel1_init(&o->sDel1_dkIWc); sDel1_init(&o->sDel1_bVeoW); sDel1_init(&o->sDel1_PulZn); sDel1_init(&o->sDel1_yTFig); sDel1_init(&o->sDel1_Is9Qf); sDel1_init(&o->sDel1_LIyNt); sDel1_init(&o->sDel1_VqpU3); sDel1_init(&o->sDel1_ZVYeg); sDel1_init(&o->sDel1_IVAZh); sDel1_init(&o->sDel1_F8WrY); sDel1_init(&o->sDel1_rkFMy); sDel1_init(&o->sDel1_BeqSK); __hv_zero_f(&o->ym); #elif HV_SIMD_SSE || HV_SIMD_NEON sDel1_init(&o->sDel1_i8Twk); sDel1_init(&o->sDel1_KYibU); sDel1_init(&o->sDel1_spa5V); sDel1_init(&o->sDel1_3HXdb); sDel1_init(&o->sDel1_Aj1oK); sDel1_init(&o->sDel1_jNX1g); __hv_zero_f(&o->ym); #else o->ym = 0.0f; #endif return 0; } void sRPole_onMessage(HeavyContextInterface *_c, SignalRPole *o, int letIn, const HvMessage *m) { // TODO } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalRPole.h0000644000000000000000000000723700000000000017471 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_RPOLE_H_ #define _SIGNAL_RPOLE_H_ #include "HvHeavyInternal.h" #include "HvSignalDel1.h" #ifdef __cplusplus extern "C" { #endif // implements y[n] = x[n] - a*y[n-1] // H(z) = 1/(1+a*z^-1) typedef struct SignalRPole { #if HV_SIMD_AVX SignalDel1 sDel1_fxiLN; SignalDel1 sDel1_kjkpV; SignalDel1 sDel1_dkIWc; SignalDel1 sDel1_bVeoW; SignalDel1 sDel1_PulZn; SignalDel1 sDel1_yTFig; SignalDel1 sDel1_Is9Qf; SignalDel1 sDel1_LIyNt; SignalDel1 sDel1_VqpU3; SignalDel1 sDel1_ZVYeg; SignalDel1 sDel1_IVAZh; SignalDel1 sDel1_F8WrY; SignalDel1 sDel1_rkFMy; SignalDel1 sDel1_BeqSK; hv_bufferf_t ym; #elif HV_SIMD_SSE || HV_SIMD_NEON SignalDel1 sDel1_i8Twk; SignalDel1 sDel1_KYibU; SignalDel1 sDel1_spa5V; SignalDel1 sDel1_3HXdb; SignalDel1 sDel1_Aj1oK; SignalDel1 sDel1_jNX1g; hv_bufferf_t ym; #else hv_bufferf_t ym; #endif } SignalRPole; hv_size_t sRPole_init(SignalRPole *o); void sRPole_onMessage(HeavyContextInterface *_c, SignalRPole *o, int letIn, const HvMessage *m); static inline void __hv_rpole_f(SignalRPole *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_bufferf_t a, b, c, d, e, f, g, i, j, k, l, m, n; __hv_del1_f(&o->sDel1_fxiLN, bIn1, &a); __hv_mul_f(bIn1, a, &b); __hv_del1_f(&o->sDel1_kjkpV, a, &a); __hv_mul_f(b, a, &c); __hv_del1_f(&o->sDel1_dkIWc, a, &a); __hv_mul_f(c, a, &d); __hv_del1_f(&o->sDel1_bVeoW, a, &a); __hv_mul_f(d, a, &e); __hv_del1_f(&o->sDel1_PulZn, a, &a); __hv_mul_f(e, a, &f); __hv_del1_f(&o->sDel1_yTFig, a, &a); __hv_mul_f(f, a, &g); __hv_del1_f(&o->sDel1_Is9Qf, a, &a); __hv_mul_f(g, a, &a); __hv_del1_f(&o->sDel1_LIyNt, bIn0, &i); __hv_del1_f(&o->sDel1_VqpU3, i, &j); __hv_del1_f(&o->sDel1_ZVYeg, j, &k); __hv_del1_f(&o->sDel1_IVAZh, k, &l); __hv_del1_f(&o->sDel1_F8WrY, l, &m); __hv_del1_f(&o->sDel1_rkFMy, m, &n); __hv_mul_f(i, bIn1, &i); __hv_sub_f(bIn0, i, &i); __hv_fma_f(j, b, i, &i); __hv_mul_f(k, c, &c); __hv_sub_f(i, c, &c); __hv_fma_f(l, d, c, &c); __hv_mul_f(m, e, &e); __hv_sub_f(c, e, &e); __hv_fma_f(n, f, e, &e); __hv_del1_f(&o->sDel1_BeqSK, n, &n); __hv_mul_f(n, g, &g); __hv_sub_f(e, g, &g); __hv_fma_f(a, o->ym, g, &g); o->ym = g; *bOut = g; #elif HV_SIMD_SSE || HV_SIMD_NEON hv_bufferf_t a, b, c, e, f; __hv_del1_f(&o->sDel1_i8Twk, bIn1, &a); __hv_mul_f(bIn1, a, &b); __hv_del1_f(&o->sDel1_KYibU, a, &a); __hv_mul_f(b, a, &c); __hv_del1_f(&o->sDel1_spa5V, a, &a); __hv_mul_f(c, a, &a); __hv_del1_f(&o->sDel1_3HXdb, bIn0, &e); __hv_del1_f(&o->sDel1_Aj1oK, e, &f); __hv_mul_f(e, bIn1, &e); __hv_sub_f(bIn0, e, &e); __hv_fma_f(f, b, e, &e); __hv_del1_f(&o->sDel1_jNX1g, f, &f); __hv_mul_f(f, c, &c); __hv_sub_f(e, c, &c); __hv_fma_f(a, o->ym, c, &c); o->ym = c; *bOut = c; #else *bOut = bIn0 - bIn1 * o->ym; o->ym = *bOut; #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_RPOLE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalSamphold.c0000644000000000000000000000300100000000000020173 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalSamphold.h" hv_size_t sSamphold_init(SignalSamphold *o) { #if HV_SIMD_AVX o->s = _mm256_setzero_ps(); #elif HV_SIMD_SSE o->s = _mm_setzero_ps(); #elif HV_SIMD_NEON o->s = vdupq_n_f32(0.0f); #else o->s = 0.0f; #endif return 0; } void sSamphold_onMessage(HeavyContextInterface *_c, SignalSamphold *o, int letIndex, const HvMessage *m, void *sendMessage) { switch (letIndex) { case 2: { if (msg_isFloat(m,0)) { #if HV_SIMD_AVX o->s = _mm256_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_SSE o->s = _mm_set1_ps(msg_getFloat(m,0)); #elif HV_SIMD_NEON o->s = vdupq_n_f32(msg_getFloat(m,0)); #else o->s = msg_getFloat(m,0); #endif } break; } default: break; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalSamphold.h0000644000000000000000000002242400000000000020212 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_SAMPHOLD_H_ #define _SIGNAL_SAMPHOLD_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalSamphold { hv_bufferf_t s; } SignalSamphold; hv_size_t sSamphold_init(SignalSamphold *o); static inline void __hv_samphold_f(SignalSamphold *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) { #if HV_SIMD_AVX hv_assert(0); // __hv_samphold_f() not implemented #elif HV_SIMD_SSE switch (_mm_movemask_ps(bIn1)) { default: case 0x0: *bOut = o->s; break; case 0x1: { *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(0,0,0,0)); o->s = *bOut; break; } case 0x2: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(1,1,1,1)); *bOut = _mm_blend_ps(o->s, x, 0xE); o->s = x; break; } case 0x3: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(1,1,1,1)); *bOut = _mm_blend_ps(bIn0, x, 0xC); o->s = x; break; } case 0x4: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); *bOut = _mm_blend_ps(o->s, x, 0xC); o->s = x; break; } case 0x5: { *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,0,0)); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); break; } case 0x6: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,1,0)); *bOut = _mm_blend_ps(o->s, x, 0xE); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); break; } case 0x7: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(2,2,2,2)); *bOut = _mm_blend_ps(bIn0, x, 0x8); o->s = x; break; } case 0x8: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); *bOut = _mm_blend_ps(o->s, x, 0x8); o->s = x; break; } case 0x9: { *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,0,0,0)); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } case 0xA: { const __m128 x = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,1,1,0)); *bOut = _mm_blend_ps(o->s, x, 0xE); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } case 0xB: { *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,1,1,0)); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } case 0xC: { *bOut = _mm_blend_ps(o->s, bIn0, 0xC); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } case 0xD: { *bOut = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,2,0,0)); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } case 0xE: { *bOut = _mm_blend_ps(o->s, bIn0, 0xE); o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } case 0xF: { *bOut = bIn0; o->s = _mm_shuffle_ps(bIn0, bIn0, _MM_SHUFFLE(3,3,3,3)); break; } } #elif HV_SIMD_NEON uint32x4_t mmA = vandq_u32( vreinterpretq_u32_f32(bIn1), (uint32x4_t) {0x1, 0x2, 0x4, 0x8}); // [0 1 2 3] uint32x4_t mmB = vextq_u32(mmA, mmA, 2); // [2 3 0 1] uint32x4_t mmC = vorrq_u32(mmA, mmB); // [0+2 1+3 0+2 1+3] uint32x4_t mmD = vextq_u32(mmC, mmC, 3); // [1+3 0+2 1+3 0+2] uint32x4_t mmE = vorrq_u32(mmC, mmD); // [0+1+2+3 ...] uint32_t movemask = vgetq_lane_u32(mmE, 0); switch (movemask) { default: case 0x0: *bOut = o->s; break; case 0x1: { *bOut = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); o->s = *bOut; break; } case 0x2: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); *bOut = vextq_f32(o->s, x, 3); o->s = x; break; } case 0x3: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0xFFFFFFFF, 0x0, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}))); o->s = x; break; } case 0x4: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); *bOut = vextq_f32(o->s, x, 2); o->s = x; break; } case 0x5: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF}))); o->s = y; } case 0x6: { const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); float32x4_t z = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {0xFFFFFFFF, 0x0, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}))); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(z), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}), vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0x0, 0xFFFFFFFF}))); o->s = y; } case 0x7: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,2)); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF}))); o->s = x; break; } case 0x8: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); *bOut = vextq_f32(o->s, x, 1); o->s = x; break; } case 0x9: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}), vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0x0, 0x0, 0xFFFFFFFF}))); o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); } case 0xA: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); const float32x4_t y = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); float32x4_t z = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {0xFFFFFFFF, 0x0, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}))); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(z), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}), vandq_u32(vreinterpretq_u32_f32(y), (uint32x4_t) {0x0, 0x0, 0x0, 0xFFFFFFFF}))); o->s = y; } case 0xB: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,1)); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0xFFFFFFFF}), vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0x0, 0xFFFFFFFF, 0x0}))); o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); break; } case 0xC: { *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0x0, 0xFFFFFFFF, 0xFFFFFFFF}))); o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); break; } case 0xD: { const float32x4_t x = vdupq_n_f32(vgetq_lane_f32(bIn0,0)); *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0xFFFFFFFF, 0x0, 0xFFFFFFFF, 0xFFFFFFFF}), vandq_u32(vreinterpretq_u32_f32(x), (uint32x4_t) {0x0, 0xFFFFFFFF, 0x0, 0x0}))); o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); } case 0xE: { *bOut = vreinterpretq_f32_u32(vorrq_u32( vandq_u32(vreinterpretq_u32_f32(o->s), (uint32x4_t) {0xFFFFFFFF, 0x0, 0x0, 0x0}), vandq_u32(vreinterpretq_u32_f32(bIn0), (uint32x4_t) {0x0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}))); o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); break; } case 0xF: { *bOut = bIn0; o->s = vdupq_n_f32(vgetq_lane_f32(bIn0,3)); break; } } #else // HV_SIMD_NONE if (bIn1 != 0.0f) o->s = bIn0; *bOut = o->s; #endif } void sSamphold_onMessage(HeavyContextInterface *_c, SignalSamphold *o, int letIndex, const HvMessage *m, void *sendMessage); #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_SAMPHOLD_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalSample.c0000644000000000000000000000333100000000000017653 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalSample.h" #define __HV_SAMPLE_NULL -1 hv_size_t sSample_init(SignalSample *o) { o->i = __HV_SAMPLE_NULL; return 0; } void sSample_onMessage(HeavyContextInterface *_c, SignalSample *o, int letIndex, const HvMessage *m) { o->i = msg_getTimestamp(m); } void __hv_sample_f(HeavyContextInterface *_c, SignalSample *o, hv_bInf_t bIn, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { if (o->i != __HV_SAMPLE_NULL) { #if HV_SIMD_AVX || HV_SIMD_SSE const float *const b = (float *) &bIn; float out = b[o->i & HV_N_SIMD_MASK]; #elif HV_SIMD_NEON float out = bIn[o->i & HV_N_SIMD_MASK]; #else // HV_SIMD_NONE float out = bIn; #endif HvMessage *n = HV_MESSAGE_ON_STACK(1); hv_uint32_t ts = (o->i + HV_N_SIMD) & ~HV_N_SIMD_MASK; // start of next block msg_initWithFloat(n, ts, out); hv_scheduleMessageForObject(_c, n, sendMessage, 0); o->i = __HV_SAMPLE_NULL; // reset the index } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalSample.h0000644000000000000000000000254300000000000017664 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _SIGNAL_SAMPLE_H_ #define _SIGNAL_SAMPLE_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalSample { hv_uint32_t i; // timestamp at which to get sample } SignalSample; hv_size_t sSample_init(SignalSample *o); void __hv_sample_f(HeavyContextInterface *_c, SignalSample *o, hv_bInf_t bIn, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); void sSample_onMessage(HeavyContextInterface *_c, SignalSample *o, int letIndex, const HvMessage *m); #ifdef __cplusplus } // extern "C" #endif #endif // _SIGNAL_SAMPLE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalTabread.c0000644000000000000000000000617000000000000020000 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalTabread.h" hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads) { o->table = table; o->head = 0; o->end = hTable_getSize(o->table); o->forceAlignedLoads = forceAlignedLoads; o->playing = false; return 0; } void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { case 0: { if (o->table != NULL) { o->end = hTable_getSize(o->table); switch (msg_getType(m,0)) { case HV_MSG_BANG: { o->head = 0; o->playing = true; break; } case HV_MSG_FLOAT: { hv_uint32_t h = (hv_uint32_t) hv_abs_f(msg_getFloat(m,0)); if (msg_getFloat(m,0) < 0.0f) { // if input is negative, wrap around the end of the table h = hTable_getSize(o->table) - h; } o->head = o->forceAlignedLoads ? (h & ~HV_N_SIMD_MASK) : h; o->playing = true; // output new head HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, msg_getTimestamp(m), (float) o->head); sendMessage(_c, 1, n); break; } case HV_MSG_SYMBOL: { if (msg_compareSymbol(m, 0, "stop")) { o->head = 0; o->playing = false; } break; } default: break; } } break; } case 1: { if (msg_isHashLike(m,0)) { o->table = hv_table_get(_c, msg_getHash(m,0)); o->head = 0; o->end = hTable_getSize(o->table); } break; } case 2: { if (o->table != NULL) { switch (msg_getType(m,0)) { case HV_MSG_FLOAT: { hv_uint32_t e = (hv_uint32_t) hv_abs_f(msg_getFloat(m,0)); o->end = o->head + e; break; } default: break; } } break; } default: break; } } #if HV_APPLE #pragma mark - Tabhead #endif void sTabhead_onMessage(HeavyContextInterface *_c, SignalTabhead *o, const HvMessage *m) { if (msg_isHashLike(m,0)) { o->table = hv_table_get(_c, msg_getHash(m,0)); } } hv_size_t sTabhead_init(SignalTabhead *o, HvTable *table) { o->table = table; return 0; } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalTabread.h0000644000000000000000000001510100000000000017777 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_SIGNAL_TABREAD_H_ #define _HEAVY_SIGNAL_TABREAD_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif typedef struct SignalTabread { HvTable *table; // the table to read hv_uint32_t head; hv_uint32_t end; bool forceAlignedLoads; // false by default, true if using __hv_tabread_f bool playing; // false by default, only __hv_tabread_stoppable_f may respond to it } SignalTabread; // random access to a table hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads); #if HV_APPLE #pragma mark - Tabread - Random Access #endif static inline void __hv_tabread_if(SignalTabread *o, hv_bIni_t bIn, hv_bOutf_t bOut) { const float *const b = hTable_getBuffer(o->table); #if HV_SIMD_AVX const hv_int32_t *const i = (hv_int32_t *) &bIn; hv_assert(i[0] >= 0 && (hv_uint32_t) i[0] < hTable_getAllocated(o->table)); hv_assert(i[1] >= 0 && (hv_uint32_t) i[1] < hTable_getAllocated(o->table)); hv_assert(i[2] >= 0 && (hv_uint32_t) i[2] < hTable_getAllocated(o->table)); hv_assert(i[3] >= 0 && (hv_uint32_t) i[3] < hTable_getAllocated(o->table)); hv_assert(i[4] >= 0 && (hv_uint32_t) i[4] < hTable_getAllocated(o->table)); hv_assert(i[5] >= 0 && (hv_uint32_t) i[5] < hTable_getAllocated(o->table)); hv_assert(i[6] >= 0 && (hv_uint32_t) i[6] < hTable_getAllocated(o->table)); hv_assert(i[7] >= 0 && (hv_uint32_t) i[7] < hTable_getAllocated(o->table)); *bOut = _mm256_set_ps(b[i[7]], b[i[6]], b[i[5]], b[i[4]], b[i[3]], b[i[2]], b[i[1]], b[i[0]]); #elif HV_SIMD_SSE const hv_int32_t *const i = (hv_int32_t *) &bIn; hv_assert(i[0] >= 0 && (hv_uint32_t) i[0] < hTable_getAllocated(o->table)); hv_assert(i[1] >= 0 && (hv_uint32_t) i[1] < hTable_getAllocated(o->table)); hv_assert(i[2] >= 0 && (hv_uint32_t) i[2] < hTable_getAllocated(o->table)); hv_assert(i[3] >= 0 && (hv_uint32_t) i[3] < hTable_getAllocated(o->table)); *bOut = _mm_set_ps(b[i[3]], b[i[2]], b[i[1]], b[i[0]]); #elif HV_SIMD_NEON hv_assert((bIn[0] >= 0) && (hv_uint32_t) bIn[0] < hTable_getAllocated(o->table)); hv_assert((bIn[1] >= 0) && (hv_uint32_t) bIn[1] < hTable_getAllocated(o->table)); hv_assert((bIn[2] >= 0) && (hv_uint32_t) bIn[2] < hTable_getAllocated(o->table)); hv_assert((bIn[3] >= 0) && (hv_uint32_t) bIn[3] < hTable_getAllocated(o->table)); *bOut = (float32x4_t) {b[bIn[0]], b[bIn[1]], b[bIn[2]], b[bIn[3]]}; #else // HV_SIMD_NONE hv_assert(bIn >= 0 && ((hv_uint32_t) bIn < hTable_getAllocated(o->table))); *bOut = b[bIn]; #endif } #if HV_APPLE #pragma mark - Tabread - Linear Access #endif // this tabread never stops reading. It is mainly intended for linear reads that loop around a table. static inline void __hv_tabread_f(SignalTabread *o, hv_bOutf_t bOut) { hv_assert((o->head + HV_N_SIMD) <= hTable_getAllocated(o->table)); // assert that we always read within the table bounds hv_uint32_t head = o->head; #if HV_SIMD_AVX *bOut = _mm256_load_ps(hTable_getBuffer(o->table) + head); #elif HV_SIMD_SSE *bOut = _mm_load_ps(hTable_getBuffer(o->table) + head); #elif HV_SIMD_NEON *bOut = vld1q_f32(hTable_getBuffer(o->table) + head); #else // HV_SIMD_NONE *bOut = *(hTable_getBuffer(o->table) + head); #endif o->head = head + HV_N_SIMD; } // unaligned linear tabread, as above static inline void __hv_tabreadu_f(SignalTabread *o, hv_bOutf_t bOut) { hv_assert((o->head + HV_N_SIMD) <= hTable_getAllocated(o->table)); // assert that we always read within the table bounds hv_uint32_t head = o->head; #if HV_SIMD_AVX *bOut = _mm256_loadu_ps(hTable_getBuffer(o->table) + head); #elif HV_SIMD_SSE *bOut = _mm_loadu_ps(hTable_getBuffer(o->table) + head); #elif HV_SIMD_NEON *bOut = vld1q_f32(hTable_getBuffer(o->table) + head); #else // HV_SIMD_NONE *bOut = *(hTable_getBuffer(o->table) + head); #endif o->head = head + HV_N_SIMD; } // this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer. static inline void __hv_tabread_stoppable_f(HeavyContextInterface *_c, SignalTabread *o, hv_bOutf_t bOut, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { hv_uint32_t head = o->head; if (head >= hTable_getAllocated(o->table)) { // stop when we reach the table bounds o->playing = false; } if (!o->playing) { __hv_zero_f(bOut); // output silence when not playing } else { if (o->end > o->head) { // only play when end is further than play head #if HV_SIMD_AVX *bOut = _mm256_loadu_ps(hTable_getBuffer(o->table) + head); #elif HV_SIMD_SSE *bOut = _mm_load_ps(hTable_getBuffer(o->table) + head); #elif HV_SIMD_NEON *bOut = vld1q_f32(hTable_getBuffer(o->table) + head); #else // HV_SIMD_NONE *bOut = *(hTable_getBuffer(o->table) + head); #endif o->head = head + HV_N_SIMD; } else { o->playing = false; __hv_zero_f(bOut); // output silence when not playing HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithBang(n, 0); sendMessage(_c, 2, n); } } } void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); #if HV_APPLE #pragma mark - Tabhead #endif typedef struct SignalTabhead { HvTable *table; } SignalTabhead; hv_size_t sTabhead_init(SignalTabhead *o, HvTable *table); static inline void __hv_tabhead_f(SignalTabhead *o, hv_bOutf_t bOut) { #if HV_SIMD_AVX *bOut = _mm256_set1_ps((float) hTable_getHead(o->table)); #elif HV_SIMD_SSE *bOut = _mm_set1_ps((float) hTable_getHead(o->table)); #elif HV_SIMD_NEON *bOut = vdupq_n_f32((float32_t) hTable_getHead(o->table)); #else // HV_SIMD_NONE *bOut = (float) hTable_getHead(o->table); #endif } void sTabhead_onMessage(HeavyContextInterface *_c, SignalTabhead *o, const HvMessage *m); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_SIGNAL_TABREAD_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalTabwrite.c0000644000000000000000000000365300000000000020222 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalTabwrite.h" hv_size_t sTabwrite_init(SignalTabwrite *o, HvTable *table) { o->table = table; o->head = 0; return 0; } void sTabwrite_onMessage(HeavyContextInterface *_c, SignalTabwrite *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { switch (letIn) { // inlet 0 is the signal inlet case 1: { switch (msg_getType(m,0)) { case HV_MSG_BANG: o->head = 0; break; case HV_MSG_FLOAT: { o->head = (msg_getFloat(m,0) >= 0.0f) ? (hv_uint32_t) msg_getFloat(m,0) : HV_TABWRITE_STOPPED; break; } case HV_MSG_SYMBOL: { if (msg_compareSymbol(m, 0, "stop")) { o->head = HV_TABWRITE_STOPPED; } else if (msg_compareSymbol(m, 0, "clear")) { hv_size_t numBytes = o->table->allocated * sizeof(float); hv_memclear(o->table->buffer, numBytes); } break; } default: break; } break; } case 2: { if (msg_isHashLike(m,0)) { o->table = hv_table_get(_c, msg_getHash(m,0)); } break; } default: break; } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalTabwrite.h0000644000000000000000000001267100000000000020227 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_SIGNAL_TABWRITE_H_ #define _HEAVY_SIGNAL_TABWRITE_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif #define HV_TABWRITE_STOPPED (~(hv_uint32_t)0x0) typedef struct SignalTabwrite { HvTable *table; hv_uint32_t head; // local write head. Where this object has most recently written to the table. } SignalTabwrite; hv_size_t sTabwrite_init(SignalTabwrite *o, HvTable *table); void sTabwrite_onMessage(HeavyContextInterface *_c, SignalTabwrite *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); // linear write to table static inline void __hv_tabwrite_f(SignalTabwrite *o, hv_bInf_t bIn) { hv_assert((o->head + HV_N_SIMD) <= hTable_getSize(o->table)); // assert that the table bounds are respected hv_uint32_t head = o->head; #if HV_SIMD_AVX _mm256_store_ps(hTable_getBuffer(o->table) + head, bIn); #elif HV_SIMD_SSE _mm_store_ps(hTable_getBuffer(o->table) + head, bIn); #elif HV_SIMD_NEON vst1q_f32(hTable_getBuffer(o->table) + head, bIn); #else // HV_SIMD_NONE *(hTable_getBuffer(o->table) + head) = bIn; #endif head += HV_N_SIMD; o->head = head; // update local write head hTable_setHead(o->table, head); // update the remote write head (e.g. for use by vd~) } // linear unaligned write to table static inline void __hv_tabwriteu_f(SignalTabwrite *o, hv_bInf_t bIn) { hv_uint32_t head = o->head; #if HV_SIMD_AVX _mm256_storeu_ps(hTable_getBuffer(o->table) + head, bIn); #elif HV_SIMD_SSE _mm_storeu_ps(hTable_getBuffer(o->table) + head, bIn); #elif HV_SIMD_NEON vst1q_f32(hTable_getBuffer(o->table) + head, bIn); #else // HV_SIMD_NONE *(hTable_getBuffer(o->table) + head) = bIn; #endif head += HV_N_SIMD; o->head = head; // update local write head hTable_setHead(o->table, head); // update remote write head } // this tabwrite can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer. // Stores are unaligned, which can be slow but allows any indicies to be written to. // TODO(mhroth): this is not stopping! static inline void __hv_tabwrite_stoppable_f(SignalTabwrite *o, hv_bInf_t bIn) { if (o->head != HV_TABWRITE_STOPPED) { #if HV_SIMD_AVX _mm256_storeu_ps(hTable_getBuffer(o->table) + o->head, bIn); #elif HV_SIMD_SSE _mm_storeu_ps(hTable_getBuffer(o->table) + o->head, bIn); #elif HV_SIMD_NEON vst1q_f32(hTable_getBuffer(o->table) + o->head, bIn); #else // HV_SIMD_NONE *(hTable_getBuffer(o->table) + o->head) = bIn; #endif o->head += HV_N_SIMD; } } // random write to table static inline void __hv_tabwrite_if(SignalTabwrite *o, hv_bIni_t bIn0, hv_bInf_t bIn1) { float *const b = hTable_getBuffer(o->table); #if HV_SIMD_AVX const hv_int32_t *const i = (hv_int32_t *) &bIn0; const float *const f = (float *) &bIn1; hv_assert(i[0] >= 0 && i[0] < hTable_getAllocated(o->table)); hv_assert(i[1] >= 0 && i[1] < hTable_getAllocated(o->table)); hv_assert(i[2] >= 0 && i[2] < hTable_getAllocated(o->table)); hv_assert(i[3] >= 0 && i[3] < hTable_getAllocated(o->table)); hv_assert(i[4] >= 0 && i[4] < hTable_getAllocated(o->table)); hv_assert(i[5] >= 0 && i[5] < hTable_getAllocated(o->table)); hv_assert(i[6] >= 0 && i[6] < hTable_getAllocated(o->table)); hv_assert(i[7] >= 0 && i[7] < hTable_getAllocated(o->table)); b[i[0]] = f[0]; b[i[1]] = f[1]; b[i[2]] = f[2]; b[i[3]] = f[3]; b[i[4]] = f[4]; b[i[5]] = f[5]; b[i[6]] = f[6]; b[i[7]] = f[7]; #elif HV_SIMD_SSE const hv_int32_t *const i = (hv_int32_t *) &bIn0; const float *const f = (float *) &bIn1; hv_assert(i[0] >= 0 && ((hv_uint32_t) i[0]) < hTable_getAllocated(o->table)); hv_assert(i[1] >= 0 && ((hv_uint32_t) i[1]) < hTable_getAllocated(o->table)); hv_assert(i[2] >= 0 && ((hv_uint32_t) i[2]) < hTable_getAllocated(o->table)); hv_assert(i[3] >= 0 && ((hv_uint32_t) i[3]) < hTable_getAllocated(o->table)); b[i[0]] = f[0]; b[i[1]] = f[1]; b[i[2]] = f[2]; b[i[3]] = f[3]; #elif HV_SIMD_NEON hv_assert((vgetq_lane_s32(bIn0,0) >= 0) && (vgetq_lane_s32(bIn0,0) < hTable_getSize(o->table))); hv_assert((vgetq_lane_s32(bIn0,1) >= 0) && (vgetq_lane_s32(bIn0,1) < hTable_getSize(o->table))); hv_assert((vgetq_lane_s32(bIn0,2) >= 0) && (vgetq_lane_s32(bIn0,2) < hTable_getSize(o->table))); hv_assert((vgetq_lane_s32(bIn0,3) >= 0) && (vgetq_lane_s32(bIn0,3) < hTable_getSize(o->table))); vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 0), bIn1, 0); vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 1), bIn1, 1); vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 2), bIn1, 2); vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 3), bIn1, 3); #else // HV_SIMD_NONE b[bIn0] = bIn1; #endif } #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_SIGNAL_TABWRITE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalVar.c0000644000000000000000000000551200000000000017165 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvSignalVar.h" // __var~f static void sVarf_update(SignalVarf *o, float k, float step, bool reverse) { #if HV_SIMD_AVX if (reverse) o->v = _mm256_setr_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k); else o->v = _mm256_set_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k); #elif HV_SIMD_SSE if (reverse) o->v = _mm_setr_ps(k+3.0f*step, k+2.0f*step, k+step, k); else o->v = _mm_set_ps(k+3.0f*step, k+2.0f*step, k+step, k); #elif HV_SIMD_NEON if (reverse) o->v = (float32x4_t) {3.0f*step+k, 2.0f*step+k, step+k, k}; else o->v = (float32x4_t) {k, step+k, 2.0f*step+k, 3.0f*step+k}; #else // HV_SIMD_NONE o->v = k; #endif } hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse) { sVarf_update(o, k, step, reverse); return 0; } void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m) { if (msg_isFloat(m,0)) { sVarf_update(o, msg_getFloat(m,0), msg_isFloat(m,1) ? msg_getFloat(m,1) : 0.0f, msg_getNumElements(m) == 3); } } // __var~i static void sVari_update(SignalVari *o, int k, int step, bool reverse) { #if HV_SIMD_AVX if (reverse) o->v = _mm256_setr_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k); else o->v = _mm256_set_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k); #elif HV_SIMD_SSE if (reverse) o->v = _mm_setr_epi32(k+3*step, k+2*step, k+step, k); else o->v = _mm_set_epi32(k+3*step, k+2*step, k+step, k); #elif HV_SIMD_NEON if (reverse) o->v = (int32x4_t) {3*step+k, 2*step+k, step+k, k}; else o->v = (int32x4_t) {k, step+k, 2*step+k, 3*step+k}; #else // HV_SIMD_NEON o->v = k; #endif } hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse) { sVari_update(o, k, step, reverse); return 0; } void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m) { if (msg_isFloat(m,0)) { sVari_update(o, (int) msg_getFloat(m,0), msg_isFloat(m,1) ? (int) msg_getFloat(m,1) : 0, msg_getNumElements(m) == 3); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvSignalVar.h0000644000000000000000000000621300000000000017171 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_SIGNAL_VAR_H_ #define _HEAVY_SIGNAL_VAR_H_ #include "HvHeavyInternal.h" #ifdef __cplusplus extern "C" { #endif // __var~f, __varread~f, __varwrite~f typedef struct SignalVarf { hv_bufferf_t v; } SignalVarf; hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse); static inline void __hv_varread_f(SignalVarf *o, hv_bOutf_t bOut) { *bOut = o->v; } static inline void __hv_varwrite_f(SignalVarf *o, hv_bInf_t bIn) { o->v = bIn; } void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m); // __var~i, __varread~i, __varwrite~i typedef struct SignalVari { hv_bufferi_t v; } SignalVari; hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse); static inline void __hv_varread_i(SignalVari *o, hv_bOuti_t bOut) { *bOut = o->v; } static inline void __hv_varwrite_i(SignalVari *o, hv_bIni_t bIn) { o->v = bIn; } void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m); // __var_k~f, __var_k~i #if HV_SIMD_AVX #define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_h,_g,_f,_e,_d,_c,_b,_a) #define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_a,_b,_c,_d,_e,_f,_g,_h) #define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_h,_g,_f,_e,_d,_c,_b,_a) #define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_a,_b,_c,_d,_e,_f,_g,_h) #elif HV_SIMD_SSE #define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_d,_c,_b,_a) #define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_a,_b,_c,_d) #define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_d,_c,_b,_a) #define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_a,_b,_c,_d) #elif HV_SIMD_NEON #define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_a,_b,_c,_d}) #define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_d,_c,_b,_a}) #define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_a,_b,_c,_d}) #define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_d,_c,_b,_a}) #else // HV_SIMD_NONE #define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a #define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a #define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a #define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a #endif #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_SIGNAL_VAR_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvTable.c0000644000000000000000000001023300000000000016322 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvTable.h" #include "HvMessage.h" hv_size_t hTable_init(HvTable *o, int length) { o->length = length; // true size of the table is always an integer multple of HV_N_SIMD o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; // add an extra length for mirroring o->allocated = o->size + HV_N_SIMD; o->head = 0; hv_size_t numBytes = o->allocated * sizeof(float); o->buffer = (float *) hv_malloc(numBytes); hv_assert(o->buffer != NULL); hv_memclear(o->buffer, numBytes); return numBytes; } hv_size_t hTable_initWithData(HvTable *o, int length, const float *data) { o->length = length; o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; o->allocated = o->size + HV_N_SIMD; o->head = 0; hv_size_t numBytes = o->size * sizeof(float); o->buffer = (float *) hv_malloc(numBytes); hv_assert(o->buffer != NULL); hv_memclear(o->buffer, numBytes); hv_memcpy(o->buffer, data, length*sizeof(float)); return numBytes; } hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) { o->length = length; o->size = length; o->allocated = length; o->buffer = data; o->head = 0; return 0; } void hTable_free(HvTable *o) { hv_free(o->buffer); } int hTable_resize(HvTable *o, hv_uint32_t newLength) { // TODO(mhroth): update context with memory allocated by table // NOTE(mhroth): mirrored bytes are not necessarily carried over const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK; if (newSize == o->size) return 0; // early exit if no change in size const hv_uint32_t oldSizeBytes = (hv_uint32_t) (o->size * sizeof(float)); const hv_uint32_t newAllocated = newSize + HV_N_SIMD; const hv_uint32_t newAllocatedBytes = (hv_uint32_t) (newAllocated * sizeof(float)); float *b = (float *) hv_realloc(o->buffer, newAllocatedBytes); hv_assert(b != NULL); // error while reallocing! // ensure that hv_realloc has given us a correctly aligned buffer if ((((hv_uintptr_t) (const void *) b) & ((0x1< o->size) { hv_memclear(b + o->size, (newAllocated - o->size) * sizeof(float)); // clear new parts of the buffer } o->buffer = b; } else { // if not, we have to re-malloc ourselves char *c = (char *) hv_malloc(newAllocatedBytes); hv_assert(c != NULL); // error while allocating new buffer! if (newAllocatedBytes > oldSizeBytes) { hv_memcpy(c, b, oldSizeBytes); hv_memclear(c + oldSizeBytes, newAllocatedBytes - oldSizeBytes); } else { hv_memcpy(c, b, newAllocatedBytes); } hv_free(b); o->buffer = (float *) c; } o->length = newLength; o->size = newSize; o->allocated = newAllocated; return (int) (newAllocated - oldSizeBytes - (HV_N_SIMD*sizeof(float))); } void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) { if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) { hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space // send out the new size of the table HvMessage *n = HV_MESSAGE_ON_STACK(1); msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o)); sendMessage(_c, 0, n); } else if (msg_compareSymbol(m,0,"mirror")) { hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float)); } } hvcc-0.16.0/hvcc/generators/ir2c/static/HvTable.h0000644000000000000000000000510100000000000016325 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_TABLE_H_ #define _HEAVY_TABLE_H_ #include "HvHeavy.h" #include "HvUtils.h" #ifdef __cplusplus extern "C" { #endif typedef struct HvTable { float *buffer; // the number of values that the table is requested to have hv_uint32_t length; // the number of usable values that the table actually has // this is always an even multiple of HV_N_SIMD hv_uint32_t size; // Note that the true size of the table is (size + HV_N_SIMD), // with the trailing values used by the system, e.g. to create a circular // buffer hv_uint32_t allocated; hv_uint32_t head; // the most recently written point } HvTable; hv_size_t hTable_init(HvTable *o, int length); hv_size_t hTable_initWithData(HvTable *o, int length, const float *data); hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data); void hTable_free(HvTable *o); int hTable_resize(HvTable *o, hv_uint32_t newLength); void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)); static inline float *hTable_getBuffer(HvTable *o) { return o->buffer; } // the user-requested length of the table (number of floats) static inline hv_uint32_t hTable_getLength(HvTable *o) { return o->length; } // the usable length of the table (an even multiple of HV_N_SIMD) static inline hv_uint32_t hTable_getSize(HvTable *o) { return o->size; } // the number of floats allocated to this table (usually size + HV_N_SIMD) static inline hv_uint32_t hTable_getAllocated(HvTable *o) { return o->allocated; } static inline hv_uint32_t hTable_getHead(HvTable *o) { return o->head; } static inline void hTable_setHead(HvTable *o, hv_uint32_t head) { o->head = head; } #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_TABLE_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/HvUtils.c0000644000000000000000000000316500000000000016401 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "HvUtils.h" hv_uint32_t hv_string_to_hash(const char *str) { // this hash is based MurmurHash2 // http://en.wikipedia.org/wiki/MurmurHash // https://sites.google.com/site/murmurhash/ static const hv_uint32_t n = 0x5bd1e995; static const hv_int32_t r = 24; if (str == NULL) return 0; hv_uint32_t len = (hv_uint32_t) hv_strlen(str); hv_uint32_t x = len; // seed (0) ^ len while (len >= 4) { #if HV_EMSCRIPTEN hv_uint32_t k = str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24); #else hv_uint32_t k = *((hv_uint32_t *) str); #endif k *= n; k ^= (k >> r); k *= n; x *= n; x ^= k; str += 4; len -= 4; } switch (len) { case 3: x ^= (str[2] << 16); case 2: x ^= (str[1] << 8); case 1: x ^= str[0]; x *= n; default: break; } x ^= (x >> 13); x *= n; x ^= (x >> 15); return x; } hvcc-0.16.0/hvcc/generators/ir2c/static/HvUtils.h0000644000000000000000000002443300000000000016407 0ustar00/** * Copyright (c) 2014-2018 Enzien Audio Ltd. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HEAVY_UTILS_H_ #define _HEAVY_UTILS_H_ // platform definitions #if _WIN32 || _WIN64 || _MSC_VER #define HV_WIN 1 #elif __APPLE__ #define HV_APPLE 1 #elif __ANDROID__ #define HV_ANDROID 1 #elif __unix__ || __unix #define HV_UNIX 1 #else #ifndef HV_BARE_METAL #warning Could not detect platform. Assuming Unix-like. #endif #endif #ifdef EMSCRIPTEN #define HV_EMSCRIPTEN 1 #endif // basic includes #include #include #include // type definitions #include #include #define hv_uint8_t uint8_t #define hv_int16_t int16_t #define hv_uint16_t uint16_t #define hv_int32_t int32_t #define hv_uint32_t uint32_t #define hv_uint64_t uint64_t #define hv_size_t size_t #define hv_uintptr_t uintptr_t // SIMD-specific includes #if !(HV_SIMD_NONE || HV_SIMD_NEON || HV_SIMD_SSE || HV_SIMD_AVX) #define HV_SIMD_NEON __ARM_NEON__ #define HV_SIMD_SSE (__SSE__ && __SSE2__ && __SSE3__ && __SSSE3__ && __SSE4_1__) #define HV_SIMD_AVX (__AVX__ && HV_SIMD_SSE) #endif #ifndef HV_SIMD_FMA #define HV_SIMD_FMA __FMA__ #endif #if HV_SIMD_AVX || HV_SIMD_SSE #include #elif HV_SIMD_NEON #include #endif #if HV_SIMD_NEON // NEON #define HV_N_SIMD 4 #define hv_bufferf_t float32x4_t #define hv_bufferi_t int32x4_t #define hv_bInf_t float32x4_t #define hv_bOutf_t float32x4_t* #define hv_bIni_t int32x4_t #define hv_bOuti_t int32x4_t* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #elif HV_SIMD_AVX // AVX #define HV_N_SIMD 8 #define hv_bufferf_t __m256 #define hv_bufferi_t __m256i #define hv_bInf_t __m256 #define hv_bOutf_t __m256* #define hv_bIni_t __m256i #define hv_bOuti_t __m256i* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #elif HV_SIMD_SSE // SSE #define HV_N_SIMD 4 #define hv_bufferf_t __m128 #define hv_bufferi_t __m128i #define hv_bInf_t __m128 #define hv_bOutf_t __m128* #define hv_bIni_t __m128i #define hv_bOuti_t __m128i* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #else // DEFAULT #define HV_N_SIMD 1 #undef HV_SIMD_NONE #define HV_SIMD_NONE 1 #define hv_bufferf_t float #define hv_bufferi_t int #define hv_bInf_t float #define hv_bOutf_t float* #define hv_bIni_t int #define hv_bOuti_t int* #define VIf(_x) (_x) #define VOf(_x) (&_x) #define VIi(_x) (_x) #define VOi(_x) (&_x) #endif #define HV_N_SIMD_MASK (HV_N_SIMD-1) // Strings #include #define hv_strlen(a) strlen(a) #define hv_strcmp(a, b) strcmp(a, b) #define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) #if HV_WIN #define hv_strncpy(_dst, _src, _len) strncpy_s(_dst, _len, _src, _TRUNCATE) #else #define hv_strncpy(_dst, _src, _len) strncpy(_dst, _src, _len) #endif // Memory management #define hv_memcpy(a, b, c) memcpy(a, b, c) #define hv_memclear(a, b) memset(a, 0, b) #if HV_WIN #include #define hv_alloca(_n) _alloca(_n) #if HV_SIMD_AVX #define hv_malloc(_n) _aligned_malloc(_n, 32) #define hv_realloc(a, b) _aligned_realloc(a, b, 32) #define hv_free(x) _aligned_free(x) #elif HV_SIMD_SSE || HV_SIMD_NEON #define hv_malloc(_n) _aligned_malloc(_n, 16) #define hv_realloc(a, b) _aligned_realloc(a, b, 16) #define hv_free(x) _aligned_free(x) #else // HV_SIMD_NONE #define hv_malloc(_n) malloc(_n) #define hv_realloc(a, b) realloc(a, b) #define hv_free(_n) free(_n) #endif #elif HV_APPLE #define hv_alloca(_n) alloca(_n) #define hv_realloc(a, b) realloc(a, b) #if HV_SIMD_AVX #include #define hv_malloc(_n) _mm_malloc(_n, 32) #define hv_free(x) _mm_free(x) #elif HV_SIMD_SSE #include #define hv_malloc(_n) _mm_malloc(_n, 16) #define hv_free(x) _mm_free(x) #elif HV_SIMD_NEON // malloc on ios always has 16-byte alignment #define hv_malloc(_n) malloc(_n) #define hv_free(x) free(x) #else // HV_SIMD_NONE #define hv_malloc(_n) malloc(_n) #define hv_free(x) free(x) #endif #else #include #define hv_alloca(_n) alloca(_n) #define hv_realloc(a, b) realloc(a, b) #if HV_SIMD_AVX #define hv_malloc(_n) aligned_alloc(32, _n) #define hv_free(x) free(x) #elif HV_SIMD_SSE #define hv_malloc(_n) aligned_alloc(16, _n) #define hv_free(x) free(x) #elif HV_SIMD_NEON #if HV_ANDROID #define hv_malloc(_n) memalign(16, _n) #define hv_free(x) free(x) #else #define hv_malloc(_n) aligned_alloc(16, _n) #define hv_free(x) free(x) #endif #else // HV_SIMD_NONE #define hv_malloc(_n) malloc(_n) #define hv_free(_n) free(_n) #endif #endif // Assert #include #define hv_assert(e) assert(e) // Export and Inline #if HV_WIN #define HV_EXPORT __declspec(dllexport) #ifndef __cplusplus // MSVC doesn't like redefining "inline" keyword #define inline __inline #endif #define HV_FORCE_INLINE __forceinline #else #define HV_EXPORT #define HV_FORCE_INLINE inline __attribute__((always_inline)) #endif #ifdef __cplusplus extern "C" { #endif // Returns a 32-bit hash of any string. Returns 0 if string is NULL. hv_uint32_t hv_string_to_hash(const char *str); #ifdef __cplusplus } #endif // Math #include static inline hv_size_t __hv_utils_max_ui(hv_size_t x, hv_size_t y) { return (x > y) ? x : y; } static inline hv_size_t __hv_utils_min_ui(hv_size_t x, hv_size_t y) { return (x < y) ? x : y; } static inline hv_int32_t __hv_utils_max_i(hv_int32_t x, hv_int32_t y) { return (x > y) ? x : y; } static inline hv_int32_t __hv_utils_min_i(hv_int32_t x, hv_int32_t y) { return (x < y) ? x : y; } #define hv_max_ui(a, b) __hv_utils_max_ui(a, b) #define hv_min_ui(a, b) __hv_utils_min_ui(a, b) #define hv_max_i(a, b) __hv_utils_max_i(a, b) #define hv_min_i(a, b) __hv_utils_min_i(a, b) #define hv_max_f(a, b) fmaxf(a, b) #define hv_min_f(a, b) fminf(a, b) #define hv_max_d(a, b) fmax(a, b) #define hv_min_d(a, b) fmin(a, b) #define hv_sin_f(a) sinf(a) #define hv_sinh_f(a) sinhf(a) #define hv_cos_f(a) cosf(a) #define hv_cosh_f(a) coshf(a) #define hv_tan_f(a) tanf(a) #define hv_tanh_f(a) tanhf(a) #define hv_asin_f(a) asinf(a) #define hv_asinh_f(a) asinhf(a) #define hv_acos_f(a) acosf(a) #define hv_acosh_f(a) acoshf(a) #define hv_atan_f(a) atanf(a) #define hv_atanh_f(a) atanhf(a) #define hv_atan2_f(a, b) atan2f(a, b) #define hv_exp_f(a) expf(a) #define hv_abs_f(a) fabsf(a) #define hv_sqrt_f(a) sqrtf(a) #define hv_log_f(a) logf(a) #define hv_ceil_f(a) ceilf(a) #define hv_floor_f(a) floorf(a) #define hv_round_f(a) roundf(a) #define hv_pow_f(a, b) powf(a, b) #if HV_EMSCRIPTEN #define hv_fma_f(a, b, c) ((a*b)+c) // emscripten does not support fmaf (yet?) #else #define hv_fma_f(a, b, c) fmaf(a, b, c) #endif #if HV_WIN // finds ceil(log2(x)) #include static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) { unsigned long z = 0; _BitScanReverse(&z, x); return (hv_uint32_t) (z+1); } #else static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) { return (hv_uint32_t) (32 - __builtin_clz(x-1)); } #endif #define hv_min_max_log2(a) __hv_utils_min_max_log2(a) #define hv_if_f(a, b, c) ((a) ? (b) : (c)) #define hv_modf_f(a) fmodf(a, 1.0f) #define hv_cbrt_f(a) cbrtf(a) #define hv_copysign_f(a, b) copysignf(a, b) #define hv_remainder_f(a, b) remainderf(a, b) #define hv_erf_f(a) erff(a) #define hv_erfc_f(a) erfcf(a) #define hv_expm1_f(a) expm1f(a) #define hv_finite_f(a) isfinite(a) #define hv_fmod_f(a, b) fmodf(a, b) #define hv_ldexp_f(a, b) ldexpf(a, b) #define hv_isinf_f(a) isinf(a) #define hv_isnan_f(a) isnan(a) #define hv_ln_f(a) logf(a) #define hv_log10_f(a) log10f(a) #define hv_log1p_f(a) log1pf(a) #define hv_rint_f(a) rintf(a) #define hv_shl_i(a, b) ((a) << (b)) #define hv_shr_i(a, b) ((a) >> (b)) #define hv_bit_not_i(a) ~a #define hv_not_f(a) !a // Atomics #if HV_WIN #include #define hv_atomic_bool volatile LONG #define HV_SPINLOCK_ACQUIRE(_x) while (InterlockedCompareExchange(&_x, true, false)) { } #define HV_SPINLOCK_TRY(_x) return !InterlockedCompareExchange(&_x, true, false) #define HV_SPINLOCK_RELEASE(_x) (_x = false) #elif HV_ANDROID // Android support for atomics isn't that great, we'll do it manually // https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html #define hv_atomic_bool hv_uint8_t #define HV_SPINLOCK_ACQUIRE(_x) while (__sync_lock_test_and_set(&_x, 1)) #define HV_SPINLOCK_TRY(_x) return !__sync_lock_test_and_set(&_x, 1) #define HV_SPINLOCK_RELEASE(_x) __sync_lock_release(&_x) #elif __cplusplus #include #define hv_atomic_bool std::atomic_flag #define HV_SPINLOCK_ACQUIRE(_x) while (_x.test_and_set(std::memory_order_acquire)) #define HV_SPINLOCK_TRY(_x) return !_x.test_and_set(std::memory_order_acquire) #define HV_SPINLOCK_RELEASE(_x) _x.clear(std::memory_order_release) #elif defined(__has_include) #if __has_include() #include #define hv_atomic_bool atomic_flag #define HV_SPINLOCK_ACQUIRE(_x) while (atomic_flag_test_and_set_explicit(&_x, memory_order_acquire)) #define HV_SPINLOCK_TRY(_x) return !atomic_flag_test_and_set_explicit(&_x, memory_order_acquire) #define HV_SPINLOCK_RELEASE(_x) atomic_flag_clear_explicit(memory_order_release) #endif #endif #ifndef hv_atomic_bool #define hv_atomic_bool volatile bool #define HV_SPINLOCK_ACQUIRE(_x) \ while (_x) {} \ _x = true; #define HV_SPINLOCK_TRY(_x) \ if (!_x) { \ _x = true; \ return true; \ } else return false; #define HV_SPINLOCK_RELEASE(_x) (_x = false) #endif #endif // _HEAVY_UTILS_H_ hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNAM_C.cpp0000644000000000000000000000633200000000000017211 0ustar00#include "MicroNAM_C.h" #include "MicroNam/MicroNAM.h" #include // We use a block size of 1 for single-sample processing #define NAM_BLOCK_SIZE 1 using namespace MicroNAM; #ifdef __cplusplus extern "C" { #endif // --- NanoNet --- MicroNAM_NanoNet* MicroNAM_NanoNet_Create(void) { return reinterpret_cast(new (std::nothrow) NanoNet()); } void MicroNAM_NanoNet_Destroy(MicroNAM_NanoNet* net) { delete reinterpret_cast*>(net); } void MicroNAM_NanoNet_Reset(MicroNAM_NanoNet* net) { reinterpret_cast*>(net)->reset(); } void MicroNAM_NanoNet_LoadWeights(MicroNAM_NanoNet* net, const float* weights) { reinterpret_cast*>(net)->load_weights(weights); } void MicroNAM_NanoNet_Process(MicroNAM_NanoNet* net, float* input, float* output) { reinterpret_cast*>(net)->forward(input, output); } // --- FeatherNet --- MicroNAM_FeatherNet* MicroNAM_FeatherNet_Create(void) { return reinterpret_cast(new (std::nothrow) FeatherNet()); } void MicroNAM_FeatherNet_Destroy(MicroNAM_FeatherNet* net) { delete reinterpret_cast*>(net); } void MicroNAM_FeatherNet_Reset(MicroNAM_FeatherNet* net) { reinterpret_cast*>(net)->reset(); } void MicroNAM_FeatherNet_LoadWeights(MicroNAM_FeatherNet* net, const float* weights) { reinterpret_cast*>(net)->load_weights(weights); } void MicroNAM_FeatherNet_Process(MicroNAM_FeatherNet* net, float* input, float* output) { reinterpret_cast*>(net)->forward(input, output); } // --- LiteNet --- MicroNAM_LiteNet* MicroNAM_LiteNet_Create(void) { return reinterpret_cast(new (std::nothrow) LiteNet()); } void MicroNAM_LiteNet_Destroy(MicroNAM_LiteNet* net) { delete reinterpret_cast*>(net); } void MicroNAM_LiteNet_Reset(MicroNAM_LiteNet* net) { reinterpret_cast*>(net)->reset(); } void MicroNAM_LiteNet_LoadWeights(MicroNAM_LiteNet* net, const float* weights) { reinterpret_cast*>(net)->load_weights(weights); } void MicroNAM_LiteNet_Process(MicroNAM_LiteNet* net, float* input, float* output) { reinterpret_cast*>(net)->forward(input, output); } // --- StandardNet --- MicroNAM_StandardNet* MicroNAM_StandardNet_Create(void) { return reinterpret_cast(new (std::nothrow) StandardNet()); } void MicroNAM_StandardNet_Destroy(MicroNAM_StandardNet* net) { delete reinterpret_cast*>(net); } void MicroNAM_StandardNet_Reset(MicroNAM_StandardNet* net) { reinterpret_cast*>(net)->reset(); } void MicroNAM_StandardNet_LoadWeights(MicroNAM_StandardNet* net, const float* weights) { reinterpret_cast*>(net)->load_weights(weights); } void MicroNAM_StandardNet_Process(MicroNAM_StandardNet* net, float* input, float* output) { reinterpret_cast*>(net)->forward(input, output); } #ifdef __cplusplus } // extern "C" #endif hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNAM_C.h0000644000000000000000000000342500000000000016656 0ustar00#pragma once #ifdef __cplusplus extern "C" { #endif #include // Opaque handles for the different network types typedef struct MicroNAM_NanoNet MicroNAM_NanoNet; typedef struct MicroNAM_FeatherNet MicroNAM_FeatherNet; typedef struct MicroNAM_LiteNet MicroNAM_LiteNet; typedef struct MicroNAM_StandardNet MicroNAM_StandardNet; // --- NanoNet API --- MicroNAM_NanoNet* MicroNAM_NanoNet_Create(void); void MicroNAM_NanoNet_Destroy(MicroNAM_NanoNet* net); void MicroNAM_NanoNet_Reset(MicroNAM_NanoNet* net); void MicroNAM_NanoNet_LoadWeights(MicroNAM_NanoNet* net, const float* weights); void MicroNAM_NanoNet_Process(MicroNAM_NanoNet* net, float* input, float* output); // --- FeatherNet API --- MicroNAM_FeatherNet* MicroNAM_FeatherNet_Create(void); void MicroNAM_FeatherNet_Destroy(MicroNAM_FeatherNet* net); void MicroNAM_FeatherNet_Reset(MicroNAM_FeatherNet* net); void MicroNAM_FeatherNet_LoadWeights(MicroNAM_FeatherNet* net, const float* weights); void MicroNAM_FeatherNet_Process(MicroNAM_FeatherNet* net, float* input, float* output); // --- LiteNet API --- MicroNAM_LiteNet* MicroNAM_LiteNet_Create(void); void MicroNAM_LiteNet_Destroy(MicroNAM_LiteNet* net); void MicroNAM_LiteNet_Reset(MicroNAM_LiteNet* net); void MicroNAM_LiteNet_LoadWeights(MicroNAM_LiteNet* net, const float* weights); void MicroNAM_LiteNet_Process(MicroNAM_LiteNet* net, float* input, float* output); // --- StandardNet API --- MicroNAM_StandardNet* MicroNAM_StandardNet_Create(void); void MicroNAM_StandardNet_Destroy(MicroNAM_StandardNet* net); void MicroNAM_StandardNet_Reset(MicroNAM_StandardNet* net); void MicroNAM_StandardNet_LoadWeights(MicroNAM_StandardNet* net, const float* weights); void MicroNAM_StandardNet_Process(MicroNAM_StandardNet* net, float* input, float* output); #ifdef __cplusplus } #endif hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/.git0000644000000000000000000000011100000000000017114 0ustar00gitdir: ../../../../../.git/modules/hvcc/generators/ir2c/static/MicroNam hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/LICENSE0000644000000000000000000000206000000000000017342 0ustar00MIT License Copyright (c) 2026 Jaffx Audio Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/MicroNAM.h0000644000000000000000000000021000000000000020106 0ustar00#pragma once #include "include/NanoNet.h" #include "include/FeatherNet.h" #include "include/LiteNet.h" #include "include/StandardNet.h"hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/README.md0000644000000000000000000000133600000000000017621 0ustar00# MicroNAM Header-only [NAM](https://neuralampmodeler.com) inference with zero dependencies. ## Using 1. `#include "MicroNAM.h"` in your C++ project 2. Generate weights header with `nam_to_header.py ` and `#include` it 3. Example code below for instantiation in app: ```cpp MicroNAM::NanoNet<1> mNamInstance; // audio block size 1 mNamInstance.load_weights(mModelWeights); float inputBuffer[1]; float outputBuffer[1]; mNamInstance.forward(inputBuffer, outputBuffer); ``` ## Awknowledgements MicroNAM is based on an implementation shared by [nadavb](https://github.com/nadavb9001) in an [Electrosmith Daisy forum thread](https://forum.electro-smith.com/t/running-nam-on-embedded-hardware/9053/7?u=kidproquo).hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/include/FeatherNet.h0000644000000000000000000011504400000000000022165 0ustar00#pragma once #include #include #include namespace MicroNAM { // ───────────────────────────────────────────────────────────────────────────── // Feather WaveNet inference engine // // Feather architecture (from neural-amp-modeler/nam/train/core.py): // LA0: 7 layers × 8-channel, kernel_size=3, dilations=[1,2,4,8,16,32,64] // head_size=4 (8-ch activations projected 8→4 to seed LA1 head) // LA1: 13 layers × 4-channel, kernel_size=3, // dilations=[128,256,512,1,2,4,8,16,32,64,128,256,512] // head_size=1 (4-ch head dot-producted → scalar output) // head_scale=0.02 // // load_weights expects exactly 3026 floats in the NAM file weight order. // forward processes exactly NAM_BLOCK samples per call. // ───────────────────────────────────────────────────────────────────────────── template class FeatherNet { public: // ── API ─────────────────────────────────────────────────────────────── void reset() { reset_impl(); } void load_weights(const float* model_weights) { load_weights_impl(model_weights); } void forward(const float* input, float* output) noexcept { forward_impl(input, output); } // ^ Process exactly NAM_BLOCK samples. // ────────────────────────────────────────────────────────────────────── private: // ───────────────────────────────────────────────────────────────────────────── // Padé(3,2) tanh — same approximation as NanoNAM. // ───────────────────────────────────────────────────────────────────────────── static inline float nam_tanh(float x) noexcept { const float x2 = x * x; const float num = x * (27.0f + x2); const float den = 27.0f + 9.0f * x2; return num / den; } // ── 4-channel layer (used for LA1) ─────────────────────────────────────── struct Layer4 { float w0T[4][4]; // tap0 (current input), [in][out] float w1T[4][4]; // tap1 = state[ptr-D], [in][out] float w2T[4][4]; // tap2 = state[ptr-2D], [in][out] float conv_b[4]; float mixin_w[4]; float w1x1T[4][4]; // 1×1 projection, [in][out] float b1x1[4]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── 8-channel layer (used for LA0) ─────────────────────────────────────── struct Layer8 { float w0T[8][8]; // tap0 (current input), [in][out] float w1T[8][8]; // tap1 = state[ptr-D], [in][out] float w2T[8][8]; // tap2 = state[ptr-2D], [in][out] float conv_b[8]; float mixin_w[8]; float w1x1T[8][8]; // 1×1 projection, [in][out] float b1x1[8]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── Layer Array 0: 7 × 8-channel ───────────────────────────────────────── float la0_rechannel_w[8]; // 1→8 input projection float la0_head_wT[8][4]; // 8→4 head projection, [in][out] Layer8 la0[7]; // State: sum((2d+1)*8) for d in {1,2,4,8,16,32,64} // = 24+40+72+136+264+520+1032 = 2088 float la0_state[2088]; // ── Layer Array 1: 13 × 4-channel ──────────────────────────────────────── float la1_rechannel_wT[8][4]; // 8→4 rechannel, [in][out] float la1_head_w[4]; float la1_head_b; Layer4 la1[13]; // State: sum((2d+1)*4) for d in {128,256,512,1,2,4,8,16,32,64,128,256,512} // = 1028+2052+4100+12+20+36+68+132+260+516+1028+2052+4100 = 15404 float la1_state[15404]; float head_scale; // ── Block working buffers ───────────────────────────────────────────────── float la0_buf_a[NAM_BLOCK][8]; float la0_buf_b[NAM_BLOCK][8]; float la0_head [NAM_BLOCK][8]; // LA0 skip-connection accumulator (8-ch) float la1_buf_a[NAM_BLOCK][4]; float la1_buf_b[NAM_BLOCK][4]; float la1_head [NAM_BLOCK][4]; void init_state_ptrs() { static constexpr int la0_d[7] = { 1, 2, 4, 8, 16, 32, 64 }; static constexpr int la1_d[13] = { 128, 256, 512, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; int off = 0; for (int i = 0; i < 7; ++i) { const int d = la0_d[i]; const int ss = (3-1)*d + 1; la0[i].state_size = ss; la0[i].state_ptr = 0; la0[i].neg_dilation = ss - d; la0[i].neg_2dilation = ss - 2*d; la0[i].state = la0_state + off; off += 8 * ss; } off = 0; for (int i = 0; i < 13; ++i) { const int d = la1_d[i]; const int ss = (3-1)*d + 1; la1[i].state_size = ss; la1[i].state_ptr = 0; la1[i].neg_dilation = ss - d; la1[i].neg_2dilation = ss - 2*d; la1[i].state = la1_state + off; off += 4 * ss; } } void reset_impl() { for (int i = 0; i < 2088; ++i) la0_state[i] = 0.f; for (int i = 0; i < 15404; ++i) la1_state[i] = 0.f; for (int i = 0; i < 7; ++i) la0[i].state_ptr = 0; for (int i = 0; i < 13; ++i) la1[i].state_ptr = 0; } // ───────────────────────────────────────────────────────────────────────────── // load_weights — float[3026] // // File weight order: conv[out][in][k], k=0 oldest, k=2 newest. // Split at load time: // file k=2 → w0T[in][out] (tap0 = current input) // file k=1 → w1T[in][out] // file k=0 → w2T[in][out] // // Weight tally: // la0_rechannel_w: 8 // LA0 × 7 layers: 7 × (8*8*3 + 8 + 8 + 8*8 + 8) = 7 × 280 = 1960 // la0_head_wT: 8×4 = 32 // la1_rechannel_wT: 8×4 = 32 // LA1 × 13 layers: 13 × (4*4*3 + 4 + 4 + 4*4 + 4) = 13 × 76 = 988 // la1_head_w: 4 // la1_head_b: 1 // head_scale: 1 // Total: 3026 // ───────────────────────────────────────────────────────────────────────────── void load_weights_impl(const float* model_weights) { init_state_ptrs(); reset_impl(); const float* w = model_weights; // ── LA0 ────────────────────────────────────────────────────────────────── for (int o = 0; o < 8; ++o) la0_rechannel_w[o] = *w++; for (int l = 0; l < 7; ++l) { for (int o = 0; o < 8; ++o) for (int i = 0; i < 8; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la0[l].w0T[i][o] = val; else if (k == 1) la0[l].w1T[i][o] = val; else la0[l].w2T[i][o] = val; } for (int o = 0; o < 8; ++o) la0[l].conv_b[o] = *w++; for (int o = 0; o < 8; ++o) la0[l].mixin_w[o] = *w++; for (int o = 0; o < 8; ++o) for (int i = 0; i < 8; ++i) la0[l].w1x1T[i][o] = *w++; for (int o = 0; o < 8; ++o) la0[l].b1x1[o] = *w++; } for (int o = 0; o < 4; ++o) for (int i = 0; i < 8; ++i) la0_head_wT[i][o] = *w++; // ── LA1 ────────────────────────────────────────────────────────────────── for (int o = 0; o < 4; ++o) for (int i = 0; i < 8; ++i) la1_rechannel_wT[i][o] = *w++; for (int l = 0; l < 13; ++l) { for (int o = 0; o < 4; ++o) for (int i = 0; i < 4; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la1[l].w0T[i][o] = val; else if (k == 1) la1[l].w1T[i][o] = val; else la1[l].w2T[i][o] = val; } for (int o = 0; o < 4; ++o) la1[l].conv_b[o] = *w++; for (int o = 0; o < 4; ++o) la1[l].mixin_w[o] = *w++; for (int o = 0; o < 4; ++o) for (int i = 0; i < 4; ++i) la1[l].w1x1T[i][o] = *w++; for (int o = 0; o < 4; ++o) la1[l].b1x1[o] = *w++; } la1_head_w[0] = *w++; la1_head_w[1] = *w++; la1_head_w[2] = *w++; la1_head_w[3] = *w++; la1_head_b = *w++; head_scale = *w++; assert((int)(w - model_weights) == 3026); } // ───────────────────────────────────────────────────────────────────────────── // forward — process exactly NAM_BLOCK samples // // Structure (layer-outer, sample-inner): // // LA0: // rechannel input[n] → la0_buf_a[n][8] // zero la0_head // for each of 7 layers: // Layer8_process_block(ping, pong, input, la0_head) // swap ping/pong // project la0_head[n][8] → la1_head[n][4] (initial head for LA1) // // LA1: // rechannel la0_buf_b[n][8] → la1_buf_a[n][4] // for each of 13 layers: // Layer4_process_block(ping, pong, input, la1_head) // swap ping/pong // // Output: // output[n] = head_scale * (la1_head_b + la1_head[n] @ la1_head_w) // ───────────────────────────────────────────────────────────────────────────── void forward_impl(const float* input, float* output) noexcept { const int N = (int)NAM_BLOCK; // ── LA0 rechannel: 1→8 ──────────────────────────────────────────────── { const float r0 = la0_rechannel_w[0], r1 = la0_rechannel_w[1], r2 = la0_rechannel_w[2], r3 = la0_rechannel_w[3], r4 = la0_rechannel_w[4], r5 = la0_rechannel_w[5], r6 = la0_rechannel_w[6], r7 = la0_rechannel_w[7]; for (int n = 0; n < N; ++n) { const float x = input[n]; la0_buf_a[n][0] = r0*x; la0_buf_a[n][1] = r1*x; la0_buf_a[n][2] = r2*x; la0_buf_a[n][3] = r3*x; la0_buf_a[n][4] = r4*x; la0_buf_a[n][5] = r5*x; la0_buf_a[n][6] = r6*x; la0_buf_a[n][7] = r7*x; } } // ── Zero LA0 head accumulator ───────────────────────────────────────── for (int n = 0; n < N; ++n) la0_head[n][0] = la0_head[n][1] = la0_head[n][2] = la0_head[n][3] = la0_head[n][4] = la0_head[n][5] = la0_head[n][6] = la0_head[n][7] = 0.0f; // ── LA0 layer loop ──────────────────────────────────────────────────── // 7 swaps (odd): final output lands in la0_buf_b { const float (*ping)[8] = la0_buf_a; float (*pong)[8] = la0_buf_b; for (int l = 0; l < 7; ++l) { Layer8_process_block(la0[l], ping, pong, input, la0_head, N); float (*tmp)[8] = pong; pong = (float(*)[8])ping; ping = tmp; } (void)ping; } // ── Project LA0 head 8→4 → initialise la1_head ─────────────────────── { const float h00 = la0_head_wT[0][0], h01 = la0_head_wT[0][1], h02 = la0_head_wT[0][2], h03 = la0_head_wT[0][3]; const float h10 = la0_head_wT[1][0], h11 = la0_head_wT[1][1], h12 = la0_head_wT[1][2], h13 = la0_head_wT[1][3]; const float h20 = la0_head_wT[2][0], h21 = la0_head_wT[2][1], h22 = la0_head_wT[2][2], h23 = la0_head_wT[2][3]; const float h30 = la0_head_wT[3][0], h31 = la0_head_wT[3][1], h32 = la0_head_wT[3][2], h33 = la0_head_wT[3][3]; const float h40 = la0_head_wT[4][0], h41 = la0_head_wT[4][1], h42 = la0_head_wT[4][2], h43 = la0_head_wT[4][3]; const float h50 = la0_head_wT[5][0], h51 = la0_head_wT[5][1], h52 = la0_head_wT[5][2], h53 = la0_head_wT[5][3]; const float h60 = la0_head_wT[6][0], h61 = la0_head_wT[6][1], h62 = la0_head_wT[6][2], h63 = la0_head_wT[6][3]; const float h70 = la0_head_wT[7][0], h71 = la0_head_wT[7][1], h72 = la0_head_wT[7][2], h73 = la0_head_wT[7][3]; for (int n = 0; n < N; ++n) { const float v0 = la0_head[n][0], v1 = la0_head[n][1], v2 = la0_head[n][2], v3 = la0_head[n][3], v4 = la0_head[n][4], v5 = la0_head[n][5], v6 = la0_head[n][6], v7 = la0_head[n][7]; la1_head[n][0] = v0*h00 + v1*h10 + v2*h20 + v3*h30 + v4*h40 + v5*h50 + v6*h60 + v7*h70; la1_head[n][1] = v0*h01 + v1*h11 + v2*h21 + v3*h31 + v4*h41 + v5*h51 + v6*h61 + v7*h71; la1_head[n][2] = v0*h02 + v1*h12 + v2*h22 + v3*h32 + v4*h42 + v5*h52 + v6*h62 + v7*h72; la1_head[n][3] = v0*h03 + v1*h13 + v2*h23 + v3*h33 + v4*h43 + v5*h53 + v6*h63 + v7*h73; } } // ── LA1 rechannel: 8→4 ─────────────────────────────────────────────── { const float r00 = la1_rechannel_wT[0][0], r01 = la1_rechannel_wT[0][1], r02 = la1_rechannel_wT[0][2], r03 = la1_rechannel_wT[0][3]; const float r10 = la1_rechannel_wT[1][0], r11 = la1_rechannel_wT[1][1], r12 = la1_rechannel_wT[1][2], r13 = la1_rechannel_wT[1][3]; const float r20 = la1_rechannel_wT[2][0], r21 = la1_rechannel_wT[2][1], r22 = la1_rechannel_wT[2][2], r23 = la1_rechannel_wT[2][3]; const float r30 = la1_rechannel_wT[3][0], r31 = la1_rechannel_wT[3][1], r32 = la1_rechannel_wT[3][2], r33 = la1_rechannel_wT[3][3]; const float r40 = la1_rechannel_wT[4][0], r41 = la1_rechannel_wT[4][1], r42 = la1_rechannel_wT[4][2], r43 = la1_rechannel_wT[4][3]; const float r50 = la1_rechannel_wT[5][0], r51 = la1_rechannel_wT[5][1], r52 = la1_rechannel_wT[5][2], r53 = la1_rechannel_wT[5][3]; const float r60 = la1_rechannel_wT[6][0], r61 = la1_rechannel_wT[6][1], r62 = la1_rechannel_wT[6][2], r63 = la1_rechannel_wT[6][3]; const float r70 = la1_rechannel_wT[7][0], r71 = la1_rechannel_wT[7][1], r72 = la1_rechannel_wT[7][2], r73 = la1_rechannel_wT[7][3]; for (int n = 0; n < N; ++n) { const float* const src = la0_buf_b[n]; la1_buf_a[n][0] = src[0]*r00 + src[1]*r10 + src[2]*r20 + src[3]*r30 + src[4]*r40 + src[5]*r50 + src[6]*r60 + src[7]*r70; la1_buf_a[n][1] = src[0]*r01 + src[1]*r11 + src[2]*r21 + src[3]*r31 + src[4]*r41 + src[5]*r51 + src[6]*r61 + src[7]*r71; la1_buf_a[n][2] = src[0]*r02 + src[1]*r12 + src[2]*r22 + src[3]*r32 + src[4]*r42 + src[5]*r52 + src[6]*r62 + src[7]*r72; la1_buf_a[n][3] = src[0]*r03 + src[1]*r13 + src[2]*r23 + src[3]*r33 + src[4]*r43 + src[5]*r53 + src[6]*r63 + src[7]*r73; } } // ── LA1 layer loop ──────────────────────────────────────────────────── // 13 swaps (odd): final output lands in la1_buf_b (unused — only head needed) { const float (*ping)[4] = la1_buf_a; float (*pong)[4] = la1_buf_b; for (int l = 0; l < 13; ++l) { Layer4_process_block(la1[l], ping, pong, input, la1_head, N); float (*tmp)[4] = pong; pong = (float(*)[4])ping; ping = tmp; } } // ── Output: head → scalar ───────────────────────────────────────────── { const float w0 = la1_head_w[0], w1 = la1_head_w[1], w2 = la1_head_w[2], w3 = la1_head_w[3]; const float b = la1_head_b; const float sc = head_scale; for (int n = 0; n < N; ++n) output[n] = sc * (b + la1_head[n][0]*w0 + la1_head[n][1]*w1 + la1_head[n][2]*w2 + la1_head[n][3]*w3); } } // ───────────────────────────────────────────────────────────────────────────── // Layer4_process_block (4-channel; used for LA1) // Identical in structure to NanoNAM's Layer4_process_block. // ───────────────────────────────────────────────────────────────────────────── void Layer4_process_block(Layer4& layer, const float ins[][4], float outs[][4], const float* cond, float head[][4], int N) noexcept { const float c0_00 = layer.w0T[0][0], c0_01 = layer.w0T[0][1], c0_02 = layer.w0T[0][2], c0_03 = layer.w0T[0][3]; const float c0_10 = layer.w0T[1][0], c0_11 = layer.w0T[1][1], c0_12 = layer.w0T[1][2], c0_13 = layer.w0T[1][3]; const float c0_20 = layer.w0T[2][0], c0_21 = layer.w0T[2][1], c0_22 = layer.w0T[2][2], c0_23 = layer.w0T[2][3]; const float c0_30 = layer.w0T[3][0], c0_31 = layer.w0T[3][1], c0_32 = layer.w0T[3][2], c0_33 = layer.w0T[3][3]; const float c1_00 = layer.w1T[0][0], c1_01 = layer.w1T[0][1], c1_02 = layer.w1T[0][2], c1_03 = layer.w1T[0][3]; const float c1_10 = layer.w1T[1][0], c1_11 = layer.w1T[1][1], c1_12 = layer.w1T[1][2], c1_13 = layer.w1T[1][3]; const float c1_20 = layer.w1T[2][0], c1_21 = layer.w1T[2][1], c1_22 = layer.w1T[2][2], c1_23 = layer.w1T[2][3]; const float c1_30 = layer.w1T[3][0], c1_31 = layer.w1T[3][1], c1_32 = layer.w1T[3][2], c1_33 = layer.w1T[3][3]; const float c2_00 = layer.w2T[0][0], c2_01 = layer.w2T[0][1], c2_02 = layer.w2T[0][2], c2_03 = layer.w2T[0][3]; const float c2_10 = layer.w2T[1][0], c2_11 = layer.w2T[1][1], c2_12 = layer.w2T[1][2], c2_13 = layer.w2T[1][3]; const float c2_20 = layer.w2T[2][0], c2_21 = layer.w2T[2][1], c2_22 = layer.w2T[2][2], c2_23 = layer.w2T[2][3]; const float c2_30 = layer.w2T[3][0], c2_31 = layer.w2T[3][1], c2_32 = layer.w2T[3][2], c2_33 = layer.w2T[3][3]; const float cx_00 = layer.w1x1T[0][0], cx_01 = layer.w1x1T[0][1], cx_02 = layer.w1x1T[0][2], cx_03 = layer.w1x1T[0][3]; const float cx_10 = layer.w1x1T[1][0], cx_11 = layer.w1x1T[1][1], cx_12 = layer.w1x1T[1][2], cx_13 = layer.w1x1T[1][3]; const float cx_20 = layer.w1x1T[2][0], cx_21 = layer.w1x1T[2][1], cx_22 = layer.w1x1T[2][2], cx_23 = layer.w1x1T[2][3]; const float cx_30 = layer.w1x1T[3][0], cx_31 = layer.w1x1T[3][1], cx_32 = layer.w1x1T[3][2], cx_33 = layer.w1x1T[3][3]; const float mb0 = layer.conv_b[0], mb1 = layer.conv_b[1], mb2 = layer.conv_b[2], mb3 = layer.conv_b[3]; const float mx0 = layer.mixin_w[0], mx1 = layer.mixin_w[1], mx2 = layer.mixin_w[2], mx3 = layer.mixin_w[3]; const float bx0 = layer.b1x1[0], bx1 = layer.b1x1[1], bx2 = layer.b1x1[2], bx3 = layer.b1x1[3]; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { float* const cw = layer.state + ptr * 4; const float i0 = ins[n][0], i1 = ins[n][1], i2 = ins[n][2], i3 = ins[n][3]; cw[0] = i0; cw[1] = i1; cw[2] = i2; cw[3] = i3; int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 4; const float* __restrict__ s2 = layer.state + sp2 * 4; float t0 = mb0, t1 = mb1, t2 = mb2, t3 = mb3; t0 += i0*c0_00 + i1*c0_10 + i2*c0_20 + i3*c0_30; t1 += i0*c0_01 + i1*c0_11 + i2*c0_21 + i3*c0_31; t2 += i0*c0_02 + i1*c0_12 + i2*c0_22 + i3*c0_32; t3 += i0*c0_03 + i1*c0_13 + i2*c0_23 + i3*c0_33; const float s1_0 = s1[0], s1_1 = s1[1], s1_2 = s1[2], s1_3 = s1[3]; t0 += s1_0*c1_00 + s1_1*c1_10 + s1_2*c1_20 + s1_3*c1_30; t1 += s1_0*c1_01 + s1_1*c1_11 + s1_2*c1_21 + s1_3*c1_31; t2 += s1_0*c1_02 + s1_1*c1_12 + s1_2*c1_22 + s1_3*c1_32; t3 += s1_0*c1_03 + s1_1*c1_13 + s1_2*c1_23 + s1_3*c1_33; const float s2_0 = s2[0], s2_1 = s2[1], s2_2 = s2[2], s2_3 = s2[3]; t0 += s2_0*c2_00 + s2_1*c2_10 + s2_2*c2_20 + s2_3*c2_30; t1 += s2_0*c2_01 + s2_1*c2_11 + s2_2*c2_21 + s2_3*c2_31; t2 += s2_0*c2_02 + s2_1*c2_12 + s2_2*c2_22 + s2_3*c2_32; t3 += s2_0*c2_03 + s2_1*c2_13 + s2_2*c2_23 + s2_3*c2_33; const float cn = cond[n]; t0 += mx0*cn; t1 += mx1*cn; t2 += mx2*cn; t3 += mx3*cn; const float a0 = nam_tanh(t0), a1 = nam_tanh(t1), a2 = nam_tanh(t2), a3 = nam_tanh(t3); head[n][0] += a0; head[n][1] += a1; head[n][2] += a2; head[n][3] += a3; float o0 = i0 + bx0, o1 = i1 + bx1, o2 = i2 + bx2, o3 = i3 + bx3; o0 += a0*cx_00 + a1*cx_10 + a2*cx_20 + a3*cx_30; o1 += a0*cx_01 + a1*cx_11 + a2*cx_21 + a3*cx_31; o2 += a0*cx_02 + a1*cx_12 + a2*cx_22 + a3*cx_32; o3 += a0*cx_03 + a1*cx_13 + a2*cx_23 + a3*cx_33; outs[n][0] = o0; outs[n][1] = o1; outs[n][2] = o2; outs[n][3] = o3; } layer.state_ptr = ptr; } // ───────────────────────────────────────────────────────────────────────────── // Layer8_process_block (8-channel; used for LA0) // // Same structure as Layer4_process_block, scaled to 8×8 weight matrices. // Weights hoisted as local const for register allocation over the N loop. // ───────────────────────────────────────────────────────────────────────────── void Layer8_process_block(Layer8& layer, const float ins[][8], float outs[][8], const float* cond, float head[][8], int N) noexcept { // ── Hoist w0T[8][8] ─────────────────────────────────────────────────── const float c0_00 = layer.w0T[0][0], c0_01 = layer.w0T[0][1], c0_02 = layer.w0T[0][2], c0_03 = layer.w0T[0][3], c0_04 = layer.w0T[0][4], c0_05 = layer.w0T[0][5], c0_06 = layer.w0T[0][6], c0_07 = layer.w0T[0][7]; const float c0_10 = layer.w0T[1][0], c0_11 = layer.w0T[1][1], c0_12 = layer.w0T[1][2], c0_13 = layer.w0T[1][3], c0_14 = layer.w0T[1][4], c0_15 = layer.w0T[1][5], c0_16 = layer.w0T[1][6], c0_17 = layer.w0T[1][7]; const float c0_20 = layer.w0T[2][0], c0_21 = layer.w0T[2][1], c0_22 = layer.w0T[2][2], c0_23 = layer.w0T[2][3], c0_24 = layer.w0T[2][4], c0_25 = layer.w0T[2][5], c0_26 = layer.w0T[2][6], c0_27 = layer.w0T[2][7]; const float c0_30 = layer.w0T[3][0], c0_31 = layer.w0T[3][1], c0_32 = layer.w0T[3][2], c0_33 = layer.w0T[3][3], c0_34 = layer.w0T[3][4], c0_35 = layer.w0T[3][5], c0_36 = layer.w0T[3][6], c0_37 = layer.w0T[3][7]; const float c0_40 = layer.w0T[4][0], c0_41 = layer.w0T[4][1], c0_42 = layer.w0T[4][2], c0_43 = layer.w0T[4][3], c0_44 = layer.w0T[4][4], c0_45 = layer.w0T[4][5], c0_46 = layer.w0T[4][6], c0_47 = layer.w0T[4][7]; const float c0_50 = layer.w0T[5][0], c0_51 = layer.w0T[5][1], c0_52 = layer.w0T[5][2], c0_53 = layer.w0T[5][3], c0_54 = layer.w0T[5][4], c0_55 = layer.w0T[5][5], c0_56 = layer.w0T[5][6], c0_57 = layer.w0T[5][7]; const float c0_60 = layer.w0T[6][0], c0_61 = layer.w0T[6][1], c0_62 = layer.w0T[6][2], c0_63 = layer.w0T[6][3], c0_64 = layer.w0T[6][4], c0_65 = layer.w0T[6][5], c0_66 = layer.w0T[6][6], c0_67 = layer.w0T[6][7]; const float c0_70 = layer.w0T[7][0], c0_71 = layer.w0T[7][1], c0_72 = layer.w0T[7][2], c0_73 = layer.w0T[7][3], c0_74 = layer.w0T[7][4], c0_75 = layer.w0T[7][5], c0_76 = layer.w0T[7][6], c0_77 = layer.w0T[7][7]; // ── Hoist w1T[8][8] ─────────────────────────────────────────────────── const float c1_00 = layer.w1T[0][0], c1_01 = layer.w1T[0][1], c1_02 = layer.w1T[0][2], c1_03 = layer.w1T[0][3], c1_04 = layer.w1T[0][4], c1_05 = layer.w1T[0][5], c1_06 = layer.w1T[0][6], c1_07 = layer.w1T[0][7]; const float c1_10 = layer.w1T[1][0], c1_11 = layer.w1T[1][1], c1_12 = layer.w1T[1][2], c1_13 = layer.w1T[1][3], c1_14 = layer.w1T[1][4], c1_15 = layer.w1T[1][5], c1_16 = layer.w1T[1][6], c1_17 = layer.w1T[1][7]; const float c1_20 = layer.w1T[2][0], c1_21 = layer.w1T[2][1], c1_22 = layer.w1T[2][2], c1_23 = layer.w1T[2][3], c1_24 = layer.w1T[2][4], c1_25 = layer.w1T[2][5], c1_26 = layer.w1T[2][6], c1_27 = layer.w1T[2][7]; const float c1_30 = layer.w1T[3][0], c1_31 = layer.w1T[3][1], c1_32 = layer.w1T[3][2], c1_33 = layer.w1T[3][3], c1_34 = layer.w1T[3][4], c1_35 = layer.w1T[3][5], c1_36 = layer.w1T[3][6], c1_37 = layer.w1T[3][7]; const float c1_40 = layer.w1T[4][0], c1_41 = layer.w1T[4][1], c1_42 = layer.w1T[4][2], c1_43 = layer.w1T[4][3], c1_44 = layer.w1T[4][4], c1_45 = layer.w1T[4][5], c1_46 = layer.w1T[4][6], c1_47 = layer.w1T[4][7]; const float c1_50 = layer.w1T[5][0], c1_51 = layer.w1T[5][1], c1_52 = layer.w1T[5][2], c1_53 = layer.w1T[5][3], c1_54 = layer.w1T[5][4], c1_55 = layer.w1T[5][5], c1_56 = layer.w1T[5][6], c1_57 = layer.w1T[5][7]; const float c1_60 = layer.w1T[6][0], c1_61 = layer.w1T[6][1], c1_62 = layer.w1T[6][2], c1_63 = layer.w1T[6][3], c1_64 = layer.w1T[6][4], c1_65 = layer.w1T[6][5], c1_66 = layer.w1T[6][6], c1_67 = layer.w1T[6][7]; const float c1_70 = layer.w1T[7][0], c1_71 = layer.w1T[7][1], c1_72 = layer.w1T[7][2], c1_73 = layer.w1T[7][3], c1_74 = layer.w1T[7][4], c1_75 = layer.w1T[7][5], c1_76 = layer.w1T[7][6], c1_77 = layer.w1T[7][7]; // ── Hoist w2T[8][8] ─────────────────────────────────────────────────── const float c2_00 = layer.w2T[0][0], c2_01 = layer.w2T[0][1], c2_02 = layer.w2T[0][2], c2_03 = layer.w2T[0][3], c2_04 = layer.w2T[0][4], c2_05 = layer.w2T[0][5], c2_06 = layer.w2T[0][6], c2_07 = layer.w2T[0][7]; const float c2_10 = layer.w2T[1][0], c2_11 = layer.w2T[1][1], c2_12 = layer.w2T[1][2], c2_13 = layer.w2T[1][3], c2_14 = layer.w2T[1][4], c2_15 = layer.w2T[1][5], c2_16 = layer.w2T[1][6], c2_17 = layer.w2T[1][7]; const float c2_20 = layer.w2T[2][0], c2_21 = layer.w2T[2][1], c2_22 = layer.w2T[2][2], c2_23 = layer.w2T[2][3], c2_24 = layer.w2T[2][4], c2_25 = layer.w2T[2][5], c2_26 = layer.w2T[2][6], c2_27 = layer.w2T[2][7]; const float c2_30 = layer.w2T[3][0], c2_31 = layer.w2T[3][1], c2_32 = layer.w2T[3][2], c2_33 = layer.w2T[3][3], c2_34 = layer.w2T[3][4], c2_35 = layer.w2T[3][5], c2_36 = layer.w2T[3][6], c2_37 = layer.w2T[3][7]; const float c2_40 = layer.w2T[4][0], c2_41 = layer.w2T[4][1], c2_42 = layer.w2T[4][2], c2_43 = layer.w2T[4][3], c2_44 = layer.w2T[4][4], c2_45 = layer.w2T[4][5], c2_46 = layer.w2T[4][6], c2_47 = layer.w2T[4][7]; const float c2_50 = layer.w2T[5][0], c2_51 = layer.w2T[5][1], c2_52 = layer.w2T[5][2], c2_53 = layer.w2T[5][3], c2_54 = layer.w2T[5][4], c2_55 = layer.w2T[5][5], c2_56 = layer.w2T[5][6], c2_57 = layer.w2T[5][7]; const float c2_60 = layer.w2T[6][0], c2_61 = layer.w2T[6][1], c2_62 = layer.w2T[6][2], c2_63 = layer.w2T[6][3], c2_64 = layer.w2T[6][4], c2_65 = layer.w2T[6][5], c2_66 = layer.w2T[6][6], c2_67 = layer.w2T[6][7]; const float c2_70 = layer.w2T[7][0], c2_71 = layer.w2T[7][1], c2_72 = layer.w2T[7][2], c2_73 = layer.w2T[7][3], c2_74 = layer.w2T[7][4], c2_75 = layer.w2T[7][5], c2_76 = layer.w2T[7][6], c2_77 = layer.w2T[7][7]; // ── Hoist w1x1T[8][8] ───────────────────────────────────────────────── const float cx_00 = layer.w1x1T[0][0], cx_01 = layer.w1x1T[0][1], cx_02 = layer.w1x1T[0][2], cx_03 = layer.w1x1T[0][3], cx_04 = layer.w1x1T[0][4], cx_05 = layer.w1x1T[0][5], cx_06 = layer.w1x1T[0][6], cx_07 = layer.w1x1T[0][7]; const float cx_10 = layer.w1x1T[1][0], cx_11 = layer.w1x1T[1][1], cx_12 = layer.w1x1T[1][2], cx_13 = layer.w1x1T[1][3], cx_14 = layer.w1x1T[1][4], cx_15 = layer.w1x1T[1][5], cx_16 = layer.w1x1T[1][6], cx_17 = layer.w1x1T[1][7]; const float cx_20 = layer.w1x1T[2][0], cx_21 = layer.w1x1T[2][1], cx_22 = layer.w1x1T[2][2], cx_23 = layer.w1x1T[2][3], cx_24 = layer.w1x1T[2][4], cx_25 = layer.w1x1T[2][5], cx_26 = layer.w1x1T[2][6], cx_27 = layer.w1x1T[2][7]; const float cx_30 = layer.w1x1T[3][0], cx_31 = layer.w1x1T[3][1], cx_32 = layer.w1x1T[3][2], cx_33 = layer.w1x1T[3][3], cx_34 = layer.w1x1T[3][4], cx_35 = layer.w1x1T[3][5], cx_36 = layer.w1x1T[3][6], cx_37 = layer.w1x1T[3][7]; const float cx_40 = layer.w1x1T[4][0], cx_41 = layer.w1x1T[4][1], cx_42 = layer.w1x1T[4][2], cx_43 = layer.w1x1T[4][3], cx_44 = layer.w1x1T[4][4], cx_45 = layer.w1x1T[4][5], cx_46 = layer.w1x1T[4][6], cx_47 = layer.w1x1T[4][7]; const float cx_50 = layer.w1x1T[5][0], cx_51 = layer.w1x1T[5][1], cx_52 = layer.w1x1T[5][2], cx_53 = layer.w1x1T[5][3], cx_54 = layer.w1x1T[5][4], cx_55 = layer.w1x1T[5][5], cx_56 = layer.w1x1T[5][6], cx_57 = layer.w1x1T[5][7]; const float cx_60 = layer.w1x1T[6][0], cx_61 = layer.w1x1T[6][1], cx_62 = layer.w1x1T[6][2], cx_63 = layer.w1x1T[6][3], cx_64 = layer.w1x1T[6][4], cx_65 = layer.w1x1T[6][5], cx_66 = layer.w1x1T[6][6], cx_67 = layer.w1x1T[6][7]; const float cx_70 = layer.w1x1T[7][0], cx_71 = layer.w1x1T[7][1], cx_72 = layer.w1x1T[7][2], cx_73 = layer.w1x1T[7][3], cx_74 = layer.w1x1T[7][4], cx_75 = layer.w1x1T[7][5], cx_76 = layer.w1x1T[7][6], cx_77 = layer.w1x1T[7][7]; const float mb0 = layer.conv_b[0], mb1 = layer.conv_b[1], mb2 = layer.conv_b[2], mb3 = layer.conv_b[3], mb4 = layer.conv_b[4], mb5 = layer.conv_b[5], mb6 = layer.conv_b[6], mb7 = layer.conv_b[7]; const float mx0 = layer.mixin_w[0], mx1 = layer.mixin_w[1], mx2 = layer.mixin_w[2], mx3 = layer.mixin_w[3], mx4 = layer.mixin_w[4], mx5 = layer.mixin_w[5], mx6 = layer.mixin_w[6], mx7 = layer.mixin_w[7]; const float bx0 = layer.b1x1[0], bx1 = layer.b1x1[1], bx2 = layer.b1x1[2], bx3 = layer.b1x1[3], bx4 = layer.b1x1[4], bx5 = layer.b1x1[5], bx6 = layer.b1x1[6], bx7 = layer.b1x1[7]; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { // ── Write tap0 into circular state ─────────────────────────────────── float* const cw = layer.state + ptr * 8; const float i0 = ins[n][0], i1 = ins[n][1], i2 = ins[n][2], i3 = ins[n][3], i4 = ins[n][4], i5 = ins[n][5], i6 = ins[n][6], i7 = ins[n][7]; cw[0]=i0; cw[1]=i1; cw[2]=i2; cw[3]=i3; cw[4]=i4; cw[5]=i5; cw[6]=i6; cw[7]=i7; int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 8; const float* __restrict__ s2 = layer.state + sp2 * 8; // ── Conv: bias + W0@i + W1@s1 + W2@s2 + mixin*cond ─────────────────── float t0 = mb0, t1 = mb1, t2 = mb2, t3 = mb3, t4 = mb4, t5 = mb5, t6 = mb6, t7 = mb7; // Tap 0 t0 += i0*c0_00 + i1*c0_10 + i2*c0_20 + i3*c0_30 + i4*c0_40 + i5*c0_50 + i6*c0_60 + i7*c0_70; t1 += i0*c0_01 + i1*c0_11 + i2*c0_21 + i3*c0_31 + i4*c0_41 + i5*c0_51 + i6*c0_61 + i7*c0_71; t2 += i0*c0_02 + i1*c0_12 + i2*c0_22 + i3*c0_32 + i4*c0_42 + i5*c0_52 + i6*c0_62 + i7*c0_72; t3 += i0*c0_03 + i1*c0_13 + i2*c0_23 + i3*c0_33 + i4*c0_43 + i5*c0_53 + i6*c0_63 + i7*c0_73; t4 += i0*c0_04 + i1*c0_14 + i2*c0_24 + i3*c0_34 + i4*c0_44 + i5*c0_54 + i6*c0_64 + i7*c0_74; t5 += i0*c0_05 + i1*c0_15 + i2*c0_25 + i3*c0_35 + i4*c0_45 + i5*c0_55 + i6*c0_65 + i7*c0_75; t6 += i0*c0_06 + i1*c0_16 + i2*c0_26 + i3*c0_36 + i4*c0_46 + i5*c0_56 + i6*c0_66 + i7*c0_76; t7 += i0*c0_07 + i1*c0_17 + i2*c0_27 + i3*c0_37 + i4*c0_47 + i5*c0_57 + i6*c0_67 + i7*c0_77; // Tap 1 const float s1_0=s1[0], s1_1=s1[1], s1_2=s1[2], s1_3=s1[3], s1_4=s1[4], s1_5=s1[5], s1_6=s1[6], s1_7=s1[7]; t0 += s1_0*c1_00 + s1_1*c1_10 + s1_2*c1_20 + s1_3*c1_30 + s1_4*c1_40 + s1_5*c1_50 + s1_6*c1_60 + s1_7*c1_70; t1 += s1_0*c1_01 + s1_1*c1_11 + s1_2*c1_21 + s1_3*c1_31 + s1_4*c1_41 + s1_5*c1_51 + s1_6*c1_61 + s1_7*c1_71; t2 += s1_0*c1_02 + s1_1*c1_12 + s1_2*c1_22 + s1_3*c1_32 + s1_4*c1_42 + s1_5*c1_52 + s1_6*c1_62 + s1_7*c1_72; t3 += s1_0*c1_03 + s1_1*c1_13 + s1_2*c1_23 + s1_3*c1_33 + s1_4*c1_43 + s1_5*c1_53 + s1_6*c1_63 + s1_7*c1_73; t4 += s1_0*c1_04 + s1_1*c1_14 + s1_2*c1_24 + s1_3*c1_34 + s1_4*c1_44 + s1_5*c1_54 + s1_6*c1_64 + s1_7*c1_74; t5 += s1_0*c1_05 + s1_1*c1_15 + s1_2*c1_25 + s1_3*c1_35 + s1_4*c1_45 + s1_5*c1_55 + s1_6*c1_65 + s1_7*c1_75; t6 += s1_0*c1_06 + s1_1*c1_16 + s1_2*c1_26 + s1_3*c1_36 + s1_4*c1_46 + s1_5*c1_56 + s1_6*c1_66 + s1_7*c1_76; t7 += s1_0*c1_07 + s1_1*c1_17 + s1_2*c1_27 + s1_3*c1_37 + s1_4*c1_47 + s1_5*c1_57 + s1_6*c1_67 + s1_7*c1_77; // Tap 2 const float s2_0=s2[0], s2_1=s2[1], s2_2=s2[2], s2_3=s2[3], s2_4=s2[4], s2_5=s2[5], s2_6=s2[6], s2_7=s2[7]; t0 += s2_0*c2_00 + s2_1*c2_10 + s2_2*c2_20 + s2_3*c2_30 + s2_4*c2_40 + s2_5*c2_50 + s2_6*c2_60 + s2_7*c2_70; t1 += s2_0*c2_01 + s2_1*c2_11 + s2_2*c2_21 + s2_3*c2_31 + s2_4*c2_41 + s2_5*c2_51 + s2_6*c2_61 + s2_7*c2_71; t2 += s2_0*c2_02 + s2_1*c2_12 + s2_2*c2_22 + s2_3*c2_32 + s2_4*c2_42 + s2_5*c2_52 + s2_6*c2_62 + s2_7*c2_72; t3 += s2_0*c2_03 + s2_1*c2_13 + s2_2*c2_23 + s2_3*c2_33 + s2_4*c2_43 + s2_5*c2_53 + s2_6*c2_63 + s2_7*c2_73; t4 += s2_0*c2_04 + s2_1*c2_14 + s2_2*c2_24 + s2_3*c2_34 + s2_4*c2_44 + s2_5*c2_54 + s2_6*c2_64 + s2_7*c2_74; t5 += s2_0*c2_05 + s2_1*c2_15 + s2_2*c2_25 + s2_3*c2_35 + s2_4*c2_45 + s2_5*c2_55 + s2_6*c2_65 + s2_7*c2_75; t6 += s2_0*c2_06 + s2_1*c2_16 + s2_2*c2_26 + s2_3*c2_36 + s2_4*c2_46 + s2_5*c2_56 + s2_6*c2_66 + s2_7*c2_76; t7 += s2_0*c2_07 + s2_1*c2_17 + s2_2*c2_27 + s2_3*c2_37 + s2_4*c2_47 + s2_5*c2_57 + s2_6*c2_67 + s2_7*c2_77; // Mixin conditioning const float cn = cond[n]; t0+=mx0*cn; t1+=mx1*cn; t2+=mx2*cn; t3+=mx3*cn; t4+=mx4*cn; t5+=mx5*cn; t6+=mx6*cn; t7+=mx7*cn; // ── Activation ──────────────────────────────────────────────────────── const float a0=nam_tanh(t0), a1=nam_tanh(t1), a2=nam_tanh(t2), a3=nam_tanh(t3), a4=nam_tanh(t4), a5=nam_tanh(t5), a6=nam_tanh(t6), a7=nam_tanh(t7); // ── Accumulate head ─────────────────────────────────────────────────── head[n][0]+=a0; head[n][1]+=a1; head[n][2]+=a2; head[n][3]+=a3; head[n][4]+=a4; head[n][5]+=a5; head[n][6]+=a6; head[n][7]+=a7; // ── 1×1 + residual ──────────────────────────────────────────────────── float o0=i0+bx0, o1=i1+bx1, o2=i2+bx2, o3=i3+bx3, o4=i4+bx4, o5=i5+bx5, o6=i6+bx6, o7=i7+bx7; o0 += a0*cx_00 + a1*cx_10 + a2*cx_20 + a3*cx_30 + a4*cx_40 + a5*cx_50 + a6*cx_60 + a7*cx_70; o1 += a0*cx_01 + a1*cx_11 + a2*cx_21 + a3*cx_31 + a4*cx_41 + a5*cx_51 + a6*cx_61 + a7*cx_71; o2 += a0*cx_02 + a1*cx_12 + a2*cx_22 + a3*cx_32 + a4*cx_42 + a5*cx_52 + a6*cx_62 + a7*cx_72; o3 += a0*cx_03 + a1*cx_13 + a2*cx_23 + a3*cx_33 + a4*cx_43 + a5*cx_53 + a6*cx_63 + a7*cx_73; o4 += a0*cx_04 + a1*cx_14 + a2*cx_24 + a3*cx_34 + a4*cx_44 + a5*cx_54 + a6*cx_64 + a7*cx_74; o5 += a0*cx_05 + a1*cx_15 + a2*cx_25 + a3*cx_35 + a4*cx_45 + a5*cx_55 + a6*cx_65 + a7*cx_75; o6 += a0*cx_06 + a1*cx_16 + a2*cx_26 + a3*cx_36 + a4*cx_46 + a5*cx_56 + a6*cx_66 + a7*cx_76; o7 += a0*cx_07 + a1*cx_17 + a2*cx_27 + a3*cx_37 + a4*cx_47 + a5*cx_57 + a6*cx_67 + a7*cx_77; outs[n][0]=o0; outs[n][1]=o1; outs[n][2]=o2; outs[n][3]=o3; outs[n][4]=o4; outs[n][5]=o5; outs[n][6]=o6; outs[n][7]=o7; } layer.state_ptr = ptr; } }; } // namespace MicroNAMhvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/include/LiteNet.h0000644000000000000000000005032400000000000021503 0ustar00#pragma once #include #include #include namespace MicroNAM { // ───────────────────────────────────────────────────────────────────────────── // Lite WaveNet inference engine // // Lite architecture (from neural-amp-modeler/nam/train/core.py): // LA0: 7 layers × 12-channel, kernel_size=3, dilations=[1,2,4,8,16,32,64] // head_size=6 (12-ch activations projected 12→6 to seed LA1 head) // LA1: 13 layers × 6-channel, kernel_size=3, // dilations=[128,256,512,1,2,4,8,16,32,64,128,256,512] // head_size=1 (6-ch head dot-producted → scalar output) // head_scale=0.02 // // load_weights expects exactly 6554 floats in the NAM file weight order. // forward processes exactly NAM_BLOCK samples per call. // ───────────────────────────────────────────────────────────────────────────── template class LiteNet { public: // ── API ─────────────────────────────────────────────────────────────────── void reset() { reset_impl(); } void load_weights(const float* model_weights) { load_weights_impl(model_weights); } void forward(const float* input, float* output) noexcept { forward_impl(input, output); } // ^ Process exactly NAM_BLOCK samples. // ────────────────────────────────────────────────────────────────────────── private: // ───────────────────────────────────────────────────────────────────────────── // Padé(3,2) tanh — same approximation as NanoNAM / FeatherNAM. // ───────────────────────────────────────────────────────────────────────────── static inline float nam_tanh(float x) noexcept { const float x2 = x * x; const float num = x * (27.0f + x2); const float den = 27.0f + 9.0f * x2; return num / den; } // ── 6-channel layer (used for LA1) ─────────────────────────────────────── struct Layer6 { float w0T[6][6]; // tap0 (current input), [in][out] float w1T[6][6]; // tap1 = state[ptr-D], [in][out] float w2T[6][6]; // tap2 = state[ptr-2D], [in][out] float conv_b[6]; float mixin_w[6]; float w1x1T[6][6]; // 1×1 projection, [in][out] float b1x1[6]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── 12-channel layer (used for LA0) ────────────────────────────────────── struct Layer12 { float w0T[12][12]; // tap0 (current input), [in][out] float w1T[12][12]; // tap1 = state[ptr-D], [in][out] float w2T[12][12]; // tap2 = state[ptr-2D], [in][out] float conv_b[12]; float mixin_w[12]; float w1x1T[12][12]; // 1×1 projection, [in][out] float b1x1[12]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── Layer Array 0: 7 × 12-channel ──────────────────────────────────────── float la0_rechannel_w[12]; // 1→12 input projection float la0_head_wT[12][6]; // 12→6 head projection, [in][out] Layer12 la0[7]; // State: sum((2d+1)*12) for d in {1,2,4,8,16,32,64} // = 36+60+108+204+396+780+1548 = 3132 float la0_state[3132]; // ── Layer Array 1: 13 × 6-channel ──────────────────────────────────────── float la1_rechannel_wT[12][6]; // 12→6 rechannel, [in][out] float la1_head_w[6]; float la1_head_b; Layer6 la1[13]; // State: sum((2d+1)*6) for d in {128,256,512,1,2,4,8,16,32,64,128,256,512} // = 1542+3078+6150+18+30+54+102+198+390+774+1542+3078+6150 = 23106 float la1_state[23106]; float head_scale; // ── Block working buffers ───────────────────────────────────────────────── float la0_buf_a[NAM_BLOCK][12]; float la0_buf_b[NAM_BLOCK][12]; float la0_head [NAM_BLOCK][12]; // LA0 skip-connection accumulator (12-ch) float la1_buf_a[NAM_BLOCK][6]; float la1_buf_b[NAM_BLOCK][6]; float la1_head [NAM_BLOCK][6]; void init_state_ptrs() { static constexpr int la0_d[7] = { 1, 2, 4, 8, 16, 32, 64 }; static constexpr int la1_d[13] = { 128, 256, 512, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; int off = 0; for (int i = 0; i < 7; ++i) { const int d = la0_d[i]; const int ss = (3-1)*d + 1; la0[i].state_size = ss; la0[i].state_ptr = 0; la0[i].neg_dilation = ss - d; la0[i].neg_2dilation = ss - 2*d; la0[i].state = la0_state + off; off += 12 * ss; } off = 0; for (int i = 0; i < 13; ++i) { const int d = la1_d[i]; const int ss = (3-1)*d + 1; la1[i].state_size = ss; la1[i].state_ptr = 0; la1[i].neg_dilation = ss - d; la1[i].neg_2dilation = ss - 2*d; la1[i].state = la1_state + off; off += 6 * ss; } } void reset_impl() { for (int i = 0; i < 3132; ++i) la0_state[i] = 0.f; for (int i = 0; i < 23106; ++i) la1_state[i] = 0.f; for (int i = 0; i < 7; ++i) la0[i].state_ptr = 0; for (int i = 0; i < 13; ++i) la1[i].state_ptr = 0; } // ───────────────────────────────────────────────────────────────────────────── // load_weights — float[6554] // // File weight order: conv[out][in][k], k=0 oldest, k=2 newest. // Split at load time: // file k=2 → w0T[in][out] (tap0 = current input) // file k=1 → w1T[in][out] // file k=0 → w2T[in][out] // // Weight tally: // la0_rechannel_w: 12 // LA0 × 7 layers: 7 × (12*12*3 + 12 + 12 + 12*12 + 12) = 7 × 612 = 4284 // la0_head_wT: 12×6 = 72 // la1_rechannel_wT: 12×6 = 72 // LA1 × 13 layers: 13 × (6*6*3 + 6 + 6 + 6*6 + 6) = 13 × 162 = 2106 // la1_head_w: 6 // la1_head_b: 1 // head_scale: 1 // Total: 6554 // ───────────────────────────────────────────────────────────────────────────── void load_weights_impl(const float* model_weights) { init_state_ptrs(); reset_impl(); const float* w = model_weights; // ── LA0 ────────────────────────────────────────────────────────────────── for (int o = 0; o < 12; ++o) la0_rechannel_w[o] = *w++; for (int l = 0; l < 7; ++l) { for (int o = 0; o < 12; ++o) for (int i = 0; i < 12; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la0[l].w0T[i][o] = val; else if (k == 1) la0[l].w1T[i][o] = val; else la0[l].w2T[i][o] = val; } for (int o = 0; o < 12; ++o) la0[l].conv_b[o] = *w++; for (int o = 0; o < 12; ++o) la0[l].mixin_w[o] = *w++; for (int o = 0; o < 12; ++o) for (int i = 0; i < 12; ++i) la0[l].w1x1T[i][o] = *w++; for (int o = 0; o < 12; ++o) la0[l].b1x1[o] = *w++; } for (int o = 0; o < 6; ++o) for (int i = 0; i < 12; ++i) la0_head_wT[i][o] = *w++; // ── LA1 ────────────────────────────────────────────────────────────────── for (int o = 0; o < 6; ++o) for (int i = 0; i < 12; ++i) la1_rechannel_wT[i][o] = *w++; for (int l = 0; l < 13; ++l) { for (int o = 0; o < 6; ++o) for (int i = 0; i < 6; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la1[l].w0T[i][o] = val; else if (k == 1) la1[l].w1T[i][o] = val; else la1[l].w2T[i][o] = val; } for (int o = 0; o < 6; ++o) la1[l].conv_b[o] = *w++; for (int o = 0; o < 6; ++o) la1[l].mixin_w[o] = *w++; for (int o = 0; o < 6; ++o) for (int i = 0; i < 6; ++i) la1[l].w1x1T[i][o] = *w++; for (int o = 0; o < 6; ++o) la1[l].b1x1[o] = *w++; } for (int o = 0; o < 6; ++o) la1_head_w[o] = *w++; la1_head_b = *w++; head_scale = *w++; assert((int)(w - model_weights) == 6554); } // ───────────────────────────────────────────────────────────────────────────── // forward — process exactly NAM_BLOCK samples // // Structure (layer-outer, sample-inner): // // LA0: // rechannel input[n] → la0_buf_a[n][12] // zero la0_head // for each of 7 layers: // Layer12_process_block(ping, pong, input, la0_head) // swap ping/pong // project la0_head[n][12] → la1_head[n][6] (initial head for LA1) // // LA1: // rechannel la0_buf_b[n][12] → la1_buf_a[n][6] (7 swaps: output in b) // for each of 13 layers: // Layer6_process_block(ping, pong, input, la1_head) // swap ping/pong // // Output: // output[n] = head_scale * (la1_head_b + la1_head[n] @ la1_head_w) // ───────────────────────────────────────────────────────────────────────────── void forward_impl(const float* input, float* output) noexcept { const int N = (int)NAM_BLOCK; // ── LA0 rechannel: 1→12 ─────────────────────────────────────────────── for (int o = 0; o < 12; ++o) { const float r = la0_rechannel_w[o]; for (int n = 0; n < N; ++n) la0_buf_a[n][o] = r * input[n]; } // ── Zero LA0 head accumulator ───────────────────────────────────────── for (int n = 0; n < N; ++n) for (int o = 0; o < 12; ++o) la0_head[n][o] = 0.0f; // ── LA0 layer loop ──────────────────────────────────────────────────── // 7 swaps (odd): final output lands in la0_buf_b { const float (*ping)[12] = la0_buf_a; float (*pong)[12] = la0_buf_b; for (int l = 0; l < 7; ++l) { Layer12_process_block(la0[l], ping, pong, input, la0_head, N); float (*tmp)[12] = pong; pong = (float(*)[12])ping; ping = tmp; } (void)ping; } // ── Project LA0 head 12→6 → initialise la1_head ────────────────────── for (int n = 0; n < N; ++n) { for (int o = 0; o < 6; ++o) { float acc = 0.0f; for (int i = 0; i < 12; ++i) acc += la0_head[n][i] * la0_head_wT[i][o]; la1_head[n][o] = acc; } } // ── LA1 rechannel: 12→6 (source: la0_buf_b, output of LA0) ────────── for (int n = 0; n < N; ++n) { for (int o = 0; o < 6; ++o) { float acc = 0.0f; for (int i = 0; i < 12; ++i) acc += la0_buf_b[n][i] * la1_rechannel_wT[i][o]; la1_buf_a[n][o] = acc; } } // ── LA1 layer loop ──────────────────────────────────────────────────── // 13 swaps (odd): final output lands in la1_buf_b (unused — only head needed) { const float (*ping)[6] = la1_buf_a; float (*pong)[6] = la1_buf_b; for (int l = 0; l < 13; ++l) { Layer6_process_block(la1[l], ping, pong, input, la1_head, N); float (*tmp)[6] = pong; pong = (float(*)[6])ping; ping = tmp; } } // ── Output: head → scalar ───────────────────────────────────────────── { const float b = la1_head_b; const float sc = head_scale; for (int n = 0; n < N; ++n) { float acc = b; for (int o = 0; o < 6; ++o) acc += la1_head[n][o] * la1_head_w[o]; output[n] = sc * acc; } } } // ───────────────────────────────────────────────────────────────────────────── // Layer6_process_block (6-channel; used for LA1) // // For each sample n: // 1. Write ins[n] into circular state buffer. // 2. Read s1 = state[ptr-D], s2 = state[ptr-2D]. // 3. Conv: t[o] = conv_b[o] + W0@ins[n] + W1@s1 + W2@s2 + mixin[o]*cond[n] // 4. a[o] = tanh(t[o]) // 5. head[n][o] += a[o] // 6. outs[n][o] = ins[n][o] + b1x1[o] + W1x1 @ a // ───────────────────────────────────────────────────────────────────────────── void Layer6_process_block(Layer6& layer, const float ins[][6], float outs[][6], const float* cond, float head[][6], int N) noexcept { const float (*w0T)[6] = layer.w0T; const float (*w1T)[6] = layer.w1T; const float (*w2T)[6] = layer.w2T; const float (*w1x1T)[6] = layer.w1x1T; const float* conv_b = layer.conv_b; const float* mixin_w = layer.mixin_w; const float* b1x1 = layer.b1x1; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { // ── Write tap0 into circular state ─────────────────────────────── float* const cw = layer.state + ptr * 6; for (int c = 0; c < 6; ++c) cw[c] = ins[n][c]; // ── Tap positions ───────────────────────────────────────────────── int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 6; const float* __restrict__ s2 = layer.state + sp2 * 6; // ── Conv: bias + mixin + W0@i + W1@s1 + W2@s2 ──────────────────── float t[6]; const float cn = cond[n]; for (int o = 0; o < 6; ++o) t[o] = conv_b[o] + mixin_w[o] * cn; for (int i = 0; i < 6; ++i) { const float iv = ins[n][i]; const float s1v = s1[i]; const float s2v = s2[i]; for (int o = 0; o < 6; ++o) t[o] += iv*w0T[i][o] + s1v*w1T[i][o] + s2v*w2T[i][o]; } // ── Activation + head accumulation ─────────────────────────────── float a[6]; for (int o = 0; o < 6; ++o) { a[o] = nam_tanh(t[o]); head[n][o] += a[o]; } // ── 1×1 + residual ──────────────────────────────────────────────── float out[6]; for (int o = 0; o < 6; ++o) out[o] = ins[n][o] + b1x1[o]; for (int i = 0; i < 6; ++i) { const float av = a[i]; for (int o = 0; o < 6; ++o) out[o] += av * w1x1T[i][o]; } for (int o = 0; o < 6; ++o) outs[n][o] = out[o]; } layer.state_ptr = ptr; } // ───────────────────────────────────────────────────────────────────────────── // Layer12_process_block (12-channel; used for LA0) // // Identical structure to Layer6_process_block, scaled to 12 channels. // ───────────────────────────────────────────────────────────────────────────── void Layer12_process_block(Layer12& layer, const float ins[][12], float outs[][12], const float* cond, float head[][12], int N) noexcept { const float (*w0T)[12] = layer.w0T; const float (*w1T)[12] = layer.w1T; const float (*w2T)[12] = layer.w2T; const float (*w1x1T)[12] = layer.w1x1T; const float* conv_b = layer.conv_b; const float* mixin_w = layer.mixin_w; const float* b1x1 = layer.b1x1; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { // ── Write tap0 into circular state ─────────────────────────────── float* const cw = layer.state + ptr * 12; for (int c = 0; c < 12; ++c) cw[c] = ins[n][c]; // ── Tap positions ───────────────────────────────────────────────── int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 12; const float* __restrict__ s2 = layer.state + sp2 * 12; // ── Conv: bias + mixin + W0@i + W1@s1 + W2@s2 ──────────────────── float t[12]; const float cn = cond[n]; for (int o = 0; o < 12; ++o) t[o] = conv_b[o] + mixin_w[o] * cn; for (int i = 0; i < 12; ++i) { const float iv = ins[n][i]; const float s1v = s1[i]; const float s2v = s2[i]; for (int o = 0; o < 12; ++o) t[o] += iv*w0T[i][o] + s1v*w1T[i][o] + s2v*w2T[i][o]; } // ── Activation + head accumulation ─────────────────────────────── float a[12]; for (int o = 0; o < 12; ++o) { a[o] = nam_tanh(t[o]); head[n][o] += a[o]; } // ── 1×1 + residual ──────────────────────────────────────────────── float out[12]; for (int o = 0; o < 12; ++o) out[o] = ins[n][o] + b1x1[o]; for (int i = 0; i < 12; ++i) { const float av = a[i]; for (int o = 0; o < 12; ++o) out[o] += av * w1x1T[i][o]; } for (int o = 0; o < 12; ++o) outs[n][o] = out[o]; } layer.state_ptr = ptr; } }; } // namespace MicroNAM hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/include/NanoNet.h0000644000000000000000000005641100000000000021504 0ustar00#pragma once #include #include #include namespace MicroNAM { template class NanoNet { public: // ── API ─────────────────────────────────────────────────────────────── void reset() { reset_impl(); } void load_weights(const float* model_weights) { load_weights_impl(model_weights); } void forward(const float* input, float* output) noexcept { forward_impl(input, output); } // ^ Process exactly NAM_BLOCK samples. // ────────────────────────────────────────────────────────────────────── private: // ───────────────────────────────────────────────────────────────────────────── // Padé(3,2) tanh — accurate to ~2.4% over [-3,3], exact outside via clamp. // Plain division: single VDIV per call, no FP↔INT domain crossing stall. // Four independent calls pipeline: VDIVs issue at t=0,7,14,21 on M7. // ───────────────────────────────────────────────────────────────────────────── static inline float nam_tanh(float x) noexcept { const float x2 = x * x; const float num = x * (27.0f + x2); const float den = 27.0f + 9.0f * x2; return num / den; } // ── 2-channel layer ─────────────────────────────────────────────────── struct Layer2 { float w0T[2][2]; float w1T[2][2]; float w2T[2][2]; float conv_b[2]; float mixin_w[2]; float w1x1T[2][2]; float b1x1[2]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── 4-channel layer ─────────────────────────────────────────────────── struct Layer4 { float w0T[4][4]; // tap0 (= current input), [in][out] float w1T[4][4]; // tap1 = state[ptr-D], [in][out] float w2T[4][4]; // tap2 = state[ptr-2D], [in][out] float conv_b[4]; float mixin_w[4]; float w1x1T[4][4]; // 1×1 projection, [in][out] float b1x1[4]; float* state; int state_size; int state_ptr; int neg_dilation; // = state_size - dilation int neg_2dilation; // = state_size - 2*dilation }; // ── Layer Array 0: 7 × 4-channel ────────────────────────────────────── float la0_rechannel_w[4]; // 1→4 input projection float la0_head_wT[4][2]; // 4→2 head projection, [in][out] Layer4 la0[7]; float la0_state[1044]; // sum((2d+1)*4) for d in {1,2,4,8,16,32,64} // ── Layer Array 1: 13 × 2-channel ───────────────────────────────────── float la1_rechannel_wT[4][2]; // 4→2 rechannel, [in][out] float la1_head_w[2]; float la1_head_b; Layer2 la1[13]; float la1_state[7702]; // sum((2d+1)*2) for d in {128,256,512,1,2,4,8,16,32,64,128,256,512} float head_scale; // ── Block working buffers ───────────────────────────────────────────── // Ping-pong layer I/O + head accumulators. Re-used every call. // Total: (48*4 + 48*4 + 48*4)*4 + (48*2 + 48*2 + 48*2)*4 = 768*3 + 384*3 = 3456 bytes float la0_buf_a[NAM_BLOCK][4]; // ping: LA0 layer input float la0_buf_b[NAM_BLOCK][4]; // pong: LA0 layer output float la0_head [NAM_BLOCK][4]; // LA0 skip-connection accumulator float la1_buf_a[NAM_BLOCK][2]; float la1_buf_b[NAM_BLOCK][2]; float la1_head [NAM_BLOCK][2]; void init_state_ptrs() { static constexpr int la0_d[7] = { 1, 2, 4, 8, 16, 32, 64 }; static constexpr int la1_d[13] = { 128, 256, 512, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; int off = 0; for (int i = 0; i < 7; ++i) { const int d = la0_d[i]; const int ss = (3-1)*d + 1; la0[i].state_size = ss; la0[i].state_ptr = 0; la0[i].neg_dilation = ss - d; la0[i].neg_2dilation = ss - 2*d; la0[i].state = la0_state + off; off += 4 * ss; } off = 0; for (int i = 0; i < 13; ++i) { const int d = la1_d[i]; const int ss = (3-1)*d + 1; la1[i].state_size = ss; la1[i].state_ptr = 0; la1[i].neg_dilation = ss - d; la1[i].neg_2dilation = ss - 2*d; la1[i].state = la1_state + off; off += 2 * ss; } } void reset_impl() { // Zero state buffers using assignment (not memcpy — 4× faster on Daisy) for (int i = 0; i < 1044; ++i) la0_state[i] = 0.f; for (int i = 0; i < 7702; ++i) la1_state[i] = 0.f; for (int i = 0; i < 7; ++i) la0[i].state_ptr = 0; for (int i = 0; i < 13; ++i) la1[i].state_ptr = 0; } // ───────────────────────────────────────────────────────────────────────────── // load_weights — float[842] // // File weight order: conv[out][in][k], k=0 oldest, k=2 newest. // Split at load time: // file k=2 → w0T[in][out] (tap0 = current input) // file k=1 → w1T[in][out] // file k=0 → w2T[in][out] // ───────────────────────────────────────────────────────────────────────────── void load_weights_impl(const float* model_weights) { init_state_ptrs(); reset_impl(); const float* w = model_weights; // ── LA0 ────────────────────────────────────────────────────────────── for (int o = 0; o < 4; ++o) la0_rechannel_w[o] = *w++; for (int l = 0; l < 7; ++l) { for (int o = 0; o < 4; ++o) for (int i = 0; i < 4; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la0[l].w0T[i][o] = val; else if (k == 1) la0[l].w1T[i][o] = val; else la0[l].w2T[i][o] = val; } for (int o = 0; o < 4; ++o) la0[l].conv_b[o] = *w++; for (int o = 0; o < 4; ++o) la0[l].mixin_w[o] = *w++; for (int o = 0; o < 4; ++o) for (int i = 0; i < 4; ++i) la0[l].w1x1T[i][o] = *w++; for (int o = 0; o < 4; ++o) la0[l].b1x1[o] = *w++; } for (int o = 0; o < 2; ++o) for (int i = 0; i < 4; ++i) la0_head_wT[i][o] = *w++; // ── LA1 ────────────────────────────────────────────────────────────── for (int o = 0; o < 2; ++o) for (int i = 0; i < 4; ++i) la1_rechannel_wT[i][o] = *w++; for (int l = 0; l < 13; ++l) { for (int o = 0; o < 2; ++o) for (int i = 0; i < 2; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la1[l].w0T[i][o] = val; else if (k == 1) la1[l].w1T[i][o] = val; else la1[l].w2T[i][o] = val; } for (int o = 0; o < 2; ++o) la1[l].conv_b[o] = *w++; for (int o = 0; o < 2; ++o) la1[l].mixin_w[o] = *w++; for (int o = 0; o < 2; ++o) for (int i = 0; i < 2; ++i) la1[l].w1x1T[i][o] = *w++; for (int o = 0; o < 2; ++o) la1[l].b1x1[o] = *w++; } la1_head_w[0] = *w++; la1_head_w[1] = *w++; la1_head_b = *w++; head_scale = *w++; assert((int)(w - model_weights) == 842); } // ───────────────────────────────────────────────────────────────────────────── // forward — process exactly NAM_BLOCK samples // // Structure (layer-outer, sample-inner): // // LA0: // rechannel input[n] → la0_buf_a[n][4] // zero la0_head // for each of 7 layers: // process_block(ping, pong, input, la0_head) // swap ping/pong pointers // project la0_head[n][4] → la1_head[n][2] (initial g0,g1 for LA1) // // LA1: // rechannel la0_buf_last[n][4] → la1_buf_a[n][2] // for each of 13 layers: // process_block(ping, pong, input, la1_head) // swap ping/pong // // Output: // output[n] = head_scale * (la1_head_b + la1_head[n] @ la1_head_w) // ───────────────────────────────────────────────────────────────────────────── void forward_impl(const float* input, float* output) noexcept { const int N = NAM_BLOCK; // ── LA0 rechannel: 1→4 ──────────────────────────────────────────────── { const float r0 = la0_rechannel_w[0], r1 = la0_rechannel_w[1], r2 = la0_rechannel_w[2], r3 = la0_rechannel_w[3]; for (int n = 0; n < N; ++n) { const float x = input[n]; la0_buf_a[n][0] = r0 * x; la0_buf_a[n][1] = r1 * x; la0_buf_a[n][2] = r2 * x; la0_buf_a[n][3] = r3 * x; } } // ── Zero head accumulators ──────────────────────────────────────────── for (int n = 0; n < N; ++n) { la0_head[n][0] = la0_head[n][1] = la0_head[n][2] = la0_head[n][3] = 0.0f; } // ── LA0 layer loop ──────────────────────────────────────────────────── // ping = la0_buf_a, pong = la0_buf_b; swap after each layer. { const float (*ping)[4] = la0_buf_a; float (*pong)[4] = la0_buf_b; for (int l = 0; l < 7; ++l) { Layer4_process_block(la0[l], ping, pong, input, la0_head, N); // Swap ping/pong via index (avoids const-cast issues) float (*tmp)[4] = pong; pong = (float(*)[4])ping; ping = tmp; } // After 7 swaps (odd): last output is in ping (= la0_buf_b) (void)ping; } // 7 layers, 7 swaps: output alternates a→b→a→b→a→b→a→b // After layer 0 writes to b, layer 1 writes to a, ..., layer 6 writes to b. // la0_buf_b now contains the final LA0 output (layer 6 outs) // ── Project LA0 head 4→2 → initialise la1_head ─────────────────────── { const float h00 = la0_head_wT[0][0], h01 = la0_head_wT[0][1]; const float h10 = la0_head_wT[1][0], h11 = la0_head_wT[1][1]; const float h20 = la0_head_wT[2][0], h21 = la0_head_wT[2][1]; const float h30 = la0_head_wT[3][0], h31 = la0_head_wT[3][1]; for (int n = 0; n < N; ++n) { const float h0 = la0_head[n][0], h1 = la0_head[n][1], h2 = la0_head[n][2], h3 = la0_head[n][3]; la1_head[n][0] = h0*h00 + h1*h10 + h2*h20 + h3*h30; la1_head[n][1] = h0*h01 + h1*h11 + h2*h21 + h3*h31; } } // ── LA1 rechannel: 4→2 ─────────────────────────────────────────────── { const float r00 = la1_rechannel_wT[0][0], r01 = la1_rechannel_wT[0][1]; const float r10 = la1_rechannel_wT[1][0], r11 = la1_rechannel_wT[1][1]; const float r20 = la1_rechannel_wT[2][0], r21 = la1_rechannel_wT[2][1]; const float r30 = la1_rechannel_wT[3][0], r31 = la1_rechannel_wT[3][1]; for (int n = 0; n < N; ++n) { const float* const src = la0_buf_b[n]; la1_buf_a[n][0] = src[0]*r00 + src[1]*r10 + src[2]*r20 + src[3]*r30; la1_buf_a[n][1] = src[0]*r01 + src[1]*r11 + src[2]*r21 + src[3]*r31; } } // ── LA1 layer loop ──────────────────────────────────────────────────── { const float (*ping)[2] = la1_buf_a; float (*pong)[2] = la1_buf_b; for (int l = 0; l < 13; ++l) { Layer2_process_block(la1[l], ping, pong, input, la1_head, N); float (*tmp)[2] = pong; pong = (float(*)[2])ping; ping = tmp; } // 13 swaps (odd) → last output in la1_buf_b } // la1_head now contains final accumulated head across all LA1 layers // ── Output: head → scalar ───────────────────────────────────────────── { const float w0 = la1_head_w[0], w1 = la1_head_w[1]; const float b = la1_head_b; const float sc = head_scale; for (int n = 0; n < N; ++n) { output[n] = sc * (b + la1_head[n][0]*w0 + la1_head[n][1]*w1); } } } // ───────────────────────────────────────────────────────────────────────────── // Layer2::process_block // ───────────────────────────────────────────────────────────────────────────── void Layer2_process_block(Layer2& layer, const float ins[][2], float outs[][2], const float* cond, float head[][2], int N) noexcept { // Hoist weights — 2×2 matrices, 4 floats each const float c0_00 = layer.w0T[0][0], c0_01 = layer.w0T[0][1]; const float c0_10 = layer.w0T[1][0], c0_11 = layer.w0T[1][1]; const float c1_00 = layer.w1T[0][0], c1_01 = layer.w1T[0][1]; const float c1_10 = layer.w1T[1][0], c1_11 = layer.w1T[1][1]; const float c2_00 = layer.w2T[0][0], c2_01 = layer.w2T[0][1]; const float c2_10 = layer.w2T[1][0], c2_11 = layer.w2T[1][1]; const float cx_00 = layer.w1x1T[0][0], cx_01 = layer.w1x1T[0][1]; const float cx_10 = layer.w1x1T[1][0], cx_11 = layer.w1x1T[1][1]; const float mb0 = layer.conv_b[0], mb1 = layer.conv_b[1]; const float mx0 = layer.mixin_w[0], mx1 = layer.mixin_w[1]; const float bx0 = layer.b1x1[0], bx1 = layer.b1x1[1]; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { float* const cw = layer.state + ptr * 2; const float i0 = ins[n][0], i1 = ins[n][1]; cw[0] = i0; cw[1] = i1; int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 2; const float* __restrict__ s2 = layer.state + sp2 * 2; float t0 = mb0, t1 = mb1; t0 += i0*c0_00 + i1*c0_10; t1 += i0*c0_01 + i1*c0_11; const float s1_0 = s1[0], s1_1 = s1[1]; t0 += s1_0*c1_00 + s1_1*c1_10; t1 += s1_0*c1_01 + s1_1*c1_11; const float s2_0 = s2[0], s2_1 = s2[1]; t0 += s2_0*c2_00 + s2_1*c2_10; t1 += s2_0*c2_01 + s2_1*c2_11; const float cn = cond[n]; t0 += mx0 * cn; t1 += mx1 * cn; const float a0 = nam_tanh(t0), a1 = nam_tanh(t1); head[n][0] += a0; head[n][1] += a1; outs[n][0] = i0 + bx0 + a0*cx_00 + a1*cx_10; outs[n][1] = i1 + bx1 + a0*cx_01 + a1*cx_11; } layer.state_ptr = ptr; } // ───────────────────────────────────────────────────────────────────────────── // Layer4::process_block // // Processes N frames through a single 4-channel WaveNet layer. // Loop structure: sample-inner over N frames. // // For each sample n: // 1. Write ins[n] into circular state buffer (s0 == ins, no extra read). // 2. Read s1 = state[ptr-D], s2 = state[ptr-2D]. // 3. Conv: tmp[4] = conv_b + W0@ins[n] + W1@s1 + W2@s2 + mixin*cond[n] // Weights declared as local const → compiler register-allocates all 48 floats. // With NAM_BLOCK=48, the inner loop reuses register-resident weights. // 4. Activation: tanh(tmp[k]) → a[k] // 5. Accumulate head: head[n][k] += a[k] // 6. 1×1 + residual: outs[n] = ins[n] + b1x1 + W1x1 @ a // ───────────────────────────────────────────────────────────────────────────── void Layer4_process_block(Layer4& layer, const float ins[][4], float outs[][4], const float* cond, float head[][4], int N) noexcept { // Hoist all weight matrices as local const. // GCC -O2 -ffast-math: loop-invariant, register-allocated across the N loop. const float c0_00 = layer.w0T[0][0], c0_01 = layer.w0T[0][1], c0_02 = layer.w0T[0][2], c0_03 = layer.w0T[0][3]; const float c0_10 = layer.w0T[1][0], c0_11 = layer.w0T[1][1], c0_12 = layer.w0T[1][2], c0_13 = layer.w0T[1][3]; const float c0_20 = layer.w0T[2][0], c0_21 = layer.w0T[2][1], c0_22 = layer.w0T[2][2], c0_23 = layer.w0T[2][3]; const float c0_30 = layer.w0T[3][0], c0_31 = layer.w0T[3][1], c0_32 = layer.w0T[3][2], c0_33 = layer.w0T[3][3]; const float c1_00 = layer.w1T[0][0], c1_01 = layer.w1T[0][1], c1_02 = layer.w1T[0][2], c1_03 = layer.w1T[0][3]; const float c1_10 = layer.w1T[1][0], c1_11 = layer.w1T[1][1], c1_12 = layer.w1T[1][2], c1_13 = layer.w1T[1][3]; const float c1_20 = layer.w1T[2][0], c1_21 = layer.w1T[2][1], c1_22 = layer.w1T[2][2], c1_23 = layer.w1T[2][3]; const float c1_30 = layer.w1T[3][0], c1_31 = layer.w1T[3][1], c1_32 = layer.w1T[3][2], c1_33 = layer.w1T[3][3]; const float c2_00 = layer.w2T[0][0], c2_01 = layer.w2T[0][1], c2_02 = layer.w2T[0][2], c2_03 = layer.w2T[0][3]; const float c2_10 = layer.w2T[1][0], c2_11 = layer.w2T[1][1], c2_12 = layer.w2T[1][2], c2_13 = layer.w2T[1][3]; const float c2_20 = layer.w2T[2][0], c2_21 = layer.w2T[2][1], c2_22 = layer.w2T[2][2], c2_23 = layer.w2T[2][3]; const float c2_30 = layer.w2T[3][0], c2_31 = layer.w2T[3][1], c2_32 = layer.w2T[3][2], c2_33 = layer.w2T[3][3]; const float cx_00 = layer.w1x1T[0][0], cx_01 = layer.w1x1T[0][1], cx_02 = layer.w1x1T[0][2], cx_03 = layer.w1x1T[0][3]; const float cx_10 = layer.w1x1T[1][0], cx_11 = layer.w1x1T[1][1], cx_12 = layer.w1x1T[1][2], cx_13 = layer.w1x1T[1][3]; const float cx_20 = layer.w1x1T[2][0], cx_21 = layer.w1x1T[2][1], cx_22 = layer.w1x1T[2][2], cx_23 = layer.w1x1T[2][3]; const float cx_30 = layer.w1x1T[3][0], cx_31 = layer.w1x1T[3][1], cx_32 = layer.w1x1T[3][2], cx_33 = layer.w1x1T[3][3]; const float mb0 = layer.conv_b[0], mb1 = layer.conv_b[1], mb2 = layer.conv_b[2], mb3 = layer.conv_b[3]; const float mx0 = layer.mixin_w[0], mx1 = layer.mixin_w[1], mx2 = layer.mixin_w[2], mx3 = layer.mixin_w[3]; const float bx0 = layer.b1x1[0], bx1 = layer.b1x1[1], bx2 = layer.b1x1[2], bx3 = layer.b1x1[3]; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { // ── Write tap0 = ins[n] into circular state ─────────────────────── float* const cw = layer.state + ptr * 4; const float i0 = ins[n][0], i1 = ins[n][1], i2 = ins[n][2], i3 = ins[n][3]; cw[0] = i0; cw[1] = i1; cw[2] = i2; cw[3] = i3; // ── Tap positions ───────────────────────────────────────────────── int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 4; const float* __restrict__ s2 = layer.state + sp2 * 4; // ── Conv: bias + W0@i + W1@s1 + W2@s2 + mixin*cond ─────────────── // 4 independent accumulators — no FPU dependency stalls. float t0 = mb0, t1 = mb1, t2 = mb2, t3 = mb3; // Tap 0 (register-resident weights, no memory access) t0 += i0*c0_00 + i1*c0_10 + i2*c0_20 + i3*c0_30; t1 += i0*c0_01 + i1*c0_11 + i2*c0_21 + i3*c0_31; t2 += i0*c0_02 + i1*c0_12 + i2*c0_22 + i3*c0_32; t3 += i0*c0_03 + i1*c0_13 + i2*c0_23 + i3*c0_33; // Tap 1 const float s1_0 = s1[0], s1_1 = s1[1], s1_2 = s1[2], s1_3 = s1[3]; t0 += s1_0*c1_00 + s1_1*c1_10 + s1_2*c1_20 + s1_3*c1_30; t1 += s1_0*c1_01 + s1_1*c1_11 + s1_2*c1_21 + s1_3*c1_31; t2 += s1_0*c1_02 + s1_1*c1_12 + s1_2*c1_22 + s1_3*c1_32; t3 += s1_0*c1_03 + s1_1*c1_13 + s1_2*c1_23 + s1_3*c1_33; // Tap 2 const float s2_0 = s2[0], s2_1 = s2[1], s2_2 = s2[2], s2_3 = s2[3]; t0 += s2_0*c2_00 + s2_1*c2_10 + s2_2*c2_20 + s2_3*c2_30; t1 += s2_0*c2_01 + s2_1*c2_11 + s2_2*c2_21 + s2_3*c2_31; t2 += s2_0*c2_02 + s2_1*c2_12 + s2_2*c2_22 + s2_3*c2_32; t3 += s2_0*c2_03 + s2_1*c2_13 + s2_2*c2_23 + s2_3*c2_33; // Mixin conditioning const float cn = cond[n]; t0 += mx0 * cn; t1 += mx1 * cn; t2 += mx2 * cn; t3 += mx3 * cn; // ── Activation (4 independent VDIVs, pipeline at throughput=7) ──── const float a0 = nam_tanh(t0), a1 = nam_tanh(t1), a2 = nam_tanh(t2), a3 = nam_tanh(t3); // ── Accumulate head ─────────────────────────────────────────────── head[n][0] += a0; head[n][1] += a1; head[n][2] += a2; head[n][3] += a3; // ── 1×1 + residual ──────────────────────────────────────────────── float o0 = i0 + bx0, o1 = i1 + bx1, o2 = i2 + bx2, o3 = i3 + bx3; o0 += a0*cx_00 + a1*cx_10 + a2*cx_20 + a3*cx_30; o1 += a0*cx_01 + a1*cx_11 + a2*cx_21 + a3*cx_31; o2 += a0*cx_02 + a1*cx_12 + a2*cx_22 + a3*cx_32; o3 += a0*cx_03 + a1*cx_13 + a2*cx_23 + a3*cx_33; outs[n][0] = o0; outs[n][1] = o1; outs[n][2] = o2; outs[n][3] = o3; } layer.state_ptr = ptr; } }; } // namespace MicroNAMhvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/include/StandardNet.h0000644000000000000000000005073700000000000022356 0ustar00#pragma once #include #include #include namespace MicroNAM { // ───────────────────────────────────────────────────────────────────────────── // Standard WaveNet inference engine // // Standard architecture (from neural-amp-modeler/nam/train/core.py): // LA0: 10 layers × 16-channel, kernel_size=3, // dilations=[1,2,4,8,16,32,64,128,256,512] // head_size=8 (16-ch activations projected 16→8 to seed LA1 head) // LA1: 10 layers × 8-channel, kernel_size=3, // dilations=[1,2,4,8,16,32,64,128,256,512] // head_size=1 (8-ch head dot-producted → scalar output) // head_scale=0.02 // // load_weights expects exactly 13802 floats in the NAM file weight order. // forward processes exactly NAM_BLOCK samples per call. // ───────────────────────────────────────────────────────────────────────────── template class StandardNet { public: // ── API ─────────────────────────────────────────────────────────────────── void reset() { reset_impl(); } void load_weights(const float* model_weights) { load_weights_impl(model_weights); } void forward(const float* input, float* output) noexcept { forward_impl(input, output); } // ^ Process exactly NAM_BLOCK samples. // ────────────────────────────────────────────────────────────────────────── private: // ───────────────────────────────────────────────────────────────────────────── // Padé(3,2) tanh — same approximation as NanoNAM / FeatherNAM. // ───────────────────────────────────────────────────────────────────────────── static inline float nam_tanh(float x) noexcept { const float x2 = x * x; const float num = x * (27.0f + x2); const float den = 27.0f + 9.0f * x2; return num / den; } // ── 8-channel layer (used for LA1) ─────────────────────────────────────── struct Layer8 { float w0T[8][8]; // tap0 (current input), [in][out] float w1T[8][8]; // tap1 = state[ptr-D], [in][out] float w2T[8][8]; // tap2 = state[ptr-2D], [in][out] float conv_b[8]; float mixin_w[8]; float w1x1T[8][8]; // 1×1 projection, [in][out] float b1x1[8]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── 16-channel layer (used for LA0) ────────────────────────────────────── struct Layer16 { float w0T[16][16]; // tap0 (current input), [in][out] float w1T[16][16]; // tap1 = state[ptr-D], [in][out] float w2T[16][16]; // tap2 = state[ptr-2D], [in][out] float conv_b[16]; float mixin_w[16]; float w1x1T[16][16]; // 1×1 projection, [in][out] float b1x1[16]; float* state; int state_size; int state_ptr; int neg_dilation; int neg_2dilation; }; // ── Layer Array 0: 10 × 16-channel ─────────────────────────────────────── float la0_rechannel_w[16]; // 1→16 input projection float la0_head_wT[16][8]; // 16→8 head projection, [in][out] Layer16 la0[10]; // State: sum((2d+1)*16) for d in {1,2,4,8,16,32,64,128,256,512} // sum(2d+1) = 3+5+9+17+33+65+129+257+513+1025 = 2056 // 2056 * 16 = 32896 float la0_state[32896]; // ── Layer Array 1: 10 × 8-channel ──────────────────────────────────────── float la1_rechannel_wT[16][8]; // 16→8 rechannel, [in][out] float la1_head_w[8]; float la1_head_b; Layer8 la1[10]; // State: sum((2d+1)*8) for d in {1,2,4,8,16,32,64,128,256,512} // 2056 * 8 = 16448 float la1_state[16448]; float head_scale; // ── Block working buffers ───────────────────────────────────────────────── float la0_buf_a[NAM_BLOCK][16]; float la0_buf_b[NAM_BLOCK][16]; float la0_head [NAM_BLOCK][16]; // LA0 skip-connection accumulator (16-ch) float la1_buf_a[NAM_BLOCK][8]; float la1_buf_b[NAM_BLOCK][8]; float la1_head [NAM_BLOCK][8]; void init_state_ptrs() { static constexpr int la0_d[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; static constexpr int la1_d[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; int off = 0; for (int i = 0; i < 10; ++i) { const int d = la0_d[i]; const int ss = (3-1)*d + 1; la0[i].state_size = ss; la0[i].state_ptr = 0; la0[i].neg_dilation = ss - d; la0[i].neg_2dilation = ss - 2*d; la0[i].state = la0_state + off; off += 16 * ss; } off = 0; for (int i = 0; i < 10; ++i) { const int d = la1_d[i]; const int ss = (3-1)*d + 1; la1[i].state_size = ss; la1[i].state_ptr = 0; la1[i].neg_dilation = ss - d; la1[i].neg_2dilation = ss - 2*d; la1[i].state = la1_state + off; off += 8 * ss; } } void reset_impl() { for (int i = 0; i < 32896; ++i) la0_state[i] = 0.f; for (int i = 0; i < 16448; ++i) la1_state[i] = 0.f; for (int i = 0; i < 10; ++i) la0[i].state_ptr = 0; for (int i = 0; i < 10; ++i) la1[i].state_ptr = 0; } // ───────────────────────────────────────────────────────────────────────────── // load_weights — float[13802] // // File weight order: conv[out][in][k], k=0 oldest, k=2 newest. // Split at load time: // file k=2 → w0T[in][out] (tap0 = current input) // file k=1 → w1T[in][out] // file k=0 → w2T[in][out] // // Weight tally: // la0_rechannel_w: 16 // LA0 × 10 layers: 10 × (16*16*3 + 16 + 16 + 16*16 + 16) = 10 × 1072 = 10720 // la0_head_wT: 16×8 = 128 // la1_rechannel_wT: 16×8 = 128 // LA1 × 10 layers: 10 × (8*8*3 + 8 + 8 + 8*8 + 8) = 10 × 280 = 2800 // la1_head_w: 8 // la1_head_b: 1 // head_scale: 1 // Total: 13802 // ───────────────────────────────────────────────────────────────────────────── void load_weights_impl(const float* model_weights) { init_state_ptrs(); reset_impl(); const float* w = model_weights; // ── LA0 ────────────────────────────────────────────────────────────────── for (int o = 0; o < 16; ++o) la0_rechannel_w[o] = *w++; for (int l = 0; l < 10; ++l) { for (int o = 0; o < 16; ++o) for (int i = 0; i < 16; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la0[l].w0T[i][o] = val; else if (k == 1) la0[l].w1T[i][o] = val; else la0[l].w2T[i][o] = val; } for (int o = 0; o < 16; ++o) la0[l].conv_b[o] = *w++; for (int o = 0; o < 16; ++o) la0[l].mixin_w[o] = *w++; for (int o = 0; o < 16; ++o) for (int i = 0; i < 16; ++i) la0[l].w1x1T[i][o] = *w++; for (int o = 0; o < 16; ++o) la0[l].b1x1[o] = *w++; } for (int o = 0; o < 8; ++o) for (int i = 0; i < 16; ++i) la0_head_wT[i][o] = *w++; // ── LA1 ────────────────────────────────────────────────────────────────── for (int o = 0; o < 8; ++o) for (int i = 0; i < 16; ++i) la1_rechannel_wT[i][o] = *w++; for (int l = 0; l < 10; ++l) { for (int o = 0; o < 8; ++o) for (int i = 0; i < 8; ++i) for (int k = 0; k < 3; ++k) { const float val = *w++; if (k == 2) la1[l].w0T[i][o] = val; else if (k == 1) la1[l].w1T[i][o] = val; else la1[l].w2T[i][o] = val; } for (int o = 0; o < 8; ++o) la1[l].conv_b[o] = *w++; for (int o = 0; o < 8; ++o) la1[l].mixin_w[o] = *w++; for (int o = 0; o < 8; ++o) for (int i = 0; i < 8; ++i) la1[l].w1x1T[i][o] = *w++; for (int o = 0; o < 8; ++o) la1[l].b1x1[o] = *w++; } for (int o = 0; o < 8; ++o) la1_head_w[o] = *w++; la1_head_b = *w++; head_scale = *w++; assert((int)(w - model_weights) == 13802); } // ───────────────────────────────────────────────────────────────────────────── // forward — process exactly NAM_BLOCK samples // // Structure (layer-outer, sample-inner): // // LA0: // rechannel input[n] → la0_buf_a[n][16] // zero la0_head // for each of 10 layers: // Layer16_process_block(ping, pong, input, la0_head) // swap ping/pong // project la0_head[n][16] → la1_head[n][8] (initial head for LA1) // // LA1: // rechannel la0_buf_a[n][16] → la1_buf_a[n][8] (10 swaps: output in a) // for each of 10 layers: // Layer8_process_block(ping, pong, input, la1_head) // swap ping/pong // // Output: // output[n] = head_scale * (la1_head_b + la1_head[n] @ la1_head_w) // // Note on ping/pong: with an even number of layers (10) and starting with // ping=buf_a, the final layer writes into buf_a (not buf_b as in the 7- and // 13-layer arrays). LA1 rechannel therefore reads from la0_buf_a. // ───────────────────────────────────────────────────────────────────────────── void forward_impl(const float* input, float* output) noexcept { const int N = (int)NAM_BLOCK; // ── LA0 rechannel: 1→16 ─────────────────────────────────────────────── for (int o = 0; o < 16; ++o) { const float r = la0_rechannel_w[o]; for (int n = 0; n < N; ++n) la0_buf_a[n][o] = r * input[n]; } // ── Zero LA0 head accumulator ───────────────────────────────────────── for (int n = 0; n < N; ++n) for (int o = 0; o < 16; ++o) la0_head[n][o] = 0.0f; // ── LA0 layer loop ──────────────────────────────────────────────────── // 10 swaps (even): final output lands in la0_buf_a { const float (*ping)[16] = la0_buf_a; float (*pong)[16] = la0_buf_b; for (int l = 0; l < 10; ++l) { Layer16_process_block(la0[l], ping, pong, input, la0_head, N); float (*tmp)[16] = pong; pong = (float(*)[16])ping; ping = tmp; } (void)ping; } // ── Project LA0 head 16→8 → initialise la1_head ────────────────────── for (int n = 0; n < N; ++n) { for (int o = 0; o < 8; ++o) { float acc = 0.0f; for (int i = 0; i < 16; ++i) acc += la0_head[n][i] * la0_head_wT[i][o]; la1_head[n][o] = acc; } } // ── LA1 rechannel: 16→8 (source: la0_buf_a, output of LA0) ────────── for (int n = 0; n < N; ++n) { for (int o = 0; o < 8; ++o) { float acc = 0.0f; for (int i = 0; i < 16; ++i) acc += la0_buf_a[n][i] * la1_rechannel_wT[i][o]; la1_buf_a[n][o] = acc; } } // ── LA1 layer loop ──────────────────────────────────────────────────── // 10 swaps (even): final output lands in la1_buf_a (unused — only head needed) { const float (*ping)[8] = la1_buf_a; float (*pong)[8] = la1_buf_b; for (int l = 0; l < 10; ++l) { Layer8_process_block(la1[l], ping, pong, input, la1_head, N); float (*tmp)[8] = pong; pong = (float(*)[8])ping; ping = tmp; } } // ── Output: head → scalar ───────────────────────────────────────────── { const float b = la1_head_b; const float sc = head_scale; for (int n = 0; n < N; ++n) { float acc = b; for (int o = 0; o < 8; ++o) acc += la1_head[n][o] * la1_head_w[o]; output[n] = sc * acc; } } } // ───────────────────────────────────────────────────────────────────────────── // Layer8_process_block (8-channel; used for LA1) // // For each sample n: // 1. Write ins[n] into circular state buffer. // 2. Read s1 = state[ptr-D], s2 = state[ptr-2D]. // 3. Conv: t[o] = conv_b[o] + W0@ins[n] + W1@s1 + W2@s2 + mixin[o]*cond[n] // 4. a[o] = tanh(t[o]) // 5. head[n][o] += a[o] // 6. outs[n][o] = ins[n][o] + b1x1[o] + W1x1 @ a // ───────────────────────────────────────────────────────────────────────────── void Layer8_process_block(Layer8& layer, const float ins[][8], float outs[][8], const float* cond, float head[][8], int N) noexcept { const float (*w0T)[8] = layer.w0T; const float (*w1T)[8] = layer.w1T; const float (*w2T)[8] = layer.w2T; const float (*w1x1T)[8] = layer.w1x1T; const float* conv_b = layer.conv_b; const float* mixin_w = layer.mixin_w; const float* b1x1 = layer.b1x1; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { // ── Write tap0 into circular state ─────────────────────────────── float* const cw = layer.state + ptr * 8; for (int c = 0; c < 8; ++c) cw[c] = ins[n][c]; // ── Tap positions ───────────────────────────────────────────────── int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 8; const float* __restrict__ s2 = layer.state + sp2 * 8; // ── Conv: bias + mixin + W0@i + W1@s1 + W2@s2 ──────────────────── float t[8]; const float cn = cond[n]; for (int o = 0; o < 8; ++o) t[o] = conv_b[o] + mixin_w[o] * cn; for (int i = 0; i < 8; ++i) { const float iv = ins[n][i]; const float s1v = s1[i]; const float s2v = s2[i]; for (int o = 0; o < 8; ++o) t[o] += iv*w0T[i][o] + s1v*w1T[i][o] + s2v*w2T[i][o]; } // ── Activation + head accumulation ─────────────────────────────── float a[8]; for (int o = 0; o < 8; ++o) { a[o] = nam_tanh(t[o]); head[n][o] += a[o]; } // ── 1×1 + residual ──────────────────────────────────────────────── float out[8]; for (int o = 0; o < 8; ++o) out[o] = ins[n][o] + b1x1[o]; for (int i = 0; i < 8; ++i) { const float av = a[i]; for (int o = 0; o < 8; ++o) out[o] += av * w1x1T[i][o]; } for (int o = 0; o < 8; ++o) outs[n][o] = out[o]; } layer.state_ptr = ptr; } // ───────────────────────────────────────────────────────────────────────────── // Layer16_process_block (16-channel; used for LA0) // // Identical structure to Layer8_process_block, scaled to 16 channels. // ───────────────────────────────────────────────────────────────────────────── void Layer16_process_block(Layer16& layer, const float ins[][16], float outs[][16], const float* cond, float head[][16], int N) noexcept { const float (*w0T)[16] = layer.w0T; const float (*w1T)[16] = layer.w1T; const float (*w2T)[16] = layer.w2T; const float (*w1x1T)[16] = layer.w1x1T; const float* conv_b = layer.conv_b; const float* mixin_w = layer.mixin_w; const float* b1x1 = layer.b1x1; const int ss = layer.state_size; const int nd = layer.neg_dilation; const int nd2 = layer.neg_2dilation; int ptr = layer.state_ptr; for (int n = 0; n < N; ++n) { // ── Write tap0 into circular state ─────────────────────────────── float* const cw = layer.state + ptr * 16; for (int c = 0; c < 16; ++c) cw[c] = ins[n][c]; // ── Tap positions ───────────────────────────────────────────────── int sp1 = ptr + nd; if (sp1 >= ss) sp1 -= ss; int sp2 = ptr + nd2; if (sp2 >= ss) sp2 -= ss; ++ptr; if (ptr == ss) ptr = 0; const float* __restrict__ s1 = layer.state + sp1 * 16; const float* __restrict__ s2 = layer.state + sp2 * 16; // ── Conv: bias + mixin + W0@i + W1@s1 + W2@s2 ──────────────────── float t[16]; const float cn = cond[n]; for (int o = 0; o < 16; ++o) t[o] = conv_b[o] + mixin_w[o] * cn; for (int i = 0; i < 16; ++i) { const float iv = ins[n][i]; const float s1v = s1[i]; const float s2v = s2[i]; for (int o = 0; o < 16; ++o) t[o] += iv*w0T[i][o] + s1v*w1T[i][o] + s2v*w2T[i][o]; } // ── Activation + head accumulation ─────────────────────────────── float a[16]; for (int o = 0; o < 16; ++o) { a[o] = nam_tanh(t[o]); head[n][o] += a[o]; } // ── 1×1 + residual ──────────────────────────────────────────────── float out[16]; for (int o = 0; o < 16; ++o) out[o] = ins[n][o] + b1x1[o]; for (int i = 0; i < 16; ++i) { const float av = a[i]; for (int o = 0; o < 16; ++o) out[o] += av * w1x1T[i][o]; } for (int o = 0; o < 16; ++o) outs[n][o] = out[o]; } layer.state_ptr = ptr; } }; } // namespace MicroNAM hvcc-0.16.0/hvcc/generators/ir2c/static/MicroNam/nam_to_header.py0000644000000000000000000000535300000000000021504 0ustar00#!/usr/bin/env python3 import argparse import json import re from pathlib import Path def _to_symbol_stem(nam_path: Path) -> str: stem = nam_path.stem.strip() if not stem: return "NamModel" # Split on non-alphanumeric boundaries, then form PascalCase. raw_parts = [p for p in re.split(r"[^A-Za-z0-9]+", stem) if p] if not raw_parts: return "NamModel" parts = [] for part in raw_parts: if part[0].isdigit(): part = f"M{part}" parts.append(part[0].upper() + part[1:]) return "".join(parts) def _format_float(value: float) -> str: # Keep enough precision for model weights while staying compact. return f"{format(value, '.17g')}f" def convert_nam_to_header(nam_file: Path, header_file: Path) -> tuple[str, int]: with nam_file.open("r", encoding="utf-8") as f: payload = json.load(f) if "weights" not in payload or not isinstance(payload["weights"], list): raise ValueError("Input .nam file must contain a 'weights' array") weights = payload["weights"] for idx, value in enumerate(weights): if not isinstance(value, (int, float)): raise ValueError(f"weights[{idx}] is not numeric") symbol_stem = _to_symbol_stem(nam_file) count_name = f"{symbol_stem}WeightsCount" weights_name = f"{symbol_stem}Weights" lines = [ "#pragma once", "", f"static constexpr unsigned int {count_name} = {len(weights)};", f"static constexpr float {weights_name}[{count_name}] = {{", ] row = [] for idx, value in enumerate(weights, start=1): row.append(_format_float(float(value))) if idx % 6 == 0: lines.append(" " + ", ".join(row) + ",") row = [] if row: lines.append(" " + ", ".join(row) + ",") lines.append("};") lines.append("") header_file.parent.mkdir(parents=True, exist_ok=True) header_file.write_text("\n".join(lines), encoding="utf-8") return weights_name, len(weights) def main() -> None: parser = argparse.ArgumentParser( description=( "Convert a Neural Amp Modeler .nam JSON file into a C++ header " "with static constexpr weight symbols." ) ) parser.add_argument("input_nam", type=Path, help="Path to input .nam file") parser.add_argument("output_header", type=Path, help="Path to output .h file") args = parser.parse_args() if not args.input_nam.is_file(): raise FileNotFoundError(f"Input file not found: {args.input_nam}") weights_name, count = convert_nam_to_header(args.input_nam, args.output_header) print(f"Generated {args.output_header} with {count} weights in symbol {weights_name}.") if __name__ == "__main__": main()hvcc-0.16.0/hvcc/generators/ir2c/static/cpuid.c0000644000000000000000000001071100000000000016102 0ustar00/* cpuid.c * * Author : Alexander J. Yee * Date Created : 01/19/2012 * Last Modified : 01/25/2012 * * * * And of course... The typical copyright stuff... * * Redistribution of this program in both source or binary, regardless of * form, with or without modification is permitted as long as the following * conditions are met: * 1. This copyright notice is maintained either inline in the source * or distributed with the binary. * 2. A list of all contributing authors along with their contributions * is included either inline in the source or distributed with the * binary. * 3. The following disclaimer is maintained either inline in the * source or distributed with the binary. * * Disclaimer: * This software is provided "as is", without any guarantee made to its * suitability or fitness for any particular use. It may contain bugs so use * of this program is at your own risk. I take no responsibility for any * damage that may unintentionally be caused through its use. */ // https://github.com/Mysticial/Flops/blob/e571da6e94f7b6d2d1a90e87b19398c5c4de4375/version1/source/cpuid.c // http://www.sandpile.org/x86/cpuid.htm #ifndef _cpuid_c #define _cpuid_c #include //#include #include "cpuid.h" //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #ifdef WIN32 #else void cpuid(int *info,int x){ int ax,bx,cx,dx; __asm__ __volatile__ ("cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (x)); info[0] = ax; info[1] = bx; info[2] = cx; info[3] = dx; } #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void cpuid_print_name(){ int name[13]; cpuid(name + 0,0x80000002); cpuid(name + 4,0x80000003); cpuid(name + 8,0x80000004); name[12] = '\0'; printf("CPU Name = %s\n",(char*)name); // printf("Threads = %d\n",omp_get_max_threads()); printf("\n"); } void cpuid_print_exts(){ int x64 = 0; int MMX = 0; int SSE = 0; int SSE2 = 0; int SSE3 = 0; int SSSE3 = 0; int SSE41 = 0; int SSE42 = 0; int SSE4a = 0; int AVX = 0; int AVX2 = 0; int XOP = 0; int FMA3 = 0; int FMA4 = 0; int info[4]; cpuid(info, 0); int nIds = info[0]; cpuid(info, 0x80000000); int nExIds = info[0]; // Detect Instruction Set if (nIds >= 1){ cpuid(info,0x00000001); MMX = (info[3] & ((int)1 << 23)) != 0; SSE = (info[3] & ((int)1 << 25)) != 0; SSE2 = (info[3] & ((int)1 << 26)) != 0; SSE3 = (info[2] & ((int)1 << 0)) != 0; SSSE3 = (info[2] & ((int)1 << 9)) != 0; SSE41 = (info[2] & ((int)1 << 19)) != 0; SSE42 = (info[2] & ((int)1 << 20)) != 0; AVX = (info[2] & ((int)1 << 28)) != 0; FMA3 = (info[2] & ((int)1 << 12)) != 0; } if (nExIds >= 0x00000007){ cpuid(info,0x00000007); AVX2 = (info[2] & ((int)1 << 5)) != 0; } if (nExIds >= 0x80000001){ cpuid(info,0x80000001); x64 = (info[3] & ((int)1 << 29)) != 0; SSE4a = (info[2] & ((int)1 << 6)) != 0; FMA4 = (info[2] & ((int)1 << 16)) != 0; XOP = (info[2] & ((int)1 << 11)) != 0; } printf("Hardware Features:\n"); printf("x64 = %d\n",x64); printf("MMX = %d\n",MMX); printf("SSE = %d\n",SSE); printf("SSE2 = %d\n",SSE2); printf("SSE3 = %d\n",SSE3); printf("SSSE3 = %d\n",SSSE3); printf("SSE4a = %d\n",SSE4a); printf("SSE41 = %d\n",SSE41); printf("SSE42 = %d\n",SSE42); printf("AVX = %d\n",AVX); printf("AVX2 = %d\n",AVX2); printf("FMA3 = %d\n",FMA3); printf("FMA4 = %d\n",FMA4); printf("XOP = %d\n",XOP); printf("\n"); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #endif hvcc-0.16.0/hvcc/generators/ir2c/static/cpuid.h0000644000000000000000000000441700000000000016115 0ustar00/* cpuid.h * * Author : Alexander J. Yee * Date Created : 01/19/2012 * Last Modified : 01/25/2012 * * * * And of course... The typical copyright stuff... * * Redistribution of this program in both source or binary, regardless of * form, with or without modification is permitted as long as the following * conditions are met: * 1. This copyright notice is maintained either inline in the source * or distributed with the binary. * 2. A list of all contributing authors along with their contributions * is included either inline in the source or distributed with the * binary. * 3. The following disclaimer is maintained either inline in the * source or distributed with the binary. * * Disclaimer: * This software is provided "as is", without any guarantee made to its * suitability or fitness for any particular use. It may contain bugs so use * of this program is at your own risk. I take no responsibility for any * damage that may unintentionally be caused through its use. */ // https://github.com/Mysticial/Flops/blob/e571da6e94f7b6d2d1a90e87b19398c5c4de4375/version1/source/cpuid.h #ifndef _cpuid_h #define _cpuid_h #ifdef __cplusplus extern "C" { #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #ifdef WIN32 #include #define cpuid __cpuid #else void cpuid(int *info,int x); #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void cpuid_print_name(); void cpuid_print_exts(); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus } #endif #endif hvcc-0.16.0/hvcc/generators/ir2c/templates/Heavy_NAME.cpp0000644000000000000000000002741400000000000017731 0ustar00{{copyright}} #include "Heavy_{{name}}.hpp" #include #define Context(_c) static_cast(_c) /* * C Functions */ extern "C" { HV_EXPORT HeavyContextInterface *hv_{{name}}_new(double sampleRate) { // allocate aligned memory void *ptr = hv_malloc(sizeof(Heavy_{{name}})); // ensure non-null if (!ptr) return nullptr; // call constructor new(ptr) Heavy_{{name}}(sampleRate); return Context(ptr); } HV_EXPORT HeavyContextInterface *hv_{{name}}_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) { // allocate aligned memory void *ptr = hv_malloc(sizeof(Heavy_{{name}})); // ensure non-null if (!ptr) return nullptr; // call constructor new(ptr) Heavy_{{name}}(sampleRate, poolKb, inQueueKb, outQueueKb); return Context(ptr); } HV_EXPORT void hv_{{name}}_free(HeavyContextInterface *instance) { // call destructor Context(instance)->~Heavy_{{name}}(); // free memory hv_free(instance); } } // extern "C" {% if table_data_list|length > 0 -%} /* * Table Data */ {% for x in table_data_list %} {{x}} {%- endfor %} {%- endif %} /* * Class Functions */ Heavy_{{name}}::Heavy_{{name}}(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) : HeavyContext(sampleRate, poolKb, inQueueKb, outQueueKb) { {%- for x in init_list %} numBytes += {{x}} {%- endfor %} {% if "__hv_init" in send_receive %} // schedule a message to trigger all loadbangs via the __hv_init receiver scheduleMessageForReceiver({{send_receive["__hv_init"]["hash"]}}, msg_initWithBang(HV_MESSAGE_ON_STACK(1), 0)); {%- endif %} } Heavy_{{name}}::~Heavy_{{name}}() { {%- if free_list|length > 0 %} {%- for x in free_list %} {{x}} {%- endfor %} {%- else %} // nothing to free {%- endif %} } HvTable *Heavy_{{name}}::getTableForHash(hv_uint32_t tableHash) { {%- if send_table|length > 0 -%} switch (tableHash) { {%- for k,v in send_table.items() %} case {{v.hash}}: return &hTable_{{v.id}}; // {{v.display}} {%- endfor %} default: return nullptr; } {%- else %} return nullptr; {%- endif %} } void Heavy_{{name}}::scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) { switch (receiverHash) { {%- for k,v in send_receive.items() %} case {{v.hash}}: { // {{v.display}} {%- for obj_id in v.ids %} mq_addMessageByTimestamp(&mq, m, 0, &cReceive_{{obj_id}}_sendMessage); {%- endfor %} break; } {%- endfor %} default: return; } } int Heavy_{{name}}::getParameterInfo(int index, HvParameterInfo *info) { if (info != nullptr) { switch (index) { {%- for v in (send_receive|extern).values() %} case {{loop.index-1}}: { info->name = "{{v.display}}"; info->hash = {{v.hash}}; {%- if v.extern == "param" %} info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN; info->minVal = {{v.attributes.min}}f; info->maxVal = {{v.attributes.max}}f; info->defaultVal = {{v.attributes.default}}f; {%- else %} info->type = HvParameterType::HV_PARAM_TYPE_EVENT_IN; info->minVal = 0.0f; info->maxVal = 0.0f; info->defaultVal = 0.0f; {%- endif %} break; } {%- endfor %} default: { info->name = "invalid parameter index"; info->hash = 0; info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN; info->minVal = 0.0f; info->maxVal = 0.0f; info->defaultVal = 0.0f; break; } } } return {{send_receive|extern|length}}; } /* * Send Function Implementations */ {% for x in impl_list %} void Heavy_{{name}}::{{x}} {% if not loop.last -%} {%- endif %} {%- endfor %} /* * Code for expr~ implementation * Write out the generic implementation code */ // per class code {%- for line in class_impl_lines %} {{line}} {%- endfor %} // per object code {%- for line in obj_impl_lines %} {{line}} {%- endfor %} /* * Context Process Implementation */ int Heavy_{{name}}::process(float **inputBuffers, float **outputBuffers, int n) { while (hLp_hasData(&inQueue)) { hv_uint32_t numBytes = 0; ReceiverMessagePair *p = reinterpret_cast(hLp_getReadBuffer(&inQueue, &numBytes)); hv_assert(numBytes >= sizeof(ReceiverMessagePair)); scheduleMessageForReceiver(p->receiverHash, &p->msg); hLp_consume(&inQueue); } sendBangToReceiver(0xDD21C0EB); // send to __hv_bang~ on next cycle {%- if nodsp is sameas false %} const int n4 = n & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD // temporary signal vars {%- if signal.numTemporaryBuffers.float > 0 %} hv_bufferf_t {% for i in range(signal.numTemporaryBuffers.float) %}Bf{{i}}{% if not loop.last %}, {%endif%}{% endfor %}; {%- endif %} {%- if signal.numTemporaryBuffers.integer > 0 %} hv_bufferi_t {% for i in range(signal.numTemporaryBuffers.integer) %}Bi{{i}}{% if not loop.last %}, {%endif%}{% endfor %}; {%- endif %} // input and output vars {%- if signal.numOutputBuffers > 0 %} hv_bufferf_t {% for i in range(signal.numOutputBuffers) %}O{{i}}{% if not loop.last %}, {%endif%}{% endfor %}; {%- endif %} {%- if signal.numInputBuffers > 0 %} hv_bufferf_t {% for i in range(signal.numInputBuffers) %}I{{i}}{% if not loop.last %}, {%endif%}{% endfor %}; {%- endif %} // declare and init the zero buffer hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO)); hv_uint32_t nextBlock = blockStartTimestamp; for (int n = 0; n < n4; n += HV_N_SIMD) { // process all of the messages for this block nextBlock += HV_N_SIMD; while (mq_hasMessageBefore(&mq, nextBlock)) { MessageNode *const node = mq_peek(&mq); node->sendMessage(this, node->let, node->m); mq_pop(&mq); } {% if signal.numInputBuffers > 0 -%} // load input buffers {%- for i in range(signal.numInputBuffers) %} __hv_load_f(inputBuffers[{{i}}]+n, VOf(I{{i}})); {%- endfor %} {%- endif %} {% if signal.numOutputBuffers > 0 -%} // zero output buffers {%- for i in range(signal.numOutputBuffers) %} __hv_zero_f(VOf(O{{i}})); {%- endfor %} {%- endif %} // process all signal functions {%- for f in process_list %} {{f}} {%- endfor %} // save output vars to output buffer {%- if signal.numOutputBuffers > 0 %} {%- for i in range(signal.numOutputBuffers) %} __hv_store_f(outputBuffers[{{i}}]+n, VIf(O{{i}})); {%- endfor %} {%- else %} // no output channels {%- endif %} } blockStartTimestamp = nextBlock; return n4; // return the number of frames processed {%- else %} {# if this is a control-only patch, the process loop is substantially simpler. #} hv_uint32_t nextBlock = blockStartTimestamp + n; while (mq_hasMessageBefore(&mq, nextBlock)) { MessageNode *const node = mq_peek(&mq); node->sendMessage(this, node->let, node->m); mq_pop(&mq); } blockStartTimestamp = nextBlock; return n; {%- endif %} } int Heavy_{{name}}::processInline(float *inputBuffers, float *outputBuffers, int n4) { hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD // define the heavy input buffer for {{signal.numInputBuffers}} channel(s) {%- if signal.numInputBuffers == 0 %} float **const bIn = NULL; {%- elif signal.numInputBuffers == 1 %} float **const bIn = &inputBuffers; {%- else %} float **const bIn = reinterpret_cast(hv_alloca({{signal.numInputBuffers}}*sizeof(float *))); {%- for i in range(signal.numInputBuffers) %} bIn[{{i}}] = inputBuffers+({{i}}*n4); {%- endfor %} {%- endif %} // define the heavy output buffer for {{signal.numOutputBuffers}} channel(s) {%- if signal.numOutputBuffers == 0 %} float **const bOut = NULL; {%- elif signal.numOutputBuffers == 1 %} float **const bOut = &outputBuffers; {%- else %} float **const bOut = reinterpret_cast(hv_alloca({{signal.numOutputBuffers}}*sizeof(float *))); {%- for i in range(signal.numOutputBuffers) %} bOut[{{i}}] = outputBuffers+({{i}}*n4); {%- endfor %} {%- endif %} int n = process(bIn, bOut, n4); return n; } int Heavy_{{name}}::processInlineInterleaved(float *inputBuffers, float *outputBuffers, int n4) { hv_assert(n4 & ~HV_N_SIMD_MASK); // ensure that n4 is a multiple of HV_N_SIMD // define the heavy input buffer for {{signal.numInputBuffers}} channel(s), uninterleave {%- if signal.numInputBuffers == 0 %} float *const bIn = NULL; {%- elif signal.numInputBuffers == 1 %} float *const bIn = inputBuffers; {%- elif signal.numInputBuffers == 2 %} float *const bIn = reinterpret_cast(hv_alloca(2*n4*sizeof(float))); #if HV_SIMD_SSE || HV_SIMD_AVX for (int i = 0, j = 0; j < n4; j += 4, i += 8) { __m128 a = _mm_load_ps(inputBuffers+i); // LRLR __m128 b = _mm_load_ps(inputBuffers+4+i); // LRLR __m128 x = _mm_shuffle_ps(a, b, _MM_SHUFFLE(2,0,2,0)); // LLLL __m128 y = _mm_shuffle_ps(a, b, _MM_SHUFFLE(3,1,3,1)); // RRRR _mm_store_ps(bIn+j, x); _mm_store_ps(bIn+n4+j, y); } #elif HV_SIMD_NEON for (int i = 0, j = 0; j < n4; j += 4, i += 8) { float32x4x2_t a = vld2q_f32(inputBuffers+i); // load and uninterleave vst1q_f32(bIn+j, a.val[0]); vst1q_f32(bIn+n4+j, a.val[1]); } #else // HV_SIMD_NONE for (int j = 0; j < n4; ++j) { {%- for i in range(signal.numInputBuffers) %} bIn[{{i}}*n4+j] = inputBuffers[{{i}}+{{signal.numInputBuffers}}*j]; {%- endfor %} } #endif {%- else %} float *const bIn = (float *) hv_alloca({{signal.numInputBuffers}}*n4*sizeof(float)); for (int j = 0; j < n4; ++j) { {%- for i in range(signal.numInputBuffers) %} bIn[{{i}}*n4+j] = inputBuffers[{{i}}+{{signal.numInputBuffers}}*j]; {%- endfor %} } {%- endif %} // define the heavy output buffer for {{signal.numOutputBuffers}} channel(s) {%- if signal.numOutputBuffers == 0 %} float *const bOut = NULL; {%- elif signal.numOutputBuffers == 1 %} float *const bOut = outputBuffers; {%- else %} float *const bOut = reinterpret_cast(hv_alloca({{signal.numOutputBuffers}}*n4*sizeof(float))); {%- endif %} int n = processInline(bIn, bOut, n4); {% if signal.numOutputBuffers == 2 -%} // interleave the heavy output into the output buffer #if HV_SIMD_AVX for (int i = 0, j = 0; j < n4; j += 8, i += 16) { __m256 x = _mm256_load_ps(bOut+j); // LLLLLLLL __m256 y = _mm256_load_ps(bOut+n4+j); // RRRRRRRR __m256 a = _mm256_unpacklo_ps(x, y); // LRLRLRLR __m256 b = _mm256_unpackhi_ps(x, y); // LRLRLRLR _mm256_store_ps(outputBuffers+i, a); _mm256_store_ps(outputBuffers+8+i, b); } #elif HV_SIMD_SSE for (int i = 0, j = 0; j < n4; j += 4, i += 8) { __m128 x = _mm_load_ps(bOut+j); // LLLL __m128 y = _mm_load_ps(bOut+n4+j); // RRRR __m128 a = _mm_unpacklo_ps(x, y); // LRLR __m128 b = _mm_unpackhi_ps(x, y); // LRLR _mm_store_ps(outputBuffers+i, a); _mm_store_ps(outputBuffers+4+i, b); } #elif HV_SIMD_NEON // https://community.arm.com/groups/processors/blog/2012/03/13/coding-for-neon--part-5-rearranging-vectors for (int i = 0, j = 0; j < n4; j += 4, i += 8) { float32x4_t x = vld1q_f32(bOut+j); float32x4_t y = vld1q_f32(bOut+n4+j); float32x4x2_t z = {x, y}; vst2q_f32(outputBuffers+i, z); // interleave and store } #else // HV_SIMD_NONE for (int i = 0; i < {{signal.numOutputBuffers}}; ++i) { for (int j = 0; j < n4; ++j) { outputBuffers[i+{{signal.numOutputBuffers}}*j] = bOut[i*n4+j]; } } #endif {%- elif signal.numOutputBuffers > 2 %} // interleave the heavy output into the output buffer for (int i = 0; i < {{signal.numOutputBuffers}}; ++i) { for (int j = 0; j < n4; ++j) { outputBuffers[i+{{signal.numOutputBuffers}}*j] = bOut[i*n4+j]; } } {%- endif %} return n; } {# force newline #} hvcc-0.16.0/hvcc/generators/ir2c/templates/Heavy_NAME.h0000644000000000000000000000477500000000000017403 0ustar00{{copyright}} #ifndef _HEAVY_{{name|upper}}_H_ #define _HEAVY_{{name|upper}}_H_ #include "HvHeavy.h" #ifdef __cplusplus extern "C" { #endif #if HV_APPLE #pragma mark - Heavy Context #endif {% if externs.parameters.inParam|length > 0 -%} typedef enum { {%- for k,v in externs.parameters.inParam %} HV_{{name|upper}}_PARAM_IN_{{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} } Hv_{{name}}_ParameterIn; {% endif -%} {% if externs.parameters.outParam|length > 0 %} typedef enum { {%- for k,v in externs.parameters.outParam %} HV_{{name|upper}}_PARAM_OUT_{{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} } Hv_{{name}}_ParameterOut; {% endif -%} {% if externs.events.inEvent|length > 0 %} typedef enum { {%- for k,v in externs.events.inEvent %} HV_{{name|upper}}_EVENT_IN_{{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} } Hv_{{name}}_EventIn; {% endif -%} {% if externs.events.outEvent|length > 0 %} typedef enum { {%- for k,v in externs.events.outEvent %} HV_{{name|upper}}_EVENT_OUT_{{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} } Hv_{{name}}_EventOut; {% endif -%} {% if externs.tables|length > 0 %} typedef enum { {%- for k,v in externs.tables %} HV_{{name|upper}}_TABLE_{{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} } Hv_{{name}}_Table; {%- endif %} /** * Creates a new patch instance. * Sample rate should be positive and in Hertz, e.g. 44100.0. */ HeavyContextInterface *hv_{{name}}_new(double sampleRate); /** * Creates a new patch instance. * @param sampleRate Sample rate should be positive (> 0) and in Hertz, e.g. 48000.0. * @param poolKb Pool size is in kilobytes, and determines the maximum amount of memory * allocated to messages at any time. By default this is 10 KB. * @param inQueueKb The size of the input message queue in kilobytes. It determines the * amount of memory dedicated to holding scheduled messages between calls to * process(). Default is 2 KB. * @param outQueueKb The size of the output message queue in kilobytes. It determines the * amount of memory dedicated to holding scheduled messages to the default sendHook. * See getNextSentMessage() for info on accessing these messages. Default is 0 KB. */ HeavyContextInterface *hv_{{name}}_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb); /** * Free the patch instance. */ void hv_{{name}}_free(HeavyContextInterface *instance); #ifdef __cplusplus } // extern "C" #endif #endif // _HEAVY_{{name|upper}}_H_ {# force a new line #} hvcc-0.16.0/hvcc/generators/ir2c/templates/Heavy_NAME.hpp0000644000000000000000000000574000000000000017734 0ustar00{{copyright}} #ifndef _HEAVY_CONTEXT_{{name|upper}}_HPP_ #define _HEAVY_CONTEXT_{{name|upper}}_HPP_ // object includes #include "HeavyContext.hpp" {%- for i in include_set %} #include "{{i}}" {%- endfor %} class Heavy_{{name}} : public HeavyContext { public: Heavy_{{name}}(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0); ~Heavy_{{name}}(); const char *getName() override { return "{{name}}"; } int getNumInputChannels() override { return {{signal.numInputBuffers}}; } int getNumOutputChannels() override { return {{signal.numOutputBuffers}}; } int process(float **inputBuffers, float **outputBuffer, int n) override; int processInline(float *inputBuffers, float *outputBuffer, int n) override; int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) override; int getParameterInfo(int index, HvParameterInfo *info) override; {%- if externs.parameters.inParam|length > 0 or externs.parameters.outParam|length > 0 %} struct Parameter { {% if externs.parameters.inParam|length > 0 -%} struct In { enum ParameterIn : hv_uint32_t { {%- for k,v in externs.parameters.inParam %} {{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} }; }; {%- endif %} {%- if externs.parameters.outParam|length > 0 %} struct Out { enum ParameterOut : hv_uint32_t { {%- for k,v in externs.parameters.outParam %} {{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} }; }; {%- endif %} }; {%- endif %} {%- if externs.events.inEvent|length > 0 or externs.events.outEvent|length > 0 %} struct Event { {%- if externs.events.inEvent|length > 0 %} struct In { enum EventIn : hv_uint32_t { {%- for k,v in externs.events.inEvent %} {{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} }; }; {%- endif %} {%- if externs.events.outEvent|length > 0 %} struct Out { enum EventOut : hv_uint32_t { {%- for k,v in externs.events.outEvent %} {{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} }; }; {%- endif %} }; {%- endif %} {%- if externs.tables|length > 0 %} enum Table : hv_uint32_t { {%- for k,v in externs.tables %} {{k|upper}} = {{v.hash}}, // {{v.display}} {%- endfor %} }; {%- endif %} private: HvTable *getTableForHash(hv_uint32_t tableHash) override; void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) override; /* * Code for expr~ implementation * Write out the generic header code */ // per class code {%- for line in class_header_lines %} {{line}} {%- endfor %} // per object code {%- for line in obj_header_lines %} {{line}} {%- endfor %} // static sendMessage functions {%- for d in decl_list %} static void {{d}} {%- endfor %} // objects {%- for d in def_list %} {{d}} {%- endfor %} }; #endif // _HEAVY_CONTEXT_{{name|upper}}_HPP_ {# force newline #} hvcc-0.16.0/hvcc/generators/vs2015/Heavy/Heavy.sln0000644000000000000000000000235700000000000016321 0ustar00 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Heavy", "Heavy.vcxproj", "{B1085EE2-C54E-4892-A24D-06B80001DB68}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B1085EE2-C54E-4892-A24D-06B80001DB68}.Debug|x64.ActiveCfg = Debug|x64 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Debug|x64.Build.0 = Debug|x64 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Debug|x86.ActiveCfg = Debug|Win32 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Debug|x86.Build.0 = Debug|Win32 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Release|x64.ActiveCfg = Release|x64 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Release|x64.Build.0 = Release|x64 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Release|x86.ActiveCfg = Release|Win32 {B1085EE2-C54E-4892-A24D-06B80001DB68}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal hvcc-0.16.0/hvcc/generators/vs2015/Heavy/Heavy.vcxproj0000644000000000000000000003132700000000000017217 0ustar00 Debug Win32 Release Win32 Debug x64 Release x64 {B1085EE2-C54E-4892-A24D-06B80001DB68} Win32Proj Heavy 8.1 Application true v140 Unicode Application false v140 true Unicode Application true v140 Unicode Application false v140 true Unicode true true false false Level3 Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS Console true python $(SolutionDir)\..\..\..\hvcc.py C:\Users\Joe\Downloads\woosh.iX2jC.pd\_main.pd -o $(SolutionDir)\generated -n heavy Level3 Disabled _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS Default false StreamingSIMDExtensions2 Console true python $(SolutionDir)..\..\..\hvcc.py C:\Users\enzien\Desktop\test_osc.pd -o $(SolutionDir)\generated -n heavy Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS Console true true true python $(SolutionDir)\..\..\..\hvcc.py C:\Users\Joe\Downloads\woosh.iX2jC.pd\_main.pd -o $(SolutionDir)\generated -n heavy Level3 MaxSpeed true true NDEBUG;_CONSOLE;HV_SIMD_SSE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS Console true true true python $(SolutionDir)..\..\..\hvcc.py C:\Users\enzien\Desktop\test_osc.pd -o $(SolutionDir)\generated -n heavy Default hvcc-0.16.0/hvcc/generators/vs2015/Heavy/Heavy.vcxproj.filters0000644000000000000000000002237300000000000020667 0ustar00 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {0a0854fe-2e4e-4aab-b804-7395e7f2cbbd} {2ff1fc05-5468-4baa-8299-b7b154a49aa2} Header Files Header Files Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Generated Generated Static Source Files Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Static Generated Static Source Files hvcc-0.16.0/hvcc/generators/vs2015/Heavy/main.c0000644000000000000000000000473700000000000015623 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #include #include #include #include #include "../../vs2015/Heavy/generated/c/Heavy_heavy.h" void printHook(double timestampMs, const char *name, const char *s, void *userData) { printf("[@ %.3fms] %s: %s\n", timestampMs, name, s); } #define NUM_ITERATIONS 8388600 #define BLOCK_SIZE 512 #define SAMPLE_RATE 48000.0 int main(int argc, const char * argv[]) { Hv_heavy *context = hv_heavy_new(SAMPLE_RATE); hv_setPrintHook(context, &printHook); float *inputBuffers = (float *) malloc(hv_getNumInputChannels(context) * BLOCK_SIZE * sizeof(float)); float *outputBuffers = (float *) malloc(hv_getNumOutputChannels(context) * BLOCK_SIZE * sizeof(float)); uint64_t freq, start, end; QueryPerformanceFrequency((LARGE_INTEGER *) &freq); QueryPerformanceCounter((LARGE_INTEGER *) &start); for (int i = 0; i < NUM_ITERATIONS; ++i) { hv_heavy_process_inline(context, inputBuffers, outputBuffers, BLOCK_SIZE); } QueryPerformanceCounter((LARGE_INTEGER *) &end); const double elapsedTimeUs = 1000.0 * (end - start) / ((double) freq); printf("Executed %i blocks of length %i at a sample rate of %gHz. A total of %i samples were generated.\n", NUM_ITERATIONS, BLOCK_SIZE, SAMPLE_RATE, (int) (NUM_ITERATIONS * BLOCK_SIZE)); printf("Runtime is: %i iterations in %.3f milliseconds\n", NUM_ITERATIONS, elapsedTimeUs); printf(" %f iterations/second.\n", (NUM_ITERATIONS*1000.0)/elapsedTimeUs); printf(" %.6f milliseconds per block.\n", elapsedTimeUs/NUM_ITERATIONS); printf(" %.6f microseconds per block.\n", 1000.0*elapsedTimeUs/NUM_ITERATIONS); printf(" %0.6f%% CPU\n", 100.0*((elapsedTimeUs/1000.0)/NUM_ITERATIONS)/(BLOCK_SIZE/SAMPLE_RATE)); free(inputBuffers); free(outputBuffers); hv_heavy_free(context); Sleep(10000); return 0; } hvcc-0.16.0/hvcc/generators/vs2015/Heavy/stdafx.cpp0000644000000000000000000000043400000000000016516 0ustar00// stdafx.cpp : source file that includes just the standard includes // Heavy.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file hvcc-0.16.0/hvcc/generators/vs2015/Heavy/stdafx.h0000644000000000000000000000046100000000000016163 0ustar00// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include "targetver.h" #include #include // TODO: reference additional headers your program requires here hvcc-0.16.0/hvcc/generators/vs2015/Heavy/targetver.h0000644000000000000000000000046200000000000016676 0ustar00#pragma once // Including SDKDDKVer.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. #include hvcc-0.16.0/hvcc/generators/xcode/Heavy/main.c0000644000000000000000000000467400000000000015765 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #include #include #include #include "cpuid.h" #include "Heavy_heavy.h" void printHook(HeavyContextInterface *c, const char *name, const char *s, const HvMessage *m) { printf("[@ %.3f] %s: %s\n", hv_samplesToMilliseconds(c, hv_msg_getTimestamp(m)), name, s); } #define NUM_ITERATIONS 100000000 // 8388600 #define BLOCK_SIZE 512 #define SAMPLE_RATE 48000.0 int main(int argc, const char * argv[]) { cpuid_print_exts(); HeavyContextInterface *context = hv_heavy_new(SAMPLE_RATE); hv_setPrintHook(context, &printHook); float *inputBuffers = (float *) malloc(hv_getNumInputChannels(context) * BLOCK_SIZE * sizeof(float)); float *outputBuffers = (float *) malloc(hv_getNumOutputChannels(context) * BLOCK_SIZE * sizeof(float)); mach_timebase_info_data_t sTimebaseInfo; mach_timebase_info(&sTimebaseInfo); uint64_t start = mach_absolute_time(); for (int i = 0; i < NUM_ITERATIONS; ++i) { hv_processInline(context, inputBuffers, outputBuffers, BLOCK_SIZE); } uint64_t end = mach_absolute_time(); uint64_t elapsedTimeNs = (end - start) * sTimebaseInfo.numer / sTimebaseInfo.denom; printf("Executed %i blocks of length %i at a sample rate of %gHz. A total of %llu samples were generated.\n", NUM_ITERATIONS, BLOCK_SIZE, SAMPLE_RATE, (1LLU*NUM_ITERATIONS) * BLOCK_SIZE); printf("Runtime is: %i iterations in %.3f seconds\n", NUM_ITERATIONS, elapsedTimeNs/1000000000.0); printf(" %f iterations/second.\n", (NUM_ITERATIONS*1000000000.0)/elapsedTimeNs); printf(" %.3f nanoseconds/block.\n", (1.0*elapsedTimeNs)/NUM_ITERATIONS); printf(" %0.6f%% CPU\n", 100.0*((elapsedTimeNs/1000000000.0)/NUM_ITERATIONS)/(BLOCK_SIZE/SAMPLE_RATE)); free(inputBuffers); free(outputBuffers); hv_delete(context); return 0; } hvcc-0.16.0/hvcc/generators/xcode/Heavy.xcodeproj/project.pbxproj0000644000000000000000000023672100000000000021745 0ustar00// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 900D618A1AD9EFAD001BDB71 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900D61891AD9EFAD001BDB71 /* Accelerate.framework */; }; 900D618C1AD9F2AE001BDB71 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 900D618B1AD9F2AE001BDB71 /* AVFoundation.framework */; }; 9036C1B01AD57CDF00C7B994 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9036C1AF1AD57CDF00C7B994 /* main.m */; }; 9036C1B31AD57CDF00C7B994 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9036C1B21AD57CDF00C7B994 /* AppDelegate.m */; }; 9036C1B61AD57CDF00C7B994 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9036C1B51AD57CDF00C7B994 /* ViewController.m */; }; 9036C1B91AD57CDF00C7B994 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9036C1B71AD57CDF00C7B994 /* Main.storyboard */; }; 9036C1BB1AD57CDF00C7B994 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9036C1BA1AD57CDF00C7B994 /* Images.xcassets */; }; 9036C1BE1AD57CDF00C7B994 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9036C1BC1AD57CDF00C7B994 /* LaunchScreen.xib */; }; 9036C1D51AD58B3A00C7B994 /* TPCircularBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 9036C1D11AD58B3A00C7B994 /* TPCircularBuffer.c */; }; 9036C1D91AD58B9B00C7B994 /* HeavyAudio.m in Sources */ = {isa = PBXBuildFile; fileRef = 9036C1D81AD58B9B00C7B994 /* HeavyAudio.m */; }; 9059F9271BECEE5100589DE5 /* tinywav.c in Sources */ = {isa = PBXBuildFile; fileRef = 9059F9251BECEE5100589DE5 /* tinywav.c */; }; 906644F61E5E43F7007F4762 /* HvUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = 906644F51E5E43F7007F4762 /* HvUtils.c */; }; 906644F71E5E43F7007F4762 /* HvUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = 906644F51E5E43F7007F4762 /* HvUtils.c */; }; 906644F81E5E43F7007F4762 /* HvUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = 906644F51E5E43F7007F4762 /* HvUtils.c */; }; 90AA59441A63407400F3B66E /* cpuid.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA590B1A63407400F3B66E /* cpuid.c */; }; 90B848C41D95C8E60004BCE3 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90B848C31D95C8E60004BCE3 /* AudioUnit.framework */; }; 90B848C61D95C8EB0004BCE3 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90B848C51D95C8EB0004BCE3 /* Accelerate.framework */; }; 90B848D01D95CA310004BCE3 /* HvHeavy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA0431D573C86002E49ED /* HvHeavy.cpp */; }; 90B848D11D95CA310004BCE3 /* HeavyContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA0451D573C86002E49ED /* HeavyContext.cpp */; }; 90B848D21D95CA310004BCE3 /* HvControlBinop.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58F71A63407400F3B66E /* HvControlBinop.c */; }; 90B848D31D95CA310004BCE3 /* HvControlCast.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58F91A63407400F3B66E /* HvControlCast.c */; }; 90B848D41D95CA310004BCE3 /* HvControlDelay.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FB1A63407400F3B66E /* HvControlDelay.c */; }; 90B848D51D95CA310004BCE3 /* HvControlIf.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FD1A63407400F3B66E /* HvControlIf.c */; }; 90B848D61D95CA310004BCE3 /* HvControlPack.c in Sources */ = {isa = PBXBuildFile; fileRef = D8A281EA1AEFC765004F8531 /* HvControlPack.c */; }; 90B848D71D95CA310004BCE3 /* HvControlPrint.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FF1A63407400F3B66E /* HvControlPrint.c */; }; 90B848D81D95CA310004BCE3 /* HvControlRandom.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59011A63407400F3B66E /* HvControlRandom.c */; }; 90B848D91D95CA310004BCE3 /* HvControlSlice.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59031A63407400F3B66E /* HvControlSlice.c */; }; 90B848DA1D95CA310004BCE3 /* HvControlSystem.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59051A63407400F3B66E /* HvControlSystem.c */; }; 90B848DB1D95CA310004BCE3 /* HvControlTabhead.c in Sources */ = {isa = PBXBuildFile; fileRef = 90226C171A9F8DAD005D8253 /* HvControlTabhead.c */; }; 90B848DC1D95CA310004BCE3 /* HvControlTabread.c in Sources */ = {isa = PBXBuildFile; fileRef = 906FAB781AEF85C000B9F165 /* HvControlTabread.c */; }; 90B848DD1D95CA310004BCE3 /* HvControlTabwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 906FAB7D1AEF895E00B9F165 /* HvControlTabwrite.c */; }; 90B848DE1D95CA310004BCE3 /* HvControlUnop.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59071A63407400F3B66E /* HvControlUnop.c */; }; 90B848DF1D95CA310004BCE3 /* HvControlVar.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59091A63407400F3B66E /* HvControlVar.c */; }; 90B848E01D95CA310004BCE3 /* HvLightPipe.c in Sources */ = {isa = PBXBuildFile; fileRef = 9088F1B81CB36DA600569945 /* HvLightPipe.c */; }; 90B848E11D95CA310004BCE3 /* HvMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59111A63407400F3B66E /* HvMessage.c */; }; 90B848E21D95CA310004BCE3 /* HvTable.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59131A63407400F3B66E /* HvTable.c */; }; 90B848E31D95CA310004BCE3 /* HvMessagePool.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59151A63407400F3B66E /* HvMessagePool.c */; }; 90B848E41D95CA310004BCE3 /* HvMessageQueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59171A63407400F3B66E /* HvMessageQueue.c */; }; 90B848E51D95CA310004BCE3 /* HvSignalBiquad.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59191A63407400F3B66E /* HvSignalBiquad.c */; }; 90B848E61D95CA310004BCE3 /* HvSignalConvolution.c in Sources */ = {isa = PBXBuildFile; fileRef = 90D200C01BC2AB6400E45A9D /* HvSignalConvolution.c */; }; 90B848E71D95CA310004BCE3 /* HvSignalCPole.c in Sources */ = {isa = PBXBuildFile; fileRef = D89405DA1BE19A8300491551 /* HvSignalCPole.c */; }; 90B848E81D95CA310004BCE3 /* HvSignalDel1.c in Sources */ = {isa = PBXBuildFile; fileRef = D8500AD81BD9B9D400D12C3A /* HvSignalDel1.c */; }; 90B848E91D95CA310004BCE3 /* HvSignalEnvelope.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591B1A63407400F3B66E /* HvSignalEnvelope.c */; }; 90B848EA1D95CA310004BCE3 /* HvSignalLine.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591D1A63407400F3B66E /* HvSignalLine.c */; }; 90B848EB1D95CA310004BCE3 /* HvSignalLorenz.c in Sources */ = {isa = PBXBuildFile; fileRef = D88AD8F91C5EEFEC000AC60F /* HvSignalLorenz.c */; }; 90B848EC1D95CA310004BCE3 /* HvSignalPhasor.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591F1A63407400F3B66E /* HvSignalPhasor.c */; }; 90B848ED1D95CA310004BCE3 /* HvSignalRPole.c in Sources */ = {isa = PBXBuildFile; fileRef = 9015F0C51BDDB25300070222 /* HvSignalRPole.c */; }; 90B848EE1D95CA310004BCE3 /* HvSignalSamphold.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AC14541BD51F67006C126E /* HvSignalSamphold.c */; }; 90B848EF1D95CA310004BCE3 /* HvSignalSample.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59211A63407400F3B66E /* HvSignalSample.c */; }; 90B848F01D95CA310004BCE3 /* HvSignalTabread.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59231A63407400F3B66E /* HvSignalTabread.c */; }; 90B848F11D95CA310004BCE3 /* HvSignalTabwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59251A63407400F3B66E /* HvSignalTabwrite.c */; }; 90B848F21D95CA310004BCE3 /* HvSignalVar.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59271A63407400F3B66E /* HvSignalVar.c */; }; 90B848F31D95CA320004BCE3 /* HvHeavy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA0431D573C86002E49ED /* HvHeavy.cpp */; }; 90B848F41D95CA320004BCE3 /* HeavyContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA0451D573C86002E49ED /* HeavyContext.cpp */; }; 90B848F51D95CA320004BCE3 /* HvControlBinop.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58F71A63407400F3B66E /* HvControlBinop.c */; }; 90B848F61D95CA320004BCE3 /* HvControlCast.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58F91A63407400F3B66E /* HvControlCast.c */; }; 90B848F71D95CA320004BCE3 /* HvControlDelay.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FB1A63407400F3B66E /* HvControlDelay.c */; }; 90B848F81D95CA320004BCE3 /* HvControlIf.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FD1A63407400F3B66E /* HvControlIf.c */; }; 90B848F91D95CA320004BCE3 /* HvControlPack.c in Sources */ = {isa = PBXBuildFile; fileRef = D8A281EA1AEFC765004F8531 /* HvControlPack.c */; }; 90B848FA1D95CA320004BCE3 /* HvControlPrint.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FF1A63407400F3B66E /* HvControlPrint.c */; }; 90B848FB1D95CA320004BCE3 /* HvControlRandom.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59011A63407400F3B66E /* HvControlRandom.c */; }; 90B848FC1D95CA320004BCE3 /* HvControlSlice.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59031A63407400F3B66E /* HvControlSlice.c */; }; 90B848FD1D95CA320004BCE3 /* HvControlSystem.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59051A63407400F3B66E /* HvControlSystem.c */; }; 90B848FE1D95CA320004BCE3 /* HvControlTabhead.c in Sources */ = {isa = PBXBuildFile; fileRef = 90226C171A9F8DAD005D8253 /* HvControlTabhead.c */; }; 90B848FF1D95CA320004BCE3 /* HvControlTabread.c in Sources */ = {isa = PBXBuildFile; fileRef = 906FAB781AEF85C000B9F165 /* HvControlTabread.c */; }; 90B849001D95CA320004BCE3 /* HvControlTabwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 906FAB7D1AEF895E00B9F165 /* HvControlTabwrite.c */; }; 90B849011D95CA320004BCE3 /* HvControlUnop.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59071A63407400F3B66E /* HvControlUnop.c */; }; 90B849021D95CA320004BCE3 /* HvControlVar.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59091A63407400F3B66E /* HvControlVar.c */; }; 90B849031D95CA320004BCE3 /* HvLightPipe.c in Sources */ = {isa = PBXBuildFile; fileRef = 9088F1B81CB36DA600569945 /* HvLightPipe.c */; }; 90B849041D95CA320004BCE3 /* HvMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59111A63407400F3B66E /* HvMessage.c */; }; 90B849051D95CA320004BCE3 /* HvTable.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59131A63407400F3B66E /* HvTable.c */; }; 90B849061D95CA320004BCE3 /* HvMessagePool.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59151A63407400F3B66E /* HvMessagePool.c */; }; 90B849071D95CA320004BCE3 /* HvMessageQueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59171A63407400F3B66E /* HvMessageQueue.c */; }; 90B849081D95CA320004BCE3 /* HvSignalBiquad.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59191A63407400F3B66E /* HvSignalBiquad.c */; }; 90B849091D95CA320004BCE3 /* HvSignalConvolution.c in Sources */ = {isa = PBXBuildFile; fileRef = 90D200C01BC2AB6400E45A9D /* HvSignalConvolution.c */; }; 90B8490A1D95CA320004BCE3 /* HvSignalCPole.c in Sources */ = {isa = PBXBuildFile; fileRef = D89405DA1BE19A8300491551 /* HvSignalCPole.c */; }; 90B8490B1D95CA320004BCE3 /* HvSignalDel1.c in Sources */ = {isa = PBXBuildFile; fileRef = D8500AD81BD9B9D400D12C3A /* HvSignalDel1.c */; }; 90B8490C1D95CA320004BCE3 /* HvSignalEnvelope.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591B1A63407400F3B66E /* HvSignalEnvelope.c */; }; 90B8490D1D95CA320004BCE3 /* HvSignalLine.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591D1A63407400F3B66E /* HvSignalLine.c */; }; 90B8490E1D95CA320004BCE3 /* HvSignalLorenz.c in Sources */ = {isa = PBXBuildFile; fileRef = D88AD8F91C5EEFEC000AC60F /* HvSignalLorenz.c */; }; 90B8490F1D95CA320004BCE3 /* HvSignalPhasor.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591F1A63407400F3B66E /* HvSignalPhasor.c */; }; 90B849101D95CA320004BCE3 /* HvSignalRPole.c in Sources */ = {isa = PBXBuildFile; fileRef = 9015F0C51BDDB25300070222 /* HvSignalRPole.c */; }; 90B849111D95CA320004BCE3 /* HvSignalSamphold.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AC14541BD51F67006C126E /* HvSignalSamphold.c */; }; 90B849121D95CA320004BCE3 /* HvSignalSample.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59211A63407400F3B66E /* HvSignalSample.c */; }; 90B849131D95CA320004BCE3 /* HvSignalTabread.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59231A63407400F3B66E /* HvSignalTabread.c */; }; 90B849141D95CA320004BCE3 /* HvSignalTabwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59251A63407400F3B66E /* HvSignalTabwrite.c */; }; 90B849151D95CA320004BCE3 /* HvSignalVar.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59271A63407400F3B66E /* HvSignalVar.c */; }; 90B849161D95CA320004BCE3 /* HvHeavy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA0431D573C86002E49ED /* HvHeavy.cpp */; }; 90B849171D95CA320004BCE3 /* HeavyContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA0451D573C86002E49ED /* HeavyContext.cpp */; }; 90B849181D95CA320004BCE3 /* HvControlBinop.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58F71A63407400F3B66E /* HvControlBinop.c */; }; 90B849191D95CA320004BCE3 /* HvControlCast.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58F91A63407400F3B66E /* HvControlCast.c */; }; 90B8491A1D95CA320004BCE3 /* HvControlDelay.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FB1A63407400F3B66E /* HvControlDelay.c */; }; 90B8491B1D95CA320004BCE3 /* HvControlIf.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FD1A63407400F3B66E /* HvControlIf.c */; }; 90B8491C1D95CA320004BCE3 /* HvControlPack.c in Sources */ = {isa = PBXBuildFile; fileRef = D8A281EA1AEFC765004F8531 /* HvControlPack.c */; }; 90B8491D1D95CA320004BCE3 /* HvControlPrint.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA58FF1A63407400F3B66E /* HvControlPrint.c */; }; 90B8491E1D95CA320004BCE3 /* HvControlRandom.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59011A63407400F3B66E /* HvControlRandom.c */; }; 90B8491F1D95CA320004BCE3 /* HvControlSlice.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59031A63407400F3B66E /* HvControlSlice.c */; }; 90B849201D95CA320004BCE3 /* HvControlSystem.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59051A63407400F3B66E /* HvControlSystem.c */; }; 90B849211D95CA320004BCE3 /* HvControlTabhead.c in Sources */ = {isa = PBXBuildFile; fileRef = 90226C171A9F8DAD005D8253 /* HvControlTabhead.c */; }; 90B849221D95CA320004BCE3 /* HvControlTabread.c in Sources */ = {isa = PBXBuildFile; fileRef = 906FAB781AEF85C000B9F165 /* HvControlTabread.c */; }; 90B849231D95CA320004BCE3 /* HvControlTabwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 906FAB7D1AEF895E00B9F165 /* HvControlTabwrite.c */; }; 90B849241D95CA320004BCE3 /* HvControlUnop.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59071A63407400F3B66E /* HvControlUnop.c */; }; 90B849251D95CA320004BCE3 /* HvControlVar.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59091A63407400F3B66E /* HvControlVar.c */; }; 90B849261D95CA320004BCE3 /* HvLightPipe.c in Sources */ = {isa = PBXBuildFile; fileRef = 9088F1B81CB36DA600569945 /* HvLightPipe.c */; }; 90B849271D95CA320004BCE3 /* HvMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59111A63407400F3B66E /* HvMessage.c */; }; 90B849281D95CA320004BCE3 /* HvTable.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59131A63407400F3B66E /* HvTable.c */; }; 90B849291D95CA320004BCE3 /* HvMessagePool.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59151A63407400F3B66E /* HvMessagePool.c */; }; 90B8492A1D95CA320004BCE3 /* HvMessageQueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59171A63407400F3B66E /* HvMessageQueue.c */; }; 90B8492B1D95CA320004BCE3 /* HvSignalBiquad.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59191A63407400F3B66E /* HvSignalBiquad.c */; }; 90B8492C1D95CA320004BCE3 /* HvSignalConvolution.c in Sources */ = {isa = PBXBuildFile; fileRef = 90D200C01BC2AB6400E45A9D /* HvSignalConvolution.c */; }; 90B8492D1D95CA320004BCE3 /* HvSignalCPole.c in Sources */ = {isa = PBXBuildFile; fileRef = D89405DA1BE19A8300491551 /* HvSignalCPole.c */; }; 90B8492E1D95CA320004BCE3 /* HvSignalDel1.c in Sources */ = {isa = PBXBuildFile; fileRef = D8500AD81BD9B9D400D12C3A /* HvSignalDel1.c */; }; 90B8492F1D95CA320004BCE3 /* HvSignalEnvelope.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591B1A63407400F3B66E /* HvSignalEnvelope.c */; }; 90B849301D95CA320004BCE3 /* HvSignalLine.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591D1A63407400F3B66E /* HvSignalLine.c */; }; 90B849311D95CA320004BCE3 /* HvSignalLorenz.c in Sources */ = {isa = PBXBuildFile; fileRef = D88AD8F91C5EEFEC000AC60F /* HvSignalLorenz.c */; }; 90B849321D95CA320004BCE3 /* HvSignalPhasor.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA591F1A63407400F3B66E /* HvSignalPhasor.c */; }; 90B849331D95CA320004BCE3 /* HvSignalRPole.c in Sources */ = {isa = PBXBuildFile; fileRef = 9015F0C51BDDB25300070222 /* HvSignalRPole.c */; }; 90B849341D95CA320004BCE3 /* HvSignalSamphold.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AC14541BD51F67006C126E /* HvSignalSamphold.c */; }; 90B849351D95CA320004BCE3 /* HvSignalSample.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59211A63407400F3B66E /* HvSignalSample.c */; }; 90B849361D95CA320004BCE3 /* HvSignalTabread.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59231A63407400F3B66E /* HvSignalTabread.c */; }; 90B849371D95CA320004BCE3 /* HvSignalTabwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59251A63407400F3B66E /* HvSignalTabwrite.c */; }; 90B849381D95CA320004BCE3 /* HvSignalVar.c in Sources */ = {isa = PBXBuildFile; fileRef = 90AA59271A63407400F3B66E /* HvSignalVar.c */; }; 90B849391D95CAA80004BCE3 /* Heavy_heavy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA04A1D573D0F002E49ED /* Heavy_heavy.cpp */; }; 90B8493A1D95CAA90004BCE3 /* Heavy_heavy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA04A1D573D0F002E49ED /* Heavy_heavy.cpp */; }; 90FBA04E1D573DD3002E49ED /* Heavy_heavy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90FBA04A1D573D0F002E49ED /* Heavy_heavy.cpp */; }; D827FD591DF5BBB300FFB63E /* AudioEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = D827FD581DF5BBB300FFB63E /* AudioEngine.m */; }; D84C615119D1038F00D01F59 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D84C615019D1038F00D01F59 /* Cocoa.framework */; }; D84C615B19D1038F00D01F59 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D84C615919D1038F00D01F59 /* InfoPlist.strings */; }; D84C615D19D1038F00D01F59 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D84C615C19D1038F00D01F59 /* main.m */; }; D84C616119D1038F00D01F59 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = D84C615F19D1038F00D01F59 /* Credits.rtf */; }; D84C616419D1038F00D01F59 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D84C616319D1038F00D01F59 /* AppDelegate.m */; }; D84C616719D1038F00D01F59 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D84C616519D1038F00D01F59 /* MainMenu.xib */; }; D84C616919D1038F00D01F59 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D84C616819D1038F00D01F59 /* Images.xcassets */; }; D84C618519D1042000D01F59 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D84C618319D1042000D01F59 /* MainViewController.m */; }; D84C618619D1042000D01F59 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D84C618419D1042000D01F59 /* MainViewController.xib */; }; D8B4BE64198BC76B00987698 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = D8B4BE63198BC76B00987698 /* main.c */; }; D8B4BE66198BC76B00987698 /* Heavy.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = D8B4BE65198BC76B00987698 /* Heavy.1 */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ D8B4BE5E198BC76B00987698 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/share/man/man1/; dstSubfolderSpec = 0; files = ( D8B4BE66198BC76B00987698 /* Heavy.1 in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 900D61891AD9EFAD001BDB71 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; }; 900D618B1AD9F2AE001BDB71 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; 9015F0C51BDDB25300070222 /* HvSignalRPole.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalRPole.c; path = ../ir2c/static/HvSignalRPole.c; sourceTree = ""; }; 9015F0C61BDDB25300070222 /* HvSignalRPole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalRPole.h; path = ../ir2c/static/HvSignalRPole.h; sourceTree = ""; }; 90226C171A9F8DAD005D8253 /* HvControlTabhead.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlTabhead.c; path = ../ir2c/static/HvControlTabhead.c; sourceTree = ""; }; 90226C181A9F8DAD005D8253 /* HvControlTabhead.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlTabhead.h; path = ../ir2c/static/HvControlTabhead.h; sourceTree = ""; }; 9036C1AB1AD57CDF00C7B994 /* Heavy_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Heavy_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9036C1AE1AD57CDF00C7B994 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9036C1AF1AD57CDF00C7B994 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 9036C1B11AD57CDF00C7B994 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 9036C1B21AD57CDF00C7B994 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9036C1B41AD57CDF00C7B994 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 9036C1B51AD57CDF00C7B994 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 9036C1B81AD57CDF00C7B994 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 9036C1BA1AD57CDF00C7B994 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 9036C1BD1AD57CDF00C7B994 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 9036C1D11AD58B3A00C7B994 /* TPCircularBuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = TPCircularBuffer.c; sourceTree = ""; }; 9036C1D21AD58B3A00C7B994 /* TPCircularBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPCircularBuffer.h; sourceTree = ""; }; 9036C1D71AD58B9B00C7B994 /* HeavyAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeavyAudio.h; sourceTree = ""; }; 9036C1D81AD58B9B00C7B994 /* HeavyAudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HeavyAudio.m; sourceTree = ""; }; 905185D51D9E5BF20001CB5F /* HeavyContextInterface.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = HeavyContextInterface.hpp; path = ../ir2c/static/HeavyContextInterface.hpp; sourceTree = ""; }; 9053E1181D95519300D3B881 /* Heavy_heavy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Heavy_heavy.h; path = build/c/Heavy_heavy.h; sourceTree = ""; }; 9053E1191D95519300D3B881 /* Heavy_heavy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Heavy_heavy.hpp; path = build/c/Heavy_heavy.hpp; sourceTree = ""; }; 9053E11A1D95531C00D3B881 /* HeavyContext.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = HeavyContext.hpp; path = ../ir2c/static/HeavyContext.hpp; sourceTree = ""; }; 9053E11C1D9555C600D3B881 /* HvHeavyInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvHeavyInternal.h; path = ../ir2c/static/HvHeavyInternal.h; sourceTree = ""; }; 9053E11D1D95565000D3B881 /* Heavy_NAME.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Heavy_NAME.hpp; sourceTree = ""; }; 9059F9251BECEE5100589DE5 /* tinywav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tinywav.c; path = tinywav/tinywav.c; sourceTree = ""; }; 9059F9261BECEE5100589DE5 /* tinywav.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tinywav.h; path = tinywav/tinywav.h; sourceTree = ""; }; 906644F51E5E43F7007F4762 /* HvUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvUtils.c; path = ../ir2c/static/HvUtils.c; sourceTree = ""; }; 906FAB781AEF85C000B9F165 /* HvControlTabread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlTabread.c; path = ../ir2c/static/HvControlTabread.c; sourceTree = ""; }; 906FAB791AEF85C000B9F165 /* HvControlTabread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlTabread.h; path = ../ir2c/static/HvControlTabread.h; sourceTree = ""; }; 906FAB7D1AEF895E00B9F165 /* HvControlTabwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlTabwrite.c; path = ../ir2c/static/HvControlTabwrite.c; sourceTree = ""; }; 906FAB7E1AEF895E00B9F165 /* HvControlTabwrite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlTabwrite.h; path = ../ir2c/static/HvControlTabwrite.h; sourceTree = ""; }; 9088F1B81CB36DA600569945 /* HvLightPipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvLightPipe.c; path = ../ir2c/static/HvLightPipe.c; sourceTree = ""; }; 9088F1B91CB36DA600569945 /* HvLightPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvLightPipe.h; path = ../ir2c/static/HvLightPipe.h; sourceTree = ""; }; 90AA58F71A63407400F3B66E /* HvControlBinop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlBinop.c; path = ../ir2c/static/HvControlBinop.c; sourceTree = ""; }; 90AA58F81A63407400F3B66E /* HvControlBinop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlBinop.h; path = ../ir2c/static/HvControlBinop.h; sourceTree = ""; }; 90AA58F91A63407400F3B66E /* HvControlCast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlCast.c; path = ../ir2c/static/HvControlCast.c; sourceTree = ""; }; 90AA58FA1A63407400F3B66E /* HvControlCast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlCast.h; path = ../ir2c/static/HvControlCast.h; sourceTree = ""; }; 90AA58FB1A63407400F3B66E /* HvControlDelay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlDelay.c; path = ../ir2c/static/HvControlDelay.c; sourceTree = ""; }; 90AA58FC1A63407400F3B66E /* HvControlDelay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlDelay.h; path = ../ir2c/static/HvControlDelay.h; sourceTree = ""; }; 90AA58FD1A63407400F3B66E /* HvControlIf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlIf.c; path = ../ir2c/static/HvControlIf.c; sourceTree = ""; }; 90AA58FE1A63407400F3B66E /* HvControlIf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlIf.h; path = ../ir2c/static/HvControlIf.h; sourceTree = ""; }; 90AA58FF1A63407400F3B66E /* HvControlPrint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlPrint.c; path = ../ir2c/static/HvControlPrint.c; sourceTree = ""; }; 90AA59001A63407400F3B66E /* HvControlPrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlPrint.h; path = ../ir2c/static/HvControlPrint.h; sourceTree = ""; }; 90AA59011A63407400F3B66E /* HvControlRandom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlRandom.c; path = ../ir2c/static/HvControlRandom.c; sourceTree = ""; }; 90AA59021A63407400F3B66E /* HvControlRandom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlRandom.h; path = ../ir2c/static/HvControlRandom.h; sourceTree = ""; }; 90AA59031A63407400F3B66E /* HvControlSlice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlSlice.c; path = ../ir2c/static/HvControlSlice.c; sourceTree = ""; }; 90AA59041A63407400F3B66E /* HvControlSlice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlSlice.h; path = ../ir2c/static/HvControlSlice.h; sourceTree = ""; }; 90AA59051A63407400F3B66E /* HvControlSystem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlSystem.c; path = ../ir2c/static/HvControlSystem.c; sourceTree = ""; }; 90AA59061A63407400F3B66E /* HvControlSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlSystem.h; path = ../ir2c/static/HvControlSystem.h; sourceTree = ""; }; 90AA59071A63407400F3B66E /* HvControlUnop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlUnop.c; path = ../ir2c/static/HvControlUnop.c; sourceTree = ""; }; 90AA59081A63407400F3B66E /* HvControlUnop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlUnop.h; path = ../ir2c/static/HvControlUnop.h; sourceTree = ""; }; 90AA59091A63407400F3B66E /* HvControlVar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlVar.c; path = ../ir2c/static/HvControlVar.c; sourceTree = ""; }; 90AA590A1A63407400F3B66E /* HvControlVar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlVar.h; path = ../ir2c/static/HvControlVar.h; sourceTree = ""; }; 90AA590B1A63407400F3B66E /* cpuid.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpuid.c; path = ../ir2c/static/cpuid.c; sourceTree = ""; }; 90AA590C1A63407400F3B66E /* cpuid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpuid.h; path = ../ir2c/static/cpuid.h; sourceTree = ""; }; 90AA590E1A63407400F3B66E /* HvMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvMath.h; path = ../ir2c/static/HvMath.h; sourceTree = ""; }; 90AA59111A63407400F3B66E /* HvMessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvMessage.c; path = ../ir2c/static/HvMessage.c; sourceTree = ""; }; 90AA59121A63407400F3B66E /* HvMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvMessage.h; path = ../ir2c/static/HvMessage.h; sourceTree = ""; }; 90AA59131A63407400F3B66E /* HvTable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvTable.c; path = ../ir2c/static/HvTable.c; sourceTree = ""; }; 90AA59141A63407400F3B66E /* HvTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvTable.h; path = ../ir2c/static/HvTable.h; sourceTree = ""; }; 90AA59151A63407400F3B66E /* HvMessagePool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvMessagePool.c; path = ../ir2c/static/HvMessagePool.c; sourceTree = ""; }; 90AA59161A63407400F3B66E /* HvMessagePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvMessagePool.h; path = ../ir2c/static/HvMessagePool.h; sourceTree = ""; }; 90AA59171A63407400F3B66E /* HvMessageQueue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvMessageQueue.c; path = ../ir2c/static/HvMessageQueue.c; sourceTree = ""; }; 90AA59181A63407400F3B66E /* HvMessageQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvMessageQueue.h; path = ../ir2c/static/HvMessageQueue.h; sourceTree = ""; }; 90AA59191A63407400F3B66E /* HvSignalBiquad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalBiquad.c; path = ../ir2c/static/HvSignalBiquad.c; sourceTree = ""; }; 90AA591A1A63407400F3B66E /* HvSignalBiquad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalBiquad.h; path = ../ir2c/static/HvSignalBiquad.h; sourceTree = ""; }; 90AA591B1A63407400F3B66E /* HvSignalEnvelope.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalEnvelope.c; path = ../ir2c/static/HvSignalEnvelope.c; sourceTree = ""; }; 90AA591C1A63407400F3B66E /* HvSignalEnvelope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalEnvelope.h; path = ../ir2c/static/HvSignalEnvelope.h; sourceTree = ""; }; 90AA591D1A63407400F3B66E /* HvSignalLine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalLine.c; path = ../ir2c/static/HvSignalLine.c; sourceTree = ""; }; 90AA591E1A63407400F3B66E /* HvSignalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalLine.h; path = ../ir2c/static/HvSignalLine.h; sourceTree = ""; }; 90AA591F1A63407400F3B66E /* HvSignalPhasor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalPhasor.c; path = ../ir2c/static/HvSignalPhasor.c; sourceTree = ""; }; 90AA59201A63407400F3B66E /* HvSignalPhasor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalPhasor.h; path = ../ir2c/static/HvSignalPhasor.h; sourceTree = ""; }; 90AA59211A63407400F3B66E /* HvSignalSample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalSample.c; path = ../ir2c/static/HvSignalSample.c; sourceTree = ""; }; 90AA59221A63407400F3B66E /* HvSignalSample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalSample.h; path = ../ir2c/static/HvSignalSample.h; sourceTree = ""; }; 90AA59231A63407400F3B66E /* HvSignalTabread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalTabread.c; path = ../ir2c/static/HvSignalTabread.c; sourceTree = ""; }; 90AA59241A63407400F3B66E /* HvSignalTabread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalTabread.h; path = ../ir2c/static/HvSignalTabread.h; sourceTree = ""; }; 90AA59251A63407400F3B66E /* HvSignalTabwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalTabwrite.c; path = ../ir2c/static/HvSignalTabwrite.c; sourceTree = ""; }; 90AA59261A63407400F3B66E /* HvSignalTabwrite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalTabwrite.h; path = ../ir2c/static/HvSignalTabwrite.h; sourceTree = ""; }; 90AA59271A63407400F3B66E /* HvSignalVar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalVar.c; path = ../ir2c/static/HvSignalVar.c; sourceTree = ""; }; 90AA59281A63407400F3B66E /* HvSignalVar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalVar.h; path = ../ir2c/static/HvSignalVar.h; sourceTree = ""; }; 90AA592F1A63407400F3B66E /* HvUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvUtils.h; path = ../ir2c/static/HvUtils.h; sourceTree = ""; }; 90AC14541BD51F67006C126E /* HvSignalSamphold.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalSamphold.c; path = ../ir2c/static/HvSignalSamphold.c; sourceTree = ""; }; 90AC14551BD51F67006C126E /* HvSignalSamphold.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalSamphold.h; path = ../ir2c/static/HvSignalSamphold.h; sourceTree = ""; }; 90B848C31D95C8E60004BCE3 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; 90B848C51D95C8EB0004BCE3 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 90D200C01BC2AB6400E45A9D /* HvSignalConvolution.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalConvolution.c; path = ../ir2c/static/HvSignalConvolution.c; sourceTree = ""; }; 90D200C11BC2AB6400E45A9D /* HvSignalConvolution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalConvolution.h; path = ../ir2c/static/HvSignalConvolution.h; sourceTree = ""; }; 90FBA03E1D573C63002E49ED /* Heavy_NAME.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Heavy_NAME.cpp; sourceTree = ""; }; 90FBA03F1D573C63002E49ED /* Heavy_NAME.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Heavy_NAME.h; sourceTree = ""; }; 90FBA0431D573C86002E49ED /* HvHeavy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HvHeavy.cpp; path = ../ir2c/static/HvHeavy.cpp; sourceTree = ""; }; 90FBA0441D573C86002E49ED /* HvHeavy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvHeavy.h; path = ../ir2c/static/HvHeavy.h; sourceTree = ""; }; 90FBA0451D573C86002E49ED /* HeavyContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HeavyContext.cpp; path = ../ir2c/static/HeavyContext.cpp; sourceTree = ""; }; 90FBA04A1D573D0F002E49ED /* Heavy_heavy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Heavy_heavy.cpp; path = build/c/Heavy_heavy.cpp; sourceTree = ""; }; D827FD581DF5BBB300FFB63E /* AudioEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioEngine.m; sourceTree = ""; }; D84C614E19D1038F00D01F59 /* Heavy_OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Heavy_OSX.app; sourceTree = BUILT_PRODUCTS_DIR; }; D84C615019D1038F00D01F59 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; D84C615319D1038F00D01F59 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; D84C615419D1038F00D01F59 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; D84C615519D1038F00D01F59 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; D84C615819D1038F00D01F59 /* Heavy_OSX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Heavy_OSX-Info.plist"; sourceTree = ""; }; D84C615A19D1038F00D01F59 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; D84C615C19D1038F00D01F59 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; D84C615E19D1038F00D01F59 /* Heavy_OSX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Heavy_OSX-Prefix.pch"; sourceTree = ""; }; D84C616019D1038F00D01F59 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; D84C616219D1038F00D01F59 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; D84C616319D1038F00D01F59 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; D84C616619D1038F00D01F59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; D84C616819D1038F00D01F59 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; D84C616F19D1038F00D01F59 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; D84C618219D1042000D01F59 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; D84C618319D1042000D01F59 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; D84C618419D1042000D01F59 /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; D84C618719D104F800D01F59 /* AudioEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioEngine.h; sourceTree = ""; }; D8500AD81BD9B9D400D12C3A /* HvSignalDel1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalDel1.c; path = ../ir2c/static/HvSignalDel1.c; sourceTree = ""; }; D8500AD91BD9B9D400D12C3A /* HvSignalDel1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalDel1.h; path = ../ir2c/static/HvSignalDel1.h; sourceTree = ""; }; D88AD8F91C5EEFEC000AC60F /* HvSignalLorenz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalLorenz.c; path = ../ir2c/static/HvSignalLorenz.c; sourceTree = ""; }; D88AD8FA1C5EEFEC000AC60F /* HvSignalLorenz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalLorenz.h; path = ../ir2c/static/HvSignalLorenz.h; sourceTree = ""; }; D89405DA1BE19A8300491551 /* HvSignalCPole.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvSignalCPole.c; path = ../ir2c/static/HvSignalCPole.c; sourceTree = ""; }; D89405DB1BE19A8300491551 /* HvSignalCPole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvSignalCPole.h; path = ../ir2c/static/HvSignalCPole.h; sourceTree = ""; }; D8A281EA1AEFC765004F8531 /* HvControlPack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = HvControlPack.c; path = ../ir2c/static/HvControlPack.c; sourceTree = ""; }; D8A281EB1AEFC765004F8531 /* HvControlPack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HvControlPack.h; path = ../ir2c/static/HvControlPack.h; sourceTree = ""; }; D8B4BE60198BC76B00987698 /* Heavy_CmdLine */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Heavy_CmdLine; sourceTree = BUILT_PRODUCTS_DIR; }; D8B4BE63198BC76B00987698 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; D8B4BE65198BC76B00987698 /* Heavy.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = Heavy.1; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 9036C1A81AD57CDF00C7B994 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 900D618C1AD9F2AE001BDB71 /* AVFoundation.framework in Frameworks */, 900D618A1AD9EFAD001BDB71 /* Accelerate.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D84C614B19D1038F00D01F59 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 90B848C61D95C8EB0004BCE3 /* Accelerate.framework in Frameworks */, 90B848C41D95C8E60004BCE3 /* AudioUnit.framework in Frameworks */, D84C615119D1038F00D01F59 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D8B4BE5D198BC76B00987698 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 9036C1AC1AD57CDF00C7B994 /* Heavy_iOS */ = { isa = PBXGroup; children = ( 9036C1B11AD57CDF00C7B994 /* AppDelegate.h */, 9036C1B21AD57CDF00C7B994 /* AppDelegate.m */, 9036C1B41AD57CDF00C7B994 /* ViewController.h */, 9036C1B51AD57CDF00C7B994 /* ViewController.m */, 9036C1D11AD58B3A00C7B994 /* TPCircularBuffer.c */, 9036C1D21AD58B3A00C7B994 /* TPCircularBuffer.h */, 9036C1D71AD58B9B00C7B994 /* HeavyAudio.h */, 9036C1D81AD58B9B00C7B994 /* HeavyAudio.m */, 9036C1B71AD57CDF00C7B994 /* Main.storyboard */, 9036C1BA1AD57CDF00C7B994 /* Images.xcassets */, 9036C1BC1AD57CDF00C7B994 /* LaunchScreen.xib */, 9036C1AD1AD57CDF00C7B994 /* Supporting Files */, ); path = Heavy_iOS; sourceTree = ""; }; 9036C1AD1AD57CDF00C7B994 /* Supporting Files */ = { isa = PBXGroup; children = ( 9036C1AE1AD57CDF00C7B994 /* Info.plist */, 9036C1AF1AD57CDF00C7B994 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 9059F9211BECD62F00589DE5 /* tinywav */ = { isa = PBXGroup; children = ( 9059F9251BECEE5100589DE5 /* tinywav.c */, 9059F9261BECEE5100589DE5 /* tinywav.h */, ); name = tinywav; sourceTree = ""; }; D84C614F19D1038F00D01F59 /* Frameworks */ = { isa = PBXGroup; children = ( 90B848C51D95C8EB0004BCE3 /* Accelerate.framework */, 90B848C31D95C8E60004BCE3 /* AudioUnit.framework */, 900D618B1AD9F2AE001BDB71 /* AVFoundation.framework */, 900D61891AD9EFAD001BDB71 /* Accelerate.framework */, D84C615019D1038F00D01F59 /* Cocoa.framework */, D84C616F19D1038F00D01F59 /* XCTest.framework */, D84C615219D1038F00D01F59 /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; D84C615219D1038F00D01F59 /* Other Frameworks */ = { isa = PBXGroup; children = ( D84C615319D1038F00D01F59 /* AppKit.framework */, D84C615419D1038F00D01F59 /* CoreData.framework */, D84C615519D1038F00D01F59 /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; D84C615619D1038F00D01F59 /* Heavy_OSX */ = { isa = PBXGroup; children = ( 9059F9211BECD62F00589DE5 /* tinywav */, D84C616219D1038F00D01F59 /* AppDelegate.h */, D84C616319D1038F00D01F59 /* AppDelegate.m */, D84C616519D1038F00D01F59 /* MainMenu.xib */, D84C618219D1042000D01F59 /* MainViewController.h */, D84C618319D1042000D01F59 /* MainViewController.m */, D84C618419D1042000D01F59 /* MainViewController.xib */, D84C618719D104F800D01F59 /* AudioEngine.h */, D827FD581DF5BBB300FFB63E /* AudioEngine.m */, D84C616819D1038F00D01F59 /* Images.xcassets */, D84C615719D1038F00D01F59 /* Supporting Files */, ); path = Heavy_OSX; sourceTree = ""; }; D84C615719D1038F00D01F59 /* Supporting Files */ = { isa = PBXGroup; children = ( D84C615819D1038F00D01F59 /* Heavy_OSX-Info.plist */, D84C615919D1038F00D01F59 /* InfoPlist.strings */, D84C615C19D1038F00D01F59 /* main.m */, D84C615E19D1038F00D01F59 /* Heavy_OSX-Prefix.pch */, D84C615F19D1038F00D01F59 /* Credits.rtf */, ); name = "Supporting Files"; sourceTree = ""; }; D861EF351990F95300F7C7A7 /* generated */ = { isa = PBXGroup; children = ( 9053E1181D95519300D3B881 /* Heavy_heavy.h */, 9053E1191D95519300D3B881 /* Heavy_heavy.hpp */, 90FBA04A1D573D0F002E49ED /* Heavy_heavy.cpp */, ); name = generated; sourceTree = ""; }; D881D57319915025009CAC78 /* templates */ = { isa = PBXGroup; children = ( 9053E11D1D95565000D3B881 /* Heavy_NAME.hpp */, 90FBA03E1D573C63002E49ED /* Heavy_NAME.cpp */, 90FBA03F1D573C63002E49ED /* Heavy_NAME.h */, ); name = templates; path = ../ir2c/templates; sourceTree = ""; }; D8B4BE57198BC76B00987698 = { isa = PBXGroup; children = ( D8B4BE62198BC76B00987698 /* Heavy_CmdLine */, D84C615619D1038F00D01F59 /* Heavy_OSX */, 9036C1AC1AD57CDF00C7B994 /* Heavy_iOS */, D8B4BE6C198BC84600987698 /* Heavy */, D84C614F19D1038F00D01F59 /* Frameworks */, D8B4BE61198BC76B00987698 /* Products */, ); sourceTree = ""; }; D8B4BE61198BC76B00987698 /* Products */ = { isa = PBXGroup; children = ( D8B4BE60198BC76B00987698 /* Heavy_CmdLine */, D84C614E19D1038F00D01F59 /* Heavy_OSX.app */, 9036C1AB1AD57CDF00C7B994 /* Heavy_iOS.app */, ); name = Products; sourceTree = ""; }; D8B4BE62198BC76B00987698 /* Heavy_CmdLine */ = { isa = PBXGroup; children = ( D8B4BE63198BC76B00987698 /* main.c */, D8B4BE65198BC76B00987698 /* Heavy.1 */, ); name = Heavy_CmdLine; path = Heavy; sourceTree = ""; }; D8B4BE6C198BC84600987698 /* Heavy */ = { isa = PBXGroup; children = ( D881D57319915025009CAC78 /* templates */, D861EF351990F95300F7C7A7 /* generated */, D8B4BE6D198BC85D00987698 /* static */, ); name = Heavy; sourceTree = ""; }; D8B4BE6D198BC85D00987698 /* static */ = { isa = PBXGroup; children = ( 905185D51D9E5BF20001CB5F /* HeavyContextInterface.hpp */, 9053E11C1D9555C600D3B881 /* HvHeavyInternal.h */, 90FBA0431D573C86002E49ED /* HvHeavy.cpp */, 90FBA0441D573C86002E49ED /* HvHeavy.h */, 90FBA0451D573C86002E49ED /* HeavyContext.cpp */, 9053E11A1D95531C00D3B881 /* HeavyContext.hpp */, 90AA58F71A63407400F3B66E /* HvControlBinop.c */, 90AA58F81A63407400F3B66E /* HvControlBinop.h */, 90AA58F91A63407400F3B66E /* HvControlCast.c */, 90AA58FA1A63407400F3B66E /* HvControlCast.h */, 90AA58FB1A63407400F3B66E /* HvControlDelay.c */, 90AA58FC1A63407400F3B66E /* HvControlDelay.h */, 90AA58FD1A63407400F3B66E /* HvControlIf.c */, 90AA58FE1A63407400F3B66E /* HvControlIf.h */, D8A281EA1AEFC765004F8531 /* HvControlPack.c */, D8A281EB1AEFC765004F8531 /* HvControlPack.h */, 90AA58FF1A63407400F3B66E /* HvControlPrint.c */, 90AA59001A63407400F3B66E /* HvControlPrint.h */, 90AA59011A63407400F3B66E /* HvControlRandom.c */, 90AA59021A63407400F3B66E /* HvControlRandom.h */, 90AA59031A63407400F3B66E /* HvControlSlice.c */, 90AA59041A63407400F3B66E /* HvControlSlice.h */, 90AA59051A63407400F3B66E /* HvControlSystem.c */, 90AA59061A63407400F3B66E /* HvControlSystem.h */, 90226C171A9F8DAD005D8253 /* HvControlTabhead.c */, 90226C181A9F8DAD005D8253 /* HvControlTabhead.h */, 906FAB781AEF85C000B9F165 /* HvControlTabread.c */, 906FAB791AEF85C000B9F165 /* HvControlTabread.h */, 906FAB7D1AEF895E00B9F165 /* HvControlTabwrite.c */, 906FAB7E1AEF895E00B9F165 /* HvControlTabwrite.h */, 90AA59071A63407400F3B66E /* HvControlUnop.c */, 90AA59081A63407400F3B66E /* HvControlUnop.h */, 90AA59091A63407400F3B66E /* HvControlVar.c */, 90AA590A1A63407400F3B66E /* HvControlVar.h */, 90AA590B1A63407400F3B66E /* cpuid.c */, 90AA590C1A63407400F3B66E /* cpuid.h */, 90AA590E1A63407400F3B66E /* HvMath.h */, 9088F1B81CB36DA600569945 /* HvLightPipe.c */, 9088F1B91CB36DA600569945 /* HvLightPipe.h */, 90AA59111A63407400F3B66E /* HvMessage.c */, 90AA59121A63407400F3B66E /* HvMessage.h */, 90AA59131A63407400F3B66E /* HvTable.c */, 90AA59141A63407400F3B66E /* HvTable.h */, 90AA59151A63407400F3B66E /* HvMessagePool.c */, 90AA59161A63407400F3B66E /* HvMessagePool.h */, 90AA59171A63407400F3B66E /* HvMessageQueue.c */, 90AA59181A63407400F3B66E /* HvMessageQueue.h */, 90AA59191A63407400F3B66E /* HvSignalBiquad.c */, 90AA591A1A63407400F3B66E /* HvSignalBiquad.h */, 90D200C01BC2AB6400E45A9D /* HvSignalConvolution.c */, 90D200C11BC2AB6400E45A9D /* HvSignalConvolution.h */, D89405DA1BE19A8300491551 /* HvSignalCPole.c */, D89405DB1BE19A8300491551 /* HvSignalCPole.h */, D8500AD81BD9B9D400D12C3A /* HvSignalDel1.c */, D8500AD91BD9B9D400D12C3A /* HvSignalDel1.h */, 90AA591B1A63407400F3B66E /* HvSignalEnvelope.c */, 90AA591C1A63407400F3B66E /* HvSignalEnvelope.h */, 90AA591D1A63407400F3B66E /* HvSignalLine.c */, 90AA591E1A63407400F3B66E /* HvSignalLine.h */, D88AD8F91C5EEFEC000AC60F /* HvSignalLorenz.c */, D88AD8FA1C5EEFEC000AC60F /* HvSignalLorenz.h */, 90AA591F1A63407400F3B66E /* HvSignalPhasor.c */, 90AA59201A63407400F3B66E /* HvSignalPhasor.h */, 9015F0C51BDDB25300070222 /* HvSignalRPole.c */, 9015F0C61BDDB25300070222 /* HvSignalRPole.h */, 90AC14541BD51F67006C126E /* HvSignalSamphold.c */, 90AC14551BD51F67006C126E /* HvSignalSamphold.h */, 90AA59211A63407400F3B66E /* HvSignalSample.c */, 90AA59221A63407400F3B66E /* HvSignalSample.h */, 90AA59231A63407400F3B66E /* HvSignalTabread.c */, 90AA59241A63407400F3B66E /* HvSignalTabread.h */, 90AA59251A63407400F3B66E /* HvSignalTabwrite.c */, 90AA59261A63407400F3B66E /* HvSignalTabwrite.h */, 90AA59271A63407400F3B66E /* HvSignalVar.c */, 90AA59281A63407400F3B66E /* HvSignalVar.h */, 90AA592F1A63407400F3B66E /* HvUtils.h */, 906644F51E5E43F7007F4762 /* HvUtils.c */, ); name = static; path = ../static; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 9036C1AA1AD57CDF00C7B994 /* Heavy_iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 9036C1CF1AD57CDF00C7B994 /* Build configuration list for PBXNativeTarget "Heavy_iOS" */; buildPhases = ( 900D616D1AD9ED8E001BDB71 /* ShellScript */, 9036C1A71AD57CDF00C7B994 /* Sources */, 9036C1A81AD57CDF00C7B994 /* Frameworks */, 9036C1A91AD57CDF00C7B994 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = Heavy_iOS; productName = Heavy_iOS; productReference = 9036C1AB1AD57CDF00C7B994 /* Heavy_iOS.app */; productType = "com.apple.product-type.application"; }; D84C614D19D1038F00D01F59 /* Heavy_OSX */ = { isa = PBXNativeTarget; buildConfigurationList = D84C617C19D1038F00D01F59 /* Build configuration list for PBXNativeTarget "Heavy_OSX" */; buildPhases = ( D84C619B19D1087100D01F59 /* Run Script */, D84C614A19D1038F00D01F59 /* Sources */, D84C614B19D1038F00D01F59 /* Frameworks */, D84C614C19D1038F00D01F59 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = Heavy_OSX; productName = Heavy_OSX; productReference = D84C614E19D1038F00D01F59 /* Heavy_OSX.app */; productType = "com.apple.product-type.application"; }; D8B4BE5F198BC76B00987698 /* Heavy_CmdLine */ = { isa = PBXNativeTarget; buildConfigurationList = D8B4BE69198BC76B00987698 /* Build configuration list for PBXNativeTarget "Heavy_CmdLine" */; buildPhases = ( D8B4BE8F198BD4EA00987698 /* Run Script */, D8B4BE5C198BC76B00987698 /* Sources */, D8B4BE5D198BC76B00987698 /* Frameworks */, D8B4BE5E198BC76B00987698 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = Heavy_CmdLine; productName = Heavy; productReference = D8B4BE60198BC76B00987698 /* Heavy_CmdLine */; productType = "com.apple.product-type.tool"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D8B4BE58198BC76B00987698 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0800; ORGANIZATIONNAME = section6; TargetAttributes = { 9036C1AA1AD57CDF00C7B994 = { CreatedOnToolsVersion = 6.2; }; }; }; buildConfigurationList = D8B4BE5B198BC76B00987698 /* Build configuration list for PBXProject "Heavy" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = D8B4BE57198BC76B00987698; productRefGroup = D8B4BE61198BC76B00987698 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D8B4BE5F198BC76B00987698 /* Heavy_CmdLine */, D84C614D19D1038F00D01F59 /* Heavy_OSX */, 9036C1AA1AD57CDF00C7B994 /* Heavy_iOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 9036C1A91AD57CDF00C7B994 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 9036C1B91AD57CDF00C7B994 /* Main.storyboard in Resources */, 9036C1BE1AD57CDF00C7B994 /* LaunchScreen.xib in Resources */, 9036C1BB1AD57CDF00C7B994 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; D84C614C19D1038F00D01F59 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D84C615B19D1038F00D01F59 /* InfoPlist.strings in Resources */, D84C616919D1038F00D01F59 /* Images.xcassets in Resources */, D84C618619D1042000D01F59 /* MainViewController.xib in Resources */, D84C616119D1038F00D01F59 /* Credits.rtf in Resources */, D84C616719D1038F00D01F59 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 900D616D1AD9ED8E001BDB71 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /usr/bin/python; shellScript = "#!/usr/bin/python\n\nimport os\nimport sys\n\n_PROJ_ROOT = os.environ[\"SRCROOT\"]\nsys.path.append(os.path.join(_PROJ_ROOT, \"../../\"))\nimport hvcc\n\ndef main():\n pd_path = \"/Users/mhroth/Desktop/test_osc.pd\"\n output_dir = os.path.join(_PROJ_ROOT, \"build\")\n hvcc_results = hvcc.compile_dataflow(in_path=pd_path, out_dir=output_dir, generators=[\"c\"], verbose=False)\n for r in hvcc_results.values():\n if r[\"notifs\"].get(\"has_error\", False):\n print r[\"stage\"], \"returned error:\"\n for error in hvcc_results[\"pd2hv\"][\"notifs\"][\"errors\"]:\n print \"\\t\", error[\"message\"]\n sys.exit(1)\n\nif __name__ == \"__main__\":\n main()\n"; }; D84C619B19D1087100D01F59 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /usr/bin/python; shellScript = "#!/usr/bin/python\n\nimport os\nimport sys\n\n_PROJ_ROOT = os.environ[\"SRCROOT\"]\nsys.path.append(os.path.join(_PROJ_ROOT, \"../../\"))\nimport hvcc\n\ndef main():\n pd_path = \"/Users/joe/Desktop/Unity Project/Assets/Patches/sine/_main.pd\"\n output_dir = os.path.join(_PROJ_ROOT, \"build\")\n hvcc_results = hvcc.compile_dataflow(in_path=pd_path, out_dir=output_dir, generators=[\"c\"], verbose=False)\n for r in hvcc_results.values():\n if r[\"notifs\"].get(\"has_error\", False):\n print r[\"stage\"], \"returned error:\"\n for error in hvcc_results[\"pd2hv\"][\"notifs\"][\"errors\"]:\n print \"\\t\", error[\"message\"]\n sys.exit(1)\n\nif __name__ == \"__main__\":\n main()\n"; }; D8B4BE8F198BD4EA00987698 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /usr/bin/python; shellScript = "#!/usr/bin/python\n\nimport os\nimport sys\n\n_PROJ_ROOT = os.environ[\"SRCROOT\"]\nsys.path.append(os.path.join(_PROJ_ROOT, \"../../\"))\nimport hvcc\n\ndef main():\n pd_path = \"/Users/mhroth/Desktop/e_cos.pd\"\n output_dir = os.path.join(_PROJ_ROOT, \"build\")\n hvcc_results = hvcc.compile_dataflow(in_path=pd_path, out_dir=output_dir, generators=[\"c\"], verbose=False)\n for r in hvcc_results.values():\n if r[\"notifs\"].get(\"has_error\", False):\n print r[\"stage\"], \"returned error:\"\n for error in hvcc_results[\"pd2hv\"][\"notifs\"][\"errors\"]:\n print \"\\t\", error[\"message\"]\n sys.exit(1)\n\nif __name__ == \"__main__\":\n main()\n # pass"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 9036C1A71AD57CDF00C7B994 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 90B849351D95CA320004BCE3 /* HvSignalSample.c in Sources */, 90B8493A1D95CAA90004BCE3 /* Heavy_heavy.cpp in Sources */, 90B849211D95CA320004BCE3 /* HvControlTabhead.c in Sources */, 90B8492E1D95CA320004BCE3 /* HvSignalDel1.c in Sources */, 90B849381D95CA320004BCE3 /* HvSignalVar.c in Sources */, 90B849241D95CA320004BCE3 /* HvControlUnop.c in Sources */, 90B849301D95CA320004BCE3 /* HvSignalLine.c in Sources */, 90B849181D95CA320004BCE3 /* HvControlBinop.c in Sources */, 9036C1B61AD57CDF00C7B994 /* ViewController.m in Sources */, 90B8491C1D95CA320004BCE3 /* HvControlPack.c in Sources */, 90B849341D95CA320004BCE3 /* HvSignalSamphold.c in Sources */, 90B8491B1D95CA320004BCE3 /* HvControlIf.c in Sources */, 90B849321D95CA320004BCE3 /* HvSignalPhasor.c in Sources */, 90B8492C1D95CA320004BCE3 /* HvSignalConvolution.c in Sources */, 90B8492F1D95CA320004BCE3 /* HvSignalEnvelope.c in Sources */, 9036C1B31AD57CDF00C7B994 /* AppDelegate.m in Sources */, 9036C1D91AD58B9B00C7B994 /* HeavyAudio.m in Sources */, 90B849281D95CA320004BCE3 /* HvTable.c in Sources */, 90B8492A1D95CA320004BCE3 /* HvMessageQueue.c in Sources */, 90B849261D95CA320004BCE3 /* HvLightPipe.c in Sources */, 90B849201D95CA320004BCE3 /* HvControlSystem.c in Sources */, 90B8492B1D95CA320004BCE3 /* HvSignalBiquad.c in Sources */, 90B8491D1D95CA320004BCE3 /* HvControlPrint.c in Sources */, 906644F81E5E43F7007F4762 /* HvUtils.c in Sources */, 90B849171D95CA320004BCE3 /* HeavyContext.cpp in Sources */, 90B849331D95CA320004BCE3 /* HvSignalRPole.c in Sources */, 90B8491E1D95CA320004BCE3 /* HvControlRandom.c in Sources */, 90B849291D95CA320004BCE3 /* HvMessagePool.c in Sources */, 90B849221D95CA320004BCE3 /* HvControlTabread.c in Sources */, 90B849271D95CA320004BCE3 /* HvMessage.c in Sources */, 90B849251D95CA320004BCE3 /* HvControlVar.c in Sources */, 90B8491F1D95CA320004BCE3 /* HvControlSlice.c in Sources */, 90B849311D95CA320004BCE3 /* HvSignalLorenz.c in Sources */, 90B8492D1D95CA320004BCE3 /* HvSignalCPole.c in Sources */, 9036C1D51AD58B3A00C7B994 /* TPCircularBuffer.c in Sources */, 90B849371D95CA320004BCE3 /* HvSignalTabwrite.c in Sources */, 9036C1B01AD57CDF00C7B994 /* main.m in Sources */, 90B849231D95CA320004BCE3 /* HvControlTabwrite.c in Sources */, 90B8491A1D95CA320004BCE3 /* HvControlDelay.c in Sources */, 90B849361D95CA320004BCE3 /* HvSignalTabread.c in Sources */, 90B849161D95CA320004BCE3 /* HvHeavy.cpp in Sources */, 90B849191D95CA320004BCE3 /* HvControlCast.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D84C614A19D1038F00D01F59 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 90B848FC1D95CA320004BCE3 /* HvControlSlice.c in Sources */, 90B849391D95CAA80004BCE3 /* Heavy_heavy.cpp in Sources */, 90B848F81D95CA320004BCE3 /* HvControlIf.c in Sources */, 90B849101D95CA320004BCE3 /* HvSignalRPole.c in Sources */, 90B848FB1D95CA320004BCE3 /* HvControlRandom.c in Sources */, 90B8490F1D95CA320004BCE3 /* HvSignalPhasor.c in Sources */, 90B849081D95CA320004BCE3 /* HvSignalBiquad.c in Sources */, 90B8490E1D95CA320004BCE3 /* HvSignalLorenz.c in Sources */, D84C616419D1038F00D01F59 /* AppDelegate.m in Sources */, 90B848F71D95CA320004BCE3 /* HvControlDelay.c in Sources */, 90B848F61D95CA320004BCE3 /* HvControlCast.c in Sources */, 90B848FE1D95CA320004BCE3 /* HvControlTabhead.c in Sources */, D84C618519D1042000D01F59 /* MainViewController.m in Sources */, 90B849001D95CA320004BCE3 /* HvControlTabwrite.c in Sources */, 90B849111D95CA320004BCE3 /* HvSignalSamphold.c in Sources */, 90B848F41D95CA320004BCE3 /* HeavyContext.cpp in Sources */, 90B8490D1D95CA320004BCE3 /* HvSignalLine.c in Sources */, 90B849031D95CA320004BCE3 /* HvLightPipe.c in Sources */, 90B8490A1D95CA320004BCE3 /* HvSignalCPole.c in Sources */, 90B848F51D95CA320004BCE3 /* HvControlBinop.c in Sources */, 90B848F91D95CA320004BCE3 /* HvControlPack.c in Sources */, 90B849151D95CA320004BCE3 /* HvSignalVar.c in Sources */, 90B849021D95CA320004BCE3 /* HvControlVar.c in Sources */, 906644F71E5E43F7007F4762 /* HvUtils.c in Sources */, 90B849041D95CA320004BCE3 /* HvMessage.c in Sources */, 90B849121D95CA320004BCE3 /* HvSignalSample.c in Sources */, 90B848FD1D95CA320004BCE3 /* HvControlSystem.c in Sources */, 90B849011D95CA320004BCE3 /* HvControlUnop.c in Sources */, 90B848FA1D95CA320004BCE3 /* HvControlPrint.c in Sources */, 90B849091D95CA320004BCE3 /* HvSignalConvolution.c in Sources */, 90B849131D95CA320004BCE3 /* HvSignalTabread.c in Sources */, 9059F9271BECEE5100589DE5 /* tinywav.c in Sources */, 90B849051D95CA320004BCE3 /* HvTable.c in Sources */, 90B849061D95CA320004BCE3 /* HvMessagePool.c in Sources */, D827FD591DF5BBB300FFB63E /* AudioEngine.m in Sources */, 90B849071D95CA320004BCE3 /* HvMessageQueue.c in Sources */, 90B849141D95CA320004BCE3 /* HvSignalTabwrite.c in Sources */, 90B848F31D95CA320004BCE3 /* HvHeavy.cpp in Sources */, 90B8490B1D95CA320004BCE3 /* HvSignalDel1.c in Sources */, 90B8490C1D95CA320004BCE3 /* HvSignalEnvelope.c in Sources */, 90B848FF1D95CA320004BCE3 /* HvControlTabread.c in Sources */, D84C615D19D1038F00D01F59 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D8B4BE5C198BC76B00987698 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 90B848E61D95CA310004BCE3 /* HvSignalConvolution.c in Sources */, 90B848DD1D95CA310004BCE3 /* HvControlTabwrite.c in Sources */, 90B848E41D95CA310004BCE3 /* HvMessageQueue.c in Sources */, 90B848D61D95CA310004BCE3 /* HvControlPack.c in Sources */, D8B4BE64198BC76B00987698 /* main.c in Sources */, 90B848D11D95CA310004BCE3 /* HeavyContext.cpp in Sources */, 90B848EB1D95CA310004BCE3 /* HvSignalLorenz.c in Sources */, 90B848D91D95CA310004BCE3 /* HvControlSlice.c in Sources */, 90AA59441A63407400F3B66E /* cpuid.c in Sources */, 90B848E31D95CA310004BCE3 /* HvMessagePool.c in Sources */, 90B848EC1D95CA310004BCE3 /* HvSignalPhasor.c in Sources */, 90B848DC1D95CA310004BCE3 /* HvControlTabread.c in Sources */, 90B848D51D95CA310004BCE3 /* HvControlIf.c in Sources */, 90B848F01D95CA310004BCE3 /* HvSignalTabread.c in Sources */, 90B848F11D95CA310004BCE3 /* HvSignalTabwrite.c in Sources */, 90B848E91D95CA310004BCE3 /* HvSignalEnvelope.c in Sources */, 90FBA04E1D573DD3002E49ED /* Heavy_heavy.cpp in Sources */, 90B848D31D95CA310004BCE3 /* HvControlCast.c in Sources */, 90B848DA1D95CA310004BCE3 /* HvControlSystem.c in Sources */, 90B848D21D95CA310004BCE3 /* HvControlBinop.c in Sources */, 90B848E11D95CA310004BCE3 /* HvMessage.c in Sources */, 90B848F21D95CA310004BCE3 /* HvSignalVar.c in Sources */, 90B848DB1D95CA310004BCE3 /* HvControlTabhead.c in Sources */, 90B848D71D95CA310004BCE3 /* HvControlPrint.c in Sources */, 90B848E01D95CA310004BCE3 /* HvLightPipe.c in Sources */, 90B848E71D95CA310004BCE3 /* HvSignalCPole.c in Sources */, 906644F61E5E43F7007F4762 /* HvUtils.c in Sources */, 90B848EA1D95CA310004BCE3 /* HvSignalLine.c in Sources */, 90B848D01D95CA310004BCE3 /* HvHeavy.cpp in Sources */, 90B848D81D95CA310004BCE3 /* HvControlRandom.c in Sources */, 90B848D41D95CA310004BCE3 /* HvControlDelay.c in Sources */, 90B848E51D95CA310004BCE3 /* HvSignalBiquad.c in Sources */, 90B848DE1D95CA310004BCE3 /* HvControlUnop.c in Sources */, 90B848ED1D95CA310004BCE3 /* HvSignalRPole.c in Sources */, 90B848EF1D95CA310004BCE3 /* HvSignalSample.c in Sources */, 90B848E81D95CA310004BCE3 /* HvSignalDel1.c in Sources */, 90B848E21D95CA310004BCE3 /* HvTable.c in Sources */, 90B848DF1D95CA310004BCE3 /* HvControlVar.c in Sources */, 90B848EE1D95CA310004BCE3 /* HvSignalSamphold.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 9036C1B71AD57CDF00C7B994 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 9036C1B81AD57CDF00C7B994 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 9036C1BC1AD57CDF00C7B994 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( 9036C1BD1AD57CDF00C7B994 /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; D84C615919D1038F00D01F59 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( D84C615A19D1038F00D01F59 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; D84C615F19D1038F00D01F59 /* Credits.rtf */ = { isa = PBXVariantGroup; children = ( D84C616019D1038F00D01F59 /* en */, ); name = Credits.rtf; sourceTree = ""; }; D84C616519D1038F00D01F59 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( D84C616619D1038F00D01F59 /* Base */, ); name = MainMenu.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 9036C1CB1AD57CDF00C7B994 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Heavy_iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.enzienaudio.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 9036C1CC1AD57CDF00C7B994 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_OPTIMIZATION_LEVEL = 3; INFOPLIST_FILE = Heavy_iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CFLAGS = ( "-ffast-math", "-DNDEBUG", ); PRODUCT_BUNDLE_IDENTIFIER = "com.enzienaudio.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; D84C617D19D1038F00D01F59 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Heavy_OSX/Heavy_OSX-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "Heavy_OSX/Heavy_OSX-Info.plist"; PRODUCT_BUNDLE_IDENTIFIER = "com.section6.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Debug; }; D84C617E19D1038F00D01F59 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Heavy_OSX/Heavy_OSX-Prefix.pch"; INFOPLIST_FILE = "Heavy_OSX/Heavy_OSX-Info.plist"; PRODUCT_BUNDLE_IDENTIFIER = "com.section6.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; name = Release; }; D8B4BE67198BC76B00987698 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = c11; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "-Wno-unused-function", "-Wno-#warnings", ); SDKROOT = macosx; SUPPORTED_PLATFORMS = macosx; }; name = Debug; }; D8B4BE68198BC76B00987698 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = c11; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 3; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.9; OTHER_CFLAGS = ( "-ffast-math", "-msse4.1", "-DNDEBUG", "-Wno-#warnings", "-Wno-unused-function", ); SDKROOT = macosx; SUPPORTED_PLATFORMS = macosx; }; name = Release; }; D8B4BE6A198BC76B00987698 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; D8B4BE6B198BC76B00987698 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_TREAT_WARNINGS_AS_ERRORS = YES; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 9036C1CF1AD57CDF00C7B994 /* Build configuration list for PBXNativeTarget "Heavy_iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 9036C1CB1AD57CDF00C7B994 /* Debug */, 9036C1CC1AD57CDF00C7B994 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D84C617C19D1038F00D01F59 /* Build configuration list for PBXNativeTarget "Heavy_OSX" */ = { isa = XCConfigurationList; buildConfigurations = ( D84C617D19D1038F00D01F59 /* Debug */, D84C617E19D1038F00D01F59 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D8B4BE5B198BC76B00987698 /* Build configuration list for PBXProject "Heavy" */ = { isa = XCConfigurationList; buildConfigurations = ( D8B4BE67198BC76B00987698 /* Debug */, D8B4BE68198BC76B00987698 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D8B4BE69198BC76B00987698 /* Build configuration list for PBXNativeTarget "Heavy_CmdLine" */ = { isa = XCConfigurationList; buildConfigurations = ( D8B4BE6A198BC76B00987698 /* Debug */, D8B4BE6B198BC76B00987698 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D8B4BE58198BC76B00987698 /* Project object */; } hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/AppDelegate.h0000644000000000000000000000164600000000000017746 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import @class MainViewController; @interface AppDelegate : NSObject @property (assign) IBOutlet NSWindow *window; @property (nonatomic, strong) MainViewController *mainViewController; @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/AppDelegate.m0000644000000000000000000000216500000000000017750 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import "AppDelegate.h" #import "MainViewController.h" @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { self.mainViewController = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil]; [self.window setContentView:[self.mainViewController view]]; } - (void)applicationWillTerminate:(NSNotification *)notification { [self.mainViewController destroy]; } @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/AudioEngine.h0000644000000000000000000000313200000000000017752 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import #include #include "tinywav.h" struct HeavyContextInterface; @class MainViewController; @interface AudioEngine : NSObject { double _sampleRate; int _blockSize; int _numOutputChannels; @public TinyWav tinywav; MainViewController *viewController; NSLock *lock; } @property (readonly) AudioUnit outputUnit; @property (assign) double startingFrameCount; @property (assign) int counter; @property (nonatomic) struct HeavyContextInterface *context; @property (atomic) bool keepRunning; + (void)update:(AudioEngine *)engine; - (id)initWithView:(MainViewController *)viewController; - (void)start; - (void)stop; - (void)destroy; - (void)sendFloat:(float)value toReceiver:(NSString *)receiverName; - (void)printStreamDescription:(const AudioStreamBasicDescription)asbd; - (void)recordAudioToFile:(NSString *)filepath; - (void)stopRecordingAudio; @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/AudioEngine.m0000644000000000000000000002310500000000000017761 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import #import "AudioEngine.h" #import "Heavy_heavy.h" #import "MainViewController.h" static void printHook(HeavyContextInterface *c, const char *name, const char *s, const HvMessage *m) { double timestampMs = 1000.0 * ((double) hv_msg_getTimestamp(m)) / hv_getSampleRate(c); NSLog(@"[%0.3fms] %s: %s", timestampMs, name, s); } static void checkError(OSStatus error, const char *operation) { if (error == noErr) return; char errorString[20] = {}; // See if it appears to be a 4-char code *(UInt32 *)(errorString+1) = CFSwapInt32HostToBig(error); if (isprint(errorString[1]) && isprint(errorString[2]) && isprint(errorString[3]) && isprint(errorString[4])) { errorString[0] = errorString[5] = '\''; errorString[6] = '\0'; } else { sprintf(errorString, "%d", (int)error); } fprintf(stderr, "Error: %s (%s)\n", operation, errorString); exit(1); } OSStatus AudioEngineRenderProc(void *inRefCon, AudioUnitRenderActionFlags *ioActionsFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { // const double tick_rc = CFAbsoluteTimeGetCurrent(); AudioEngine *audioEngine = (__bridge AudioEngine *) inRefCon; [audioEngine->lock lock]; int n = 0; double tock = 0.0; switch (hv_getNumOutputChannels(audioEngine.context)) { case 2: { const double tick = CFAbsoluteTimeGetCurrent(); float *outputBuffers[2] = { (float *) ioData->mBuffers[0].mData, (float *) ioData->mBuffers[1].mData }; n = hv_process(audioEngine.context, NULL, outputBuffers, inNumberFrames); tock = CFAbsoluteTimeGetCurrent() - tick; if (tinywav_isOpen(&audioEngine->tinywav)) { tinywav_write_f(&audioEngine->tinywav, outputBuffers, inNumberFrames); } break; } case 1: { const double tick = CFAbsoluteTimeGetCurrent(); float *b = (float *) ioData->mBuffers[0].mData; n = hv_process(audioEngine.context, NULL, &b, inNumberFrames); tock = CFAbsoluteTimeGetCurrent() - tick; if (tinywav_isOpen(&audioEngine->tinywav)) { tinywav_write_f(&audioEngine->tinywav, &b, inNumberFrames); } break; } default: break; } // const double tock_rc = CFAbsoluteTimeGetCurrent() - tick_rc; // NSLog(@"%iµs (%iµs) @ %i/%gHz (%0.3f%% CPU)", // (int) (1000000.0 * tock), // execution time of heavy callback // (int) (1000000.0 * tock_rc), // execution time of entire render callback // (int) inNumberFrames, // hv_getSampleRate(audioEngine.context), // 100.0*(tock/(inNumberFrames/hv_getSampleRate(audioEngine.context)))); [audioEngine->lock unlock]; dispatch_async(dispatch_get_main_queue(), ^{ [audioEngine->viewController updateCpuWithDuration:tock andFraction:tock/(inNumberFrames/hv_getSampleRate(audioEngine.context))]; }); if (n != inNumberFrames) { NSLog(@"WARNING: Heavy did not process the full frame: %i/%i", n, inNumberFrames); } return noErr; } @implementation AudioEngine + (void)update:(AudioEngine *)engine { while (engine.keepRunning) { unsigned int sendHash = 0; HvMessage *msg = (HvMessage *) malloc(hv_msg_getByteSize(100)); while (hv_getNextSentMessage(engine.context, &sendHash, msg, (hv_uint32_t) hv_msg_getByteSize(100))) { if (sendHash == hv_stringToHash("hello")) { if (hv_msg_hasFormat(msg, "f")) { NSLog(@"hello: %f", hv_msg_getFloat(msg, 0)); } } if (sendHash == hv_stringToHash("finished")) { if (hv_msg_hasFormat(msg, "b")) { NSLog(@"finished"); } } } [NSThread sleepForTimeInterval:0.0001f]; } } - (id)initWithView:(MainViewController *)view { self = [super init]; if (self) { _sampleRate = 48000.0; _context = hv_heavy_new_with_options(_sampleRate, 10, 2, 2); hv_setPrintHook(_context, &printHook); _blockSize = 512; _counter = 0; _numOutputChannels = hv_getNumOutputChannels(_context); lock = [[NSLock alloc] init]; self->viewController = view; memset(&tinywav, 0, sizeof(TinyWav)); [self initialiseAudioUnit]; } return self; } - (void)initialiseAudioUnit { // Generate output audio unit AudioComponentDescription outputcd = {0}; outputcd.componentType = kAudioUnitType_Output; outputcd.componentSubType = kAudioUnitSubType_DefaultOutput; outputcd.componentManufacturer = kAudioUnitManufacturer_Apple; AudioComponent comp = AudioComponentFindNext(NULL, &outputcd); if (comp == NULL) { NSLog(@"Can't get output unit"); exit(-1); } checkError(AudioComponentInstanceNew(comp, &_outputUnit), "Couldn't open component for outputUnit"); // Get stream format AudioStreamBasicDescription asbd = {0}; UInt32 size = sizeof(asbd); checkError(AudioUnitGetProperty(_outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &asbd, &size), "AudioUnitGetProperty (kAudioUnitProperty_StreamFormat) failed"); // Set stream format asbd.mBytesPerPacket = 4; asbd.mFramesPerPacket = 1; asbd.mChannelsPerFrame = _numOutputChannels; asbd.mBitsPerChannel = 32; asbd.mFormatID = kAudioFormatLinearPCM; asbd.mFormatFlags = kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; asbd.mSampleRate = _sampleRate; [self printStreamDescription:asbd]; checkError(AudioUnitSetProperty(_outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &asbd, size), "AudioUnitSetProperty (kAudioUnitProperty_StreamFormat) failed"); // Register the render callback AURenderCallbackStruct input; input.inputProc = AudioEngineRenderProc; input.inputProcRefCon = (__bridge void *)(self); checkError(AudioUnitSetProperty(_outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(input)), "AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed"); // Initialise the unit checkError(AudioUnitInitialize(_outputUnit), "Couldn't initialise outut unit"); // Make sure samplerate is correctly set after initialisation _sampleRate = asbd.mSampleRate; } - (void)start { checkError(AudioOutputUnitStart(_outputUnit), "Couldn't start output unit"); _keepRunning = true; // [NSThread detachNewThreadSelector:@selector(update:) toTarget:[AudioEngine class] withObject:self]; } - (void)stop { _keepRunning = false; checkError(AudioOutputUnitStop(_outputUnit), "Couldn't stop output unit"); } - (void)sendFloat:(float)value toReceiver:(NSString *)receiverName { if (self.context != NULL) { [lock lock]; hv_sendFloatToReceiver(self.context, hv_stringToHash([receiverName cStringUsingEncoding:NSASCIIStringEncoding]), value); [lock unlock]; } } - (void)destroy { AudioOutputUnitStop(_outputUnit); AudioUnitUninitialize(_outputUnit); AudioComponentInstanceDispose(_outputUnit); _keepRunning = false; } - (void)printStreamDescription:(const AudioStreamBasicDescription)asbd { NSLog(@"AudioStreamBasicDescription:"); NSLog(@"\t Sample Rate:\t\t %g", asbd.mSampleRate); NSLog(@"\t Bytes Per Packet:\t %d", asbd.mBytesPerPacket); NSLog(@"\t Frames Per Packet:\t %d", asbd.mFramesPerPacket); NSLog(@"\t Channels Per Frame: %d", asbd.mChannelsPerFrame); NSLog(@"\t Bits Per Channel:\t %d", asbd.mBitsPerChannel); char formatID[20] = {}; *(UInt32 *)(formatID+1) = CFSwapInt32HostToBig(asbd.mFormatID); if (isprint(formatID[1]) && isprint(formatID[2]) && isprint(formatID[3]) && isprint(formatID[4])) { formatID[0] = formatID[5] = '\''; formatID[6] = '\0'; NSLog(@"\t Format ID:\t\t\t %s", formatID); } else { NSLog(@"\t Format ID:\t\t\t unknown"); } NSLog(@"\t Format Flags:"); if (asbd.mFormatFlags & kAudioFormatFlagIsFloat) NSLog(@"\t\t kAudioFormatFlagIsFloat"); if (asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) NSLog(@"\t\t kAudioFormatFlagIsBigEndian"); if (asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) NSLog(@"\t\t kAudioFormatFlagIsSignedInteger"); if (asbd.mFormatFlags & kAudioFormatFlagIsPacked) NSLog(@"\t\t kAudioFormatFlagIsPacked"); if (asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) NSLog(@"\t\t kAudioFormatFlagIsAlignedHigh"); if (asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) NSLog(@"\t\t kAudioFormatFlagIsNonInterleaved"); if (asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) NSLog(@"\t\t kAudioFormatFlagIsNonMixable"); if (asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) NSLog(@"\t\t kAudioFormatFlagsAreAllClear"); } - (void)recordAudioToFile:(NSString *)filepath { [lock lock]; tinywav_new(&tinywav, (int16_t) hv_getNumOutputChannels(_context), (int32_t) _sampleRate, TW_FLOAT32, TW_SPLIT, [filepath cStringUsingEncoding:NSASCIIStringEncoding]); [lock unlock]; } - (void)stopRecordingAudio { [lock lock]; tinywav_close(&tinywav); [lock unlock]; } @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/Base.lproj/MainMenu.xib0000644000000000000000000014077700000000000021647 0ustar00 Default Left to Right Right to Left Default Left to Right Right to Left hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/Heavy_OSX-Info.plist0000644000000000000000000000207000000000000021165 0ustar00 CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright Copyright © 2014 section6. All rights reserved. NSMainNibFile MainMenu NSPrincipalClass NSApplication hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/Heavy_OSX-Prefix.pch0000644000000000000000000000025200000000000021146 0ustar00// // Prefix header // // The contents of this file are implicitly included at the beginning of every source file. // #ifdef __OBJC__ #import #endif hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/Images.xcassets/AppIcon.appiconset/Contents.json0000644000000000000000000000160700000000000026645 0ustar00{ "images" : [ { "idiom" : "mac", "size" : "16x16", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "scale" : "2x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "scale" : "2x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "scale" : "2x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "1x" }, { "idiom" : "mac", "size" : "256x256", "scale" : "2x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "1x" }, { "idiom" : "mac", "size" : "512x512", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } }hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/MainViewController.h0000644000000000000000000000317600000000000021356 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import @class AudioEngine; @interface MainViewController : NSViewController @property (weak) IBOutlet NSButton *startAudioButton; @property (weak) IBOutlet NSButton *recordAudioButton; @property (weak) IBOutlet NSLevelIndicator *cpuIndicator; @property (nonatomic, strong) AudioEngine *audioEngine; @property (weak) IBOutlet NSTextField *paramOneValue; @property (weak) IBOutlet NSTextField *paramTwoValue; @property (weak) IBOutlet NSTextField *paramThreeValue; @property (weak) IBOutlet NSTextField *paramFourValue; @property (weak) IBOutlet NSSlider *paramOneSlider; @property (weak) IBOutlet NSSlider *paramTwoSlider; @property (weak) IBOutlet NSSlider *paramThreeSlider; @property (weak) IBOutlet NSSlider *paramFourSlider; - (void)destroy; - (IBAction)onStartAudio:(id)sender; - (IBAction)onRecordAudio:(id)sender; - (IBAction)onSliderDidChange:(id)sender; - (void)updateCpuWithDuration:(NSTimeInterval)i andFraction:(double)p; @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/MainViewController.m0000644000000000000000000000552600000000000021364 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import "MainViewController.h" #import "AudioEngine.h" @interface MainViewController () @end @implementation MainViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.audioEngine = [[AudioEngine alloc] initWithView:self]; } return self; } - (void)loadView { [super loadView]; [self.paramOneValue setStringValue:[self.paramOneSlider stringValue]]; [self.paramTwoValue setStringValue:[self.paramTwoSlider stringValue]]; [self.paramThreeValue setStringValue:[self.paramThreeSlider stringValue]]; [self.paramFourValue setStringValue:[self.paramFourSlider stringValue]]; } - (void)destroy { [self.audioEngine destroy]; } - (IBAction)onStartAudio:(id)sender { if ([self.startAudioButton state] == 1) { [self.audioEngine start]; } else { [self.audioEngine stop]; } } - (IBAction)onRecordAudio:(id)sender { if ([self.recordAudioButton state] == 1) { [self.audioEngine recordAudioToFile:@"~/Desktop/Heavy_OSX.wav".stringByStandardizingPath]; } else { [self.audioEngine stopRecordingAudio]; } } - (IBAction)onSliderDidChange:(id)sender { float sliderValue = [sender floatValue]; NSString *valueString = [NSString stringWithFormat:@"%.2f", sliderValue]; if ([sender isEqualTo:self.paramOneSlider]) { [self.paramOneValue setStringValue:valueString]; [self.audioEngine sendFloat:sliderValue toReceiver:@"Channel-A"]; } else if ([sender isEqualTo:self.paramTwoSlider]) { [self.paramTwoValue setStringValue:valueString]; [self.audioEngine sendFloat:sliderValue toReceiver:@"Channel-B"]; } else if ([sender isEqualTo:self.paramThreeSlider]) { [self.paramThreeValue setStringValue:valueString]; [self.audioEngine sendFloat:sliderValue toReceiver:@"Channel-C"]; } else if ([sender isEqualTo:self.paramFourSlider]) { [self.paramFourValue setStringValue:valueString]; [self.audioEngine sendFloat:sliderValue toReceiver:@"Channel-D"]; } } - (void)updateCpuWithDuration:(NSTimeInterval)i andFraction:(double)p { [self.cpuIndicator setDoubleValue:10.0*log10(p) + 40.0]; } @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/MainViewController.xib0000644000000000000000000003753000000000000021712 0ustar00 hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/Views/nuklear/nuklear_glfw_gl3.h0000644000000000000000000004341000000000000023551 0ustar00/* * Nuklear - 1.32.0 - public domain * no warrenty implied; use at your own risk. * authored from 2015-2016 by Micha Mettke */ /* * ============================================================== * * API * * =============================================================== */ #ifndef NK_GLFW_GL3_H_ #define NK_GLFW_GL3_H_ #include enum nk_glfw_init_state{ NK_GLFW3_DEFAULT=0, NK_GLFW3_INSTALL_CALLBACKS }; NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); NK_API void nk_glfw3_shutdown(void); NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); NK_API void nk_glfw3_font_stash_end(void); NK_API void nk_glfw3_new_frame(void); NK_API void nk_glfw3_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer); NK_API void nk_glfw3_device_destroy(void); NK_API void nk_glfw3_device_create(void); NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); NK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods); #endif /* * ============================================================== * * IMPLEMENTATION * * =============================================================== */ #ifdef NK_GLFW_GL3_IMPLEMENTATION #ifndef NK_GLFW_TEXT_MAX #define NK_GLFW_TEXT_MAX 256 #endif #ifndef NK_GLFW_DOUBLE_CLICK_LO #define NK_GLFW_DOUBLE_CLICK_LO 0.02 #endif #ifndef NK_GLFW_DOUBLE_CLICK_HI #define NK_GLFW_DOUBLE_CLICK_HI 0.2 #endif struct nk_glfw_device { struct nk_buffer cmds; struct nk_draw_null_texture null; GLuint vbo, vao, ebo; GLuint prog; GLuint vert_shdr; GLuint frag_shdr; GLint attrib_pos; GLint attrib_uv; GLint attrib_col; GLint uniform_tex; GLint uniform_proj; GLuint font_tex; }; struct nk_glfw_vertex { float position[2]; float uv[2]; nk_byte col[4]; }; static struct nk_glfw { GLFWwindow *win; int width, height; int display_width, display_height; struct nk_glfw_device ogl; struct nk_context ctx; struct nk_font_atlas atlas; struct nk_vec2 fb_scale; unsigned int text[NK_GLFW_TEXT_MAX]; int text_len; struct nk_vec2 scroll; double last_button_click; int is_double_click_down; struct nk_vec2 double_click_pos; } glfw; #ifdef __APPLE__ #define NK_SHADER_VERSION "#version 150\n" #else #define NK_SHADER_VERSION "#version 300 es\n" #endif NK_API void nk_glfw3_device_create(void) { GLint status; static const GLchar *vertex_shader = NK_SHADER_VERSION "uniform mat4 ProjMtx;\n" "in vec2 Position;\n" "in vec2 TexCoord;\n" "in vec4 Color;\n" "out vec2 Frag_UV;\n" "out vec4 Frag_Color;\n" "void main() {\n" " Frag_UV = TexCoord;\n" " Frag_Color = Color;\n" " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" "}\n"; static const GLchar *fragment_shader = NK_SHADER_VERSION "precision mediump float;\n" "uniform sampler2D Texture;\n" "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" "out vec4 Out_Color;\n" "void main(){\n" " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" "}\n"; struct nk_glfw_device *dev = &glfw.ogl; nk_buffer_init_default(&dev->cmds); dev->prog = glCreateProgram(); dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER); dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0); glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0); glCompileShader(dev->vert_shdr); glCompileShader(dev->frag_shdr); glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status); assert(status == GL_TRUE); glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status); assert(status == GL_TRUE); glAttachShader(dev->prog, dev->vert_shdr); glAttachShader(dev->prog, dev->frag_shdr); glLinkProgram(dev->prog); glGetProgramiv(dev->prog, GL_LINK_STATUS, &status); assert(status == GL_TRUE); dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture"); dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx"); dev->attrib_pos = glGetAttribLocation(dev->prog, "Position"); dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord"); dev->attrib_col = glGetAttribLocation(dev->prog, "Color"); { /* buffer setup */ GLsizei vs = sizeof(struct nk_glfw_vertex); size_t vp = offsetof(struct nk_glfw_vertex, position); size_t vt = offsetof(struct nk_glfw_vertex, uv); size_t vc = offsetof(struct nk_glfw_vertex, col); glGenBuffers(1, &dev->vbo); glGenBuffers(1, &dev->ebo); glGenVertexArrays(1, &dev->vao); glBindVertexArray(dev->vao); glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); glEnableVertexAttribArray((GLuint)dev->attrib_pos); glEnableVertexAttribArray((GLuint)dev->attrib_uv); glEnableVertexAttribArray((GLuint)dev->attrib_col); glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp); glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt); glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc); } glBindTexture(GL_TEXTURE_2D, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(0); } NK_INTERN void nk_glfw3_device_upload_atlas(const void *image, int width, int height) { struct nk_glfw_device *dev = &glfw.ogl; glGenTextures(1, &dev->font_tex); glBindTexture(GL_TEXTURE_2D, dev->font_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); } NK_API void nk_glfw3_device_destroy(void) { struct nk_glfw_device *dev = &glfw.ogl; glDetachShader(dev->prog, dev->vert_shdr); glDetachShader(dev->prog, dev->frag_shdr); glDeleteShader(dev->vert_shdr); glDeleteShader(dev->frag_shdr); glDeleteProgram(dev->prog); glDeleteTextures(1, &dev->font_tex); glDeleteBuffers(1, &dev->vbo); glDeleteBuffers(1, &dev->ebo); nk_buffer_free(&dev->cmds); } NK_API void nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer) { struct nk_glfw_device *dev = &glfw.ogl; struct nk_buffer vbuf, ebuf; GLfloat ortho[4][4] = { {2.0f, 0.0f, 0.0f, 0.0f}, {0.0f,-2.0f, 0.0f, 0.0f}, {0.0f, 0.0f,-1.0f, 0.0f}, {-1.0f,1.0f, 0.0f, 1.0f}, }; ortho[0][0] /= (GLfloat)glfw.width; ortho[1][1] /= (GLfloat)glfw.height; /* setup global state */ glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glEnable(GL_SCISSOR_TEST); glActiveTexture(GL_TEXTURE0); /* setup program */ glUseProgram(dev->prog); glUniform1i(dev->uniform_tex, 0); glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]); glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); { /* convert from command queue into draw list and draw to screen */ const struct nk_draw_command *cmd; void *vertices, *elements; const nk_draw_index *offset = NULL; /* allocate vertex and element buffer */ glBindVertexArray(dev->vao); glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW); /* load draw vertices & elements directly into vertex + element buffer */ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); { /* fill convert configuration */ struct nk_convert_config config; static const struct nk_draw_vertex_layout_element vertex_layout[] = { {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, {NK_VERTEX_LAYOUT_END} }; NK_MEMSET(&config, 0, sizeof(config)); config.vertex_layout = vertex_layout; config.vertex_size = sizeof(struct nk_glfw_vertex); config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); config.null = dev->null; config.circle_segment_count = 22; config.curve_segment_count = 22; config.arc_segment_count = 22; config.global_alpha = 1.0f; config.shape_AA = AA; config.line_AA = AA; /* setup buffers to load vertices and elements */ nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer); nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer); nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); } glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); /* iterate over and execute each draw command */ nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) { if (!cmd->elem_count) continue; glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); glScissor( (GLint)(cmd->clip_rect.x * glfw.fb_scale.x), (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), (GLint)(cmd->clip_rect.w * glfw.fb_scale.x), (GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); offset += cmd->elem_count; } nk_clear(&glfw.ctx); } /* default OpenGL state */ glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(0); glDisable(GL_BLEND); glDisable(GL_SCISSOR_TEST); } NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) { (void)win; if (glfw.text_len < NK_GLFW_TEXT_MAX) glfw.text[glfw.text_len++] = codepoint; } NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) { (void)win; (void)xoff; glfw.scroll.x += (float)xoff; glfw.scroll.y += (float)yoff; } NK_API void nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { double x, y; if (button != GLFW_MOUSE_BUTTON_LEFT) return; glfwGetCursorPos(window, &x, &y); if (action == GLFW_PRESS) { double dt = glfwGetTime() - glfw.last_button_click; if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) { glfw.is_double_click_down = nk_true; glfw.double_click_pos = nk_vec2((float)x, (float)y); } glfw.last_button_click = glfwGetTime(); } else glfw.is_double_click_down = nk_false; } NK_INTERN void nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) { const char *text = glfwGetClipboardString(glfw.win); if (text) nk_textedit_paste(edit, text, nk_strlen(text)); (void)usr; } NK_INTERN void nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) { char *str = 0; (void)usr; if (!len) return; str = (char*)malloc((size_t)len+1); if (!str) return; memcpy(str, text, (size_t)len); str[len] = '\0'; glfwSetClipboardString(glfw.win, str); free(str); } NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) { glfw.win = win; if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { glfwSetScrollCallback(win, nk_gflw3_scroll_callback); glfwSetCharCallback(win, nk_glfw3_char_callback); glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); } nk_init_default(&glfw.ctx, 0); glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; glfw.ctx.clip.userdata = nk_handle_ptr(0); glfw.last_button_click = 0; nk_glfw3_device_create(); glfw.is_double_click_down = nk_false; glfw.double_click_pos = nk_vec2(0, 0); return &glfw.ctx; } NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) { nk_font_atlas_init_default(&glfw.atlas); nk_font_atlas_begin(&glfw.atlas); *atlas = &glfw.atlas; } NK_API void nk_glfw3_font_stash_end(void) { const void *image; int w, h; image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); nk_glfw3_device_upload_atlas(image, w, h); nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); if (glfw.atlas.default_font) nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); } NK_API void nk_glfw3_new_frame(void) { int i; double x, y; struct nk_context *ctx = &glfw.ctx; struct GLFWwindow *win = glfw.win; glfwGetWindowSize(win, &glfw.width, &glfw.height); glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; nk_input_begin(ctx); for (i = 0; i < glfw.text_len; ++i) nk_input_unicode(ctx, glfw.text[i]); #ifdef NK_GLFW_GL3_MOUSE_GRABBING /* optional grabbing behavior */ if (ctx->input.mouse.grab) glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); else if (ctx->input.mouse.ungrab) glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); #endif nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); } else { nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); nk_input_key(ctx, NK_KEY_COPY, 0); nk_input_key(ctx, NK_KEY_PASTE, 0); nk_input_key(ctx, NK_KEY_CUT, 0); nk_input_key(ctx, NK_KEY_SHIFT, 0); } glfwGetCursorPos(win, &x, &y); nk_input_motion(ctx, (int)x, (int)y); #ifdef NK_GLFW_GL3_MOUSE_GRABBING if (ctx->input.mouse.grabbed) { glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y); ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; } #endif nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down); nk_input_scroll(ctx, glfw.scroll); nk_input_end(&glfw.ctx); glfw.text_len = 0; glfw.scroll = nk_vec2(0,0); } NK_API void nk_glfw3_shutdown(void) { nk_font_atlas_clear(&glfw.atlas); nk_free(&glfw.ctx); nk_glfw3_device_destroy(); memset(&glfw, 0, sizeof(glfw)); } #endif hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/en.lproj/Credits.rtf0000644000000000000000000000066400000000000021262 0ustar00{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} {\colortbl;\red255\green255\blue255;} \paperw9840\paperh8400 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \f0\b\fs24 \cf0 Engineering: \b0 \ Some people\ \ \b Human Interface Design: \b0 \ Some other people\ \ \b Testing: \b0 \ Hopefully not nobody\ \ \b Documentation: \b0 \ Whoever\ \ \b With special thanks to: \b0 \ Mom\ } hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/en.lproj/InfoPlist.strings0000644000000000000000000000005500000000000022464 0ustar00/* Localized versions of Info.plist keys */ hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/main.m0000644000000000000000000000145100000000000016516 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import int main(int argc, const char * argv[]) { return NSApplicationMain(argc, argv); } hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/tinywav/tinywav.c0000644000000000000000000001061500000000000020764 0ustar00/** * Copyright (c) 2015, Martin Roth (mhroth@gmail.com) * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include #include "tinywav.h" typedef struct TinyWavHeader { uint32_t ChunkID; uint32_t ChunkSize; uint32_t Format; uint32_t Subchunk1ID; uint32_t Subchunk1Size; uint16_t AudioFormat; uint16_t NumChannels; uint32_t SampleRate; uint32_t ByteRate; uint16_t BlockAlign; uint16_t BitsPerSample; uint32_t Subchunk2ID; uint32_t Subchunk2Size; } TinyWavHeader; int tinywav_new(TinyWav *tw, int16_t numChannels, int32_t samplerate, TinyWavSampleFormat sampFmt, TinyWavChannelFormat chanFmt, const char *path) { tw->f = fopen(path, "w"); tw->numChannels = numChannels; tw->totalFramesWritten = 0; tw->sampFmt = sampFmt; tw->chanFmt = chanFmt; // prepare WAV header TinyWavHeader h; h.ChunkID = htonl(0x52494646); // "RIFF" h.ChunkSize = 0; // fill this in on file-close h.Format = htonl(0x57415645); // "WAVE" h.Subchunk1ID = htonl(0x666d7420); // "fmt " h.Subchunk1Size = 16; // PCM h.AudioFormat = (tw->sampFmt-1); // 1 PCM, 3 IEEE float h.NumChannels = numChannels; h.SampleRate = samplerate; h.ByteRate = samplerate * numChannels * tw->sampFmt; h.BlockAlign = numChannels * tw->sampFmt; h.BitsPerSample = 8*tw->sampFmt; h.Subchunk2ID = htonl(0x64617461); // "data" h.Subchunk2Size = 0; // fill this in on file-close // write WAV header fwrite(&h, sizeof(TinyWavHeader), 1, tw->f); return 0; } size_t tinywav_write_f(TinyWav *tw, void *f, int len) { switch (tw->sampFmt) { case TW_INT16: { int16_t z[tw->numChannels*len]; switch (tw->chanFmt) { case TW_INTERLEAVED: { return 0; } case TW_INLINE: { const float *const x = (const float *const) f; for (int i = 0, k = 0; i < len; ++i) { for (int j = 0; j < tw->numChannels; ++j) { z[k++] = (int16_t) (x[j*len+i] * 32767.0f); } } break; } case TW_SPLIT: { const float **const x = (const float **const) f; for (int i = 0, k = 0; i < len; ++i) { for (int j = 0; j < tw->numChannels; ++j) { z[k++] = (int16_t) (x[j][i] * 32767.0f); } } break; } default: return 0; } tw->totalFramesWritten += len; return fwrite(z, sizeof(int16_t), tw->numChannels*len, tw->f); break; } case TW_FLOAT32: { float z[tw->numChannels*len]; switch (tw->chanFmt) { case TW_INTERLEAVED: { return 0; } case TW_INLINE: { const float *const x = (const float *const) f; for (int i = 0, k = 0; i < len; ++i) { for (int j = 0; j < tw->numChannels; ++j) { z[k++] = x[j*len+i]; } } break; } case TW_SPLIT: { const float **const x = (const float **const) f; for (int i = 0, k = 0; i < len; ++i) { for (int j = 0; j < tw->numChannels; ++j) { z[k++] = x[j][i]; } } break; } default: return 0; } tw->totalFramesWritten += len; return fwrite(z, sizeof(float), tw->numChannels*len, tw->f); } default: return 0; } } void tinywav_close(TinyWav *tw) { uint32_t data_len = tw->totalFramesWritten * tw->numChannels * tw->sampFmt; // set length of data fseek(tw->f, 4, SEEK_SET); uint32_t chunkSize_len = 36 + data_len; fwrite(&chunkSize_len, sizeof(uint32_t), 1, tw->f); fseek(tw->f, 40, SEEK_SET); fwrite(&data_len, sizeof(uint32_t), 1, tw->f); fclose(tw->f); tw->f = NULL; } bool tinywav_isOpen(TinyWav *tw) { return (tw->f != NULL); } hvcc-0.16.0/hvcc/generators/xcode/Heavy_OSX/tinywav/tinywav.h0000644000000000000000000000364400000000000020775 0ustar00/** * Copyright (c) 2015, Martin Roth (mhroth@gmail.com) * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _TINY_WAV_ #define _TINY_WAV_ #include #include #include #ifdef __cplusplus extern "C" { #endif // http://soundfile.sapp.org/doc/WaveFormat/ // http://www-mmsp.ece.mcgill.ca/documents/AudioFormats/WAVE/WAVE.html typedef enum TinyWavChannelFormat { TW_INTERLEAVED, // channel buffer is interleaved e.g. [LRLRLRLR] TW_INLINE, // channel buffer is inlined e.g. [LLLLRRRR] TW_SPLIT // channel buffer is split e.g. [[LLLL],[RRRR]] } TinyWavChannelFormat; typedef enum TinyWavSampleFormat { TW_INT16 = 2, // two byte signed integer TW_FLOAT32 = 4 // four byte IEEE float } TinyWavSampleFormat; typedef struct TinyWav { FILE *f; int16_t numChannels; uint32_t totalFramesWritten; TinyWavChannelFormat chanFmt; TinyWavSampleFormat sampFmt; } TinyWav; int tinywav_new(TinyWav *tw, int16_t numChannels, int32_t samplerate, TinyWavSampleFormat sampFmt, TinyWavChannelFormat chanFmt, const char *path); size_t tinywav_write_f(TinyWav *tw, void *f, int len); void tinywav_close(TinyWav *tw); bool tinywav_isOpen(TinyWav *tw); #ifdef __cplusplus } #endif #endif // _TINY_WAV_ hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/AppDelegate.h0000644000000000000000000000151200000000000017757 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/AppDelegate.m0000644000000000000000000000531100000000000017765 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import "AppDelegate.h" #import "HeavyAudio.h" @interface AppDelegate() { HeavyAudio *heavyAudio; } @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { heavyAudio = [[HeavyAudio alloc] init]; [heavyAudio initialiseAudioSession]; [heavyAudio initialiseAudioUnit]; dispatch_async(dispatch_get_main_queue(), ^{ [heavyAudio play]; }); return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/Base.lproj/LaunchScreen.xib0000644000000000000000000000716600000000000022523 0ustar00 hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/Base.lproj/Main.storyboard0000644000000000000000000000304700000000000022435 0ustar00 hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/HeavyAudio.h0000644000000000000000000000163100000000000017644 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import @interface HeavyAudio : NSObject - (void)initialiseAudioSession; - (void)initialiseAudioUnit; - (void)play; - (void)pause; - (void)overrideOutputToSpeaker:(BOOL)shouldOverride; @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/HeavyAudio.m0000644000000000000000000003250300000000000017653 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import #import #import "HeavyAudio.h" #include "TPCircularBuffer.h" #import "Heavy_heavy.h" #define SAMPLE_RATE 44100.0 #define BLOCK_SIZE 1024 @interface HeavyAudio() { @public @private AudioUnit audioUnit; TPCircularBuffer inputQueue; HeavyContextInterface *hv; } @end @implementation HeavyAudio static void printHook(HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg) { NSLog(@"> [%s@%0.3fms] %s", printName, hv_getCurrentTime(context), str); } static void sendHook(HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg) { NSLog(@"> [%s@%0.3fms] received message via sendhook", sendName, hv_getCurrentTime(context)); } - (HeavyAudio *)init { self = [super init]; if (self != nil) { hv = hv_heavy_new(SAMPLE_RATE); // assert that the patch isn't claiming more input or output channels than we care to support assert(hv_getNumInputChannels(hv) < 2); // 0 or 1 if (hv_getNumInputChannels(hv) >= 2) { NSLog(@"WARNING: Heavy requires more than one channel of input. " "This is NOT supported by this code. Undefined behaviour will result."); } assert(hv_getNumOutputChannels(hv) <= 2); // 0, 1, or 2 // make input queue 4 times larger than necessary to protect against IO jitter // NOTE(mhroth): buffer length should never be zero TPCircularBufferInit( &inputQueue, MAX(1,hv_getNumInputChannels(hv)) * BLOCK_SIZE * 4 * sizeof(Float32)); hv_setPrintHook(hv, printHook); // hv_setSendHook(hv, sendHook); hv_setUserData(hv, (__bridge void *) self); } return self; } - (void)dealloc { hv_delete(hv); TPCircularBufferCleanup(&inputQueue); } - (void)initialiseAudioSession { NSError *error = nil; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; [[AVAudioSession sharedInstance] setMode:AVAudioSessionModeMeasurement error:&error]; // set the preferred sample rate [[AVAudioSession sharedInstance] setPreferredSampleRate:SAMPLE_RATE error:&error]; // set the preferred block size const NSTimeInterval bufferDuration = BLOCK_SIZE / SAMPLE_RATE; // buffer duration in seconds [[AVAudioSession sharedInstance] setPreferredIOBufferDuration:bufferDuration error:&error]; // register route change and interruption listeners [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionRouteChangeListener:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionInterruptionListener:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; [[AVAudioSession sharedInstance] setActive:YES error:&error]; if (error == nil) { NSLog(@"++++ Audio Session successfully initialised."); } else { NSLog(@"There was an error initialising the Audio Session: %@", error.localizedDescription); } } // the interrupt listener for when the audio route changes (e.g., headphones are added or removed) // this will be preceeded by a (begin) interruption, and proceeded by an (end) interruption - (void)audioSessionRouteChangeListener:(NSNotification *)notification { NSLog(@"audioSessionRouteChangeListener: %@", notification.userInfo); } - (void)audioSessionInterruptionListener:(NSNotification *)notification { // get the interruption type NSNumber *type = [notification.userInfo objectForKey:AVAudioSessionInterruptionTypeKey]; switch (type.intValue) { case kAudioSessionEndInterruption: { NSLog(@"kAudioSessionEndInterruption: %@", notification.userInfo); break; } case kAudioSessionBeginInterruption: { NSLog(@"kAudioSessionBeginInterruption: %@", notification.userInfo); break; } default: break; } } - (void)initialiseAudioUnit { AudioComponentDescription desc; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_RemoteIO; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; AudioComponent comp = AudioComponentFindNext(NULL, &desc); OSStatus status = AudioComponentInstanceNew(comp, &audioUnit); const UInt32 setProperty = 1; const UInt32 unsetProperty = 0; // https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html // Enable mic status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &setProperty, sizeof(setProperty)); // Add an output to the speaker status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &setProperty, sizeof(setProperty)); // Set the input format to 32-bit, single channel, float, linear PCM const Float64 kSampleRate = SAMPLE_RATE; // set the sample rate on the input bus AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 1, &kSampleRate, sizeof(kSampleRate)); // set the sample rate on the output bus AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &kSampleRate, sizeof(kSampleRate)); // mono input stream from the microphone AudioStreamBasicDescription inputStreamFormat; inputStreamFormat.mSampleRate = kSampleRate; inputStreamFormat.mFormatID = kAudioFormatLinearPCM; inputStreamFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; inputStreamFormat.mBytesPerPacket = hv_getNumInputChannels(hv) * sizeof(Float32); inputStreamFormat.mFramesPerPacket = 1; inputStreamFormat.mBytesPerFrame = hv_getNumInputChannels(hv) * sizeof(Float32); inputStreamFormat.mChannelsPerFrame = hv_getNumInputChannels(hv); inputStreamFormat.mBitsPerChannel = sizeof(Float32) * 8; // Set the output format to the same as above AudioStreamBasicDescription outputStreamFormat; outputStreamFormat.mSampleRate = kSampleRate; outputStreamFormat.mFormatID = kAudioFormatLinearPCM; outputStreamFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; outputStreamFormat.mBytesPerPacket = hv_getNumOutputChannels(hv) * sizeof(Float32); outputStreamFormat.mFramesPerPacket = 1; outputStreamFormat.mBytesPerFrame = hv_getNumOutputChannels(hv) * sizeof(Float32); outputStreamFormat.mChannelsPerFrame = hv_getNumOutputChannels(hv); outputStreamFormat.mBitsPerChannel = sizeof(Float32) * 8; if (hv_getNumInputChannels(hv) > 0) { // set the input stream format status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &inputStreamFormat, sizeof(AudioStreamBasicDescription)); // Add a render callback to get input from the microphone AURenderCallbackStruct renderCallbackStructInput; renderCallbackStructInput.inputProc = inputCallback; renderCallbackStructInput.inputProcRefCon = (__bridge void *) self; status = AudioUnitSetProperty(audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &renderCallbackStructInput, sizeof(renderCallbackStructInput)); } if (hv_getNumOutputChannels(hv) > 0) { // set the output stream format status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outputStreamFormat, sizeof(AudioStreamBasicDescription)); // Add a render callback to send the output to the speaker AURenderCallbackStruct renderCallbackStructOutput; renderCallbackStructOutput.inputProc = renderCallback; renderCallbackStructOutput.inputProcRefCon = (__bridge void *) self; status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &renderCallbackStructOutput, sizeof(renderCallbackStructOutput)); } // no need to allocate an additional AU buffer (slight increase in efficiency) status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ShouldAllocateBuffer, kAudioUnitScope_Output, 1, &unsetProperty, sizeof(unsetProperty)); status = AudioUnitInitialize(audioUnit); } OSStatus inputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { HeavyAudio *const heavyAudio = (__bridge HeavyAudio *) inRefCon; // get a buffer to render the input audio into const int32_t required = hv_getNumInputChannels(heavyAudio->hv) * inNumberFrames * sizeof(Float32); int32_t available = 0; Float32 *const inputBuffers = (Float32 *) TPCircularBufferHead(&heavyAudio->inputQueue, &available); if (available < required) { NSLog(@"inputCallback: available %i < required %i", available, required); return noErr; } // prepare a buffer to render the microphone data into AudioBuffer ab; ab.mNumberChannels = hv_getNumInputChannels(heavyAudio->hv); ab.mDataByteSize = hv_getNumInputChannels(heavyAudio->hv) * inNumberFrames * sizeof(Float32); ab.mData = inputBuffers; AudioBufferList list; list.mNumberBuffers = 1; list.mBuffers[0] = ab; // render the microphone data into the buffer AudioUnitRender(heavyAudio->audioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, &list); TPCircularBufferProduce(&heavyAudio->inputQueue, required); return noErr; } OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { // counters for average CPU usage static double frameCount = 0.0; static double tickCount = 0.0; const double tick_rc = CFAbsoluteTimeGetCurrent(); HeavyAudio *const heavyAudio = (__bridge HeavyAudio *) inRefCon; // consume the input in the circular buffer and render the output int32_t available = 0; Float32 *inputBuffers = TPCircularBufferTail(&heavyAudio->inputQueue, &available); const int32_t required = hv_getNumInputChannels(heavyAudio->hv) * inNumberFrames * sizeof(Float32); if (available < required) { NSLog(@"renderCallback: available %i < required %i", available, required); return noErr; } double tock = 0.0; switch (hv_getNumOutputChannels(heavyAudio->hv)) { case 1: { const double tick = CFAbsoluteTimeGetCurrent(); hv_process(heavyAudio->hv, &inputBuffers, (Float32 **) &(ioData->mBuffers[0].mData), inNumberFrames); tock = CFAbsoluteTimeGetCurrent() - tick; break; } case 2: { Float32 *outputBuffers[2] = { (Float32 *) alloca(inNumberFrames * sizeof(Float32)), (Float32 *) alloca(inNumberFrames * sizeof(Float32)) }; // process Heavy const double tick = CFAbsoluteTimeGetCurrent(); hv_process(heavyAudio->hv, &inputBuffers, outputBuffers, inNumberFrames); tock = CFAbsoluteTimeGetCurrent() - tick; vDSP_ztoc((DSPSplitComplex *) outputBuffers, 1, (DSPComplex *) ioData->mBuffers[0].mData, 2, inNumberFrames); break; } default: break; } TPCircularBufferConsume(&heavyAudio->inputQueue, required); tickCount += tock; frameCount += (double) inNumberFrames; const double tock_rc = CFAbsoluteTimeGetCurrent() - tick_rc; NSLog(@"%iµs (%iµs) @ %i/%gHz (%0.3f%% CPU) [%0.3f%% avgCPU]", (int) (1000000.0 * tock), // execution time of heavy callback (int) (1000000.0 * tock_rc), // execution time of entire render callback (int) inNumberFrames, hv_getSampleRate(heavyAudio->hv), 100.0*(tock/(inNumberFrames/hv_getSampleRate(heavyAudio->hv))), 100.0*(tickCount/(frameCount/hv_getSampleRate(heavyAudio->hv)))); return noErr; } - (void)play { AudioOutputUnitStart(audioUnit); } - (void)pause { AudioOutputUnitStop(audioUnit); } - (void)overrideOutputToSpeaker:(BOOL)shouldOverride { NSError *error = nil; AVAudioSessionPortOverride portOverride = shouldOverride ? AVAudioSessionPortOverrideSpeaker : AVAudioSessionPortOverrideNone; [[AVAudioSession sharedInstance] overrideOutputAudioPort:portOverride error:&error]; if (error != nil) { NSLog(@"Error while overriding the AudioSession route: %@", error.localizedDescription); } } @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/Images.xcassets/AppIcon.appiconset/Contents.json0000644000000000000000000000206500000000000026665 0ustar00{ "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } }hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/Info.plist0000644000000000000000000000305000000000000017402 0ustar00 NSMicrophoneUsageDescription Need mic for testing! CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/TPCircularBuffer.c0000644000000000000000000001355300000000000020751 0ustar00// // TPCircularBuffer.c // Circular/Ring buffer implementation // // https://github.com/michaeltyson/TPCircularBuffer // // Created by Michael Tyson on 10/12/2011. // // Copyright (C) 2012-2013 A Tasty Pixel // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // #include "TPCircularBuffer.h" #include #include #include #define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__)) static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) { if ( result != ERR_SUCCESS ) { printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result)); return false; } return true; } bool _TPCircularBufferInit(TPCircularBuffer *buffer, int32_t length, size_t structSize) { assert(length > 0); if ( structSize != sizeof(TPCircularBuffer) ) { fprintf(stderr, "TPCircularBuffer: Header version mismatch. Check for old versions of TPCircularBuffer in your project\n"); abort(); } // Keep trying until we get our buffer, needed to handle race conditions int retries = 3; while ( true ) { buffer->length = (int32_t)round_page(length); // We need whole page sizes // Temporarily allocate twice the length, so we have the contiguous address space to // support a second instance of the buffer directly after vm_address_t bufferAddress; kern_return_t result = vm_allocate(mach_task_self(), &bufferAddress, buffer->length * 2, VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit if ( result != ERR_SUCCESS ) { if ( retries-- == 0 ) { reportResult(result, "Buffer allocation"); return false; } // Try again if we fail continue; } // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half... result = vm_deallocate(mach_task_self(), bufferAddress + buffer->length, buffer->length); if ( result != ERR_SUCCESS ) { if ( retries-- == 0 ) { reportResult(result, "Buffer deallocation"); return false; } // If this fails somehow, deallocate the whole region and try again vm_deallocate(mach_task_self(), bufferAddress, buffer->length); continue; } // Re-map the buffer to the address space immediately after the buffer vm_address_t virtualAddress = bufferAddress + buffer->length; vm_prot_t cur_prot, max_prot; result = vm_remap(mach_task_self(), &virtualAddress, // mirror target buffer->length, // size of mirror 0, // auto alignment 0, // force remapping to virtualAddress mach_task_self(), // same task bufferAddress, // mirror source 0, // MAP READ-WRITE, NOT COPY &cur_prot, // unused protection struct &max_prot, // unused protection struct VM_INHERIT_DEFAULT); if ( result != ERR_SUCCESS ) { if ( retries-- == 0 ) { reportResult(result, "Remap buffer memory"); return false; } // If this remap failed, we hit a race condition, so deallocate and try again vm_deallocate(mach_task_self(), bufferAddress, buffer->length); continue; } if ( virtualAddress != bufferAddress+buffer->length ) { // If the memory is not contiguous, clean up both allocated buffers and try again if ( retries-- == 0 ) { printf("Couldn't map buffer memory to end of buffer\n"); return false; } vm_deallocate(mach_task_self(), virtualAddress, buffer->length); vm_deallocate(mach_task_self(), bufferAddress, buffer->length); continue; } buffer->buffer = (void*)bufferAddress; buffer->fillCount = 0; buffer->head = buffer->tail = 0; buffer->atomic = true; return true; } return false; } void TPCircularBufferCleanup(TPCircularBuffer *buffer) { vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2); memset(buffer, 0, sizeof(TPCircularBuffer)); } void TPCircularBufferClear(TPCircularBuffer *buffer) { int32_t fillCount; if ( TPCircularBufferTail(buffer, &fillCount) ) { TPCircularBufferConsume(buffer, fillCount); } } void TPCircularBufferSetAtomic(TPCircularBuffer *buffer, bool atomic) { buffer->atomic = atomic; } hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/TPCircularBuffer.h0000644000000000000000000001640400000000000020754 0ustar00// // TPCircularBuffer.h // Circular/Ring buffer implementation // // https://github.com/michaeltyson/TPCircularBuffer // // Created by Michael Tyson on 10/12/2011. // // // This implementation makes use of a virtual memory mapping technique that inserts a virtual copy // of the buffer memory directly after the buffer's end, negating the need for any buffer wrap-around // logic. Clients can simply use the returned memory address as if it were contiguous space. // // The implementation is thread-safe in the case of a single producer and single consumer. // // Virtual memory technique originally proposed by Philip Howard (http://vrb.slashusr.org/), and // adapted to Darwin by Kurt Revis (http://www.snoize.com, // http://www.snoize.com/Code/PlayBufferedSoundFile.tar.gz) // // // Copyright (C) 2012-2013 A Tasty Pixel // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // #ifndef TPCircularBuffer_h #define TPCircularBuffer_h #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct { void *buffer; int32_t length; int32_t tail; int32_t head; volatile int32_t fillCount; bool atomic; } TPCircularBuffer; /*! * Initialise buffer * * Note that the length is advisory only: Because of the way the * memory mirroring technique works, the true buffer length will * be multiples of the device page size (e.g. 4096 bytes) * * @param buffer Circular buffer * @param length Length of buffer */ #define TPCircularBufferInit(buffer, length) \ _TPCircularBufferInit(buffer, length, sizeof(*buffer)) bool _TPCircularBufferInit(TPCircularBuffer *buffer, int32_t length, size_t structSize); /*! * Cleanup buffer * * Releases buffer resources. */ void TPCircularBufferCleanup(TPCircularBuffer *buffer); /*! * Clear buffer * * Resets buffer to original, empty state. * * This is safe for use by consumer while producer is accessing * buffer. */ void TPCircularBufferClear(TPCircularBuffer *buffer); /*! * Set the atomicity * * If you set the atomiticy to false using this method, the buffer will * not use atomic operations. This can be used to give the compiler a little * more optimisation opportunities when the buffer is only used on one thread. * * Important note: Only set this to false if you know what you're doing! * * The default value is true (the buffer will use atomic operations) * * @param buffer Circular buffer * @param atomic Whether the buffer is atomic (default true) */ void TPCircularBufferSetAtomic(TPCircularBuffer *buffer, bool atomic); // Reading (consuming) /*! * Access end of buffer * * This gives you a pointer to the end of the buffer, ready * for reading, and the number of available bytes to read. * * @param buffer Circular buffer * @param availableBytes On output, the number of bytes ready for reading * @return Pointer to the first bytes ready for reading, or NULL if buffer is empty */ static __inline__ __attribute__((always_inline)) void* TPCircularBufferTail(TPCircularBuffer *buffer, int32_t* availableBytes) { *availableBytes = buffer->fillCount; if ( *availableBytes == 0 ) return NULL; return (void*)((char*)buffer->buffer + buffer->tail); } /*! * Consume bytes in buffer * * This frees up the just-read bytes, ready for writing again. * * @param buffer Circular buffer * @param amount Number of bytes to consume */ static __inline__ __attribute__((always_inline)) void TPCircularBufferConsume(TPCircularBuffer *buffer, int32_t amount) { buffer->tail = (buffer->tail + amount) % buffer->length; if ( buffer->atomic ) { OSAtomicAdd32Barrier(-amount, &buffer->fillCount); } else { buffer->fillCount -= amount; } assert(buffer->fillCount >= 0); } /*! * Access front of buffer * * This gives you a pointer to the front of the buffer, ready * for writing, and the number of available bytes to write. * * @param buffer Circular buffer * @param availableBytes On output, the number of bytes ready for writing * @return Pointer to the first bytes ready for writing, or NULL if buffer is full */ static __inline__ __attribute__((always_inline)) void* TPCircularBufferHead(TPCircularBuffer *buffer, int32_t* availableBytes) { *availableBytes = (buffer->length - buffer->fillCount); if ( *availableBytes == 0 ) return NULL; return (void*)((char*)buffer->buffer + buffer->head); } // Writing (producing) /*! * Produce bytes in buffer * * This marks the given section of the buffer ready for reading. * * @param buffer Circular buffer * @param amount Number of bytes to produce */ static __inline__ __attribute__((always_inline)) void TPCircularBufferProduce(TPCircularBuffer *buffer, int32_t amount) { buffer->head = (buffer->head + amount) % buffer->length; if ( buffer->atomic ) { OSAtomicAdd32Barrier(amount, &buffer->fillCount); } else { buffer->fillCount += amount; } assert(buffer->fillCount <= buffer->length); } /*! * Helper routine to copy bytes to buffer * * This copies the given bytes to the buffer, and marks them ready for reading. * * @param buffer Circular buffer * @param src Source buffer * @param len Number of bytes in source buffer * @return true if bytes copied, false if there was insufficient space */ static __inline__ __attribute__((always_inline)) bool TPCircularBufferProduceBytes(TPCircularBuffer *buffer, const void* src, int32_t len) { int32_t space; void *ptr = TPCircularBufferHead(buffer, &space); if ( space < len ) return false; memcpy(ptr, src, len); TPCircularBufferProduce(buffer, len); return true; } /*! * Deprecated method */ static __inline__ __attribute__((always_inline)) __deprecated_msg("use TPCircularBufferSetAtomic(false) and TPCircularBufferConsume instead") void TPCircularBufferConsumeNoBarrier(TPCircularBuffer *buffer, int32_t amount) { buffer->tail = (buffer->tail + amount) % buffer->length; buffer->fillCount -= amount; assert(buffer->fillCount >= 0); } /*! * Deprecated method */ static __inline__ __attribute__((always_inline)) __deprecated_msg("use TPCircularBufferSetAtomic(false) and TPCircularBufferProduce instead") void TPCircularBufferProduceNoBarrier(TPCircularBuffer *buffer, int32_t amount) { buffer->head = (buffer->head + amount) % buffer->length; buffer->fillCount += amount; assert(buffer->fillCount <= buffer->length); } #ifdef __cplusplus } #endif #endif hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/ViewController.h0000644000000000000000000000141100000000000020560 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import @interface ViewController : UIViewController @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/ViewController.m0000644000000000000000000000203100000000000020564 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end hvcc-0.16.0/hvcc/generators/xcode/Heavy_iOS/main.m0000644000000000000000000000160500000000000016540 0ustar00/** * Copyright (C) 2014-2018 Enzien Audio, Ltd. * * 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 . */ #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } hvcc-0.16.0/hvcc/interpreters/__init__.py0000644000000000000000000000000000000000000015160 0ustar00hvcc-0.16.0/hvcc/interpreters/pd2gui/PdGUIParser.py0000644000000000000000000005175600000000000016730 0ustar00# Heavy Compiler Collection # Copyright (C) 2025-2026 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only import re from collections import Counter from typing import Generator, Optional, Union from pathlib import Path from hvcc.interpreters.pd2hv.PdParser import PdParser from hvcc.types.GUI import ( Size, Coords, Font, LabelShow, LabelPos, Label, Color, Canvas, Bang, Toggle, VRadio, HRadio, VSlider, HSlider, Knob, Number, Float, Comment, GUIObjects, Graph, GraphRoot ) class PdGUIParser(PdParser): # retain width by overriding this regex with a pattern that never matches RE_WIDTH = re.compile(r"$^") def __init__(self) -> None: # the current global value of $0 # Note(joe): set a high starting value to avoid potential user naming conflicts self.__DOLLAR_ZERO = 1000 self.object_counter: Counter = Counter() # search paths at this graph level self.search_paths: list[Path] = [] def gui_from_file( self, file_path: Path, obj_args: Optional[list] = None, is_root: bool = True ) -> tuple[Union[Graph, GraphRoot], bool]: if is_root: self.search_paths.append(file_path) file_iterator = self.get_pd_line(file_path) canvas_line: str = file_iterator.__next__() self.__DOLLAR_ZERO += 1 # increment $0 graph_args = [self.__DOLLAR_ZERO] + (obj_args or []) if not canvas_line.startswith("#N canvas"): raise Exception(f"Pd files must begin with \"#N canvas\": {canvas_line}") g, gop = self.gui_from_canvas( file_iterator, canvas_line, graph_args, file_path, is_root ) return g, gop def gui_from_canvas( self, file_iterator: Generator, canvas_line: str, graph_args: list, pd_path: Path, is_root: bool = False ) -> tuple[Union[Graph, GraphRoot], bool]: objects: list[GUIObjects] = [] graphs: list[Graph] = [] x: Optional[GUIObjects] = None # graph on parent settings gop: bool = False gop_start: Coords = Coords() gop_size: Size = Size() obj_type = "" obj_args = [] try: for li in file_iterator: line = self.split_line(li) if line[0] == "#N": if line[1] == "canvas": g, gop = self.gui_from_canvas( file_iterator=file_iterator, canvas_line=li, graph_args=graph_args, pd_path=pd_path ) if gop: assert isinstance(g, Graph) graphs.append(g) elif line[0] == "#X": if line[1] == "coords": try: if int(line[8]) > 0: # canvas is active gop = True gop_start = Coords(x=int(line[9]), y=int(line[10])) gop_size = Size(x=int(line[6]), y=int(line[7])) except IndexError: continue elif line[1] == "restore" and gop: objects = self.filter_invisible_objects(objects, gop_start, gop_size) graphs = self.filter_invisible_graphs(graphs, gop_start, gop_size) self.object_counter["graph"] += 1 return Graph( id=f"graph{self.object_counter['graph']}", position=Coords( x=int(line[2]), y=int(line[3]) ), gop_start=gop_start, gop_size=gop_size, objects=objects, graphs=graphs ), gop elif line[1] == "text": x = self.add_comment(line) elif line[1] == "floatatom": obj_args = self.__resolve_object_args( obj_args=line[1:], graph_args=graph_args, is_root=is_root ) # replace args with resolved args line = line[:1] + obj_args x = self.add_float(line) elif line[1] == "obj": if len(line) > 4: obj_type = line[4] # sometimes objects have $ arguments in them as well obj_type = self.__resolve_object_args( obj_args=[obj_type], graph_args=graph_args, is_root=is_root)[0] obj_args = self.__resolve_object_args( obj_args=line[5:], graph_args=graph_args, is_root=is_root ) # replace args with resolved args line = line[:5] + obj_args abs_path = self.find_abstraction_path(pd_path.parent, obj_type) if abs_path is not None: g, gop = self.gui_from_file(abs_path, obj_args=obj_args, is_root=False) if gop: assert isinstance(g, Graph) # set object coordinates g.position = Coords( x=int(line[2]), y=int(line[3]) ) graphs.append(g) if obj_type == "cnv": x = self.add_canvas(line) elif obj_type == "bng": x = self.add_bang(line) elif obj_type == "tgl": x = self.add_toggle(line) elif obj_type == "vradio" or obj_type == "hradio": x = self.add_radio(line) elif obj_type == "vsl" or obj_type == "hsl": x = self.add_slider(line) elif obj_type == "knob" or obj_type == "else/knob": x = self.add_knob(line) elif obj_type == "nbx": x = self.add_number(line) if x is not None: objects.append(x) x = None except Exception as e: raise e if is_root: line = self.split_line(canvas_line) gop_start = Coords(x=0, y=0) gop_size = Size( x=int(line[4]), y=int(line[5]) ) objects = self.filter_invisible_objects(objects, gop_start, gop_size) graphs = self.filter_invisible_graphs(graphs, gop_start, gop_size) return GraphRoot( size=gop_size, objects=objects, graphs=graphs ), gop else: objects = self.filter_invisible_objects(objects, gop_start, gop_size) graphs = self.filter_invisible_graphs(graphs, gop_start, gop_size) self.object_counter["graph"] += 1 return Graph( id=f"graph{self.object_counter['graph']}", position=Coords( x=int(line[2]), y=int(line[3]) ), gop_start=gop_start, gop_size=gop_size, objects=objects, graphs=graphs ), gop @classmethod def filter_invisible_objects( cls, objects: list[GUIObjects], gop_start: Coords, gop_size: Size ) -> list[GUIObjects]: filtered_objects: list[GUIObjects] = [] gop_max_y = gop_start.y + gop_size.y gop_max_x = gop_start.x + gop_size.x for obj in objects: obj_min_y = obj.position.y obj_max_y = obj.position.y + obj.size.y obj_min_x = obj.position.x obj_max_x = obj.position.x + obj.size.x # check if object is overlapping with gop if ((obj_min_y < gop_max_y) or (obj_min_x < gop_max_x)) and \ ((obj_max_y > gop_start.y) and (obj_max_x > gop_start.x)) and \ ((obj_min_y < gop_max_y) and (obj_min_x < gop_max_x)): filtered_objects.append(obj) return filtered_objects @classmethod def filter_invisible_graphs( cls, graphs: list[Graph], gop_start: Coords, gop_size: Size ) -> list[Graph]: filtered_graphs: list[Graph] = [] gop_max_y = gop_start.y + gop_size.y gop_max_x = gop_start.x + gop_size.x for g in graphs: # skip empty graphs if cls.graph_is_empty(g): continue g_min_y = g.position.y g_max_y = g.position.y + g.gop_size.y g_min_x = g.position.x g_max_x = g.position.x + g.gop_size.x # check if graph is overlapping with gop if ((g_min_y < gop_max_y) or (g_min_x < gop_max_x)) and \ ((g_max_y > gop_start.y) and (g_max_x > gop_start.x)) and \ ((g_min_y < gop_max_y) and (g_min_x < gop_max_x)): filtered_graphs.append(g) return filtered_graphs @classmethod def graph_is_empty(cls, graph: Graph) -> bool: """ A graph is considered empty when it doesn't have any objects and all of it's child graphs are also empty. """ g_empty: list[bool] = [] for g in graph.graphs: g_empty.append(cls.graph_is_empty(g)) return len(graph.objects) == 0 and ( (len(g_empty) and all(g_empty)) or len(graph.graphs) == 0 ) @classmethod def filter_params(cls, param: str) -> Optional[str]: """ Only allow externed parameters """ if "@hv_param" in param or "@hv_event" in param: return param.split(" ")[0] else: return None @classmethod def __resolve_object_args( cls, obj_args: list, graph_args: list, raise_on_failure: bool = True, is_root: bool = False ) -> list: """ Resolve object arguments against the given graph arguments. By default this function raises an Exception if it cannot resolve an argument. This behaviour may be disabled, in which case the unresolved argument is replaced with None (which is an otherwise invalid value). A value of None typically indicates to a HeavyObject that the default value may be used. """ resolved_obj_args = list(obj_args) # make a copy of the original obj_args for i, a in enumerate(obj_args): for m in set(cls.RE_DOLLAR.findall(a)): assert isinstance(a, str) x = int(m) # the dollar index (i.e. $x) if len(graph_args) > x: a = a.replace(fr"\${m}", str(graph_args[x])) elif is_root: # NOTE(mhroth): this case is questionable, but since Pd # defaults to this behavior without warning, so will we. a = a.replace(fr"\${m}", "0") else: if raise_on_failure: # NOTE(mhroth): this case is questionable, but since Pd # defaults to this behavior without warning, so will we. a = a.replace(fr"\${m}", "0") else: a = None # indicate that this argument could not be resolved by replacing it with None resolved_obj_args[i] = a return resolved_obj_args def add_canvas(self, line: list[str]) -> Canvas: self.object_counter["canvas"] += 1 label = Label( text=line[10], color=Color(line[16]), position=Coords( x=int(line[11]), y=int(line[12]) ), font=Font(int(line[13])), font_size=int(line[14]) + 2 ) if line[10] != "empty" else None return Canvas( id=f"canvas{self.object_counter['canvas']}", position=Coords( x=int(line[2]), y=int(line[3]) ), label=label, size=Size( x=int(line[6]), y=int(line[7]) ), bg_color=Color(line[15]) ) @classmethod def add_bang(cls, line: list[str]) -> Optional[Bang]: param = cls.filter_params(line[10]) if param is None: return None label = Label( text=line[11], color=Color(line[18]), position=Coords( x=int(line[12]), y=int(line[13]) ), font=Font(int(line[14])), font_size=int(line[15]) + 2 ) if line[11] != "empty" else None return Bang( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[5]), y=int(line[5]) ), parameter=param, label=label, flash_time=int(line[6]), bg_color=Color(line[16]), fg_color=Color(line[17]) ) @classmethod def add_toggle(cls, line: list[str]) -> Optional[Toggle]: param = cls.filter_params(line[8]) if param is None: return None label = Label( text=line[9], color=Color(line[16]), position=Coords( x=int(line[10]), y=int(line[11]) ), font=Font(int(line[12])), font_size=int(line[13]) + 2 ) if line[9] != "empty" else None return Toggle( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[5]), y=int(line[5]) ), parameter=param, label=label, bg_color=Color(line[14]), fg_color=Color(line[15]), non_zero=float(line[18]) ) @classmethod def add_radio(cls, line: list[str]) -> Optional[Union[VRadio, HRadio]]: param = cls.filter_params(line[10]) if param is None: return None radio_type = line[4] radio_obj: dict[str, type[Union[VRadio, HRadio]]] = { "vradio": VRadio, "hradio": HRadio } label = Label( text=line[11], color=Color(line[18]), position=Coords( x=int(line[12]), y=int(line[13]) ), font=Font(int(line[14])), font_size=int(line[15]) + 2 ) if line[11] != "empty" else None return radio_obj[radio_type]( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[5]) * (int(line[8]) if radio_type == "hradio" else 1), y=int(line[5]) * (int(line[8]) if radio_type == "vradio" else 1) ), parameter=param, label=label, bg_color=Color(line[16]), fg_color=Color(line[17]), options=int(line[8]) ) @classmethod def add_slider(cls, line: list[str]) -> Optional[Union[VSlider, HSlider]]: param = cls.filter_params(line[12]) if param is None: return None slider: dict[str, type[Union[VSlider, HSlider]]] = { "vsl": VSlider, "hsl": HSlider } label = Label( text=line[13], color=Color(line[20]), position=Coords( x=int(line[14]), y=int(line[15]) ), font=Font(int(line[16])), font_size=int(line[17]) + 2 ) if line[13] != "empty" else None return slider[line[4]]( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[5]), y=int(line[6]) ), parameter=param, label=label, bg_color=Color(line[18]), fg_color=Color(line[19]), min=float(line[7]), max=float(line[8]), logarithmic=bool(int(line[9])), steady=bool(int(line[22])) ) @classmethod def add_knob(cls, line: list[str]) -> Optional[Knob]: param = cls.filter_params(line[11]) if param is None: return None log_val = float(line[8]) if log_val == 0.0: log_mode = "lin" elif log_val == 1.0: log_mode = "log" else: log_mode = "exp" return Knob( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[5]), y=int(line[5]) ), parameter=param, label_size=int(line[27]), label_pos=Coords( x=int(line[28]), y=int(line[29]) ), label_show=LabelShow(int(line[26])), min=float(line[6]), max=float(line[7]), bg_color=Color(line[12]), fg_color=Color(line[14]), init_val=float(line[9]), ang_range=int(line[20]), ang_offset=int(line[21]), log_mode=log_mode, exp_fact=float(line[8]), discrete=bool(int(line[18])), ticks=bool(int(line[32])), steps=int(line[17]), circular=bool(int(line[16])), jump=bool(0), square=bool(int(line[15])), arc_color=Color(line[13]), arc_start=float(line[23]), arc_show=bool(int(line[19])) ) @classmethod def add_number(cls, line: list[str]) -> Optional[Number]: param = cls.filter_params(line[12]) if param is None: return None label = Label( text=line[13], color=Color(line[20]), position=Coords( x=int(line[14]), y=int(line[15]) ), font=Font(0), font_size=int(line[17]) + 2 ) if line[13] != "empty" else None return Number( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[5])*int(line[17])+8, y=int(line[6]) ), parameter=param, label=label, bg_color=Color(line[18]), fg_color=Color(line[19]), log_mode=bool(int(line[9])), log_height=int(line[21]), min=float(line[7]), max=float(line[8]) ) def add_comment(self, line: list[str]) -> Comment: self.object_counter["comment"] += 1 # get width and clean up remaining text if line[-2] == "f" \ and line[-3][-1] == ",": width = int(line[-1]) text = " ".join(line[4:-2])[:-1] else: width = None text = " ".join(line[4:]) # escape characters text = text.replace("\"", "\\\"") # text = text.replace("\\": "\\\\") # backslash is already removed by self.split_line() return Comment( id=f"comment{self.object_counter['comment']}", position=Coords( x=int(line[2]), y=int(line[3]) ), text=text, width=width, size=Size( x=10*len(text), y=10 ) ) @classmethod def add_float(cls, line: list[str]) -> Optional[Float]: param = cls.filter_params(line[9]) if param is None: return None font_height = int(line[11]) if line[11] != "0" else 8 return Float( position=Coords( x=int(line[2]), y=int(line[3]) ), size=Size( x=int(line[4]) * (font_height - 4), y=font_height ), parameter=param, label_text=line[8] if line[8] != "-" else "", font_height=font_height, label_pos=LabelPos(int(line[7])), min=float(line[5]), max=float(line[6]) ) hvcc-0.16.0/hvcc/interpreters/pd2gui/__init__.py0000644000000000000000000000000000000000000016352 0ustar00hvcc-0.16.0/hvcc/interpreters/pd2gui/pd2gui.py0000644000000000000000000000546500000000000016031 0ustar00# Heavy Compiler Collection # Copyright (C) 2025-2026 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only import argparse import time from typing import Optional from pathlib import Path from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.interpreters.pd2gui.PdGUIParser import PdGUIParser from hvcc.types.compiler import CompilerResp, CompilerNotif, CompilerMsg class Colours: purple = "\033[95m" cyan = "\033[96m" dark_cyan = "\033[36m" blue = "\033[94m" green = "\033[92m" yellow = "\033[93m" red = "\033[91m" bold = "\033[1m" underline = "\033[4m" end = "\033[0m" class pd2gui: @classmethod def compile( cls, pd_path: Path, ir_file: Path, search_paths: Optional[list] = None, verbose: bool = False ): tick = time.time() parser = PdGUIParser() if search_paths is not None: for p in search_paths: parser.add_absolute_search_directory(p) try: gui_graph, _ = parser.gui_from_file(pd_path) ir_dir = ir_file.parent if not ir_dir.exists(): Path.mkdir(ir_dir) with open(ir_file, "w") as f: f.write(gui_graph.model_dump_json(indent=2) + "\n") return CompilerResp( stage="pd2gui", notifs=CompilerNotif(), in_dir=pd_path.parent, in_file=pd_path, out_dir=ir_dir, out_file=ir_file, compile_time=(time.time() - tick) ) except Exception as e: return CompilerResp( stage="pd2gui", notifs=CompilerNotif( has_error=True, exception=e, errors=[CompilerMsg( enum=NotificationEnum.ERROR_EXCEPTION, message=str(e) )] ), compile_time=(time.time() - tick) ) def main() -> None: parser = argparse.ArgumentParser( description="Converts a Pd patch into the GUI format.") parser.add_argument( "pd_path", help="The Pd patch to convert to GUI.") parser.add_argument( "ir_dir", help="Directory to store generated GUI patches.") parser.add_argument( "-v", "--verbose", help="Show debugging information.", action="count") args = parser.parse_args() pd_path = Path(args.pd_path).expanduser().absolute() ir_dir = Path(args.ir_dir).expanduser().absolute() pd2gui.compile( pd_path=pd_path, ir_file=Path(ir_dir, f"{pd_path.stem}.heavy.gui.json"), search_paths=None, verbose=args.verbose) if __name__ == "__main__": main() hvcc-0.16.0/hvcc/interpreters/pd2hv/Connection.py0000644000000000000000000000464600000000000016567 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from typing import Dict, Optional, TYPE_CHECKING if TYPE_CHECKING: from .PdObject import PdObject class Connection: def __init__( self, from_obj: 'PdObject', outlet_index: int, to_obj: 'PdObject', inlet_index: int, conn_type: Optional[str] # not actually Optional. This is due to the requirement in HeavyObject. ) -> None: assert from_obj is not None assert to_obj is not None assert conn_type is not None self.__from_obj = from_obj self.__to_obj = to_obj self.__hv_json: Dict = { "from": { "id": from_obj.obj_id, "outlet": outlet_index }, "to": { "id": to_obj.obj_id, "inlet": inlet_index }, "type": conn_type } @property def from_obj(self) -> 'PdObject': return self.__from_obj @property def from_id(self) -> str: return self.__hv_json["from"]["id"] @property def outlet_index(self) -> int: return self.__hv_json["from"]["outlet"] @property def to_obj(self) -> 'PdObject': return self.__to_obj @property def to_id(self) -> str: return self.__hv_json["to"]["id"] @property def inlet_index(self) -> int: return self.__hv_json["to"]["inlet"] @property def conn_type(self) -> str: return self.__hv_json["type"] def to_hv(self) -> Dict: return self.__hv_json def __repr__(self) -> str: return "{0}:{1} {4} {2}:{3}".format( self.from_id, self.outlet_index, self.to_id, self.inlet_index, self.conn_type) hvcc-0.16.0/hvcc/interpreters/pd2hv/HeavyGraph.py0000644000000000000000000000565200000000000016524 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import json from typing import Optional, List, Dict from pathlib import Path from .PdObject import PdObject from .HeavyObject import HeavyObject class HeavyGraph(PdObject): def __init__( self, hv_path: Path, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: super().__init__(hv_path.name.split(".")[0], obj_args, pos_x, pos_y) # read the heavy graph with open(hv_path, "r") as f: self.hv_json = json.load(f) # parse the heavy data structure to determine the outlet connection type outlets = [o for o in self.hv_json["objects"].values() if o["type"] == "outlet"] sorted(outlets, key=lambda o: o["args"]["index"]) self.__outlet_connection_types = [o["args"]["type"] for o in outlets] # resolve the arguments for i, a in enumerate(self.hv_json["args"]): if i < len(self.obj_args): arg_value = self.obj_args[i] elif a["required"]: self.add_error(f"Required argument \"{a['name']}\" not found.") continue else: arg_value = a["default"] try: arg_value = HeavyObject.force_arg_type(arg_value, a["value_type"]) except Exception as e: self.add_error( f"Heavy {self.obj_type} cannot convert argument \"{a['name']}\"" f" with value \"{arg_value}\" to type {a['value_type']}: {e}") # resolve all arguments for each object in the graph for o in self.hv_json["objects"].values(): for k, v in o["args"].items(): # TODO(mhroth): make resolution more robust if v == "$" + a["name"]: o["args"][k] = arg_value # reset all arguments, as they have all been resolved # any required arguments would break hv2ir as they will no longer # be supplied (because they are resolved) self.hv_json["args"] = [] def get_outlet_connection_type(self, outlet_index: int) -> str: return self.__outlet_connection_types[outlet_index] def to_hv(self) -> Dict: return self.hv_json hvcc-0.16.0/hvcc/interpreters/pd2hv/HeavyObject.py0000644000000000000000000002224100000000000016662 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . import decimal import json from importlib import resources from pathlib import Path from typing import Optional, List, Dict, Any, Union, cast from .Connection import Connection from .NotificationEnum import NotificationEnum from .PdObject import PdObject from hvcc.types.IR import HeavyIRType, IRNode, IRArg from hvcc.types.Lang import HeavyLangType, LangNode, LangArg class HeavyObject(PdObject): heavy_lang_json = str(resources.files('hvcc') / 'core/json/heavy.lang.json') with open(Path(heavy_lang_json), "r") as f: __HEAVY_LANG_OBJS = HeavyLangType(**json.load(f)).root heavy_ir_json = str(resources.files('hvcc') / 'core/json/heavy.ir.json') with open(Path(heavy_ir_json), "r") as f: __HEAVY_IR_OBJS = HeavyIRType(**json.load(f)).root def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: super().__init__(obj_type, obj_args, pos_x, pos_y) self.__obj_dict: Union[IRNode, LangNode] # get the object dictionary (note that it is NOT a copy) if self.is_hvlang: self.__obj_dict = self.__HEAVY_LANG_OBJS[obj_type] elif self.is_hvir: self.__obj_dict = self.__HEAVY_IR_OBJS[obj_type] else: assert False, f"{obj_type} is not a Heavy Lang or IR object." # resolve arguments obj_args = obj_args or [] self.obj_dict = {} # clean up externed tables if obj_type in ( "__var", "__tabwrite", "__tabwrite~f", "__tabwrite_stoppable~f", "__tabread", "__tabread~f", "__tabread~if", "__tabread_stoppable~f" ): for i, a in enumerate(obj_args): if isinstance(a, str): obj_args[i] = a.split(" ")[0] if "@hv_table" in a else a for i, a in enumerate(self.__obj_dict.args): arg = cast(Union[IRArg, LangArg], a) # if the argument exists (and has been correctly resolved) if i < len(obj_args) and obj_args[i] is not None: # force the Heavy argument type # Catch type errors as early as possible try: self.obj_dict[arg.name] = self.force_arg_type( obj_args[i], arg.value_type) except Exception as e: self.add_error( f"Heavy {obj_type} cannot convert argument \"{arg.name}\"" f" with value \"{obj_args[i]}\" to type {arg.value_type}: {e}") else: # the default argument is required if arg.required: self.add_error( f"Required argument \"{arg.name}\" to object {obj_type} not present: {obj_args}") else: # don't worry about supplying a default, # let hv2ir take care of it. pd2hv only passes on the # provided parameters. # self.obj_args[a["name"]] = a["default"] pass self.__annotations = {} # send/receive, table, etc. must have public scope # TODO(mhroth): dirty if obj_type in ("table", "__table", "send", "__send", "receive", "__receive"): self.__annotations["scope"] = "public" @classmethod def force_arg_type( cls, value: str, value_type: Optional[str] = None ) -> Any: # TODO(mhroth): add support for mixedarray? if value_type == "auto": try: return float(value) except Exception: return str(value) elif value_type == "float": return float(value) elif value_type == "int": return int(decimal.Decimal(value)) elif value_type == "string": return str(value) elif value_type == "boolean": if isinstance(value, str): return value.strip().lower() not in {"false", "f", "0"} else: return bool(value) elif value_type == "floatarray": if isinstance(value, list): return [float(v) for v in value] if isinstance(value, str): return [float(v) for v in value.split()] else: raise Exception(f"Cannot convert value to type floatarray: {value}") elif value_type == "intarray": if isinstance(value, list): return [int(v) for v in value] if isinstance(value, str): return [int(v) for v in value.split()] else: raise Exception(f"Cannot convert value to type intarray: {value}") elif value_type == "stringarray": if isinstance(value, list): return [str(v) for v in value] if isinstance(value, str): return [str(v) for v in value.split()] else: raise Exception(f"Cannot convert value to type stringarray: {value}") else: # NOTE(mhroth): if value_type is not a known type or None, that is # not necessarily an error. It may simply be that the value should # not be resolved to anything other than what it already is. # This happens most often with message objects. return value @property def is_hvlang(self) -> bool: return self.obj_type in self.__HEAVY_LANG_OBJS.keys() @property def is_hvir(self) -> bool: return self.obj_type in self.__HEAVY_IR_OBJS.keys() def get_inlet_connection_type(self, inlet_index: int) -> Optional[str]: """ Returns the inlet connection type, None if the inlet does not exist. """ # TODO(mhroth): it's stupid that hvlang and hvir json have different data formats here if self.is_hvlang and isinstance(self.__obj_dict, LangNode): if len(self.__obj_dict.inlets) > inlet_index: return self.__obj_dict.inlets[inlet_index].connectionType else: return None elif self.is_hvir and isinstance(self.__obj_dict, IRNode): if len(self.__obj_dict.inlets) > inlet_index: return self.__obj_dict.inlets[inlet_index] else: return None else: return None def get_outlet_connection_type(self, outlet_index: int) -> Optional[str]: """ Returns the outlet connection type, None if the inlet does not exist. """ # TODO(mhroth): it's stupid that hvlang and hvir json have different data formats here if self.is_hvlang and isinstance(self.__obj_dict, LangNode): if len(self.__obj_dict.outlets) > outlet_index: return self.__obj_dict.outlets[outlet_index].connectionType else: return None elif self.is_hvir and isinstance(self.__obj_dict, IRNode): if len(self.__obj_dict.outlets) > outlet_index: return self.__obj_dict.outlets[outlet_index] else: return None else: return None def add_connection(self, c: Connection) -> None: """ Adds a connection, either inlet or outlet, to this object. """ if c.from_id == self.obj_id: if self.get_outlet_connection_type(c.outlet_index) is not None: self._outlet_connections[str(c.outlet_index)].append(c) else: self.add_error( f"Connection made from non-existent outlet at {self.obj_type}:{c.outlet_index}.", enum=NotificationEnum.ERROR_UNABLE_TO_CONNECT_OBJECTS) elif c.to_id == self.obj_id: if self.get_inlet_connection_type(c.inlet_index) is not None: self._inlet_connections[str(c.inlet_index)].append(c) else: self.add_error( f"Connection made to non-existent inlet at [{self.obj_type} {self.obj_dict}]:{c.inlet_index}.", enum=NotificationEnum.ERROR_UNABLE_TO_CONNECT_OBJECTS) else: raise Exception("Adding a connection to the wrong object!") def to_hv(self) -> Dict: return { "type": self.obj_type, "args": self.obj_dict, "properties": { "x": self.pos_x, "y": self.pos_y }, "annotations": self.__annotations } hvcc-0.16.0/hvcc/interpreters/pd2hv/HvSwitchcase.py0000644000000000000000000000320000000000000017044 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .PdObject import PdObject class HvSwitchcase(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type == "__switchcase" super().__init__(obj_type, obj_args, pos_x, pos_y) # ensure that correct case hashes are generated for i, a in enumerate(self.obj_args): try: self.obj_args[i] = float(a) except Exception: pass def get_outlet_connection_type(self, outlet_index: int = 0) -> str: return "-->" def to_hv(self) -> Dict: return { "type": "__switchcase", "args": { "cases": self.obj_args }, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/NotificationEnum.py0000644000000000000000000000451100000000000017732 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2024 Wasted Audio # # 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 . from enum import Enum # http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python class NotificationEnum(Enum): """ These enumerations refer to all possible warnings and errors produced by pd2hv. """ EMPTY = -1 # Warnings # an unspecified generic warning WARNING_GENERIC = 1000 # an empty object has been added to a Pd graph WARNING_EMPTY_OBJECT = 1001 # heavy only supports the -path flag to the Pd declare object WARNING_DECLARE_PATH = 1002 # the object does nothing (and will likely be removed) WARNING_USELESS_OBJECT = 1003 # the message box is empty and does nothing WARNING_EMPTY_MESSAGE = 1004 # Errors # an unspecified generic error ERROR_GENERIC = 2000 # the parser doesn't know how to handle the object ERROR_UNKNOWN_OBJECT = 2001 # top-level graphs may not contain inlet~ or outlet~ objects ERROR_NO_TOPLEVEL_SIGNAL_LETS = 2002 # only arguments 'a', 'f', 's', and 'b' are supported for trigger object ERROR_TRIGGER_ABFS = 2003 # only arguments 'f', 'float' and numeric values are supported for pack object ERROR_PACK_FLOAT_ARGUMENTS = 2003 # a value cannot be resolved because the required argument is missing ERROR_MISSING_REQUIRED_ARGUMENT = 2004 # unique arguments are required for this object ERROR_UNIQUE_ARGUMENTS_REQUIRED = 2005 # two objects cannot be connected ERROR_UNABLE_TO_CONNECT_OBJECTS = 2006 # a particular connection (type?) is not supported ERROR_UNSUPPORTED_CONNECTION = 2007 # Exception # the exception that was raised ERROR_EXCEPTION = 3000 hvcc-0.16.0/hvcc/interpreters/pd2hv/PdAudioIoObject.py0000644000000000000000000000361100000000000017423 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdAudioIoObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type in {"adc~", "dac~"} super().__init__(obj_type, obj_args, pos_x, pos_y) def validate_configuration(self) -> None: # ensure that only signal connections are made to the dac for i, connections in self._inlet_connections.items(): if any(c.conn_type == "-->" for c in connections): self.add_error( f"{self.obj_type} does not support control connections (inlet {i}). They should be removed.", NotificationEnum.ERROR_UNSUPPORTED_CONNECTION) def to_hv(self) -> Dict: return { "type": self.obj_type.strip("~"), "args": { "channels": [1, 2] if len(self.obj_args) == 0 else [int(a) for a in self.obj_args] }, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdBinopObject.py0000644000000000000000000001365700000000000017154 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .Connection import Connection from .HeavyObject import HeavyObject from .PdObject import PdObject class PdBinopObject(PdObject): # a translation dictionary from a Pd object to corresponding heavy object __PD_HEAVY_DICT = { "+": "+", "+~": "+", "-": "-", "-~": "-", "*": "*", "*~": "*", "/": "/", "/~": "/", "mod": "mod", "%": "%", "max": "max", "max~": "max", "min": "min", "min~": "min", "&": "&", "&&": "&&", "|": "|", "||": "||", "==": "==", "!=": "!=", "<": "<", "<=": "<=", ">": ">", ">=": ">=", "pow": "pow", "pow~": "pow", ">>": ">>", "<<": "<<", "cyclone/>~": ">", "cyclone/greaterthan~": ">", "cyclone/>=~": ">=", "cyclone/greaterthaneq~": ">=", "cyclone/<~": "<", "cyclone/lessthan~": "<", "cyclone/<=~": "<=", "cyclone/lessthaneq~": "<=", "cyclone/==~": "==", "cyclone/equals~": "==", "cyclone/!=~": "!=", "cyclone/notequals~": "!=" } def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert self.is_binop(obj_type) super().__init__(obj_type, obj_args, pos_x, pos_y) @classmethod def is_binop(cls, obj_type: str) -> bool: return obj_type in cls.__PD_HEAVY_DICT @classmethod def get_supported_objects(cls) -> set: return set(cls.__PD_HEAVY_DICT.keys()) def validate_configuration(self) -> None: # check signal objects for control connections and auto insert # heavy var objects where necessary if self.obj_type.endswith("~"): # left inlet check conns_left = self._inlet_connections.get("0", []) if len(conns_left) == 0: # no left inlet connections self.convert_ctrl_to_sig_connections_at_inlet([], 0) elif (len([c for c in conns_left if c.conn_type == "~f>"]) == 0) and len(conns_left) > 0: # control connection and no sig connection self.convert_ctrl_to_sig_connections_at_inlet(conns_left, 0) # right inlet check conns_right = self._inlet_connections.get("1", []) num_signal_conns = len([c for c in conns_right if c.conn_type == "~f>"]) if len(self.obj_args) > 0 and num_signal_conns > 0: # TODO(joe): removing this connection instead of throwing an error # would be compatible with Pd's behaviour self.add_error("signal outlet connected to nonsignal inlet") if len(self.obj_args) == 0 and num_signal_conns == 0 and len(conns_right) > 0: # any arguments present will create a control type right inlet self.convert_ctrl_to_sig_connections_at_inlet(conns_right, 1) if len(self.obj_args) > 0: try: self.__k = float(self.obj_args[0]) except Exception: self.add_warning(f"\"{self.obj_args[0]}\" cannot be resolved to a number. Defaulting to zero.") self.__k = 0.0 else: self.__k = 0.0 def convert_ctrl_to_sig_connections_at_inlet(self, connection_list: List, inlet_index: int) -> None: """ Auto insert heavy var object inbetween control connections. """ sig_obj = HeavyObject(obj_type="var", obj_args=[0], pos_x=int(self.pos_x), pos_y=int(self.pos_y - 5)) # shift upwards a few points # add sig~ object to parent graph if self.parent_graph is not None: self.parent_graph.add_object(sig_obj) # add connection from sig~ to this object c = Connection(sig_obj, 0, self, inlet_index, "~f>") self.parent_graph._PdGraph__connections.append(c) # update the local connections list sig_obj.add_connection(c) self.add_connection(c) # retrieve all control connections control_conns = [c for c in connection_list if c.conn_type == "-->"] for old_conn in control_conns: # get from obj from_obj = old_conn.from_obj # add connection from fromobj to new sig new_conn = Connection(from_obj, old_conn.outlet_index, sig_obj, 0, "-->") self.parent_graph._PdGraph__connections.append(new_conn) sig_obj.add_connection(new_conn) from_obj.add_connection(new_conn) # remove connection from fromobj self.parent_graph._PdGraph__connections.remove(old_conn) from_obj.remove_connection(old_conn) self.remove_connection(old_conn) def to_hv(self) -> Dict: return { "type": self.__PD_HEAVY_DICT[self.obj_type], "args": { "k": self.__k }, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdExprObject.py0000644000000000000000000000561100000000000017012 0ustar00# Copyright (C) 2022-2025 Daniel Billotte, Wasted Audio # # 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 . import re from .PdObject import PdObject from typing import Optional, List class PdExprObject(PdObject): """ Limitations (compared to vanilla pd): - only supports a single expression - Available pd docs/examples say expr support up to 100 variables This version currently supports up to 100 variables as defined in HvControlExpr.h - I don't know what pd-expr does with strings, haven't experimented and haven't given it any thought yet here """ def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: """ Validate the expr object and any heavy restrictions, then convert it directly into a HeavyIR object. """ assert obj_type in ["expr", "expr~"] super().__init__(obj_type, obj_args, pos_x, pos_y) # turn the arguments into a list of expressions, but only one for now if len(self.obj_args) == 0: self.add_error("Empty expression") expressions = [e.strip() for e in " ".join(self.obj_args).split("\\;")] if len(expressions) > 1: self.add_error("Heavy expr does not support multiple expressions") else: self.expressions = expressions # count the number of inlets var_nums = { int(var[2:]) for var in # this should be checked separately for control vs. signal instances # fis for control, v for signal re.findall(r"\$[fisv]\d+", self.expressions[0]) } self.num_inlets = max(var_nums) if len(var_nums) > 0 else 1 if self.num_inlets > 100: self.add_error("Heavy expr supports upto 100 variables") def validate_configuration(self): # things that could be validated: # - inlet count/types match variables in the expression(s) pass def to_hv(self): return { "type": f"__{self.obj_type}", "args": { "expressions": self.expressions, "num_inlets": self.num_inlets }, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdGraph.py0000644000000000000000000002237400000000000016013 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . from typing import Optional, List, Dict, Any from pathlib import Path from .Connection import Connection from .NotificationEnum import NotificationEnum from .PdObject import PdObject from hvcc.types.compiler import CompilerNotif class PdGraph(PdObject): def __init__( self, obj_args: List, pd_path: Path, pos_x: int = 0, pos_y: int = 0 ) -> None: assert len(obj_args) > 0, "PdGraph arguments must contain at least dollar zero." super().__init__("graph", obj_args, pos_x, pos_y) # file location of this graph self.__pd_path: Path = pd_path self.__objs: List[PdObject] = [] self.__connections: List[Connection] = [] self.__inlet_objects: List = [] self.__outlet_objects: List = [] # the first search path is always the directory of this graph self.__declared_paths: List[Path] = [pd_path.parent] # heavy graph arguments (added via @hv_arg flag in #X text) self.hv_args: List = [] # the subpatch name of this graph # only used is this graph is actually a subpatch self.subpatch_name: Optional[str] = None # TODO(dromer) these are virtual attributes that are only instantiated with internal representation self._PdGraph__connections: List[Connection] = [] self._PdGraph__pd_path: Path = Path() @property def dollar_zero(self) -> str: return self.obj_args[0] @property def is_root(self) -> bool: return self.parent_graph is None @property def is_subpatch(self) -> bool: if self.parent_graph is None: return False else: return self.parent_graph.__pd_path == self.__pd_path if not self.is_root else False def add_object(self, obj: PdObject) -> int: obj.parent_graph = self self.__objs.append(obj) if obj.obj_type in ["inlet", "inlet~"]: self.__inlet_objects.append(obj) # set correct let index by sorting on x position self.__inlet_objects.sort(key=lambda o: o.pos_x) for i, o in enumerate(self.__inlet_objects): o.let_index = i elif obj.obj_type in ["outlet", "outlet~"]: self.__outlet_objects.append(obj) self.__outlet_objects.sort(key=lambda o: o.pos_x) for i, o in enumerate(self.__outlet_objects): o.let_index = i return (len(self.__objs) - 1) def add_parsed_connection(self, from_index: int, from_outlet: int, to_index: int, to_inlet: int) -> None: """ Add a connection to the graph which has been parsed externally. """ try: # when connecting a Heavy object that allows mixed connection types, # try to immediately resolve to a non-mixed type based on the # object that it is connected to. connection_type = self.__objs[from_index].get_outlet_connection_type(from_outlet) if connection_type == "-~>": connection_type = self.__objs[to_index].get_inlet_connection_type(to_inlet) # make the connection c = Connection( self.__objs[from_index], from_outlet, self.__objs[to_index], to_inlet, connection_type) self.__connections.append(c) # update the local connections list # allow the connected objects to keep track of their own connections # (generally used for reporting and validation purposes) self.__objs[from_index].add_connection(c) self.__objs[to_index].add_connection(c) except Exception: self.add_error("There was an error while connecting two objects. " "Have all objects been correctly instantiated? " "Have all inlets and outlets been declared?", NotificationEnum.ERROR_UNABLE_TO_CONNECT_OBJECTS) def add_hv_arg( self, arg_index: int, name: str, value_type: str, default_value: Optional[Any], required: bool ) -> None: """ Add a Heavy argument to the graph. Indicies are from zero (not one, like Pd). """ # ensure that self.hv_args is big enough, as heavy arguments are not # necessarily added in the natural order while arg_index >= len(self.hv_args): self.hv_args.append(None) self.hv_args[arg_index] = { "name": name, "description": "", "value_type": value_type, "default": default_value, "required": required } def get_object(self, obj_index: int) -> PdObject: return self.__objs[obj_index] def get_objects(self) -> List[PdObject]: return self.__objs def get_inlet_connection_type(self, inlet_index: int) -> str: return self.__inlet_objects[inlet_index].get_inlet_connection_type(inlet_index) def get_outlet_connection_type(self, outlet_index: int) -> str: return self.__outlet_objects[outlet_index].get_outlet_connection_type(outlet_index) def validate_configuration(self) -> None: if self.is_root: if any((o.obj_type in {"inlet~", "outlet~"}) for o in self.__objs): self.add_error( "Top-level graphs may not contain inlet~ or outlet~ objects. " "Use adc~ and dac~.", NotificationEnum.ERROR_NO_TOPLEVEL_SIGNAL_LETS) if any((o.obj_type in {"inlet", "outlet"}) for o in self.__objs): self.add_warning( "Control inlets and outlets in top-level graphs don't do " "anything. Use receive and send objects.") # validate all object recursively for o in self.__objs: o.validate_configuration() def is_abstraction_on_call_stack(self, abs_path: Path) -> bool: """ Returns True if the given abstraction name is already on the call stack (i.e. it is currently being parsed). This function is used to detect recursion within abstractions. """ if self.__pd_path == abs_path: return True elif not self.is_root and self.parent_graph: return self.parent_graph.is_abstraction_on_call_stack(abs_path) else: return False def get_notices(self) -> CompilerNotif: notices = PdObject.get_notices(self) for o in self.__objs: n = o.get_notices() notices.warnings.extend(n.warnings) notices.errors.extend(n.errors) # remove ERROR_EXCEPTION if there are already other errors. # The exception is always a result of some other error if any((n.enum != NotificationEnum.ERROR_EXCEPTION) for n in notices.errors): notices.errors = [n for n in notices.errors if n.enum != NotificationEnum.ERROR_EXCEPTION] return notices def get_graph_heirarchy(self) -> List: """ Returns the "path" of this graph, indicating where it is in the graph heirarchy (i.e. with file names, etc.) """ if self.is_root: return [str(self)] elif self.parent_graph is not None: return self.parent_graph.get_graph_heirarchy() + [str(self)] else: # NOTE(dromer): we should never get here raise Exception("parent_graph argument is None") def get_depth(self) -> int: """ Returns the depth of this graph, with the root being at 1. """ if self.is_root: return 1 elif self.parent_graph is not None: return 1 + self.parent_graph.get_depth() else: # NOTE(dromer): we should never get here raise Exception("parent_graph argument is None") def to_hv(self, export_args: bool = False) -> Dict: # NOTE(mhroth): hv_args are not returned. Because all arguments have # been resolved, no arguments are otherwise passed. hv2ir would break # on required arguments that are not passed to the graph assert all(a is not None for a in self.hv_args), "Graph is missing a @hv_arg." return { "type": "graph", "imports": [], "args": self.hv_args if export_args else [], "objects": {o.obj_id: o.to_hv() for o in self.__objs}, "connections": [c.to_hv() for c in self.__connections], "properties": { "x": self.pos_x, "y": self.pos_y } } def __repr__(self) -> str: return self.subpatch_name or self.__pd_path.name hvcc-0.16.0/hvcc/interpreters/pd2hv/PdLetObject.py0000644000000000000000000000345600000000000016625 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .PdObject import PdObject class PdLetObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type in {"inlet", "inlet~", "outlet", "outlet~"} super().__init__(obj_type, obj_args, pos_x, pos_y) self.let_index = 0 def get_outlet_connection_type(self, outlet_index: int) -> Optional[str]: if len(self.obj_args) > 0 and self.obj_args[0] in {"-->", "~f>", "~i>", "-~>"}: return self.obj_args[0] else: return super().get_outlet_connection_type(outlet_index) def to_hv(self) -> Dict: return { "type": self.obj_type.strip("~"), "args": { "name": "", # Pd does not give an inlet name "index": self.let_index, "type": self.get_outlet_connection_type(self.let_index) }, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdLibSignalGraph.py0000644000000000000000000000657000000000000017600 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . from typing import List from pathlib import Path from .Connection import Connection from .HeavyObject import HeavyObject from .PdGraph import PdGraph class PdLibSignalGraph(PdGraph): def __init__( self, obj_args: List, pd_path: Path, pos_x: int = 0, pos_y: int = 0 ) -> None: super().__init__(obj_args, pd_path, pos_x, pos_y) def validate_configuration(self) -> None: """ Auto-detect control only connections to expected signal inlets and insert a sig~ (var) object inbetween to ensure it doesn't break. """ # Note(joe): only checking first inlet, should we check all inlets by # default? i.e. samphold~ has a 2nd inlet that requires checking conns = self._inlet_connections.get("0", []) # only do this if no signal connections are present if (len([c for c in conns if c.conn_type == "~f>"]) == 0) and len(conns) > 0: # add sig~ object to parent graph if self.parent_graph is not None: sig_obj = HeavyObject( obj_type="var", obj_args=[0], pos_x=int(self.pos_x), pos_y=int(self.pos_y - 5)) # shift upwards a few points self.parent_graph.add_object(sig_obj) # add connection from sig~ to this abstraction c = Connection(sig_obj, 0, self, 0, "~f>") self.parent_graph._PdGraph__connections.append(c) # update the local connections list sig_obj.add_connection(c) self.add_connection(c) # retrieve all control connections control_conns = [c for c in conns if c.conn_type == "-->"] for old_conn in control_conns: # get from obj from_obj = old_conn.from_obj # add connection from fromobj to new sig new_conn = Connection(from_obj, old_conn.outlet_index, sig_obj, 0, "-->") self.parent_graph._PdGraph__connections.append(new_conn) sig_obj.add_connection(new_conn) from_obj.add_connection(new_conn) # remove connection from fromobj self.parent_graph._PdGraph__connections.remove(old_conn) from_obj.remove_connection(old_conn) self.remove_connection(old_conn) # make sure to call parent validate_configuration() super().validate_configuration() def __repr__(self) -> str: return "[{0} {1}]".format( self._PdGraph__pd_path.stem, " ".join(self.obj_args[1:])) hvcc-0.16.0/hvcc/interpreters/pd2hv/PdMessageObject.py0000644000000000000000000000554100000000000017462 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . import re from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdMessageObject(PdObject): # only allow dollar argumnets if they are alone __RE_DOLLAR = re.compile(r"\$(\d+)") def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type == "msg" super().__init__("msg", obj_args, pos_x, pos_y) self.obj_dict: Dict = {} semi_split: List = [] # parse messages # remove prepended slash from $. Heavy does not use that. if obj_args is not None: semi_split = obj_args[0].replace(r"\$", "$").split(r"\;") semi_split = [x for x in semi_split if x] # remove empty strings # parse local messages # ensure that empty message are not passed on if len(semi_split) > 0: self.obj_dict["local"] = [li.strip().split() for li in semi_split[0].split(r"\,") if len(li.strip()) > 0] else: self.obj_dict["local"] = [] self.add_warning( "Message object is empty. Can it be removed?", NotificationEnum.WARNING_EMPTY_MESSAGE) # heavy does not support messages such as "$1-$2" for li in self.obj_dict["local"]: for m in li: x = self.__RE_DOLLAR.search(m) if x and len(x.group(0)) < len(m): self.add_error( "Heavy does not yet support message concatenation. " "Dollar arguments must be alone: " + m) # parse remote messages self.obj_dict["remote"] = [] for li in semi_split[1:]: l_split = li.strip().split() self.obj_dict["remote"].append({ "receiver": l_split[0], "message": l_split[1:] }) def to_hv(self) -> Dict: return { "type": "message", "args": self.obj_dict, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdObject.py0000644000000000000000000001603300000000000016153 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2024 Wasted Audio # # 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 . from collections import defaultdict import random import string from typing import Optional, List, Dict, TYPE_CHECKING from .Connection import Connection from .NotificationEnum import NotificationEnum from hvcc.types.compiler import CompilerMsg, CompilerNotif if TYPE_CHECKING: from .PdGraph import PdGraph class PdObject: __RANDOM = random.Random() __ID_CHARS = string.ascii_letters + string.digits def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: self.obj_type = obj_type # all arguments should be resolved when passed to a PdObject self.obj_args = obj_args or [] self.obj_id = "{0}_{1}".format( obj_type, "".join(self.__RANDOM.choice(self.__ID_CHARS) for _ in range(8))) self.pos_x = pos_x self.pos_y = pos_y # this is set when the object is added to a graph self.parent_graph: Optional['PdGraph'] = None self._inlet_connections: Dict = defaultdict(list) self._outlet_connections: Dict = defaultdict(list) self._warnings: List[CompilerMsg] = [] self._errors: List[CompilerMsg] = [] def add_warning(self, warning: str, enum: NotificationEnum = NotificationEnum.WARNING_GENERIC) -> None: """ Add a warning regarding this object. """ self._warnings.append(CompilerMsg(enum=enum, message=warning)) def add_error(self, error: str, enum: NotificationEnum = NotificationEnum.ERROR_GENERIC) -> None: """ Add an error regarding this object. """ self._errors.append(CompilerMsg(enum=enum, message=error)) def get_notices(self) -> CompilerNotif: """ Returns a dictionary of all warnings and errors at this object. """ # TODO(mhroth): we might want to consider moving to a more expressive format. # { # "objectType": "trigger", # "objectString": "t l l", # "graphs": ["_main", "hello"], # "rawText": "Heavy only supports arguments 'a', 'f', 's', and 'b'.", # "humanText": "[t l l] in "_main/osc~" @ (x:452, y:273): Heavy only supports # arguments 'a', 'f', 's', and 'b'.", # "position": { # "x": 452, # "y": 273 # } # } """ { "warnings": [{ "enum": 1000, "message": "this is a warning" }], "errors": [{ "enum": 2000, "message": "this is an error" }] } """ return CompilerNotif( has_error=len(self._errors) > 0, warnings=[ CompilerMsg(enum=n.enum, message="{0} in \"{1}\" @ (x:{2}, y:{3}): {4}".format( self, "/".join(self.get_graph_heirarchy()), self.pos_x, self.pos_y, n.message )) for n in self._warnings ], errors=[ CompilerMsg(enum=n.enum, message="{0} in \"{1}\" @ (x:{2}, y:{3}): {4}".format( self, "/".join(self.get_graph_heirarchy()), self.pos_x, self.pos_y, n.message )) for n in self._errors ] ) def get_inlet_connections(self) -> Dict: return self._inlet_connections def get_outlet_connections(self) -> Dict: return self._outlet_connections def get_inlet_connection_type(self, inlet_index: int) -> Optional[str]: """ Returns the inlet connection type of this Pd object. For the sake of convenience, the connection type is reported in Heavy's format. """ return "~f>" if self.obj_type.endswith("~") else "-->" def get_outlet_connection_type(self, outlet_index: int) -> Optional[str]: """ Returns the outlet connection type of this Pd object. For the sake of convenience, the connection type is reported in Heavy's format. """ return "~f>" if self.obj_type.endswith("~") else "-->" def add_connection(self, c: Connection) -> None: """ Adds a connection, either inlet or outlet, to this object. """ if c.from_id == self.obj_id: self._outlet_connections[str(c.outlet_index)].append(c) elif c.to_id == self.obj_id: self._inlet_connections[str(c.inlet_index)].append(c) else: raise Exception("Adding a connection to the wrong object!") def remove_connection(self, c: Connection) -> None: """ Remove a connection to this object. """ if c.to_obj is self: self._inlet_connections[str(c.inlet_index)].remove(c) elif c.from_obj is self: self._outlet_connections[str(c.outlet_index)].remove(c) else: raise Exception(f"Connection {c} does not connect to this object {self}.") def get_graph_heirarchy(self) -> List: """ Returns an indication of the graph "path" of this object. It only includes unique graphs (not subpatches) E.g. _main/tabosc4~ The check for None is in case the object is somehow not yet attached. """ return self.parent_graph.get_graph_heirarchy() \ if self.parent_graph is not None else ["unattached"] def validate_configuration(self) -> None: """ Called when all graphs are finished parsing, from the root. Gives each object the chance to validate it's configuration, including connections. In general this function does nothing, though it may add warnings and errors. Note that object validation occurs when the entire patch is finished parsing and before it is returned to the user. The program may assume that all parameters and variables have been set. """ pass @classmethod def get_supported_objects(cls) -> set: """ Returns a list of Pd objects that this class can parse. """ raise NotImplementedError() def to_hv(self) -> Dict: """ Returns the HeavyLang JSON representation of this object. """ raise NotImplementedError() def __repr__(self) -> str: if len(self.obj_args) == 0: return f"[{self.obj_type}]" else: return f"[{self.obj_type} {' '.join([str(o) for o in self.obj_args])}]" hvcc-0.16.0/hvcc/interpreters/pd2hv/PdPackObject.py0000644000000000000000000000363600000000000016757 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdPackObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type == "pack" super().__init__(obj_type, obj_args, pos_x, pos_y) self.values = [] if len(self.obj_args) == 0: self.values = [0.0, 0.0] for i, x in enumerate(self.obj_args): try: self.values.append(float(x)) except Exception: if x in ("f", "float") or (i > 0 and x in ("s", "symbol")): self.values.append(0.0) else: self.add_error( f"\"{x}\" argument to [pack] object not supported.", NotificationEnum.ERROR_PACK_FLOAT_ARGUMENTS) def to_hv(self) -> Dict: return { "type": "__pack", "args": { "values": self.values }, "properties": { "x": self.pos_x, "y": self.pos_y } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdParser.py0000644000000000000000000011011100000000000016171 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import decimal import os import re from collections import Counter from collections import OrderedDict from pathlib import Path from typing import Optional, Type, Any, Generator from .HeavyObject import HeavyObject from .HeavyGraph import HeavyGraph # pre-converted Heavy graphs from .HvSwitchcase import HvSwitchcase # __switchcase from .PdAudioIoObject import PdAudioIoObject # adc~/dac~ from .PdBinopObject import PdBinopObject # binary arithmatic operators from .PdExprObject import PdExprObject # expr/expr~ from .PdGraph import PdGraph # canvas from .PdLetObject import PdLetObject # inlet/inlet~/outlet/outlet~ from .PdMessageObject import PdMessageObject # msg from .PdPackObject import PdPackObject # pack from .PdReceiveObject import PdReceiveObject # r/r~/receive/receive~/catch~ from .PdRouteObject import PdRouteObject # route from .PdSelectObject import PdSelectObject # select/sel from .PdSendObject import PdSendObject # s/s~/send/send~/throw~ from .PdTriggerObject import PdTriggerObject # trigger/t from .PdTableObject import PdTableObject # table from .PdUnpackObject import PdUnpackObject # unpack from .PdLibSignalGraph import PdLibSignalGraph # pd/lib abstraction connection checks from .NotificationEnum import NotificationEnum class PdParser: # library search paths __LIB_DIR = Path(Path(__file__).parent, "libs") __HVLIB_DIR = Path(Path(__file__).parent, "libs", "heavy") __HVLIB_CONVERTED_DIR = Path(Path(__file__).parent, "libs", "heavy_converted") __PDLIB_DIR = Path(Path(__file__).parent, "libs", "pd") __ELSELIB_DIR = Path(Path(__file__).parent, "libs", "else") __CYCLONE_DIR = Path(Path(__file__).parent, "libs", "cyclone") __PDLIB_CONVERTED_DIR = Path(Path(__file__).parent, "libs", "pd_converted") # detect a dollar argument in a string RE_DOLLAR = re.compile(r"\$(\d+)") # detect width parameter e.g. "#X obj 172 79 t b b, f 22;" RE_WIDTH = re.compile(r", f \d+$") # split arguments on non-escaped spaces e.g. "test\ ing" RE_SPACE = re.compile(r'(? None: # the current global value of $0 # Note(joe): set a high starting value to avoid potential user naming conflicts self.__DOLLAR_ZERO = 1000 # a counter of all Pd objects in the graph self.obj_counter: Counter = Counter() # search paths at this graph level self.search_paths: list[Path] = [] @classmethod def get_supported_objects(cls) -> list: """ Returns a set of all pd objects names supported by the parser. """ pd_objects = [os.path.splitext(f)[0] for f in os.listdir(cls.__PDLIB_DIR) if f.endswith(".pd")] pd_objects += [f"else/{os.path.splitext(f)[0]}" for f in os.listdir(cls.__ELSELIB_DIR) if f.endswith(".pd")] pd_objects += [f"cyclone/{os.path.splitext(f)[0]}" for f in os.listdir(cls.__CYCLONE_DIR) if f.endswith(".pd")] pd_objects.extend(cls.__PD_CLASSES.keys()) return pd_objects @classmethod def __get_hv_args(cls, pd_path: Path) -> OrderedDict: """ Pre-parse the file for Heavy arguments, such that they are available as soon as a graph is created. """ num_canvas = -1 hv_arg_dict = OrderedDict() hv_arg_list: Optional[list] = None with open(pd_path, "r") as f: for li in f: if li.startswith("#N canvas"): hv_arg_list = [] hv_arg_dict[li.rstrip(";\r\n")] = hv_arg_list num_canvas += 1 elif "@hv_arg" in li and hv_arg_list is not None: hv_arg_list.append(li.rstrip(";\r\n")) elif li.startswith("#X restore"): num_canvas -= 1 hv_arg_list = list(hv_arg_dict.values())[num_canvas] return hv_arg_dict @classmethod def get_pd_line(cls, pd_path: Path) -> Generator: concat = "" # concatination state with open(pd_path, "r") as f: for li in f: # concatenate split lines in the Pd file here li = li.rstrip("\r\n") # account for windows CRLF if li.endswith(";") and not li.endswith(r"\;"): out = li[:-1] # remove single ";" if len(concat) > 0: out = f'{concat} {out}' concat = "" # reset concatenation state yield out else: concat = (f'{concat} {li}') if len(concat) > 0 else f'{li}' @classmethod def split_line(cls, li: str) -> list[str]: # remove width parameter li = cls.RE_WIDTH.sub("", li) # split on non-escaped spaces line = cls.RE_SPACE.split(li) # replace escaped spaces line = [i.replace('\\ ', ' ') for i in line] return line def add_absolute_search_directory(self, search_dir: Path) -> bool: if search_dir.is_dir(): self.search_paths.append(search_dir) return True else: return False def add_relative_search_directory(self, search_dir: Path) -> bool: search_dir = Path( self.search_paths[0], search_dir ).absolute() return self.add_absolute_search_directory(search_dir) def find_abstraction_path(self, local_dir: Path, abs_name: str) -> Optional[Path]: """ Finds the full path for an abstraction. Checks the local directory first, then all declared paths. """ abs_filename = f"{abs_name}.pd" # check local directory first abs_path = Path(local_dir.absolute(), abs_filename) if abs_path.is_file(): return abs_path # check search paths in reverse order (last added search path first) for d in reversed(self.search_paths): abs_path = Path(d, abs_filename) if abs_path.is_file(): return abs_path return None def graph_from_file( self, file_path: Path, obj_args: Optional[list] = None, pos_x: int = 0, pos_y: int = 0, is_root: bool = True, pd_graph_class: Type[PdGraph] = PdGraph ) -> Any: """ Instantiate a PdGraph from a file. Note that obj_args does not include $0. @param pd_graph_class The python class to handle specific graph types """ # add main patch directory. The first entry of self.search_paths is # assumed to be the root path of the whole system if is_root: self.search_paths.append(file_path.parent) file_hv_arg_dict = self.__get_hv_args(file_path) file_iterator = self.get_pd_line(file_path) canvas_line: str = file_iterator.__next__() self.__DOLLAR_ZERO += 1 # increment $0 graph_args = [self.__DOLLAR_ZERO] + (obj_args or []) if not canvas_line.startswith("#N canvas"): g_cls = pd_graph_class(graph_args, file_path, pos_x, pos_y) g_cls.add_error(f"Pd files must begin with \"#N canvas\": {canvas_line}") return g_cls g: PdGraph = self.graph_from_canvas( file_iterator, file_hv_arg_dict, canvas_line, graph_args, file_path, pos_x, pos_y, is_root, pd_graph_class) if is_root: if g.get_notices().has_error: # return the graph early here as there are already errors and it is # clearly invalid, avoids triggering unrelated errors in validation return g g.validate_configuration() return g def graph_from_canvas( self, file_iterator: Generator, file_hv_arg_dict: dict[str, list[str]], canvas_line: str, graph_args: list, pd_path: Path, pos_x: int = 0, pos_y: int = 0, is_root: bool = False, pd_graph_class: Type[PdGraph] = PdGraph ) -> Any: """ Instantiate a PdGraph from an existing canvas. Note that graph_args includes $0. @param file_hv_arg_dict A dictionary containing all Heavy argument lines for each "#N canvas" in this file. @param canvas_line The "#N canvas" which initiates this canvas. @param pd_graph_class The python class to handle specific graph types """ obj_array: Optional[HeavyObject] = None # an #A (table) object which is currently being parsed def finalize_array(array: HeavyObject) -> None: declared_size = array.obj_dict["size"] values_size = len(array.obj_dict["values"]) if declared_size != values_size: new_size = max(declared_size, values_size) array.add_warning( "Table \"{0}\" was declared as having {1} values, " "but {2} were supplied. It will be resized to {3} " "values (any unsupplied values will be zeroed).".format( array.obj_dict["name"], declared_size, values_size, new_size)) array.obj_dict["size"] = new_size if new_size < declared_size: array.obj_dict["values"] = obj_args["values"][:new_size] else: array.obj_dict["values"].extend([0.0 for _ in range(new_size - declared_size)]) g = pd_graph_class(graph_args, pd_path, pos_x, pos_y) msg_send: dict = {} gui_send: dict = {} gui_recv: dict = {} # parse and add all Heavy arguments to the graph for li in file_hv_arg_dict[canvas_line]: line = li.split() assert line[4] == "@hv_arg" is_required = (line[9] == "true") default_value = HeavyObject.force_arg_type(line[8], line[7]) if not is_required else None g.add_hv_arg( arg_index=int(line[5][2:]) - 1, # strip off the leading "\$" and make index zero-based name=line[6], value_type=line[7], default_value=default_value, required=is_required) try: # this try will capture any critical errors for li in file_iterator: line = self.split_line(li) if line[0] == "#N": if line[1] == "canvas": x = self.graph_from_canvas( file_iterator, file_hv_arg_dict, canvas_line=li, graph_args=graph_args, # subpatch inherits parent graph arguments, including $0 pd_path=pd_path, pos_x=int(line[2]), pos_y=int(line[3])) g.add_object(x) elif line[0] == "#X": if line[1] == "restore": if len(line) > 5 and line[5] == "@hv_obj": obj_args = self.__resolve_object_args( obj_args=line[7:], graph=g, raise_on_failure=False, is_root=is_root) if line[6] == "__switchcase": x = HvSwitchcase( obj_type=line[6], obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3])) else: x = HeavyObject( obj_type=line[6], obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3])) return x # return a Heavy object instead of a graph else: # are we restoring an array object? # do some final sanity checks if obj_array is not None: finalize_array(obj_array) obj_array = None # done parsing the array # set the subpatch name g.subpatch_name = " ".join(line[5:]) if len(line) > 5 else "subpatch" g = self.__create_send_recv(g, msg_send, gui_send, gui_recv) return g # pop the graph elif line[1] == "text": # @hv_arg arguments are pre-parsed # TODO(mhroth): is it necessary to split the entire line at once? # always add the comment to the graph, regardless self.obj_counter["text"] += 1 g.add_object(HeavyObject( obj_type="comment", obj_args=[" ".join(line[4:])], pos_x=int(line[2]), pos_y=int(line[3]))) elif line[1] == "obj": x = None # a PdObject if len(line) > 4: obj_type = line[4] # sometimes objects have $ arguments in them as well obj_type = self.__resolve_object_args( obj_args=[obj_type], graph=g, is_root=is_root)[0] obj_args = self.__resolve_object_args( obj_args=line[5:], graph=g, is_root=is_root) else: g.add_warning( "This graph contains an empty object. " "It should be removed or defined.", NotificationEnum.WARNING_EMPTY_OBJECT) g.add_object(HeavyObject( obj_type="comment", obj_args=["null object placeholder"], pos_x=int(line[2]), pos_y=int(line[3]))) continue if obj_type in ('block~',): # we ignore the object and continue g.add_warning( f"This graph contains a {obj_type} object that is ignored.", NotificationEnum.WARNING_USELESS_OBJECT) g.add_object(HeavyObject( obj_type="comment", obj_args=[f"{obj_type} object placeholder"], pos_x=int(line[2]), pos_y=int(line[3]))) continue # do we have an abstraction for this object? abs_path = self.find_abstraction_path(pd_path.parent, obj_type) if abs_path is not None and not g.is_abstraction_on_call_stack(abs_path): # ensure that infinite recursion into abstractions is not possible x = self.graph_from_file( file_path=abs_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False) # is this object in lib/pd_converted? elif Path(self.__PDLIB_CONVERTED_DIR, f"{obj_type}.hv.json").is_file(): self.obj_counter[obj_type] += 1 hv_path = Path(self.__PDLIB_CONVERTED_DIR, f"{obj_type}.hv.json") x = HeavyGraph( hv_path=hv_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3])) # is this object in lib/heavy_converted? elif Path(self.__HVLIB_CONVERTED_DIR, f"{obj_type}.hv.json").is_file(): self.obj_counter[obj_type] += 1 hv_path = Path(self.__HVLIB_CONVERTED_DIR, f"{obj_type}.hv.json") x = HeavyGraph( hv_path=hv_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3])) # is this object in lib/pd? elif Path(self.__PDLIB_DIR, f"{obj_type}.pd").is_file(): self.obj_counter[obj_type] += 1 pdlib_path = Path(self.__PDLIB_DIR, f"{obj_type}.pd") # mapping of pd/lib abstraction objects to classes # for checking connection validity pd_class = { "abs~": PdLibSignalGraph, "clip~": PdLibSignalGraph, "cos~": PdLibSignalGraph, "dbtopow~": PdLibSignalGraph, "dbtorms~": PdLibSignalGraph, "exp~": PdLibSignalGraph, "ftom~": PdLibSignalGraph, "hip~": PdLibSignalGraph, "lop~": PdLibSignalGraph, "mtof~": PdLibSignalGraph, "powtodb~": PdLibSignalGraph, "q8_rsqrt~": PdLibSignalGraph, "q8_sqrt~": PdLibSignalGraph, "rmstodb~": PdLibSignalGraph, "rsqrt~": PdLibSignalGraph, "sqrt~": PdLibSignalGraph, "wrap~": PdLibSignalGraph }.get(obj_type, PdGraph) x = self.graph_from_file( file_path=pdlib_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False, pd_graph_class=pd_class) # register any object-specific warnings or errors if obj_type in {"rzero~", "rzero_rev~", "czero~", "czero_rev~"}: g.add_warning( f"[{obj_type}] accepts only signal input. " "Arguments and control connections are ignored.") # is this object in lib/heavy? elif Path(self.__HVLIB_DIR, f"{obj_type}.pd").is_file(): self.obj_counter[obj_type] += 1 hvlib_path = Path(self.__HVLIB_DIR, f"{obj_type}.pd") x = self.graph_from_file( file_path=hvlib_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False) # is this object in lib/else? elif Path(self.__ELSELIB_DIR, f"{obj_type}.pd").is_file(): self.obj_counter[obj_type] += 1 hvlib_path = Path(self.__ELSELIB_DIR, f"{obj_type}.pd") x = self.graph_from_file( file_path=hvlib_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False) # is this object in lib/cyclone? elif Path(self.__CYCLONE_DIR, f"{obj_type}.pd").is_file(): self.obj_counter[obj_type] += 1 hvlib_path = Path(self.__CYCLONE_DIR, f"{obj_type}.pd") x = self.graph_from_file( file_path=hvlib_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False) # is this object in lib? (sub-directory) elif Path(self.__LIB_DIR, f"{obj_type}.pd").is_file(): self.obj_counter[obj_type] += 1 hvlib_path = Path(self.__LIB_DIR, f"{obj_type}.pd") x = self.graph_from_file( file_path=hvlib_path, obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False) # is this an object that must be programatically parsed? elif obj_type in self.__PD_CLASSES: self.obj_counter[obj_type] += 1 obj_class = self.__PD_CLASSES[obj_type] x = obj_class( obj_type, obj_args, pos_x=int(line[2]), pos_y=int(line[3])) elif self.__is_float(obj_type): # parse float literals self.obj_counter["float"] += 1 x = HeavyObject( obj_type="__var", obj_args=[float(obj_type)], pos_x=int(line[2]), pos_y=int(line[3])) else: g.add_error( f"Don't know how to parse object \"{obj_type}\". Is it an " "object supported by Heavy? Is it an abstraction? " "Have the search paths been correctly configured?", NotificationEnum.ERROR_UNKNOWN_OBJECT) x = HeavyObject( obj_type="comment", obj_args=[f"null object placeholder ({obj_type})"]) assert x is not None index = g.add_object(x) # add gui send/receive objects arg_index = { "nbx": (6, 7), "vsl": (6, 7), "hsl": (6, 7), "vradio": (4, 5), "hradio": (4, 5), "bng": (4, 5), "tgl": (2, 3), "knob": (5, 6), "else/knob": (5, 6), } if obj_type in arg_index.keys(): send_index = arg_index[obj_type][0] recv_index = arg_index[obj_type][1] if obj_args[send_index] != "empty": gui_send[index] = obj_args[send_index] if obj_args[recv_index] != "empty": gui_recv[index] = obj_args[recv_index] elif line[1] in ("floatatom", "symbolatom"): self.obj_counter[line[1]] += 1 obj_args = self.__resolve_object_args( obj_args=line[1:], graph=g, is_root=is_root) x = self.graph_from_file( file_path=Path(self.__PDLIB_DIR, f"{line[1]}.pd"), obj_args=obj_args, pos_x=int(line[2]), pos_y=int(line[3]), is_root=False) index = g.add_object(x) # symbolatom is not supported # due to symbol/__var implementation if line[1] == "floatatom": if obj_args[9] != "-": gui_send[index] = obj_args[9] if obj_args[8] != "-": gui_recv[index] = obj_args[8] elif line[1] == "array": # are we still parsing a previous array? finalize it. if obj_array is not None: finalize_array(obj_array) # array names can have dollar arguments in them. # ensure that they are resolved table_def = self.__resolve_object_args( obj_args=[line[2]], graph=g)[0].split(" ") table_name = table_def[0] # check if we need to extern the table if len(table_def) > 1: table_extern = table_def[1] == "@hv_table" else: table_extern = False # Pd encodes arrays with length greater than 999,999 with # scientific notatation (e.g. 1e6) which Python's int() can't parse table_size = int(decimal.Decimal(line[3])) obj_array = HeavyObject( obj_type="table", # ensure that obj_array has its own values instance obj_args=[table_name, table_size, [], table_extern]) # TODO(mhroth): position information g.add_object(obj_array) elif line[1] == "msg": self.obj_counter["msg"] += 1 msg = PdMessageObject( obj_type="msg", obj_args=[" ".join(line[4:])], pos_x=int(line[2]), pos_y=int(line[3])) index = g.add_object(msg) if len(msg.obj_dict) > 0: msg_send[index] = [] for remote in msg.obj_dict["remote"]: msg_send[index].append(remote) elif line[1] == "connect": g.add_parsed_connection( from_index=int(line[2]), from_outlet=int(line[3]), to_index=int(line[4]), to_inlet=int(line[5])) elif line[1] == "declare": if not is_root: g.add_warning( "[declare] objects are not supported in abstractions. " "They can only be in the root canvas.") elif len(line) >= 4 and line[2] == "-path": pd_parent = pd_path.parent pd_search = Path(pd_parent, line[3]) did_add = self.add_relative_search_directory(pd_search) if not did_add: g.add_warning( f"\"{line[3]}\" is not a valid relative abstraction " "search path. It will be ignored.") else: g.add_warning( "Heavy only supports the -path flag for the " "declare object.", NotificationEnum.WARNING_DECLARE_PATH) elif line[1] == "coords": pass # don't do anything with this command elif line[1] == "f": # A line such as "#X f 123" # is found after a "#X restore" when the [pd afasdfasd] # object's box has been resized pass # don't do anything with this command else: g.add_error(f"Don't know how to parse line: {' '.join(line)}") elif line[0] == "#A" and obj_array is not None: # Test that we have an array continuation and extend the array values. try: float(line[1]) obj_array.obj_dict["values"].extend([float(f) for f in line[2:] if f != ""]) except ValueError: continue else: g.add_error(f"Don't know how to parse line: {' '.join(line)}") except Exception as e: # bubble the Exception back to the root graph where the graph # will be returned if not g.is_root: raise e else: # NOTE(mhroth): should the exception be added as an error? # Sometimes it's all that we have, so perhaps it's a good idea. g.add_error(str(e), NotificationEnum.ERROR_EXCEPTION) g = self.__create_send_recv(g, msg_send, gui_send, gui_recv) return g @classmethod def __resolve_object_args( cls, obj_args: list, graph: PdGraph, raise_on_failure: bool = True, is_root: bool = False ) -> Any: """ Resolve object arguments against the given graph arguments. By default this function raises an Exception if it cannot resolve an argument. This behaviour may be disabled, in which case the unresolved argument is replaced with None (which is an otherwise invalid value). A value of None typically indicates to a HeavyObject that the default value may be used. """ # TODO(mhroth): can this be done more elegantly? resolved_obj_args = list(obj_args) # make a copy of the original obj_args for i, a in enumerate(obj_args): for m in set(cls.RE_DOLLAR.findall(a)): assert isinstance(a, str) x = int(m) # the dollar index (i.e. $x) if len(graph.obj_args) > x: a = a.replace(fr"\${m}", str(graph.obj_args[x])) # check if hv_args can be used to supply a default value elif len(graph.hv_args) > (x - 1): # heavy args are zero-indexed if not graph.hv_args[x - 1]["required"]: a = a.replace(fr"\${m}", str(graph.hv_args[x - 1]["default"])) else: graph.add_error( f"There is a missing required argument named \"{graph.hv_args[x - 1]['name']}\".", NotificationEnum.ERROR_MISSING_REQUIRED_ARGUMENT) elif is_root: # NOTE(mhroth): this case is questionable, but since Pd # defaults to this behavior without warning, so will we. # graph.add_warning( # "${0} in \"{1}\" in the top-level graph is resolved to " # "\"0\". It is recommended that you remove $-arguments " # "from the top-level graph.".format(m, a)) a = a.replace(fr"\${m}", "0") else: if raise_on_failure: # NOTE(mhroth): this case is questionable, but since Pd # defaults to this behavior without warning, so will we. # graph.add_warning( # "Object [{0}] requires argument \"{1}\" but the parent " # "patch does not provide one ({2}). A default value of " # "\"0\" will be used.".format(obj_type, a, graph.obj_args)) a = a.replace(fr"\${m}", "0") else: a = None # indicate that this argument could not be resolved by replacing it with None resolved_obj_args[i] = a return resolved_obj_args # a mapping of Pd objects to the classes that will parse them __PD_CLASSES = { "adc~": PdAudioIoObject, "dac~": PdAudioIoObject, "expr": PdExprObject, "expr~": PdExprObject, "inlet": PdLetObject, "inlet~": PdLetObject, "outlet": PdLetObject, "outlet~": PdLetObject, "pack": PdPackObject, "pd": PdGraph, "route": PdRouteObject, "sel": PdSelectObject, "select": PdSelectObject, "t": PdTriggerObject, "trigger": PdTriggerObject, "table": PdTableObject, "unpack": PdUnpackObject, "s": PdSendObject, "send": PdSendObject, "s~": PdSendObject, "send~": PdSendObject, "throw~": PdSendObject, "r": PdReceiveObject, "receive": PdReceiveObject, "r~": PdReceiveObject, "receive~": PdReceiveObject, "catch~": PdReceiveObject } # fill in as much of __PD_CLASSES programmatically as possible for o in PdBinopObject.get_supported_objects(): __PD_CLASSES[o] = PdBinopObject @classmethod def __is_float(cls, x: int) -> bool: """ Returns True if the input can be converted to a float. False otherwise. """ try: float(x) return True except Exception: return False def __create_send_recv( self, g: PdGraph, msg_send: dict, gui_send: dict, gui_recv: dict ) -> PdGraph: # parse remote messages for index in msg_send.keys(): first_msg = g.get_object(index) conns = first_msg.get_inlet_connections() for remote in msg_send[index]: self.obj_counter["msg"] += 1 msg = PdMessageObject("msg", [" ".join(msg for msg in remote["message"])]) msg_index = g.add_object(msg) self.obj_counter["send"] += 1 send = PdSendObject("send", [remote["receiver"]]) send_index = g.add_object(send) # connect new message to upstream objects of first message for conn in conns["0"]: up_obj = conn.from_obj up_index = g.get_objects().index(up_obj) g.add_parsed_connection(up_index, 0, msg_index, 0) g.add_parsed_connection(msg_index, 0, send_index, 0) # parse gui sends for index in gui_send.keys(): self.obj_counter["send"] += 1 send = PdSendObject('send', gui_send[index].split()) send_index = g.add_object(send) g.add_parsed_connection(index, 0, send_index, 0) # parse gui receives for index in gui_recv.keys(): self.obj_counter["receive"] += 1 recv = PdReceiveObject('receive', gui_recv[index].split()) recv_index = g.add_object(recv) g.add_parsed_connection(recv_index, 0, index, 0) return g hvcc-0.16.0/hvcc/interpreters/pd2hv/PdRaw.py0000644000000000000000000000545000000000000015477 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import List, Dict class PdRawException(Exception): pass def replace_owl(args: List) -> List: new_args = [] for arg in args: new_arg = arg.replace('owl', 'raw') new_args.append(new_arg) return new_args def parse_pd_raw_args(args: List) -> Dict: """Parses a list of puredata send or receive objects looking for @raw and legacy @owl* annotations, parsing everything and throwing errors when syntax is not correct or values are of incorrect type""" attrdict = {} # define default values attrdict["min"] = 0.0 attrdict["max"] = 1.0 args = replace_owl(args) # TODO(dromer): deprecate @owl on next stable release for raw_param in {'@raw', '@raw_min', '@raw_max', '@raw_default', '@raw_param'}: if raw_param not in args: continue i = args.index(raw_param) if raw_param in {'@raw', '@raw_param'}: try: attrdict["raw"] = args[i + 1] except IndexError: raise PdRawException(f"{raw_param} annotation missing assigned parameter") if raw_param == '@raw': try: # expect the presence of up to 3 parameters which can be converted to float attrdict["min"] = float(args[i + 2]) attrdict["max"] = float(args[i + 3]) attrdict["default"] = float(args[i + 4]) except (IndexError, ValueError): # otherwise keep default pass elif raw_param in {'@raw_min', '@raw_max', '@raw_default'}: # make sure that it is a float value try: attrdict[raw_param.split('@raw_')[1]] = float(args[i + 1]) except ValueError: raise PdRawException(f"{raw_param} annotation value '{args[i + 1]}' is not numeric") except IndexError: raise PdRawException(f"{raw_param} annotation is missing its value") if attrdict.get("default") is None: attrdict["default"] = (attrdict["max"] - attrdict["min"]) / 2.0 return attrdict hvcc-0.16.0/hvcc/interpreters/pd2hv/PdReceiveObject.py0000644000000000000000000001306600000000000017461 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .PdObject import PdObject from .PdRaw import parse_pd_raw_args, PdRawException class PdReceiveObject(PdObject): __INSTANCE_COUNTER = 0 def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type in {"r", "r~", "receive", "receive~", "catch~"} super().__init__(obj_type, obj_args, pos_x, pos_y) self.__receiver_name = "" self.__extern_type = None self.__attributes: Dict = {} self.__priority = None # priority is not set PdReceiveObject.__INSTANCE_COUNTER += 1 self.__instance = PdReceiveObject.__INSTANCE_COUNTER try: # receive objects don't necessarily need to have a name self.__receiver_name = self.obj_args[0] # only extern control rate receivers if obj_type in ("r", "receive"): # NOTE(mhroth): the second argument is _either_ externing the receiver or setting the priority # This means that right now priority cannot be set on externed receivers if self.obj_args[1] == "@hv_param": self.__extern_type = "param" elif self.obj_args[1] == "@hv_event": self.__extern_type = "event" elif int(self.obj_args[1]): self.__priority = int(self.obj_args[1]) except Exception: pass if self.__extern_type == "param": try: self.__attributes = { "min": 0.0, "max": 1.0, "default": 0.5, "type": "float" } self.__attributes["min"] = float(self.obj_args[2]) self.__attributes["max"] = float(self.obj_args[3]) self.__attributes["default"] = float(self.obj_args[4]) self.__attributes["type"] = str(self.obj_args[5]) except ValueError: self.add_warning( f"Minimum, maximum, and default values for Parameter {self.__receiver_name} must be numbers.") except Exception: pass if not (self.__attributes["min"] <= self.__attributes["default"]): self.add_error("Default parameter value is less than the minimum. " "Receiver will not be exported: {0:g} < {1:g}".format( self.__attributes["default"], self.__attributes["min"])) self.__extern_type = None if not (self.__attributes["default"] <= self.__attributes["max"]): self.add_error("Default parameter value is greater than the maximum. " "Receiver will not be exported: {0:g} > {1:g}".format( self.__attributes["default"], self.__attributes["max"])) self.__extern_type = None if '@raw' in self.obj_args or '@owl' in self.obj_args: # TODO(dromer): deprecate @owl on next stable release try: pd_raw_args = parse_pd_raw_args(self.obj_args) self.__attributes.update(pd_raw_args) self.__extern_type = "param" # make sure output code is generated except PdRawException as e: self.add_error(str(e)) def validate_configuration(self) -> None: if self.obj_type in ("r~", "receive~"): if len(self._inlet_connections.get("0", [])) > 0: self.add_error("[receive~] inlet connections are not supported.") def to_hv(self) -> Dict: # note: control rate send objects should not modify their name argument names = { "r": "", "receive": "", "r~": "sndrcv_sig_", "receive~": "sndrcv_sig_", "catch~": "thrwctch_sig_" } # NOTE(mhroth): we follow Pd's execution rule: deeper receivers fire first. # Receivers on the same level fire in the order of instantiation. if self.parent_graph is not None and \ ((self.__priority is None) or (self.__receiver_name == "__hv_init" and self.__priority == 0)): self.__priority = (self.parent_graph.get_depth() * 1000) - self.__instance return { "type": "receive", "args": { "name": f"{names[self.obj_type]}{self.__receiver_name}", "extern": self.__extern_type, "attributes": self.__attributes, "priority": self.__priority }, "properties": { "x": self.pos_x, "y": self.pos_y }, "annotations": { "scope": "public" } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdRouteObject.py0000644000000000000000000001423600000000000017175 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from collections import Counter from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdRouteObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type == "route" super().__init__(obj_type, obj_args, pos_x, pos_y) if obj_args is not None: if len(obj_args) == 0: self.add_error("At least one argument is required.") # NOTE(joe): disabling this warning as it can be quite annoying. # if len(set(obj_args) & set(["bang", "list", "float", "symbol"])) > 0: # self.add_warning( # "Heavy interprets route arguments such as \"bang\", \"list\", \"float\", " # "and \"symbol\" literally. They cannot be used to filter generic " # "messages as in Pd.") if len(set(obj_args)) != len(obj_args): c = Counter(obj_args).most_common(1) self.add_error( f"All arguments to [route] must be unique. Argument \"{c[0][0]}\" is repeated {c[0][1]} times.", NotificationEnum.ERROR_UNIQUE_ARGUMENTS_REQUIRED) # convert to obj_args to mixedarray, such that correct switchcase hash # is generated for i, a in enumerate(self.obj_args): try: self.obj_args[i] = float(a) except Exception: pass def validate_configuration(self) -> None: if len(self._inlet_connections.get("1", [])) > 0: self.add_warning("The right inlet of route is not supported. It will not do anything.") def to_hv(self) -> Dict: """Creates a graph dynamically based on the number of arguments. An unconnected right inlet is added. [inlet] [inlet] | [@hv_obj switchcase [arg list (N elements)] ] | | | [@hv_obj __slice 1 -1] [@hv_obj __slice 1 -1] | | | | | | [outlet_0] [outlet_N-1] [outlet_right] """ route_graph: Dict = { "type": "graph", "imports": [], "args": [], "objects": { "inlet": { "type": "inlet", "args": { "type": "-->", "index": 0 }, "properties": {"x": 0, "y": 0} }, "inlet_right": { "type": "inlet", "args": { "type": "-->", "index": 1 }, "properties": {"x": 0, "y": 0} }, "switchcase": { "type": "__switchcase", "args": { "cases": self.obj_args }, "properties": {"x": 0, "y": 0} }, "outlet_right": { "type": "outlet", "args": { "type": "-->", "index": len(self.obj_args) }, "properties": {"x": 0, "y": 0} }, }, "connections": [ { "from": {"id": "inlet", "outlet": 0}, "to": {"id": "switchcase", "inlet": 0}, "type": "-->" }, { "from": {"id": "switchcase", "outlet": len(self.obj_args)}, "to": {"id": "outlet_right", "inlet": 0}, "type": "-->" } ], "properties": {"x": self.pos_x, "y": self.pos_y} } # add slices to graph for i, a in enumerate(self.obj_args): # add slices to graph route_graph["objects"][f"slice_{i}"] = { "type": "slice", "args": { "index": 1, "length": -1 }, "properties": {"x": 0, "y": 0} } # add outlets to graph route_graph["objects"][f"outlet_{i}"] = { "type": "outlet", "args": { "type": "-->", "index": i }, "properties": {"x": 0, "y": 0} } # add connection from switchcase to slice route_graph["connections"].append({ "from": {"id": "switchcase", "outlet": i}, "to": {"id": f"slice_{i}", "inlet": 0}, "type": "-->" }) # add connection from slice outlets 0 and 1 to outlet route_graph["connections"].append({ "from": {"id": f"slice_{i}", "outlet": 0}, "to": {"id": f"outlet_{i}", "inlet": 0}, "type": "-->" }) route_graph["connections"].append({ "from": {"id": f"slice_{i}", "outlet": 1}, "to": {"id": f"outlet_{i}", "inlet": 0}, "type": "-->" }) return route_graph hvcc-0.16.0/hvcc/interpreters/pd2hv/PdSelectObject.py0000644000000000000000000001264100000000000017314 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from collections import Counter from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdSelectObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type in {"select", "sel"} super().__init__(obj_type, obj_args, pos_x, pos_y) if not obj_args: obj_args = [] if len(self.obj_args) == 0: self.add_error("At least one argument is required.") if len(set(self.obj_args)) != len(obj_args): c = Counter(obj_args).most_common(1) self.add_error( f"All arguments to [select] must be unique. Argument \"{c[0][0]}\" is repeated {c[0][1]} times.", NotificationEnum.ERROR_UNIQUE_ARGUMENTS_REQUIRED) # convert to obj_args to mixedarray, such that correct switchcase hash # is generated for i, a in enumerate(self.obj_args): try: self.obj_args[i] = float(a) except Exception: pass def validate_configuration(self) -> None: if len(self._inlet_connections.get("1", [])) > 0: self.add_warning("The right inlet of select is not supported. It will not do anything.") def to_hv(self) -> Dict: """ Creates a graph dynamically based on the number of arguments. An unconnected right inlet is added. [inlet] [inlet] | [@hv_obj switchcase [arg list (N elements)] ] | | | [@hv_obj __cast_b] [@hv_obj __cast_b] | | | | [outlet_0] [outlet_N-1] [outlet_right] """ route_graph: Dict = { "type": "graph", "imports": [], "args": [], "objects": { "inlet": { "type": "inlet", "args": { "type": "-->", "index": 0 }, "properties": {"x": 0, "y": 0} }, "inlet_right": { "type": "inlet", "args": { "type": "-->", "index": 1 }, "properties": {"x": 0, "y": 0} }, "switchcase": { "type": "__switchcase", "args": { "cases": self.obj_args }, "properties": {"x": 0, "y": 0} }, "outlet_right": { "type": "outlet", "args": { "type": "-->", "index": len(self.obj_args) }, "properties": {"x": 0, "y": 0} }, }, "connections": [ { "from": {"id": "inlet", "outlet": 0}, "to": {"id": "switchcase", "inlet": 0}, "type": "-->" }, { "from": {"id": "switchcase", "outlet": len(self.obj_args)}, "to": {"id": "outlet_right", "inlet": 0}, "type": "-->" } ], "properties": {"x": self.pos_x, "y": self.pos_y} } for i in range(len(self.obj_args)): # add __cast_b to graph route_graph["objects"][f"__cast_b_{i}"] = { "type": "__cast_b", "args": {}, "properties": {"x": 0, "y": 0} } # add outlets to graph route_graph["objects"][f"outlet_{i}"] = { "type": "outlet", "args": { "type": "-->", "index": i }, "properties": {"x": 0, "y": 0} } # add connection from switchcase to slice route_graph["connections"].append({ "from": {"id": "switchcase", "outlet": i}, "to": {"id": f"__cast_b_{i}", "inlet": 0}, "type": "-->" }) # add connection from slice to outlet route_graph["connections"].append({ "from": {"id": f"__cast_b_{i}", "outlet": 0}, "to": {"id": f"outlet_{i}", "inlet": 0}, "type": "-->" }) return route_graph hvcc-0.16.0/hvcc/interpreters/pd2hv/PdSendObject.py0000644000000000000000000001242200000000000016763 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject from .PdRaw import parse_pd_raw_args, PdRawException class PdSendObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type in {"s", "send", "s~", "send~", "throw~"} PdObject.__init__(self, obj_type, obj_args, pos_x, pos_y) self.__send_name = "" self.__extern_type = None self.__attributes: Dict = {} try: # send objects don't necessarily need to have a name self.__send_name = self.obj_args[0] # only extern control rate sends if obj_type in {"s", "send"}: if self.obj_args[1] == "@hv_param": self.__extern_type = "param" elif self.obj_args[1] == "@hv_event": self.__extern_type = "event" except Exception: pass if self.__extern_type == "param": try: self.__attributes = { "min": 0.0, "max": 1.0, "default": 0.5, "type": "float" } self.__attributes["min"] = float(self.obj_args[2]) self.__attributes["max"] = float(self.obj_args[3]) self.__attributes["default"] = float(self.obj_args[4]) self.__attributes["type"] = str(self.obj_args[5]) except ValueError: self.add_warning( f"Minimum, maximum, and default values for Parameter {self.__send_name} must be numbers.") except Exception: pass if not (self.__attributes["min"] <= self.__attributes["default"]): self.add_error("Default parameter value is less than the minimum. " "Send will not be exported: {0:g} < {1:g}".format( self.__attributes["default"], self.__attributes["min"])) self.__extern_type = None if not (self.__attributes["default"] <= self.__attributes["max"]): self.add_error("Default parameter value is greater than the maximum. " "Send will not be exported: {0:g} > {1:g}".format( self.__attributes["default"], self.__attributes["max"])) self.__extern_type = None if '@raw' in self.obj_args or '@owl' in self.obj_args: # TODO(dromer): deprecate @owl on next stable release try: pd_raw_args = parse_pd_raw_args(self.obj_args) self.__attributes.update(pd_raw_args) self.__extern_type = "param" # make sure output code is generated except PdRawException as e: self.add_error(str(e)) def validate_configuration(self) -> None: if len(self.obj_args) == 0: self.add_warning( f"No name was given to this {self.obj_type} object. " "It should have a name to reduce the risk of errors.", NotificationEnum.WARNING_USELESS_OBJECT) if len(self._inlet_connections.get("0", [])) == 0: self.add_warning( "This object has no inlet connections. " "It does nothing and will be removed.", NotificationEnum.WARNING_USELESS_OBJECT) if self.obj_type in {"s", "send"} and len(self._inlet_connections.get("1", [])) > 0: self.add_error( "Connections to the right inlet of a send object " "are not supported. A name should be given.", NotificationEnum.ERROR_MISSING_REQUIRED_ARGUMENT) def to_hv(self) -> Dict: # note: control rate send/receive objects should not modify their name argument names = { "s": "", "send": "", "s~": "sndrcv_sig_", "send~": "sndrcv_sig_", "throw~": "thrwctch_sig_" } return { "type": "send", "args": { "name": names[self.obj_type] + self.__send_name, "extern": self.__extern_type, "attributes": self.__attributes, }, "properties": { "x": self.pos_x, "y": self.pos_y }, "annotations": { "scope": "public" } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdTableObject.py0000644000000000000000000000420300000000000017117 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdTableObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type == "table" super().__init__(obj_type, obj_args, pos_x, pos_y) self.__table_name = "" self.__size = 0 self.__extern = False try: self.__table_name = self.obj_args[0] except Exception: self.add_error( "Missing \"name\" argument for table", NotificationEnum.ERROR_MISSING_REQUIRED_ARGUMENT) try: # optional arguments try: self.__size = int(self.obj_args[1]) self.__extern = (self.obj_args[2] == "@hv_table") except Exception: pass except Exception: pass def to_hv(self) -> Dict: return { "type": "table", "args": { "name": self.__table_name, "size": self.__size, "values": [], "extern": self.__extern }, "properties": { "x": self.pos_x, "y": self.pos_y }, "annotations": { "scope": "public" } } hvcc-0.16.0/hvcc/interpreters/pd2hv/PdTriggerObject.py0000644000000000000000000000426600000000000017504 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .NotificationEnum import NotificationEnum from .PdObject import PdObject class PdTriggerObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type in {"trigger", "t"} super().__init__("trigger", obj_args, pos_x, pos_y) # convert all numeric casts to "f" for i, a in enumerate(self.obj_args): self.obj_args[i] = "f" if PdTriggerObject.__is_float(a) else a if len(self.obj_args) == 0: self.obj_args = ["b", "b"] self.add_warning("A trigger with no arguments defualts to [t b b].") if obj_args is not None and not (set(obj_args) <= set(["a", "f", "s", "b"])): self.add_error( "Heavy only supports arguments 'a', 'f', 's', and 'b'.", NotificationEnum.ERROR_TRIGGER_ABFS) def to_hv(self) -> Dict: return { "type": "sequence", "args": { "casts": self.obj_args }, "properties": { "x": self.pos_x, "y": self.pos_y } } @classmethod def __is_float(cls, x: int) -> bool: """ Returns True if the input can be converted to a float. False otherwise. """ try: float(x) return True except Exception: return False hvcc-0.16.0/hvcc/interpreters/pd2hv/PdUnpackObject.py0000644000000000000000000000666600000000000017330 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023 Wasted Audio # # 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 . from typing import Optional, List, Dict from .PdObject import PdObject class PdUnpackObject(PdObject): def __init__( self, obj_type: str, obj_args: Optional[List] = None, pos_x: int = 0, pos_y: int = 0 ) -> None: assert obj_type == "unpack" super().__init__(obj_type, obj_args, pos_x, pos_y) if len(self.obj_args) == 0: self.add_error("Unpack requires at least one argument.") if not (set(self.obj_args) <= set(["f", "s"])): self.add_warning("Heavy only supports arguments 'f' and 's' to unpack.") def to_hv(self) -> Dict: """ Creates a graph dynamically based on the number of arguments. [inlet ] | | | [@hv_obj __slice 0 1] ... [@hv_obj __slice N-1 1] | | | [outlet_0] ... [outlet_N-1] """ hv_graph: Dict = { "type": "graph", "imports": [], "args": [], "objects": { "inlet": { "type": "inlet", "args": { "type": "-->", "index": 0 }, "properties": {"x": 0, "y": 0} } }, "connections": [], "properties": {"x": self.pos_x, "y": self.pos_y} } # NOTE(mhroth): reverse the iteration such that connections are # added in the correct order for i in reversed(range(len(self.obj_args))): # add slices to graph hv_graph["objects"][f"slice_{i}"] = { "type": "slice", "args": { "index": i, "length": 1 }, "properties": {"x": 0, "y": 0} } # add outlets to graph hv_graph["objects"][f"outlet_{i}"] = { "type": "outlet", "args": { "type": "-->", "index": i }, "properties": {"x": 0, "y": 0} } # add connection from inlet to slice hv_graph["connections"].append({ "from": {"id": "inlet", "outlet": 0}, "to": {"id": f"slice_{i}", "inlet": 0}, "type": "-->" }) # add connection from slice to outlet hv_graph["connections"].append({ "from": {"id": f"slice_{i}", "outlet": 0}, "to": {"id": f"outlet_{i}", "inlet": 0}, "type": "-->" }) return hv_graph hvcc-0.16.0/hvcc/interpreters/pd2hv/__init__.py0000644000000000000000000000000000000000000016203 0ustar00hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/acosh~.pd0000644000000000000000000000056300000000000020315 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 167 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __acosh~f; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 124 pd @hv_obj __bitsafe~f; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/acos~.pd0000644000000000000000000000056200000000000020144 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 162 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __acos~f; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 125 pd @hv_obj __bitsafe~f; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/asinh~.pd0000644000000000000000000000034700000000000020322 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __asinh~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/asin~.pd0000644000000000000000000000056200000000000020151 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 163 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __asin~f; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 37 121 pd @hv_obj __bitsafe~f; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/atan2~.pd0000644000000000000000000000045300000000000020223 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 1091 104 298 181 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X obj 150 35 inlet~; #X restore 38 82 pd @hv_obj __atan2~f; #X obj 174 33 inlet~; #X connect 0 0 2 0; #X connect 2 0 1 0; #X connect 3 0 2 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/atanh~.pd0000644000000000000000000000056300000000000020313 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 37 171 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __atanh~f; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 124 pd @hv_obj __bitsafe~f; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/atan~.pd0000644000000000000000000000034600000000000020142 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __atan~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/bitand~.pd0000644000000000000000000000045200000000000020456 0ustar00#N canvas 855 583 241 181 10; #X obj 155 31 inlet~; #X obj 27 31 inlet~; #X obj 27 113 outlet~; #N canvas 1 558 346 208 @hv_obj 0; #X obj 167 31 inlet~; #X obj 71 31 inlet~; #X obj 73 152 outlet~; #X restore 27 72 pd @hv_obj __bit_and~f; #X connect 0 0 3 1; #X connect 1 0 3 0; #X connect 3 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/bitnot~.pd0000644000000000000000000000035200000000000020513 0ustar00#N canvas 855 583 241 181 10; #X obj 27 31 inlet~; #X obj 27 113 outlet~; #N canvas 1 558 346 208 @hv_obj 0; #X obj 71 31 inlet~; #X obj 73 152 outlet~; #X restore 27 72 pd @hv_obj __bit_not~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/bitor~.pd0000644000000000000000000000045100000000000020333 0ustar00#N canvas 855 583 241 181 10; #X obj 149 31 inlet~; #X obj 27 31 inlet~; #X obj 27 113 outlet~; #N canvas 1 558 346 208 @hv_obj 0; #X obj 167 31 inlet~; #X obj 71 31 inlet~; #X obj 73 152 outlet~; #X restore 27 72 pd @hv_obj __bit_or~f; #X connect 0 0 3 1; #X connect 1 0 3 0; #X connect 3 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/bitsafe~.pd0000644000000000000000000000035200000000000020631 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 458 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __bitsafe~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/bitxor~.pd0000644000000000000000000000045100000000000020523 0ustar00#N canvas 855 583 241 181 10; #X obj 149 31 inlet~; #X obj 27 31 inlet~; #X obj 27 113 outlet~; #N canvas 1 558 346 208 @hv_obj 0; #X obj 167 31 inlet~; #X obj 71 31 inlet~; #X obj 73 152 outlet~; #X restore 27 72 pd @hv_obj __exc_or~f; #X connect 0 0 3 1; #X connect 1 0 3 0; #X connect 3 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/cartopol~.pd0000644000000000000000000000122100000000000021033 0ustar00#N canvas 756 224 412 319 12; #X obj 68 48 inlet~; #X obj 224 48 inlet~; #X obj 68 109 *~; #X obj 102 110 *~; #N canvas 0 459 450 300 @hv_obj 0; #X obj 31 15 inlet~; #X obj 30 87 outlet~; #X restore 68 198 pd @hv_obj __sqrt~f; #X obj 68 155 +~; #X obj 68 255 outlet~; #N canvas 1091 104 298 181 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X obj 150 35 inlet~; #X restore 223 197 pd @hv_obj __atan2~f; #X obj 223 254 outlet~; #X connect 0 0 2 0; #X connect 0 0 2 1; #X connect 0 0 7 1; #X connect 1 0 3 0; #X connect 1 0 3 1; #X connect 1 0 7 0; #X connect 2 0 5 0; #X connect 3 0 5 1; #X connect 4 0 6 0; #X connect 5 0 4 0; #X connect 7 0 8 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/cosh~.pd0000644000000000000000000000034600000000000020153 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __cosh~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/cosx~.pd0000644000000000000000000000034500000000000020172 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __cos~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/poltocar~.pd0000644000000000000000000000105200000000000021035 0ustar00#N canvas 882 360 406 266 12; #X obj 68 48 inlet~; #X obj 224 48 inlet~; #X obj 68 218 outlet~; #X obj 223 217 outlet~; #X obj 67 170 *~; #X obj 222 172 *~; #N canvas 0 459 275 162 @hv_obj 0; #X obj 31 15 inlet~; #X obj 30 87 outlet~; #X restore 85 123 pd @hv_obj __cos~f; #N canvas 1091 104 255 205 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 240 122 pd @hv_obj __sin~f; #X connect 0 0 4 0; #X connect 0 0 5 0; #X connect 1 0 6 0; #X connect 1 0 7 0; #X connect 4 0 2 0; #X connect 5 0 3 0; #X connect 6 0 4 1; #X connect 7 0 5 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/sinh~.pd0000644000000000000000000000034600000000000020160 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __sinh~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/sinx~.pd0000644000000000000000000000034500000000000020177 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __sin~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/tanh~.pd0000644000000000000000000000034600000000000020151 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __tanh~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/cyclone/tanx~.pd0000644000000000000000000000034500000000000020170 0ustar00#N canvas 827 239 262 208 12; #X obj 38 32 inlet~; #X obj 38 134 outlet~; #N canvas 0 50 197 210 @hv_obj 0; #X obj 56 36 inlet~; #X obj 56 128 outlet~; #X restore 38 82 pd @hv_obj __tan~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/else/knob.pd0000644000000000000000000000020300000000000017236 0ustar00#N canvas 0 149 210 157 10; #X obj 24 35 inlet; #X obj 24 57 float 0; #X obj 24 79 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/heavy/conv~.pd0000644000000000000000000000143600000000000017645 0ustar00#N canvas 702 23 312 255 10; #N canvas 0 22 450 300 @hv_obj 0; #X obj 55 136 outlet~; #X obj 55 75 inlet~; #X obj 190 74 inlet; #X obj 139 74 inlet; #X restore 25 155 pd @hv_obj __conv~f \$1 \$2; #X text 24 232 @hv_arg \$2 size int 0 false; #X text 24 210 @hv_arg \$1 table string "" true; #X obj 25 15 inlet~; #X obj 172 65 loadbang; #X msg 172 110 table \$1 size; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 172 133 pd @hv_obj system; #X text 37 46 measured after initialisation; #X text 37 35 NOTE(mhroth): ensure that the table size is; #X obj 172 87 symbol \$1; #X obj 25 183 outlet~; #X obj 98 132 inlet; #X connect 0 0 10 0; #X connect 3 0 0 0; #X connect 4 0 9 0; #X connect 5 0 6 0; #X connect 6 0 0 2; #X connect 9 0 5 0; #X connect 11 0 0 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/heavy/lorenz~.pd0000644000000000000000000000137100000000000020207 0ustar00#N canvas 137 197 531 225 10; #N canvas 0 22 1061 416 @hv_obj 0; #X obj 200 60 inlet~; #X obj 140 50 inlet~; #X obj 338 65 inlet~; #X obj 278 55 inlet~; #X obj 288 147 outlet~; #X obj 146 146 outlet~; #X obj 210 147 outlet~; #X obj 415 71 inlet; #X restore 30 140 pd @hv_obj __lorenz~f; #X obj 30 29 inlet~; #X obj 60 50 inlet~; #X obj 91 70 inlet~; #X obj 122 90 inlet~; #X obj 30 170 outlet~ x; #X obj 91 170 outlet~ y; #X obj 153 170 outlet~ z; #X text 175 86 NOTE(joe): there is supposed to be a control; #X obj 153 117 route xyz; #X text 174 99 connection from the first [inlet~] to the [route]; #X connect 0 0 5 0; #X connect 0 1 6 0; #X connect 0 2 7 0; #X connect 1 0 0 0; #X connect 2 0 0 1; #X connect 3 0 0 2; #X connect 4 0 0 3; #X connect 9 0 0 4; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/heavy/pdnam~.pd0000644000000000000000000000043200000000000017772 0ustar00#N canvas 710 529 382 224 12; #X obj 39 42 inlet~; #N canvas 1212 0 450 300 @hv_obj 0; #X obj 37 37 inlet~; #X obj 37 145 outlet~; #X restore 39 89 pd @hv_obj __nam~f \$1; #X obj 39 135 outlet~; #X text 39 176 @hv_arg \$1 nam string "" true; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/heavy_converted/lorenz~.hv.json0000644000000000000000000001465100000000000023247 0ustar00{ "args": [], "connections": [ { "from": { "id": "__lorenz~f_7dUFW", "outlet": 0 }, "to": { "id": "outlet~_Lf24h", "inlet": 0 }, "type": "~f>" }, { "from": { "id": "__lorenz~f_7dUFW", "outlet": 1 }, "to": { "id": "outlet~_aCD1q", "inlet": 0 }, "type": "~f>" }, { "from": { "id": "__lorenz~f_7dUFW", "outlet": 2 }, "to": { "id": "outlet~_pOs6O", "inlet": 0 }, "type": "~f>" }, { "from": { "id": "inlet~_l0vgT", "outlet": 0 }, "to": { "id": "__lorenz~f_7dUFW", "inlet": 0 }, "type": "~f>" }, { "from": { "id": "inlet~_fGKSc", "outlet": 0 }, "to": { "id": "__lorenz~f_7dUFW", "inlet": 1 }, "type": "~f>" }, { "from": { "id": "inlet~_IdP6v", "outlet": 0 }, "to": { "id": "__lorenz~f_7dUFW", "inlet": 2 }, "type": "~f>" }, { "from": { "id": "inlet~_jm5dl", "outlet": 0 }, "to": { "id": "__lorenz~f_7dUFW", "inlet": 3 }, "type": "~f>" }, { "from": { "id": "inlet~_l0vgT", "outlet": 0 }, "to": { "id": "route_Ymaxs", "inlet": 0 }, "type": "-->" }, { "from": { "id": "route_Ymaxs", "outlet": 0 }, "to": { "id": "__lorenz~f_7dUFW", "inlet": 4 }, "type": "-->" } ], "imports": [], "objects": { "__lorenz~f_7dUFW": { "annotations": {}, "args": { "x": 0, "y": 0, "z": 0 }, "properties": { "x": 30, "y": 140 }, "type": "__lorenz~f" }, "comment_2QlQ0": { "annotations": {}, "args": { "mime": "text/plain", "text": "connection from the first [inlet~] to the [route]" }, "properties": { "x": "174", "y": "99" }, "type": "comment" }, "comment_JloHn": { "annotations": {}, "args": { "mime": "text/plain", "text": "NOTE(joe): there is supposed to be a control" }, "properties": { "x": "175", "y": "86" }, "type": "comment" }, "inlet~_IdP6v": { "annotations": {}, "args": { "index": 2, "name": "", "type": "~f>" }, "properties": { "x": 91, "y": 70 }, "type": "inlet" }, "inlet~_fGKSc": { "annotations": {}, "args": { "index": 1, "name": "", "type": "~f>" }, "properties": { "x": 60, "y": 50 }, "type": "inlet" }, "inlet~_jm5dl": { "annotations": {}, "args": { "index": 3, "name": "", "type": "~f>" }, "properties": { "x": 122, "y": 90 }, "type": "inlet" }, "inlet~_l0vgT": { "annotations": {}, "args": { "index": 0, "name": "", "type": "~f>" }, "properties": { "x": 30, "y": 29 }, "type": "inlet" }, "outlet~_Lf24h": { "annotations": {}, "args": { "index": 0, "name": "x", "type": "~f>" }, "properties": { "x": 30, "y": 170 }, "type": "outlet" }, "outlet~_aCD1q": { "annotations": {}, "args": { "index": 1, "name": "y", "type": "~f>" }, "properties": { "x": 91, "y": 170 }, "type": "outlet" }, "outlet~_pOs6O": { "annotations": {}, "args": { "index": 2, "name": "z", "type": "~f>" }, "properties": { "x": 153, "y": 170 }, "type": "outlet" }, "route_Ymaxs": { "args": {}, "connections": [ { "from": { "id": "inlet_ofY1a", "outlet": 0 }, "to": { "id": "__switchcase_PyIvC", "inlet": 0 }, "type": "-->" }, { "from": { "id": "__switchcase_PyIvC", "outlet": 0 }, "to": { "id": "__slice_1AcsG", "inlet": 0 }, "type": "-->" }, { "from": { "id": "__slice_1AcsG", "outlet": 0 }, "to": { "id": "outlet_EWlrg", "inlet": 0 }, "type": "-->" }, { "from": { "id": "__switchcase_PyIvC", "outlet": 1 }, "to": { "id": "outlet_zxBnk", "inlet": 0 }, "type": "-->" } ], "objects": { "__slice_1AcsG": { "annotations": {}, "args": { "index": 1, "length": -1 }, "properties": { "x": 10, "y": 50 }, "type": "__slice" }, "__switchcase_PyIvC": { "annotations": {}, "args": { "cases": [ "xyz" ] }, "properties": { "x": 10, "y": 50 }, "type": "__switchcase" }, "inlet_ofY1a": { "annotations": {}, "args": { "index": 0, "name": "", "type": "-->" }, "properties": { "x": 10, "y": 10 }, "type": "inlet" }, "outlet_EWlrg": { "annotations": {}, "args": { "index": 0, "name": "xyz", "type": "-->" }, "properties": { "x": 10, "y": 10 }, "type": "outlet" }, "outlet_zxBnk": { "annotations": {}, "args": { "index": 1, "name": "", "type": "-->" }, "properties": { "x": 10, "y": 10 }, "type": "outlet" } }, "type": "graph" } }, "properties": { "x": 0, "y": 0 }, "type": "graph" }hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/abs.pd0000644000000000000000000000033500000000000016533 0ustar00#N canvas 439 480 151 128 10; #X obj 13 20 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet; #X obj 19 66 outlet; #X restore 13 50 pd @hv_obj __abs; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/abs~.pd0000644000000000000000000000034300000000000016730 0ustar00#N canvas 439 480 165 137 10; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet~; #X obj 19 66 outlet~; #X restore 13 50 pd @hv_obj __abs~f; #X obj 13 20 inlet~; #X obj 13 80 outlet~; #X connect 0 0 2 0; #X connect 1 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/atan.pd0000644000000000000000000000033600000000000016712 0ustar00#N canvas 439 480 151 128 10; #X obj 13 20 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet; #X obj 19 66 outlet; #X restore 13 50 pd @hv_obj __atan; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/atan2.pd0000644000000000000000000000043400000000000016773 0ustar00#N canvas 439 480 161 128 10; #X obj 13 19 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 76 24 inlet; #X obj 19 66 outlet; #X obj 19 24 inlet; #X restore 13 50 pd @hv_obj __atan2; #X obj 118 18 inlet; #X connect 0 0 2 0; #X connect 2 0 1 0; #X connect 3 0 2 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/b.pd0000644000000000000000000000034500000000000016210 0ustar00#N canvas 638 45 161 94 10; #X obj 9 10 inlet -->; #N canvas 0 22 450 300 @hv_obj 0; #X obj 143 44 inlet; #X obj 146 94 outlet; #X restore 9 33 pd @hv_obj __cast_b; #X obj 9 57 outlet -->; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/bang.pd0000644000000000000000000000034500000000000016676 0ustar00#N canvas 638 45 161 94 10; #X obj 9 10 inlet -->; #N canvas 0 22 450 300 @hv_obj 0; #X obj 143 44 inlet; #X obj 146 94 outlet; #X restore 9 33 pd @hv_obj __cast_b; #X obj 9 57 outlet -->; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/bang~.pd0000644000000000000000000000047600000000000017101 0ustar00#N canvas 320 37 549 254 12; #X obj 99 102 r __hv_bang~; #X obj 99 173 outlet; #X obj 99 71 inlet; #X text 151 69 inlet is inactive; #X text 255 111 because we only receive the first bang at the end of the first process() loop we first send a loadbang; #X obj 128 132 loadbang; #X connect 0 0 1 0; #X connect 5 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/bendin.pd0000644000000000000000000000155000000000000017225 0ustar00#N canvas 114 229 459 438 10; #X obj 209 337 outlet; #X obj 152 76 unpack f f; #X obj 152 47 r __hv_bendin; #X obj 50 307 outlet; #X obj 83 104 loadbang; #X obj 83 174 == 0; #X obj 83 128 i \$1; #X obj 50 266 spigot; #X obj 209 101 + 1; #X obj 209 236 spigot; #X obj 215 175 ==; #X obj 152 237 spigot; #X obj 215 200 t f f; #X obj 209 313 max 1; #X text 226 78 bend value and channel/port; #X obj 83 197 t f f; #X obj 150 270 spigot; #X connect 1 0 11 0; #X connect 1 0 7 0; #X connect 1 1 8 0; #X connect 2 0 1 0; #X connect 4 0 6 0; #X connect 5 0 15 0; #X connect 6 0 5 0; #X connect 6 0 10 1; #X connect 7 0 3 0; #X connect 8 0 10 0; #X connect 8 0 16 0; #X connect 8 0 9 0; #X connect 9 0 13 0; #X connect 10 0 12 0; #X connect 11 0 3 0; #X connect 12 0 11 1; #X connect 12 1 9 1; #X connect 13 0 0 0; #X connect 15 0 7 1; #X connect 15 1 16 1; #X connect 16 0 13 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/bendout.pd0000644000000000000000000000063500000000000017431 0ustar00#N canvas 735 166 248 326 10; #X obj 46 232 pack f f; #X obj 91 104 inlet channel; #X obj 91 155 f \$1; #X obj 108 129 loadbang; #X obj 46 262 s __hv_bendout @hv_param; #X obj 46 40 inlet bend; #X obj 46 72 + 8192; #X obj 91 181 - 1; #X obj 91 204 max; #X connect 0 0 4 0; #X connect 1 0 2 0; #X connect 2 0 7 0; #X connect 3 0 2 0; #X connect 5 0 6 0; #X connect 6 0 0 0; #X connect 7 0 8 0; #X connect 8 0 0 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/biquad~.pd0000644000000000000000000000407300000000000017434 0ustar00#N canvas 846 105 451 381 10; #X obj 25 355 outlet~; #X obj 166 303 * -1; #X obj 202 303 * -1; #X text 95 15 NOTE(mhroth): there is supposed to be a control; #N canvas 0 22 450 300 @hv_obj 0; #X obj 78 79 inlet~; #X obj 86 146 outlet~; #X obj 184 76 inlet; #X obj 144 76 inlet; #X obj 302 76 inlet; #X obj 223 76 inlet; #X obj 263 76 inlet; #X restore 25 332 pd @hv_obj biquad \$3 \$4 \$5 0 0; #X text 262 62 @hv_arg \$3 x0 float 1 false; #X text 262 80 @hv_arg \$4 x1 float 0 false; #X text 262 100 @hv_arg \$5 x2 float 0 false; #X text 262 119 @hv_arg \$1 y0 float 0 false; #X text 262 139 @hv_arg \$2 y1 float 0 false; #N canvas 0 22 450 300 @hv_obj 0; #X obj 165 61 inlet; #X obj 169 116 outlet; #X restore 62 110 pd @hv_obj __slice 0 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 165 61 inlet; #X obj 169 116 outlet; #X restore 86 133 pd @hv_obj __slice 1 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 165 61 inlet; #X obj 169 116 outlet; #X restore 109 156 pd @hv_obj __slice 2 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 165 61 inlet; #X obj 169 116 outlet; #X restore 134 179 pd @hv_obj __slice 3 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 165 61 inlet; #X obj 169 116 outlet; #X restore 162 202 pd @hv_obj __slice 4 1; #X obj 166 226 loadbang; #X text 94 28 connection from the left inlet to the trigger; #N canvas 0 22 450 300 @hv_obj 0; #X obj 179 57 inlet; #X obj 169 117 outlet; #X restore 166 255 pd @hv_obj __var \$1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 179 57 inlet; #X obj 169 117 outlet; #X restore 202 276 pd @hv_obj __var \$2; #X obj 25 23 inlet~ -~>; #N canvas 0 22 162 66 to_control 0; #X obj 17 10 inlet; #X obj 17 32 outlet; #X connect 0 0 1 0; #X restore 62 67 pd to_control; #X connect 1 0 4 4; #X connect 2 0 4 5; #X connect 4 0 0 0; #X connect 10 0 1 0; #X connect 11 0 2 0; #X connect 12 0 4 1; #X connect 13 0 4 2; #X connect 14 0 4 3; #X connect 15 0 17 0; #X connect 15 0 18 0; #X connect 17 0 1 0; #X connect 18 0 2 0; #X connect 19 0 20 0; #X connect 19 0 4 0; #X connect 20 0 10 0; #X connect 20 0 11 0; #X connect 20 0 12 0; #X connect 20 0 13 0; #X connect 20 0 14 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/bng.pd0000644000000000000000000000034500000000000016535 0ustar00#N canvas 638 45 161 94 10; #X obj 9 10 inlet -->; #N canvas 0 22 450 300 @hv_obj 0; #X obj 143 44 inlet; #X obj 146 94 outlet; #X restore 9 33 pd @hv_obj __cast_b; #X obj 9 57 outlet -->; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/bp~.pd0000644000000000000000000000400400000000000016562 0ustar00#N canvas 742 22 339 614 10; #X obj 18 21 inlet~; #X obj 108 21 inlet fc; #X obj 18 538 outlet~; #X obj 108 179 /; #X obj 186 128 samplerate~; #X obj 167 77 loadbang; #X obj 108 123 f \$1; #N canvas 0 22 324 130 @hv_obj 0; #X obj 75 4 inlet; #X obj 229 4 inlet; #X obj 113 4 inlet; #X obj 152 4 inlet; #X obj 30 37 outlet~; #X obj 192 4 inlet; #X obj 30 4 inlet~, f 19; #X restore 18 513 pd @hv_obj biquad; #X obj 108 153 * 6.28319; #X text 13 584 @hv_arg \$2 q float 1 false; #X text 13 566 @hv_arg \$1 fc float 22050 false; #X obj 176 21 inlet q; #X obj 206 153 f \$2; #X obj 167 100 t a a a; #X obj 108 230 /; #X obj 147 310 * -1; #X obj 147 332 + 1; #X text 70 179 omega; #X text 46 233 oneminusr; #X text 133 332 r; #X obj 193 310 cos; #X obj 193 334 * 2; #X obj 147 378 *; #X text 108 378 coef1; #X obj 176 48 t b a, f 9; #X text 154 426 coef2; #X obj 192 426 * -1; #X obj 129 488 * -1; #X obj 106 465 * -1; #X obj 40 465 * 2; #X obj 80 444 *; #X obj 108 204 t a a a, f 29; #X obj 192 392 pow 2; #X obj 65 465 +; #X obj 40 488 *; #X obj 108 285 t a a a; #X text 64 487 gain; #X text 149 132 fc; #X text 237 152 q; #X obj 206 176 max 0.001; #X obj 108 258 min 1; #X obj 128 354 t a a a; #X connect 0 0 7 0; #X connect 1 0 6 0; #X connect 3 0 31 0; #X connect 4 0 3 1; #X connect 5 0 13 0; #X connect 6 0 8 0; #X connect 7 0 2 0; #X connect 8 0 3 0; #X connect 11 0 24 0; #X connect 12 0 39 0; #X connect 13 0 6 0; #X connect 13 1 4 0; #X connect 13 2 12 0; #X connect 14 0 40 0; #X connect 15 0 16 0; #X connect 16 0 41 0; #X connect 20 0 21 0; #X connect 21 0 22 1; #X connect 22 0 28 0; #X connect 24 0 6 0; #X connect 24 1 12 0; #X connect 26 0 27 0; #X connect 27 0 7 5; #X connect 28 0 7 4; #X connect 29 0 34 0; #X connect 30 0 33 1; #X connect 31 0 14 0; #X connect 31 1 20 0; #X connect 31 2 30 1; #X connect 32 0 26 0; #X connect 33 0 34 1; #X connect 34 0 7 1; #X connect 35 0 29 0; #X connect 35 1 33 0; #X connect 35 2 15 0; #X connect 39 0 14 1; #X connect 40 0 35 0; #X connect 41 0 30 0; #X connect 41 1 22 0; #X connect 41 2 32 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/change.pd0000644000000000000000000000116300000000000017213 0ustar00#N canvas 877 436 234 342 10; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 72 169 pd @hv_obj if; #X obj 130 199 t f f; #X obj 22 274 outlet; #X obj 22 48 route bang set; #X obj 130 139 != \$1; #X text 21 305 @hv_arg \$1 value float 0 false; #X obj 22 19 inlet; #X obj 103 76 t f f; #X obj 22 244 f \$1; #X connect 0 1 1 0; #X connect 1 0 8 0; #X connect 1 1 4 1; #X connect 3 0 8 0; #X connect 3 1 4 1; #X connect 3 1 8 1; #X connect 3 2 7 0; #X connect 4 0 0 1; #X connect 6 0 3 0; #X connect 7 0 0 0; #X connect 7 1 4 0; #X connect 8 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/clip.pd0000644000000000000000000000056400000000000016721 0ustar00#N canvas 659 496 326 179 10; #X obj 61 14 inlet; #X obj 104 14 inlet; #X text 14 118 @hv_arg \$1 lower_threshold float 0 false; #X text 14 133 @hv_arg \$2 upper_threshold float 1 false; #X obj 14 39 min \$2; #X obj 14 66 max \$1; #X obj 14 92 outlet; #X obj 14 14 inlet; #X connect 0 0 5 1; #X connect 1 0 4 1; #X connect 4 0 5 0; #X connect 5 0 6 0; #X connect 7 0 4 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/clip~.pd0000644000000000000000000000057000000000000017114 0ustar00#N canvas 409 258 326 179 10; #X obj 14 14 inlet~; #X obj 61 14 inlet; #X obj 104 14 inlet; #X obj 14 92 outlet~; #X text 14 118 @hv_arg \$1 lower_threshold float 0 false; #X text 14 133 @hv_arg \$2 upper_threshold float 1 false; #X obj 14 39 min~ \$2; #X obj 14 66 max~ \$1; #X connect 0 0 6 0; #X connect 1 0 7 1; #X connect 2 0 6 1; #X connect 6 0 7 0; #X connect 7 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/cnv.pd0000644000000000000000000000016500000000000016555 0ustar00#N canvas 591 233 346 56 10; #X text 11 10 // this patch is left blank \, as the cnv object has no fuction in Heavy; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/cos.pd0000644000000000000000000000033500000000000016552 0ustar00#N canvas 439 480 151 128 10; #X obj 13 20 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet; #X obj 19 66 outlet; #X restore 13 50 pd @hv_obj __cos; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/cos~.pd0000644000000000000000000000226100000000000016750 0ustar00#N canvas 515 39 304 425 10; #X obj 32 167 *~ 6.28319; #X obj 32 17 inlet~; #X obj 31 594 outlet~; #X obj 32 137 -~ 0.25; #X obj 32 77 -~ 0.5; #X obj 32 107 abs~; #X obj 32 47 wrap~; #X obj 64 268 *~; #X obj 92 327 *~; #X obj 127 215 *~; #X text 166 214 x^2; #X text 100 267 x^3; #X text 127 326 x^5; #X obj 32 430 +~; #X obj 32 360 -~; #X obj 65 298 *~ 0.166667; #X obj 92 359 *~ 0.00833333; #X obj 113 391 *~; #X obj 113 425 *~ 0.000198413; #X obj 32 518 -~; #X obj 139 455 *~; #X obj 31 551 +~; #X obj 139 481 *~ 2.75573e-06; #X text 148 390 x^7; #X text 176 454 x^9; #X text 121 166 sine taylor approximation; #X connect 0 0 14 0; #X connect 0 0 7 0; #X connect 0 0 9 0; #X connect 0 0 9 1; #X connect 1 0 6 0; #X connect 3 0 0 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X connect 6 0 4 0; #X connect 7 0 15 0; #X connect 7 0 8 0; #X connect 8 0 16 0; #X connect 8 0 17 0; #X connect 9 0 8 1; #X connect 9 0 7 1; #X connect 9 0 17 1; #X connect 9 0 20 1; #X connect 13 0 19 0; #X connect 14 0 13 0; #X connect 15 0 14 1; #X connect 16 0 13 1; #X connect 17 0 18 0; #X connect 17 0 20 0; #X connect 18 0 19 1; #X connect 19 0 21 0; #X connect 20 0 22 0; #X connect 21 0 2 0; #X connect 22 0 21 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/cpole~.pd0000644000000000000000000000107500000000000017270 0ustar00#N canvas 313 179 214 178 10; #X obj 59 35 inlet~; #X obj 20 15 inlet~; #X obj 137 145 outlet~; #X obj 98 77 *~ -1; #X obj 137 76 inlet~; #X obj 98 55 inlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 204 68 inlet~; #X obj 144 68 inlet~; #X obj 225 128 outlet~; #X obj 322 67 inlet~; #X obj 262 67 inlet~; #X obj 160 129 outlet~; #X restore 20 120 pd @hv_obj __cpole~f; #X obj 20 145 outlet~; #X obj 137 98 *~ -1; #X connect 0 0 6 1; #X connect 1 0 6 0; #X connect 3 0 6 2; #X connect 4 0 8 0; #X connect 5 0 3 0; #X connect 6 0 7 0; #X connect 6 1 2 0; #X connect 8 0 6 3; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/ctlin.pd0000644000000000000000000000436300000000000017104 0ustar00#N canvas 881 247 766 648 12; #X obj 14 591 outlet; #X obj 229 591 outlet; #X obj 551 591 outlet; #X obj 33 60 loadbang; #X text 19 24 data1/value data0/cc# channel; #X obj 438 56 r __hv_ctlin; #X obj 33 93 t a a; #X obj 33 118 i \$1; #X obj 120 118 i \$2; #X obj 438 81 unpack f f f; #X obj 519 117 + 1; #X obj 519 201 max 1; #X obj 393 225 ==; #X obj 33 143 t f f; #X obj 33 168 == 0; #X obj 14 258 spigot; #X obj 70 258 spigot; #X obj 354 294 spigot; #X text 120 259 0 args case; #X obj 416 436 spigot 1, f 11; #X obj 31 414 spigot 1; #X obj 33 371 == 0; #X text 507 441 this should close if there is 2 args set, f 13; #X text 178 69 the special case when first argument is 0 is buggy at the moment, f 25; #X obj 31 543 spigot 1; #X obj 416 483 spigot 1; #X obj 551 303 spigot; #X obj 120 143 t f f; #X obj 590 270 != 0; #X obj 519 269 t f f; #X obj 468 221 t a a; #X obj 469 460 == 0; #X obj 84 501 ==; #X text 607 305 2 args case; #X obj 519 338 t f f; #X obj 551 366 spigot; #X text 605 365 0 arg case; #X text 420 509 1 arg case; #X obj 416 402 f; #X obj 590 337 t a; #X text 98 536 this will keep open unless there is a second arg and it doesn't match, f 15; #X text 102 409 this will close if there is 0 arg set, f 11; #X obj 393 255 t f b f; #X obj 33 193 t f f f f; #X connect 3 0 6 0; #X connect 5 0 9 0; #X connect 6 0 7 0; #X connect 6 1 8 0; #X connect 7 0 13 0; #X connect 8 0 27 0; #X connect 9 0 15 0; #X connect 9 0 17 0; #X connect 9 1 16 0; #X connect 9 1 12 0; #X connect 9 2 10 0; #X connect 10 0 11 0; #X connect 11 0 29 0; #X connect 12 0 42 0; #X connect 13 0 14 0; #X connect 13 1 12 1; #X connect 14 0 43 0; #X connect 15 0 0 0; #X connect 16 0 1 0; #X connect 17 0 20 0; #X connect 19 0 25 0; #X connect 20 0 24 0; #X connect 21 0 20 1; #X connect 24 0 0 0; #X connect 25 0 1 0; #X connect 26 0 32 0; #X connect 27 0 32 1; #X connect 27 1 30 0; #X connect 28 0 26 1; #X connect 29 0 34 0; #X connect 29 1 26 0; #X connect 30 0 31 0; #X connect 30 1 28 0; #X connect 31 0 25 1; #X connect 32 0 24 1; #X connect 34 0 38 1; #X connect 34 1 35 0; #X connect 35 0 2 0; #X connect 38 0 19 0; #X connect 39 0 35 1; #X connect 42 0 17 1; #X connect 42 1 38 0; #X connect 42 2 19 1; #X connect 43 0 21 0; #X connect 43 1 15 1; #X connect 43 2 16 1; #X connect 43 3 39 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/ctlout.pd0000644000000000000000000000101300000000000017272 0ustar00#N canvas 21 409 309 367 10; #X obj 59 278 pack f f f; #X obj 155 76 loadbang; #X obj 116 156 inlet channel; #X obj 59 310 s __hv_ctlout @hv_param; #X obj 59 46 inlet value; #X obj 116 203 f \$2; #X obj 87 76 inlet cc; #X obj 87 118 f \$1; #X obj 155 98 t b b; #X obj 116 225 - 1; #X obj 116 248 max; #X connect 0 0 3 0; #X connect 1 0 8 0; #X connect 2 0 5 0; #X connect 4 0 0 0; #X connect 5 0 9 0; #X connect 6 0 7 0; #X connect 7 0 0 1; #X connect 8 0 7 0; #X connect 8 1 5 0; #X connect 9 0 10 0; #X connect 10 0 0 2; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/czero_rev~.pd0000644000000000000000000000172500000000000020166 0ustar00#N canvas 561 23 370 282 10; #X obj 164 237 outlet~; #X obj 24 237 outlet~; #X obj 24 24 inlet~ a; #X obj 106 24 inlet~ b; #X obj 194 24 inlet~ c; #X obj 277 24 inlet~ d; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 24 177 pd @hv_obj __del1~f e; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 164 177 pd @hv_obj __del1~f f; #X obj 106 107 *~; #X obj 39 147 -~; #X obj 39 107 *~; #X obj 24 207 -~; #X obj 262 105 *~; #X obj 179 107 *~; #X obj 164 207 -~; #X obj 179 147 +~; #X connect 2 0 6 0; #X connect 2 0 10 0; #X connect 2 0 12 0; #X connect 3 0 7 0; #X connect 3 0 8 0; #X connect 3 0 13 0; #X connect 4 0 10 1; #X connect 4 0 13 1; #X connect 5 0 8 1; #X connect 5 0 12 1; #X connect 6 0 11 0; #X connect 7 0 14 0; #X connect 8 0 9 1; #X connect 9 0 11 1; #X connect 10 0 9 0; #X connect 11 0 1 0; #X connect 12 0 15 1; #X connect 13 0 15 0; #X connect 14 0 0 0; #X connect 15 0 14 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/czero~.pd0000644000000000000000000000172300000000000017310 0ustar00#N canvas 561 23 350 265 10; #X obj 207 217 outlet~; #X obj 16 233 outlet~; #X obj 16 211 +~; #X obj 146 139 *~; #X obj 25 139 *~; #X obj 16 18 inlet~ a; #X obj 161 16 inlet~ b; #X obj 220 17 inlet~ c; #X obj 280 17 inlet~ d; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 25 63 pd @hv_obj __del1~f e; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 161 63 pd @hv_obj __del1~f f; #X obj 31 185 -~; #X obj 205 139 *~; #X obj 265 139 *~; #X obj 250 164 +~; #X obj 207 193 -~; #X connect 2 0 1 0; #X connect 3 0 11 0; #X connect 4 0 11 1; #X connect 5 0 9 0; #X connect 5 0 2 0; #X connect 6 0 10 0; #X connect 6 0 15 0; #X connect 7 0 4 1; #X connect 7 0 12 1; #X connect 8 0 3 0; #X connect 8 0 13 1; #X connect 9 0 4 0; #X connect 9 0 13 0; #X connect 10 0 3 1; #X connect 10 0 12 0; #X connect 11 0 2 1; #X connect 12 0 14 0; #X connect 13 0 14 1; #X connect 14 0 15 1; #X connect 15 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/dbtopow.pd0000644000000000000000000000126600000000000017450 0ustar00#N canvas 32 267 339 384 10; #X msg 116 264 10; #X obj 116 294 pow; #X obj 116 174 - 100; #X obj 29 30 inlet; #X obj 29 342 outlet; #X obj 29 60 t f f; #X obj 116 88 > 0; #X msg 29 294 0; #X obj 116 144 min 870; #X obj 116 234 t a a; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 29 114 pd @hv_obj __if; #X obj 116 204 / 10; #X connect 0 0 1 0; #X connect 1 0 4 0; #X connect 2 0 11 0; #X connect 3 0 5 0; #X connect 5 0 10 0; #X connect 5 1 6 0; #X connect 6 0 10 1; #X connect 7 0 4 0; #X connect 8 0 2 0; #X connect 9 0 0 0; #X connect 9 1 1 1; #X connect 10 0 7 0; #X connect 10 1 8 0; #X connect 11 0 9 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/dbtopow~.pd0000644000000000000000000000034500000000000017643 0ustar00#N canvas 864 515 183 129 10; #X obj 11 38 -~ 100; #X obj 11 16 inlet~; #X obj 11 104 outlet~; #X obj 11 81 exp~; #X obj 11 60 *~ 0.230258509299405; #X connect 0 0 4 0; #X connect 1 0 0 0; #X connect 3 0 2 0; #X connect 4 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/dbtorms.pd0000644000000000000000000000126400000000000017442 0ustar00#N canvas 0 183 339 384 10; #X msg 116 264 10; #X obj 116 294 pow; #X obj 116 174 - 100; #X obj 29 30 inlet; #X obj 29 342 outlet; #X obj 29 60 t f f; #X obj 116 88 > 0; #X obj 116 144 min 485; #X msg 29 294 0; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 29 114 pd @hv_obj __if; #X obj 116 204 / 20; #X obj 116 234 t a a; #X connect 0 0 1 0; #X connect 1 0 4 0; #X connect 2 0 10 0; #X connect 3 0 5 0; #X connect 5 0 9 0; #X connect 5 1 6 0; #X connect 6 0 9 1; #X connect 7 0 2 0; #X connect 8 0 4 0; #X connect 9 0 8 0; #X connect 9 1 7 0; #X connect 10 0 11 0; #X connect 11 0 0 0; #X connect 11 1 1 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/dbtorms~.pd0000644000000000000000000000034500000000000017637 0ustar00#N canvas 973 242 183 134 10; #X obj 11 38 -~ 100; #X obj 11 16 inlet~; #X obj 11 104 outlet~; #X obj 11 81 exp~; #X obj 11 60 *~ 0.115129254649702; #X connect 0 0 4 0; #X connect 1 0 0 0; #X connect 3 0 2 0; #X connect 4 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/declare.pd0000644000000000000000000000007500000000000017366 0ustar00#N canvas 612 207 258 179 10; #X text 35 49 // dummy object; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/del.pd0000644000000000000000000000033500000000000016532 0ustar00#N canvas 66 332 226 143 10; #X obj 13 16 inlet; #X obj 58 16 inlet; #X obj 13 67 outlet; #X text 12 94 @hv_arg \$1 delay float 0 false; #X obj 13 42 delay \$1; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/delay.pd0000644000000000000000000000122100000000000017057 0ustar00#N canvas 362 256 269 251 10; #X obj 21 20 inlet; #X obj 144 20 inlet; #X obj 21 221 outlet; #X text 67 221 @hv_arg \$1 delay float 0 false; #N canvas 0 22 450 300 @hv_obj 0; #X obj 179 47 inlet; #X obj 275 124 outlet; #X obj 209 124 outlet; #X restore 21 43 pd @hv_obj __switchcase stop; #X msg 21 149 clear; #N canvas 377 209 450 300 @hv_obj 0; #X obj 152 38 inlet; #X obj 261 44 inlet; #X obj 199 177 outlet; #X restore 21 196 pd @hv_obj __delay \$1; #X obj 186 67 t b a a; #X connect 0 0 4 0; #X connect 1 0 6 1; #X connect 4 0 5 0; #X connect 4 1 7 0; #X connect 5 0 6 0; #X connect 6 0 2 0; #X connect 7 0 6 0; #X connect 7 1 6 1; #X connect 7 2 5 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/delread4~.pd0000644000000000000000000000641400000000000017654 0ustar00#N canvas 859 23 532 664 10; #X obj 19 26 inlet~; #X obj 4 638 outlet~; #X obj 19 163 *~; #X obj 34 116 samplerate~; #X text 79 140 convert millisecond delay to sample delay; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 95 93 pd @hv_obj system; #X obj 4 302 -~; #X obj 4 409 +~; #X text 33 301 table index; #X obj 19 565 -~; #X obj 47 565 -~; #X obj 19 589 *~; #X obj 4 613 +~; #X text 73 566 linear interpolation; #N canvas 587 66 450 300 @hv_obj 0; #X obj 146 106 inlet~; #X obj 154 156 outlet~; #X obj 239 103 inlet~; #X restore 35 385 pd @hv_obj __and~f; #X obj 4 279 +~; #X obj 68 26 t a a; #N canvas 587 66 450 300 @hv_obj 0; #X obj 221 104 inlet~; #X obj 154 156 outlet~; #X obj 146 106 inlet~; #X restore 150 363 pd @hv_obj __lt~f; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X restore 4 438 pd @hv_obj __cast~fi; #N canvas 0 23 450 300 @hv_obj 0; #X obj 232 43 inlet~; #X obj 169 185 outlet~; #X obj 165 46 inlet~; #X restore 195 478 pd @hv_obj __add~i; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 75 inlet; #X obj 175 149 outlet~; #X restore 300 456 pd @hv_obj __var_k~i 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 75 inlet; #X obj 175 149 outlet~; #X restore 249 341 pd @hv_obj __var_k~f 0; #X obj 95 49 symbol del-\$1; #X obj 34 139 / 1000; #N canvas 587 66 450 300 @hv_obj 0; #X obj 154 156 outlet~; #X obj 146 106 inlet; #X restore 4 234 pd @hv_obj __tabhead~f del-\$1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 280 42 inlet; #X restore 195 501 pd @hv_obj __tabread~if del-\$1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 249 48 inlet; #X restore 4 501 pd @hv_obj __tabread~if del-\$1; #X text 182 49 @hv_arg \$1 table string "" true; #N canvas 0 22 450 300 @hv_obj 0; #X obj 148 99 inlet; #X obj 143 158 outlet~; #X restore 27 257 pd @hv_obj __var_k~f -1 -1 true; #X obj 68 4 loadbang -1; #X msg 95 71 table \$1 size; #X text 150 430 NOTE(mhroth): SSE cast op seems to round to the nearest int \, not down; #X obj 19 210 max~ 0; #X obj 19 188 min~; #X text 70 202 [0 \, size-1]; #X text 71 187 ensure that the input never exceeds the table bounds ; #X obj 45 163 - 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 160 52 inlet~; #X obj 173 97 outlet~; #X restore 4 331 pd @hv_obj __floor~f; #X text 30 412 wrapped table index; #N canvas 0 22 450 300 @hv_obj 0; #X obj 148 99 inlet; #X obj 143 158 outlet~; #X restore 35 362 pd @hv_obj var; #X connect 0 0 2 0; #X connect 2 0 33 0; #X connect 3 0 23 0; #X connect 5 0 36 0; #X connect 5 0 39 0; #X connect 6 0 37 0; #X connect 6 0 10 0; #X connect 7 0 18 0; #X connect 9 0 11 0; #X connect 10 0 11 1; #X connect 11 0 12 1; #X connect 12 0 1 0; #X connect 14 0 7 1; #X connect 15 0 6 0; #X connect 16 0 3 0; #X connect 16 1 22 0; #X connect 17 0 14 1; #X connect 18 0 26 0; #X connect 18 0 19 0; #X connect 19 0 25 0; #X connect 20 0 19 1; #X connect 21 0 17 1; #X connect 22 0 30 0; #X connect 23 0 2 1; #X connect 24 0 15 0; #X connect 25 0 9 0; #X connect 26 0 9 1; #X connect 26 0 12 0; #X connect 28 0 15 1; #X connect 29 0 16 0; #X connect 30 0 5 0; #X connect 32 0 6 1; #X connect 33 0 32 0; #X connect 36 0 33 1; #X connect 37 0 17 0; #X connect 37 0 10 1; #X connect 37 0 7 0; #X connect 39 0 14 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/delread~.pd0000644000000000000000000000507300000000000017570 0ustar00#N canvas 238 23 573 595 10; #N canvas 0 22 450 300 @hv_obj 0; #X obj 167 41 inlet; #X obj 178 113 outlet; #X restore 17 86 pd @hv_obj __tabhead del-\$1; #X obj 32 111 samplerate~; #X text 66 156 ms to samples; #X obj 32 156 * \$2; #X obj 32 134 / 1000; #X obj 17 226 -; #N canvas 0 22 450 300 @hv_obj 0; #X obj 152 55 inlet; #X obj 145 120 outlet; #X restore 83 298 pd @hv_obj system; #X msg 83 274 table \$1 size; #N canvas 0 22 450 300 @hv_obj 0; #X obj 186 57 inlet; #X obj 190 116 outlet; #X restore 83 251 pd @hv_obj __var del-\$1; #N canvas 0 22 258 159 @hv_obj 0; #X obj 37 33 inlet; #X obj 141 33 inlet; #X obj 53 104 outlet; #X obj 88 31 inlet; #X restore 87 436 pd @hv_obj __delay \$2; #X obj 75 520 outlet~; #X text 74 562 @hv_arg \$2 delay float 10 true; #X text 74 543 @hv_arg \$1 table string "" true; #X msg 95 407 clear; #X obj 224 469 t a a; #N canvas 0 22 450 300 @hv_obj 0; #X obj 154 94 inlet; #X obj 191 93 inlet; #X obj 170 165 outlet; #X obj 233 92 inlet; #X restore 87 469 pd @hv_obj __delay; #X obj 95 6 inlet delay-ms; #X obj 17 6 loadbang -1; #X text 205 7 NOTE(mhroth): there may be an issue here in which; #X text 223 24 tabread sets itself to a different offset than; #X text 224 42 the input \, due to alignment issues.; #X text 224 58 But the first delay is set based on the original offset ; #X text 224 74 which may account for the difference of a few samples ; #X msg 47 178 @HV_N_SIMD; #X text 56 201 add minimum delay of HV_N_SIMD; #X obj 32 200 max; #X obj 56 345 t b a a; #X obj 17 32 t a a; #X obj 17 57 t a a a; #X obj 210 412 * -1; #X obj 210 391 -; #X text 263 469 delay from one end of the table to the other; #X text 222 435 delay from current head to the end of the table; #X obj 95 31 t b a; #N canvas 172 223 450 300 @hv_obj 0; #X obj 169 93 inlet; #X obj 156 131 outlet~; #X obj 229 137 outlet; #X restore 75 497 pd @hv_obj __tabread~f del-\$1; #X connect 0 0 5 0; #X connect 1 0 4 0; #X connect 3 0 25 0; #X connect 4 0 3 0; #X connect 5 0 26 0; #X connect 6 0 30 1; #X connect 6 0 15 2; #X connect 7 0 6 0; #X connect 8 0 7 0; #X connect 9 0 15 0; #X connect 9 0 34 0; #X connect 13 0 9 0; #X connect 13 0 15 0; #X connect 14 0 15 0; #X connect 14 1 34 0; #X connect 15 0 14 0; #X connect 16 0 33 0; #X connect 17 0 27 0; #X connect 23 0 25 1; #X connect 25 0 5 1; #X connect 26 0 9 0; #X connect 26 1 34 0; #X connect 26 2 13 0; #X connect 27 0 28 0; #X connect 27 1 23 0; #X connect 28 0 0 0; #X connect 28 1 1 0; #X connect 28 2 8 0; #X connect 29 0 9 2; #X connect 30 0 29 0; #X connect 33 0 28 0; #X connect 33 1 3 1; #X connect 34 0 10 0; #X connect 34 1 30 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/delwrite~.pd0000644000000000000000000000323000000000000020000 0ustar00#N canvas 973 266 457 387 10; #N canvas 0 22 450 300 @hv_obj 0; #X obj 48 70 inlet~; #X obj 147 72 inlet; #X restore 10 309 pd @hv_obj __tabwrite~f del-\$1; #X text 9 356 @hv_arg \$2 delay float 0 true; #X obj 187 134 samplerate~; #X obj 187 174 * \$2; #N canvas 0 22 450 300 @hv_obj 0; #X obj 142 60 inlet; #X obj 135 103 outlet; #X restore 187 214 pd @hv_obj table del-\$1; #X msg 187 194 resize \$1; #X text 9 337 @hv_arg \$1 table string "" true; #X obj 187 154 / 1000; #N canvas 0 22 450 300 @hv_obj 0; #X obj 215 71 inlet; #X obj 165 71 inlet; #X obj 120 72 inlet; #X obj 129 122 outlet; #X restore 187 262 pd @hv_obj __delay; #X obj 187 111 loadbang; #X obj 187 285 t a a a; #X msg 226 331 mirror; #N canvas 0 22 450 300 @hv_obj 0; #X obj 215 71 inlet; #X obj 165 71 inlet; #X obj 120 72 inlet; #X obj 129 122 outlet; #X restore 226 309 pd @hv_obj __delay; #X obj 187 237 t b a a, f 25; #X text 254 193 returns the size of the table; #X msg 331 262 @HV_N_SIMD; #N canvas 1401 0 450 300 @hv_obj 0; #X obj 48 57 inlet; #X obj 48 114 outlet; #X restore 83 52 pd @hv_obj __switchcase clear; #X msg 83 75 clear; #X text 80 32 connection from the left inlet to the switchcase; #X text 81 21 NOTE(dreamer): there is supposed to be a control; #X obj 10 26 inlet~ -~>; #X connect 2 0 7 0; #X connect 3 0 5 0; #X connect 4 0 13 0; #X connect 5 0 4 0; #X connect 7 0 3 0; #X connect 8 0 10 0; #X connect 9 0 2 0; #X connect 10 0 0 1; #X connect 10 1 8 0; #X connect 10 2 12 0; #X connect 11 0 4 0; #X connect 12 0 11 0; #X connect 13 0 8 0; #X connect 13 1 8 2; #X connect 13 2 15 0; #X connect 15 0 12 2; #X connect 16 0 17 0; #X connect 17 0 0 1; #X connect 20 0 0 0; #X connect 20 0 16 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/div.pd0000644000000000000000000000052700000000000016553 0ustar00#N canvas 710 85 214 110 10; #X obj 12 59 outlet; #X obj 12 12 inlet -->; #X obj 141 13 inlet -->; #X text 11 81 @hv_arg \$1 k float 1 false; #N canvas 0 22 450 300 @hv_obj 0; #X obj 212 64 inlet; #X obj 163 64 inlet; #X obj 173 116 outlet; #X restore 12 35 pd @hv_obj __intdiv \$1; #X connect 1 0 4 0; #X connect 2 0 4 1; #X connect 4 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/env~.pd0000644000000000000000000000052600000000000016756 0ustar00#N canvas 241 322 302 155 10; #X obj 20 19 inlet~; #X obj 20 65 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 156 85 inlet~; #X obj 162 188 outlet; #X restore 20 42 pd @hv_obj __env~f \$1 \$2; #X text 19 91 @hv_arg \$1 windowSize float 1024 false; #X text 19 109 @hv_arg \$2 period float 512 false; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/exp.pd0000644000000000000000000000041400000000000016560 0ustar00#N canvas 556 377 141 159 10; #X obj 13 19 inlet; #X obj 13 110 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 66 outlet; #X obj 19 24 inlet; #X restore 13 80 pd @hv_obj __exp; #X obj 13 49 min 87.3365; #X connect 0 0 3 0; #X connect 2 0 1 0; #X connect 3 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/exp~.pd0000644000000000000000000000034400000000000016760 0ustar00#N canvas 164 442 186 95 10; #X obj 12 7 inlet~; #X obj 12 53 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 193 52 inlet~; #X obj 188 146 outlet~; #X restore 12 31 pd @hv_obj __exp~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/f.pd0000644000000000000000000000052000000000000016207 0ustar00#N canvas 0 149 210 157 10; #X text 11 119 @hv_arg \$1 k float 0 false; #N canvas 0 22 183 125 @hv_obj 0; #X obj 78 24 inlet; #X obj 19 66 outlet; #X obj 19 24 inlet; #X restore 13 60 pd @hv_obj __var \$1; #X obj 13 90 outlet; #X obj 13 20 inlet -->; #X obj 124 20 inlet -->; #X connect 1 0 2 0; #X connect 3 0 1 0; #X connect 4 0 1 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/float.pd0000644000000000000000000000052000000000000017067 0ustar00#N canvas 0 149 210 157 10; #X text 11 119 @hv_arg \$1 k float 0 false; #N canvas 0 22 183 125 @hv_obj 0; #X obj 78 24 inlet; #X obj 19 66 outlet; #X obj 19 24 inlet; #X restore 13 60 pd @hv_obj __var \$1; #X obj 13 90 outlet; #X obj 13 20 inlet -->; #X obj 124 20 inlet -->; #X connect 1 0 2 0; #X connect 3 0 1 0; #X connect 4 0 1 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/floatatom.pd0000644000000000000000000000025500000000000017755 0ustar00#N canvas 202 244 210 108 10; #X obj 17 9 inlet; #X obj 17 55 outlet; #X text 15 76 @hv_arg \$1 k float 0 false; #X obj 17 32 f \$1; #X connect 0 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/ftom.pd0000644000000000000000000000207200000000000016733 0ustar00#N canvas 0 37 423 374 10; #X obj 21 19 inlet; #X obj 21 269 outlet; #X obj 108 139 / 440; #X obj 108 199 * 12; #X obj 108 229 + 69; #X text 19 299 // Note: Pd's internal implementation of [ftom] uses doubles instead of floats so there will be slight rounding discrepencies. ; #X obj 21 49 t f f; #X obj 108 79 > 0; #X msg 21 229 -1500; #N canvas 0 22 450 300 @hv_obj 0; #X obj 43 62 inlet; #X obj 43 84 outlet; #X obj 103 62 inlet; #X obj 103 84 outlet; #X connect 0 0 1 0; #X connect 2 0 3 0; #X restore 21 109 pd @hv_obj __if; #N canvas 0 22 450 300 @hv_obj 0; #X obj 65 52 inlet; #X obj 65 152 outlet; #X obj 65 74 log; #X obj 65 126 /; #X obj 114 124 log; #X obj 113 69 loadbang; #X msg 113 91 2; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; #X connect 4 0 3 1; #X connect 5 0 6 0; #X connect 6 0 4 0; #X restore 108 169 pd @hv_obj __log2; #X connect 0 0 6 0; #X connect 2 0 10 0; #X connect 3 0 4 0; #X connect 4 0 1 0; #X connect 6 0 9 0; #X connect 6 1 7 0; #X connect 7 0 9 1; #X connect 8 0 1 0; #X connect 9 0 8 0; #X connect 9 1 2 0; #X connect 10 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/ftom~.pd0000644000000000000000000000056100000000000017132 0ustar00#N canvas 336 416 153 151 10; #X obj 14 125 outlet~; #X obj 14 11 inlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 133 40 inlet~; #X obj 134 119 outlet~; #X restore 14 80 pd @hv_obj __log2~f; #X obj 14 102 *~ 12; #X obj 14 57 *~ 0.122312205855086; #X obj 14 34 max~ 0; #X connect 1 0 5 0; #X connect 2 0 3 0; #X connect 3 0 0 0; #X connect 4 0 2 0; #X connect 5 0 4 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/hip~.pd0000644000000000000000000000232700000000000016747 0ustar00#N canvas 524 123 547 510 10; #X text 96 432 @hv_arg \$1 fc float 0 false; #X obj 172 361 + 1; #X obj 172 383 * 0.5; #X obj 28 411 *~; #X msg 145 197 1 \$1; #X obj 145 217 -; #X obj 145 237 clip 0 1; #X obj 61 360 sig~ 1; #X obj 28 387 rzero~; #X obj 145 310 sig~; #X obj 169 50 loadbang; #X obj 145 105 f \$1; #X obj 169 75 t a a; #X obj 28 432 outlet~; #X obj 145 257 t a a; #X obj 28 27 inlet~; #X obj 145 27 inlet fc; #N canvas 0 22 450 300 @hv_obj 0; #X obj 130 85 inlet~; #X obj 81 86 inlet~; #X obj 103 163 outlet~; #X restore 28 335 pd @hv_obj __rpole~f; #X obj 145 284 * -1; #X obj 145 126 max 1; #X obj 196 105 samplerate~; #X obj 145 148 * 6.28319; #X obj 145 173 /; #X text 193 125 hip~ 0 in Pd is a passthrough \, so we limit the cutoff ; #X connect 1 0 2 0; #X connect 2 0 3 1; #X connect 3 0 13 0; #X connect 4 0 5 0; #X connect 5 0 6 0; #X connect 6 0 14 0; #X connect 7 0 8 1; #X connect 8 0 3 0; #X connect 9 0 17 1; #X connect 10 0 12 0; #X connect 11 0 19 0; #X connect 12 0 11 0; #X connect 12 1 20 0; #X connect 14 0 18 0; #X connect 14 1 1 0; #X connect 15 0 17 0; #X connect 16 0 11 0; #X connect 17 0 8 0; #X connect 18 0 9 0; #X connect 19 0 21 0; #X connect 20 0 22 1; #X connect 21 0 22 0; #X connect 22 0 4 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/hradio.pd0000644000000000000000000000020300000000000017226 0ustar00#N canvas 0 149 210 157 10; #X obj 24 35 inlet; #X obj 24 57 float 0; #X obj 24 79 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/hsl.pd0000644000000000000000000000020300000000000016546 0ustar00#N canvas 0 149 210 157 10; #X obj 24 35 inlet; #X obj 24 57 float 0; #X obj 24 79 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/i.pd0000644000000000000000000000032400000000000016214 0ustar00#N canvas 872 130 183 121 10; #X obj 7 10 inlet; #X obj 40 31 inlet; #X obj 7 76 outlet; #X text 7 96 @hv_arg \$1 k float 0 false; #X obj 7 52 int \$1; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/int.pd0000644000000000000000000000154300000000000016562 0ustar00#N canvas 872 130 257 234 10; #X obj 14 10 inlet; #X obj 14 56 f \$1; #X obj 35 31 inlet; #X obj 14 183 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 148 66 inlet; #X obj 222 64 inlet; #X obj 140 131 outlet; #X obj 233 141 outlet; #X restore 14 129 pd @hv_obj if \$1; #X obj 107 104 > 0; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 134 155 pd @hv_obj __floor; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 14 155 pd @hv_obj __ceil; #X text 11 205 @hv_arg \$1 k float 0 false; #X obj 14 80 t a a; #X connect 0 0 1 0; #X connect 1 0 9 0; #X connect 2 0 1 1; #X connect 4 0 7 0; #X connect 4 1 6 0; #X connect 5 0 4 1; #X connect 6 0 3 0; #X connect 7 0 3 0; #X connect 9 0 4 0; #X connect 9 1 5 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/line.pd0000644000000000000000000000524400000000000016721 0ustar00#N canvas 300 23 663 743 10; #X obj 118 709 outlet; #X obj 22 17 inlet target; #X obj 452 120 samplerate~; #X obj 437 317 / 1000; #X obj 437 293 *; #X obj 118 409 metro 20; #X obj 464 341 *; #X obj 465 363 / 1000; #X obj 118 449 f; #X obj 148 449 -; #X msg 118 378 1; #X obj 118 509 sel 0 1; #X msg 174 569 0; #X obj 118 479 <= 0; #X obj 159 649 +; #X obj 371 287 / 20; #X obj 270 457 /; #X obj 371 263 t f f; #X obj 190 276 t f f; #X obj 137 539 t b b; #X text 482 316 num samples to target; #X text 295 460 slope; #X obj 214 709 +; #X text 469 397 next output value; #X obj 452 142 t a a; #X obj 22 47 route stop set; #X msg 22 232 0; #X obj 165 202 inlet ramp; #X obj 373 17 inlet grain; #X text 284 691 @hv_arg \$1 initial_value float 0 false; #X text 284 707 @hv_arg \$2 grain float 20 false; #X obj 150 232 f 0; #X msg 103 93 0; #X obj 373 120 f \$2; #X obj 373 70 max 0; #X obj 373 143 sel 0; #X msg 373 167 20; #X obj 432 397 f \$1; #X obj 137 569 f; #X obj 118 649 f \$1; #X obj 62 187 t f b; #X obj 190 306 -; #X obj 174 597 t a a; #X obj 174 621 t a a; #X obj 195 458 t a a b; #X obj 373 193 t a a a; #X obj 118 679 t a a; #X obj 413 96 t a a a; #X obj 137 114 unpack f f; #X obj 103 70 t b b a b; #X obj 413 71 loadbang; #X connect 1 0 25 0; #X connect 2 0 24 0; #X connect 3 0 8 1; #X connect 4 0 3 0; #X connect 5 0 8 0; #X connect 6 0 7 0; #X connect 7 0 9 1; #X connect 8 0 9 0; #X connect 8 0 13 0; #X connect 9 0 8 1; #X connect 10 0 5 0; #X connect 11 0 39 0; #X connect 11 1 19 0; #X connect 12 0 42 0; #X connect 13 0 11 0; #X connect 14 0 39 1; #X connect 15 0 16 1; #X connect 16 0 43 0; #X connect 17 0 15 0; #X connect 17 1 4 0; #X connect 18 0 41 0; #X connect 18 1 38 1; #X connect 19 0 38 0; #X connect 19 1 12 0; #X connect 22 0 37 0; #X connect 24 0 4 1; #X connect 24 1 6 1; #X connect 25 0 26 0; #X connect 25 1 40 0; #X connect 25 2 49 0; #X connect 26 0 5 0; #X connect 27 0 31 1; #X connect 28 0 34 0; #X connect 31 0 17 0; #X connect 32 0 31 1; #X connect 33 0 35 0; #X connect 34 0 33 0; #X connect 35 0 36 0; #X connect 35 1 45 0; #X connect 36 0 45 0; #X connect 37 0 41 1; #X connect 38 0 39 0; #X connect 39 0 14 0; #X connect 39 0 46 0; #X connect 40 0 44 0; #X connect 40 1 26 0; #X connect 41 0 16 0; #X connect 42 0 43 0; #X connect 42 1 5 0; #X connect 43 0 14 1; #X connect 43 1 22 1; #X connect 44 0 39 1; #X connect 44 1 22 0; #X connect 44 2 12 0; #X connect 45 0 5 1; #X connect 45 1 15 1; #X connect 45 2 6 0; #X connect 46 0 0 0; #X connect 46 1 22 0; #X connect 47 0 33 0; #X connect 47 1 37 0; #X connect 47 2 2 0; #X connect 48 0 18 0; #X connect 48 1 17 0; #X connect 49 0 32 0; #X connect 49 1 10 0; #X connect 49 2 48 0; #X connect 49 3 31 0; #X connect 50 0 47 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/line~.pd0000644000000000000000000000045300000000000017114 0ustar00#N canvas 604 23 250 152 10; #X obj 24 28 inlet -->; #X obj 135 28 inlet -->; #N canvas 0 22 450 300 @hv_obj 0; #X obj 41 54 inlet; #X obj 89 60 inlet; #X obj 52 134 outlet~; #X restore 24 58 pd @hv_obj __line~f; #X obj 24 88 outlet~ ~f>; #X connect 0 0 2 0; #X connect 1 0 2 1; #X connect 2 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/loadbang.pd0000644000000000000000000000022300000000000017531 0ustar00#N canvas 880 53 226 80 10; #X obj 12 11 r __hv_init \$1; #X obj 12 34 outlet; #X text 12 58 @hv_arg \$1 priority int 0 false; #X connect 0 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/log.pd0000644000000000000000000000033500000000000016547 0ustar00#N canvas 439 480 151 128 10; #X obj 13 20 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet; #X obj 19 66 outlet; #X restore 13 50 pd @hv_obj __log; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/lop~.pd0000644000000000000000000000210000000000000016746 0ustar00#N canvas 659 183 231 379 10; #X text 21 347 @hv_arg \$1 fc float 22050 false; #X obj 62 70 loadbang; #X obj 23 22 inlet~; #X obj 38 125 f \$1; #N canvas 870 68 227 202 hz2rad 0; #X obj 88 50 samplerate~; #X obj 28 148 *; #X obj 28 178 outlet; #X obj 28 20 inlet fc; #X obj 88 20 inlet init; #X obj 88 108 /, f 5; #X msg 88 76 6.28319 \$1; #X connect 0 0 6 0; #X connect 1 0 2 0; #X connect 3 0 1 0; #X connect 4 0 0 0; #X connect 5 0 1 1; #X connect 6 0 5 0; #X restore 38 150 pd hz2rad; #X obj 23 227 *~; #X obj 38 47 inlet; #X obj 140 274 sig~; #X obj 23 325 outlet~; #X obj 38 176 clip 0 1; #X obj 38 202 t a a; #X obj 62 95 t a a; #N canvas 0 22 450 300 @hv_obj 0; #X obj 130 85 inlet~; #X obj 81 86 inlet~; #X obj 103 163 outlet~; #X restore 23 298 pd @hv_obj __rpole~f; #X obj 140 250 - 1; #X connect 1 0 11 0; #X connect 2 0 5 0; #X connect 3 0 4 0; #X connect 4 0 9 0; #X connect 5 0 12 0; #X connect 6 0 3 0; #X connect 7 0 12 1; #X connect 9 0 10 0; #X connect 10 0 5 1; #X connect 10 1 13 0; #X connect 11 0 3 0; #X connect 11 1 4 1; #X connect 12 0 8 0; #X connect 13 0 7 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/makenote.pd0000644000000000000000000000202300000000000017565 0ustar00#N canvas 732 230 504 438 10; #X obj 37 34 inlet pitch; #X obj 155 31 inlet velocity; #X obj 325 31 inlet duration; #X msg 102 342 0; #X obj 257 31 loadbang; #X obj 325 143 f \$2; #X obj 325 165 max 0; #X obj 37 250 pipe; #X obj 141 373 outlet velocity; #X obj 37 373 outlet pitch; #X obj 37 190 spigot 0; #X obj 155 99 f \$1; #X obj 141 314 f; #X obj 182 147 != 0; #X text 209 260 @hv_arg \$1 velocity float 0 false; #X text 209 281 @hv_arg \$2 duration float 0 false; #X obj 257 53 t a a; #X obj 155 123 t a a; #X obj 37 214 t a a; #X obj 37 293 t a a; #X obj 114 283 t a b; #X connect 0 0 10 0; #X connect 1 0 11 0; #X connect 2 0 5 0; #X connect 3 0 8 0; #X connect 4 0 16 0; #X connect 5 0 6 0; #X connect 6 0 7 1; #X connect 7 0 19 0; #X connect 10 0 18 0; #X connect 11 0 17 0; #X connect 12 0 8 0; #X connect 13 0 10 1; #X connect 16 0 11 0; #X connect 16 1 5 0; #X connect 17 0 12 1; #X connect 17 1 13 0; #X connect 18 0 7 0; #X connect 18 1 20 0; #X connect 19 0 9 0; #X connect 19 1 3 0; #X connect 20 0 9 0; #X connect 20 1 12 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/metro.pd0000644000000000000000000000224100000000000017112 0ustar00#N canvas 115 218 483 232 10; #X obj 62 50 inlet; #X obj 255 7 inlet; #X obj 62 205 outlet; #X text 112 206 @hv_arg \$1 period float 1000 false; #N canvas 0 22 450 300 @hv_obj 0; #X obj 158 79 inlet; #X obj 173 183 outlet; #X obj 275 180 outlet; #X obj 116 183 outlet; #X restore 62 76 pd @hv_obj __switchcase 0 stop; #X msg 150 145 clear; #X obj 62 175 t a a; #N canvas 0 22 450 300 @hv_obj 0; #X obj 133 43 inlet; #X obj 197 44 inlet; #X obj 179 240 outlet; #X obj 272 47 inlet; #X restore 150 175 pd @hv_obj __delay; #X obj 62 122 bang; #X obj 62 145 t a a; #X text 264 162 minimum period is set to one sample; #X obj 255 145 max 1; #X obj 292 76 samplerate~; #X obj 292 99 / 1000; #X obj 255 123 *; #X obj 255 76 f \$1; #X obj 265 52 t a a; #X obj 265 29 loadbang; #X connect 0 0 4 0; #X connect 1 0 15 0; #X connect 4 0 5 0; #X connect 4 1 5 0; #X connect 4 2 8 0; #X connect 5 0 7 0; #X connect 6 0 2 0; #X connect 6 1 7 0; #X connect 7 0 6 0; #X connect 8 0 9 0; #X connect 9 0 6 0; #X connect 9 1 5 0; #X connect 11 0 7 2; #X connect 12 0 13 0; #X connect 13 0 14 1; #X connect 14 0 11 0; #X connect 15 0 14 0; #X connect 16 0 15 0; #X connect 16 1 12 0; #X connect 17 0 16 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/midiin.pd0000644000000000000000000000037200000000000017240 0ustar00#N canvas 814 376 208 199 10; #X obj 77 126 outlet; #X obj 20 148 outlet; #X obj 20 37 r __hv_midiin; #X text 18 13 data port; #X obj 20 61 unpack f f; #X obj 77 93 + 1; #X connect 2 0 4 0; #X connect 4 0 1 0; #X connect 4 1 5 0; #X connect 5 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/midiout.pd0000644000000000000000000000057200000000000017443 0ustar00#N canvas 1026 489 417 247 10; #X obj 56 62 inlet data; #X obj 140 63 inlet port; #X obj 56 190 s __hv_midiout @hv_param; #X obj 140 161 s __hv_midioutport @hv_param; #X text 33 28 data packed in message; #X obj 152 95 loadbang; #X obj 140 130 f \$1; #X text 223 66 port is on separate Heavy send; #X connect 0 0 2 0; #X connect 1 0 6 0; #X connect 5 0 6 0; #X connect 6 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/midirealtimein.pd0000644000000000000000000000033400000000000020761 0ustar00#N canvas 951 312 204 190 12; #X obj 86 148 outlet; #X obj 20 148 outlet; #X text 23 13 data port; #X obj 20 61 unpack f f; #X obj 20 37 r __hv_midirealtimein; #X connect 3 0 1 0; #X connect 3 1 0 0; #X connect 4 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/moses.pd0000644000000000000000000000076600000000000017124 0ustar00#N canvas 623 160 245 197 10; #X obj 15 12 inlet; #X obj 129 12 inlet; #X obj 15 122 outlet; #X obj 102 122 outlet; #X obj 102 63 >= \$1; #X text 13 162 @hv_arg \$1 threshold float 0 false; #X obj 15 35 t a a; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 15 92 pd @hv_obj __if; #X connect 0 0 6 0; #X connect 1 0 4 1; #X connect 4 0 7 1; #X connect 6 0 7 0; #X connect 6 1 4 0; #X connect 7 0 2 0; #X connect 7 1 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/mtof.pd0000644000000000000000000000075400000000000016740 0ustar00#N canvas 96 248 412 280 10; #X text 24 213 // Note: Pd's internal implementation of [mtof] uses doubles instead of floats so there will be slight rounding discrepencies. ; #X obj 25 20 inlet; #X obj 25 185 outlet; #X obj 25 162 * 440; #X obj 25 44 - 69; #X obj 25 68 / 12; #X obj 25 139 pow 1; #X msg 25 116 2; #X obj 25 92 t a a; #X connect 1 0 4 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 8 0; #X connect 6 0 3 0; #X connect 7 0 6 0; #X connect 8 0 7 0; #X connect 8 1 6 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/mtof~.pd0000644000000000000000000000055600000000000017136 0ustar00#N canvas 672 125 396 190 10; #X obj 14 102 outlet~; #X obj 14 57 exp~; #X obj 14 11 inlet~; #X obj 14 34 *~ 0.057762265046662; #X obj 14 79 *~ 8.175798915643707; #X text 12 126 NOTE(mhroth): heavy uses an approximation of exp~ which may lead to slight inaccuracies at high midi notes; #X connect 1 0 4 0; #X connect 2 0 3 0; #X connect 3 0 1 0; #X connect 4 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/nbx.pd0000644000000000000000000000020300000000000016547 0ustar00#N canvas 0 149 210 157 10; #X obj 24 35 inlet; #X obj 24 57 float 0; #X obj 24 79 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/noise~.pd0000644000000000000000000000232200000000000017277 0ustar00#N canvas 655 41 342 290 10; #X obj 23 10 loadbang; #X obj 23 34 random 8.38861e+06; #N canvas 0 22 450 300 @hv_obj 0; #X obj 157 180 outlet~; #X restore 128 131 pd @hv_obj __var_k~i 16807; #N canvas 0 22 450 300 @hv_obj 0; #X obj 195 79 inlet~; #X obj 198 143 outlet~; #X restore 23 200 pd @hv_obj __cast~if; #N canvas 0 22 450 300 @hv_obj 0; #X obj 191 59 inlet~; #X obj 129 56 inlet~; #X obj 161 143 outlet~; #X restore 23 244 pd @hv_obj __mul~f; #N canvas 0 22 450 300 @hv_obj 0; #X obj 163 139 outlet~; #X restore 128 221 pd @hv_obj __var_k~f 4.65661e-10; #X obj 23 268 outlet~ ~f>; #N canvas 0 22 450 300 @hv_obj 0; #X obj 157 180 outlet~; #X obj 217 124 inlet~; #X obj 162 124 inlet~; #X restore 23 154 pd @hv_obj __mul~i; #X msg 23 83 \$1 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 162 124 inlet; #X obj 157 180 outlet~; #X restore 23 106 pd @hv_obj var 0 0 0 x; #N canvas 0 22 450 300 @hv_obj 0; #X obj 170 106 inlet~; #X restore 35 177 pd @hv_obj vario x; #X obj 36 57 inlet; #X text 78 56 set state; #X connect 0 0 1 0; #X connect 1 0 8 0; #X connect 2 0 7 1; #X connect 3 0 4 0; #X connect 4 0 6 0; #X connect 5 0 4 1; #X connect 7 0 3 0; #X connect 7 0 10 0; #X connect 8 0 9 0; #X connect 9 0 7 0; #X connect 11 0 8 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/notein.pd0000644000000000000000000000162600000000000017266 0ustar00#N canvas 692 314 379 296 10; #X text 18 13 data0/pitch data1/velocity channel; #X obj 140 69 unpack f f f; #X obj 23 39 loadbang; #X obj 23 67 i \$1; #X obj 203 212 spigot; #X obj 22 181 spigot; #X obj 87 181 spigot; #X obj 209 100 + 1; #X obj 140 214 spigot; #X obj 23 99 == 0; #X obj 209 147 ==; #X obj 209 181 t f f; #X obj 23 124 t f f; #X obj 22 250 outlet; #X obj 140 247 outlet; #X obj 301 250 outlet; #X obj 140 38 r __hv_notein; #X obj 301 219 max 1; #X connect 1 0 8 0; #X connect 1 0 5 0; #X connect 1 1 6 0; #X connect 1 1 4 0; #X connect 1 2 7 0; #X connect 2 0 3 0; #X connect 3 0 9 0; #X connect 3 0 10 1; #X connect 4 0 14 0; #X connect 5 0 13 0; #X connect 6 0 14 0; #X connect 7 0 10 0; #X connect 7 0 17 0; #X connect 8 0 13 0; #X connect 9 0 12 0; #X connect 10 0 11 0; #X connect 11 0 8 1; #X connect 11 1 4 1; #X connect 12 0 5 1; #X connect 12 1 6 1; #X connect 16 0 1 0; #X connect 17 0 15 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/noteout.pd0000644000000000000000000000064600000000000017470 0ustar00#N canvas 331 418 278 331 10; #X obj 59 232 pack f f f; #X obj 59 264 s __hv_noteout @hv_param; #X obj 59 46 inlet note; #X obj 87 76 inlet vel; #X obj 126 133 loadbang; #X obj 116 163 f \$1; #X obj 116 106 inlet channel; #X obj 116 185 - 1; #X obj 116 208 max; #X connect 0 0 1 0; #X connect 2 0 0 0; #X connect 3 0 0 1; #X connect 4 0 5 0; #X connect 5 0 7 0; #X connect 6 0 5 0; #X connect 7 0 8 0; #X connect 8 0 0 2; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/osc~.pd0000644000000000000000000000220400000000000016745 0ustar00#N canvas 650 23 284 370 10; #X obj 33 178 *~; #X obj 44 231 *~; #X obj 48 154 *~; #X text 74 153 x^2; #X text 57 178 x^3; #X text 68 231 x^5; #X obj 18 276 +~; #X obj 18 299 outlet~; #X text 17 320 @hv_arg \$1 frequency float 440 false; #X text 85 122 x; #X obj 18 78 abs~; #X obj 18 56 -~ 0.5; #X text 67 98 [-0.25 \, +0.25]; #X obj 18 122 *~ 6.283185307179586; #X obj 18 99 -~ 0.25; #X obj 135 9 inlet phase; #X obj 18 9 inlet -~>; #X text 44 278 -5% to adjust for taylor expansion; #X obj 44 255 *~ 0.007833333333333; #X text 16 335 a cosine oscillator; #N canvas 0 22 450 300 @hv_obj 0; #X obj 185 86 inlet; #X obj 277 90 inlet; #X obj 182 150 outlet~; #X restore 18 33 pd @hv_obj phasor \$1; #X obj 33 202 *~ -0.166666666666667; #X obj 18 254 +~; #X connect 0 0 1 0; #X connect 0 0 21 0; #X connect 1 0 18 0; #X connect 2 0 1 1; #X connect 2 0 0 1; #X connect 6 0 7 0; #X connect 10 0 14 0; #X connect 11 0 10 0; #X connect 13 0 2 0; #X connect 13 0 2 1; #X connect 13 0 0 0; #X connect 13 0 22 0; #X connect 14 0 13 0; #X connect 15 0 20 1; #X connect 16 0 20 0; #X connect 18 0 6 1; #X connect 20 0 11 0; #X connect 21 0 22 1; #X connect 22 0 6 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/pgmin.pd0000644000000000000000000000162200000000000017100 0ustar00#N canvas 114 229 459 438 10; #X obj 209 337 outlet; #X obj 152 76 unpack f f; #X obj 50 334 outlet; #X obj 83 104 loadbang; #X obj 83 174 == 0; #X obj 83 128 i \$1; #X obj 50 266 spigot; #X obj 209 101 + 1; #X obj 209 236 spigot; #X obj 215 175 ==; #X obj 152 237 spigot; #X obj 215 200 t f f; #X obj 209 313 max 1; #X obj 83 197 t f f; #X obj 150 270 spigot; #X obj 152 47 r __hv_pgmin; #X text 226 78 program value and channel/port; #X obj 50 299 + 1; #X connect 1 0 10 0; #X connect 1 0 6 0; #X connect 1 1 7 0; #X connect 3 0 5 0; #X connect 4 0 13 0; #X connect 5 0 4 0; #X connect 5 0 9 1; #X connect 6 0 17 0; #X connect 7 0 9 0; #X connect 7 0 14 0; #X connect 7 0 8 0; #X connect 8 0 12 0; #X connect 9 0 11 0; #X connect 10 0 17 0; #X connect 11 0 10 1; #X connect 11 1 8 1; #X connect 12 0 0 0; #X connect 13 0 6 1; #X connect 13 1 14 1; #X connect 14 0 12 0; #X connect 15 0 1 0; #X connect 17 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/pgmout.pd0000644000000000000000000000070300000000000017300 0ustar00#N canvas 611 471 232 295 10; #X obj 52 248 s __hv_pgmout @hv_param; #X obj 52 216 pack f f; #X obj 97 74 inlet channel; #X obj 97 146 f \$1; #X obj 114 106 loadbang; #X obj 52 40 inlet program; #X obj 97 168 - 1; #X obj 97 191 max; #X obj 52 168 - 1; #X obj 52 191 max; #X connect 1 0 0 0; #X connect 2 0 3 0; #X connect 3 0 6 0; #X connect 4 0 3 0; #X connect 5 0 8 0; #X connect 6 0 7 0; #X connect 7 0 1 1; #X connect 8 0 9 0; #X connect 9 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/phasor~.pd0000644000000000000000000000053700000000000017464 0ustar00#N canvas 638 45 254 136 10; #X obj 25 69 outlet~; #X obj 142 14 inlet phase; #N canvas 0 22 450 300 @hv_obj 0; #X obj 130 77 inlet; #X obj 55 136 outlet~; #X obj 55 75 inlet; #X restore 25 41 pd @hv_obj phasor \$1; #X text 23 91 @hv_arg \$1 frequency float 0 false; #X obj 25 15 inlet -~>; #X connect 1 0 2 1; #X connect 2 0 0 0; #X connect 4 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/pipe.pd0000644000000000000000000000052600000000000016725 0ustar00#N canvas 715 492 262 117 10; #X obj 14 16 inlet; #X obj 137 16 inlet; #X obj 14 62 outlet; #X text 12 87 @hv_arg \$1 delay float 0 false; #N canvas 377 209 450 300 @hv_obj 0; #X obj 152 38 inlet; #X obj 261 44 inlet; #X obj 199 177 outlet; #X restore 14 39 pd @hv_obj __delay \$1; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/poly.pd0000644000000000000000000003076100000000000016757 0ustar00#N canvas 313 155 762 544 10; #X obj 448 121 s \$0-shouldSteal; #X obj 478 208 + 1; #X obj 448 281 s \$0-currentVoiceId; #X obj 181 490 outlet pitch; #X obj 311 490 outlet velocity; #X obj 448 35 loadbang; #X obj 448 78 \$2; #X obj 45 490 outlet id; #X obj 45 457 + 1; #X obj 448 185 r \$0-voiceId++; #X obj 448 208 f 0; #X obj 448 258 mod 65535; #X obj 448 344 table \$0-pitches \$1; #X obj 448 374 table \$0-used \$1; #X obj 448 404 table \$0-ids \$1; #X obj 448 55 t b b; #X obj 564 121 s \$0-maxVoiceId; #X msg 564 98 65535; #X obj 499 236 r \$0-maxVoiceId; #X obj 45 70 route stop clear; #X obj 153 152 unpack f f; #X obj 273 208 f; #X obj 273 35 inlet velocity; #X obj 198 291 > 0; #X obj 198 311 t a a; #X obj 260 351 spigot 0; #X obj 272 229 t a a a; #X obj 153 351 spigot 0; #X obj 198 331 == 0; #X obj 153 201 t a a; #X obj 45 35 inlet pitch; #X obj 448 98 != 0; #N canvas 696 131 696 703 NoteOff 0; #X obj 159 927 outlet pitch; #X obj 247 927 outlet velocity; #X obj 58 927 outlet id; #N canvas 0 22 317 402 count 0; #X obj 31 37 inlet; #X obj 70 217 t f f; #X obj 70 277 spigot 0; #X obj 115 247 <; #X obj 70 127 t f f; #X obj 70 187 f; #X obj 100 187 + 1; #X msg 70 157 0; #X obj 97 338 outlet; #X obj 31 97 moses 1; #X obj 31 67 int; #X obj 70 307 t f f; #X connect 0 0 10 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 2 0 11 0; #X connect 3 0 2 1; #X connect 4 0 7 0; #X connect 4 1 3 1; #X connect 5 0 1 0; #X connect 6 0 5 0; #X connect 7 0 5 0; #X connect 9 1 4 0; #X connect 10 0 9 0; #X connect 11 0 6 0; #X connect 11 1 8 0; #X restore 157 226 pd count; #X obj 157 206 \$1; #X obj 157 246 t f f f f; #X msg 104 554 0; #X obj 282 292 tabread \$0-used; #X obj 392 292 tabread \$0-ids; #X obj 269 596 f; #X msg 176 554 1; #X obj 70 111 t a a b b; #X obj 157 166 unpack f f; #X obj 157 186 t b f; #X obj 157 292 tabread \$0-pitches; #X obj 157 408 ==; #X obj 157 434 &&; #X obj 282 408 &&; #X obj 562 272 r \$0-maxVoiceId; #X obj 547 300 f; #X obj 392 378 <; #X obj 157 463 sel 1; #X obj 157 493 t b b b; #X obj 407 347 f; #X obj 392 317 t f f; #X obj 59 632 spigot 0; #X obj 98 708 tabwrite \$0-used; #X obj 78 828 tabwrite \$0-ids; #X obj 78 729 t b b; #X obj 93 778 r \$0-currentVoiceId; #X obj 105 749 s \$0-voiceId++; #X obj 78 798 f; #X obj 59 655 t a b b; #X msg 98 688 0; #X obj 58 897 f; #X obj 59 865 t b a b; #X obj 159 897 unpack f f; #X msg 247 897 0; #X obj 70 31 inlet pitch; #X obj 115 56 inlet velocity; #X obj 70 89 pack f f; #X obj 104 596 t a; #X connect 3 0 5 0; #X connect 4 0 3 0; #X connect 5 0 14 0; #X connect 5 1 7 0; #X connect 5 2 8 0; #X connect 5 3 9 1; #X connect 6 0 41 0; #X connect 6 0 9 0; #X connect 7 0 17 0; #X connect 8 0 24 0; #X connect 9 0 26 1; #X connect 9 0 27 1; #X connect 9 0 34 1; #X connect 10 0 41 0; #X connect 11 0 25 0; #X connect 11 1 12 0; #X connect 11 2 6 0; #X connect 11 3 19 0; #X connect 12 0 13 0; #X connect 13 0 4 0; #X connect 13 1 15 1; #X connect 14 0 15 0; #X connect 15 0 16 0; #X connect 16 0 21 0; #X connect 17 0 16 1; #X connect 18 0 19 1; #X connect 19 0 20 1; #X connect 20 0 17 1; #X connect 21 0 22 0; #X connect 22 0 9 0; #X connect 22 1 10 0; #X connect 22 2 23 0; #X connect 23 0 20 1; #X connect 24 0 20 0; #X connect 24 1 23 1; #X connect 25 0 32 0; #X connect 28 0 31 0; #X connect 28 1 30 0; #X connect 29 0 31 1; #X connect 31 0 27 0; #X connect 32 0 35 0; #X connect 32 1 28 0; #X connect 32 2 33 0; #X connect 33 0 26 0; #X connect 34 0 2 0; #X connect 35 0 34 0; #X connect 35 1 36 0; #X connect 35 2 37 0; #X connect 36 0 0 0; #X connect 37 0 1 0; #X connect 38 0 40 0; #X connect 39 0 40 1; #X connect 40 0 11 0; #X connect 41 0 25 1; #X restore 153 381 pd NoteOff; #N canvas 596 156 499 510 Stop 0; #X obj 52 45 inlet; #N canvas 0 22 317 402 count 0; #X obj 31 37 inlet; #X obj 70 217 t f f; #X obj 70 277 spigot 0; #X obj 115 247 <; #X obj 70 127 t f f; #X obj 70 187 f; #X obj 100 187 + 1; #X msg 70 157 0; #X obj 97 338 outlet; #X obj 31 97 moses 1; #X obj 31 67 int; #X obj 70 307 t f f; #X connect 0 0 10 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 2 0 11 0; #X connect 3 0 2 1; #X connect 4 0 7 0; #X connect 4 1 3 1; #X connect 5 0 1 0; #X connect 6 0 5 0; #X connect 7 0 5 0; #X connect 9 1 4 0; #X connect 10 0 9 0; #X connect 11 0 6 0; #X connect 11 1 8 0; #X restore 52 132 pd count; #X obj 52 105 \$1; #X obj 67 428 tabwrite \$0-used; #X obj 52 75 t b b; #X msg 128 114 0; #X obj 128 136 s \$0-voiceId++; #X obj 97 200 tabread \$0-used; #X obj 97 222 != 0; #X obj 52 157 t f f; #X obj 52 251 spigot 0; #X obj 83 351 outlet id; #X obj 173 351 outlet pitch; #X obj 307 351 outlet velocity; #X msg 307 321 0; #X obj 173 321 tabread \$0-pitches; #X obj 52 273 t b f f f b; #X obj 67 380 t b f; #X msg 67 402 0; #X obj 52 464 s \$0-voiceId++; #X connect 0 0 4 0; #X connect 1 0 9 0; #X connect 2 0 1 0; #X connect 4 0 2 0; #X connect 4 1 5 0; #X connect 5 0 6 0; #X connect 7 0 8 0; #X connect 8 0 10 1; #X connect 9 0 10 0; #X connect 9 1 7 0; #X connect 10 0 16 0; #X connect 14 0 13 0; #X connect 15 0 12 0; #X connect 16 0 19 0; #X connect 16 1 17 0; #X connect 16 2 11 0; #X connect 16 3 15 0; #X connect 16 4 14 0; #X connect 17 0 18 0; #X connect 17 1 3 1; #X connect 18 0 3 0; #X restore 45 381 pd Stop; #N canvas 0 22 329 363 Clear 0; #X obj 52 45 inlet; #N canvas 0 22 317 402 count 0; #X obj 31 37 inlet; #X obj 70 217 t f f; #X obj 70 277 spigot 0; #X obj 115 247 <; #X obj 70 127 t f f; #X obj 70 187 f; #X obj 100 187 + 1; #X msg 70 157 0; #X obj 97 338 outlet; #X obj 31 97 moses 1; #X obj 31 67 int; #X obj 70 307 t f f; #X connect 0 0 10 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 2 0 11 0; #X connect 3 0 2 1; #X connect 4 0 7 0; #X connect 4 1 3 1; #X connect 5 0 1 0; #X connect 6 0 5 0; #X connect 7 0 5 0; #X connect 9 1 4 0; #X connect 10 0 9 0; #X connect 11 0 6 0; #X connect 11 1 8 0; #X restore 52 135 pd count; #X obj 52 105 \$1; #X obj 52 301 tabwrite \$0-used; #X obj 71 275 tabwrite \$0-ids; #X msg 52 195 0; #X obj 52 75 t b b; #X msg 128 114 0; #X obj 128 136 s \$0-voiceId++; #X obj 52 225 t a a a; #X obj 52 165 t b a a a; #X obj 91 250 tabwrite \$0-pitches; #X connect 0 0 6 0; #X connect 1 0 10 0; #X connect 2 0 1 0; #X connect 5 0 9 0; #X connect 6 0 2 0; #X connect 6 1 7 0; #X connect 7 0 8 0; #X connect 9 0 3 0; #X connect 9 1 4 0; #X connect 9 2 11 0; #X connect 10 0 5 0; #X connect 10 1 3 1; #X connect 10 2 4 1; #X connect 10 3 11 1; #X restore 91 152 pd Clear; #N canvas 549 249 1276 703 NoteOn 0; #N canvas 0 22 317 402 count 0; #X obj 31 37 inlet; #X obj 70 217 t f f; #X obj 70 277 spigot 0; #X obj 115 247 <; #X obj 70 127 t f f; #X obj 70 187 f; #X obj 100 187 + 1; #X msg 70 157 0; #X obj 97 338 outlet; #X obj 31 97 moses 1; #X obj 31 67 int; #X obj 70 307 t f f; #X connect 0 0 10 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 2 0 11 0; #X connect 3 0 2 1; #X connect 4 0 7 0; #X connect 4 1 3 1; #X connect 5 0 1 0; #X connect 6 0 5 0; #X connect 7 0 5 0; #X connect 9 1 4 0; #X connect 10 0 9 0; #X connect 11 0 6 0; #X connect 11 1 8 0; #X restore 900 369 pd count; #X obj 897 336 \$1; #X obj 1050 624 &&; #X obj 1115 590 <; #X obj 1088 683 sel 1; #X obj 1081 768 f; #X obj 900 391 t f f f f; #X obj 1080 821 s \$0-indexOn; #X obj 989 557 t f f; #X obj 973 701 spigot 0; #X obj 982 628 &&; #X obj 980 587 == 0; #X obj 1050 646 t f f; #X obj 1047 680 == 0; #X obj 915 788 f; #X obj 921 843 s \$0-indexOff; #X obj 777 229 s \$0-indexOn; #X obj 730 251 s \$0-indexOff; #X obj 410 212 t a b b b; #X obj 973 723 sel 1; #X obj 1156 592 <; #X obj 1184 557 f; #X obj 1118 494 t f f f; #X obj 1226 557 f; #X obj 1184 499 t f f; #X obj 966 804 s \$0-isFirstOff; #X obj 973 745 t b b b; #X msg 967 777 1; #X msg 1167 739 1; #X obj 1167 774 s \$0-isFirstOn; #X obj 1088 705 t b b b; #X msg 733 189 0; #X obj 792 193 s \$0-isFirstOn; #X obj 821 169 s \$0-isFirstOff; #X obj 385 485 r \$0-isFirstOff; #X obj 288 567 spigot 0; #X obj 385 507 t f f; #X obj 498 555 r \$0-isFirstOn; #X obj 404 681 spigot 0; #X obj 460 637 &&; #X obj 412 536 == 0; #X obj 407 398 pack f f; #X obj 407 420 t a a; #X obj 291 966 outlet pitch; #X obj 377 966 outlet velocity; #X obj 138 592 r \$0-indexOff; #X obj 278 785 f; #X obj 305 794 unpack f f; #X obj 489 724 r \$0-indexOn; #X obj 428 776 f; #X obj 489 746 t a a a a; #X obj 138 614 t a a a a; #X msg 130 832 1; #X msg 472 902 1; #X obj 505 634 r \$0-shouldSteal; #X obj 460 659 spigot 0; #X obj 221 974 outlet id; #X obj 473 815 f; #X obj 468 783 t b b b; #X msg 393 939 0; #X obj 280 596 t b b b a; #X obj 258 630 t b b; #X obj 267 677 r \$0-currentVoiceId; #X obj 284 652 s \$0-voiceId++; #X obj 255 703 f; #X obj 999 430 tabread \$0-used; #X obj 1118 432 tabread \$0-ids; #X obj 427 874 tabwrite \$0-pitches; #X obj 473 839 tabread \$0-pitches; #X obj 122 799 tabwrite \$0-pitches; #X obj 124 859 tabwrite \$0-used; #X obj 196 889 tabwrite \$0-ids; #X obj 621 923 tabwrite \$0-ids; #X obj 632 752 t b b; #X obj 641 799 r \$0-currentVoiceId; #X obj 658 774 s \$0-voiceId++; #X obj 629 825 f; #X obj 404 703 t b b b a b; #X obj 498 577 t b f; #X obj 470 927 tabwrite \$0-used; #X obj 1015 251 r \$0-maxVoiceId; #X obj 1021 308 f; #X obj 389 815 unpack f f; #X obj 389 837 t a a; #X obj 304 822 t a a; #X obj 421 51 inlet pitch; #X obj 665 41 inlet vel; #X obj 457 610 f; #X connect 0 0 6 0; #X connect 1 0 0 0; #X connect 2 0 12 0; #X connect 3 0 10 1; #X connect 4 0 30 0; #X connect 5 0 7 0; #X connect 6 1 65 0; #X connect 6 2 66 0; #X connect 6 3 5 1; #X connect 6 3 14 1; #X connect 8 0 11 0; #X connect 8 1 2 0; #X connect 9 0 19 0; #X connect 10 0 9 0; #X connect 11 0 10 0; #X connect 12 0 13 0; #X connect 12 1 4 0; #X connect 13 0 9 1; #X connect 14 0 15 0; #X connect 18 0 41 0; #X connect 18 1 1 0; #X connect 18 2 81 0; #X connect 18 3 31 0; #X connect 19 0 26 0; #X connect 20 0 2 1; #X connect 21 0 3 1; #X connect 22 0 3 0; #X connect 22 1 20 0; #X connect 22 2 21 1; #X connect 22 2 23 1; #X connect 23 0 20 1; #X connect 24 0 21 0; #X connect 24 1 23 0; #X connect 26 0 14 0; #X connect 26 1 27 0; #X connect 26 2 21 0; #X connect 27 0 25 0; #X connect 28 0 29 0; #X connect 30 0 5 0; #X connect 30 1 28 0; #X connect 30 2 23 0; #X connect 31 0 17 0; #X connect 31 0 16 0; #X connect 31 0 32 0; #X connect 31 0 33 0; #X connect 34 0 36 0; #X connect 35 0 60 0; #X connect 36 0 35 1; #X connect 36 1 40 0; #X connect 37 0 78 0; #X connect 38 0 77 0; #X connect 39 0 55 0; #X connect 40 0 87 0; #X connect 41 0 42 0; #X connect 42 0 35 0; #X connect 42 1 38 0; #X connect 45 0 51 0; #X connect 46 0 56 0; #X connect 47 0 84 0; #X connect 47 1 44 0; #X connect 48 0 50 0; #X connect 49 0 56 0; #X connect 50 0 49 1; #X connect 50 0 57 1; #X connect 50 1 72 1; #X connect 50 2 79 1; #X connect 50 3 67 1; #X connect 51 0 70 1; #X connect 51 1 69 1; #X connect 51 2 71 1; #X connect 51 3 46 1; #X connect 52 0 70 0; #X connect 53 0 79 0; #X connect 54 0 55 1; #X connect 55 0 38 1; #X connect 57 0 68 0; #X connect 58 0 49 0; #X connect 58 1 57 0; #X connect 58 2 59 0; #X connect 59 0 44 0; #X connect 60 0 61 0; #X connect 60 1 52 0; #X connect 60 2 46 0; #X connect 60 3 47 0; #X connect 61 0 64 0; #X connect 61 1 63 0; #X connect 62 0 64 1; #X connect 64 0 71 0; #X connect 65 0 8 0; #X connect 66 0 22 0; #X connect 68 0 43 0; #X connect 73 0 76 0; #X connect 73 1 75 0; #X connect 74 0 76 1; #X connect 76 0 72 0; #X connect 77 0 73 0; #X connect 77 1 53 0; #X connect 77 2 49 0; #X connect 77 3 82 0; #X connect 77 4 58 0; #X connect 78 0 87 0; #X connect 78 1 39 1; #X connect 80 0 81 1; #X connect 81 0 24 0; #X connect 82 0 83 0; #X connect 82 1 44 0; #X connect 83 0 43 0; #X connect 83 1 67 0; #X connect 84 0 43 0; #X connect 84 1 69 0; #X connect 85 0 18 0; #X connect 86 0 41 1; #X connect 87 0 39 0; #X restore 260 381 pd NoteOn; #X text 447 466 @hv_arg \$1 NumVoices int 1 false; #X text 447 486 @hv_arg \$2 VoiceStealing int 0 false; #X connect 1 0 10 1; #X connect 5 0 15 0; #X connect 6 0 31 0; #X connect 8 0 7 0; #X connect 9 0 10 0; #X connect 10 0 11 0; #X connect 11 0 1 0; #X connect 11 0 2 0; #X connect 15 0 6 0; #X connect 15 1 17 0; #X connect 17 0 16 0; #X connect 18 0 11 1; #X connect 19 0 33 0; #X connect 19 1 34 0; #X connect 19 2 20 0; #X connect 20 0 29 0; #X connect 20 1 21 0; #X connect 21 0 26 0; #X connect 22 0 21 0; #X connect 23 0 24 0; #X connect 24 0 28 0; #X connect 24 1 25 1; #X connect 25 0 35 0; #X connect 26 0 23 0; #X connect 26 1 32 1; #X connect 26 2 35 1; #X connect 27 0 32 0; #X connect 28 0 27 1; #X connect 29 0 27 0; #X connect 29 1 25 0; #X connect 30 0 19 0; #X connect 31 0 0 0; #X connect 32 0 8 0; #X connect 32 1 3 0; #X connect 32 2 4 0; #X connect 33 0 8 0; #X connect 33 1 3 0; #X connect 33 2 4 0; #X connect 35 0 8 0; #X connect 35 1 3 0; #X connect 35 2 4 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/polytouchin.pd0000644000000000000000000000162700000000000020350 0ustar00#N canvas 692 314 379 296 10; #X obj 140 69 unpack f f f; #X obj 23 39 loadbang; #X obj 23 67 i \$1; #X obj 203 212 spigot; #X obj 22 181 spigot; #X obj 87 181 spigot; #X obj 209 100 + 1; #X obj 140 214 spigot; #X obj 23 99 == 0; #X obj 209 147 ==; #X obj 209 181 t f f; #X obj 23 124 t f f; #X obj 22 250 outlet; #X obj 140 247 outlet; #X obj 301 250 outlet; #X obj 301 219 max 1; #X obj 140 38 r __hv_polytouchin; #X text 18 13 data0/note data1/pressure channel; #X connect 0 0 7 0; #X connect 0 0 4 0; #X connect 0 1 5 0; #X connect 0 1 3 0; #X connect 0 2 6 0; #X connect 1 0 2 0; #X connect 2 0 8 0; #X connect 2 0 9 1; #X connect 3 0 13 0; #X connect 4 0 12 0; #X connect 5 0 13 0; #X connect 6 0 9 0; #X connect 6 0 15 0; #X connect 7 0 12 0; #X connect 8 0 11 0; #X connect 9 0 10 0; #X connect 10 0 7 1; #X connect 10 1 3 1; #X connect 11 0 4 1; #X connect 11 1 5 1; #X connect 15 0 14 0; #X connect 16 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/polytouchout.pd0000644000000000000000000000065600000000000020552 0ustar00#N canvas 1225 622 278 331 10; #X obj 59 232 pack f f f; #X obj 126 133 loadbang; #X obj 116 163 f \$1; #X obj 116 106 inlet channel; #X obj 116 185 - 1; #X obj 116 208 max; #X obj 59 264 s __hv_polytouchout @hv_param; #X obj 59 46 inlet touch; #X obj 87 76 inlet note; #X connect 0 0 6 0; #X connect 1 0 2 0; #X connect 2 0 4 0; #X connect 3 0 2 0; #X connect 4 0 5 0; #X connect 5 0 0 2; #X connect 7 0 0 0; #X connect 8 0 0 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/powtodb.pd0000644000000000000000000000125000000000000017441 0ustar00#N canvas 243 267 355 324 10; #X obj 26 21 inlet; #X obj 26 273 outlet; #X obj 26 51 t f f; #X msg 26 225 0; #X obj 113 195 + 100; #X obj 113 225 max 0; #X obj 113 79 > 0; #X obj 113 165 * 10; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 26 105 pd @hv_obj __if; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 60 95 outlet; #X restore 113 135 pd @hv_obj __log10; #X connect 0 0 2 0; #X connect 2 0 8 0; #X connect 2 1 6 0; #X connect 3 0 1 0; #X connect 4 0 5 0; #X connect 5 0 1 0; #X connect 6 0 8 1; #X connect 7 0 4 0; #X connect 8 0 3 0; #X connect 8 1 9 0; #X connect 9 0 7 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/powtodb~.pd0000644000000000000000000000063400000000000017644 0ustar00#N canvas 712 409 141 174 10; #X obj 14 147 outlet~; #X obj 14 11 inlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 133 40 inlet~; #X obj 134 119 outlet~; #X restore 14 57 pd @hv_obj __log2~f; #X obj 14 34 max~ 0; #X obj 14 102 +~ 100; #X obj 14 79 *~ 3.010299956639812; #X obj 14 125 max~ 0; #X connect 1 0 3 0; #X connect 2 0 5 0; #X connect 3 0 2 0; #X connect 4 0 6 0; #X connect 5 0 4 0; #X connect 6 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/print.pd0000644000000000000000000000032700000000000017123 0ustar00#N canvas 801 225 258 123 10; #N canvas 0 22 450 300 @hv_obj 0; #X obj 46 72 inlet; #X restore 21 51 pd @hv_obj print \$1; #X obj 21 21 inlet; #X text 19 83 @hv_arg \$1 label string print false; #X connect 1 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/q8_rsqrt~.pd0000644000000000000000000000034300000000000017746 0ustar00#N canvas 0 22 191 83 10; #X obj 10 4 inlet~; #X obj 10 52 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 163 70 inlet~; #X obj 156 144 outlet~; #X restore 10 27 pd @hv_obj __rsqrt~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/q8_sqrt~.pd0000644000000000000000000000034200000000000017563 0ustar00#N canvas 0 22 191 83 10; #X obj 10 4 inlet~; #X obj 10 52 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 163 70 inlet~; #X obj 156 144 outlet~; #X restore 10 27 pd @hv_obj __sqrt~f; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/random.pd0000644000000000000000000000150300000000000017244 0ustar00#N canvas 585 151 215 219 10; #X obj 13 10 inlet; #X obj 34 105 inlet; #X obj 13 172 outlet; #X obj 13 128 * \$1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 223 53 inlet; #X obj 241 144 outlet; #X restore 13 150 pd @hv_obj floor; #X text 12 192 @hv_arg \$1 range float 2 false; #N canvas 636 94 450 300 @hv_obj 0; #X obj 37 37 inlet; #X obj 190 49 inlet; #X obj 155 131 outlet; #X restore 13 83 pd @hv_obj random; #N canvas 0 22 450 300 @hv_obj 0; #X obj 178 47 inlet; #X obj 165 128 outlet; #X restore 13 57 pd @hv_obj slice 1 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 24 inlet; #X obj 221 83 outlet; #X obj 159 83 outlet; #X restore 13 34 pd @hv_obj __switchcase seed; #X connect 0 0 8 0; #X connect 1 0 3 1; #X connect 3 0 4 0; #X connect 4 0 2 0; #X connect 6 0 3 0; #X connect 7 0 6 1; #X connect 8 0 7 0; #X connect 8 1 6 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/rmstodb.pd0000644000000000000000000000125000000000000017435 0ustar00#N canvas 474 236 355 324 10; #X obj 26 21 inlet; #X obj 26 273 outlet; #X obj 26 51 t f f; #X msg 26 225 0; #X obj 113 165 * 20; #X obj 113 195 + 100; #X obj 113 225 max 0; #X obj 113 79 > 0; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 120 35 inlet; #X obj 60 95 outlet; #X obj 120 95 outlet; #X restore 26 105 pd @hv_obj __if; #N canvas 0 22 260 165 @hv_obj 0; #X obj 60 35 inlet; #X obj 60 95 outlet; #X restore 113 135 pd @hv_obj __log10; #X connect 0 0 2 0; #X connect 2 0 8 0; #X connect 2 1 7 0; #X connect 3 0 1 0; #X connect 4 0 5 0; #X connect 5 0 6 0; #X connect 6 0 1 0; #X connect 7 0 8 1; #X connect 8 0 3 0; #X connect 8 1 9 0; #X connect 9 0 4 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/rmstodb~.pd0000644000000000000000000000063400000000000017640 0ustar00#N canvas 569 274 140 178 10; #X obj 14 148 outlet~; #X obj 14 11 inlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 133 40 inlet~; #X obj 134 119 outlet~; #X restore 14 57 pd @hv_obj __log2~f; #X obj 14 79 *~ 6.020599913279624; #X obj 14 34 max~ 0; #X obj 14 102 +~ 100; #X obj 14 125 max~ 0; #X connect 1 0 4 0; #X connect 2 0 3 0; #X connect 3 0 5 0; #X connect 4 0 2 0; #X connect 5 0 6 0; #X connect 6 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/rpole~.pd0000644000000000000000000000052100000000000017302 0ustar00#N canvas 796 340 189 114 10; #X obj 130 16 inlet~; #X obj 13 16 inlet~; #X obj 13 84 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 204 68 inlet~; #X obj 144 68 inlet~; #X obj 160 129 outlet~; #X restore 13 61 pd @hv_obj __rpole~f; #X obj 130 38 *~ -1; #X connect 0 0 4 0; #X connect 1 0 3 0; #X connect 3 0 2 0; #X connect 4 0 3 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/rsqrt~.pd0000644000000000000000000000161300000000000017337 0ustar00#N canvas 0 23 281 147 10; #X obj 19 10 inlet~; #X obj 19 105 outlet~; #N canvas 467 216 450 300 @hv_obj 0; #X obj 217 60 inlet~; #X obj 120 60 inlet~; #X obj 170 183 outlet~; #X connect 1 0 2 0; #X restore 19 81 pd @hv_obj __and~f; #X obj 118 10 sig~ 0; #N canvas 715 101 191 233 @hv_obj 0; #X obj 49 83 -~; #X obj 50 109 clip~ -1e-37 0; #X obj 49 32 inlet~; #X obj 93 33 inlet~; #X obj 50 174 outlet~; #X obj 50 151 *~ 1e+37; #X obj 49 58 min~; #X obj 50 130 +~ 1e-37; #X connect 0 0 1 0; #X connect 1 0 7 0; #X connect 2 0 6 0; #X connect 2 0 0 1; #X connect 3 0 6 1; #X connect 5 0 4 0; #X connect 6 0 0 0; #X connect 7 0 5 0; #X restore 19 33 pd @hv_obj __gt~f; #N canvas 0 23 450 300 @hv_obj 0; #X obj 163 70 inlet~; #X obj 156 144 outlet~; #X restore 124 60 pd @hv_obj __rsqrt~f; #X connect 0 0 4 0; #X connect 0 0 5 0; #X connect 2 0 1 0; #X connect 3 0 4 1; #X connect 4 0 2 0; #X connect 5 0 2 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/rzero_rev~.pd0000644000000000000000000000055700000000000020207 0ustar00#N canvas 932 23 172 215 10; #X obj 71 18 inlet~; #X obj 16 18 inlet~; #X obj 16 163 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 16 96 pd @hv_obj __del1~f; #X obj 31 64 *~; #X obj 16 141 -~; #X connect 0 0 4 1; #X connect 1 0 3 0; #X connect 1 0 4 0; #X connect 3 0 5 0; #X connect 4 0 5 1; #X connect 5 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/rzero~.pd0000644000000000000000000000064100000000000017325 0ustar00#N canvas 397 215 281 159 10; #X obj 46 65 inlet~; #X obj 16 18 inlet~; #X obj 16 133 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 31 43 pd @hv_obj __del1~f; #X obj 31 88 *~; #X obj 16 111 -~; #X text 65 18 Implements Pd's H(z) = 1 - a*z^-1; #X connect 0 0 4 1; #X connect 1 0 3 0; #X connect 1 0 5 0; #X connect 3 0 4 0; #X connect 4 0 5 1; #X connect 5 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/samphold~.pd0000644000000000000000000000114700000000000017775 0ustar00#N canvas 714 389 383 150 10; #X obj 12 114 outlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 55 136 outlet~; #X obj 54 74 inlet~; #X obj 130 77 inlet~; #X restore 12 86 pd @hv_obj __samphold~f; #X obj 12 12 inlet~; #X obj 147 12 inlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 175 149 outlet~; #X obj 173 75 inlet~; #X restore 246 38 pd @hv_obj __del1~f; #N canvas 0 22 450 300 @hv_obj 0; #X obj 216 44 inlet~; #X obj 139 45 inlet~; #X obj 172 91 outlet~; #X restore 147 61 pd @hv_obj __lt~f; #X connect 1 0 0 0; #X connect 2 0 1 0; #X connect 3 0 4 0; #X connect 3 0 5 0; #X connect 4 0 5 1; #X connect 5 0 1 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/samplerate~.pd0000644000000000000000000000041500000000000020320 0ustar00#N canvas 698 370 281 258 10; #X obj 19 11 inlet; #X obj 19 84 outlet; #X msg 19 35 samplerate; #N canvas 0 22 450 300 @hv_obj 0; #X obj 119 57 inlet; #X obj 119 97 outlet; #X restore 19 59 pd @hv_obj system; #X connect 0 0 2 0; #X connect 2 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/sig~.pd0000644000000000000000000000041300000000000016743 0ustar00#N canvas 329 553 183 106 10; #X obj 9 11 inlet; #X obj 9 57 outlet~; #X text 7 78 @hv_arg \$1 k float 0 false; #N canvas 0 22 450 300 @hv_obj 0; #X obj 170 59 inlet; #X obj 180 116 outlet~; #X restore 9 34 pd @hv_obj var \$1; #X connect 0 0 3 0; #X connect 3 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/sin.pd0000644000000000000000000000033500000000000016557 0ustar00#N canvas 439 480 151 128 10; #X obj 13 20 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet; #X obj 19 66 outlet; #X restore 13 50 pd @hv_obj __sin; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/snapshot~.pd0000644000000000000000000000063300000000000020024 0ustar00#N canvas 450 250 412 101 10; #X obj 15 61 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 186 56 inlet~; #X obj 194 120 outlet; #X obj 260 62 inlet; #X restore 15 36 pd @hv_obj __sample~f; #X text 65 59 NOTE(mhroth): there is supposed to be a control; #X text 64 72 connection from the inlet to the right __sample~f inlet ; #X obj 15 11 inlet~ -~>; #X connect 1 0 0 0; #X connect 4 0 1 0; #X connect 4 0 1 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/spigot.pd0000644000000000000000000000054700000000000017300 0ustar00#N canvas 623 160 225 146 10; #X obj 10 8 inlet; #X obj 103 44 inlet; #X obj 103 92 outlet; #X text 8 118 @hv_arg \$1 is_true float 0 false; #N canvas 0 22 450 300 @hv_obj 0; #X obj 148 66 inlet; #X obj 222 64 inlet; #X obj 140 131 outlet; #X obj 233 141 outlet; #X restore 10 68 pd @hv_obj if \$1; #X connect 0 0 4 0; #X connect 1 0 4 1; #X connect 4 1 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/sqrt.pd0000644000000000000000000000033600000000000016760 0ustar00#N canvas 399 260 218 85 10; #X obj 16 9 inlet; #X obj 16 59 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 172 24 inlet; #X obj 172 78 outlet; #X restore 16 34 pd @hv_obj __sqrt; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/sqrt~.pd0000644000000000000000000000161500000000000017157 0ustar00#N canvas 170 337 302 168 10; #N canvas 0 23 450 300 @hv_obj 0; #X obj 163 70 inlet~; #X obj 156 144 outlet~; #X restore 135 69 pd @hv_obj __sqrt~f; #X obj 30 19 inlet~; #X obj 30 114 outlet~; #N canvas 467 216 450 300 @hv_obj 0; #X obj 217 60 inlet~; #X obj 120 60 inlet~; #X obj 170 183 outlet~; #X connect 1 0 2 0; #X restore 30 90 pd @hv_obj __and~f; #X obj 129 19 sig~ 0; #N canvas 715 101 191 233 @hv_obj 0; #X obj 49 83 -~; #X obj 50 109 clip~ -1e-37 0; #X obj 49 32 inlet~; #X obj 93 33 inlet~; #X obj 50 174 outlet~; #X obj 50 151 *~ 1e+37; #X obj 49 58 min~; #X obj 50 130 +~ 1e-37; #X connect 0 0 1 0; #X connect 1 0 7 0; #X connect 2 0 6 0; #X connect 2 0 0 1; #X connect 3 0 6 1; #X connect 5 0 4 0; #X connect 6 0 0 0; #X connect 7 0 5 0; #X restore 30 42 pd @hv_obj __gt~f; #X connect 0 0 3 1; #X connect 1 0 5 0; #X connect 1 0 0 0; #X connect 3 0 2 0; #X connect 4 0 5 1; #X connect 5 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/stripnote.pd0000644000000000000000000000173300000000000020020 0ustar00#N canvas 648 404 450 300 12; #X obj 47 10 inlet; #X obj 47 503 outlet; #X obj 47 335 unpack f f; #X obj 96 503 outlet; #X obj 47 460 spigot; #X obj 107 408 != 0; #X obj 96 460 spigot; #X obj 248 10 inlet; #X obj 216 289 spigot; #X obj 96 365 t f f; #X obj 96 87 unpack f f; #X obj 47 41 t a a; #X obj 111 199 f; #X msg 96 159 0; #X msg 144 159 1; #X obj 47 289 spigot; #X obj 216 199 pack f f; #X obj 96 117 t b f b; #X obj 241 258 == 0; #X connect 0 0 11 0; #X connect 2 0 4 0; #X connect 2 1 9 0; #X connect 4 0 1 0; #X connect 5 0 4 1; #X connect 5 0 6 1; #X connect 6 0 3 0; #X connect 6 0 16 1; #X connect 7 0 16 1; #X connect 8 0 2 0; #X connect 9 0 6 0; #X connect 9 1 5 0; #X connect 10 0 17 0; #X connect 10 1 14 0; #X connect 11 0 15 0; #X connect 11 1 10 0; #X connect 12 0 15 1; #X connect 12 0 18 0; #X connect 13 0 12 1; #X connect 14 0 12 1; #X connect 15 0 2 0; #X connect 16 0 8 0; #X connect 17 0 13 0; #X connect 17 1 16 0; #X connect 17 2 12 0; #X connect 18 0 8 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/swap.pd0000644000000000000000000000111100000000000016731 0ustar00#N canvas 566 310 291 266 10; #X obj 28 26 inlet; #X obj 107 26 inlet; #X obj 28 196 outlet; #X obj 220 189 outlet; #X obj 220 149 f; #X obj 28 106 t b b; #X obj 193 109 t b f; #X obj 28 156 f \$1; #N canvas 0 22 201 165 @hv_obj 0; #X obj 34 25 inlet; #X obj 34 97 outlet; #X obj 86 93 outlet; #X restore 28 66 pd @hv_obj __switchcase bang; #X text 27 235 @hv_arg \$1 k float 0 false; #X connect 0 0 8 0; #X connect 1 0 7 1; #X connect 4 0 3 0; #X connect 5 0 7 0; #X connect 5 1 4 0; #X connect 6 0 7 0; #X connect 6 1 4 0; #X connect 7 0 2 0; #X connect 8 0 5 0; #X connect 8 1 6 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/symbol.pd0000644000000000000000000000051400000000000017272 0ustar00#N canvas 779 41 226 111 10; #X obj 13 9 inlet; #X obj 13 53 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 49 inlet; #X obj 172 144 outlet; #X obj 259 42 inlet; #X restore 13 31 pd @hv_obj __var \$1; #X obj 124 9 inlet; #X text 13 74 @hv_arg \$1 k string "" false; #X connect 0 0 2 0; #X connect 2 0 1 0; #X connect 3 0 2 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/symbolatom.pd0000644000000000000000000000026300000000000020154 0ustar00#N canvas 172 200 211 99 10; #X obj 16 9 inlet; #X obj 16 55 outlet; #X obj 16 32 symbol \$1; #X text 14 74 @hv_arg \$1 k string "" false; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabosc4~.pd0000644000000000000000000000447100000000000017530 0ustar00#N canvas 117 51 500 497 10; #X obj 9 196 *~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 24 152 pd @hv_obj system; #X msg 24 130 table \$1 size; #N canvas 0 22 450 300 @hv_obj 0; #X obj 150 61 inlet; #X obj 147 118 outlet; #X restore 24 108 pd @hv_obj __var \$1; #X obj 9 431 outlet~; #X obj 24 359 -~; #X obj 52 359 -~; #X obj 24 383 *~; #X obj 9 406 +~; #X text 78 360 linear interpolation; #N canvas 0 22 450 300 @hv_obj 0; #X obj 160 52 inlet~; #X obj 173 97 outlet~; #X restore 9 233 pd @hv_obj __floor~f; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X restore 9 259 pd @hv_obj __cast~fi; #N canvas 0 23 450 300 @hv_obj 0; #X obj 232 43 inlet~; #X obj 169 185 outlet~; #X obj 165 46 inlet~; #X restore 180 288 pd @hv_obj __add~i; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 75 inlet; #X obj 175 149 outlet~; #X restore 285 266 pd @hv_obj __var_k~i 1; #X text 6 455 @hv_arg \$1 table string "" true; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 280 42 inlet; #X restore 180 310 pd @hv_obj __tabread~if \$1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 249 48 inlet; #X restore 9 310 pd @hv_obj __tabread~if \$1; #X obj 24 174 - 2; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 24 inlet; #X obj 221 83 outlet; #X obj 159 83 outlet; #X restore 162 29 pd @hv_obj __switchcase set; #N canvas 0 22 450 300 @hv_obj 0; #X obj 178 47 inlet; #X obj 165 128 outlet; #X restore 162 52 pd @hv_obj slice 1 1; #X obj 108 39 inlet; #X obj 24 85 loadbang -1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 170 45 inlet; #X obj 127 48 inlet; #X obj 138 82 outlet~; #X restore 9 62 pd @hv_obj phasor; #X obj 9 3 inlet -~>; #X connect 0 0 10 0; #X connect 0 0 6 0; #X connect 1 0 17 0; #X connect 2 0 1 0; #X connect 3 0 2 0; #X connect 5 0 7 0; #X connect 6 0 7 1; #X connect 7 0 8 1; #X connect 8 0 4 0; #X connect 10 0 6 1; #X connect 10 0 11 0; #X connect 11 0 16 0; #X connect 11 0 12 0; #X connect 12 0 15 0; #X connect 13 0 12 1; #X connect 15 0 5 0; #X connect 16 0 8 0; #X connect 16 0 5 1; #X connect 17 0 0 1; #X connect 18 0 19 0; #X connect 19 0 3 0; #X connect 19 0 16 1; #X connect 19 0 15 1; #X connect 20 0 22 1; #X connect 21 0 3 0; #X connect 22 0 0 0; #X connect 23 0 18 0; #X connect 23 0 22 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabplay~.pd0000644000000000000000000000337400000000000017626 0ustar00#N canvas 303 459 461 431 10; #X obj 41 351 outlet~; #X text 38 375 @hv_arg \$1 table string "" true; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 112 150 pd @hv_obj system; #X msg 112 128 table \$1 size; #N canvas 0 22 450 300 @hv_obj 0; #X obj 178 47 inlet; #X obj 165 128 outlet; #X restore 43 55 pd @hv_obj slice 1 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 150 61 inlet; #X obj 147 118 outlet; #X restore 112 106 pd @hv_obj __var \$1; #X obj 112 174 - 1; #X obj 112 80 loadbang -1; #N canvas 0 23 450 300 @hv_obj 1; #X obj 169 185 outlet~; #X obj 249 48 inlet; #X obj 165 46 inlet; #X obj 337 48 inlet; #X obj 306 185 outlet; #X obj 374 185 outlet; #X restore 41 327 pd @hv_obj __tabread_stoppable~f \$1; #X obj 42 7 inlet -->; #X obj 41 270 max 0; #X obj 41 297 min 0; #X msg 253 131 \$1; #X obj 248 358 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 24 inlet; #X obj 273 82 outlet; #X obj 159 83 outlet; #X obj 333 82 outlet; #X obj 212 82 outlet; #X restore 42 34 pd @hv_obj __switchcase set bang stop; #X obj 41 221 loadbang 0; #N canvas 1361 151 307 222 @hv_obj 0; #X obj 37 37 inlet; #X obj 40 90 outlet; #X restore 41 244 pd @hv_obj __var \$1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 178 47 inlet; #X obj 165 128 outlet; #X restore 287 132 pd @hv_obj slice 1 2; #X connect 2 0 6 0; #X connect 3 0 2 0; #X connect 4 0 8 1; #X connect 4 0 5 0; #X connect 5 0 3 0; #X connect 6 0 11 1; #X connect 7 0 5 0; #X connect 8 0 0 0; #X connect 8 2 13 0; #X connect 9 0 14 0; #X connect 10 0 11 0; #X connect 11 0 8 0; #X connect 12 0 16 0; #X connect 14 0 4 0; #X connect 14 1 16 0; #X connect 14 1 8 0; #X connect 14 2 8 0; #X connect 14 3 12 0; #X connect 14 3 17 0; #X connect 15 0 16 0; #X connect 16 0 10 0; #X connect 17 0 8 2; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabread.pd0000644000000000000000000000143400000000000017371 0ustar00#N canvas 451 572 294 338 10; #X obj 13 10 inlet -->; #X obj 64 272 outlet -->; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 52 inlet; #X obj 244 58 inlet; #X obj 189 127 outlet; #X restore 64 242 pd @hv_obj __tabread \$1; #X obj 13 32 route set; #X text 63 293 @hv_arg \$1 table string "" true; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 105 152 pd @hv_obj system; #X obj 64 92 max 0; #X obj 64 62 t f b; #X obj 105 92 symbol \$1; #X obj 64 212 min 0; #X msg 105 122 table \$1 length; #X obj 105 182 - 1; #X connect 0 0 3 0; #X connect 2 0 1 0; #X connect 3 0 2 1; #X connect 3 1 7 0; #X connect 5 0 11 0; #X connect 6 0 9 0; #X connect 7 0 6 0; #X connect 7 1 8 0; #X connect 8 0 10 0; #X connect 9 0 2 0; #X connect 10 0 5 0; #X connect 11 0 9 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabread4~.pd0000644000000000000000000000467600000000000017666 0ustar00#N canvas 75 23 584 478 10; #X obj 10 424 outlet~; #X obj 25 352 -~; #X obj 53 352 -~; #X obj 25 376 *~; #X obj 10 399 +~; #X text 79 353 linear interpolation; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X restore 10 252 pd @hv_obj __cast~fi; #N canvas 0 23 450 300 @hv_obj 0; #X obj 232 43 inlet~; #X obj 169 185 outlet~; #X obj 165 46 inlet~; #X restore 181 281 pd @hv_obj __add~i; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 75 inlet; #X obj 175 149 outlet~; #X restore 286 259 pd @hv_obj __var_k~i 1; #X text 7 448 @hv_arg \$1 table string "" true; #X obj 10 201 max~ 0; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 81 130 pd @hv_obj system; #X obj 10 178 min~; #X obj 81 154 - 2; #X text 52 201 the sample delay may not exceed the table boundaries ; #X msg 81 108 table \$1 size; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 280 42 inlet; #X restore 181 303 pd @hv_obj __tabread~if \$1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 249 48 inlet; #X restore 10 303 pd @hv_obj __tabread~if \$1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 24 inlet; #X obj 221 83 outlet; #X obj 159 83 outlet; #X restore 163 38 pd @hv_obj __switchcase set; #X text 162 7 NOTE(mhroth): there is supposed to be a control; #X text 161 20 connection from the left inlet to the switchcase; #N canvas 0 22 450 300 @hv_obj 0; #X obj 178 47 inlet; #X obj 165 128 outlet; #X restore 163 61 pd @hv_obj slice 1 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 150 61 inlet; #X obj 147 118 outlet; #X restore 81 86 pd @hv_obj __var \$1; #X obj 81 60 loadbang -1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 160 52 inlet~; #X obj 173 97 outlet~; #X restore 10 227 pd @hv_obj __floor~f; #X obj 328 79 inlet; #X text 327 60 a "fake" inlet to mimic onset messages; #X obj 10 154 inlet~ -~>; #X connect 1 0 3 0; #X connect 2 0 3 1; #X connect 3 0 4 1; #X connect 4 0 0 0; #X connect 6 0 17 0; #X connect 6 0 7 0; #X connect 7 0 16 0; #X connect 8 0 7 1; #X connect 10 0 2 0; #X connect 10 0 24 0; #X connect 11 0 13 0; #X connect 12 0 10 0; #X connect 13 0 12 1; #X connect 15 0 11 0; #X connect 16 0 1 0; #X connect 17 0 4 0; #X connect 17 0 1 1; #X connect 18 0 21 0; #X connect 21 0 16 1; #X connect 21 0 17 1; #X connect 21 0 22 0; #X connect 22 0 15 0; #X connect 23 0 22 0; #X connect 24 0 2 1; #X connect 24 0 6 0; #X connect 27 0 12 0; #X connect 27 0 18 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabread~.pd0000644000000000000000000000273100000000000017570 0ustar00#N canvas 672 216 463 321 10; #X obj 10 273 outlet~; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X restore 10 226 pd @hv_obj __cast~fi; #X text 7 297 @hv_arg \$1 table string "" true; #X obj 10 201 max~ 0; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 81 130 pd @hv_obj system; #X obj 10 178 min~; #X text 52 201 the sample delay may not exceed the table boundaries ; #X msg 81 108 table \$1 size; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 249 48 inlet; #X restore 10 249 pd @hv_obj __tabread~if \$1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 24 inlet; #X obj 221 83 outlet; #X obj 159 83 outlet; #X restore 163 38 pd @hv_obj __switchcase set; #X text 162 7 NOTE(mhroth): there is supposed to be a control; #X text 161 20 connection from the left inlet to the switchcase; #N canvas 0 22 450 300 @hv_obj 0; #X obj 178 47 inlet; #X obj 165 128 outlet; #X restore 163 61 pd @hv_obj slice 1 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 150 61 inlet; #X obj 147 118 outlet; #X restore 81 86 pd @hv_obj __var \$1; #X obj 81 154 - 1; #X obj 81 60 loadbang -1; #X obj 10 154 inlet~ -~>; #X connect 1 0 8 0; #X connect 3 0 1 0; #X connect 4 0 14 0; #X connect 5 0 3 0; #X connect 7 0 4 0; #X connect 8 0 0 0; #X connect 9 0 12 0; #X connect 12 0 8 1; #X connect 12 0 13 0; #X connect 13 0 7 0; #X connect 14 0 5 1; #X connect 15 0 13 0; #X connect 16 0 5 0; #X connect 16 0 9 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabwrite.pd0000644000000000000000000000067000000000000017611 0ustar00#N canvas 686 568 220 136 10; #X obj 12 13 inlet -->; #X obj 82 13 inlet -->; #X obj 12 84 outlet -->; #N canvas 0 22 450 300 @hv_obj 0; #X obj 142 59 inlet; #X obj 157 109 outlet; #X obj 257 62 inlet; #X obj 206 59 inlet; #X restore 12 62 pd @hv_obj __tabwrite \$1; #X obj 12 35 route set; #X text 12 105 @hv_arg \$1 table string "" true; #X connect 0 0 4 0; #X connect 1 0 3 1; #X connect 3 0 2 0; #X connect 4 0 3 2; #X connect 4 1 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tabwrite~.pd0000644000000000000000000000507300000000000020011 0ustar00#N canvas 536 160 472 533 10; #N canvas 107 52 450 300 @hv_obj 0; #X obj 145 102 inlet; #X obj 345 193 outlet; #X obj 236 180 outlet; #X obj 159 188 outlet; #X obj 291 186 outlet; #X restore 80 35 pd @hv_obj __switchcase start stop set; #N canvas 0 22 450 300 @hv_obj 0; #X obj 174 66 inlet; #X obj 176 154 outlet; #X obj 256 66 inlet; #X obj 316 65 inlet; #X restore 230 57 pd @hv_obj slice 1 1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 174 66 inlet; #X obj 193 152 outlet; #X obj 256 66 inlet; #X obj 316 65 inlet; #X obj 259 153 outlet; #X restore 80 57 pd @hv_obj slice 1 1; #X text 8 499 @hv_arg \$1 table string "" true; #N canvas 0 22 450 300 @hv_obj 0; #X obj 169 68 inlet; #X obj 273 67 inlet; #X obj 96 70 inlet~; #X restore 9 479 pd @hv_obj __tabwrite_stoppable~f \$1; #X text 234 479 tabwrite~ starts in stopped state; #X obj 320 296 / 1000; #X obj 305 318 /; #X msg 305 80 0; #X text 366 296 samples per ms; #X text 329 319 ms per sample; #N canvas 0 22 450 300 @hv_obj 0; #X obj 151 67 inlet; #X obj 174 161 outlet; #X restore 336 167 pd @hv_obj system; #X msg 336 143 table \$1 size; #X obj 305 187 -; #X obj 305 207 * -1; #X obj 305 340 t a a a; #X text 39 178 TODO(mhroth): deal with OOB indicies; #X msg 316 363 clear; #X msg 152 446 stop; #N canvas 0 22 450 300 @hv_obj 0; #X obj 198 56 inlet; #X obj 128 57 inlet; #X obj 137 128 outlet; #X restore 305 385 pd @hv_obj __delay; #X text 79 3 NOTE(mhroth): there is supposed to be a control; #X text 78 16 connection from the left inlet to the switchcase; #X msg 320 249 samplerate; #N canvas 0 22 450 300 @hv_obj 0; #X obj 119 57 inlet; #X obj 119 97 outlet; #X restore 320 273 pd @hv_obj system; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 49 inlet; #X obj 172 144 outlet; #X obj 259 42 inlet; #X restore 336 120 pd @hv_obj __var \$1; #X obj 336 97 loadbang; #X obj 320 226 loadbang; #X obj 164 420 loadbang; #X msg 197 81 0; #X obj 9 35 inlet~ -~>; #X connect 0 0 2 0; #X connect 0 1 18 0; #X connect 0 2 1 0; #X connect 0 3 8 0; #X connect 1 0 4 2; #X connect 1 0 24 0; #X connect 2 0 4 1; #X connect 2 0 13 0; #X connect 2 1 28 0; #X connect 6 0 7 1; #X connect 7 0 15 0; #X connect 8 0 4 1; #X connect 8 0 13 0; #X connect 11 0 13 1; #X connect 12 0 11 0; #X connect 13 0 14 0; #X connect 14 0 7 0; #X connect 15 0 19 0; #X connect 15 1 19 1; #X connect 15 2 17 0; #X connect 17 0 19 0; #X connect 18 0 4 1; #X connect 19 0 18 0; #X connect 22 0 23 0; #X connect 23 0 6 0; #X connect 24 0 12 0; #X connect 25 0 24 0; #X connect 26 0 22 0; #X connect 27 0 18 0; #X connect 28 0 4 1; #X connect 28 0 13 0; #X connect 29 0 4 0; #X connect 29 0 0 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tan.pd0000644000000000000000000000033500000000000016550 0ustar00#N canvas 439 480 151 128 10; #X obj 13 20 inlet; #X obj 13 80 outlet; #N canvas 0 22 183 125 @hv_obj 0; #X obj 19 24 inlet; #X obj 19 66 outlet; #X restore 13 50 pd @hv_obj __tan; #X connect 0 0 2 0; #X connect 2 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/tgl.pd0000644000000000000000000000027400000000000016556 0ustar00#N canvas 409 120 143 157 10; #X obj 32 32 inlet; #X obj 71 64 == 0; #X obj 32 96 outlet; #X obj 32 64 f 1; #X connect 0 0 3 0; #X connect 1 0 3 1; #X connect 3 0 1 0; #X connect 3 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/timer.pd0000644000000000000000000000154500000000000017112 0ustar00#N canvas 192 130 288 304 10; #X obj 24 23 inlet, f 6; #X obj 136 23 inlet; #X obj 83 272 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 145 62 inlet; #X obj 150 127 outlet; #X restore 24 115 pd @hv_obj system; #X msg 24 85 currentTime; #X obj 82 161 -; #N canvas 0 22 450 300 @hv_obj 0; #X obj 145 62 inlet; #X obj 150 127 outlet; #X restore 136 115 pd @hv_obj system; #X msg 136 85 currentTime; #X obj 83 247 /; #X obj 136 53 t a a; #N canvas 0 22 450 300 @hv_obj 0; #X obj 145 62 inlet; #X obj 150 127 outlet; #X restore 163 177 pd @hv_obj system; #X msg 163 147 samplerate; #X obj 163 207 / 1000; #X connect 0 0 4 0; #X connect 1 0 9 0; #X connect 3 0 5 1; #X connect 4 0 3 0; #X connect 5 0 8 0; #X connect 6 0 5 0; #X connect 7 0 6 0; #X connect 8 0 2 0; #X connect 9 0 7 0; #X connect 9 1 11 0; #X connect 10 0 12 0; #X connect 11 0 10 0; #X connect 12 0 8 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/touchin.pd0000644000000000000000000000155300000000000017442 0ustar00#N canvas 114 229 459 438 10; #X obj 209 337 outlet; #X obj 152 76 unpack f f; #X obj 50 334 outlet; #X obj 83 104 loadbang; #X obj 83 174 == 0; #X obj 83 128 i \$1; #X obj 50 266 spigot; #X obj 209 101 + 1; #X obj 209 236 spigot; #X obj 215 175 ==; #X obj 152 237 spigot; #X obj 215 200 t f f; #X obj 209 313 max 1; #X obj 83 197 t f f; #X obj 150 270 spigot; #X obj 152 47 r __hv_touchin; #X text 226 78 pressure value and channel/port; #X connect 1 0 10 0; #X connect 1 0 6 0; #X connect 1 1 7 0; #X connect 3 0 5 0; #X connect 4 0 13 0; #X connect 5 0 4 0; #X connect 5 0 9 1; #X connect 6 0 2 0; #X connect 7 0 9 0; #X connect 7 0 14 0; #X connect 7 0 8 0; #X connect 8 0 12 0; #X connect 9 0 11 0; #X connect 10 0 2 0; #X connect 11 0 10 1; #X connect 11 1 8 1; #X connect 12 0 0 0; #X connect 13 0 6 1; #X connect 13 1 14 1; #X connect 14 0 12 0; #X connect 15 0 1 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/touchout.pd0000644000000000000000000000056500000000000017645 0ustar00#N canvas 860 405 231 322 10; #X obj 52 215 pack f f; #X obj 97 74 inlet channel; #X obj 97 146 f \$1; #X obj 114 106 loadbang; #X obj 52 40 inlet touch; #X obj 52 247 s __hv_touchout @hv_param; #X obj 97 168 - 1; #X obj 97 191 max; #X connect 0 0 5 0; #X connect 1 0 2 0; #X connect 2 0 6 0; #X connect 3 0 2 0; #X connect 4 0 0 0; #X connect 6 0 7 0; #X connect 7 0 0 1; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/until.pd0000644000000000000000000000166200000000000017125 0ustar00#N canvas 121 411 250 478 10; #X obj 39 26 inlet; #X obj 78 236 t f f; #X obj 78 296 spigot 0; #X obj 123 266 <; #X obj 78 206 f; #X obj 125 167 + 1; #X obj 105 357 outlet; #X obj 39 106 moses 1; #X obj 39 76 int; #X obj 78 326 t f b; #X obj 170 24 inlet; #X msg 170 76 0; #X obj 39 48 t f b; #X msg 66 76 1; #X obj 125 136 spigot 1; #X msg 39 394 input needs to be >= 1; #X obj 39 424 print (heavy) until error; #X obj 78 167 f 0; #X obj 78 136 t b f; #X connect 0 0 12 0; #X connect 1 0 2 0; #X connect 1 1 3 0; #X connect 2 0 9 0; #X connect 3 0 2 1; #X connect 4 0 1 0; #X connect 5 0 4 0; #X connect 7 0 15 0; #X connect 7 1 18 0; #X connect 8 0 7 0; #X connect 9 0 14 0; #X connect 9 1 6 0; #X connect 10 0 11 0; #X connect 11 0 14 1; #X connect 12 0 8 0; #X connect 12 1 13 0; #X connect 13 0 14 1; #X connect 14 0 5 0; #X connect 15 0 16 0; #X connect 17 0 4 0; #X connect 18 0 17 0; #X connect 18 1 3 1; #X coords 0 478 1 477 111 106 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/vcf~.pd0000644000000000000000000000522500000000000016745 0ustar00#N canvas 830 72 440 622 10; #X obj 96 11 inlet~ f; #X obj 260 11 inlet q; #X msg 361 189 1 \$1; #X obj 361 212 /; #X text 384 213 invq; #X obj 260 147 + 2; #X msg 260 168 2 \$1; #X obj 260 189 /; #X msg 260 212 2 \$1; #X obj 260 234 -; #X text 284 235 ampcorrect; #X obj 144 103 samplerate~; #X obj 112 143 /; #X obj 97 166 *~; #X obj 97 372 *~; #X obj 112 403 sig~ 1; #X obj 97 433 -~; #X obj 136 566 outlet~; #X obj 19 566 outlet~; #X msg 112 123 6.28319 \$1; #X obj 19 419 *~; #X obj 19 455 *~; #X obj 97 496 *~; #X obj 224 482 *~; #X obj 254 397 *~; #X obj 239 437 -~; #X obj 239 458 sqrt~; #X text 277 457 sin; #N canvas 0 23 450 300 @hv_obj 0; #X obj 188 51 inlet~; #X obj 135 50 inlet~; #X obj 209 193 outlet~; #X obj 290 50 inlet~; #X obj 235 50 inlet~; #X obj 137 192 outlet~; #X obj 146 125 cpole~; #X obj 235 72 *~ -1; #X obj 291 72 *~ -1; #X connect 0 0 6 1; #X connect 1 0 6 0; #X connect 3 0 8 0; #X connect 4 0 7 0; #X connect 6 0 5 0; #X connect 6 1 2 0; #X connect 7 0 6 2; #X connect 8 0 6 3; #X restore 19 543 pd @hv_obj __cpole~f; #X text 125 431 -r = cf*qinv-1; #X text 122 495 -coefr; #X text 251 482 -coefi; #X obj 260 53 f \$1; #X obj 171 11 loadbang; #N canvas 0 23 450 300 @hv_obj 0; #X obj 131 90 inlet~; #X obj 131 156 cos~; #X obj 131 177 outlet~; #X obj 131 126 /~ 6.28319; #X connect 0 0 3 0; #X connect 1 0 2 0; #X connect 3 0 1 0; #X restore 254 368 pd @hv_obj __cos~f; #X obj 19 11 inlet~ in; #X msg 260 119 0; #X obj 361 235 t a; #X obj 171 32 t a a; #X obj 97 329 min~; #X msg 231 119 -1; #X text 125 372 oneminusr = cf*qinv; #X obj 260 76 moses 1e-05; #X text 333 90 > 0; #X text 147 246 cf [1e-05 \, pi]; #X obj 97 247 max~ 1e-05; #X connect 0 0 13 0; #X connect 1 0 32 0; #X connect 2 0 3 0; #X connect 3 0 37 0; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 7 0 8 0; #X connect 8 0 9 0; #X connect 9 0 21 1; #X connect 11 0 19 0; #X connect 12 0 13 1; #X connect 13 0 45 0; #X connect 14 0 20 1; #X connect 14 0 16 0; #X connect 15 0 16 1; #X connect 15 0 25 0; #X connect 16 0 22 0; #X connect 16 0 23 0; #X connect 19 0 12 0; #X connect 20 0 21 0; #X connect 21 0 28 0; #X connect 22 0 28 2; #X connect 23 0 28 3; #X connect 24 0 25 1; #X connect 25 0 26 0; #X connect 26 0 23 1; #X connect 28 0 18 0; #X connect 28 1 17 0; #X connect 32 0 42 0; #X connect 33 0 38 0; #X connect 34 0 24 0; #X connect 34 0 24 1; #X connect 34 0 22 1; #X connect 35 0 20 0; #X connect 36 0 5 0; #X connect 37 0 14 1; #X connect 38 0 32 0; #X connect 38 1 11 0; #X connect 39 0 14 0; #X connect 40 0 39 1; #X connect 40 0 14 1; #X connect 42 0 36 0; #X connect 42 0 40 0; #X connect 42 1 2 0; #X connect 42 1 5 0; #X connect 42 1 39 1; #X connect 45 0 39 0; #X connect 45 0 34 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/vd~.pd0000644000000000000000000000641400000000000016601 0ustar00#N canvas 859 23 532 664 10; #X obj 19 26 inlet~; #X obj 4 638 outlet~; #X obj 19 163 *~; #X obj 34 116 samplerate~; #X text 79 140 convert millisecond delay to sample delay; #N canvas 0 22 450 300 @hv_obj 0; #X obj 146 77 inlet; #X obj 147 120 outlet; #X restore 95 93 pd @hv_obj system; #X obj 4 302 -~; #X obj 4 409 +~; #X text 33 301 table index; #X obj 19 565 -~; #X obj 47 565 -~; #X obj 19 589 *~; #X obj 4 613 +~; #X text 73 566 linear interpolation; #N canvas 587 66 450 300 @hv_obj 0; #X obj 146 106 inlet~; #X obj 154 156 outlet~; #X obj 239 103 inlet~; #X restore 35 385 pd @hv_obj __and~f; #X obj 4 279 +~; #X obj 68 26 t a a; #N canvas 587 66 450 300 @hv_obj 0; #X obj 221 104 inlet~; #X obj 154 156 outlet~; #X obj 146 106 inlet~; #X restore 150 363 pd @hv_obj __lt~f; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X restore 4 438 pd @hv_obj __cast~fi; #N canvas 0 23 450 300 @hv_obj 0; #X obj 232 43 inlet~; #X obj 169 185 outlet~; #X obj 165 46 inlet~; #X restore 195 478 pd @hv_obj __add~i; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 75 inlet; #X obj 175 149 outlet~; #X restore 300 456 pd @hv_obj __var_k~i 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 173 75 inlet; #X obj 175 149 outlet~; #X restore 249 341 pd @hv_obj __var_k~f 0; #X obj 95 49 symbol del-\$1; #X obj 34 139 / 1000; #N canvas 587 66 450 300 @hv_obj 0; #X obj 154 156 outlet~; #X obj 146 106 inlet; #X restore 4 234 pd @hv_obj __tabhead~f del-\$1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 280 42 inlet; #X restore 195 501 pd @hv_obj __tabread~if del-\$1; #N canvas 0 23 450 300 @hv_obj 0; #X obj 165 46 inlet~; #X obj 169 185 outlet~; #X obj 249 48 inlet; #X restore 4 501 pd @hv_obj __tabread~if del-\$1; #X text 182 49 @hv_arg \$1 table string "" true; #N canvas 0 22 450 300 @hv_obj 0; #X obj 148 99 inlet; #X obj 143 158 outlet~; #X restore 27 257 pd @hv_obj __var_k~f -1 -1 true; #X obj 68 4 loadbang -1; #X msg 95 71 table \$1 size; #X text 150 430 NOTE(mhroth): SSE cast op seems to round to the nearest int \, not down; #X obj 19 210 max~ 0; #X obj 19 188 min~; #X text 70 202 [0 \, size-1]; #X text 71 187 ensure that the input never exceeds the table bounds ; #X obj 45 163 - 1; #N canvas 0 22 450 300 @hv_obj 0; #X obj 160 52 inlet~; #X obj 173 97 outlet~; #X restore 4 331 pd @hv_obj __floor~f; #X text 30 412 wrapped table index; #N canvas 0 22 450 300 @hv_obj 0; #X obj 148 99 inlet; #X obj 143 158 outlet~; #X restore 35 362 pd @hv_obj var; #X connect 0 0 2 0; #X connect 2 0 33 0; #X connect 3 0 23 0; #X connect 5 0 36 0; #X connect 5 0 39 0; #X connect 6 0 37 0; #X connect 6 0 10 0; #X connect 7 0 18 0; #X connect 9 0 11 0; #X connect 10 0 11 1; #X connect 11 0 12 1; #X connect 12 0 1 0; #X connect 14 0 7 1; #X connect 15 0 6 0; #X connect 16 0 3 0; #X connect 16 1 22 0; #X connect 17 0 14 1; #X connect 18 0 26 0; #X connect 18 0 19 0; #X connect 19 0 25 0; #X connect 20 0 19 1; #X connect 21 0 17 1; #X connect 22 0 30 0; #X connect 23 0 2 1; #X connect 24 0 15 0; #X connect 25 0 9 0; #X connect 26 0 9 1; #X connect 26 0 12 0; #X connect 28 0 15 1; #X connect 29 0 16 0; #X connect 30 0 5 0; #X connect 32 0 6 1; #X connect 33 0 32 0; #X connect 36 0 33 1; #X connect 37 0 17 0; #X connect 37 0 10 1; #X connect 37 0 7 0; #X connect 39 0 14 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/vradio.pd0000644000000000000000000000020300000000000017244 0ustar00#N canvas 0 149 210 157 10; #X obj 24 35 inlet; #X obj 24 57 float 0; #X obj 24 79 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/vsl.pd0000644000000000000000000000020300000000000016564 0ustar00#N canvas 0 149 210 157 10; #X obj 24 35 inlet; #X obj 24 57 float 0; #X obj 24 79 outlet; #X connect 0 0 1 0; #X connect 1 0 2 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/wrap.pd0000644000000000000000000000076100000000000016742 0ustar00#N canvas 525 135 222 227 10; #X obj 39 30 inlet; #X obj 39 150 -; #X obj 39 180 outlet; #N canvas 0 22 450 300 @hv_obj 0; #X obj 118 64 inlet; #X obj 118 86 outlet; #X connect 0 0 1 0; #X restore 66 120 pd @hv_obj __floor; #X obj 39 90 t a a; #N canvas 0 22 450 300 @hv_obj 0; #X obj 87 75 inlet; #X obj 87 97 outlet; #X connect 0 0 1 0; #X restore 39 60 pd @hv_obj __cast_f; #X connect 0 0 5 0; #X connect 1 0 2 0; #X connect 3 0 1 1; #X connect 4 0 1 0; #X connect 4 1 3 0; #X connect 5 0 4 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/libs/pd/wrap~.pd0000644000000000000000000000044000000000000017132 0ustar00#N canvas 525 135 213 168 10; #X obj 29 26 inlet~; #N canvas 0 22 450 300 @hv_obj 0; #X obj 69 171 outlet~; #X obj 69 82 inlet~; #X restore 44 56 pd @hv_obj __floor~f; #X obj 29 86 -~; #X obj 29 116 outlet~; #X connect 0 0 1 0; #X connect 0 0 2 0; #X connect 1 0 2 1; #X connect 2 0 3 0; hvcc-0.16.0/hvcc/interpreters/pd2hv/pd2hv.py0000644000000000000000000001110100000000000015473 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2023-2026 Wasted Audio # # 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 . import argparse import json import time from typing import List, Optional from pathlib import Path from hvcc.interpreters.pd2hv.PdParser import PdParser from hvcc.types.compiler import CompilerResp, CompilerNotif from .PdGraph import PdGraph class Colours: purple = "\033[95m" cyan = "\033[96m" dark_cyan = "\033[36m" blue = "\033[94m" green = "\033[92m" yellow = "\033[93m" red = "\033[91m" bold = "\033[1m" underline = "\033[4m" end = "\033[0m" class pd2hv: @classmethod def get_supported_objects(cls) -> List: return PdParser.get_supported_objects() @classmethod def compile( cls, pd_path: Path, hv_dir: Path, search_paths: Optional[List] = None, verbose: bool = False, export_args: bool = False ) -> CompilerResp: tick = time.time() parser = PdParser() # create parser state if search_paths is not None: for p in search_paths: parser.add_absolute_search_directory(p) pd_graph: PdGraph = parser.graph_from_file(pd_path) notices = pd_graph.get_notices() # check for errors if len(notices.errors) > 0: return CompilerResp( stage="pd2hv", obj_counter=parser.obj_counter, notifs=CompilerNotif( has_error=True, errors=notices.errors, warnings=notices.warnings ), in_dir=pd_path.parent, in_file=pd_path, compile_time=(time.time() - tick) ) if not hv_dir.exists(): hv_dir.mkdir(parents=True) hv_file = f"{pd_path.stem}.hv.json" hv_path = Path(hv_dir, hv_file) with open(hv_path, "w") as f: json.dump(pd_graph.to_hv(export_args=export_args), f, indent=4) return CompilerResp( stage="pd2hv", obj_counter=parser.obj_counter, notifs=CompilerNotif( warnings=notices.warnings ), in_dir=pd_path.parent, in_file=pd_path, out_dir=hv_dir, out_file=Path(hv_file), compile_time=(time.time() - tick) ) def main() -> None: parser = argparse.ArgumentParser( description="Converts a Pd patch into the Heavy language format.") parser.add_argument( "pd_path", help="The Pd patch to convert to Heavy.") parser.add_argument( "hv_dir", help="Directory to store generated Heavy patches.") parser.add_argument( "--export", help="Export Heavy arguments. Use this to make precompiled patches.", action="count") parser.add_argument( "-v", "--verbose", help="Show debugging information.", action="count") args = parser.parse_args() args.pd_path = Path(args.pd_path).expanduser().absolute() args.hv_dir = Path(args.hv_dir).expanduser().absolute() result = pd2hv.compile( pd_path=args.pd_path, hv_dir=args.hv_dir, search_paths=None, verbose=args.verbose, export_args=args.export) for i, n in enumerate(result.notifs.errors): print("{0:3d}) {1}Error #{2:4d}:{3} {4}".format( i + 1, Colours.red, n.enum, Colours.end, n.message)) for i, n in enumerate(result.notifs.warnings): print("{0:3d}) {1}Warning #{2:4d}:{3} {4}".format( i + 1, Colours.yellow, n.enum, Colours.end, n.message)) if args.verbose: if len(result.notifs.errors) == 0: print("Heavy file written to", Path(result.out_dir, result.out_file)) print("Total pd2hv compile time: {0:.2f}ms".format(result.compile_time * 1000)) if __name__ == "__main__": main() hvcc-0.16.0/hvcc/main.py0000644000000000000000000001227700000000000011642 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # Copyright (C) 2021-2026 Wasted Audio # # 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 . import argparse import json import sys import time from pathlib import Path from hvcc.version import VERSION from hvcc.compiler import compile_dataflow class Colours: purple = "\033[95m" cyan = "\033[96m" dark_cyan = "\033[36m" blue = "\033[94m" green = "\033[92m" yellow = "\033[93m" red = "\033[91m" bold = "\033[1m" underline = "\033[4m" end = "\033[0m" def main() -> bool: tick = time.time() parser = argparse.ArgumentParser( description="This is the Wasted Audio Heavy compiler. It compiles supported dataflow languages into C," " and other supported frameworks.") parser.add_argument( "in_path", help="The input dataflow file.") parser.add_argument( "-o", "--out_dir", help="Build output path.") parser.add_argument( "-p", "--search_paths", nargs="+", default=[], help="Add a list of directories to search through for abstractions.") parser.add_argument( "-n", "--name", default="heavy", help="Provides a name for the generated Heavy context.") parser.add_argument( "-m", "--meta", help="Provide metadata file (json) for generator") parser.add_argument( "-g", "--gen", nargs="+", default=["c"], help="List of generator outputs: c, daisy, dpf, js, owl, pdext, unity, wwise.") parser.add_argument( "-G", "--ext-gen", nargs="*", help="Name of a Python module that implements a generator, see 'External Generators' docs page.") parser.add_argument( "--results_path", help="Write results dictionary to the given path as a JSON-formatted string." " Target directory will be created if it does not exist.") parser.add_argument( "--nodsp", action='store_true', help="Disable DSP. Run as control-only patch." ) parser.add_argument( "--gui", action='store_true', help="Parse GUI objects into IR." ) parser.add_argument( "-v", "--verbose", help="Show debugging information.", action="count") parser.add_argument( "--copyright", help="A string indicating the owner of the copyright.") parser.add_argument( "-V", "--version", action='version', help="Print version and exit.", version=VERSION ) args = parser.parse_args() in_path = Path(args.in_path).absolute() results = compile_dataflow( in_path=in_path, out_dir=Path(args.out_dir) if args.out_dir is not None else in_path.parent, patch_name=args.name, patch_meta_file=Path(args.meta) if args.meta is not None else Path(), search_paths=[Path(path) for path in args.search_paths], generators=args.gen, ext_generators=args.ext_gen, verbose=args.verbose, copyright=args.copyright, nodsp=args.nodsp, gui=args.gui ) errorCount = 0 for r in list(results.root.values()): # print any errors if r.notifs.has_error: for i, error in enumerate(r.notifs.errors): errorCount += 1 print("{4:3d}) {2}Error{3} {0}: {1}".format( r.stage, error.message, Colours.red, Colours.end, i + 1)) # only print exception if no errors are indicated if len(r.notifs.errors) == 0 and r.notifs.exception is not None: errorCount += 1 print("{2}Error{3} {0} exception: {1}".format( r.stage, r.notifs.exception, Colours.red, Colours.end)) # clear any exceptions such that results can be JSONified if necessary r.notifs.exception = None # print any warnings for i, warning in enumerate(r.notifs.warnings): print("{4:3d}) {2}Warning{3} {0}: {1}".format( r.stage, warning.message, Colours.yellow, Colours.end, i + 1)) if args.results_path: results_path = Path(args.results_path).absolute().resolve() results_dir = results_path.parent if not results_dir.exists(): results_dir.mkdir(parents=True) with open(results_path, "w") as f: json.dump(results.model_dump(), f) if args.verbose: print("Total compile time: {0:.2f}ms".format(1000 * (time.time() - tick))) return errorCount != 0 if __name__ == "__main__": ret = main() sys.exit(ret) hvcc-0.16.0/hvcc/types/GUI.py0000644000000000000000000000672300000000000012505 0ustar00# Heavy Compiler Collection # Copyright (C) 2025-2026 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only from enum import IntEnum from typing import Literal, Optional, Union from pydantic import BaseModel from pydantic_extra_types.color import Color from hvcc.version import VERSION class Coords(BaseModel): x: int = 0 y: int = 0 class Size(BaseModel): x: int = 0 y: int = 0 class Font(IntEnum): courier = 0 helvetica = 1 times = 2 class LabelShow(IntEnum): never = 0 always = 1 active = 2 typing = 3 class LabelPos(IntEnum): left = 0 right = 1 top = 2 bottom = 3 class Base(BaseModel): type: str position: Coords size: Size class BaseUI(Base): id: str = "" class BaseParam(Base): parameter: str class Label(BaseModel): text: str position: Coords color: Color font: Font font_size: int class Comment(BaseUI): type: Literal["comment"] = "comment" text: str width: Optional[int] = 0 class Canvas(BaseUI): type: Literal["canvas"] = "canvas" label: Optional[Label] = None bg_color: Color class Bang(BaseParam): type: Literal["bang"] = "bang" label: Optional[Label] = None flash_time: int fg_color: Color bg_color: Color class Toggle(BaseParam): type: Literal["toggle"] = "toggle" label: Optional[Label] = None fg_color: Color bg_color: Color non_zero: float class Radio(BaseParam): label: Optional[Label] = None fg_color: Color bg_color: Color options: int class VRadio(Radio): type: Literal["vradio"] = "vradio" class HRadio(Radio): type: Literal["hradio"] = "hradio" class Slider(BaseParam): label: Optional[Label] = None min: float max: float fg_color: Color bg_color: Color logarithmic: bool steady: bool class VSlider(Slider): type: Literal["vslider"] = "vslider" class HSlider(Slider): type: Literal["hslider"] = "hslider" class Knob(BaseParam): type: Literal["knob"] = "knob" label_size: int label_pos: Coords label_show: LabelShow min: float max: float fg_color: Color bg_color: Color init_val: float ang_range: int ang_offset: int log_mode: Literal["lin", "log", "exp"] exp_fact: float discrete: bool ticks: bool steps: int circular: bool jump: bool square: bool arc_color: Color arc_start: float arc_show: bool class Number(BaseParam): type: Literal["number"] = "number" label: Optional[Label] = None fg_color: Color bg_color: Color log_mode: bool log_height: int min: float max: float class Float(BaseParam): type: Literal["float"] = "float" font_height: int label_text: str label_pos: LabelPos min: float max: float GUIObjects = Union[Bang, Toggle, Radio, Slider, Knob, Number, Float, Comment, Canvas] class Theme(BaseModel): obj_corner_radius: Optional[float] = None cnv_color: Optional[Color] = None text_color: Optional[Color] = None io_color: Optional[Color] = None bg_color: Optional[Color] = None sel_color: Optional[Color] = None out_color: Optional[Color] = None class GraphBase(BaseModel): id: str = "mainPatch" objects: list[GUIObjects] graphs: list["Graph"] class Graph(GraphBase): position: Coords gop_start: Coords gop_size: Size class GraphRoot(GraphBase): size: Size theme: Optional[Theme] = Theme() version: str = VERSION hvcc-0.16.0/hvcc/types/IR.py0000644000000000000000000000573400000000000012374 0ustar00# Heavy Compiler Collection # Copyright (C) 2024 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only from pydantic import BaseModel, RootModel from typing import Dict, List, Optional, Union from hvcc.types.Lang import LangLetType from hvcc.version import VERSION # IR Object Definitions IRValue = Union[float, int, str, List[float], List[int]] class IRArg(BaseModel): name: str value_type: str description: str = "" default: Optional[IRValue] = None required: bool class IR(BaseModel): control: bool signal: bool init: bool class Perf(BaseModel): avx: float = 0 sse: float = 0 neon: float = 0 class IRNode(BaseModel): inlets: List[LangLetType] ir: IR outlets: List[LangLetType] args: List[IRArg] = [] perf: Optional[Perf] = Perf() # perf: Perf description: Optional[str] = None alias: List[str] = [] tags: List[str] = [] keywords: List[str] = [] class HeavyIRType(RootModel): root: Dict[str, IRNode] # IR Graph Definitions class IRName(BaseModel): escaped: str display: str class IRObjectdict(BaseModel): args: Dict type: str class IRInit(BaseModel): order: List[str] = [] class IRReceiver(BaseModel): display: str hash: str extern: Optional[str] = None attributes: Dict ids: List[str] class IROnMessage(BaseModel): id: str inletIndex: Optional[int] = None class IRSendMessage(BaseModel): """ This object is a mess and should be split up """ id: str onMessage: List[List[IROnMessage]] # TODO: why is it a nested List? type: Optional[str] = None extern: Optional[str] = '' attributes: Optional[Union[List, Dict]] = None # TODO: List from IR and Dict from Lang hash: Optional[str] = None display: Optional[str] = None name: str = '' class IRTable(BaseModel): id: str display: str hash: str extern: Optional[bool] = None class IRControl(BaseModel): receivers: Dict[str, IRReceiver] sendMessage: List[IRSendMessage] class IRNumTempBuffer(BaseModel): float: int integer: int class IRBuffer(BaseModel): type: str index: int class IRSignalList(BaseModel): id: str inputBuffers: List[IRBuffer] outputBuffers: List[IRBuffer] class IRSignal(BaseModel): numInputBuffers: int numOutputBuffers: int numTemporaryBuffers: IRNumTempBuffer processOrder: List[IRSignalList] class IRGraph(BaseModel): version: str = VERSION name: IRName objects: Dict[str, IRObjectdict] = {} init: IRInit tables: Dict[str, IRTable] = {} control: IRControl signal: IRSignal if __name__ == "__main__": """ Test object definitions """ import json from importlib import resources from pathlib import Path heavy_ir_json = str(resources.files('hvcc') / 'core/json/heavy.ir.json') with open(Path(heavy_ir_json), "r") as f: data = json.load(f) heavy_ir = HeavyIRType(root=data) print(heavy_ir.root.keys()) hvcc-0.16.0/hvcc/types/Lang.py0000644000000000000000000000242200000000000012732 0ustar00# Heavy Compiler Collection # Copyright (C) 2024 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only from pydantic import BaseModel, RootModel from typing import List, Optional, Dict, Literal, Union LangConnectionType = Literal["-->", "-~>", "~f>"] LangLetType = Literal["-->", "-~>", "~i>", "~f>", "signal"] LangValueType = Literal["float", "int", "string", "bool", "dict", "floatarray", "intarray", "stringarray"] class LangArg(BaseModel): name: str value_type: Optional[LangValueType] = None description: str default: Union[float, int, str, Dict, List, None] = None required: bool class LangLet(BaseModel): name: str connectionType: LangConnectionType description: str class LangNode(BaseModel): description: str inlets: List[LangLet] outlets: List[LangLet] args: List[LangArg] alias: List[str] tags: List[str] class HeavyLangType(RootModel): root: Dict[str, LangNode] if __name__ == "__main__": import json from importlib import resources from pathlib import Path heavy_lang_json = str(resources.files('hvcc') / 'core/json/heavy.lang.json') with open(Path(heavy_lang_json), "r") as f: data = json.load(f) heavy_lang = HeavyLangType(root=data) print(heavy_lang.root.keys()) hvcc-0.16.0/hvcc/types/__.init__.py0000644000000000000000000000000000000000000013654 0ustar00hvcc-0.16.0/hvcc/types/compiler.py0000644000000000000000000000453600000000000013673 0ustar00# Heavy Compiler Collection # Copyright (C) 2024-2026 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only from abc import ABC, abstractmethod from collections import Counter, defaultdict from typing import Dict, List, Optional, Tuple from pathlib import Path from pydantic import BaseModel, RootModel from hvcc.interpreters.pd2hv.NotificationEnum import NotificationEnum from hvcc.types.meta import Meta from hvcc.types.IR import IRGraph, IRReceiver, IRSendMessage, IRTable class CompilerMsg(BaseModel): enum: NotificationEnum = NotificationEnum.EMPTY message: str class CompilerNotif(BaseModel, arbitrary_types_allowed=True): has_error: bool = False exception: Optional[Exception] = None warnings: List[CompilerMsg] = [] errors: List[CompilerMsg] = [] class CompilerResp(BaseModel): stage: str notifs: CompilerNotif = CompilerNotif() in_dir: Path = Path() in_file: Path = Path() out_dir: Path = Path() out_file: Path = Path() compile_time: float = 0.0 obj_counter: Counter = Counter() obj_perf: Dict[str, Dict[str, float]] = defaultdict(lambda: defaultdict(float)) ir: Optional[IRGraph] = None class CompilerResults(RootModel): root: Dict[str, CompilerResp] class ExternParams(BaseModel): inParam: List[Tuple[str, IRReceiver]] = [] outParam: List[Tuple[str, IRSendMessage]] = [] class ExternEvents(BaseModel): inEvent: List[Tuple[str, IRReceiver]] = [] outEvent: List[Tuple[str, IRSendMessage]] = [] class ExternMidi(BaseModel): inMidi: List[str] = [] outMidi: List[str] = [] class ExternMemoryPool(BaseModel): internal: int = 0 inputQueue: int = 0 outputQueue: int = 0 class ExternInfo(BaseModel): parameters: ExternParams = ExternParams() events: ExternEvents = ExternEvents() midi: ExternMidi = ExternMidi() tables: List[Tuple[str, IRTable]] = [] memoryPoolSizesKb: ExternMemoryPool = ExternMemoryPool() class Generator(ABC): @classmethod @abstractmethod def compile( cls, c_src_dir: Path, out_dir: Path, externs: ExternInfo, patch_name: str, patch_meta: Meta = Meta(), num_input_channels: int = 0, num_output_channels: int = 0, copyright: Optional[str] = None, verbose: Optional[bool] = False ) -> CompilerResp: raise NotImplementedError hvcc-0.16.0/hvcc/types/meta.py0000644000000000000000000000540000000000000012776 0ustar00# Heavy Compiler Collection # Copyright (C) 2024 Wasted Audio # # SPDX-License-Identifier: GPL-3.0-only from enum import IntEnum from typing import Dict, Literal, List, Optional, Tuple, Union from typing_extensions import Self from pydantic import BaseModel, HttpUrl, model_validator DaisyBoards = Literal['pod', 'petal', 'patch', 'patch_init', 'field'] DaisyBootloader = Literal['BOOT_NONE', 'BOOT_SRAM', 'BOOT_QSPI'] DPFFormats = Literal['lv2', 'lv2_sep', 'vst2', 'vst3', 'clap', 'jack', 'dssi', 'ladspa', 'au'] class Daisy(BaseModel): board: DaisyBoards = 'pod' board_file: Optional[str] = None libdaisy_path: Union[str, int] = 2 usb_midi: bool = False debug_printing: bool = False samplerate: int = 48000 blocksize: Optional[int] = None linker_script: str = '' bootloader: Optional[DaisyBootloader] = None class DPFUISize(BaseModel): width: int height: int class DPFUIType(IntEnum): NONE = 0 IMGUI = 1 NANOVG = 2 class DPFPortGroups(BaseModel): input: Dict[str, Dict[str, Union[int, Tuple[int, bool]]]] = {} output: Dict[str, Dict[str, Union[int, Tuple[int, bool]]]] = {} class DPF(BaseModel): dpf_path: str = "" description: Optional[str] = None makefile_dep: List[str] = [] enable_ui: Optional[DPFUIType] = DPFUIType.NONE enable_modgui: bool = False ui_size: Optional[DPFUISize] = None midi_input: bool = False midi_output: bool = False port_groups: Optional[DPFPortGroups] = None enumerators: Optional[Dict[str, List[str]]] = None denormals: bool = True version: Optional[str] = None license: Optional[str] = None maker: Optional[str] = None brand_id: Optional[str] = None brand_id_no_vst3: Optional[bool] = False unique_id: Optional[str] = None homepage: Optional[HttpUrl] = None plugin_uri: Optional[str] = None plugin_clap_id: Optional[str] = None plugin_formats: List[DPFFormats] = [] lv2_info: Optional[str] = None vst3_info: Optional[str] = None clap_info: List[str] = [] @model_validator(mode='after') def au_required(self) -> Self: if 'au' in self.plugin_formats: if self.brand_id is None: raise ValueError("brand_id is required for au plugins") if self.unique_id is None: raise ValueError("unique_id is required for au plugins") return self class Meta(BaseModel): name: Optional[str] = None nosimd: Optional[bool] = False daisy: Daisy = Daisy() dpf: DPF = DPF() external: Optional[Dict] = None hvcc-0.16.0/hvcc/utils.py0000644000000000000000000000461200000000000012050 0ustar00# Copyright (C) 2014-2018 Enzien Audio, Ltd. # # 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 . import sys import argparse import json from hvcc.core.hv2ir.HeavyLangObject import HeavyLangObject from hvcc.interpreters.pd2hv.PdParser import PdParser from hvcc.types.meta import Meta, DPF, Daisy gens = { "dpf": DPF, "daisy": Daisy } def main() -> None: parser = argparse.ArgumentParser( description="Some separate heavy utilities, wrapped into a single app") subparsers = parser.add_subparsers(dest="command") subparsers.add_parser("pdobjects", help="list supported Pure Data objects") subparser_hvhash = subparsers.add_parser("hvhash", help="print the heavy hash of the input string") subparser_hvhash.add_argument("string") subparser_meta = subparsers.add_parser("metaschema", help="show JSON Schema of the Meta() model") subparser_meta.add_argument("-g", "--generator", help="Choose supported generator: DPF, Daisy") parsed_args = parser.parse_args(args=None if sys.argv[1:] else ['--help']) args = vars(parsed_args) command = args.pop("command") if command == "pdobjects": obj_list = PdParser.get_supported_objects() obj_list.sort() obj_dict = { "Message Objects": [k for k in obj_list if '~' not in k], "Signal Objects": [k for k in obj_list if '~' in k] } print(json.dumps(obj_dict, indent=4)) elif command == "hvhash": print("0x{0:X}".format(HeavyLangObject.get_hash(args['string']))) elif command == "metaschema": generator = args.get('generator') if generator is not None: model = gens[generator.lower()]() else: model = Meta print(json.dumps(model.model_json_schema(), indent=4)) else: pass if __name__ == "__main__": main() hvcc-0.16.0/hvcc/version.py0000644000000000000000000000002300000000000012365 0ustar00VERSION = "0.16.0" hvcc-0.16.0/pyproject.toml0000644000000000000000000000337200000000000012331 0ustar00[tool.poetry] name = "hvcc" version = "0.16.0" description = "`hvcc` is a python-based dataflow audio programming language compiler that generates C/C++ code and a variety of specific framework wrappers." authors = ["Enzien Audio, Wasted Audio"] license = "GPLv3" readme = "README.md" documentation = "https://wasted-audio.github.io/hvcc/" repository = "https://github.com/Wasted-Audio/hvcc" classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Topic :: Software Development :: Compilers", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", ] [tool.poetry.scripts] hvcc = "hvcc:main" hvutil = "hvcc.utils:main" [tool.poetry.dependencies] python = "^3.9" Jinja2 = ">=2.11" pydantic = ">=2.9.1" pydantic-extra-types = "^2.10.6" arpeggio = "^2.0.2" [tool.poetry.group.dev.dependencies] numpy = "^2.0.1" scipy = [ { version = "^1.16.1", python = "^3.11"}, { version = "^1.13.1", python = "^3.9"}, ] pytest-cov = ">=5,<8" flake8 = "^7.1.1" mypy = "^1.11.2" pytest = "^8.3.3" [tool.poetry-pyinstaller-plugin] collect = { "all" = ["arpeggio"] } include = { "hvcc/generators" = "hvcc/generators", "hvcc/core" = "hvcc/core", "hvcc/interpreters" = "hvcc/interpreters" } [tool.poetry-pyinstaller-plugin.targets] Heavy = { source = "hvcc/main.py", type = "onefile", bundle = true, arch = "x86_64" } [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api" [tool.mypy] plugins = [ "pydantic.mypy" ] hvcc-0.16.0/PKG-INFO0000644000000000000000000002236100000000000010511 0ustar00Metadata-Version: 2.4 Name: hvcc Version: 0.16.0 Summary: `hvcc` is a python-based dataflow audio programming language compiler that generates C/C++ code and a variety of specific framework wrappers. License: GPLv3 License-File: LICENSE Author: Enzien Audio, Wasted Audio Requires-Python: >=3.9,<4.0 Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) Classifier: License :: Other/Proprietary License Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 Classifier: Topic :: Software Development :: Compilers Requires-Dist: Jinja2 (>=2.11) Requires-Dist: arpeggio (>=2.0.2,<3.0.0) Requires-Dist: pydantic (>=2.9.1) Requires-Dist: pydantic-extra-types (>=2.10.6,<3.0.0) Project-URL: Documentation, https://wasted-audio.github.io/hvcc/ Project-URL: Repository, https://github.com/Wasted-Audio/hvcc Description-Content-Type: text/markdown # Heavy Compiler Collection (hvcc) [![Build Status](https://github.com/Wasted-Audio/hvcc/actions/workflows/ci.yml/badge.svg)](https://github.com/Wasted-Audio/hvcc/actions) [![pypi](https://img.shields.io/pypi/v/hvcc.svg)](https://pypi.python.org/pypi/hvcc) [![python](https://img.shields.io/pypi/pyversions/hvcc.svg)](https://pypi.python.org/pypi/hvcc) `hvcc` is a python-based dataflow audio programming language compiler that generates C/C++ code and a variety of specific framework wrappers. ## Background Originaly created by Enzien Audio, the need for `hvcc` arose from running against performance limitations while creating interactive music and sound products for the iPhone. [Pure Data](https://puredata.info) (libpd) was the only real choice for a design tool as it was embeddable and provided a high enough abstraction level that musicians or sound designers could be creative. The goal was to leverage Pure Data as a design interface and statically interpret the resultant patches to generate a low-level, portable and optimised C/C++ program that would be structured to take advantage of modern hardware whilst still generating the same behaviour and audio output as Pure Data. It has since then been expanded to provide further support for many different platforms and frameworks, targeting game audio design, daw plugins and embedded production tools. In 2021 Wasted Audio took over maintenance of the project. ## Documentation - [Introduction](docs/getting-started/index.md) - [What is heavy?](docs/getting-started/index.md#what-is-heavy) - [Supported patch formats](docs/getting-started/index.md#supported-patch-formats) - [Supported platforms](docs/getting-started/index.md#supported-platforms) - [Supported frameworks](docs/getting-started/index.md#supported-frameworks) - [Licensing](docs/getting-started/index.md#licensing) - [Getting Started](docs/getting-started/patching.md) - [Generators](docs/generators/index.md) - [MIDI](docs/reference/midi.md) - [C API](docs/reference/c.md) - [C++ API](docs/reference/cpp.md) - [Heavy Lang Info](docs/reference/ir/heavy_lang.md) - [Heavy IR Info](docs/reference/ir/heavy_ir.md) - [Heavy GUI IR Info](docs/reference/ir/heavy_gui_ir.md) - [Supported vanilla objects](docs/reference/objects/supported.md) - [Unsupported vanilla objects](docs/reference/objects/unsupported.md) ## Integrations hvcc has been integrated into several projects and services. This allows to easily compile patches without having to install hvcc manually. - [plugdata](https://plugdata.org/) - Modern interface for Pure Data. Includes a full cross-platform toolchain and targets Daisy, DPF and PD Externals. - [mod-cloud-builder](https://github.com/moddevices/mod-cloud-builder) - Online service for building LV2 plugins for the MOD platform. - [OWL Patch Library](https://www.rebeltech.org/patch-library) - Online service for building OWL plugins (uses an old fork). ## Requirements Python 3.9 up to 3.14 - `jinja2` (for generator templating) - `pydantic` (for data types) - `pydantic-extra-types` (for data types) - `arpeggio` (for `expr~` translation) For tests: - `tox` (python install) - `numpy/scipy` (dev dependencies) - `midifile` (git submodule) - `tinywav` (git submodule) - `clang/clang++` (system install) ## Installation hvcc is available from pypi.org and can be installed using python3 pip: ```sh pip3 install hvcc ``` If you want to develop hvcc you can install it from the source directory: ```sh git clone https://github.com/Wasted-Audio/hvcc.git cd hvcc/ pip3 install -e . ``` Also review our [Contribution Guide](CONTRIBUTING.md) before opening a pull request. ## Usage `hvcc` requires at least one argument that determines the top-level patch file to be loaded. Generate a C/C++ program from `input.pd` and place the files in `~/myProject/` ```sh hvcc ~/myProject/_main.pd ``` This command will generate the following directories: - `~/myProject/hv` heavylang representation of the input pd patch(es) - `~/myProject/ir` heavyir representation of the heavylang patch - `~/myProject/c` final generated C/C++ source files (this is what you would use in your project) ### `-o` Select output directory As seen in the above command, typical output of `hvcc` is split into several directories that contain the intermediate files used by the compiler itself, the final generated source files, and any additional framework specific files and projects. The `-o` or `--out_dir` parameter will specify where the output files are placed after a successful compile. For example: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ ``` Will place all the generated files in `~/Desktop/somewhere/else/`. ### `-n` Specify Patch Name The `-n` or `--name` parameter can be used to easily namespace the generated code so that there are no conflicts when integrating multiple patches into the same project. ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth ``` ### `-g` Generators Once `hvcc` has generated internal information about the patch the `-g` or `--gen` parameter can be used to specify the output files it should generate. By default it will always include `c` for the C/C++ source files and additional generators can specified for certain framework targets. For example: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth -g unity ``` Will also generate a `unity` section in the output directory contain all the build projects and source files to compile a Unity plugin. It is also possible to pass a list of generators: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth -g unity wwise js ``` A list of available generator options can be found [here](docs/generators/index.md) ### `-p` Search Paths `hvcc` will iterate through various directories when resolving patch objects and abstractions. The `-p` or `--search_paths` argument can be used to add additional folders for `hvcc` to look in. Note that this argument is not needed for abstractions in the same folder as the top-level patch. This can be handy when using a third-party patch library like [heavylib](https://github.com/Wasted-Audio/heavylib) for example. Simply append any folder paths after the `-p` flag like so: ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth -p ~/Workspace/Projects/Enzien/heavylib/ ~/Desktop/myLib/ ``` ### `-m` Meta Data `hvcc` can take extra meta-data via a supplied json file. It depends on the generator which fields are supported. ### `--copyright` User Copyright By default all the generated source files via `hvcc` will have the following copyright text applied to the top of the file: `Copyright (c) 2018 Enzien Audio, Ltd.` This can be changed with `--copyright` parameter ```sh hvcc ~/myProject/_main.pd -o ~/Desktop/somewhere/else/ -n mySynth --copyright "Copyright (c) Los Pollos Hermanos 2019" ``` ### `--help` Displays all the available parameters and options for hvcc. ## Contact The Heavy community aims to be safe and inclusive, please read our [Code of Conduct](CODE_OF_CONDUCT.md) before engaging. There are several places where heavy/hvcc conversation is happening: - [Discord](https://discord.gg/fmxJveg) - [IRC](https://web.libera.chat/#hvcc) - A number of forums: - [Bela](https://forum.bela.io/?q=hvcc) - [Rebel Technology](https://community.rebeltech.org/tags/puredata) - [Daisy](https://forum.electro-smith.com/c/integrations/pure-data/32) - [MOD](https://forum.moddevices.com/c/developers/pure-data/56) Or you can use the [discussions](https://github.com/Wasted-Audio/hvcc/discussions) tab of this repository ## Funding This project is partially funded through [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/HVCC). [NLnet foundation logo](https://nlnet.nl) [NGI Zero Logo](https://nlnet.nl/commonsfund)