diff --git a/src/asid.c b/src/asid.c index 6b4cdd7..0941bb0 100644 --- a/src/asid.c +++ b/src/asid.c @@ -120,10 +120,10 @@ void asid_process(asid instance, const float** x, float** y, int n_samples) { } void asid_set_parameter(asid instance, int index, float value) { - instance->params[index] = value; + if (index < 3) + instance->params[index] = value; } -float asid_get_cutoff_modulated(asid instance) -{ - return instance->modulated_cutoff; +float asid_get_parameter(asid instance, int index) { + return index == 3 ? instance->modulated_cutoff : instance->params[index]; } diff --git a/src/asid.h b/src/asid.h index 94f6935..d96a0d8 100644 --- a/src/asid.h +++ b/src/asid.h @@ -32,7 +32,7 @@ void asid_set_sample_rate(asid instance, float sample_rate); void asid_reset(asid instance); void asid_process(asid instance, const float** x, float** y, int n_samples); void asid_set_parameter(asid instance, int index, float value); -float asid_get_cutoff_modulated(asid instance); +float asid_get_parameter(asid instance, int index); #ifdef __cplusplus } diff --git a/src/ormath.h b/src/ormath.h index 9250f9f..82172fc 100644 --- a/src/ormath.h +++ b/src/ormath.h @@ -49,12 +49,12 @@ #ifndef _ORMATH_H #define _ORMATH_H +#include + #ifdef __cplusplus extern "C" { #endif -#include - typedef union { float f; int32_t i; @@ -116,7 +116,6 @@ static inline float ormath_clipf(float x, float m, float M) { static inline float ormath_truncf(float x) { ormath_floatint v = {.f = x}; - v.f = x; int32_t ex = (v.i & 0x7f800000) >> 23; int32_t m = (~0) << ormath_clipi32(150 - ex, 0, 23); m &= ormath_signexti32(126 - ex) | 0x80000000; diff --git a/vst3/asid.vst3/Contents/Info.plist b/vst3/asid.vst3/Contents/Info.plist new file mode 100755 index 0000000..1cc121d --- /dev/null +++ b/vst3/asid.vst3/Contents/Info.plist @@ -0,0 +1,12 @@ + + + + + CFBundleName + ASID + + CFBundleExecutable + asid + + + diff --git a/vst3/asid.vst3/Contents/PkgInfo b/vst3/asid.vst3/Contents/PkgInfo new file mode 100644 index 0000000..19a9cf6 --- /dev/null +++ b/vst3/asid.vst3/Contents/PkgInfo @@ -0,0 +1 @@ +BNDL???? \ No newline at end of file diff --git a/vst3/asid.vst3/Contents/Resources/ChangeLog.txt b/vst3/asid.vst3/Contents/Resources/ChangeLog.txt new file mode 100644 index 0000000..6e492a2 --- /dev/null +++ b/vst3/asid.vst3/Contents/Resources/ChangeLog.txt @@ -0,0 +1,10 @@ +ASID 1.0.1 +========== + +* reworked GUI OS layer; +* added Linux/x86-64 and MacOS x86-64/arm64 support. + +ASID 1.0.0 +========== + +First release. diff --git a/vst3/asid.vst3/Contents/Resources/sse2neon-license.txt b/vst3/asid.vst3/Contents/Resources/sse2neon-license.txt new file mode 100644 index 0000000..5654561 --- /dev/null +++ b/vst3/asid.vst3/Contents/Resources/sse2neon-license.txt @@ -0,0 +1,19 @@ +sse2neon is freely redistributable under the MIT License. + +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. diff --git a/vst3/build/asid.vst3/Contents/Resources/Snapshots/83AB611011950DD300944BFFF4F2ABBB_snapshot.png b/vst3/build/asid.vst3/Contents/Resources/Snapshots/83AB611011950DD300944BFFF4F2ABBB_snapshot.png deleted file mode 100644 index 7a52b57..0000000 Binary files a/vst3/build/asid.vst3/Contents/Resources/Snapshots/83AB611011950DD300944BFFF4F2ABBB_snapshot.png and /dev/null differ diff --git a/vst3/build/asid.vst3/Contents/Resources/Snapshots/83AB611011950DD300944BFFF4F2ABBB_snapshot_2.0x.png b/vst3/build/asid.vst3/Contents/Resources/Snapshots/83AB611011950DD300944BFFF4F2ABBB_snapshot_2.0x.png deleted file mode 100644 index c86013b..0000000 Binary files a/vst3/build/asid.vst3/Contents/Resources/Snapshots/83AB611011950DD300944BFFF4F2ABBB_snapshot_2.0x.png and /dev/null differ diff --git a/vst3/build/asid.vst3/Contents/Resources/gpl-3.0.txt b/vst3/build/asid.vst3/Contents/Resources/gpl-3.0.txt deleted file mode 100644 index f288702..0000000 --- a/vst3/build/asid.vst3/Contents/Resources/gpl-3.0.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/vst3/build/asid.vst3/Contents/x86_64-win/asid.vst3 b/vst3/build/asid.vst3/Contents/x86_64-win/asid.vst3 deleted file mode 100644 index 4f90f43..0000000 Binary files a/vst3/build/asid.vst3/Contents/x86_64-win/asid.vst3 and /dev/null differ diff --git a/vst3/build/asid.vst3/Plugin.ico b/vst3/build/asid.vst3/Plugin.ico deleted file mode 100644 index f8486c4..0000000 Binary files a/vst3/build/asid.vst3/Plugin.ico and /dev/null differ diff --git a/vst3/build/asid.vst3/desktop.ini b/vst3/build/asid.vst3/desktop.ini deleted file mode 100644 index be3001a..0000000 --- a/vst3/build/asid.vst3/desktop.ini +++ /dev/null @@ -1,2 +0,0 @@ -[.ShellClassInfo] -IconResource=Plugin.ico,0 diff --git a/vst3/buildLinux.sh b/vst3/buildLinux.sh index e6b5dd2..cd71827 100755 --- a/vst3/buildLinux.sh +++ b/vst3/buildLinux.sh @@ -39,12 +39,12 @@ g++ \ src/asid_gui.c \ src/gui-x.c \ \ - -DDEVELOPMENT=1 \ + -DRELEASE=1 \ -I../src \ -Isrc \ -I$VST_SDK_DIR/vst3sdk/ \ -fPIC -shared \ - -ldl \ - -rdynamic \ - -o build/asid.vst3/Contents/x86_64-linux/asid.so -# -DRELEASE=1 + -static-libgcc \ + -static-libstdc++ \ + -o build/asid.vst3/Contents/x86_64-linux/asid.so \ + -O3 diff --git a/vst3/buildMacOS.sh b/vst3/buildMacOS.sh new file mode 100755 index 0000000..2ba9fda --- /dev/null +++ b/vst3/buildMacOS.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +VST_SDK_DIR=../../VST_SDK + +rm -rf build + +mkdir -p build +cp -R asid.vst3 build + +mkdir -p build/asid.vst3/Contents/MacOS + +SOURCES=" + src/vst3/entry.cpp \ + src/vst3/plugin.cpp \ + src/vst3/controllerOSX.cpp \ + src/vst3/controllerOSXTimer.mm \ + $VST_SDK_DIR/vst3sdk/base/source/fobject.cpp \ + $VST_SDK_DIR/vst3sdk/base/source/baseiids.cpp \ + $VST_SDK_DIR/vst3sdk/base/source/fstreamer.cpp \ + $VST_SDK_DIR/vst3sdk/base/source/fstring.cpp \ + $VST_SDK_DIR/vst3sdk/pluginterfaces/base/coreiids.cpp \ + $VST_SDK_DIR/vst3sdk/pluginterfaces/base/funknown.cpp \ + $VST_SDK_DIR/vst3sdk/pluginterfaces/base/ustring.cpp \ + $VST_SDK_DIR/vst3sdk/pluginterfaces/base/conststringtable.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/main/pluginfactory.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/main/moduleinit.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/common/commoniids.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/common/pluginview.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vstcomponentbase.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vstcomponent.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vstaudioeffect.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vstinitiids.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vstbus.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vsteditcontroller.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/vst/vstparameters.cpp \ + $VST_SDK_DIR/vst3sdk/base/source/fdebug.cpp \ + $VST_SDK_DIR/vst3sdk/base/source/updatehandler.cpp \ + $VST_SDK_DIR/vst3sdk/base/thread/source/flock.cpp \ + $VST_SDK_DIR/vst3sdk/base/source/fbuffer.cpp \ + $VST_SDK_DIR/vst3sdk/public.sdk/source/main/macmain.cpp \ + ../src/asid.c \ + ../src/mos_8580_filter.c \ + src/asid_gui.c \ + src/gui-cocoa.mm \ +" + +CFLAGS=" + -framework Cocoa \ + -std=c++11 \ + \ + -DDEVELOPMENT=1 \ + -I../src \ + -Isrc \ + -I$VST_SDK_DIR/vst3sdk/ \ + -fPIC -shared \ + -ldl \ + -rdynamic \ + -o build/asid.vst3/Contents/MacOS/asid \ + -DRELEASE=1 \ + -O3 \ + -ffast-math +" + +clang++ $SOURCES $CFLAGS -arch x86_64 -o build/asid.vst3/Contents/MacOS/asid-x86_64 +clang++ $SOURCES $CFLAGS -arch arm64 -o build/asid.vst3/Contents/MacOS/asid-arm64 + +lipo -create -output build/asid.vst3/Contents/MacOS/asid build/asid.vst3/Contents/MacOS/asid-x86_64 build/asid.vst3/Contents/MacOS/asid-arm64 +rm build/asid.vst3/Contents/MacOS/asid-x86_64 build/asid.vst3/Contents/MacOS/asid-arm64 + +# -lobjc -Wno-import + +# Should solve some signature problem (for Ableton Live e.g.) +# sudo xattr -rd com.apple.quarantine build/asid.vst3 diff --git a/vst3/buildWin.sh b/vst3/buildWin.sh index c6d493c..9929428 100644 --- a/vst3/buildWin.sh +++ b/vst3/buildWin.sh @@ -9,6 +9,7 @@ cp -R asid.vst3 build mkdir -p build/asid.vst3/Contents/x86_64-win +# to fix: linuxmain should not be compiled here! g++ \ src/vst3/entry.cpp \ src/vst3/plugin.cpp \ diff --git a/vst3/src/asid_gui.c b/vst3/src/asid_gui.c index 43d7a4e..0c3bc94 100644 --- a/vst3/src/asid_gui.c +++ b/vst3/src/asid_gui.c @@ -14,27 +14,20 @@ * * You should have received a copy of the GNU General Public License * - * File author: Paolo Marrone + * File author: Paolo Marrone, Stefano D'Angelo */ #include "asid_gui.h" -#include -#include +#include +#include -#include "vst3/controller.h" +#include "gui.h" +#include "screens.h" -#ifdef __cplusplus -extern "C" { -#endif +#include - -#define PIXELED -#ifdef PIXELED - #define RESIZE_FUNC pixeled_resize -#else - #define RESIZE_FUNC bilinear_interpolation_resize -#endif +#define BILINEAR_INTERPOLATION static const uint32_t width_default = 404; static const uint32_t height_default = 284; @@ -91,16 +84,21 @@ static uint8_t colors_default[4][3] = { static uint8_t color_grey[3] = {51, 51, 51}; - -#include "screens.h" - static const uint8_t* screen_map_defaults[] = {screen1_map_default, screen2_map_default, screen3_map_default, screen4_map_default}; struct _asid_gui { - void *handle; - - asid_gui_view window; // Main window + gui g; + asid_gui_view views; + void *data; + float (*get_parameter)(asid_gui gui, uint32_t id); + void (*set_parameter)(asid_gui gui, uint32_t id, float value); +}; + +struct _asid_gui_view { + asid_gui gui; + asid_gui_view next; + window win; unsigned char* screen_maps[4]; @@ -165,13 +163,12 @@ struct _asid_gui { char toResize; }; - static uint32_t floorI(float x) { return (uint32_t) x; } static uint32_t ceilI(float x) { - uint32_t f = floorI(x); + int32_t f = floorI(x); return f + (x - (float) f <= 0.000001f ? 0 : 1); } @@ -196,56 +193,14 @@ static float clipF(float x, float min, float max) { return minF(max, maxF(min, x)); } - -static void pixeled_resize ( - unsigned char *src, unsigned char *dest, - uint32_t src_w, uint32_t src_h, - uint32_t src_target_x, uint32_t src_target_y, uint32_t src_target_w, uint32_t src_target_h, - uint32_t dest_w, uint32_t dest_h, - uint32_t dest_target_x, uint32_t dest_target_y, uint32_t dest_target_w, uint32_t dest_target_h) -{ - const float w_scale_factor = (float) src_target_w / (float) dest_target_w; - const float h_scale_factor = (float) src_target_h / (float) dest_target_h; - - const uint32_t wOffset = (dest_w - dest_target_w) << 2; - uint32_t newIndex = (dest_target_y * dest_w + dest_target_x) << 2; - - for (uint32_t ri = 0; ri < dest_target_h; ri++) { - const float y = (float) ri * h_scale_factor + src_target_y; - uint32_t y_floor, y_ceil; - floorceilI(y, &y_floor, &y_ceil); - y_ceil = minI(src_h - 1, y_ceil); - - const uint32_t yFall = y - y_floor < 0.5f ? y_floor : y_ceil; - - for (uint32_t ci = 0; ci < dest_target_w; ci++) { - - const float x = (float) ci * w_scale_factor + src_target_x; - uint32_t x_floor, x_ceil; - floorceilI(x, &x_floor, &x_ceil); - x_ceil = minI(src_w - 1, x_ceil); - - const uint32_t xFall = x - x_floor < 0.5f ? x_floor : x_ceil; - - const uint32_t pixelIndex = (yFall * src_w + xFall) << 2; - - dest[newIndex++] = src[pixelIndex + 0];; - dest[newIndex++] = src[pixelIndex + 1];; - dest[newIndex++] = src[pixelIndex + 2];; - dest[newIndex++] = 0; - } - newIndex += wOffset; - } -} - - -static void bilinear_interpolation_resize ( +static void interpolate ( unsigned char *src, unsigned char *dest, uint32_t src_w, uint32_t src_h, uint32_t src_target_x, uint32_t src_target_y, uint32_t src_target_w, uint32_t src_target_h, uint32_t dest_w, uint32_t dest_h, uint32_t dest_target_x, uint32_t dest_target_y, uint32_t dest_target_w, uint32_t dest_target_h) { +#ifdef BILINEAR_INTERPOLATION const float w_scale_factor = (float) src_target_w / (float) dest_target_w; const float h_scale_factor = (float) src_target_h / (float) dest_target_h; @@ -323,9 +278,43 @@ static void bilinear_interpolation_resize ( } newIndex += wOffset; } +#else + const float w_scale_factor = (float) src_target_w / (float) dest_target_w; + const float h_scale_factor = (float) src_target_h / (float) dest_target_h; + + const uint32_t wOffset = (dest_w - dest_target_w) << 2; + uint32_t newIndex = (dest_target_y * dest_w + dest_target_x) << 2; + + for (uint32_t ri = 0; ri < dest_target_h; ri++) { + const float y = (float) ri * h_scale_factor + src_target_y; + uint32_t y_floor, y_ceil; + floorceilI(y, &y_floor, &y_ceil); + y_ceil = minI(src_h - 1, y_ceil); + + const uint32_t yFall = y - y_floor < 0.5f ? y_floor : y_ceil; + + for (uint32_t ci = 0; ci < dest_target_w; ci++) { + + const float x = (float) ci * w_scale_factor + src_target_x; + uint32_t x_floor, x_ceil; + floorceilI(x, &x_floor, &x_ceil); + x_ceil = minI(src_w - 1, x_ceil); + + const uint32_t xFall = x - x_floor < 0.5f ? x_floor : x_ceil; + + const uint32_t pixelIndex = (yFall * src_w + xFall) << 2; + + dest[newIndex++] = src[pixelIndex + 0];; + dest[newIndex++] = src[pixelIndex + 1];; + dest[newIndex++] = src[pixelIndex + 2];; + dest[newIndex++] = 0; + } + newIndex += wOffset; + } +#endif } -static void draw_parameter_fixed(asid_gui gui, char p) { +static void draw_parameter_fixed(asid_gui_view view, char p) { uint32_t pb_x1, pb_x2, yValue; uint32_t p_x1, p_x2; @@ -334,21 +323,21 @@ static void draw_parameter_fixed(asid_gui gui, char p) { pb_x2 = parambox_cutoff_x2; p_x1 = param_cutoff_x1; p_x2 = param_cutoff_x2; - yValue = (uint32_t) ((1.f - gui->paramMappedValues[p]) * (float) params_inner_h) + params_inner_y; + yValue = (uint32_t) ((1.f - view->paramMappedValues[p]) * (float) params_inner_h) + params_inner_y; } else if (p == 1) { pb_x1 = parambox_lfoamt_x1; pb_x2 = parambox_lfoamt_x2; p_x1 = param_lfoamt_x1; p_x2 = param_lfoamt_x2; - yValue = (uint32_t) ((1.f - gui->paramMappedValues[p]) * (float) params_inner_h) + params_inner_y; + yValue = (uint32_t) ((1.f - view->paramMappedValues[p]) * (float) params_inner_h) + params_inner_y; } else if (p == 2) { pb_x1 = parambox_lfospd_x1; pb_x2 = parambox_lfospd_x2; p_x1 = param_lfospd_x1; p_x2 = param_lfospd_x2; - yValue = (uint32_t) ((1.f - gui->paramMappedValues[p]) * (float) params_inner_h) + params_inner_y; + yValue = (uint32_t) ((1.f - view->paramMappedValues[p]) * (float) params_inner_h) + params_inner_y; } else return; @@ -356,14 +345,14 @@ static void draw_parameter_fixed(asid_gui gui, char p) { uint32_t index = ((paramboxs_y1) * inner_width_default + pb_x1) << 2; uint32_t wOffset = (inner_width_default - paramboxs_w) << 2; - if (gui->param_hover == p) { // isHover + if (view->param_hover == p) { // isHover for (uint32_t c = paramboxs_y1; c <= paramboxs_y2; c++) { for (int r = pb_x1; r <= pb_x2; r++) { if (screen_map_defaults[0][index] != 255) { for (char i = 0; i < 4; i++) { - gui->screen_maps[i][index + 0] = colors_default[i][0]; - gui->screen_maps[i][index + 1] = colors_default[i][1]; - gui->screen_maps[i][index + 2] = colors_default[i][2]; + view->screen_maps[i][index + 0] = colors_default[i][0]; + view->screen_maps[i][index + 1] = colors_default[i][1]; + view->screen_maps[i][index + 2] = colors_default[i][2]; } } index += 4; @@ -376,9 +365,9 @@ static void draw_parameter_fixed(asid_gui gui, char p) { for (int r = pb_x1; r <= pb_x2; r++) { if (screen_map_defaults[0][index] != 255) { for (char i = 0; i < 4; i++) { - gui->screen_maps[i][index + 0] = screen_map_defaults[0][index + 0]; - gui->screen_maps[i][index + 1] = screen_map_defaults[0][index + 1]; - gui->screen_maps[i][index + 2] = screen_map_defaults[0][index + 2]; + view->screen_maps[i][index + 0] = screen_map_defaults[0][index + 0]; + view->screen_maps[i][index + 1] = screen_map_defaults[0][index + 1]; + view->screen_maps[i][index + 2] = screen_map_defaults[0][index + 2]; } } index += 4; @@ -391,9 +380,9 @@ static void draw_parameter_fixed(asid_gui gui, char p) { for (uint32_t c = params_inner_y; c < yValue; c++) { for (int r = p_x1 + 1; r < p_x2; r++) { for (char i = 0; i < 4; i++) { - gui->screen_maps[i][index + 0] = 255; - gui->screen_maps[i][index + 1] = 255; - gui->screen_maps[i][index + 2] = 255; + view->screen_maps[i][index + 0] = 255; + view->screen_maps[i][index + 1] = 255; + view->screen_maps[i][index + 2] = 255; } index += 4; } @@ -401,76 +390,76 @@ static void draw_parameter_fixed(asid_gui gui, char p) { } } -static void draw_parameter_resized(asid_gui gui, char p) { +static void draw_parameter_resized(asid_gui_view view, char p) { uint32_t pb_x1, resized_x1; if (p == 0) { pb_x1 = parambox_cutoff_x1; - resized_x1 = gui->xBoxCutoff; + resized_x1 = view->xBoxCutoff; } else if (p == 1) { pb_x1 = parambox_lfoamt_x1; - resized_x1 = gui->xBoxAmount; + resized_x1 = view->xBoxAmount; } else if (p == 2) { pb_x1 = parambox_lfospd_x1; - resized_x1 = gui->xBoxSpeed; + resized_x1 = view->xBoxSpeed; } else return; for (int ri = 0; ri < 4; ri++) { - RESIZE_FUNC( - gui->screen_maps[ri], gui->resized[ri], + interpolate( + view->screen_maps[ri], view->resized[ri], inner_width_default, inner_height_default, pb_x1, paramboxs_y1, paramboxs_w, paramboxs_h, - gui->w, gui->h, - resized_x1, gui->yBoxParams, gui->wBoxParams, gui->hBoxParams); + view->w, view->h, + resized_x1, view->yBoxParams, view->wBoxParams, view->hBoxParams); } } -static void update_gui_parameter(asid_gui gui, char p) { +static void update_view_parameter(asid_gui_view view, char p) { uint32_t resized_x1; if (p == 0) { - resized_x1 = gui->xBoxCutoff; + resized_x1 = view->xBoxCutoff; } else if (p == 1) { - resized_x1 = gui->xBoxAmount; + resized_x1 = view->xBoxAmount; } else if (p == 2) { - resized_x1 = gui->xBoxSpeed; + resized_x1 = view->xBoxSpeed; } else return; - gui_window_draw (gui->window, gui->resized[gui->screen_map_selected], - resized_x1, gui->yBoxParams, gui->w, gui->h, - resized_x1, gui->yBoxParams, gui->wBoxParams, gui->hBoxParams); + gui_window_draw (view->win, view->resized[view->screen_map_selected], + resized_x1, view->yBoxParams, view->w, view->h, + resized_x1, view->yBoxParams, view->wBoxParams, view->hBoxParams); } -static void draw_modCutoff_slider_fixed (asid_gui gui) { +static void draw_modCutoff_slider_fixed (asid_gui_view view) { static const uint32_t indexStart = (modCutoff_y1 * inner_width_default + modCutoff_x1) << 2; static const uint32_t wOffset = (inner_width_default - modCutoff_w) << 2; - const uint32_t yMid = modCutoff_y1 + (uint32_t) ((1.f - gui->modCutoffValue) * modCutoff_h); + const uint32_t yMid = modCutoff_y1 + (uint32_t) ((1.f - view->modCutoffValue) * modCutoff_h); uint8_t* colors = color_grey; for (int ri = 0; ri < 4; ri++) { - if (gui->param_selected == 0 || gui->param_hover == 0) + if (view->param_selected == 0 || view->param_hover == 0) colors = colors_default[ri]; uint32_t index = indexStart; uint32_t r = modCutoff_y1; for (; r < yMid; r++) { for (uint32_t c = modCutoff_x1; c <= modCutoff_x2; c++) { - gui->screen_maps[ri][index + 0] = 255; // Optimize: see array of char as array of int32. - gui->screen_maps[ri][index + 1] = 255; - gui->screen_maps[ri][index + 2] = 255; + view->screen_maps[ri][index + 0] = 255; // Optimize: see array of char as array of int32. + view->screen_maps[ri][index + 1] = 255; + view->screen_maps[ri][index + 2] = 255; index += 4; } index += wOffset; } for (; r <= modCutoff_y2; r++) { for (uint32_t c = modCutoff_x1; c <= modCutoff_x2; c++) { - gui->screen_maps[ri][index + 0] = colors[0]; - gui->screen_maps[ri][index + 1] = colors[1]; - gui->screen_maps[ri][index + 2] = colors[2]; + view->screen_maps[ri][index + 0] = colors[0]; + view->screen_maps[ri][index + 1] = colors[1]; + view->screen_maps[ri][index + 2] = colors[2]; index += 4; } index += wOffset; @@ -489,254 +478,211 @@ static void draw_padding (unsigned char* img, uint32_t xBlack, uint32_t yBlack, } } -void asid_gui_view_resize(asid_gui gui, asid_gui_view view, uint32_t width, uint32_t height) { - float newrate = (float)width / (float) height; +static void draw_resized (asid_gui_view view) { + const uint32_t size = (view->w * view->h) << 2; + view->resized[0] = (unsigned char*) realloc(view->resized[0], size); + view->resized[1] = (unsigned char*) realloc(view->resized[1], size); + view->resized[2] = (unsigned char*) realloc(view->resized[2], size); + view->resized[3] = (unsigned char*) realloc(view->resized[3], size); - if (newrate >= imgrate) { - gui->wWhite = (uint32_t) (imgrate * (float) height); - gui->hWhite = height; - gui->xWhite = (width - gui->wWhite) >> 1; - gui->yWhite = 0; - } - else { - gui->wWhite = width; - gui->hWhite = (uint32_t) (((float) width) / imgrate); - gui->xWhite = 0; - gui->yWhite = (height - gui->hWhite) >> 1; - } - - gui->scaleFactor = (float) gui->wWhite / (float) width_default; - gui->scaleFactorInv = 1.f / gui->scaleFactor; - uint32_t newPadding = (uint32_t) (((float) padding_default) * gui->scaleFactor); - - gui->xContent = gui->xWhite + newPadding; - gui->yContent = gui->yWhite + newPadding; - gui->wContent = gui->wWhite - (newPadding << 1); - gui->hContent = gui->hWhite - (newPadding << 1); - - gui->xCutoff = (uint32_t) (gui->xContent + ((float) (param_cutoff_x1 + 1)) * gui->scaleFactor); - gui->xAmount = (uint32_t) (gui->xContent + ((float) (param_lfoamt_x1 + 1)) * gui->scaleFactor); - gui->xSpeed = (uint32_t) (gui->xContent + ((float) (param_lfospd_x1 + 1)) * gui->scaleFactor); - gui->yParams = (uint32_t) (gui->yContent + ((float) (params_y1 + 1)) * gui->scaleFactor); - gui->wParams = (uint32_t) (((float) params_w) * gui->scaleFactor); - gui->hParams = (uint32_t) (((float) params_h) * gui->scaleFactor); - - gui->xBoxCutoff = (uint32_t) (gui->xContent + ((float) (parambox_cutoff_x1)) * gui->scaleFactor); // Forse round è meglio - gui->xBoxAmount = (uint32_t) (gui->xContent + ((float) (parambox_lfoamt_x1)) * gui->scaleFactor); - gui->xBoxSpeed = (uint32_t) (gui->xContent + ((float) (parambox_lfospd_x1)) * gui->scaleFactor); - gui->yBoxParams = (uint32_t) (gui->yContent + ((float) (paramboxs_y1)) * gui->scaleFactor); - gui->wBoxParams = ceilI (((float) paramboxs_w) * gui->scaleFactor); - gui->hBoxParams = ceilI (((float) paramboxs_h) * gui->scaleFactor); - - gui->xModCutoff = gui->xContent + (uint32_t) (((float) modCutoff_x1) * gui->scaleFactor); - gui->yModCutoff = gui->yContent + (uint32_t) (((float) modCutoff_y1) * gui->scaleFactor); - gui->wModCutoff = ceilI (((float) modCutoff_w) * gui->scaleFactor); - gui->hModCutoff = ceilI (((float) modCutoff_h) * gui->scaleFactor); - - gui->w = width; - gui->h = height; - - gui->toResize = 1; -} - -static void draw_resized (asid_gui gui) { - const uint32_t size = (gui->w * gui->h) << 2; - gui->resized[0] = (unsigned char*) realloc(gui->resized[0], size); - gui->resized[1] = (unsigned char*) realloc(gui->resized[1], size); - gui->resized[2] = (unsigned char*) realloc(gui->resized[2], size); - gui->resized[3] = (unsigned char*) realloc(gui->resized[3], size); - - if (gui->resized[0] == NULL || gui->resized[1] == NULL || gui->resized[2] == NULL || gui->resized[3] == NULL) { + if (view->resized[0] == NULL || view->resized[1] == NULL || view->resized[2] == NULL || view->resized[3] == NULL) { return; } for (int ri = 0; ri < 4; ri++) { - draw_padding(gui->resized[ri], 0, 0, gui->w, gui->h, gui->xWhite, gui->yWhite, gui->wWhite, gui->hWhite); - RESIZE_FUNC( - gui->screen_maps[ri], gui->resized[ri], + draw_padding(view->resized[ri], 0, 0, view->w, view->h, view->xWhite, view->yWhite, view->wWhite, view->hWhite); + interpolate( + view->screen_maps[ri], view->resized[ri], inner_width_default, inner_height_default, 0, 0, inner_width_default, inner_height_default, - gui->w, gui->h, - gui->xContent, gui->yContent, gui->wContent, gui->hContent); + view->w, view->h, + view->xContent, view->yContent, view->wContent, view->hContent); } } -static void update_gui_resize (asid_gui gui) { - gui_window_resize(gui->window, gui->w, gui->h); - gui_window_draw (gui->window, gui->resized[gui->screen_map_selected], 0, 0, gui->w, gui->h, 0, 0, gui->w, gui->h); -} +static void resize(asid_gui_view view, uint32_t width, uint32_t height) { + float newrate = (float)width / (float) height; -static void piggyback_draw(asid_gui gui) { - if (gui == NULL || gui->window == NULL) { - return; + if (newrate >= imgrate) { + view->wWhite = (uint32_t) (imgrate * (float) height); + view->hWhite = height; + view->xWhite = (width - view->wWhite) >> 1; + view->yWhite = 0; + } + else { + view->wWhite = width; + view->hWhite = (uint32_t) (((float) width) / imgrate); + view->xWhite = 0; + view->yWhite = (height - view->hWhite) >> 1; } + view->scaleFactor = (float) view->wWhite / (float) width_default; + view->scaleFactorInv = 1.f / view->scaleFactor; + uint32_t newPadding = (uint32_t) (((float) padding_default) * view->scaleFactor); + + view->xContent = view->xWhite + newPadding; + view->yContent = view->yWhite + newPadding; + view->wContent = view->wWhite - (newPadding << 1); + view->hContent = view->hWhite - (newPadding << 1); + + view->xCutoff = (uint32_t) (view->xContent + ((float) (param_cutoff_x1 + 1)) * view->scaleFactor); + view->xAmount = (uint32_t) (view->xContent + ((float) (param_lfoamt_x1 + 1)) * view->scaleFactor); + view->xSpeed = (uint32_t) (view->xContent + ((float) (param_lfospd_x1 + 1)) * view->scaleFactor); + view->yParams = (uint32_t) (view->yContent + ((float) (params_y1 + 1)) * view->scaleFactor); + view->wParams = (uint32_t) (((float) params_w) * view->scaleFactor); + view->hParams = (uint32_t) (((float) params_h) * view->scaleFactor); + + view->xBoxCutoff = (uint32_t) (view->xContent + ((float) (parambox_cutoff_x1)) * view->scaleFactor); // Forse round è meglio + view->xBoxAmount = (uint32_t) (view->xContent + ((float) (parambox_lfoamt_x1)) * view->scaleFactor); + view->xBoxSpeed = (uint32_t) (view->xContent + ((float) (parambox_lfospd_x1)) * view->scaleFactor); + view->yBoxParams = (uint32_t) (view->yContent + ((float) (paramboxs_y1)) * view->scaleFactor); + view->wBoxParams = ceilI (((float) paramboxs_w) * view->scaleFactor); + view->hBoxParams = ceilI (((float) paramboxs_h) * view->scaleFactor); + + view->xModCutoff = view->xContent + (uint32_t) (((float) modCutoff_x1) * view->scaleFactor); + view->yModCutoff = view->yContent + (uint32_t) (((float) modCutoff_y1) * view->scaleFactor); + view->wModCutoff = ceilI (((float) modCutoff_w) * view->scaleFactor); + view->hModCutoff = ceilI (((float) modCutoff_h) * view->scaleFactor); + + view->w = width; + view->h = height; + + view->toResize = 1; +} + +static void draw(asid_gui_view view) { for (int i = 0; i < 3; i++) { - if (gui->paramToRedraw[i]) - draw_parameter_fixed(gui, i); + if (view->paramToRedraw[i]) + draw_parameter_fixed(view, i); } - if (gui->modCutoffToRedraw) - draw_modCutoff_slider_fixed(gui); + if (view->modCutoffToRedraw) + draw_modCutoff_slider_fixed(view); - if (gui->toResize) { - draw_resized(gui); - update_gui_resize(gui); + if (view->toResize) { + draw_resized(view); + gui_window_draw (view->win, view->resized[view->screen_map_selected], 0, 0, view->w, view->h, 0, 0, view->w, view->h); for (int i = 0; i < 3; i++) - gui->paramToRedraw[i] = 1; - gui->modCutoffToRedraw = 0; - gui->toResize = 0; + view->paramToRedraw[i] = 1; + view->modCutoffToRedraw = 0; + view->toResize = 0; } else { for (int i = 0; i < 3; i++) { - if (gui->paramToRedraw[i]) - draw_parameter_resized(gui, i); + if (view->paramToRedraw[i]) + draw_parameter_resized(view, i); } - if (gui->paramToRedraw[0] == 0 && gui->modCutoffToRedraw) - draw_parameter_resized(gui, 0); + if (view->paramToRedraw[0] == 0 && view->modCutoffToRedraw) + draw_parameter_resized(view, 0); - if (gui->screen_map_selected != gui->screen_map_selected_old) { - gui_window_draw (gui->window, gui->resized[gui->screen_map_selected], - gui->xContent, gui->yContent, gui->w, gui->h, - gui->xContent, gui->yContent, gui->wContent, gui->hContent); - gui->screen_map_selected_old = gui->screen_map_selected; + if (view->screen_map_selected != view->screen_map_selected_old) { + gui_window_draw (view->win, view->resized[view->screen_map_selected], + view->xContent, view->yContent, view->w, view->h, + view->xContent, view->yContent, view->wContent, view->hContent); + view->screen_map_selected_old = view->screen_map_selected; } else { for (int i = 0; i < 3; i++) { - if (gui->paramToRedraw[i]) - update_gui_parameter(gui, i); + if (view->paramToRedraw[i]) + update_view_parameter(view, i); } - if (gui->paramToRedraw[0] == 0 && gui->modCutoffToRedraw) - update_gui_parameter(gui, 0); + if (view->paramToRedraw[0] == 0 && view->modCutoffToRedraw) + update_view_parameter(view, 0); } - gui->paramToRedraw[0] = 0; - gui->paramToRedraw[1] = 0; - gui->paramToRedraw[2] = 0; - gui->modCutoffToRedraw = 0; + view->paramToRedraw[0] = 0; + view->paramToRedraw[1] = 0; + view->paramToRedraw[2] = 0; + view->modCutoffToRedraw = 0; } } -asid_gui asid_gui_new(void *handle) { - asid_gui gui = (asid_gui)malloc(sizeof(struct _asid_gui)); - if (gui == NULL) - return NULL; - - gui->handle = handle; - gui->window = NULL; // Main and only window - - gui_init(); - - gui->screen_maps[0] = (unsigned char*) malloc(inner_size_pixel); - gui->screen_maps[1] = (unsigned char*) malloc(inner_size_pixel); - gui->screen_maps[2] = (unsigned char*) malloc(inner_size_pixel); - gui->screen_maps[3] = (unsigned char*) malloc(inner_size_pixel); - - memcpy(gui->screen_maps[0], screen_map_defaults[0], inner_size_pixel); - memcpy(gui->screen_maps[1], screen_map_defaults[1], inner_size_pixel); - memcpy(gui->screen_maps[2], screen_map_defaults[2], inner_size_pixel); - memcpy(gui->screen_maps[3], screen_map_defaults[3], inner_size_pixel); - - gui->resized[0] = NULL; - gui->resized[1] = NULL; - gui->resized[2] = NULL; - gui->resized[3] = NULL; - - gui->scaleFactor = 1.f; - gui->scaleFactorInv = 1.f; - - gui->w = width_default; - gui->h = height_default; - - gui->xWhite = 0; - gui->yWhite = 0; - gui->wWhite = width_default; - gui->hWhite = height_default; - - gui->xContent = padding_default; - gui->yContent = padding_default; - gui->wContent = inner_width_default; - gui->hContent = inner_height_default; - - gui->xCutoff = param_cutoff_x1; - gui->xAmount = param_lfoamt_x1; - gui->xSpeed = param_lfospd_x1; - gui->yParams = params_y1; - gui->wParams = params_w; - gui->hParams = params_h; - - gui->xBoxCutoff = parambox_cutoff_x1; - gui->xBoxAmount = parambox_lfoamt_x1; - gui->xBoxSpeed = parambox_lfospd_x1; - gui->yBoxParams = paramboxs_y1; - gui->wBoxParams = paramboxs_w; - gui->hBoxParams = paramboxs_h; - - gui->xModCutoff = modCutoff_x1; - gui->yModCutoff = modCutoff_y1; - gui->wModCutoff = modCutoff_w; - gui->hModCutoff = modCutoff_h; - - gui->paramValues[0] = 1.f; - gui->paramValues[1] = 0.f; - gui->paramValues[2] = 0.5f; - - gui->paramMappedValues[0] = 1.f; - gui->paramMappedValues[1] = 0.f; - gui->paramMappedValues[2] = 0.46666666666666f; - - gui->param_hover = -1; // -1 = None, 0 = cutoff, 1 = amount, 2 = speed - gui->param_selected = -1; // -1 = None, 0 = cutoff, 1 = amount, 2 = speed - gui->mouse_old_y = 0; - - gui->screen_map_selected = 3; - - gui->modCutoffValue = 0.f; - - // Redrawing state - gui->paramToRedraw[0] = 0; - gui->paramToRedraw[1] = 0; - gui->paramToRedraw[2] = 0; - gui->modCutoffToRedraw = 0; - gui->toResize = 0; - - return gui; +static void on_resize(window w, uint32_t width, uint32_t height) { + asid_gui_view view = (asid_gui_view)gui_window_get_data(w); + resize(view, width, height); + draw(view); } -void asid_gui_free(asid_gui gui) { - gui_fini(); +static void on_mouse_press (window w, int32_t x, int32_t y) { + asid_gui_view view = (asid_gui_view)gui_window_get_data(w); - for (int i = 0; i < 4; i++) { - free(gui->screen_maps[i]); - free(gui->resized[i]); + x = (int) (((float) (x - (int) view->xContent)) * view->scaleFactorInv); + y = (int) (((float) (y - (int) view->yContent)) * view->scaleFactorInv); + + if (y >= paramboxs_y1 && y <= paramboxs_y2) { + if (x >= parambox_cutoff_x1 && x <= parambox_cutoff_x2) { + view->param_selected = 0; + } + else if (x >= parambox_lfoamt_x1 && x <= parambox_lfoamt_x2) { + view->param_selected = 1; + } + else if (x >= parambox_lfospd_x1 && x <= parambox_lfospd_x2) { + view->param_selected = 2; + } + else { + view->param_selected = -1; + } + view->mouse_old_y = y; } - free(gui); } -asid_gui_view asid_gui_view_new(asid_gui gui, void *parent) { - asid_gui_view view = gui_window_new (parent, width_default, height_default, gui); - if (view == NULL) - return NULL; - gui->window = view; - - gui_window_show (view); - - asid_gui_view_resize(gui, view, 403, 283); - draw_parameter_fixed(gui, 0); - draw_parameter_fixed(gui, 1); - draw_parameter_fixed(gui, 2); - - gui_set_timeout (view, 10); - - return view; +static void on_mouse_release (window w, int32_t x, int32_t y) { + asid_gui_view view = (asid_gui_view)gui_window_get_data(w); + view->param_selected = -1; + //view->mouse_old_y = 0; // Maybe something better } -void asid_gui_view_free(asid_gui gui, asid_gui_view view) { - gui_window_free(view); +static void on_mouse_move (window w, int32_t x, int32_t y, uint32_t mouseState) { + asid_gui_view view = (asid_gui_view)gui_window_get_data(w); + + x = (int) (((float) (x - (int) view->xContent)) * view->scaleFactorInv); + y = (int) (((float) (y - (int) view->yContent)) * view->scaleFactorInv); + + // Hover + if (view->param_selected == -1) { + char old_param_hover = view->param_hover; + if (y >= paramboxs_y1 && y <= paramboxs_y2) { + if (x >= parambox_cutoff_x1 && x <= parambox_cutoff_x2) + view->param_hover = 0; + else if (x >= parambox_lfoamt_x1 && x <= parambox_lfoamt_x2) + view->param_hover = 1; + else if (x >= parambox_lfospd_x1 && x <= parambox_lfospd_x2) + view->param_hover = 2; + else + view->param_hover = -1; + } + else + view->param_hover = -1; + + if (old_param_hover == view->param_hover) + ; + else { + if (old_param_hover != -1) + view->paramToRedraw[old_param_hover] = 1; + if (view->param_hover != -1) + view->paramToRedraw[view->param_hover] = 1; + if (view->paramToRedraw[0]) + view->modCutoffToRedraw = 1; + } + } + // Mouse diff + if (view->param_selected != -1 && mouseState > 0) { + float diff = ((float) (view->mouse_old_y - y)) / (float) params_h; + if (diff != 0.f) { + view->paramValues[view->param_selected] = clipF(view->paramValues[view->param_selected] + diff, 0.f, 1.f); + float newMappedV = floorI(view->paramValues[view->param_selected] * 15.f) * 0.0666666666666666f; + if (view->paramMappedValues[view->param_selected] != newMappedV) { + view->paramMappedValues[view->param_selected] = newMappedV; + view->paramToRedraw[view->param_selected] = -1; + view->gui->set_parameter(view->gui, view->param_selected, view->paramMappedValues[view->param_selected]); + } + } + } + view->mouse_old_y = y; } -void asid_gui_on_param_set(asid_gui gui, uint32_t id, float value) { +static void view_on_param_set(asid_gui_view view, uint32_t id, float value) { if (id == 3) { - gui->modCutoffValue = value; + view->modCutoffValue = value; char screen_map_selected_new; if (value < 0.25f) { screen_map_selected_new = 0; @@ -751,132 +697,229 @@ void asid_gui_on_param_set(asid_gui gui, uint32_t id, float value) { screen_map_selected_new = 3; } - gui->screen_map_selected = screen_map_selected_new; - gui->modCutoffToRedraw = 1; + view->screen_map_selected = screen_map_selected_new; + view->modCutoffToRedraw = 1; } else { - if (gui->paramToRedraw[id] == -1) // Set by the gui - gui->paramToRedraw[id] = 1; + if (view->paramToRedraw[id] == -1) {// Set by the gui + view->paramToRedraw[id] = 1; return; - gui->paramValues[id] = clipF(value, 0.f, 1.f); - float newMappedV = floorI(gui->paramValues[id] * 15.f) * 0.0666666666666666f; - if (gui->paramMappedValues[id] != newMappedV) { - gui->paramMappedValues[id] = newMappedV; - gui->paramToRedraw[id] = 1; + } + view->paramValues[id] = clipF(value, 0.f, 1.f); + float newMappedV = floorI(view->paramValues[id] * 15.f) * 0.0666666666666666f; + if (view->paramMappedValues[id] != newMappedV) { + view->paramMappedValues[id] = newMappedV; + view->paramToRedraw[id] = 1; } } } -uint32_t asid_gui_view_get_width(asid_gui gui, asid_gui_view view) { - return gui_window_get_width(view); +asid_gui asid_gui_new( + float (*get_parameter)(asid_gui gui, uint32_t id), + void (*set_parameter)(asid_gui gui, uint32_t id, float value), + void *data +) { + asid_gui ret = (asid_gui)malloc(sizeof(struct _asid_gui)); + if (!ret) + return NULL; + + ret->g = gui_new(); + if (ret->g == NULL) { + free(ret); + return NULL; + } + + ret->get_parameter = get_parameter; + ret->set_parameter = set_parameter; + ret->data = data; + ret->views = NULL; + + return ret; } -uint32_t asid_gui_view_get_height(asid_gui gui, asid_gui_view view) { - return gui_window_get_height(view); +void asid_gui_free(asid_gui gui) { + gui_free(gui->g); + free(gui); } -uint32_t asid_gui_view_get_default_width(asid_gui gui) { +void asid_gui_process_events(asid_gui gui) { + gui_run(gui->g, 1); +} + +uint32_t asid_gui_get_default_width(asid_gui gui) { return width_default; } -uint32_t asid_gui_view_get_default_height(asid_gui gui) { +uint32_t asid_gui_get_default_height(asid_gui gui) { return height_default; } +void *asid_gui_get_data(asid_gui gui) { + return gui->data; +} -void asid_on_mouse_press (asid_gui gui, int x, int y) { - x = (int) (((float) (x - (int) gui->xContent)) * gui->scaleFactorInv); - y = (int) (((float) (y - (int) gui->yContent)) * gui->scaleFactorInv); +void asid_gui_on_param_set(asid_gui gui, uint32_t id, float value) { + for (asid_gui_view view = gui->views; view; view = view->next) + view_on_param_set(view, id, value); +} - if (y >= paramboxs_y1 && y <= paramboxs_y2) { - if (x >= parambox_cutoff_x1 && x <= parambox_cutoff_x2) { - gui->param_selected = 0; - } - else if (x >= parambox_lfoamt_x1 && x <= parambox_lfoamt_x2) { - gui->param_selected = 1; - } - else if (x >= parambox_lfospd_x1 && x <= parambox_lfospd_x2) { - gui->param_selected = 2; - } - else { - gui->param_selected = -1; - } - gui->mouse_old_y = y; +asid_gui_view asid_gui_view_new(asid_gui gui, void *parent) { + asid_gui_view ret = (asid_gui_view)malloc(sizeof(struct _asid_gui_view)); + if (ret == NULL) + return NULL; + + ret->gui = gui; + + ret->screen_maps[0] = (unsigned char*) malloc(inner_size_pixel); + ret->screen_maps[1] = (unsigned char*) malloc(inner_size_pixel); + ret->screen_maps[2] = (unsigned char*) malloc(inner_size_pixel); + ret->screen_maps[3] = (unsigned char*) malloc(inner_size_pixel); + + if (!ret->screen_maps[0] || !ret->screen_maps[1] || !ret->screen_maps[2] || !ret->screen_maps[3]) { + for (int i = 0; i < 4; i++) + if (ret->screen_maps[i]) + free(ret->screen_maps[i]); + return NULL; } -} -void asid_on_mouse_release (asid_gui gui) { - gui->param_selected = -1; - //gui->mouse_old_y = 0; // Maybe something better -} + memcpy(ret->screen_maps[0], screen_map_defaults[0], inner_size_pixel); + memcpy(ret->screen_maps[1], screen_map_defaults[1], inner_size_pixel); + memcpy(ret->screen_maps[2], screen_map_defaults[2], inner_size_pixel); + memcpy(ret->screen_maps[3], screen_map_defaults[3], inner_size_pixel); -void asid_on_mouse_move (asid_gui gui, int x, int y, uint32_t mouseState) { - x = (int) (((float) (x - (int) gui->xContent)) * gui->scaleFactorInv); - y = (int) (((float) (y - (int) gui->yContent)) * gui->scaleFactorInv); + ret->resized[0] = NULL; + ret->resized[1] = NULL; + ret->resized[2] = NULL; + ret->resized[3] = NULL; - // Hover - if (gui->param_selected == -1) { - char old_param_hover = gui->param_hover; - if (y >= paramboxs_y1 && y <= paramboxs_y2) { - if (x >= parambox_cutoff_x1 && x <= parambox_cutoff_x2) - gui->param_hover = 0; - else if (x >= parambox_lfoamt_x1 && x <= parambox_lfoamt_x2) - gui->param_hover = 1; - else if (x >= parambox_lfospd_x1 && x <= parambox_lfospd_x2) - gui->param_hover = 2; - else - gui->param_hover = -1; - } - else - gui->param_hover = -1; + ret->scaleFactor = 1.f; + ret->scaleFactorInv = 1.f; - if (old_param_hover == gui->param_hover) - ; - else { - if (old_param_hover != -1) - gui->paramToRedraw[old_param_hover] = 1; - if (gui->param_hover != -1) - gui->paramToRedraw[gui->param_hover] = 1; - if (gui->paramToRedraw[0]) - gui->modCutoffToRedraw = 1; - } + ret->w = width_default; + ret->h = height_default; + + ret->xWhite = 0; + ret->yWhite = 0; + ret->wWhite = width_default; + ret->hWhite = height_default; + + ret->xContent = padding_default; + ret->yContent = padding_default; + ret->wContent = inner_width_default; + ret->hContent = inner_height_default; + + ret->xCutoff = param_cutoff_x1; + ret->xAmount = param_lfoamt_x1; + ret->xSpeed = param_lfospd_x1; + ret->yParams = params_y1; + ret->wParams = params_w; + ret->hParams = params_h; + + ret->xBoxCutoff = parambox_cutoff_x1; + ret->xBoxAmount = parambox_lfoamt_x1; + ret->xBoxSpeed = parambox_lfospd_x1; + ret->yBoxParams = paramboxs_y1; + ret->wBoxParams = paramboxs_w; + ret->hBoxParams = paramboxs_h; + + ret->xModCutoff = modCutoff_x1; + ret->yModCutoff = modCutoff_y1; + ret->wModCutoff = modCutoff_w; + ret->hModCutoff = modCutoff_h; + + ret->paramValues[0] = gui->get_parameter(gui, 0); + ret->paramValues[1] = gui->get_parameter(gui, 1); + ret->paramValues[2] = gui->get_parameter(gui, 2); + + ret->paramMappedValues[0] = floorI(ret->paramValues[0] * 15.f) * 0.0666666666666666f; + ret->paramMappedValues[1] = floorI(ret->paramValues[1] * 15.f) * 0.0666666666666666f; + ret->paramMappedValues[2] = floorI(ret->paramValues[2] * 15.f) * 0.0666666666666666f; + + ret->param_hover = -1; // -1 = None, 0 = cutoff, 1 = amount, 2 = speed + ret->param_selected = -1; // -1 = None, 0 = cutoff, 1 = amount, 2 = speed + ret->mouse_old_y = 0; + + ret->screen_map_selected = 3; + + ret->modCutoffValue = 0.f; + + // Redrawing state + ret->paramToRedraw[0] = 0; + ret->paramToRedraw[1] = 0; + ret->paramToRedraw[2] = 0; + ret->modCutoffToRedraw = 0; + ret->toResize = 0; + + ret->win = gui_window_new(gui->g, parent, width_default, height_default); + if (ret->win == NULL) { + for (int i = 0; i < 4; i++) + free(ret->screen_maps[i]); + free(ret); + return NULL; } - // Mouse diff - if (gui->param_selected != -1 && mouseState > 0) { - float diff = ((float) (gui->mouse_old_y - y)) / (float) params_h; - if (diff != 0.f) { - gui->paramValues[gui->param_selected] = clipF(gui->paramValues[gui->param_selected] + diff, 0.f, 1.f); - float newMappedV = floorI(gui->paramValues[gui->param_selected] * 15.f) * 0.0666666666666666f; - if (gui->paramMappedValues[gui->param_selected] != newMappedV) { - gui->paramMappedValues[gui->param_selected] = newMappedV; - gui->paramToRedraw[gui->param_selected] = -1; - EditController *c = (EditController *) gui->handle; - c->beginEdit(gui->param_selected); - c->performEdit(gui->param_selected, gui->paramMappedValues[gui->param_selected]); - c->endEdit(gui->param_selected); - } - } + ret->next = NULL; + if (gui->views == NULL) + gui->views = ret; + else { + asid_gui_view n = gui->views; + while (n->next) + n = n->next; + n->next = ret; } - gui->mouse_old_y = y; + + gui_window_set_data(ret->win, (void *)ret); + gui_window_set_cb(ret->win, GUI_CB_RESIZE, (gui_cb)on_resize); + gui_window_set_cb(ret->win, GUI_CB_MOUSE_PRESS, (gui_cb)on_mouse_press); + gui_window_set_cb(ret->win, GUI_CB_MOUSE_RELEASE, (gui_cb)on_mouse_release); + gui_window_set_cb(ret->win, GUI_CB_MOUSE_MOVE, (gui_cb)on_mouse_move); + + gui_window_show (ret->win); + + resize(ret, width_default, height_default); + draw_parameter_fixed(ret, 0); + draw_parameter_fixed(ret, 1); + draw_parameter_fixed(ret, 2); + + return ret; } -void asid_on_timeout (asid_gui gui) { - struct timeval stop, start; - gettimeofday(&start, NULL); +void asid_gui_view_free(asid_gui_view view) { + if (view->gui->views == view) + view->gui->views = view->next; + else { + asid_gui_view n = view->gui->views; + while (n->next != view) + n = n->next; + n->next = view->next; + } - if (gui != NULL) - piggyback_draw(gui); - - gettimeofday(&stop, NULL); - - const time_t elapsed = ((stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec) / 1000; - uint32_t nextMs = elapsed < 20 ? 20 - elapsed : 1; - - gui_set_timeout (gui->window, nextMs); + for (int i = 0; i < 4; i++) { + free(view->screen_maps[i]); + if (view->resized[i]) + free(view->resized[i]); + } + gui_window_free(view->win); + free(view); } -#ifdef __cplusplus +void asid_gui_view_resize_window(asid_gui_view view, uint32_t width, uint32_t height) { + gui_window_resize(view->win, width, height); +} + +void *asid_gui_view_get_handle(asid_gui_view view) { + return gui_window_get_handle(view->win); +} + +uint32_t asid_gui_view_get_width(asid_gui_view view) { + return gui_window_get_width(view->win); +} + +uint32_t asid_gui_view_get_height(asid_gui_view view) { + return gui_window_get_height(view->win); +} + +void asid_gui_view_on_timeout(asid_gui_view view) { + draw(view); } -#endif diff --git a/vst3/src/asid_gui.h b/vst3/src/asid_gui.h index 01f75e2..fd5e0ae 100644 --- a/vst3/src/asid_gui.h +++ b/vst3/src/asid_gui.h @@ -17,49 +17,37 @@ * File authors: Stefano D'Angelo, Paolo Marrone */ - #ifndef _ASID_GUI_H #define _ASID_GUI_H +#include + #ifdef __cplusplus extern "C" { #endif -#include - typedef struct _asid_gui* asid_gui; +typedef struct _asid_gui_view* asid_gui_view; -#ifdef _WIN32 - -#include "gui-win32.h" - -#endif - -#ifdef linux - -#include "gui-x.h" - -#endif - -asid_gui asid_gui_new(void *handle); +asid_gui asid_gui_new( + float (*get_parameter)(asid_gui gui, uint32_t id), + void (*set_parameter)(asid_gui gui, uint32_t id, float value), + void *data +); void asid_gui_free(asid_gui gui); -void asid_gui_set_set_parameter(asid_gui gui, void (*set_parameter)(void *handle, uint32_t id, float value)); +void asid_gui_process_events(asid_gui gui); +uint32_t asid_gui_get_default_width(asid_gui gui); +uint32_t asid_gui_get_default_height(asid_gui gui); +void *asid_gui_get_data(asid_gui gui); void asid_gui_on_param_set(asid_gui gui, uint32_t id, float value); -typedef window asid_gui_view; - asid_gui_view asid_gui_view_new(asid_gui gui, void *parent); -void asid_gui_view_free(asid_gui gui, asid_gui_view view); -uint32_t asid_gui_view_get_width(asid_gui gui, asid_gui_view view); -uint32_t asid_gui_view_get_height(asid_gui gui, asid_gui_view view); -void asid_gui_view_resize(asid_gui gui, asid_gui_view view, uint32_t width, uint32_t height); -uint32_t asid_gui_view_get_default_width(asid_gui gui); -uint32_t asid_gui_view_get_default_height(asid_gui gui); - -void asid_on_mouse_press (asid_gui gui, int x, int y); -void asid_on_mouse_release (asid_gui gui); -void asid_on_mouse_move (asid_gui gui, int x, int y, uint32_t mouseState); -void asid_on_timeout (asid_gui gui); +void asid_gui_view_free(asid_gui_view view); +void asid_gui_view_resize_window(asid_gui_view view, uint32_t width, uint32_t height); +void *asid_gui_view_get_handle(asid_gui_view view); +uint32_t asid_gui_view_get_width(asid_gui_view view); +uint32_t asid_gui_view_get_height(asid_gui_view view); +void asid_gui_view_on_timeout(asid_gui_view view); #ifdef __cplusplus } diff --git a/vst3/src/gui-cocoa.mm b/vst3/src/gui-cocoa.mm new file mode 100644 index 0000000..ff64abf --- /dev/null +++ b/vst3/src/gui-cocoa.mm @@ -0,0 +1,309 @@ +/* + * A-SID - C64 bandpass filter + LFO + * + * Copyright (C) 2022 Orastron srl unipersonale + * + * A-SID 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, version 3 of the License. + * + * A-SID 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 + * + * File authors: Paolo Marrone + */ + +#include "gui.h" + +#import + +struct _window; + +@interface GuiView : NSView { + NSTrackingArea* tracking; + @public struct _window* win; +} +@end + +struct _window { + gui g; + struct _window* next; + NSWindow* nswindow; + GuiView* view; + unsigned char* img; + NSImage* nsImage; + uint16_t width; + uint16_t height; + void* data; + gui_cb resize_cb; + gui_cb mouse_press_cb; + gui_cb mouse_release_cb; + gui_cb mouse_move_cb; +}; + +struct _gui { + window windows; + NSApplication* app; + NSAutoreleasePool* pool; +}; + +@implementation GuiView + +- (void) updateTrackingAreas { + + [self removeTrackingArea]; + NSTrackingAreaOptions options = + NSTrackingActiveAlways + | NSTrackingInVisibleRect + | NSTrackingMouseEnteredAndExited + | NSTrackingMouseMoved; + + tracking = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:options + owner:self + userInfo:nil]; + + [self addTrackingArea:tracking]; + [super updateTrackingAreas]; +} + +- (void) removeTrackingArea { + if (tracking) { + [super removeTrackingArea:tracking]; + [tracking release]; + tracking = 0; + } +} + +- (void) mouseDown : (NSEvent *) e { + window w = self->win; + NSPoint p = [self convertPoint:[e locationInWindow] fromView:nil]; + if (w->mouse_press_cb) + ((void(*)(window, int32_t, int32_t))w->mouse_press_cb)(w, (int32_t)p.x, self.frame.size.height - (int32_t)p.y); +} + +- (void) mouseUp : (NSEvent *) e { + window w = self->win; + NSPoint p = [self convertPoint:[e locationInWindow] fromView:nil]; + + if (w->mouse_release_cb) + ((void(*)(window, int32_t, int32_t))w->mouse_release_cb)(w, (int32_t)p.x, self.frame.size.height - (int32_t)p.y); +} + +- (void) mouseMoved : (NSEvent *) e { + window w = self->win; + NSPoint p = [self convertPoint:[e locationInWindow] fromView:nil]; + + if (w->mouse_move_cb) + ((void(*)(window, int32_t, int32_t, uint32_t))w->mouse_move_cb)(w, (int32_t)p.x, self.frame.size.height - (int32_t)p.y, 1); +} + +- (void) mouseDragged : (NSEvent *) e { + window w = self->win; + NSPoint p = [self convertPoint:[e locationInWindow] fromView:nil]; + + if (w->mouse_move_cb) + ((void(*)(window, int32_t, int32_t, uint32_t))w->mouse_move_cb)(w, (int32_t)p.x, self.frame.size.height - (int32_t)p.y, 1); +} + +- (void) drawRect:(NSRect) r { + [self->win->nsImage drawInRect:r fromRect:r operation:NSCompositingOperationCopy fraction:1.0]; +} + +@end + +static void resized (window win, int32_t w, int32_t h) { + if (win->resize_cb) + ((void(*)(window, uint32_t, uint32_t))win->resize_cb)(win, w, h); +} + +gui gui_new() { + gui g = (gui) malloc(sizeof(struct _gui)); + g->windows = NULL; + g->pool = [[NSAutoreleasePool alloc] init]; + g->app = [NSApplication sharedApplication]; + return g; +} + +void gui_free(gui g) { + free(g); +} + +void gui_run(gui g, char single) { + [g->app run]; +} + +void gui_stop (gui g) { + [g->app stop:nullptr]; +} + +window gui_window_new(gui g, void* parent, uint32_t width, uint32_t height) { + + window ret = (window) malloc(sizeof(_window)); + if (ret == NULL) + return NULL; + + NSRect frame = NSMakeRect(0, 0, width, height); + + GuiView* view = [[GuiView alloc] initWithFrame:frame]; + view->win = ret; + + [((NSView*)parent) addSubview:view positioned:NSWindowAbove relativeTo:nil]; + + [view autorelease]; + + ret->g = g; + ret->view = view; + ret->nswindow = [(NSView*)parent window]; + ret->img = (unsigned char*) malloc(width * height * 4); + ret->data = NULL; + ret->nsImage = NULL; + ret->width = width; + ret->height = height; + ret->next = NULL; + + if (g->windows == NULL) + g->windows = ret; + else { + window cur = g->windows; + while (cur->next != NULL) + cur = cur->next; + cur->next = ret; + } + + return ret; +} + +void gui_window_free(window w) { + if (w->g->windows == w) { + w->g->windows = w->next; + } + else { + window cur = w->g->windows; + while (cur != NULL && cur->next != w) + cur = cur->next; + if (cur == NULL) + return; + cur->next = w->next; + } + + [w->view removeTrackingArea]; + free(w->img); + free(w); +} + +void gui_window_draw(window w, unsigned char* img, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, uint32_t wx, uint32_t wy, uint32_t width, uint32_t height) { + if (w->img == NULL) + return; + + uint32_t iw = (wy * w->width + wx); + uint32_t o = (dy * dw + dx); + uint32_t p1 = (dw - width); + uint32_t p2 = (w->width - width); + + const uint32_t* img32 = (uint32_t*) img; + uint32_t* wimg32 = (uint32_t*) w->img; + + for (uint32_t y = dy; y < dy + height && y < dh; y++) { + for (uint32_t x = dx; x < dx + width; x++, o++, iw++) { + const uint32_t p = img32[o]; + wimg32[iw] = (p & 0xFF00FF00) | ((p >> 16) & 0x000000FF) | ((p << 16) & 0x00FF0000); + } + iw += p2; + o += p1; + } + + CGDataProviderRef provider = CGDataProviderCreateWithData( + NULL, // void *info + w->img, // const void *data + w->width * w->height * 4, // size_t size + NULL // CGDataProviderReleaseDataCallback releaseData + ); + + CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; + CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; + + CGImageRef imageRef = CGImageCreate( + w->width, // size_t width + w->height, // size_t height + 8, // size_t bitsPerComponent + 4 * 8, // size_t bitsPerPixel + w->width * 4, // size_t bytesPerRow + colorSpaceRef, // CGColorSpaceRef space + bitmapInfo, // CGBitmapInfo bitmapInfo + provider, // CGDataProviderRef provider + NULL, // const CGFloat *decode + NO, // bool shouldInterpolate + renderingIntent // CGColorRenderingIntent intent + ); + + NSImage* image = [[NSImage alloc] initWithCGImage: imageRef size:NSZeroSize]; + [w->nsImage release]; + w->nsImage = image; + + [w->view setNeedsDisplayInRect:NSMakeRect(wx, w->height - (wy + height), width, height)]; + + CGDataProviderRelease(provider); + CGColorSpaceRelease(colorSpaceRef); + CGImageRelease(imageRef); +} + +void gui_window_resize (window w, uint32_t width, uint32_t height) { + NSSize newSize = NSMakeSize(width, height); + [w->view setFrameSize:newSize]; + w->width = width; + w->height = height; + w->img = (unsigned char*)realloc(w->img, width * height * 4); + + resized(w, width, height); +} + +void* gui_window_get_handle(window w) { + return w->view; +} + +uint32_t gui_window_get_width(window w) { + return w->width; +} +uint32_t gui_window_get_height(window w) { + return w->height; +} + +void gui_window_show(window w) { + // Can we? nswindow comes from outside + //[w->nswindow setIsVisible:YES]; +} + +void gui_window_hide(window w) { + //[w->nswindow setIsVisible:NO]; +} + +void gui_window_set_data(window w, void *data) { + w->data = data; +} + +void *gui_window_get_data(window w) { + return w->data; +} + +void gui_window_set_cb(window w, gui_cb_type type, gui_cb cb) { + switch (type) { + case GUI_CB_RESIZE: + w->resize_cb = cb; + break; + case GUI_CB_MOUSE_PRESS: + w->mouse_press_cb = cb; + break; + case GUI_CB_MOUSE_RELEASE: + w->mouse_release_cb = cb; + break; + case GUI_CB_MOUSE_MOVE: + w->mouse_move_cb = cb; + break; + } +} diff --git a/vst3/src/gui-win32.c b/vst3/src/gui-win32.c index a8e1981..a0f8616 100644 --- a/vst3/src/gui-win32.c +++ b/vst3/src/gui-win32.c @@ -14,83 +14,49 @@ * * You should have received a copy of the GNU General Public License * - * File author: Paolo Marrone + * File author: Paolo Marrone, Stefano D'Angelo */ -extern "C" { - -#include #include +#include -#include "gui-win32.h" -#include "asid_gui.h" +#include "gui.h" -static const char g_szClassName[] = "guiWindowClass"; -static char keep_running; +typedef struct _window { + gui g; + struct _window *next; + HWND handle; + HBITMAP bitmap; + BITMAPINFOHEADER bitmap_info; + uint8_t *bgra; + char mouse_tracking; + void *data; + gui_cb resize_cb; + gui_cb mouse_press_cb; + gui_cb mouse_release_cb; + gui_cb mouse_move_cb; +} *window; -static TRACKMOUSEEVENT tme = {0}; // Tmp -static char m_bMouseTracking = 0; // Tmp +typedef struct _gui { + char keep_running; +} *gui; -static window firstWindow; - -int instanceCounter = 0; - -struct _window { - window next; - HWND handle; - asid_gui gui; - unsigned char* argb; - HBITMAP map; - uint32_t width, height; -}; - -static window findWin(HWND handle) { - window winCur = firstWindow; - while (winCur) { - if (winCur->handle == handle) - return winCur; - winCur = winCur->next; - } - return NULL; -} - -static void window_draw_ (HWND w, HBITMAP map, uint32_t srcX, uint32_t srcY, uint32_t destX, uint32_t destY, uint32_t width, uint32_t height) { - // Temp HDC to copy picture - HDC tmp = GetDC(NULL); - HDC src = CreateCompatibleDC(tmp); // hdc - Device context for window - SelectObject(src, map); // Inserting picture into our temp HDC - HDC dest = GetDC(w); - // Copy image from temp HDC to window - BitBlt( - dest, // Destination - (int) destX, // x and - (int) destY, // y - upper-left corner of place, where we'd like to copy - (int) width, // width of the region - (int) height, - src, // source - (int) srcX, // x and - (int) srcY, // y of upper left corner of part of the source, from where we'd like to copy - SRCCOPY // Defined DWORD to juct copy pixels. Watch more on msdn; - ); - ReleaseDC(w, dest); - DeleteDC(src); // Deleting temp HDC - DeleteDC(tmp); -} +static const char* class_name = "guiWindowClass"; +char gui_new_count = 0; +window windows = NULL; static uint32_t get_mouse_state(WPARAM wParam) { - return - (wParam & (MK_LBUTTON | MK_RBUTTON)) - | ((wParam & MK_MBUTTON) >> 2); + return (wParam & (MK_LBUTTON | MK_RBUTTON)) | ((wParam & MK_MBUTTON) >> 2); } - -static LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - window w = findWin(hwnd); +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + window w = windows; + while (w && w->handle != hwnd) + w = w->next; if (w == NULL) - return 1; + return DefWindowProc(hwnd, msg, wParam, lParam); DWORD pos; - uint32_t wt, ht; POINTS points; switch(msg) { @@ -99,251 +65,228 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPar case WM_RBUTTONDOWN: points = MAKEPOINTS(lParam); SetCapture(hwnd); - asid_on_mouse_press(w->gui, points.x, points.y); - //MessageBox(NULL, "Click", "Click!", MB_OK); + if (w->mouse_press_cb) + ((void(*)(window, int32_t, int32_t))w->mouse_press_cb)(w, points.x, points.y); break; case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: - points = MAKEPOINTS(lParam); - wt = get_mouse_state(wParam); - if (wt == 0) + points = MAKEPOINTS(lParam); + if (get_mouse_state(wParam) == 0) ReleaseCapture(); - asid_on_mouse_release(w->gui); + if (w->mouse_release_cb) + ((void(*)(window, int32_t, int32_t))w->mouse_release_cb)(w, points.x, points.y); break; case WM_MOUSEMOVE: - if (!m_bMouseTracking) + if (!w->mouse_tracking) { - // Enable mouse tracking. + TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = hwnd; tme.dwFlags = TME_HOVER | TME_LEAVE; tme.dwHoverTime = HOVER_DEFAULT; TrackMouseEvent(&tme); - m_bMouseTracking = 1; + w->mouse_tracking = 1; } - points = MAKEPOINTS(lParam); - asid_on_mouse_move(w->gui, points.x, points.y, get_mouse_state(wParam)); + if (w->mouse_move_cb) + ((void(*)(window, int32_t, int32_t, uint32_t))w->mouse_move_cb)(w, points.x, points.y, get_mouse_state(wParam)); break; case WM_MOUSELEAVE: - points = MAKEPOINTS(lParam); - m_bMouseTracking = 0; - break; - case WM_KEYDOWN: - break; - case WM_KEYUP: - break; - case WM_CLOSE: - DestroyWindow(hwnd); - break; - case WM_DESTROY: - PostQuitMessage(0); + w->mouse_tracking = 0; break; case WM_SIZE: - wt = (uint32_t) LOWORD(lParam); - ht = (uint32_t) HIWORD(lParam); - if (wt > 0 && ht > 0) { - //w->width = wt; - //w->height = ht; - //on_window_resize(ww, wt, ht); - } + { + uint32_t width = LOWORD(lParam); + uint32_t height = HIWORD(lParam); + DeleteObject(w->bitmap); + w->bitmap_info.biWidth = width; + w->bitmap_info.biHeight = -height; + HDC dc = GetDC(w->handle); + w->bitmap = CreateDIBSection(dc, (BITMAPINFO*)&w->bitmap_info, DIB_RGB_COLORS, (void **)&w->bgra, NULL, 0); + ReleaseDC(w->handle, dc); + if (w->resize_cb) + ((void(*)(window, uint32_t, uint32_t))w->resize_cb)(w, width, height); + } break; case WM_PAINT: - BeginPaint(hwnd, NULL); - if (w != NULL && w->map != NULL) { - window_draw_(hwnd, w->map, 0, 0, 0, 0, w->width, w->height); + { + RECT r; + if (GetUpdateRect(hwnd, &r, 0)) { + PAINTSTRUCT ps; + HDC dc = BeginPaint(hwnd, &ps); + SetDIBitsToDevice(dc, r.left, r.top, r.right - r.left, r.bottom - r.top, r.left, gui_window_get_height(w) - r.bottom, 0, -w->bitmap_info.biHeight, w->bgra, (BITMAPINFO*)&w->bitmap_info, DIB_RGB_COLORS); + EndPaint(hwnd, &ps); } - EndPaint(hwnd, NULL); - break; - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return 0; -} - - -int32_t gui_init () { - instanceCounter++; - - WNDCLASSEX wc; - - wc.cbSize = sizeof(wc); - wc.style = 0; // CS_HREDRAW | CS_VREDRAW; // redraw if size changes - wc.lpfnWndProc = WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = NULL; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(WHITE_BRUSH); - wc.lpszMenuName = NULL; - wc.lpszClassName = g_szClassName; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - ATOM wcATOM = RegisterClassEx(&wc); - if(!wcATOM) { - // Probably it got already registered - return 1; - } - - firstWindow = NULL; - - return 0; -} - -/* -static uint32_t count_windows() { - uint32_t counter = 0; - if (firstWindow != NULL) { - counter++; - window winCur = firstWindow; - while (winCur->next != NULL) { - counter++; - winCur = winCur->next; } - } - return counter; -} -*/ - -void gui_fini () { - instanceCounter--; - - if (instanceCounter <= 0) { // Concurrency problem? - instanceCounter = 0; - UnregisterClass(g_szClassName, NULL); - } -} - - -window gui_window_new (void* parent, uint32_t width, uint32_t height, asid_gui gui) { - - HWND* hwndParent = (HWND*) parent; - - HWND hwnd = CreateWindowEx( - WS_EX_CLIENTEDGE, - g_szClassName, - "ASID", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, width, height, - NULL, NULL, NULL, NULL - ); - - if(hwnd == NULL) - { - MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); - return NULL; + break; } - - SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ! WS_BORDER & ! WS_SIZEBOX & ! WS_DLGFRAME ); - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - - - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hwnd; - TrackMouseEvent(&tme); - - UpdateWindow(hwnd); - SetParent(hwnd, *hwndParent); - - - window newWindow = (window) malloc(sizeof(struct _window)); - if (newWindow == NULL) - return NULL; - newWindow->next = NULL; - newWindow->handle = hwnd; - newWindow->width = width; - newWindow->height = height; - newWindow->argb = NULL; /*(unsigned char*) malloc(4 * newWindow->width * newWindow->height); - if (newWindow->argb == NULL) { - MessageBox(NULL, "Memory error", "Error!", MB_ICONEXCLAMATION | MB_OK); - return NULL; - } - */ - newWindow->map = NULL; - newWindow->gui = gui; - - if (firstWindow == NULL) - firstWindow = newWindow; - else { - window winCur = firstWindow; - while (winCur->next != NULL) - winCur = winCur->next; - winCur->next = newWindow; - } - - return newWindow; - + return DefWindowProc(hwnd, msg, wParam, lParam); } -void gui_window_free (window w) { - if (w == firstWindow) - firstWindow = w->next; - else { - window winCur = firstWindow; - while (winCur->next != w) - winCur = winCur->next; - winCur->next = w->next; +gui gui_new() { + gui g = (gui)malloc(sizeof(struct _gui)); + if (!g) + return NULL; + + if (!gui_new_count) { + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = NULL; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = class_name; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + RegisterClassEx(&wc); } + gui_new_count++; - //free(w->argb); - DeleteObject(w->map); + return g; +} + +void gui_free(gui g) { + free(g); + gui_new_count--; + if (!gui_new_count) + UnregisterClass(class_name, NULL); +} + +void gui_run(gui g, char single) { + g->keep_running = 1; + MSG msg; + while (g->keep_running) { + if (single) { + BOOL b = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); + if (!b) + break; + } else { + BOOL b = GetMessage(&msg, NULL, 0, 0); + if (b <= 0) + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void gui_stop(gui g) { + g->keep_running = 0; +} + +window gui_window_new(gui g, void* parent, uint32_t width, uint32_t height) { + window w = (window)malloc(sizeof(struct _window)); + if (w == NULL) + return NULL; + + w->handle = CreateWindowEx(0, class_name, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, NULL, NULL); + if (w->handle == NULL) { + free(w); + return NULL; + } + + ZeroMemory(&w->bitmap_info, sizeof(BITMAPINFOHEADER)); + w->bitmap_info.biSize = sizeof(BITMAPINFOHEADER); + w->bitmap_info.biWidth = width; + w->bitmap_info.biHeight = -height; + w->bitmap_info.biPlanes = 1; + w->bitmap_info.biBitCount = 32; + w->bitmap_info.biCompression = BI_RGB; + HDC dc = GetDC(w->handle); + w->bitmap = CreateDIBSection(dc, (BITMAPINFO*)&w->bitmap_info, DIB_RGB_COLORS, (void **)&w->bgra, NULL, 0); + ReleaseDC(w->handle, dc); + if (w->bitmap == NULL) { + DestroyWindow(w->handle); + free(w); + return NULL; + } + + if (parent) { + SetParent(w->handle, *((HWND *)parent)); + SetWindowLong(w->handle, GWL_STYLE, GetWindowLong(w->handle, GWL_STYLE) & ! WS_BORDER & ! WS_SIZEBOX & ! WS_DLGFRAME ); + SetWindowPos(w->handle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + } + + w->next = NULL; + if (windows == NULL) + windows = w; + else { + window n = windows; + while (n->next) + n = n->next; + n->next = w; + } + + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = w->handle; + TrackMouseEvent(&tme); + w->mouse_tracking = 1; + + w->data = NULL; + w->resize_cb = NULL; + w->mouse_press_cb = NULL; + w->mouse_release_cb = NULL; + w->mouse_move_cb = NULL; + + UpdateWindow(w->handle); + + return w; +} + +void gui_window_free(window w) { + if (windows == w) + windows = w->next; + else { + window n = windows; + while (n->next != w) + n = n->next; + n->next = w->next; + } + + DeleteObject(w->bitmap); DestroyWindow(w->handle); free(w); } - -void gui_window_draw (window win, unsigned char *data, - uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, - uint32_t wx, uint32_t wy, uint32_t width, uint32_t height) -{ - - win->argb = data; - - DeleteObject(win->map); - win->map = CreateBitmap( - (int) win->width, - (int) win->height, - 1, // color planes - 32, // Size of memory for one pixel in bits - win->argb // src - ); - - BeginPaint(win->handle, NULL); - window_draw_(win->handle, win->map, wx, wy, wx, wy, width, height); - EndPaint(win->handle, NULL); +void gui_window_draw(window w, unsigned char *data, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, uint32_t wx, uint32_t wy, uint32_t width, uint32_t height) { + uint32_t *src = ((uint32_t *)data) + dw * dy + dx; + uint32_t *dest = ((uint32_t *)w->bgra) + w->bitmap_info.biWidth * wy + wx; + for (uint32_t h = height; h; h--, src += dw, dest += w->bitmap_info.biWidth) + memcpy(dest, src, 4 * width); + + RECT r; + r.left = wx; + r.top = wy; + r.right = wx + width; + r.bottom = wy + height; + RedrawWindow(w->handle, &r, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } +void gui_window_resize(window w, uint32_t width, uint32_t height) { + SetWindowPos(w->handle, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER); +} void *gui_window_get_handle(window w) { return w->handle; } -void gui_window_move(window w, uint32_t x, uint32_t y) { - SetWindowPos(w->handle, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); -} - -void gui_window_resize(window w, uint32_t width, uint32_t height) { - w->width = width; - w->height = height; - w->map = NULL; - /* - w->argb = (unsigned char*) realloc(w->argb, 4 * w->width * w->height); - if (w->argb == NULL) { - MessageBox(NULL, "Resize memory error", "Error!", MB_ICONEXCLAMATION | MB_OK); - return; - } - */ - SetWindowPos(w->handle, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER); -} - uint32_t gui_window_get_width(window w) { - return w->width; + RECT r; + GetWindowRect(w->handle, &r); + return r.right - r.left; } + uint32_t gui_window_get_height(window w) { - return w->height; + RECT r; + GetWindowRect(w->handle, &r); + return r.bottom - r.top; } void gui_window_show(window w) { @@ -354,37 +297,27 @@ void gui_window_hide(window w) { ShowWindow(w->handle, SW_HIDE); } -void gui_run () { - keep_running = 1; - MSG Msg; - while(keep_running && GetMessage(&Msg, NULL, 0, 0) > 0) - { - TranslateMessage(&Msg); - DispatchMessage(&Msg); - } +void gui_window_set_data(window w, void *data) { + w->data = data; } -void gui_stop () { - keep_running = 0; +void *gui_window_get_data(window w) { + return w->data; } - -void gui_set_timeout (window w, int32_t value) { - SetTimer( - w->handle, - (UINT_PTR) NULL, - (UINT) value, - gui_on_timeout - ); -} - - -void gui_on_timeout (HWND unnamedParam1, UINT unnamedParam2, UINT_PTR unnamedParam3, DWORD unnamedParam4) { - window w = findWin(unnamedParam1); - if (w == NULL) - return; - - asid_on_timeout(w->gui); -} - -} +void gui_window_set_cb(window w, gui_cb_type type, gui_cb cb) { + switch (type) { + case GUI_CB_RESIZE: + w->resize_cb = cb; + break; + case GUI_CB_MOUSE_PRESS: + w->mouse_press_cb = cb; + break; + case GUI_CB_MOUSE_RELEASE: + w->mouse_release_cb = cb; + break; + case GUI_CB_MOUSE_MOVE: + w->mouse_move_cb = cb; + break; + } +} \ No newline at end of file diff --git a/vst3/src/gui-x.c b/vst3/src/gui-x.c index 9d5001c..42ddd75 100644 --- a/vst3/src/gui-x.c +++ b/vst3/src/gui-x.c @@ -17,34 +17,53 @@ * File authors: Stefano D'Angelo, Paolo Marrone */ -#ifdef __cplusplus -extern "C" { -#endif +#include "gui.h" -#include "gui-x.h" +#include +#include +#include +typedef struct _window { + gui g; + _window *next; + xcb_window_t window; + xcb_pixmap_t pixmap; + xcb_gcontext_t gc; + uint16_t width; + uint16_t height; + void *data; + gui_cb resize_cb; + gui_cb mouse_press_cb; + gui_cb mouse_release_cb; + gui_cb mouse_move_cb; +} *window; -static xcb_connection_t *connection; -static xcb_screen_t *screen; -static const xcb_setup_t *setup; -static xcb_visualtype_t *visual; -static xcb_atom_t wm_protocols_atom; -static xcb_atom_t wm_delete_atom; -static xcb_atom_t xembed_info_atom; -static window windows; -static char keep_running; -static struct timespec ts_timeout; +typedef struct _gui { + xcb_connection_t *connection; + xcb_screen_t *screen; + const xcb_setup_t *setup; + xcb_visualtype_t *visual; + xcb_atom_t xembed_info_atom; + window windows; + char keep_running; +} *gui; -int32_t gui_init() { - connection = xcb_connect(NULL, NULL); - if (xcb_connection_has_error(connection)) { - xcb_disconnect(connection); - return -1; +gui gui_new() { + gui g = (gui) malloc(sizeof(struct _gui)); + if (g == NULL) + return NULL; + + g->connection = xcb_connect(NULL, NULL); + if (xcb_connection_has_error(g->connection)) { + xcb_disconnect(g->connection); + return NULL; } - screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; - setup = xcb_get_setup(connection); + g->screen = xcb_setup_roots_iterator(xcb_get_setup(g->connection)).data; + g->setup = xcb_get_setup(g->connection); - xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen); + xcb_visualtype_iterator_t visual_iter; xcb_intern_atom_reply_t* reply; // stupid C++ and its cross-initialization issues... + + xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(g->screen); xcb_depth_t *depth = NULL; while (depth_iter.rem) { if (depth_iter.data->depth == 24 && depth_iter.data->visuals_len) { @@ -53,146 +72,222 @@ int32_t gui_init() { } xcb_depth_next(&depth_iter); } - if (!depth){ - xcb_disconnect(connection); - return -1; - } + if (!depth) + goto err; - xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth); - visual = NULL; + visual_iter = xcb_depth_visuals_iterator(depth); + g->visual = NULL; while (visual_iter.rem) { if (visual_iter.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR) { - visual = visual_iter.data; + g->visual = visual_iter.data; break; } xcb_visualtype_next(&visual_iter); } - if (!visual) { - xcb_disconnect(connection); - return -1; - } + if (!g->visual) + goto err; - xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(connection, xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS"), NULL); - if (!reply) { - xcb_disconnect(connection); - return -1; - } - wm_protocols_atom = reply->atom; + reply = xcb_intern_atom_reply(g->connection, xcb_intern_atom(g->connection, 0, 12, "_XEMBED_INFO"), NULL); + if (!reply) + goto err; + g->xembed_info_atom = reply->atom; free(reply); - reply = xcb_intern_atom_reply(connection, xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW"), NULL); - if (!reply) { - xcb_disconnect(connection); - return -1; - } - wm_delete_atom = reply->atom; - free(reply); + g->windows = NULL; - reply = xcb_intern_atom_reply(connection, xcb_intern_atom(connection, 0, 12, "_XEMBED_INFO"), NULL); - if (!reply) { - xcb_disconnect(connection); - return -1; - } - xembed_info_atom = reply->atom; - free(reply); - - windows = NULL; - ts_timeout.tv_sec = -1; - - return 0; + return g; err: - // TBD: report - xcb_disconnect(connection); - return -1; + gui_free(g); + return NULL; } -void gui_fini() { - xcb_disconnect(connection); +void gui_free(gui g) { + xcb_disconnect(g->connection); + free(g); +} + +static window get_window(gui g, xcb_window_t xw) { + window w = g->windows; + while (w->window != xw) + w = (window)w->next; + return w; +} + +static uint32_t get_mouse_state(uint16_t state, xcb_button_t last) { + return ( + (state & XCB_BUTTON_MASK_1) >> 8 + | (state & XCB_BUTTON_MASK_2) >> 7 + | (state & XCB_BUTTON_MASK_3) >> 9 ) + ^ (last == 1 ? 1 : (last == 2 ? 4 : (last == 3 ? 2 : 0))) + ; +} + +void gui_run(gui g, char single) { + g->keep_running = 1; + xcb_generic_event_t *ev; + struct pollfd pfd; + pfd.fd = xcb_get_file_descriptor(g->connection); + pfd.events = POLLIN; + while (g->keep_running) { + int err = poll(&pfd, 1, single ? 0 : -1); + if (err == -1) + break; + else if (err == 0 && single) + break; + + while (g->keep_running && (ev = xcb_poll_for_event(g->connection))) { + switch (ev->response_type & ~0x80) { + case XCB_EXPOSE: + { + xcb_expose_event_t *x = (xcb_expose_event_t *)ev; + window w = get_window(g, x->window); + + xcb_copy_area(g->connection, w->pixmap, w->window, w->gc, x->x, x->y, x->x, x->y, x->width, x->height); + xcb_flush(g->connection); + } + break; + + case XCB_CONFIGURE_NOTIFY: + { + xcb_configure_notify_event_t *x = (xcb_configure_notify_event_t *)ev; + window w = get_window(g, x->window); + + if (x->width != w->width || x->height != w->height) { + w->width = x->width; + w->height = x->height; + xcb_free_pixmap(g->connection, w->pixmap); + w->pixmap = xcb_generate_id(g->connection); + xcb_create_pixmap(g->connection, g->screen->root_depth, w->pixmap, w->window, w->width, w->height); + if (w->resize_cb) + ((void(*)(window, uint32_t, uint32_t))w->resize_cb)(w, w->width, w->height); + } + } + break; + + case XCB_BUTTON_PRESS: + { + xcb_button_press_event_t *x = (xcb_button_press_event_t *)ev; + window w = get_window(g, x->event); + // First three buttons + if (x->detail <= 3 && w->mouse_press_cb) + ((void(*)(window, int32_t, int32_t))w->mouse_press_cb)(w, x->event_x, x->event_y); + } + break; + + case XCB_BUTTON_RELEASE: + { + xcb_button_release_event_t *x = (xcb_button_release_event_t *)ev; + window w = get_window(g, x->event); + // First three buttons + if (x->detail <= 3 && w->mouse_release_cb) + ((void(*)(window, int32_t, int32_t))w->mouse_release_cb)(w, x->event_x, x->event_y); + } + break; + + case XCB_MOTION_NOTIFY: + { + xcb_motion_notify_event_t *x = (xcb_motion_notify_event_t *)ev; + window w = get_window(g, x->event); + if (w->mouse_move_cb) + ((void(*)(window, int32_t, int32_t, uint32_t))w->mouse_move_cb)(w, x->event_x, x->event_y, get_mouse_state(x->state, 0)); + } + break; + } + + free(ev); + } + } +} + +void gui_stop(gui g) { + g->keep_running = 0; } #define XEMBED_MAPPED (1 << 0) -window gui_window_new(void* p, uint32_t width, uint32_t height, asid_gui gui) { // To fix +window gui_window_new(gui g, void* p, uint32_t width, uint32_t height) { xcb_window_t *parent = (xcb_window_t *) p; - window ret = (window) malloc(sizeof(_window)); + window ret = (window) malloc(sizeof(struct _window)); if (ret == NULL) return NULL; - ret->window = xcb_generate_id(connection); + ret->window = xcb_generate_id(g->connection); uint32_t mask = XCB_CW_EVENT_MASK; uint32_t values[] = { XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE }; - xcb_create_window(connection, 24, ret->window, parent ? *parent : screen->root, + xcb_create_window(g->connection, 24, ret->window, parent ? *parent : g->screen->root, 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, - visual->visual_id, mask, values); + g->visual->visual_id, mask, values); - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, ret->window, wm_protocols_atom, XCB_ATOM_ATOM, 32, 1, &wm_delete_atom); - - ret->pixmap = xcb_generate_id(connection); - xcb_create_pixmap(connection, screen->root_depth, ret->pixmap, ret->window, width, height); - ret->gc = xcb_generate_id(connection); - xcb_create_gc(connection, ret->gc, ret->pixmap, 0, NULL); + ret->pixmap = xcb_generate_id(g->connection); + xcb_create_pixmap(g->connection, g->screen->root_depth, ret->pixmap, ret->window, width, height); + ret->gc = xcb_generate_id(g->connection); + xcb_create_gc(g->connection, ret->gc, ret->pixmap, 0, NULL); uint32_t xembed_info[] = { 0, 0 }; - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, ret->window, xembed_info_atom, xembed_info_atom, 32, 2, xembed_info); + xcb_change_property(g->connection, XCB_PROP_MODE_REPLACE, ret->window, g->xembed_info_atom, g->xembed_info_atom, 32, 2, xembed_info); - xcb_flush(connection); + xcb_flush(g->connection); ret->next = NULL; - if (windows == NULL) - windows = ret; + if (g->windows == NULL) + g->windows = ret; else { - window n = windows; + window n = g->windows; while (n->next) n = (window) n->next; n->next = ret; } - ret->x = 0; - ret->y = 0; + ret->g = g; ret->width = width; ret->height = height; - + ret->data = NULL; + ret->resize_cb = NULL; + ret->mouse_press_cb = NULL; + ret->mouse_release_cb = NULL; + ret->mouse_move_cb = NULL; + return ret; } void gui_window_free(window w) { - if (windows == w) - windows = w->next; + if (w->g->windows == w) + w->g->windows = w->next; else { - window n = windows; + window n = w->g->windows; while ((window) n->next != w) n = (window) n->next; n->next = w->next; } - xcb_free_gc(connection, w->gc); - xcb_free_pixmap(connection, w->pixmap); - xcb_destroy_window(connection, w->window); - xcb_flush(connection); + xcb_free_gc(w->g->connection, w->gc); + xcb_free_pixmap(w->g->connection, w->pixmap); + xcb_destroy_window(w->g->connection, w->window); + xcb_flush(w->g->connection); free(w); } void gui_window_draw(window w, unsigned char *data, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, uint32_t wx, uint32_t wy, uint32_t width, uint32_t height) { uint32_t bytes = 4 * width * height; - unsigned char *argb = (unsigned char*) malloc(bytes); - if (argb == NULL) + unsigned char *bgra = (unsigned char*) malloc(bytes); + if (bgra == NULL) return; uint32_t i = 0; uint32_t o = (dw * dy + dx) << 2; uint32_t p = (dw - width) << 2; - if (setup->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST) { + if (w->g->setup->image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST) { for (uint32_t y = dy; y < dy + height && y < dh; y++) { for (uint32_t x = dx; x < dx + width; x++, o += 4) { - argb[i++] = data[o + 2]; - argb[i++] = data[o + 1]; - argb[i++] = data[o]; + bgra[i++] = data[o + 2]; + bgra[i++] = data[o + 1]; + bgra[i++] = data[o]; i++; } o += p; @@ -200,19 +295,19 @@ void gui_window_draw(window w, unsigned char *data, uint32_t dx, uint32_t dy, ui } else { for (uint32_t y = dy; y < dy + height; y++) { for (uint32_t x = dx; x < dx + width; x++, o += 4) { + bgra[i++] = data[o]; + bgra[i++] = data[o + 1]; + bgra[i++] = data[o + 2]; i++; - argb[i++] = data[o]; - argb[i++] = data[o + 1]; - argb[i++] = data[o + 2]; } o += p; } } - xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, w->pixmap, w->gc, width, height, wx, wy, 0, screen->root_depth, bytes, argb); - free(argb); - xcb_copy_area(connection, w->pixmap, w->window, w->gc, wx, wy, wx, wy, width, height); - xcb_flush(connection); + xcb_put_image(w->g->connection, XCB_IMAGE_FORMAT_Z_PIXMAP, w->pixmap, w->gc, width, height, wx, wy, 0, w->g->screen->root_depth, bytes, bgra); + free(bgra); + xcb_copy_area(w->g->connection, w->pixmap, w->window, w->gc, wx, wy, wx, wy, width, height); + xcb_flush(w->g->connection); } void *gui_window_get_handle(window w) { @@ -228,239 +323,45 @@ uint32_t gui_window_get_height(window w) { void gui_window_resize(window w, uint32_t width, uint32_t height) { const uint32_t values[] = { width, height }; - xcb_configure_window(connection, w->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); - xcb_flush(connection); + xcb_configure_window(w->g->connection, w->window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); + xcb_flush(w->g->connection); } void gui_window_show(window w) { uint32_t xembed_info[] = { 0, XEMBED_MAPPED }; - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, w->window, xembed_info_atom, xembed_info_atom, 32, 2, xembed_info); - xcb_map_window(connection, w->window); - xcb_flush(connection); + xcb_change_property(w->g->connection, XCB_PROP_MODE_REPLACE, w->window, w->g->xembed_info_atom, w->g->xembed_info_atom, 32, 2, xembed_info); + xcb_map_window(w->g->connection, w->window); + xcb_flush(w->g->connection); } void gui_window_hide(window w) { uint32_t xembed_info[] = { 0, 0 }; - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, w->window, xembed_info_atom, xembed_info_atom, 32, 2, xembed_info); - xcb_unmap_window(connection, w->window); - xcb_flush(connection); + xcb_change_property(w->g->connection, XCB_PROP_MODE_REPLACE, w->window, w->g->xembed_info_atom, w->g->xembed_info_atom, 32, 2, xembed_info); + xcb_unmap_window(w->g->connection, w->window); + xcb_flush(w->g->connection); } -static window get_window(xcb_window_t xw) { - window w = windows; - while (w->window != xw) - w = (window)w->next; - return w; +void gui_window_set_data(window w, void *data) { + w->data = data; } -static uint32_t get_mouse_state(uint16_t state, xcb_button_t last) { - return ( - (state & XCB_BUTTON_MASK_1) >> 8 - | (state & XCB_BUTTON_MASK_2) >> 7 - | (state & XCB_BUTTON_MASK_3) >> 9 ) - ^ (last == 1 ? 1 : (last == 2 ? 4 : (last == 3 ? 2 : 0))) - ; +void *gui_window_get_data(window w) { + return w->data; } -void gui_run(uint32_t single) { - keep_running = 1; - xcb_generic_event_t *ev; - struct pollfd pfd; - pfd.fd = xcb_get_file_descriptor(connection); - pfd.events = POLLIN; - struct timespec ts_now; - int timeout; - while (keep_running) { - if (ts_timeout.tv_sec >= 0) { - int err = clock_gettime(CLOCK_MONOTONIC, &ts_now); - if (err == -1) - break; // TODO: error - if (ts_timeout.tv_sec < ts_now.tv_sec - || (ts_timeout.tv_sec == ts_now.tv_sec && ts_timeout.tv_nsec <= ts_now.tv_nsec)) { - timeout = 0; - } - else - timeout = 1000L * (ts_timeout.tv_sec - ts_now.tv_sec) + (ts_timeout.tv_nsec - ts_now.tv_nsec) / 1000000L; - } else - timeout = -1; - if (timeout == 0) { - ts_timeout.tv_sec = -1; - //on_timeout(); - timeout = -1; - } - int err = poll(&pfd, 1, single ? 0 : timeout); - if (err == -1) - // TODO: error - break; - else if (err == 0) { - if (single) - break; - else if (ts_timeout.tv_sec >= 0) { - ts_timeout.tv_sec = -1; - //on_timeout(); - } - } - - while (keep_running && (ev = xcb_poll_for_event(connection))) { - switch (ev->response_type & ~0x80) { - case XCB_EXPOSE: - { - xcb_expose_event_t *x = (xcb_expose_event_t *)ev; - window w = get_window(x->window); - - xcb_copy_area(connection, w->pixmap, w->window, w->gc, x->x, x->y, x->x, x->y, x->width, x->height); - xcb_flush(connection); - } - break; - - case XCB_CONFIGURE_NOTIFY: - { - xcb_configure_notify_event_t *x = (xcb_configure_notify_event_t *)ev; - window w = get_window(x->window); - - // FIXME: should translate to parent? - xcb_translate_coordinates_reply_t *trans = - xcb_translate_coordinates_reply(connection, xcb_translate_coordinates(connection, w->window, screen->root, 0, 0), NULL); - if (trans) { - if (trans->dst_x != w->x || trans->dst_y != w->y) { - w->x = trans->dst_x; - w->y = trans->dst_y; - //on_window_move(w, w->x, w->y); - } - free(trans); - } - - if (x->width != w->width || x->height != w->height) { - w->width = x->width; - w->height = x->height; - xcb_free_pixmap(connection, w->pixmap); - w->pixmap = xcb_generate_id(connection); - xcb_create_pixmap(connection, screen->root_depth, w->pixmap, w->window, w->width, w->height); - ;//on_window_resize(w, w->width, w->height); - } - } - break; - - case XCB_CLIENT_MESSAGE: - { - xcb_client_message_event_t *x = (xcb_client_message_event_t *)ev; - window w = get_window(x->window); - - if (x->data.data32[0] == wm_delete_atom) - ;//on_window_close(w); - } - break; - - case XCB_BUTTON_PRESS: - { - xcb_button_press_event_t *x = (xcb_button_press_event_t *)ev; - window w = get_window(x->event); - // First three buttons - if (x->detail <= 3) { - //on_mouse_press(w, x->event_x, x->event_y, get_mouse_state(x->state, x->detail)); - } - // Mouse wheel - else { - if (x->detail == 4) - ;//on_wheel(w, x->event_x, x->event_y, 57); - else if (x->detail == 5) - ;//on_wheel(w, x->event_x, x->event_y, -57); - } - } - break; - - case XCB_BUTTON_RELEASE: - { - xcb_button_release_event_t *x = (xcb_button_release_event_t *)ev; - window w = get_window(x->event); - - // First three buttons - if (x->detail <= 3) { - //on_mouse_release(w, x->event_x, x->event_y, get_mouse_state(x->state, x->detail)); - } - // Mouse wheel - else { - // Nothing to do - } - } - break; - - case XCB_MOTION_NOTIFY: - { - xcb_motion_notify_event_t *x = (xcb_motion_notify_event_t *)ev; - window w = get_window(x->event); - - //on_mouse_move(w, x->event_x, x->event_y, get_mouse_state(x->state, 0)); - } - break; - - case XCB_ENTER_NOTIFY: - { - xcb_enter_notify_event_t *x = (xcb_enter_notify_event_t *)ev; - window w = get_window(x->event); - - //on_mouse_enter(w, x->event_x, x->event_y, get_mouse_state(x->state, 0)); - } - break; - - case XCB_LEAVE_NOTIFY: - { - xcb_leave_notify_event_t *x = (xcb_leave_notify_event_t *)ev; - window w = get_window(x->event); - - //on_mouse_leave(w, x->event_x, x->event_y, get_mouse_state(x->state, 0)); - } - break; - - case XCB_KEY_PRESS: - { - xcb_key_press_event_t *x = (xcb_key_press_event_t *)ev; - window w = get_window(x->event); - - //on_key_press(w, x->detail, x->state); - } - break; - - case XCB_KEY_RELEASE: - { - xcb_key_release_event_t *x = (xcb_key_release_event_t *)ev; - window w = get_window(x->event); - - //on_key_release(w, x->detail, x->state); - } - break; - - default: - break; - } - - free(ev); - } +void gui_window_set_cb(window w, gui_cb_type type, gui_cb cb) { + switch (type) { + case GUI_CB_RESIZE: + w->resize_cb = cb; + break; + case GUI_CB_MOUSE_PRESS: + w->mouse_press_cb = cb; + break; + case GUI_CB_MOUSE_RELEASE: + w->mouse_release_cb = cb; + break; + case GUI_CB_MOUSE_MOVE: + w->mouse_move_cb = cb; + break; } } - -void gui_stop() { - keep_running = 0; -} - -void gui_set_timeout(int32_t value) { - int err = clock_gettime(CLOCK_MONOTONIC, &ts_timeout); - if (err == -1) - return; // TODO: error - if (value < 0) - ts_timeout.tv_sec = -1; - else { - long sec = value / 1000L; - long nsec = 1000000L * (value - 1000L * sec); - ts_timeout.tv_nsec += nsec; - while (ts_timeout.tv_nsec >= 1000000000L) { - ts_timeout.tv_sec++; - ts_timeout.tv_nsec -= 1000000000L; - } - ts_timeout.tv_sec += sec; - } -} - -#ifdef __cplusplus -} -#endif diff --git a/vst3/src/gui.h b/vst3/src/gui.h new file mode 100644 index 0000000..82ecff4 --- /dev/null +++ b/vst3/src/gui.h @@ -0,0 +1,62 @@ +/* + * A-SID - C64 bandpass filter + LFO + * + * Copyright (C) 2022 Orastron srl unipersonale + * + * A-SID 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, version 3 of the License. + * + * A-SID 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 + * + * File author: Stefano D'Angelo + */ + +#ifndef _GUI_H +#define _GUI_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _gui* gui; +typedef struct _window* window; +typedef void (*gui_cb)(void); + +typedef enum { + GUI_CB_RESIZE, + GUI_CB_MOUSE_PRESS, + GUI_CB_MOUSE_RELEASE, + GUI_CB_MOUSE_MOVE +} gui_cb_type; + +gui gui_new(); +void gui_free(gui g); +void gui_run(gui g, char single); +void gui_stop(gui g); + +window gui_window_new(gui g, void* parent, uint32_t width, uint32_t height); +void gui_window_free(window w); +void gui_window_draw(window w, unsigned char *bgra, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, uint32_t wx, uint32_t wy, uint32_t width, uint32_t height); +void gui_window_resize(window w, uint32_t width, uint32_t height); +void *gui_window_get_handle(window w); +uint32_t gui_window_get_width(window w); +uint32_t gui_window_get_height(window w); +void gui_window_show(window w); +void gui_window_hide(window w); +void gui_window_set_data(window w, void *data); +void *gui_window_get_data(window w); +void gui_window_set_cb(window w, gui_cb_type type, gui_cb cb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vst3/src/vst3/config.h b/vst3/src/vst3/config.h index 9e23fb9..8cb4736 100644 --- a/vst3/src/vst3/config.h +++ b/vst3/src/vst3/config.h @@ -49,8 +49,8 @@ struct config_parameter { #define COMPANY_WEBSITE "https://www.orastron.com/" #define COMPANY_MAILTO "mailto:info@orastron.com" -#define PLUGIN_NAME "ASID" -#define PLUGIN_VERSION "1.0.0" +#define PLUGIN_NAME "A-SID" +#define PLUGIN_VERSION "1.0.1" #define PLUGIN_SUBCATEGORY "Fx|Filter" #define PLUGIN_GUID_1 0x83AB6110 @@ -79,10 +79,10 @@ static struct config_io_bus config_buses_out[NUM_BUSES_OUT] = { #define NUM_PARAMETERS 4 static struct config_parameter config_parameters[NUM_PARAMETERS] = { - { "Cutoff", "Ctff", "", 0, 0, 0, 1.f }, - { "LFO Amount", "LFO amt", "%", 0, 0, 0, 0.f }, - { "LFO Speed", "LFO sp", "", 0, 0, 0, 0.5f }, - { "cutoffOut", "cout", "", 1, 0, 0, 0.f }, + { "Cutoff", "Cutoff", "", 0, 0, 0, 1.f }, + { "LFO Amount", "LFO Amt", "%", 0, 0, 0, 0.f }, + { "LFO Speed", "LFO Speed", "", 0, 0, 0, 0.5f }, + { "Modulate Cutoff", "Mod Cutoff", "", 1, 0, 0, 0.f }, }; // Internal API @@ -92,27 +92,30 @@ static struct config_parameter config_parameters[NUM_PARAMETERS] = { #define P_TYPE asid #define P_NEW asid_new #define P_FREE asid_free -#define P_SET_SAMPLE_RATE asid_set_sample_rate +#define P_SET_SAMPLE_RATE asid_set_sample_rate #define P_RESET asid_reset #define P_PROCESS asid_process -#define P_SET_PARAMETER asid_set_parameter +#define P_SET_PARAMETER asid_set_parameter +#define P_GET_PARAMETER asid_get_parameter #include "asid_gui.h" -#define PGUI_TYPE asid_gui -#define PGUI_NEW asid_gui_new -#define PGUI_FREE asid_gui_free -#define PGUI_PROCESS_EVENTS asid_gui_process_events -#define PGUI_SET_SET_PARAMETER asid_gui_set_set_parameter -#define PGUI_ON_PARAM_SET asid_gui_on_param_set +#define PGUI_TYPE asid_gui +#define PGUI_NEW asid_gui_new +#define PGUI_FREE asid_gui_free +#define PGUI_PROCESS_EVENTS asid_gui_process_events +#define PGUI_GET_DEFAULT_WIDTH asid_gui_get_default_width +#define PGUI_GET_DEFAULT_HEIGHT asid_gui_get_default_height +#define PGUI_GET_DATA asid_gui_get_data +#define PGUI_ON_PARAM_SET asid_gui_on_param_set -#define PGUIVIEW_TYPE asid_gui_view -#define PGUIVIEW_NEW asid_gui_view_new -#define PGUIVIEW_FREE asid_gui_view_free -#define PGUIVIEW_GET_WIDTH asid_gui_view_get_width -#define PGUIVIEW_GET_HEIGHT asid_gui_view_get_height -#define PGUIVIEW_RESIZE asid_gui_view_resize -#define PGUIVIEW_GET_DEFAULT_WIDTH asid_gui_view_get_default_width -#define PGUIVIEW_GET_DEFAULT_HEIGHT asid_gui_view_get_default_height +#define PGUIVIEW_TYPE asid_gui_view +#define PGUIVIEW_NEW asid_gui_view_new +#define PGUIVIEW_FREE asid_gui_view_free +#define PGUIVIEW_RESIZE_WINDOW asid_gui_view_resize_window +#define PGUIVIEW_GET_HANDLE asid_gui_view_get_handle +#define PGUIVIEW_GET_WIDTH asid_gui_view_get_width +#define PGUIVIEW_GET_HEIGHT asid_gui_view_get_height +#define PGUIVIEW_ON_TIMEOUT asid_gui_view_on_timeout #endif diff --git a/vst3/src/vst3/controller.h b/vst3/src/vst3/controller.h index 8126a3c..1cd56cd 100644 --- a/vst3/src/vst3/controller.h +++ b/vst3/src/vst3/controller.h @@ -40,7 +40,7 @@ public: tresult PLUGIN_API setParamNormalized(ParamID tag, ParamValue value) SMTG_OVERRIDE; private: - PGUI_TYPE pgui; + PGUI_TYPE pgui = nullptr; }; #endif diff --git a/vst3/src/vst3/controllerLinux.cpp b/vst3/src/vst3/controllerLinux.cpp index 8695bb7..8a7871e 100644 --- a/vst3/src/vst3/controllerLinux.cpp +++ b/vst3/src/vst3/controllerLinux.cpp @@ -22,57 +22,16 @@ #include "pluginterfaces/base/conststringtable.h" #include "base/source/fstreamer.h" -#include -#include -#include - -class LinuxEventHandler final : public Linux::IEventHandler { -public: - void PLUGIN_API onFDIsSet(Linux::FileDescriptor fd) { - //PGUI_PROCESS_EVENTS(pgui); - } - - void setFD(int fd) { - this->fd = fd; - } - - void setPGUI(PGUI_TYPE pgui) { - this->pgui = pgui; - } - - uint32 PLUGIN_API addRef() { - refCount++; - return refCount; - } - - uint32 PLUGIN_API release() { - refCount--; - if (refCount == 0) { - delete this; - return 0; - } - return refCount; - } - - tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) { - *obj = nullptr; - return kNotImplemented; - } - -private: - uint32 refCount = 1; - int fd; - PGUI_TYPE pgui; -}; - class LinuxTimerHandler final : public Linux::ITimerHandler { public: void PLUGIN_API onTimer() { - //PGUI_PROCESS_EVENTS(pgui); + PGUI_PROCESS_EVENTS(pgui); + PGUIVIEW_ON_TIMEOUT(pgui_view); } - void setPGUI(PGUI_TYPE pgui) { + void setPGUIData(PGUI_TYPE pgui, PGUIVIEW_TYPE pgui_view) { this->pgui = pgui; + this->pgui_view = pgui_view; } uint32 PLUGIN_API addRef() { @@ -97,6 +56,7 @@ public: private: uint32 refCount = 1; PGUI_TYPE pgui; + PGUIVIEW_TYPE pgui_view; }; class PlugView : public EditorView { @@ -117,39 +77,30 @@ public: pgui_view = PGUIVIEW_NEW(pgui, &parent); pgui_view_created = 1; plugFrame->queryInterface(Linux::IRunLoop::iid, (void **)&runLoop); - int fds[2]; - pipe(fds); - ev.setFD(fds[0]); - ev.setPGUI(pgui); - runLoop->registerEventHandler(&ev, fds[1]); - timer.setPGUI(pgui); + timer.setPGUIData(pgui, pgui_view); runLoop->registerTimer(&timer, 20); return kResultTrue; } tresult PLUGIN_API removed() { - runLoop->unregisterEventHandler(&ev); runLoop->unregisterTimer(&timer); - close(fd); - PGUIVIEW_FREE(pgui, pgui_view); + PGUIVIEW_FREE(pgui_view); pgui_view_created = 0; return kResultTrue; } tresult PLUGIN_API getSize(ViewRect *size) { if (!pgui_view_created) { - *size = ViewRect(0, 0, PGUIVIEW_GET_DEFAULT_WIDTH(pgui), PGUIVIEW_GET_DEFAULT_HEIGHT(pgui)); + *size = ViewRect(0, 0, PGUI_GET_DEFAULT_WIDTH(pgui), PGUI_GET_DEFAULT_HEIGHT(pgui)); return kResultTrue; } - *size = ViewRect(0, 0, PGUIVIEW_GET_WIDTH(pgui, pgui_view), PGUIVIEW_GET_HEIGHT(pgui, pgui_view)); + *size = ViewRect(0, 0, PGUIVIEW_GET_WIDTH(pgui_view), PGUIVIEW_GET_HEIGHT(pgui_view)); return kResultTrue; } tresult PLUGIN_API onSize(ViewRect *newSize) { if (!pgui_view_created) return kResultFalse; - if (newSize) - PGUIVIEW_RESIZE(pgui, pgui_view, newSize->getWidth(), newSize->getHeight()); return kResultTrue; } @@ -163,24 +114,27 @@ private: PGUIVIEW_TYPE pgui_view; Linux::IRunLoop* runLoop; int fd; - LinuxEventHandler ev; LinuxTimerHandler timer; }; -static void setParameterCb(void *handle, uint32_t id, float value) { - EditController *c = (EditController *)handle; +static float getParameterCb(PGUI_TYPE gui, uint32_t id) { + EditController *c = (EditController *)PGUI_GET_DATA(gui); + Parameter *p = c->getParameterObject(id); + return p->getNormalized(); +} + +static void setParameterCb(PGUI_TYPE gui, uint32_t id, float value) { + EditController *c = (EditController *)PGUI_GET_DATA(gui); c->beginEdit(id); c->performEdit(id, value); c->endEdit(id); } tresult PLUGIN_API Controller::initialize(FUnknown *context) { - pgui = PGUI_NEW(this); + pgui = PGUI_NEW(getParameterCb, setParameterCb, this); if (pgui == nullptr) return kResultFalse; - //PGUI_SET_SET_PARAMETER(pgui, setParameterCb); - tresult r = EditController::initialize(context); // add parameters @@ -221,6 +175,8 @@ tresult PLUGIN_API Controller::setComponentState(IBStream *state) { float f; for (int i = 0; i < NUM_PARAMETERS; i++) { + if (config_parameters[i].out) + continue; if (streamer.readFloat(f) == false) return kResultFalse; setParamNormalized(i, f); diff --git a/vst3/src/vst3/controllerOSX.cpp b/vst3/src/vst3/controllerOSX.cpp new file mode 100644 index 0000000..795bed6 --- /dev/null +++ b/vst3/src/vst3/controllerOSX.cpp @@ -0,0 +1,171 @@ +/* + * A-SID - C64 bandpass filter + LFO + * + * Copyright (C) 2022 Orastron srl unipersonale + * + * A-SID 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, version 3 of the License. + * + * A-SID 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 + * + * File author: Stefano D'Angelo, Paolo Marrone + */ + +#include "controller.h" + +#include "pluginterfaces/base/conststringtable.h" +#include "base/source/fstreamer.h" + +#include +#include + +#include "controllerOSXTimer.h" + +#include + +static void timerProc(void* data) { + PGUIVIEW_TYPE pgui_view = (PGUIVIEW_TYPE)data; + PGUIVIEW_ON_TIMEOUT(pgui_view); +} + +class PlugView : public EditorView { +public: + PlugView(EditController *controller, PGUI_TYPE pgui) : EditorView(controller, nullptr) { + this->pgui = pgui; + pgui_view_created = 0; + } + + ~PlugView() { + } + + tresult PLUGIN_API isPlatformTypeSupported(FIDString type) { + return strcmp(type, kPlatformTypeNSView) ? kResultFalse : kResultTrue; + } + + tresult PLUGIN_API attached(void *parent, FIDString type) { + pgui_view = PGUIVIEW_NEW(pgui, parent); + pgui_view_created = 1; + + timer = COSXSet_timer(20, (void*) timerProc, (void*) pgui_view); + + return kResultTrue; + } + + tresult PLUGIN_API removed() { + COSXRemove_timer(timer); + timer = nullptr; + + PGUIVIEW_FREE(pgui_view); + pgui_view_created = 0; + return kResultTrue; + } + + tresult PLUGIN_API getSize(ViewRect *size) { + if (!pgui_view_created) { + *size = ViewRect(0, 0, PGUI_GET_DEFAULT_WIDTH(pgui), PGUI_GET_DEFAULT_HEIGHT(pgui)); + return kResultTrue; + } + *size = ViewRect(0, 0, PGUIVIEW_GET_WIDTH(pgui_view), PGUIVIEW_GET_HEIGHT(pgui_view)); + return kResultTrue; + } + + tresult PLUGIN_API onSize(ViewRect *newSize) { + if (!pgui_view_created) + return kResultFalse; + if (newSize) { + int32 w = newSize->getWidth(); + int32 h = newSize->getHeight(); + PGUIVIEW_RESIZE_WINDOW(pgui_view, w, h); + } + return kResultTrue; + } + + tresult PLUGIN_API canResize() { + return kResultTrue; + } + +private: + PGUI_TYPE pgui; + char pgui_view_created; + PGUIVIEW_TYPE pgui_view; + void* timer; +}; + +static float getParameterCb(PGUI_TYPE gui, uint32_t id) { + EditController *c = (EditController *)PGUI_GET_DATA(gui); + Parameter *p = c->getParameterObject(id); + return p->getNormalized(); +} + +static void setParameterCb(PGUI_TYPE gui, uint32_t id, float value) { + EditController *c = (EditController *)PGUI_GET_DATA(gui); + c->beginEdit(id); + c->performEdit(id, value); + c->endEdit(id); +} + +tresult PLUGIN_API Controller::initialize(FUnknown *context) { + pgui = PGUI_NEW(getParameterCb, setParameterCb, this); + if (pgui == nullptr) + return kResultFalse; + + tresult r = EditController::initialize(context); + + // add parameters + for (int i = 0; i < NUM_PARAMETERS; i++) + parameters.addParameter( + ConstStringTable::instance()->getString(config_parameters[i].name), + config_parameters[i].units ? ConstStringTable::instance()->getString(config_parameters[i].units) : nullptr, + config_parameters[i].steps, + config_parameters[i].defaultValueUnmapped, + (config_parameters[i].out ? ParameterInfo::kIsReadOnly | ParameterInfo::kIsHidden : ParameterInfo::kCanAutomate) + | (config_parameters[i].bypass ? ParameterInfo::kIsBypass : 0), + i, + 0, + config_parameters[i].shortName ? ConstStringTable::instance()->getString(config_parameters[i].shortName) : nullptr + ); + + return kResultTrue; +} + +tresult PLUGIN_API Controller::terminate() { + PGUI_FREE(pgui); + + return EditController::terminate(); +} + +IPlugView * PLUGIN_API Controller::createView(const char *name) { + if (strcmp(name, ViewType::kEditor)) + return nullptr; + + return new PlugView(this, pgui); +} + +tresult PLUGIN_API Controller::setComponentState(IBStream *state) { + if (!state) + return kResultFalse; + + IBStreamer streamer(state, kLittleEndian); + + float f; + for (int i = 0; i < NUM_PARAMETERS; i++) { + if (streamer.readFloat(f) == false) + return kResultFalse; + setParamNormalized(i, f); + } + + return kResultTrue; +} + +tresult PLUGIN_API Controller::setParamNormalized(ParamID id, ParamValue value) { + tresult r = EditController::setParamNormalized(id, value); + if (r == kResultTrue) + PGUI_ON_PARAM_SET(pgui, id, value); + return r; +} diff --git a/vst3/src/vst3/controllerOSXTimer.h b/vst3/src/vst3/controllerOSXTimer.h new file mode 100644 index 0000000..2be3c09 --- /dev/null +++ b/vst3/src/vst3/controllerOSXTimer.h @@ -0,0 +1,26 @@ +/* + * A-SID - C64 bandpass filter + LFO + * + * Copyright (C) 2022 Orastron srl unipersonale + * + * A-SID 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, version 3 of the License. + * + * A-SID 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 + * + * File author: Paolo Marrone + */ + +#ifndef _CONTROLLEROSXTIMER_H +#define _CONTROLLEROSXTIMER_H + +void* COSXSet_timer(int ms, void* cb, void* data); +void COSXRemove_timer(void* t); + +#endif diff --git a/vst3/src/vst3/controllerOSXTimer.mm b/vst3/src/vst3/controllerOSXTimer.mm new file mode 100644 index 0000000..b9f9eed --- /dev/null +++ b/vst3/src/vst3/controllerOSXTimer.mm @@ -0,0 +1,36 @@ +/* + * A-SID - C64 bandpass filter + LFO + * + * Copyright (C) 2022 Orastron srl unipersonale + * + * A-SID 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, version 3 of the License. + * + * A-SID 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 + * + * File author: Paolo Marrone + */ + +#include "controllerOSXTimer.h" + +#import + +void* COSXSet_timer(int ms, void* cb, void* data) { + NSTimer* t = [NSTimer timerWithTimeInterval:ms*0.001f repeats:YES block:^(NSTimer * _Nonnull timer) { + ((void(*) (void*)) cb)(data); + }]; + [[NSRunLoop currentRunLoop] addTimer:t forMode:NSRunLoopCommonModes]; + return (void*) t; +} + +void COSXRemove_timer(void* t) { + if (t) { + [(NSTimer*)t invalidate]; + } +} diff --git a/vst3/src/vst3/controllerWin.cpp b/vst3/src/vst3/controllerWin.cpp index 8d63c30..cb2d270 100644 --- a/vst3/src/vst3/controllerWin.cpp +++ b/vst3/src/vst3/controllerWin.cpp @@ -17,15 +17,17 @@ * File author: Stefano D'Angelo, Paolo Marrone */ +#include + #include "controller.h" #include "pluginterfaces/base/conststringtable.h" #include "base/source/fstreamer.h" -#include -#include - -#include +static void timerProc(HWND hwnd, UINT unnamedParam2, UINT_PTR data, DWORD unnamedParam4) { + PGUIVIEW_TYPE pgui_view = (PGUIVIEW_TYPE)data; + PGUIVIEW_ON_TIMEOUT(pgui_view); +} class PlugView : public EditorView { public: @@ -45,30 +47,36 @@ public: pgui_view = PGUIVIEW_NEW(pgui, &parent); pgui_view_created = 1; + // SetTimer trick: https://stackoverflow.com/questions/4625184/passing-user-data-with-settimer + SetTimer((HWND)PGUIVIEW_GET_HANDLE(pgui_view), (UINT_PTR)pgui_view, (UINT)20, (TIMERPROC)&timerProc); + return kResultTrue; } tresult PLUGIN_API removed() { - - PGUIVIEW_FREE(pgui, pgui_view); + KillTimer((HWND)PGUIVIEW_GET_HANDLE(pgui_view), (UINT_PTR)pgui); + PGUIVIEW_FREE(pgui_view); pgui_view_created = 0; return kResultTrue; } tresult PLUGIN_API getSize(ViewRect *size) { if (!pgui_view_created) { - *size = ViewRect(0, 0, PGUIVIEW_GET_DEFAULT_WIDTH(pgui), PGUIVIEW_GET_DEFAULT_HEIGHT(pgui)); + *size = ViewRect(0, 0, PGUI_GET_DEFAULT_WIDTH(pgui), PGUI_GET_DEFAULT_HEIGHT(pgui)); return kResultTrue; } - *size = ViewRect(0, 0, PGUIVIEW_GET_WIDTH(pgui, pgui_view), PGUIVIEW_GET_HEIGHT(pgui, pgui_view)); + *size = ViewRect(0, 0, PGUIVIEW_GET_WIDTH(pgui_view), PGUIVIEW_GET_HEIGHT(pgui_view)); return kResultTrue; } tresult PLUGIN_API onSize(ViewRect *newSize) { if (!pgui_view_created) return kResultFalse; - if (newSize) - PGUIVIEW_RESIZE(pgui, pgui_view, newSize->getWidth(), newSize->getHeight()); + if (newSize) { + int32 w = newSize->getWidth(); + int32 h = newSize->getHeight(); + PGUIVIEW_RESIZE_WINDOW(pgui_view, w, h); + } return kResultTrue; } @@ -82,21 +90,24 @@ private: PGUIVIEW_TYPE pgui_view; }; -/* -static void setParameterCb(void *handle, uint32_t id, float value) { - EditController *c = (EditController *)handle; +static float getParameterCb(PGUI_TYPE gui, uint32_t id) { + EditController *c = (EditController *)PGUI_GET_DATA(gui); + Parameter *p = c->getParameterObject(id); + return p->getNormalized(); +} + +static void setParameterCb(PGUI_TYPE gui, uint32_t id, float value) { + EditController *c = (EditController *)PGUI_GET_DATA(gui); c->beginEdit(id); c->performEdit(id, value); c->endEdit(id); } -*/ + tresult PLUGIN_API Controller::initialize(FUnknown *context) { - pgui = PGUI_NEW(this); + pgui = PGUI_NEW(getParameterCb, setParameterCb, this); if (pgui == nullptr) return kResultFalse; - //PGUI_SET_SET_PARAMETER(pgui, setParameterCb); - tresult r = EditController::initialize(context); // add parameters @@ -137,6 +148,8 @@ tresult PLUGIN_API Controller::setComponentState(IBStream *state) { float f; for (int i = 0; i < NUM_PARAMETERS; i++) { + if (config_parameters[i].out) + continue; if (streamer.readFloat(f) == false) return kResultFalse; setParamNormalized(i, f); @@ -151,14 +164,3 @@ tresult PLUGIN_API Controller::setParamNormalized(ParamID id, ParamValue value) PGUI_ON_PARAM_SET(pgui, id, value); return r; } - -/* -tresult PLUGIN_API Controller::setState (IBStream* state) { - return kResultTrue; -} - -//------------------------------------------------------------------------ -tresult PLUGIN_API Controller::getState (IBStream* state) { - return kResultTrue; -} -*/ diff --git a/vst3/src/vst3/plugin.cpp b/vst3/src/vst3/plugin.cpp index f9ecba2..0f2faac 100644 --- a/vst3/src/vst3/plugin.cpp +++ b/vst3/src/vst3/plugin.cpp @@ -15,9 +15,31 @@ * You should have received a copy of the GNU General Public License * * File author: Stefano D'Angelo, Paolo Marrone + * + * This file contains code from sse2neon (https://github.com/DLTcollab/sse2neon/), + * which is released under the following licensing conditions. + * + * sse2neon is freely redistributable under the MIT License. + * + * 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. */ - #include "plugin.h" #include "pluginterfaces/base/conststringtable.h" @@ -26,9 +48,97 @@ #include +#if defined(__aarch64__) + +/* Beginning of sse2neon code */ + +/* Denormals are zeros mode macros. */ +#define _MM_DENORMALS_ZERO_MASK 0x0040 +#define _MM_DENORMALS_ZERO_ON 0x0040 +#define _MM_DENORMALS_ZERO_OFF 0x0000 + +#define _MM_GET_DENORMALS_ZERO_MODE _sse2neon_mm_get_denormals_zero_mode +#define _MM_SET_DENORMALS_ZERO_MODE _sse2neon_mm_set_denormals_zero_mode + +/* Flush zero mode macros. */ +#define _MM_FLUSH_ZERO_MASK 0x8000 +#define _MM_FLUSH_ZERO_ON 0x8000 +#define _MM_FLUSH_ZERO_OFF 0x0000 + +#define _MM_GET_FLUSH_ZERO_MODE _sse2neon_mm_get_flush_zero_mode +#define _MM_SET_FLUSH_ZERO_MODE _sse2neon_mm_set_flush_zero_mode + +typedef struct { + uint16_t res0; + uint8_t res1 : 6; + uint8_t bit22 : 1; + uint8_t bit23 : 1; + uint8_t bit24 : 1; + uint8_t res2 : 7; + uint32_t res3; +} fpcr_bitfield; + +static inline unsigned int _sse2neon_mm_get_denormals_zero_mode() +{ + union { + fpcr_bitfield field; + uint64_t value; + } r; + + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); + + return r.field.bit24 ? _MM_DENORMALS_ZERO_ON : _MM_DENORMALS_ZERO_OFF; +} + +static inline void _sse2neon_mm_set_denormals_zero_mode(unsigned int flag) +{ + union { + fpcr_bitfield field; + uint64_t value; + } r; + + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); + + r.field.bit24 = (flag & _MM_DENORMALS_ZERO_MASK) == _MM_DENORMALS_ZERO_ON; + + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); +} + +static inline unsigned int _sse2neon_mm_get_flush_zero_mode() +{ + union { + fpcr_bitfield field; + uint64_t value; + } r; + + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); + + return r.field.bit24 ? _MM_FLUSH_ZERO_ON : _MM_FLUSH_ZERO_OFF; +} + +static inline void _sse2neon_mm_set_flush_zero_mode(unsigned int flag) +{ + union { + fpcr_bitfield field; + uint64_t value; + } r; + + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); + + r.field.bit24 = (flag & _MM_FLUSH_ZERO_MASK) == _MM_FLUSH_ZERO_ON; + + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); +} + +/* End of sse2neon code */ + +#else + #include #include +#endif + Plugin::Plugin() { setControllerClass(FUID(CTRL_GUID_1, CTRL_GUID_2, CTRL_GUID_3, CTRL_GUID_4)); } @@ -132,28 +242,51 @@ tresult PLUGIN_API Plugin::process(ProcessData &data) { outputs[k] = data.outputs[i].channelBuffers32[j]; for (; k < NUM_CHANNELS_OUT; k++) outputs[k] = nullptr; - + + #if defined(__aarch64__) + + const unsigned int flush_zero_mode = _MM_GET_FLUSH_ZERO_MODE(); + const unsigned int denormals_zero_mode = _MM_GET_DENORMALS_ZERO_MODE(); + + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); + + #else + const int flush_zero_mode = _MM_GET_FLUSH_ZERO_MODE(); const char denormals_zero_mode = _MM_GET_DENORMALS_ZERO_MODE(); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); + #endif + P_PROCESS(instance, inputs, outputs, data.numSamples); - + + #if defined(__aarch64__) + _MM_SET_FLUSH_ZERO_MODE(flush_zero_mode); _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode); - // Send cutoff value to host - IParameterChanges* outParamChanges = data.outputParameterChanges; - if (outParamChanges) { - float cutoffValue = asid_get_cutoff_modulated(instance); - int32 index = 0; - IParamValueQueue* paramQueue = outParamChanges->addParameterData (3, index); - if (paramQueue) - { - int32 index2 = 0; - paramQueue->addPoint (0, cutoffValue, index2); + #else + + _MM_SET_FLUSH_ZERO_MODE(flush_zero_mode); + _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode); + + #endif + + for (int i = 0; i < NUM_PARAMETERS; i++) { + if (!config_parameters[i].out) + continue; + float v = P_GET_PARAMETER(instance, i); + if (parameters[i] == v) + continue; + parameters[i] = v; + if (data.outputParameterChanges) { + int32 index; + IParamValueQueue* paramQueue = data.outputParameterChanges->addParameterData(i, index); + if (paramQueue) + paramQueue->addPoint(0, v, index); } } @@ -186,6 +319,8 @@ tresult PLUGIN_API Plugin::setState(IBStream *state) { float f; for (int i = 0; i < NUM_PARAMETERS; i++) { + if (config_parameters[i].out) + continue; if (streamer.readFloat(f) == false) return kResultFalse; parameters[i] = f; @@ -199,7 +334,8 @@ tresult PLUGIN_API Plugin::getState(IBStream *state) { IBStreamer streamer(state, kLittleEndian); for (int i = 0; i < NUM_PARAMETERS; i++) - streamer.writeFloat(parameters[i]); + if (!config_parameters[i].out) + streamer.writeFloat(parameters[i]); return kResultTrue; }