diff options
author | Andrej Shadura <andrew.shadura@collabora.co.uk> | 2021-10-07 16:12:09 +0200 |
---|---|---|
committer | Andrej Shadura <andrew.shadura@collabora.co.uk> | 2021-10-07 16:12:09 +0200 |
commit | d4700c96fd551eea539921572c03842ecdc6c8c3 (patch) | |
tree | ac37ec6ef7d954feab5ad47c427e849f051da604 |
Import Upstream version 0.2.0+hg20110905r195
-rw-r--r-- | .hgtags | 12 | ||||
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | COPYING | 674 | ||||
-rw-r--r-- | HACKING | 92 | ||||
-rw-r--r-- | Makefile | 48 | ||||
-rw-r--r-- | README | 12 | ||||
-rw-r--r-- | TODO | 6 | ||||
-rw-r--r-- | effects.c | 3317 | ||||
-rw-r--r-- | effects.h | 114 | ||||
-rw-r--r-- | gdigi.1 | 74 | ||||
-rw-r--r-- | gdigi.c | 1241 | ||||
-rw-r--r-- | gdigi.desktop | 7 | ||||
-rw-r--r-- | gdigi.h | 1007 | ||||
-rw-r--r-- | gtkknob.c | 919 | ||||
-rw-r--r-- | gtkknob.h | 102 | ||||
-rw-r--r-- | gui.c | 1265 | ||||
-rw-r--r-- | gui.h | 30 | ||||
-rw-r--r-- | knob.png | bin | 0 -> 63864 bytes | |||
-rw-r--r-- | preset.c | 357 | ||||
-rw-r--r-- | preset.h | 32 |
20 files changed, 9310 insertions, 0 deletions
@@ -0,0 +1,12 @@ +6defd1a8b4b499c46196b4112e8dff443c57609c 0.1 +2a58e6a931791cb369483dc6171d66a8a75f40f2 0.1.1 +7a31bc52075252647dd848eec6308a111d86776e 0.1.2 +5cc97dba5d412fd7d000ad0974682ed4e10c3326 0.1.3 +78367821f4f43f610edf53f5f732f74d0832f7c2 0.1.4 +45f897c02e72af5c73e0c27063f02728c0392e19 0.1.5 +80e56807413bc281b7e4331d98581ba874fb186d 0.1.6 +c622b5d3c3b3e08a87fd994ef855fba98128ed07 0.1.7 +5e6d6124b5f2860867e24cd2da033fbc6ad9d433 0.1.8 +d9a1510dc8feb81e7026882e8a7719a2ba7ff04c 0.2.0 +d9a1510dc8feb81e7026882e8a7719a2ba7ff04c 0.2.0 +6864af80db93f7dfef26c0f583ce7c60382b1142 0.2.0 @@ -0,0 +1 @@ +Tomasz Moń <desowin@gmail.com> @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 <http://www.gnu.org/licenses/>. + +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: + + <program> Copyright (C) <year> <name of author> + 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 +<http://www.gnu.org/licenses/>. + + 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 +<http://www.gnu.org/philosophy/why-not-lgpl.html>. @@ -0,0 +1,92 @@ +In general everything brings down to figure out: +-ID +-Position +-Possible value range + +There seems to be three possible ways to figure that out. +1) Use USB sniffer together with X-Edit + Once you set up X-Edit and usb sniffer, set some option. + USB sniffer should report something like this being sent to device: + (all numbers here are hex) + 04 F0 00 00 04 10 00 5E 04 02 41 00 04 30 09 00 07 00 34 F7 + + MIDI data is transferred over USB using 32-bit USB-MIDI Event Packets. + Byte 0 is Cable Number (high nibble) and Code Index Number (low nibble). + Bytes 1, 2 and 3 are data. + Every bulk transfer on USB MIDI endpoint contains atleast one such packet + (those are sent one after each other). + In case of Digitech devices, the Cable Number seems to be 0 (correct me, + if I'm wrong). + There are three different Code Index Numbers that are being used in this + particular case: + 0x4 - SysEx starts or continues (Byte 1, 2 and 3 from this packet are + part of our MIDI message) + 0x5 - SysEx ends with following single byte (we just need to take Byte 1 + from this packet) + 0x6 - SysEx ends with following two bytes (we just need to take Byte 1 and 2 + from this packet) + 0x7 - SysEx ends with following three bytes (we need to take Byte 1, 2 and 3 + from this packet) + + Unused bytes in USB-MIDI packets are supposed to be 0. + + To get SysEx command out of it, apply above rules, so we have: + F0 00 00 10 00 5E 02 41 00 30 09 00 00 34 F7 + + SysEx message format seems to be formed like this: + SysEx start byte - F0 + Manufacturer ID - 00 00 10 + Device ID - 00 + Family ID - 5E (RP) + Product ID - 02 (RP250) + Procedure - 41 (see MessageID in gdigi.h) + + As MIDI messages must not contain bytes with MSB bit set, Digitech + devices use packing system. + First byte contains MSB bits from following 7 bytes (this scheme + continues as many times as needed) (see pack_data() and unpack_message() in + gdigi.c for details). + + Assuming message has been unpacked, the meaning of next bytes: + ID - in this example 30 09 + Position - in this example 00 + Value - in this example 00 (can be more bytes long, see below) + Checksum - to calculate it, XOR all bytes (of packed message) + Every message ends with F7 + + So for above example: + ID = 3009 (hex) = 12297 (decimal) + Position = 0 + One of possible values is 0. Usually value range is 0 to 99, + albeit in some cases it's different - you have to check what values can + X-Edit assign (there doesn't seem to be any sanity check in firmware) + This is especially needed for IDs that set some effect type. + +2) Save preset patch + Patches seem to be simple XML files. + Every parameter is written like this: + <Param> + <ID>65</ID> + <Position>2</Position> + <Value>0</Value> + <Name>Pickup Enable</Name> + <Text>Off</Text> + </Param> + ID is ID, Position is Position and Value is one of possible values. + To get all possible values you can: + do + change value to next one possible in X-Edit + (for example next effect type) + save new patch + check patch file and note the change + while you don't have all possible values +3) Use gdigi + After starting gdigi turn the knobs on your device. + Check out console output, you should notice something like this: + ** Message: Received parameter change ID: 210 Position: 4 Value: 0 + ID is ID, Position is Position and Value is one of possible values. + To get all possible values keep turning knobs and watch the output. + If you change effect type usually there's more messages - where, + usually the first one is type change, and rest are default values. + This way you *CANNOT* gather all information (there're X-Edit only + controlled values, check device manual for more information). diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f46dd6a --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +CC = gcc +EXTRA_CFLAGS ?= +EXTRA_LDFLAGS ?= +CFLAGS := $(shell pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0) -Wall -g -ansi -std=c99 $(EXTRA_CFLAGS) +LDFLAGS = $(EXTRA_LDFLAGS) -Wl,--as-needed +LDADD := $(shell pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 gthread-2.0 alsa) -lexpat +OBJECTS = gdigi.o gui.o effects.o preset.o gtkknob.o +DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m) + +.PHONY : clean distclean all +%.o : %.c + $(CC) $(CFLAGS) -c $< + +.%.m : %.c + $(CC) $(CFLAGS) -M -MF $@ -MG $< + +all: gdigi + +gdigi: $(OBJECTS) + $(CC) $(LDFLAGS) -o $@ $+ $(LDADD) + +knob.h: knob.png + gdk-pixbuf-csource --name=knob_pixbuf knob.png > $@ + +clean: + rm -f *.o + rm -f knob.h + +distclean : clean + rm -f .*.m + rm -f gdigi + +install: gdigi + install gdigi $(DESTDIR)/usr/bin + install gdigi.desktop $(DESTDIR)/usr/share/applications/ + +NODEP_TARGETS := clean distclean +depinc := 1 +ifneq (,$(filter $(NODEP_TARGETS),$(MAKECMDGOALS))) +depinc := 0 +endif +ifneq (,$(fitler-out $(NODEP_TARGETS),$(MAKECMDGOALS))) +depinc := 1 +endif + +ifeq ($(depinc),1) +-include $(DEPFILES) +endif @@ -0,0 +1,12 @@ +Requirments: alsa, gtk+, glib, expat + +Getting started guide: +-to compile: make +-to run: ./gdigi + +Commandline options: +--device (-d) + +Example: +gdigi -d hw:1,0,0 +gdigi --device=hw:1,0,0 @@ -0,0 +1,6 @@ +-make complete gui (expression pedal settings, usb settings, effect level, preset level) +-handling presets (saving, exporting to xml patches) +-buildsystem (install knob.png to share dir, don't use inline knob pixbuf) +-various fixes to MIDI IN messages handling +-ask user which device to use if more than one DigiTech device is found +-optimizations diff --git a/effects.c b/effects.c new file mode 100644 index 0000000..36649a2 --- /dev/null +++ b/effects.c @@ -0,0 +1,3317 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#include "gdigi.h" +#include "effects.h" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +static gchar *wave_labels[] = { + "Tri", + "Sine", + "Square", + NULL, +}; + +static gchar *whammy_labels[] = { + "OctUp", + "2OctUp", + "2ndDn", + "Rv2nd", + "4thDn", + "OctDn", + "2OctDn", + "DivBmb", + "M3>Ma3", + "2ndMa3", + "3rd4th", + "4th5th", + "5thOct", + "HOctUp", + "HOctDn", + "OctU>D", + NULL, +}; + +static gchar *ips_shift_labels[] = { + "Oct Dn", + "7th Dn", + "6th Dn", + "5th Dn", + "4th Dn", + "3rd Dn", + "2nd Dn", + "2nd Up", + "3rd Up", + "4th Up", + "5th Up", + "6th Up", + "7th Up", + "Oct Up", + NULL, +}; + +static gchar *ips_key_labels[] = { + "E", + "F", + "Gb", + "G", + "Ab", + "A", + "Bb", + "B", + "C", + "Db", + "D", + "Eb", + NULL, +}; + +static gchar *ips_scale_labels[] = { + "Major", + "Minor", + "Dorian", + "Mixolydian", + "Lydian", + "HMinor", + NULL, +}; + +static gchar *on_off_labels[] = { + "Off", + "On", + NULL, +}; + +static gchar *odd_even_labels[] = { + "Odd", + "Even", + NULL, +}; + +static gchar *chorus_vibrato_labels[] = { + "Chorus", + "Vibrato", + NULL, +}; + +static gchar *hp_lp_labels[] = { + "HP", + "LP", + NULL, +}; + +static gchar *loose_tight_labels[] = { + "Loose", + "Tight", + NULL, +}; + +static gchar *pickup_type_labels[] = { + "SC>HB", + "HB>SC", + NULL, +}; + +static gchar *fast_medium_slow_labels[] = { + "Fast", + "Medium", + "Slow", + NULL, +}; + +static gchar *comp_ratio_labels[] = { + "1.2:1", + "1.5:1", + "1.8:1", + "2.0:1", + "2.5:1", + "3:1", + "4:1", + "5:1", + "8:1", + "10:1", + "20:1", + "Inf:1", + NULL, +}; + +static gchar *eq_bandwidth_labels[] = { + "Wide", + "Medium", + "Narrow", + NULL, +}; + +static gchar *eq_low_freq_labels[] = { + "60Hz", + "63Hz", + "67Hz", + "71Hz", + "75Hz", + "80Hz", + "85Hz", + "90Hz", + "95Hz", + "100Hz", + "106Hz", + "112Hz", + "118Hz", + "125Hz", + "132Hz", + "140Hz", + "150Hz", + "160Hz", + "170Hz", + "180Hz", + "190Hz", + "200Hz", + "212Hz", + "224Hz", + "236Hz", + "250Hz", + "265Hz", + "280Hz", + "300Hz", + "315Hz", + "335Hz", + "355Hz", + "375Hz", + "400Hz", + "425Hz", + "450Hz", + "475Hz", + "500Hz", + NULL, +}; + +static gchar *eq_mid_freq_labels[] = { + "300Hz", + "315Hz", + "335Hz", + "355Hz", + "375Hz", + "400Hz", + "425Hz", + "450Hz", + "475Hz", + "500Hz", + "530Hz", + "560Hz", + "600Hz", + "630Hz", + "670Hz", + "710Hz", + "750Hz", + "800Hz", + "850Hz", + "900Hz", + "950Hz", + "1kHz", + "1.06kHz", + "1.12kHz", + "1.18kHz", + "1.25kHz", + "1.32kHz", + "1.4kHz", + "1.5kHz", + "1.6kHz", + "1.7kHz", + "1.8kHz", + "1.9kHz", + "2kHz", + "2.12kHz", + "2.24kHz", + "2.36kHz", + "2.5kHz", + "2.65kHz", + "2.8kHz", + "3kHz", + "3.15kHz", + "3.35kHz", + "3.55kHz", + "3.75kHz", + "4kHz", + NULL, +}; + +static gchar *eq_high_freq_labels[] = { + "2kHz", + "2.12kHz", + "2.24kHz", + "2.36kHz", + "2.5kHz", + "2.65kHz", + "2.8kHz", + "3kHz", + "3.15kHz", + "3.35kHz", + "3.55kHz", + "3.75kHz", + "4kHz", + "4.25kHz", + "4.5kHz", + "4.75kHz", + "5kHz", + "5.3kHz", + "5.6kHz", + "6kHz", + "6.3kHz", + "6.7kHz", + "7.1kHz", + "7.5kHz", + "8kHz", + NULL, +}; + +static gchar *amp_channel_labels[] = { + "1", + "2", + "Warped", + NULL, +}; + +static gchar *rhold_labels[] = { + "RHold", + NULL, +}; + +static EffectValues values_1_2_warp = { + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = amp_channel_labels, +}; + +static EffectValues values_0_to_99 = { + .min = 0.0, .max = 99.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_1_to_4 = { + .min = 0.0, .max = 3.0, + .type = VALUE_TYPE_OFFSET, + .offset = 1, +}; + +static EffectValues values_warp_0_to_98 = { + .min = 0.0, .max = 98.0, + .type = VALUE_TYPE_OFFSET, + .offset = 1, +}; + +static EffectValues values_0_to_9 = { + .min = 0.0, .max = 9.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_0_to_49 = { + .min = 0.0, .max = 49.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_0_to_12 = { + .min = 0.0, .max = 12.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_0_to_15 = { + .min = 0.0, .max = 15.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_0_to_20 = { + .min = 0.0, .max = 20.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_m12_to_12_semitones = { + /** \todo make this display properly (display range -12.0 to 12.0 semitones) */ + .min = 0.0, .max = 48.0, .type = VALUE_TYPE_PLAIN, +/* .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "semitones", .offset = -12, */ +}; + +static EffectValues values_m24_to_24_step2 = { + .min = 0.0, .max = 24.0, + .type = VALUE_TYPE_OFFSET | VALUE_TYPE_STEP, + .offset = -12, .step = 2.0, +}; + +static EffectValues values_m24_to_24 = { + .min = 0.0, .max = 48.0, + .type = VALUE_TYPE_OFFSET, + .offset = -24, +}; + +static EffectValues values_m12_to_24 = { + .min = 0.0, .max = 36.0, + .type = VALUE_TYPE_OFFSET, + .offset = -12, +}; + +static EffectValues values_comp_ratio = { + .min = 0.0, .max = 12.0, + .type = VALUE_TYPE_LABEL, + .labels = comp_ratio_labels, +}; + +static EffectValues values_fast_medium_slow = { + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = fast_medium_slow_labels, +}; + +static EffectValues values_eq_db = { + .min = 0.0, .max = 24.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "dB", .offset = -12, +}; + +static EffectValues values_eq_bass_hz = { + .min = 0.0, .max = 250.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "hz", .offset = 50, +}; + +static EffectValues values_eq_mid_hz = { + .min = 0.0, .max = 4700.0, + .type = VALUE_TYPE_OFFSET, + .offset = 300, +}; + +static EffectValues values_eq_treb_hz = { + .min = 0.0, .max = 7500.0, + .type = VALUE_TYPE_OFFSET, + .offset = 500, +}; + +static EffectValues values_eq_bandwidth = { + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_bandwidth_labels, +}; + +static EffectValues values_eq_low_freq = { + .min = 0.0, .max = 37.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_low_freq_labels, +}; + +static EffectValues values_eq_mid_freq = { + .min = 0.0, .max = 45.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_mid_freq_labels, +}; + +static EffectValues values_eq_high_freq = { + .min = 0.0, .max = 24.0, + .type = VALUE_TYPE_LABEL, + .labels = eq_high_freq_labels, +}; + +static EffectValues values_200hz_to_1_5khz = { + /** \todo make this display properly (display range 200 Hz to 1.5 kHz) */ + .min = 0.0, .max = 130.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_waveform = { + .min = 0.0, .max = 2.0, + .type = VALUE_TYPE_LABEL, + .labels = wave_labels, +}; + +static EffectValues values_balance = { + /** \todo make this display properly */ + 0.0, 198.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_synth_talk_release = { + /** \todo make last value display properly */ + 0.0, 100.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_whammy_amount = { + .min = 0.0, .max = 15.0, + .type = VALUE_TYPE_LABEL, + .labels = whammy_labels, +}; + +static EffectValues values_ips_shift = { + .min = 0.0, .max = 13.0, + .type = VALUE_TYPE_LABEL, + .labels = ips_shift_labels, +}; + +static EffectValues values_ips_key = { + .min = 0.0, .max = 11.0, + .type = VALUE_TYPE_LABEL, + .labels = ips_key_labels, +}; + +static EffectValues values_ips_scale = { + .min = 0.0, .max = 5.0, + .type = VALUE_TYPE_LABEL, + .labels = ips_scale_labels, +}; + +static EffectValues values_predelay_time = { + .min = 0.0, .max = 19.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "ms", .offset = 1, +}; + +static EffectValues values_delay_time_extra = { + /* display as 1.0 sec (99) to 5.0 sec (139) */ + .min = 99.0, .max = 139.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET | + VALUE_TYPE_STEP | VALUE_TYPE_DECIMAL, + .suffix = "sec", .offset = -89, + .step = 0.1, .decimal = 1, +}; + +static EffectValues values_delay_time = { + /* 0 to 139, extended by values_delay_time_extra */ + .min = 0.0, .max = 98.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET | + VALUE_TYPE_STEP | VALUE_TYPE_EXTRA, + .suffix = "msec", .offset = 1, + .step = 10.0, .extra = &values_delay_time_extra, +}; + +static EffectValues values_delay_time_110_870 = { + .min = 0.0, .max = 760.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "ms", .offset = 110, +}; + +static EffectValues values_delay_time_0_2000 = { + /** \todo make this display properly */ + 0.0, 2000.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_delay_time_0_4650 = { + /** \todo make this display properly */ + 0.0, 4650.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_delay_time_0_4990 = { + /** \todo make this display properly */ + 0.0, 4990.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_delay_time_0_5000 = { + /** \todo make this display properly */ + 0.0, 5000.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_delay_repeats_extra = { + .min = 100.0, .max = 100.0, + .type = VALUE_TYPE_LABEL, + .labels = rhold_labels +}; + +static EffectValues values_delay_repeats = { + /* 0 to 100, extended by values_delay_repeats_extra */ + .min = 0.0, .max = 99.0, + .type = VALUE_TYPE_EXTRA, + .extra = &values_delay_repeats_extra, +}; + +static EffectValues values_delay_thresh = { + /** \todo make last value display properly */ + 0.0, 100.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_delay_repeat_rate_24_310 = { + .min = 0.0, .max = 286.0, + .type = VALUE_TYPE_SUFFIX | VALUE_TYPE_OFFSET, + .suffix = "ms", .offset = 24, +}; + +static EffectValues values_delay_spread_0_49 = { + /** \todo make this display properly */ + 0.0, 49.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectValues values_on_off = { + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = on_off_labels, +}; + +static EffectValues values_odd_even = { + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = odd_even_labels, +}; + +static EffectValues values_chorus_vibrato = { + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = chorus_vibrato_labels, +}; + +static EffectValues values_hp_lp = { + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = hp_lp_labels, +}; + +static EffectValues values_loose_tight = { + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = loose_tight_labels, +}; + +static EffectValues values_pickup_type = { + .min = 0.0, .max = 1.0, + .type = VALUE_TYPE_LABEL, + .labels = pickup_type_labels, +}; + +static EffectValues values_1_to_10_step_0p1 = { + .min = 0.0, .max = 90.0, + .type = VALUE_TYPE_OFFSET | VALUE_TYPE_STEP | VALUE_TYPE_DECIMAL, + .offset = 10, .step = 0.1, .decimal = 1, +}; + +static EffectValues values_rp_mix = { + /** \todo make this display properly (USB 0, USB 1, USB 2 ... USB 49, USB RP, RP 49, RP 48 ... RP 1, RP 0) */ + .min = 0.0, .max = 100.0, .type = VALUE_TYPE_PLAIN, +}; + +static EffectSettings usb_settings[] = { + {"USB/RP Mix", USB_AUDIO_PLAYBACK_MIX, USB_POSITION, &values_rp_mix}, + {"USB Level", USB_AUDIO_LEVEL, USB_POSITION, &values_m12_to_24}, +}; + +static EffectSettings misc_settings[] = { + {"Preset Level", PRESET_LEVEL, PRESET_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_wah_settings[] = { + {"Min", WAH_MIN, WAH_POSITION_MIN_MAX, &values_0_to_99}, + {"Max", WAH_MAX, WAH_POSITION_MIN_MAX, &values_0_to_99}, +}; + +static EffectSettings wah_settings[] = { + {"Min", WAH_MIN, WAH_POSITION_MIN_MAX, &values_0_to_99}, + {"Max", WAH_MAX, WAH_POSITION_MIN_MAX, &values_0_to_99}, + {"Level", WAH_LEVEL, WAH_POSITION, &values_0_to_12}, +}; + +static EffectSettings gnx3k_whammy_settings[] = { + {"Shift Amount", WHAMMY_AMOUNT, GNX3K_WHAM_POSITION, &values_whammy_amount}, + {"Pedal", WHAMMY_PEDAL, GNX3K_WHAM_POSITION, &values_0_to_99}, + {"Mix", WHAMMY_MIX, GNX3K_WHAM_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_ips_settings[] = { + {"Shift Amount", IPS_SHIFT_AMOUNT, GNX3K_WHAM_POSITION, &values_ips_shift}, + {"Scale", IPS_SCALE, GNX3K_WHAM_POSITION, &values_ips_scale}, + {"Key", IPS_KEY, GNX3K_WHAM_POSITION, &values_ips_key}, + {"Level", IPS_LEVEL, GNX3K_WHAM_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_detune_settings[] = { + {"Shift Amount", GNX3K_DETUNE_AMOUNT, GNX3K_WHAM_POSITION, &values_m24_to_24_step2}, + {"Level", DETUNE_LEVEL, GNX3K_WHAM_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_pitch_settings[] = { + {"Shift Amount", GNX3K_PITCH_AMOUNT, GNX3K_WHAM_POSITION, &values_m24_to_24}, + {"Level", GNX3K_PITCH_LEVEL, GNX3K_WHAM_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_talk_settings[] = { + {"Mic Level", GNX3K_TALK_LEVEL, GNX3K_WHAM_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_amp_channel_settings[] = { + {"Amp Channel", GNX_CHANNEL_AMP, GNX_CHANNEL_POSITION, &values_1_2_warp}, + {"Warp", GNX_WARP, GNX_CHANNEL_POSITION, &values_warp_0_to_98}, + {"Amp Warp", GNX_AMP_WARP, GNX_CHANNEL_POSITION, &values_warp_0_to_98}, + {"Cabinet Warp", GNX_CABINET_WARP, GNX_CHANNEL_POSITION, &values_warp_0_to_98}, +}; + +static EffectSettings gnx3k_preset_settings[] = { + {"Preset Level", PRESET_LEVEL, PRESET_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx_comp_settings[] = { + {"Attack", GNX3K_COMP_ATTACK, COMP_POSITION, &values_fast_medium_slow}, + {"Ratio", GNX3K_COMP_RATIO, COMP_POSITION, &values_comp_ratio}, + {"Threshold", GNX3K_COMP_THRESHOLD, COMP_POSITION, &values_0_to_99}, + {"Gain", GNX3K_COMP_GAIN, COMP_POSITION, &values_0_to_20}, +}; + +static EffectSettings comp_digi_settings[] = { + {"Sustain", COMP_SUSTAIN, COMP_POSITION, &values_0_to_99}, + {"Tone", COMP_TONE, COMP_POSITION, &values_0_to_99}, + {"Attack", COMP_ATTACK, COMP_POSITION, &values_0_to_99}, + {"Level", COMP_LEVEL, COMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings comp_cs_settings[] = { + {"Sustain", COMP_SUSTAIN, COMP_POSITION, &values_0_to_99}, + {"Attack", COMP_ATTACK, COMP_POSITION, &values_0_to_99}, + {"Level", COMP_LEVEL, COMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings comp_dyna_settings[] = { + {"Sensitivity", COMP_SENSITIVITY, COMP_POSITION, &values_0_to_99}, + {"Output", COMP_OUTPUT, COMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_screamer_settings[] = { + {"Drive", DIST_SCREAMER_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_SCREAMER_TONE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_SCREAMER_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_808_settings[] = { + {"Overdrive", DIST_808_OVERDRIVE, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_808_TONE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_808_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_ts_mod_settings[] = { + {"Drive", DIST_TS_MOD_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_TS_MOD_TONE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_TS_MOD_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_sd_odrv_settings[] = { + {"Drive", DIST_SD_ODRV_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_SD_ODRV_TONE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_SD_ODRV_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_od_odrv_settings[] = { + {"Overdrive", DIST_OD_ODRV_OVERDRIVE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_OD_ODRV_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_sparkdrive_settings[] = { + {"Gain", DIST_SPARKDRIVE_GAIN, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_SPARKDRIVE_TONE, DIST_POSITION, &values_0_to_99}, + {"Clean", DIST_SPARKDRIVE_CLEAN, DIST_POSITION, &values_0_to_99}, + {"Volume", DIST_SPARKDRIVE_VOLUME, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_guyod_settings[] = { + {"Drive", DIST_GUYOD_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_GUYOD_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_dod250_settings[] = { + {"Gain", DIST_DOD250_GAIN, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_DOD250_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_redline_settings[] = { + {"Gain", DIST_REDLINE_GAIN, DIST_POSITION, &values_0_to_99}, + {"Low", DIST_REDLINE_LOW, DIST_POSITION, &values_0_to_99}, + {"High", DIST_REDLINE_HIGH, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_REDLINE_LEVEL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_ampdrivr_settings[] = { + {"Gain", DIST_AMPDRIVR_GAIN, DIST_POSITION, &values_0_to_99}, + {"Mid Boost", DIST_AMPDRIVR_MIDBOOST, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_AMPDRIVR_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_oc_drive_settings[] = { + {"Drive", DIST_OC_DRIVE_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_OC_DRIVE_TONE, DIST_POSITION, &values_0_to_99}, + {"HP/LP", DIST_OC_DRIVE_HP_LP, DIST_POSITION, &values_hp_lp}, + {"Level", DIST_OC_DRIVE_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_rodent_settings[] = { + {"Dist", DIST_RODENT_DIST, DIST_POSITION, &values_0_to_99}, + {"Filter", DIST_RODENT_FILTER, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_RODENT_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_mx_settings[] = { + {"Dist", DIST_MX_DIST, DIST_POSITION, &values_0_to_99}, + {"Output", DIST_MX_OUTPUT, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_ds_settings[] = { + {"Gain", DIST_DS_GAIN, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_DS_TONE, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_DS_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_grunge_settings[] = { + {"Grunge", DIST_GRUNGE_GRUNGE, DIST_POSITION, &values_0_to_99}, + {"Face", DIST_GRUNGE_FACE, DIST_POSITION, &values_0_to_99}, + {"Loud", DIST_GRUNGE_LOUD, DIST_POSITION, &values_0_to_99}, + {"Butt", DIST_GRUNGE_BUTT, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_zone_settings[] = { + {"Gain", DIST_ZONE_GAIN, DIST_POSITION, &values_0_to_99}, + {"Low", DIST_ZONE_LOW, DIST_POSITION, &values_0_to_99}, + {"Mid level", DIST_ZONE_MID_LVL, DIST_POSITION, &values_0_to_99}, + {"Mid freq", DIST_ZONE_MID_FREQ, DIST_POSITION, &values_0_to_99}, + {"High", DIST_ZONE_HIGH, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_ZONE_LEVEL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_death_settings[] = { + {"Low", DIST_DEATH_LOW, DIST_POSITION, &values_0_to_99}, + {"Mid", DIST_DEATH_MID, DIST_POSITION, &values_0_to_99}, + {"High", DIST_DEATH_HIGH, DIST_POSITION, &values_0_to_99}, + {"Level", DIST_DEATH_LVL, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_gonk_settings[] = { + {"Gonk", DIST_GONK_GONK, DIST_POSITION, &values_0_to_99}, + {"Smear", DIST_GONK_SMEAR, DIST_POSITION, &values_0_to_99}, + {"Suck", DIST_GONK_SUCK, DIST_POSITION, &values_0_to_99}, + {"Heave", DIST_GONK_HEAVE, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_8tavia_settings[] = { + {"Drive", DIST_8TAVIA_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Volume", DIST_8TAVIA_VOLUME, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_fuzzlator_settings[] = { + {"Fuzz", DIST_FUZZLATOR_FUZZ, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_FUZZLATOR_TONE, DIST_POSITION, &values_0_to_99}, + {"LooseTight", DIST_FUZZLATOR_LOOSETIGHT, DIST_POSITION, &values_loose_tight}, + {"Volume", DIST_FUZZLATOR_VOLUME, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_classic_fuzz_settings[] = { + {"Fuzz", DIST_CLASSIC_FUZZ_FUZZ, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_CLASSIC_FUZZ_TONE, DIST_POSITION, &values_0_to_99}, + {"Volume", DIST_CLASSIC_FUZZ_VOLUME, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_fuzzy_settings[] = { + {"Fuzz", DIST_FUZZY_FUZZ, DIST_POSITION, &values_0_to_99}, + {"Volume", DIST_FUZZY_VOLUME, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings dist_mp_settings[] = { + {"Sustain", DIST_MP_SUSTAIN, DIST_POSITION, &values_0_to_99}, + {"Tone", DIST_MP_TONE, DIST_POSITION, &values_0_to_99}, + {"Volume", DIST_MP_VOLUME, DIST_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp250_amp_settings[] = { + {"Gain", AMP_GAIN, AMP_POSITION, &values_0_to_99}, + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp250_amp_settings2[] = { + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp355_amp_settings_A[] = { + {"Gain", AMP_GAIN, AMP_POSITION, &values_0_to_99}, + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp355_amp_settings_B[] = { + {"Gain", AMP_GAIN, CH2_AMP_POSITION, &values_0_to_99}, + {"Level", AMP_LEVEL, CH2_AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp355_amp_settings2_A[] = { + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp355_amp_settings2_B[] = { + {"Level", AMP_LEVEL, CH2_AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_amp_settings[] = { + {"Gain", AMP_GAIN, AMP_POSITION, &values_0_to_99}, + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, + {"Bass", AMP_BASS, AMP_POSITION, &values_1_to_10_step_0p1}, + {"Mid", AMP_MID, AMP_POSITION, &values_1_to_10_step_0p1}, + {"Treble", AMP_TREBLE, AMP_POSITION, &values_1_to_10_step_0p1}, +}; + +static EffectSettings rp500_amp_settings2[] = { + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, + {"Bass", AMP_BASS, AMP_POSITION, &values_1_to_10_step_0p1}, + {"Mid", AMP_MID, AMP_POSITION, &values_1_to_10_step_0p1}, + {"Treble", AMP_TREBLE, AMP_POSITION, &values_1_to_10_step_0p1}, +}; + +static EffectSettings rp500_amp_settings3[] = { + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_ch1_cab_tuning_settings[] = { + {"Tuning", AMP_CAB_TUNING, AMP_CAB_POSITION, &values_m12_to_12_semitones}, +}; + +static EffectSettings gnx3k_ch2_cab_tuning_settings[] = { + {"Tuning", AMP_CAB_TUNING, CH2_AMP_CAB_POSITION, &values_m12_to_12_semitones}, +}; + +static EffectSettings gnx3k_ch1_amp_eq_settings[] = { + {"Gain", AMP_GAIN, AMP_POSITION, &values_0_to_99}, + {"Bass Freq", AMP_BASS_FREQ, AMP_POSITION, &values_eq_bass_hz}, + {"Bass Level", AMP_BASS_LEVEL, AMP_POSITION, &values_eq_db}, + {"Mid Freq", AMP_MID_FREQ, AMP_POSITION, &values_eq_mid_hz}, + {"Mid Level", AMP_MID_LEVEL, AMP_POSITION, &values_eq_db}, + {"Treb Freq", AMP_TREBLE_FREQ, AMP_POSITION, &values_eq_treb_hz}, + {"Treb Level", AMP_TREBLE_LEVEL, AMP_POSITION, &values_eq_db}, + {"Presence", AMP_PRESENCE, AMP_POSITION, &values_eq_db}, + {"Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_ch2_amp_eq_settings[] = { + {"Gain", AMP_GAIN, CH2_AMP_POSITION, &values_0_to_99}, + {"Bass Freq", AMP_BASS_FREQ, CH2_AMP_POSITION, &values_eq_bass_hz}, + {"Bass Level", AMP_BASS_LEVEL, CH2_AMP_POSITION, &values_eq_db}, + {"Mid Freq", AMP_MID_FREQ, CH2_AMP_POSITION, &values_eq_mid_hz}, + {"Mid Level", AMP_MID_LEVEL, CH2_AMP_POSITION, &values_eq_db}, + {"Treb Freq", AMP_TREBLE_FREQ, CH2_AMP_POSITION, &values_eq_treb_hz}, + {"Treb Level", AMP_TREBLE_LEVEL, CH2_AMP_POSITION, &values_eq_db}, + {"Presence", AMP_PRESENCE, CH2_AMP_POSITION, &values_eq_db}, + {"Level", AMP_LEVEL, CH2_AMP_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp250_eq_settings[] = { + {"Bass", EQ_BASS, EQ_POSITION, &values_eq_db}, + {"Mid", EQ_MID, EQ_POSITION, &values_eq_db}, + {"Treble", EQ_TREBLE, EQ_POSITION, &values_eq_db}, + {"Mid Hz", EQ_MID_HZ, EQ_POSITION, &values_eq_mid_hz}, + {"Treb Hz", EQ_TREBLE_HZ, EQ_POSITION, &values_eq_treb_hz}, +}; + +static EffectSettings rp355_eq_settings_A[] = { + {"Bass", EQ_BASS, EQ_POSITION, &values_eq_db}, + {"Mid", EQ_MID, EQ_POSITION, &values_eq_db}, + {"Treble", EQ_TREBLE, EQ_POSITION, &values_eq_db}, + {"Mid Hz", EQ_MID_HZ, EQ_POSITION, &values_eq_mid_hz}, + {"Treb Hz", EQ_TREBLE_HZ, EQ_POSITION, &values_eq_treb_hz}, + {"Presence", EQ_PRESENCE, EQ_POSITION, &values_eq_db}, +}; + +static EffectSettings rp355_eq_settings_B[] = { + {"Bass", EQ_BASS, EQ_POSITION_B, &values_eq_db}, + {"Mid", EQ_MID, EQ_POSITION_B, &values_eq_db}, + {"Treble", EQ_TREBLE, EQ_POSITION_B, &values_eq_db}, + {"Mid Hz", EQ_MID_HZ, EQ_POSITION_B, &values_eq_mid_hz}, + {"Treb Hz", EQ_TREBLE_HZ, EQ_POSITION_B, &values_eq_treb_hz}, + {"Presence", EQ_PRESENCE, EQ_POSITION_B, &values_eq_db}, +}; + +static EffectSettings rp500_eq_settings[] = { + {"Low Level", EQ_LOW_LEVEL, EQ_POSITION, &values_eq_db}, + {"Mid Level", EQ_MID_LEVEL, EQ_POSITION, &values_eq_db}, + {"High Level", EQ_HIGH_LEVEL, EQ_POSITION, &values_eq_db}, + {"Low Freq", EQ_LOW_FREQ, EQ_POSITION, &values_eq_low_freq}, + {"Mid Freq", EQ_MID_FREQ, EQ_POSITION, &values_eq_mid_freq}, + {"High Freq", EQ_HIGH_FREQ, EQ_POSITION, &values_eq_high_freq}, + {"Low Bandwidth", EQ_LOW_BANDWIDTH, EQ_POSITION, &values_eq_bandwidth}, + {"Mid Bandwidth", EQ_MID_BANDWIDTH, EQ_POSITION, &values_eq_bandwidth}, + {"High Bandwidth", EQ_HIGH_BANDWIDTH, EQ_POSITION, &values_eq_bandwidth}, +}; + +static EffectSettings noisegate_silencer_settings[] = { + {"Threshold", NOISEGATE_GATE_TRESHOLD, NOISEGATE_POSITION, &values_0_to_99}, + {"Attack", GNX3K_GATE_ATTACK, NOISEGATE_POSITION, &values_0_to_9}, +}; + +static EffectSettings noisegate_pluck_settings[] = { + {"Threshold", NOISEGATE_GATE_TRESHOLD, NOISEGATE_POSITION, &values_0_to_99}, + {"Attack", GNX3K_GATE_ATTACK, NOISEGATE_POSITION, &values_0_to_9}, + {"Sens", NOISEGATE_SWELL_SENS, NOISEGATE_POSITION, &values_0_to_99}, +}; + +static EffectSettings noisegate_gate_settings[] = { + {"Treshold", NOISEGATE_GATE_TRESHOLD, NOISEGATE_POSITION, &values_0_to_99}, + {"Attack", NOISEGATE_ATTACK, NOISEGATE_POSITION, &values_0_to_99}, + {"Release", NOISEGATE_RELEASE, NOISEGATE_POSITION, &values_0_to_99}, + {"Attn", NOISEGATE_ATTN, NOISEGATE_POSITION, &values_0_to_99}, +}; + +static EffectSettings noisegate_swell_settings[] = { + {"Sens", NOISEGATE_SWELL_SENS, NOISEGATE_POSITION, &values_0_to_99}, + {"Attack", NOISEGATE_ATTACK, NOISEGATE_POSITION, &values_0_to_99}, + {"Release", NOISEGATE_RELEASE, NOISEGATE_POSITION, &values_0_to_99}, + {"Attn", NOISEGATE_ATTN, NOISEGATE_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_chorus_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Predelay", CHORUS_PREDELAY, CHORUSFX_POSITION, &values_predelay_time}, + {"Wave", CHORUS_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Balance", CHORUS_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Level", CHORUS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_flanger_settings[] = { + {"Speed", FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", FLANGER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Regen", FLANGER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Waveform", FLANGER_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Balance", FLANGER_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Mix", FLANGER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_phaser_settings[] = { + {"Speed", PHASER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", PHASER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Regen", PHASER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Waveform", PHASER_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Balance", PHASER_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Level", PHASER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_trigflanger_settings[] = { + {"Speed", TRIG_FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Sens", TRIG_FLANGER_SENS, CHORUSFX_POSITION, &values_0_to_99}, + {"Lfo Start", TRIG_FLANGER_LFO_START, CHORUSFX_POSITION, &values_0_to_99}, + {"Mix", TRIG_FLANGER_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_trigphaser_settings[] = { + {"Speed", TRIG_PHASER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Sens", TRIG_PHASER_SENS, CHORUSFX_POSITION, &values_0_to_99}, + {"Lfo Start", TRIG_PHASER_LFO_START, CHORUSFX_POSITION, &values_0_to_99}, + {"Mix", TRIG_FLANGER_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_unovibe_settings[] = { + {"Chorus/Vibrato", UNOVIBE_CHORUS_VIBRATO, CHORUSFX_POSITION, &values_chorus_vibrato}, + {"Intensity", UNOVIBE_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Pedal Speed", UNOVIBE_PEDAL_SPEED, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_vibrato_settings[] = { + {"Speed", VIBRATO_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", VIBRATO_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Waveform", VIBRATO_WAVEFORM, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings gnx3k_rotary_settings[] = { + {"Speed", ROTARY_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", ROTARY_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Doppler", ROTARY_DOPPLER, CHORUSFX_POSITION, &values_0_to_99}, + {"X-Over", ROTARY_CROSSOVER, CHORUSFX_POSITION, &values_200hz_to_1_5khz}, + {"Balance", ROTARY_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Mix", ROTARY_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_autoya_settings[] = { + {"Speed", AUTOYA_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", AUTOYA_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", GNX3K_AUTOYA_RANGE, CHORUSFX_POSITION, &values_0_to_49}, + {"Balance", AUTOYA_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Mix", AUTOYA_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_yaya_settings[] = { + {"Pedal", YAYA_PEDAL, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", YAYA_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", GNX3K_YAYA_RANGE, CHORUSFX_POSITION, &values_0_to_49}, + {"Balance", YAYA_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Mix", YAYA_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_synthtalk_settings[] = { + {"Attack", SYNTH_TALK_ATTACK, CHORUSFX_POSITION, &values_0_to_99}, + {"Release", GNX3K_SYNTH_TALK_RELEASE, CHORUSFX_POSITION, &values_synth_talk_release}, + {"Sens", SYNTH_TALK_SENS, CHORUSFX_POSITION, &values_0_to_99}, + {"Vox", SYNTH_TALK_VOX, CHORUSFX_POSITION, &values_0_to_99}, + {"Balance", SYNTH_TALK_BALANCE, CHORUSFX_POSITION, &values_balance}, +}; + +static EffectSettings gnx3k_envelope_settings[] = { + {"Sensitivity", ENVELOPE_SENSITIVITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", ENVELOPE_RANGE, CHORUSFX_POSITION, &values_0_to_99}, + {"Balance", ENVELOPE_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Mix", ENVELOPE_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_mod_detune_settings[] = { + {"Shift Amount", DETUNE_AMOUNT, CHORUSFX_POSITION, &values_m24_to_24}, + {"Balance", DETUNE_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Level", DETUNE_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_mod_pitch_settings[] = { + {"Shift Amount", PITCH_AMOUNT, CHORUSFX_POSITION, &values_m12_to_24}, + {"Balance", PITCH_BALANCE, CHORUSFX_POSITION, &values_balance}, + {"Level", GNX3K_PITCH_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_ce_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_tc_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Width", CHORUS_WIDTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", CHORUS_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_dual_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", CHORUS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", CHORUS_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_glisten_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", CHORUS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_multi_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", CHORUS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", CHORUS_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_voo_doo_settings[] = { + {"Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", CHORUS_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_clone_settings[] = { + {"Rate", CHORUS_RATE, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_flanger_settings[] = { + {"Speed", FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", FLANGER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Regen", FLANGER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", FLANGER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", FLANGER_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_trig_flanger_settings[] = { + {"Speed", TRIG_FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Sens", TRIG_FLANGER_SENS, CHORUSFX_POSITION, &values_0_to_99}, + {"Lfo Start", TRIG_FLANGER_LFO_START, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", TRIG_FLANGER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_fltflanger_settings[] = { + {"Speed", FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", FLANGER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Regen", FLANGER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Frequency", FLTFLANGER_FREQ, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_mxr_flanger_settings[] = { + {"Speed", FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Width", MXR_FLANGER_WIDTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Regen", FLANGER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Manual", MXR_FLANGER_MANUAL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_eh_flanger_settings[] = { + {"Rate", EH_FLANGER_RATE, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", EH_FLANGER_RANGE, CHORUSFX_POSITION, &values_0_to_99}, + {"Color", EH_FLANGER_COLOR, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_ad_flanger_settings[] = { + {"Speed", FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Enhance", AD_FLANGER_ENHANCE, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", EH_FLANGER_RANGE, CHORUSFX_POSITION, &values_0_to_99}, + {"Harmonics", AD_FLANGER_HARMONICS, CHORUSFX_POSITION, &values_odd_even}, + {"Manual", MXR_FLANGER_MANUAL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_phaser_settings[] = { + {"Speed", PHASER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", PHASER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Regen", PHASER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", PHASER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", PHASER_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_trig_phaser_settings[] = { + {"Speed", TRIG_PHASER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Sens", TRIG_PHASER_SENS, CHORUSFX_POSITION, &values_0_to_99}, + {"Lfo Start", TRIG_PHASER_LFO_START, CHORUSFX_POSITION, &values_0_to_99}, + {"Level", TRIG_PHASER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_mx_phaser_settings[] = { + {"Speed", PHASER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", MX_PHASER_INTENSITY, CHORUSFX_POSITION, &values_1_to_4}, +}; + +static EffectSettings chorusfx_eh_phaser_settings[] = { + {"Rate", EH_PHASER_RATE, CHORUSFX_POSITION, &values_0_to_99}, + {"Color", EH_PHASER_COLOR, CHORUSFX_POSITION, &values_on_off}, +}; + +static EffectSettings chorusfx_vibrato_settings[] = { + {"Speed", VIBRATO_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", VIBRATO_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_rotary_settings[] = { + {"Speed", ROTARY_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", ROTARY_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Doppler", ROTARY_DOPPLER, CHORUSFX_POSITION, &values_0_to_99}, + {"Crossover", ROTARY_CROSSOVER, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_vibropan_settings[] = { + {"Speed", VIBROPAN_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", VIBROPAN_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Vibra", VIBROPAN_VIBRA, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", VIBROPAN_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_unovibe_settings[] = { + {"Pedal Speed", UNOVIBE_PEDAL_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", UNOVIBE_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Chorus/Vibrato", UNOVIBE_CHORUS_VIBRATO, CHORUSFX_POSITION, &values_chorus_vibrato}, + {"Volume", UNOVIBE_VOLUME, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_tremolo_settings[] = { + {"Speed", TREMOLO_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", TREMOLO_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", TREMOLO_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_trem_settings[] = { + {"Speed", TREMOLO_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", TREMOLO_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_panner_settings[] = { + {"Speed", PANNER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Depth", PANNER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Wave", PANNER_WAVE, CHORUSFX_POSITION, &values_waveform}, +}; + +static EffectSettings chorusfx_envelope_settings[] = { + {"Sensitivity", ENVELOPE_SENSITIVITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", ENVELOPE_RANGE, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_fx25_settings[] = { + {"Sensitivity", ENVELOPE_SENSITIVITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", ENVELOPE_RANGE, CHORUSFX_POSITION, &values_0_to_99}, + {"Blend", ENVELOPE_BLEND, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_autoya_settings[] = { + {"Speed", AUTOYA_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", AUTOYA_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", AUTOYA_RANGE, CHORUSFX_POSITION, &values_0_to_49}, +}; + +static EffectSettings chorusfx_yaya_settings[] = { + {"Pedal", YAYA_PEDAL, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", YAYA_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Range", YAYA_RANGE, CHORUSFX_POSITION, &values_0_to_49}, +}; + +static EffectSettings chorusfx_synth_talk_settings[] = { + {"Attack", SYNTH_TALK_ATTACK, CHORUSFX_POSITION, &values_0_to_99}, + {"Release", SYNTH_TALK_RELEASE, CHORUSFX_POSITION, &values_0_to_99}, + {"Sens", SYNTH_TALK_SENS, CHORUSFX_POSITION, &values_0_to_99}, + {"Vox", SYNTH_TALK_VOX, CHORUSFX_POSITION, &values_0_to_99}, + {"Balance", SYNTH_TALK_BALANCE, CHORUSFX_POSITION, &values_balance}, +}; + +static EffectSettings chorusfx_step_filter_settings[] = { + {"Speed", STEP_FILTER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", STEP_FILTER_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_sample_hold_settings[] = { + {"Speed", SAMPLE_HOLD_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Intensity", SAMPLE_HOLD_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_whammy_settings[] = { + {"Pedal", WHAMMY_PEDAL, CHORUSFX_POSITION, &values_0_to_99}, + {"Mix", WHAMMY_MIX, CHORUSFX_POSITION, &values_0_to_99}, + {"Amount", WHAMMY_AMOUNT, CHORUSFX_POSITION, &values_whammy_amount}, +}; + +static EffectSettings chorusfx_pitch_shift_settings[] = { + {"Amount", PITCH_AMOUNT, CHORUSFX_POSITION, &values_m24_to_24}, + {"Mix", PITCH_MIX, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_detune_settings[] = { + {"Amount", DETUNE_AMOUNT, CHORUSFX_POSITION, &values_m24_to_24}, + {"Level", DETUNE_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_ips_settings[] = { + {"Shift", IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, &values_ips_shift}, + {"Key", IPS_KEY, CHORUSFX_POSITION, &values_ips_key}, + {"Scale", IPS_SCALE, CHORUSFX_POSITION, &values_ips_scale}, + {"Level", IPS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings chorusfx_octaver_settings[] = { + {"Octave 1", OCTAVER_OCTAVE1, CHORUSFX_POSITION, &values_0_to_99}, + {"Octave 2", OCTAVER_OCTAVE2, CHORUSFX_POSITION, &values_0_to_99}, + {"Dry Level", OCTAVER_DRY_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_delay_settings[] = { + {"Time", GNX3K_DELAY_TIME, DELAY_POSITION, &values_delay_time_0_2000}, + {"Feedback", GNX3K_DELAY_FEEDBACK, DELAY_POSITION, &values_delay_repeats}, + {"Thresh", GNX3K_DELAY_DUCK_THRESH, DELAY_POSITION, &values_delay_thresh}, + {"Atten", GNX3K_DELAY_DUCK_ATTEN, DELAY_POSITION, &values_0_to_99}, + {"Balance", GNX3K_DELAY_BALANCE, DELAY_POSITION, &values_balance}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_delay_spread_settings[] = { + {"Time", GNX3K_DELAY_TIME, DELAY_POSITION, &values_delay_time_0_2000}, + {"Feedback", GNX3K_DELAY_FEEDBACK, DELAY_POSITION, &values_delay_repeats}, + {"Thresh", GNX3K_DELAY_DUCK_THRESH, DELAY_POSITION, &values_delay_thresh}, + {"Atten", GNX3K_DELAY_DUCK_ATTEN, DELAY_POSITION, &values_0_to_99}, + {"Spread", GNX3K_DELAY_SPREAD, DELAY_POSITION, &values_delay_spread_0_49}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings delay_analog_settings[] = { + {"Time", DELAY_TIME, DELAY_POSITION, &values_delay_time}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, +}; + +static EffectSettings delay_dm_settings[] = { + {"Repeat Rate", DELAY_REPEAT_RATE_DM, DELAY_POSITION, &values_0_to_99}, + {"Echo", DELAY_ECHO, DELAY_POSITION, &values_0_to_99}, + {"Intensity", DELAY_INTENSITY, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings delay_digital_settings[] = { + {"Time", DELAY_TIME, DELAY_POSITION, &values_delay_time}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Ducker thresh", DELAY_DUCK_THRESH, DELAY_POSITION, &values_0_to_99}, + {"Ducker level", DELAY_DUCK_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings delay_modulated_settings[] = { + {"Time", DELAY_TIME, DELAY_POSITION, &values_delay_time}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Depth", DELAY_DEPTH, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings delay_pong_settings[] = { + {"Time", DELAY_TIME, DELAY_POSITION, &values_delay_time}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Ducker thresh", DELAY_DUCK_THRESH, DELAY_POSITION, &values_0_to_99}, + {"Ducker level", DELAY_DUCK_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings delay_tape_settings[] = { + {"Time", DELAY_TIME, DELAY_POSITION, &values_delay_time}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Wow", DELAY_TAPE_WOW, DELAY_POSITION, &values_0_to_99}, + {"Flutter", DELAY_TAPE_FLUTTER, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings delay_echoplex_settings[] = { + {"Time", DELAY_ECHOPLEX_TIME, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS_0_99, DELAY_POSITION, &values_0_to_99}, + {"Volume", DELAY_VOLUME, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_digital_settings[] = { + {"Tap Time", DELAY_TAP_TIME, DELAY_POSITION, &values_delay_time_0_5000}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Duck Thresh", DELAY_DUCK_THRESH, DELAY_POSITION, &values_0_to_99}, + {"Duck Level", DELAY_DUCK_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_analog_settings[] = { + {"Tap Time", DELAY_TAP_TIME, DELAY_POSITION, &values_delay_time_0_5000}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_dm_settings[] = { + {"Repeat Rate", DELAY_REPEAT_RATE, DELAY_POSITION, &values_delay_repeat_rate_24_310}, + {"Echo", DELAY_ECHO, DELAY_POSITION, &values_0_to_99}, + {"Intensity", DELAY_INTENSITY, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_echoplex_settings[] = { + {"Time", DELAY_TIME_0_760, DELAY_POSITION, &values_delay_time_110_870}, + {"Volume", DELAY_VOLUME, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS_0_99, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_modulated_settings[] = { + {"Tap Time", DELAY_TAP_TIME_0_4990, DELAY_POSITION, &values_delay_time_0_4990}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Depth", DELAY_DEPTH, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_pong_settings[] = { + {"Tap Time", DELAY_TAP_TIME, DELAY_POSITION, &values_delay_time_0_5000}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Duck Thresh", DELAY_DUCK_THRESH, DELAY_POSITION, &values_0_to_99}, + {"Duck Level", DELAY_DUCK_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_reverse_settings[] = { + {"Time", DELAY_TIME_0_4650, DELAY_POSITION, &values_delay_time_0_4650}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Mix", DELAY_MIX, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp500_delay_tape_settings[] = { + {"Tap Time", DELAY_TAP_TIME_0_4990, DELAY_POSITION, &values_delay_time_0_4990}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Tape Wow", DELAY_TAPE_WOW, DELAY_POSITION, &values_0_to_99}, + {"Tape Flutter", DELAY_TAPE_FLUTTER, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp1000_delay_lo_fi_settings[] = { + {"Time", DELAY_TAP_TIME, DELAY_POSITION, &values_delay_time_0_5000}, + {"Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Repeats", DELAY_REPEATS_0_99, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings rp1000_delay_2_tap_settings[] = { + {"Time", DELAY_TAP_TIME, DELAY_POSITION, &values_delay_time_0_5000}, + {"Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Ratio", DELAY_TAP_RATIO, DELAY_POSITION, &values_delay_repeats}, + {"Mix", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, +}; + +static EffectSettings reverb_twin_settings[] = { + {"Reverb", REVERB_LEVEL, REVERB_POSITION, &values_0_to_99}, +}; + +static EffectSettings gnx3k_reverb_settings[] = { + {"Predelay", REVERB_PREDELAY, REVERB_POSITION, &values_0_to_15}, + {"Decay", REVERB_DECAY, REVERB_POSITION, &values_0_to_99}, + {"Damping", REVERB_DAMPING, REVERB_POSITION, &values_0_to_99}, + {"Balance", REVERB_BALANCE, REVERB_POSITION, &values_balance}, + {"Level", REVERB_LEVEL, REVERB_POSITION, &values_0_to_99}, +}; + +static EffectSettings reverb_lex_settings[] = { + {"Predelay", REVERB_PREDELAY, REVERB_POSITION, &values_0_to_15}, + {"Decay", REVERB_DECAY, REVERB_POSITION, &values_0_to_99}, + {"Liveliness", REVERB_LIVELINESS, REVERB_POSITION, &values_0_to_99}, + {"Level", REVERB_LEVEL, REVERB_POSITION, &values_0_to_99}, +}; + +static EffectGroup gnx3k_wah_group[] = { + {GNX3K_WAH_TYPE_CRY, "Cry", gnx3k_wah_settings, G_N_ELEMENTS(gnx3k_wah_settings)}, + {GNX3K_WAH_TYPE_BOUTIQUE, "Boutique", gnx3k_wah_settings, G_N_ELEMENTS(gnx3k_wah_settings)}, + {GNX3K_WAH_TYPE_FULLRANGE, "Full-Range", gnx3k_wah_settings, G_N_ELEMENTS(gnx3k_wah_settings)}, +}; + +static EffectGroup wah_group[] = { + {WAH_TYPE_CRY, "Cry wah", wah_settings, G_N_ELEMENTS(wah_settings)}, + {WAH_TYPE_FULLRANGE, "Fullrange wah", wah_settings, G_N_ELEMENTS(wah_settings)}, + {WAH_TYPE_CLYDE, "Clyde wah", wah_settings, G_N_ELEMENTS(wah_settings)}, +}; + +static EffectGroup gnx3k_whammy_group[] = { + {GNX3K_WHAM_TYPE_WHAMMY, "Whammy", gnx3k_whammy_settings, G_N_ELEMENTS(gnx3k_whammy_settings)}, + {GNX3K_WHAM_TYPE_IPS, "IPS", gnx3k_ips_settings, G_N_ELEMENTS(gnx3k_ips_settings)}, + {GNX3K_WHAM_TYPE_DETUNE, "Detune", gnx3k_detune_settings, G_N_ELEMENTS(gnx3k_detune_settings)}, + {GNX3K_WHAM_TYPE_PITCH, "Pitch Shift", gnx3k_pitch_settings, G_N_ELEMENTS(gnx3k_pitch_settings)}, + {GNX3K_WHAM_TYPE_TALK1, "Talker 1", gnx3k_talk_settings, G_N_ELEMENTS(gnx3k_talk_settings)}, + {GNX3K_WHAM_TYPE_TALK2, "Talker 2", gnx3k_talk_settings, G_N_ELEMENTS(gnx3k_talk_settings)}, + {GNX3K_WHAM_TYPE_TALK3, "Talker 3", gnx3k_talk_settings, G_N_ELEMENTS(gnx3k_talk_settings)}, + {GNX3K_WHAM_TYPE_TALK4, "Talker 4", gnx3k_talk_settings, G_N_ELEMENTS(gnx3k_talk_settings)}, + {GNX3K_WHAM_TYPE_TALK5, "Talker 5", gnx3k_talk_settings, G_N_ELEMENTS(gnx3k_talk_settings)}, +}; + +static EffectGroup gnx3k_amp_channel_group[] = { + {-1, NULL, gnx3k_amp_channel_settings, G_N_ELEMENTS(gnx3k_amp_channel_settings)}, +}; + +/** \todo it's not part of Preset, but should appear in GUI */ +static EffectGroup usb_group[] = { + {-1, NULL, usb_settings, G_N_ELEMENTS(usb_settings)}, +}; + +static EffectGroup misc_group[] = { + {-1, NULL, misc_settings, G_N_ELEMENTS(misc_settings)}, +}; + +static EffectGroup gnx3k_preset_group[] = { + {-1, NULL, gnx3k_preset_settings, G_N_ELEMENTS(gnx3k_preset_settings)}, +}; + +static EffectGroup gnx_comp_group[] = { + {-1, NULL, gnx_comp_settings, G_N_ELEMENTS(gnx_comp_settings)}, +}; + +static EffectGroup rp250_comp_group[] = { + {COMP_TYPE_DIGI, "Digital compressor", comp_digi_settings, G_N_ELEMENTS(comp_digi_settings)}, + {COMP_TYPE_CS, "CS compressor", comp_cs_settings, G_N_ELEMENTS(comp_cs_settings)}, +}; + +static EffectGroup rp355_comp_group[] = { + {COMP_TYPE_DIGI, "Digital compressor", comp_digi_settings, G_N_ELEMENTS(comp_digi_settings)}, + {COMP_TYPE_CS, "CS compressor", comp_cs_settings, G_N_ELEMENTS(comp_cs_settings)}, + {COMP_TYPE_DYNA, "Dyna comp", comp_dyna_settings, G_N_ELEMENTS(comp_dyna_settings)}, +}; + +static EffectGroup rp500_comp_group[] = { + {COMP_TYPE_DIGI, "Digital compressor", comp_digi_settings, G_N_ELEMENTS(comp_digi_settings)}, + {COMP_TYPE_CS, "CS compressor", comp_cs_settings, G_N_ELEMENTS(comp_cs_settings)}, + {COMP_TYPE_DYNA, "Dyna comp", comp_dyna_settings, G_N_ELEMENTS(comp_dyna_settings)}, +}; + +static EffectGroup rp155_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_808, "808", dist_808_settings, G_N_ELEMENTS(dist_808_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_DS, "DS", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, + {DIST_TYPE_GONK, "Gonk", dist_gonk_settings, G_N_ELEMENTS(dist_gonk_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_MP, "Big MP", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, +}; + +static EffectGroup rp250_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_808, "808", dist_808_settings, G_N_ELEMENTS(dist_808_settings)}, + {DIST_TYPE_GUYOD, "GuyOD", dist_guyod_settings, G_N_ELEMENTS(dist_guyod_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_MX, "MX", dist_mx_settings, G_N_ELEMENTS(dist_mx_settings)}, + {DIST_TYPE_DS, "DS", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, + {DIST_TYPE_DEATH, "Death", dist_death_settings, G_N_ELEMENTS(dist_death_settings)}, + {DIST_TYPE_GONK, "Gonk", dist_gonk_settings, G_N_ELEMENTS(dist_gonk_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_MP, "Big MP", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, +}; + +static EffectGroup rp355_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_808, "808", dist_808_settings, G_N_ELEMENTS(dist_808_settings)}, + {DIST_TYPE_SPARKDRIVE, "Sparkdrive", dist_sparkdrive_settings, G_N_ELEMENTS(dist_sparkdrive_settings)}, + {DIST_TYPE_GUYOD, "OD Overdrive", dist_guyod_settings, G_N_ELEMENTS(dist_guyod_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_REDLINE, "Redline", dist_redline_settings, G_N_ELEMENTS(dist_redline_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_MX, "MX", dist_mx_settings, G_N_ELEMENTS(dist_mx_settings)}, + {DIST_TYPE_DS, "DS", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, + {DIST_TYPE_DEATH, "Death", dist_death_settings, G_N_ELEMENTS(dist_death_settings)}, + {DIST_TYPE_GONK, "Gonk", dist_gonk_settings, G_N_ELEMENTS(dist_gonk_settings)}, + {DIST_TYPE_8TAVIA, "8tavia", dist_8tavia_settings, G_N_ELEMENTS(dist_8tavia_settings)}, + {DIST_TYPE_FUZZLATOR, "Fuzzlator", dist_fuzzlator_settings, G_N_ELEMENTS(dist_fuzzlator_settings)}, + {DIST_TYPE_CLASSIC_FUZZ, "Classic Fuzz", dist_classic_fuzz_settings, G_N_ELEMENTS(dist_classic_fuzz_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_MP, "Big MP", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, +}; + +static EffectGroup rp500_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_808, "808", dist_808_settings, G_N_ELEMENTS(dist_808_settings)}, + {DIST_TYPE_SPARKDRIVE, "Sparkdrive", dist_sparkdrive_settings, G_N_ELEMENTS(dist_sparkdrive_settings)}, + {DIST_TYPE_GUYOD, "OD Overdrive", dist_guyod_settings, G_N_ELEMENTS(dist_guyod_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_REDLINE, "Redline", dist_redline_settings, G_N_ELEMENTS(dist_redline_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_MX, "MX", dist_mx_settings, G_N_ELEMENTS(dist_mx_settings)}, + {DIST_TYPE_DS, "DS", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, + {DIST_TYPE_DEATH, "Death", dist_death_settings, G_N_ELEMENTS(dist_death_settings)}, + {DIST_TYPE_GONK, "Gonk", dist_gonk_settings, G_N_ELEMENTS(dist_gonk_settings)}, + {DIST_TYPE_8TAVIA, "8tavia", dist_8tavia_settings, G_N_ELEMENTS(dist_8tavia_settings)}, + {DIST_TYPE_FUZZLATOR, "Fuzzlator", dist_fuzzlator_settings, G_N_ELEMENTS(dist_fuzzlator_settings)}, + {DIST_TYPE_CLASSIC_FUZZ, "Classic Fuzz", dist_classic_fuzz_settings, G_N_ELEMENTS(dist_classic_fuzz_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_MP, "Big MP", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, +}; + +static EffectGroup rp1000_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_808, "808", dist_808_settings, G_N_ELEMENTS(dist_808_settings)}, + {DIST_TYPE_TS_MOD, "TS Mod", dist_ts_mod_settings, G_N_ELEMENTS(dist_ts_mod_settings)}, + {DIST_TYPE_SD_ODRV, "SD Overdrive", dist_sd_odrv_settings, G_N_ELEMENTS(dist_sd_odrv_settings)}, + {DIST_TYPE_OD_ODRV, "OD Overdrive", dist_od_odrv_settings, G_N_ELEMENTS(dist_od_odrv_settings)}, + {DIST_TYPE_SPARKDRIVE, "Sparkdrive", dist_sparkdrive_settings, G_N_ELEMENTS(dist_sparkdrive_settings)}, + {DIST_TYPE_GUYOD, "Guy Overdrive", dist_guyod_settings, G_N_ELEMENTS(dist_guyod_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_REDLINE, "Redline", dist_redline_settings, G_N_ELEMENTS(dist_redline_settings)}, + {DIST_TYPE_AMPDRIVR, "Amp Driver", dist_ampdrivr_settings, G_N_ELEMENTS(dist_ampdrivr_settings)}, + {DIST_TYPE_OC_DRIVE, "OC Drive", dist_oc_drive_settings, G_N_ELEMENTS(dist_oc_drive_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_MX, "MX Dist", dist_mx_settings, G_N_ELEMENTS(dist_mx_settings)}, + {DIST_TYPE_DS, "DS Dist", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, + {DIST_TYPE_DEATH, "Death", dist_death_settings, G_N_ELEMENTS(dist_death_settings)}, + {DIST_TYPE_GONK, "Gonk", dist_gonk_settings, G_N_ELEMENTS(dist_gonk_settings)}, + {DIST_TYPE_8TAVIA, "8tavia", dist_8tavia_settings, G_N_ELEMENTS(dist_8tavia_settings)}, + {DIST_TYPE_FUZZLATOR, "Fuzzlator", dist_fuzzlator_settings, G_N_ELEMENTS(dist_fuzzlator_settings)}, + {DIST_TYPE_CLASSIC_FUZZ, "Classic Fuzz", dist_classic_fuzz_settings, G_N_ELEMENTS(dist_classic_fuzz_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_MP, "Big Pi", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, +}; + +static EffectGroup gnx4_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_DS, "DS Dist", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_MP, "Big MP", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, + {DIST_TYPE_GUYOD, "Guy OD", dist_guyod_settings, G_N_ELEMENTS(dist_guyod_settings)}, + {DIST_TYPE_SPARKDRIVE, "Sparkdrive", dist_sparkdrive_settings, G_N_ELEMENTS(dist_sparkdrive_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, +}; + +static EffectGroup gnx3k_dist_group[] = { + {DIST_TYPE_SCREAMER, "Screamer", dist_screamer_settings, G_N_ELEMENTS(dist_screamer_settings)}, + {DIST_TYPE_RODENT, "Rodent", dist_rodent_settings, G_N_ELEMENTS(dist_rodent_settings)}, + {DIST_TYPE_DS, "DS", dist_ds_settings, G_N_ELEMENTS(dist_ds_settings)}, + {DIST_TYPE_DOD250, "DOD250", dist_dod250_settings, G_N_ELEMENTS(dist_dod250_settings)}, + {DIST_TYPE_MP, "Big MP", dist_mp_settings, G_N_ELEMENTS(dist_mp_settings)}, + {DIST_TYPE_GUYOD, "Guy OD", dist_guyod_settings, G_N_ELEMENTS(dist_guyod_settings)}, + {DIST_TYPE_SPARKDRIVE, "Sparkdrive", dist_sparkdrive_settings, G_N_ELEMENTS(dist_sparkdrive_settings)}, + {DIST_TYPE_GRUNGE, "Grunge", dist_grunge_settings, G_N_ELEMENTS(dist_grunge_settings)}, + {DIST_TYPE_FUZZY, "Fuzzy", dist_fuzzy_settings, G_N_ELEMENTS(dist_fuzzy_settings)}, + {DIST_TYPE_ZONE, "Zone", dist_zone_settings, G_N_ELEMENTS(dist_zone_settings)}, + {DIST_TYPE_8TAVIA, "8tavia", dist_8tavia_settings, G_N_ELEMENTS(dist_8tavia_settings)}, +}; + +static EffectGroup gnx3k_noisegate_group[] = { + {NOISEGATE_GATE, "Silencer", noisegate_silencer_settings, G_N_ELEMENTS(noisegate_silencer_settings)}, + {NOISEGATE_SWELL, "Pluck", noisegate_pluck_settings, G_N_ELEMENTS(noisegate_pluck_settings)}, +}; + +static EffectGroup noisegate_group[] = { + {NOISEGATE_GATE, "Gate", noisegate_gate_settings, G_N_ELEMENTS(noisegate_gate_settings)}, + {NOISEGATE_SWELL, "Swell", noisegate_swell_settings, G_N_ELEMENTS(noisegate_swell_settings)}, +}; + +static EffectGroup gnx4_chorusfx_group[] = { + {GNX3K_MOD_TYPE_CHORUS, "Chorus", gnx3k_chorus_settings, G_N_ELEMENTS(gnx3k_chorus_settings)}, + {GNX3K_MOD_TYPE_FLANGER, "Flanger", gnx3k_flanger_settings, G_N_ELEMENTS(gnx3k_flanger_settings)}, + {GNX3K_MOD_TYPE_PHASER, "Phaser", gnx3k_phaser_settings, G_N_ELEMENTS(gnx3k_phaser_settings)}, + {GNX3K_MOD_TYPE_TRIGFLANGER, "Triggered Flanger", gnx3k_trigflanger_settings, G_N_ELEMENTS(gnx3k_trigflanger_settings)}, + {GNX3K_MOD_TYPE_TRIGPHASER, "Triggered Phaser", gnx3k_trigphaser_settings, G_N_ELEMENTS(gnx3k_trigphaser_settings)}, + {GNX3K_MOD_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {GNX3K_MOD_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {GNX3K_MOD_TYPE_VIBRATO, "Vibrato", gnx3k_vibrato_settings, G_N_ELEMENTS(gnx3k_vibrato_settings)}, + {GNX3K_MOD_TYPE_ROTARY, "Rotary", gnx3k_rotary_settings, G_N_ELEMENTS(gnx3k_rotary_settings)}, + {GNX3K_MOD_TYPE_AUTOYA, "Auto Ya", gnx3k_autoya_settings, G_N_ELEMENTS(gnx3k_autoya_settings)}, + {GNX3K_MOD_TYPE_YAYA, "Ya Ya", gnx3k_yaya_settings, G_N_ELEMENTS(gnx3k_yaya_settings)}, + {GNX3K_MOD_TYPE_SYNTHTALK, "Synthtalk", gnx3k_synthtalk_settings, G_N_ELEMENTS(gnx3k_synthtalk_settings)}, + {GNX3K_MOD_TYPE_ENVELOPE, "Envelope", gnx3k_envelope_settings, G_N_ELEMENTS(gnx3k_envelope_settings)}, + {GNX3K_MOD_TYPE_DETUNE, "Detune", gnx3k_mod_detune_settings, G_N_ELEMENTS(gnx3k_mod_detune_settings)}, + {GNX3K_MOD_TYPE_PITCH, "Pitch", gnx3k_mod_pitch_settings, G_N_ELEMENTS(gnx3k_mod_pitch_settings)}, +}; + +static EffectGroup gnx3k_chorusfx_group[] = { + {GNX3K_MOD_TYPE_CHORUS, "Chorus", gnx3k_chorus_settings, G_N_ELEMENTS(gnx3k_chorus_settings)}, + {GNX3K_MOD_TYPE_FLANGER, "Flanger", gnx3k_flanger_settings, G_N_ELEMENTS(gnx3k_flanger_settings)}, + {GNX3K_MOD_TYPE_PHASER, "Phaser", gnx3k_phaser_settings, G_N_ELEMENTS(gnx3k_phaser_settings)}, + {GNX3K_MOD_TYPE_TRIGFLANGER, "Triggered Flanger", gnx3k_trigflanger_settings, G_N_ELEMENTS(gnx3k_trigflanger_settings)}, + {GNX3K_MOD_TYPE_TRIGPHASER, "Triggered Phaser", gnx3k_trigphaser_settings, G_N_ELEMENTS(gnx3k_trigphaser_settings)}, + {GNX3K_MOD_TYPE_UNOVIBE, "Unovibe", gnx3k_unovibe_settings, G_N_ELEMENTS(gnx3k_unovibe_settings)}, + {GNX3K_MOD_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {GNX3K_MOD_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {GNX3K_MOD_TYPE_VIBRATO, "Vibrato", gnx3k_vibrato_settings, G_N_ELEMENTS(gnx3k_vibrato_settings)}, + {GNX3K_MOD_TYPE_ROTARY, "Rotary", gnx3k_rotary_settings, G_N_ELEMENTS(gnx3k_rotary_settings)}, + {GNX3K_MOD_TYPE_AUTOYA, "Auto Ya", gnx3k_autoya_settings, G_N_ELEMENTS(gnx3k_autoya_settings)}, + {GNX3K_MOD_TYPE_YAYA, "Ya Ya", gnx3k_yaya_settings, G_N_ELEMENTS(gnx3k_yaya_settings)}, + {GNX3K_MOD_TYPE_SYNTHTALK, "Synthtalk", gnx3k_synthtalk_settings, G_N_ELEMENTS(gnx3k_synthtalk_settings)}, + {GNX3K_MOD_TYPE_ENVELOPE, "Envelope", gnx3k_envelope_settings, G_N_ELEMENTS(gnx3k_envelope_settings)}, + {GNX3K_MOD_TYPE_DETUNE, "Detune", gnx3k_mod_detune_settings, G_N_ELEMENTS(gnx3k_mod_detune_settings)}, + {GNX3K_MOD_TYPE_PITCH, "Pitch", gnx3k_mod_pitch_settings, G_N_ELEMENTS(gnx3k_mod_pitch_settings)}, +}; + +static EffectGroup rp155_chorusfx_group[] = { + {CHORUS_TYPE_CE, "CE Chorus", chorusfx_ce_settings, G_N_ELEMENTS(chorusfx_ce_settings)}, + {CHORUS_TYPE_DUAL, "Dual Chorus", chorusfx_dual_settings, G_N_ELEMENTS(chorusfx_dual_settings)}, + {CHORUS_TYPE_MULTI, "Multi Chorus", chorusfx_multi_settings, G_N_ELEMENTS(chorusfx_multi_settings)}, + {CHORUS_TYPE_FLANGER, "Flanger", chorusfx_flanger_settings, G_N_ELEMENTS(chorusfx_flanger_settings)}, + {CHORUS_TYPE_MXR_FLANGER, "MXR Flanger", chorusfx_mxr_flanger_settings, G_N_ELEMENTS(chorusfx_mxr_flanger_settings)}, + {CHORUS_TYPE_PHASER, "Phaser", chorusfx_phaser_settings, G_N_ELEMENTS(chorusfx_phaser_settings)}, + {CHORUS_TYPE_VIBRATO, "Vibrato", chorusfx_vibrato_settings, G_N_ELEMENTS(chorusfx_vibrato_settings)}, + {CHORUS_TYPE_ROTARY, "Rotary", chorusfx_rotary_settings, G_N_ELEMENTS(chorusfx_rotary_settings)}, + {CHORUS_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {CHORUS_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {CHORUS_TYPE_ENVELOPE, "Envelope", chorusfx_envelope_settings, G_N_ELEMENTS(chorusfx_envelope_settings)}, + {CHORUS_TYPE_AUTOYA, "AutoYa", chorusfx_autoya_settings, G_N_ELEMENTS(chorusfx_autoya_settings)}, + {CHORUS_TYPE_STEP_FILTER, "Step Filter", chorusfx_step_filter_settings, G_N_ELEMENTS(chorusfx_step_filter_settings)}, + {CHORUS_TYPE_WHAMMY, "Whammy", chorusfx_whammy_settings, G_N_ELEMENTS(chorusfx_whammy_settings)}, + {CHORUS_TYPE_PITCH_SHIFT, "Pitch Shift", chorusfx_pitch_shift_settings, G_N_ELEMENTS(chorusfx_pitch_shift_settings)}, + {CHORUS_TYPE_DETUNE, "Detune", chorusfx_detune_settings, G_N_ELEMENTS(chorusfx_detune_settings)}, + {CHORUS_TYPE_IPS, "Harmony Pitch", chorusfx_ips_settings, G_N_ELEMENTS(chorusfx_ips_settings)}, +}; + +static EffectGroup rp250_chorusfx_group[] = { + {CHORUS_TYPE_CE, "CE Chorus", chorusfx_ce_settings, G_N_ELEMENTS(chorusfx_ce_settings)}, + {CHORUS_TYPE_DUAL, "Dual Chorus", chorusfx_dual_settings, G_N_ELEMENTS(chorusfx_dual_settings)}, + {CHORUS_TYPE_MULTI, "Multi Chorus", chorusfx_multi_settings, G_N_ELEMENTS(chorusfx_multi_settings)}, + {CHORUS_TYPE_FLANGER, "Flanger", chorusfx_flanger_settings, G_N_ELEMENTS(chorusfx_flanger_settings)}, + {CHORUS_TYPE_MXR_FLANGER, "MXR FLANGER", chorusfx_mxr_flanger_settings, G_N_ELEMENTS(chorusfx_mxr_flanger_settings)}, + {CHORUS_TYPE_PHASER, "Phaser", chorusfx_phaser_settings, G_N_ELEMENTS(chorusfx_phaser_settings)}, + {CHORUS_TYPE_VIBRATO, "Vibrato", chorusfx_vibrato_settings, G_N_ELEMENTS(chorusfx_vibrato_settings)}, + {CHORUS_TYPE_ROTARY, "Rotary", chorusfx_rotary_settings, G_N_ELEMENTS(chorusfx_rotary_settings)}, + {CHORUS_TYPE_VIBROPAN, "Vibropan", chorusfx_vibropan_settings, G_N_ELEMENTS(chorusfx_vibropan_settings)}, + {CHORUS_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {CHORUS_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {CHORUS_TYPE_ENVELOPE, "Envelope", chorusfx_envelope_settings, G_N_ELEMENTS(chorusfx_envelope_settings)}, + {CHORUS_TYPE_AUTOYA, "AutoYa", chorusfx_autoya_settings, G_N_ELEMENTS(chorusfx_autoya_settings)}, + {CHORUS_TYPE_YAYA, "YaYa", chorusfx_yaya_settings, G_N_ELEMENTS(chorusfx_yaya_settings)}, + {CHORUS_TYPE_STEP_FILTER, "Step Filter", chorusfx_step_filter_settings, G_N_ELEMENTS(chorusfx_step_filter_settings)}, + {CHORUS_TYPE_WHAMMY, "Whammy", chorusfx_whammy_settings, G_N_ELEMENTS(chorusfx_whammy_settings)}, + {CHORUS_TYPE_PITCH_SHIFT, "Pitch Shift", chorusfx_pitch_shift_settings, G_N_ELEMENTS(chorusfx_pitch_shift_settings)}, + {CHORUS_TYPE_DETUNE, "Detune", chorusfx_detune_settings, G_N_ELEMENTS(chorusfx_detune_settings)}, + {CHORUS_TYPE_IPS, "IPS", chorusfx_ips_settings, G_N_ELEMENTS(chorusfx_ips_settings)}, +}; + +/* same as rp250, with IPS renamed to Harmony Pitch */ +static EffectGroup rp255_chorusfx_group[] = { + {CHORUS_TYPE_CE, "CE Chorus", chorusfx_ce_settings, G_N_ELEMENTS(chorusfx_ce_settings)}, + {CHORUS_TYPE_DUAL, "Dual Chorus", chorusfx_dual_settings, G_N_ELEMENTS(chorusfx_dual_settings)}, + {CHORUS_TYPE_MULTI, "Multi Chorus", chorusfx_multi_settings, G_N_ELEMENTS(chorusfx_multi_settings)}, + {CHORUS_TYPE_FLANGER, "Flanger", chorusfx_flanger_settings, G_N_ELEMENTS(chorusfx_flanger_settings)}, + {CHORUS_TYPE_MXR_FLANGER, "MXR FLANGER", chorusfx_mxr_flanger_settings, G_N_ELEMENTS(chorusfx_mxr_flanger_settings)}, + {CHORUS_TYPE_PHASER, "Phaser", chorusfx_phaser_settings, G_N_ELEMENTS(chorusfx_phaser_settings)}, + {CHORUS_TYPE_VIBRATO, "Vibrato", chorusfx_vibrato_settings, G_N_ELEMENTS(chorusfx_vibrato_settings)}, + {CHORUS_TYPE_ROTARY, "Rotary", chorusfx_rotary_settings, G_N_ELEMENTS(chorusfx_rotary_settings)}, + {CHORUS_TYPE_VIBROPAN, "Vibropan", chorusfx_vibropan_settings, G_N_ELEMENTS(chorusfx_vibropan_settings)}, + {CHORUS_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {CHORUS_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {CHORUS_TYPE_ENVELOPE, "Envelope", chorusfx_envelope_settings, G_N_ELEMENTS(chorusfx_envelope_settings)}, + {CHORUS_TYPE_AUTOYA, "AutoYa", chorusfx_autoya_settings, G_N_ELEMENTS(chorusfx_autoya_settings)}, + {CHORUS_TYPE_YAYA, "YaYa", chorusfx_yaya_settings, G_N_ELEMENTS(chorusfx_yaya_settings)}, + {CHORUS_TYPE_STEP_FILTER, "Step Filter", chorusfx_step_filter_settings, G_N_ELEMENTS(chorusfx_step_filter_settings)}, + {CHORUS_TYPE_WHAMMY, "Whammy", chorusfx_whammy_settings, G_N_ELEMENTS(chorusfx_whammy_settings)}, + {CHORUS_TYPE_PITCH_SHIFT, "Pitch Shift", chorusfx_pitch_shift_settings, G_N_ELEMENTS(chorusfx_pitch_shift_settings)}, + {CHORUS_TYPE_DETUNE, "Detune", chorusfx_detune_settings, G_N_ELEMENTS(chorusfx_detune_settings)}, + {CHORUS_TYPE_IPS, "Harmony Pitch", chorusfx_ips_settings, G_N_ELEMENTS(chorusfx_ips_settings)}, +}; + +static EffectGroup rp355_chorusfx_group[] = { + {CHORUS_TYPE_CE, "CE Chorus", chorusfx_ce_settings, G_N_ELEMENTS(chorusfx_ce_settings)}, + {CHORUS_TYPE_TC, "TC Chorus", chorusfx_tc_settings, G_N_ELEMENTS(chorusfx_tc_settings)}, + {CHORUS_TYPE_DUAL, "Dual Chorus", chorusfx_dual_settings, G_N_ELEMENTS(chorusfx_dual_settings)}, + {CHORUS_TYPE_MULTI, "Multi Chorus", chorusfx_multi_settings, G_N_ELEMENTS(chorusfx_multi_settings)}, + {CHORUS_TYPE_FLANGER, "Flanger", chorusfx_flanger_settings, G_N_ELEMENTS(chorusfx_flanger_settings)}, + {CHORUS_TYPE_TRIGGERED_FLANGER, "Triggered Flanger", chorusfx_trig_flanger_settings, G_N_ELEMENTS(chorusfx_trig_flanger_settings)}, + {CHORUS_TYPE_MXR_FLANGER, "MXR FLANGER", chorusfx_mxr_flanger_settings, G_N_ELEMENTS(chorusfx_mxr_flanger_settings)}, + {CHORUS_TYPE_EH_FLANGER, "EH Flanger", chorusfx_eh_flanger_settings, G_N_ELEMENTS(chorusfx_eh_flanger_settings)}, + {CHORUS_TYPE_PHASER, "Phaser", chorusfx_phaser_settings, G_N_ELEMENTS(chorusfx_phaser_settings)}, + {CHORUS_TYPE_TRIGGERED_PHASER, "Triggered Phaser", chorusfx_trig_phaser_settings, G_N_ELEMENTS(chorusfx_trig_phaser_settings)}, + {CHORUS_TYPE_MX_PHASER, "MX Phaser", chorusfx_mx_phaser_settings, G_N_ELEMENTS(chorusfx_mx_phaser_settings)}, + {CHORUS_TYPE_EH_PHASER, "EH Phaser", chorusfx_eh_phaser_settings, G_N_ELEMENTS(chorusfx_eh_phaser_settings)}, + {CHORUS_TYPE_VIBRATO, "Vibrato", chorusfx_vibrato_settings, G_N_ELEMENTS(chorusfx_vibrato_settings)}, + {CHORUS_TYPE_ROTARY, "Rotary", chorusfx_rotary_settings, G_N_ELEMENTS(chorusfx_rotary_settings)}, + {CHORUS_TYPE_VIBROPAN, "Vibropan", chorusfx_vibropan_settings, G_N_ELEMENTS(chorusfx_vibropan_settings)}, + {CHORUS_TYPE_UNOVIBE, "Unovibe", chorusfx_unovibe_settings, G_N_ELEMENTS(chorusfx_unovibe_settings)}, + {CHORUS_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {CHORUS_TYPE_OPTO_TREMOLO, "Opto Tremolo", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_BIAS_TREMOLO, "Bias Tremolo", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {CHORUS_TYPE_ENVELOPE, "Envelope", chorusfx_envelope_settings, G_N_ELEMENTS(chorusfx_envelope_settings)}, + {CHORUS_TYPE_FX25, "FX25", chorusfx_fx25_settings, G_N_ELEMENTS(chorusfx_fx25_settings)}, + {CHORUS_TYPE_AUTOYA, "AutoYa", chorusfx_autoya_settings, G_N_ELEMENTS(chorusfx_autoya_settings)}, + {CHORUS_TYPE_YAYA, "YaYa", chorusfx_yaya_settings, G_N_ELEMENTS(chorusfx_yaya_settings)}, + {CHORUS_TYPE_SYNTH_TALK, "Synth Talk", chorusfx_synth_talk_settings, G_N_ELEMENTS(chorusfx_synth_talk_settings)}, + {CHORUS_TYPE_STEP_FILTER, "Step Filter", chorusfx_step_filter_settings, G_N_ELEMENTS(chorusfx_step_filter_settings)}, + {CHORUS_TYPE_WHAMMY, "Whammy", chorusfx_whammy_settings, G_N_ELEMENTS(chorusfx_whammy_settings)}, + {CHORUS_TYPE_PITCH_SHIFT, "Pitch Shift", chorusfx_pitch_shift_settings, G_N_ELEMENTS(chorusfx_pitch_shift_settings)}, + {CHORUS_TYPE_DETUNE, "Detune", chorusfx_detune_settings, G_N_ELEMENTS(chorusfx_detune_settings)}, + {CHORUS_TYPE_IPS, "Harmony Pitch", chorusfx_ips_settings, G_N_ELEMENTS(chorusfx_ips_settings)}, + {CHORUS_TYPE_OCTAVER, "Octaver", chorusfx_octaver_settings, G_N_ELEMENTS(chorusfx_octaver_settings)}, +}; + +static EffectGroup rp500_chorusfx_group[] = { + {CHORUS_TYPE_CE, "CE Chorus", chorusfx_ce_settings, G_N_ELEMENTS(chorusfx_ce_settings)}, + {CHORUS_TYPE_TC, "TC Chorus", chorusfx_tc_settings, G_N_ELEMENTS(chorusfx_tc_settings)}, + {CHORUS_TYPE_DUAL, "Dual Chorus", chorusfx_dual_settings, G_N_ELEMENTS(chorusfx_dual_settings)}, + {CHORUS_TYPE_GLISTEN, "Glisten Chorus", chorusfx_glisten_settings, G_N_ELEMENTS(chorusfx_glisten_settings)}, + {CHORUS_TYPE_MULTI, "Multi Chorus", chorusfx_multi_settings, G_N_ELEMENTS(chorusfx_multi_settings)}, + {CHORUS_TYPE_FLANGER, "Flanger", chorusfx_flanger_settings, G_N_ELEMENTS(chorusfx_flanger_settings)}, + {CHORUS_TYPE_TRIGGERED_FLANGER, "Triggered Flanger", chorusfx_trig_flanger_settings, G_N_ELEMENTS(chorusfx_trig_flanger_settings)}, + {CHORUS_TYPE_MXR_FLANGER, "MXR FLANGER", chorusfx_mxr_flanger_settings, G_N_ELEMENTS(chorusfx_mxr_flanger_settings)}, + {CHORUS_TYPE_EH_FLANGER, "EH Flanger", chorusfx_eh_flanger_settings, G_N_ELEMENTS(chorusfx_eh_flanger_settings)}, + {CHORUS_TYPE_AD_FLANGER, "AD Flanger", chorusfx_ad_flanger_settings, G_N_ELEMENTS(chorusfx_ad_flanger_settings)}, + {CHORUS_TYPE_PHASER, "Phaser", chorusfx_phaser_settings, G_N_ELEMENTS(chorusfx_phaser_settings)}, + {CHORUS_TYPE_TRIGGERED_PHASER, "Triggered Phaser", chorusfx_trig_phaser_settings, G_N_ELEMENTS(chorusfx_trig_phaser_settings)}, + {CHORUS_TYPE_MX_PHASER, "MX Phaser", chorusfx_mx_phaser_settings, G_N_ELEMENTS(chorusfx_mx_phaser_settings)}, + {CHORUS_TYPE_EH_PHASER, "EH Phaser", chorusfx_eh_phaser_settings, G_N_ELEMENTS(chorusfx_eh_phaser_settings)}, + {CHORUS_TYPE_VIBRATO, "Vibrato", chorusfx_vibrato_settings, G_N_ELEMENTS(chorusfx_vibrato_settings)}, + {CHORUS_TYPE_ROTARY, "Rotary", chorusfx_rotary_settings, G_N_ELEMENTS(chorusfx_rotary_settings)}, + {CHORUS_TYPE_VIBROPAN, "Vibropan", chorusfx_vibropan_settings, G_N_ELEMENTS(chorusfx_vibropan_settings)}, + {CHORUS_TYPE_UNOVIBE, "Unovibe", chorusfx_unovibe_settings, G_N_ELEMENTS(chorusfx_unovibe_settings)}, + {CHORUS_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {CHORUS_TYPE_SCATTER_TREM, "ScatterTrem", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_OPTO_TREMOLO, "Opto Tremolo", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_BIAS_TREMOLO, "Bias Tremolo", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {CHORUS_TYPE_ENVELOPE, "Envelope", chorusfx_envelope_settings, G_N_ELEMENTS(chorusfx_envelope_settings)}, + {CHORUS_TYPE_FX25, "FX25", chorusfx_fx25_settings, G_N_ELEMENTS(chorusfx_fx25_settings)}, + {CHORUS_TYPE_AUTOYA, "AutoYa", chorusfx_autoya_settings, G_N_ELEMENTS(chorusfx_autoya_settings)}, + {CHORUS_TYPE_YAYA, "YaYa", chorusfx_yaya_settings, G_N_ELEMENTS(chorusfx_yaya_settings)}, + {CHORUS_TYPE_SYNTH_TALK, "Synth Talk", chorusfx_synth_talk_settings, G_N_ELEMENTS(chorusfx_synth_talk_settings)}, + {CHORUS_TYPE_STEP_FILTER, "Step Filter", chorusfx_step_filter_settings, G_N_ELEMENTS(chorusfx_step_filter_settings)}, + {CHORUS_TYPE_SAMPLE_HOLD, "Sample/Hold", chorusfx_sample_hold_settings, G_N_ELEMENTS(chorusfx_sample_hold_settings)}, + {CHORUS_TYPE_WHAMMY, "Whammy", chorusfx_whammy_settings, G_N_ELEMENTS(chorusfx_whammy_settings)}, + {CHORUS_TYPE_PITCH_SHIFT, "Pitch", chorusfx_pitch_shift_settings, G_N_ELEMENTS(chorusfx_pitch_shift_settings)}, + {CHORUS_TYPE_DETUNE, "Detune", chorusfx_detune_settings, G_N_ELEMENTS(chorusfx_detune_settings)}, + {CHORUS_TYPE_IPS, "Harmony Pitch", chorusfx_ips_settings, G_N_ELEMENTS(chorusfx_ips_settings)}, + {CHORUS_TYPE_OCTAVER, "Octaver", chorusfx_octaver_settings, G_N_ELEMENTS(chorusfx_octaver_settings)}, +}; + +static EffectGroup rp1000_chorusfx_group[] = { + {CHORUS_TYPE_CE, "CE Chorus", chorusfx_ce_settings, G_N_ELEMENTS(chorusfx_ce_settings)}, + {CHORUS_TYPE_TC, "TC Chorus", chorusfx_tc_settings, G_N_ELEMENTS(chorusfx_tc_settings)}, + {CHORUS_TYPE_DUAL, "Dual Chorus", chorusfx_dual_settings, G_N_ELEMENTS(chorusfx_dual_settings)}, + {CHORUS_TYPE_GLISTEN, "Glisten Chorus", chorusfx_glisten_settings, G_N_ELEMENTS(chorusfx_glisten_settings)}, + {CHORUS_TYPE_MULTI, "Multi Chorus", chorusfx_multi_settings, G_N_ELEMENTS(chorusfx_multi_settings)}, + {CHORUS_TYPE_VOO_DOO, "Analog Chorus", chorusfx_voo_doo_settings, G_N_ELEMENTS(chorusfx_voo_doo_settings)}, + {CHORUS_TYPE_CLONE, "Small Clone", chorusfx_clone_settings, G_N_ELEMENTS(chorusfx_clone_settings)}, + {CHORUS_TYPE_FLANGER, "Flanger", chorusfx_flanger_settings, G_N_ELEMENTS(chorusfx_flanger_settings)}, + {CHORUS_TYPE_TRIGGERED_FLANGER, "Triggered Flanger", chorusfx_trig_flanger_settings, G_N_ELEMENTS(chorusfx_trig_flanger_settings)}, + {CHORUS_TYPE_FLTFLANGER, "Filter Flanger", chorusfx_fltflanger_settings, G_N_ELEMENTS(chorusfx_fltflanger_settings)}, + {CHORUS_TYPE_MXR_FLANGER, "MXR FLANGER", chorusfx_mxr_flanger_settings, G_N_ELEMENTS(chorusfx_mxr_flanger_settings)}, + {CHORUS_TYPE_EH_FLANGER, "EH Flanger", chorusfx_eh_flanger_settings, G_N_ELEMENTS(chorusfx_eh_flanger_settings)}, + {CHORUS_TYPE_AD_FLANGER, "AD Flanger", chorusfx_ad_flanger_settings, G_N_ELEMENTS(chorusfx_ad_flanger_settings)}, + {CHORUS_TYPE_PHASER, "Phaser", chorusfx_phaser_settings, G_N_ELEMENTS(chorusfx_phaser_settings)}, + {CHORUS_TYPE_TRIGGERED_PHASER, "Triggered Phaser", chorusfx_trig_phaser_settings, G_N_ELEMENTS(chorusfx_trig_phaser_settings)}, + {CHORUS_TYPE_MX_PHASER, "MX Phaser", chorusfx_mx_phaser_settings, G_N_ELEMENTS(chorusfx_mx_phaser_settings)}, + {CHORUS_TYPE_EH_PHASER, "EH Phaser", chorusfx_eh_phaser_settings, G_N_ELEMENTS(chorusfx_eh_phaser_settings)}, + {CHORUS_TYPE_VIBRATO, "Vibrato", chorusfx_vibrato_settings, G_N_ELEMENTS(chorusfx_vibrato_settings)}, + {CHORUS_TYPE_ROTARY, "Rotary", chorusfx_rotary_settings, G_N_ELEMENTS(chorusfx_rotary_settings)}, + {CHORUS_TYPE_VIBROPAN, "Vibropan", chorusfx_vibropan_settings, G_N_ELEMENTS(chorusfx_vibropan_settings)}, + {CHORUS_TYPE_UNOVIBE, "Unovibe", chorusfx_unovibe_settings, G_N_ELEMENTS(chorusfx_unovibe_settings)}, + {CHORUS_TYPE_TREMOLO, "Tremolo", chorusfx_tremolo_settings, G_N_ELEMENTS(chorusfx_tremolo_settings)}, + {CHORUS_TYPE_SCATTER_TREM, "ScatterTrem", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_OPTO_TREMOLO, "Opto Tremolo", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_BIAS_TREMOLO, "Bias Tremolo", chorusfx_trem_settings, G_N_ELEMENTS(chorusfx_trem_settings)}, + {CHORUS_TYPE_PANNER, "Panner", chorusfx_panner_settings, G_N_ELEMENTS(chorusfx_panner_settings)}, + {CHORUS_TYPE_ENVELOPE, "Envelope", chorusfx_envelope_settings, G_N_ELEMENTS(chorusfx_envelope_settings)}, + {CHORUS_TYPE_FX25, "FX25", chorusfx_fx25_settings, G_N_ELEMENTS(chorusfx_fx25_settings)}, + {CHORUS_TYPE_AUTOYA, "AutoYa", chorusfx_autoya_settings, G_N_ELEMENTS(chorusfx_autoya_settings)}, + {CHORUS_TYPE_YAYA, "YaYa", chorusfx_yaya_settings, G_N_ELEMENTS(chorusfx_yaya_settings)}, + {CHORUS_TYPE_SYNTH_TALK, "Synth Talk", chorusfx_synth_talk_settings, G_N_ELEMENTS(chorusfx_synth_talk_settings)}, + {CHORUS_TYPE_STEP_FILTER, "Step Filter", chorusfx_step_filter_settings, G_N_ELEMENTS(chorusfx_step_filter_settings)}, + {CHORUS_TYPE_SAMPLE_HOLD, "Sample/Hold", chorusfx_sample_hold_settings, G_N_ELEMENTS(chorusfx_sample_hold_settings)}, + {CHORUS_TYPE_WHAMMY, "Whammy", chorusfx_whammy_settings, G_N_ELEMENTS(chorusfx_whammy_settings)}, + {CHORUS_TYPE_PITCH_SHIFT, "Pitch", chorusfx_pitch_shift_settings, G_N_ELEMENTS(chorusfx_pitch_shift_settings)}, + {CHORUS_TYPE_DETUNE, "Detune", chorusfx_detune_settings, G_N_ELEMENTS(chorusfx_detune_settings)}, + {CHORUS_TYPE_IPS, "Harmony Pitch", chorusfx_ips_settings, G_N_ELEMENTS(chorusfx_ips_settings)}, + {CHORUS_TYPE_OCTAVER, "Octaver", chorusfx_octaver_settings, G_N_ELEMENTS(chorusfx_octaver_settings)}, +}; + +static EffectGroup gnx3k_delay_group[] = { + {DELAY_GNX3K_TYPE_MONO, "Mono", gnx3k_delay_settings, G_N_ELEMENTS(gnx3k_delay_settings)}, + {DELAY_GNX3K_TYPE_PINGPONG, "Ping-Pong", gnx3k_delay_settings, G_N_ELEMENTS(gnx3k_delay_settings)}, + {DELAY_GNX3K_TYPE_ANALOG, "Analog", gnx3k_delay_settings, G_N_ELEMENTS(gnx3k_delay_settings)}, + {DELAY_GNX3K_TYPE_ANAPONG, "Analog-Pong", gnx3k_delay_settings, G_N_ELEMENTS(gnx3k_delay_settings)}, + {DELAY_GNX3K_TYPE_SPREAD, "Spread", gnx3k_delay_spread_settings, G_N_ELEMENTS(gnx3k_delay_spread_settings)}, +}; + +static EffectGroup rp250_delay_group[] = { + {DELAY_TYPE_ANALOG, "Analog", delay_analog_settings, G_N_ELEMENTS(delay_analog_settings)}, + {DELAY_TYPE_DIGITAL, "Digital", delay_digital_settings, G_N_ELEMENTS(delay_digital_settings)}, + {DELAY_TYPE_MODULATED, "Modulated", delay_modulated_settings, G_N_ELEMENTS(delay_modulated_settings)}, + {DELAY_TYPE_PONG, "Pong", delay_pong_settings, G_N_ELEMENTS(delay_pong_settings)}, + {DELAY_TYPE_TAPE, "Tape", delay_tape_settings, G_N_ELEMENTS(delay_tape_settings)}, +}; + +static EffectGroup rp355_delay_group[] = { + {DELAY_TYPE_ANALOG, "Analog", delay_analog_settings, G_N_ELEMENTS(delay_analog_settings)}, + {DELAY_TYPE_DM, "DM Delay", delay_dm_settings, G_N_ELEMENTS(delay_dm_settings)}, + {DELAY_TYPE_DIGITAL, "Digital", delay_digital_settings, G_N_ELEMENTS(delay_digital_settings)}, + {DELAY_TYPE_MODULATED, "Modulated", delay_modulated_settings, G_N_ELEMENTS(delay_modulated_settings)}, + {DELAY_TYPE_PONG, "Pong", delay_pong_settings, G_N_ELEMENTS(delay_pong_settings)}, + {DELAY_TYPE_TAPE, "Tape", delay_tape_settings, G_N_ELEMENTS(delay_tape_settings)}, + {DELAY_TYPE_ECHOPLEX, "Echo Plex", delay_echoplex_settings, G_N_ELEMENTS(delay_echoplex_settings)}, +}; + +static EffectGroup rp500_delay_group[] = { + {DELAY_RP500_TYPE_DIGITAL, "Digital", rp500_delay_digital_settings, G_N_ELEMENTS(rp500_delay_digital_settings)}, + {DELAY_RP500_TYPE_ANALOG, "Analog", rp500_delay_analog_settings, G_N_ELEMENTS(rp500_delay_analog_settings)}, + {DELAY_RP500_TYPE_DM, "DM Delay", rp500_delay_dm_settings, G_N_ELEMENTS(rp500_delay_dm_settings)}, + {DELAY_RP500_TYPE_ECHOPLEX, "Echo Plex", rp500_delay_echoplex_settings, G_N_ELEMENTS(rp500_delay_echoplex_settings)}, + {DELAY_RP500_TYPE_MODULATED, "Modulated", rp500_delay_modulated_settings, G_N_ELEMENTS(rp500_delay_modulated_settings)}, + {DELAY_RP500_TYPE_PONG, "Pong", rp500_delay_pong_settings, G_N_ELEMENTS(rp500_delay_pong_settings)}, + {DELAY_RP500_TYPE_REVERSE, "Reverse", rp500_delay_reverse_settings, G_N_ELEMENTS(rp500_delay_reverse_settings)}, + {DELAY_RP500_TYPE_TAPE, "Tape", rp500_delay_tape_settings, G_N_ELEMENTS(rp500_delay_tape_settings)}, +}; + +static EffectGroup rp1000_delay_group[] = { + {DELAY_RP500_TYPE_DIGITAL, "Digital", rp500_delay_digital_settings, G_N_ELEMENTS(rp500_delay_digital_settings)}, + {DELAY_RP500_TYPE_ANALOG, "Analog", rp500_delay_analog_settings, G_N_ELEMENTS(rp500_delay_analog_settings)}, + {DELAY_RP500_TYPE_DM, "DM Delay", rp500_delay_dm_settings, G_N_ELEMENTS(rp500_delay_dm_settings)}, + {DELAY_RP500_TYPE_ECHOPLEX, "Echo Plex", rp500_delay_echoplex_settings, G_N_ELEMENTS(rp500_delay_echoplex_settings)}, + {DELAY_RP500_TYPE_MODULATED, "Modulated", rp500_delay_modulated_settings, G_N_ELEMENTS(rp500_delay_modulated_settings)}, + {DELAY_RP500_TYPE_PONG, "Pong", rp500_delay_pong_settings, G_N_ELEMENTS(rp500_delay_pong_settings)}, + {DELAY_RP500_TYPE_REVERSE, "Reverse", rp500_delay_reverse_settings, G_N_ELEMENTS(rp500_delay_reverse_settings)}, + {DELAY_RP500_TYPE_TAPE, "Tape", rp500_delay_tape_settings, G_N_ELEMENTS(rp500_delay_tape_settings)}, + {DELAY_RP1000_TYPE_LO_FI, "Lo Fidelity", rp1000_delay_lo_fi_settings, G_N_ELEMENTS(rp1000_delay_lo_fi_settings)}, + {DELAY_RP1000_TYPE_2_TAP, "2-tap", rp1000_delay_2_tap_settings, G_N_ELEMENTS(rp1000_delay_2_tap_settings)}, +}; + +static EffectGroup gnx3k_reverb_group[] = { + {GNX3K_REVERB_TYPE_STUDIO, "Studio", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_ROOM, "Room", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_CLUB, "Club", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_PLATE, "Plate", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_HALL, "Hall", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_AMPHITHEATER, "Amphitheater", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_CHURCH, "Church", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_GARAGE, "Garage", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_ARENA, "Arena", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, + {GNX3K_REVERB_TYPE_SPRING, "Spring", gnx3k_reverb_settings, G_N_ELEMENTS(gnx3k_reverb_settings)}, +}; + +static EffectGroup reverb_group[] = { + {REVERB_TYPE_TWIN, "Twin", reverb_twin_settings, G_N_ELEMENTS(reverb_twin_settings)}, + {REVERB_TYPE_LEX_AMBIENCE, "Lexicon ambience", reverb_lex_settings, G_N_ELEMENTS(reverb_lex_settings)}, + {REVERB_TYPE_LEX_STUDIO, "Lexicon studio", reverb_lex_settings, G_N_ELEMENTS(reverb_lex_settings)}, + {REVERB_TYPE_LEX_ROOM, "Lexicon room", reverb_lex_settings, G_N_ELEMENTS(reverb_lex_settings)}, + {REVERB_TYPE_LEX_HALL, "Lexicon hall", reverb_lex_settings, G_N_ELEMENTS(reverb_lex_settings)}, + {REVERB_TYPE_EMT240_PLATE, "EMT240 Plate", reverb_lex_settings, G_N_ELEMENTS(reverb_lex_settings)}, +}; + +static EffectGroup rp155_amp_group[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Super Lead Plexi", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_JCM800, "JCM800", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_JCM900, "JCM900", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_AC15, "AC15", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_AC30TB, "AC30TB", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark II", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SOLO, "Solo", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_METAL, "Metal", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BRIGHT, "Bright", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_CLEAN, "Clean", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_ACOUSTIC, "Acoustic", rp250_amp_settings2, G_N_ELEMENTS(rp250_amp_settings2)}, + {AMP_TYPE_DIRECT, "Direct", rp250_amp_settings2, G_N_ELEMENTS(rp250_amp_settings2)}, +}; + +static EffectGroup rp250_amp_group[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Super Lead Plexi", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_JCM800, "JCM800", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_JCM900, "JCM900", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_AC15, "AC15", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_AC30TB, "AC30TB", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark II", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SOLO, "Solo", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_METAL, "Metal", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BRIGHT, "Bright", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_CLEAN, "Clean", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_ACOUSTIC, "Acoustic", rp250_amp_settings2, G_N_ELEMENTS(rp250_amp_settings2)}, + {AMP_TYPE_DIRECT, "Direct", rp250_amp_settings2, G_N_ELEMENTS(rp250_amp_settings2)}, +}; + +/* same as RP250, with added 45 JTM, JMPPNL and SOLDNO */ +static EffectGroup rp255_amp_group[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Super Lead Plexi", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_PLEXI_JTM_45, "Plexi JTM-45", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_PLEXI_JUMP_PANEL, "Plexi Jump Panel", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_JCM800, "JCM800", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_JCM900, "JCM900", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_AC15, "AC15", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_AC30TB, "AC30TB", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark II", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SOLDANO_100, "Soldano 100", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_SOLO, "Solo", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_METAL, "Metal", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_BRIGHT, "Bright", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_CLEAN, "Clean", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp250_amp_settings, G_N_ELEMENTS(rp250_amp_settings)}, + {AMP_TYPE_ACOUSTIC, "Acoustic", rp250_amp_settings2, G_N_ELEMENTS(rp250_amp_settings2)}, + {AMP_TYPE_DIRECT, "Direct", rp250_amp_settings2, G_N_ELEMENTS(rp250_amp_settings2)}, +}; + +static EffectGroup rp355_amp_select_group[] = { + {AMP_CHANNEL_A, "A", NULL, -1}, + {AMP_CHANNEL_B, "B", NULL, -1}, +}; + +static EffectGroup rp355_amp_group_A[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_PLEXI_JTM_45, "Plexi JTM-45", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Plexi Lead", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_PLEXI_JUMP_PANEL, "Plexi Jump Panel", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_JCM800, "JCM800", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_JCM900, "JCM900", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_AC15, "AC-15", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_AC30TB, "AC-30 TB", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark IIC", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_SOLDANO_100, "Soldano 100", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_SOLO, "Solo", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_METAL, "Metal", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_BRIGHT, "Bright Clean", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_CHUNK, "Chunk", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_CLEAN, "Clean Tube", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_GSP2101_CLEAN_TUBE, "GSP2101 Clean Tube", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_GSP2101_SAT_TUBE, "GSP2101 Sat Tube", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_MONSTER, "Monster", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_TWEEDFACE, "Tweedface", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_BLACKBASS, "Blackbass", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_STONER_ROCK, "Stoner Rock", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_DARK_METAL, "Dark Metal", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_BROWN_SOUND, "Brown Sound", rp355_amp_settings_A, G_N_ELEMENTS(rp355_amp_settings_A)}, + {AMP_TYPE_ACOUSTIC, "Dread Acoustic", rp355_amp_settings2_A, G_N_ELEMENTS(rp355_amp_settings2_A)}, + {AMP_TYPE_JUMBO_ACOUSTIC, "Jumbo Acoustic", rp355_amp_settings2_A, G_N_ELEMENTS(rp355_amp_settings2_A)}, + {AMP_TYPE_DIRECT, "Direct", rp355_amp_settings2_A, G_N_ELEMENTS(rp355_amp_settings2_A)}, +}; + +static EffectGroup rp355_amp_group_B[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_PLEXI_JTM_45, "Plexi JTM-45", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Plexi Lead", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_PLEXI_JUMP_PANEL, "Plexi Jump Panel", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_JCM800, "JCM800", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_JCM900, "JCM900", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_AC15, "AC-15", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_AC30TB, "AC-30 TB", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark IIC", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_SOLDANO_100, "Soldano 100", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_SOLO, "Solo", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_METAL, "Metal", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_BRIGHT, "Bright Clean", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_CHUNK, "Chunk", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_CLEAN, "Clean Tube", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_GSP2101_CLEAN_TUBE, "GSP2101 Clean Tube", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_GSP2101_SAT_TUBE, "GSP2101 Sat Tube", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_MONSTER, "Monster", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_TWEEDFACE, "Tweedface", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_BLACKBASS, "Blackbass", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_STONER_ROCK, "Stoner Rock", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_DARK_METAL, "Dark Metal", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_BROWN_SOUND, "Brown Sound", rp355_amp_settings_B, G_N_ELEMENTS(rp355_amp_settings_B)}, + {AMP_TYPE_ACOUSTIC, "Dread Acoustic", rp355_amp_settings2_B, G_N_ELEMENTS(rp355_amp_settings2_B)}, + {AMP_TYPE_JUMBO_ACOUSTIC, "Jumbo Acoustic", rp355_amp_settings2_B, G_N_ELEMENTS(rp355_amp_settings2_B)}, + {AMP_TYPE_DIRECT, "Direct", rp355_amp_settings2_B, G_N_ELEMENTS(rp355_amp_settings2_B)}, +}; + +static EffectGroup rp500_amp_group[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BROWN_BASSMAN, "Brown Bassman", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_PLEXI_JTM_45, "Plexi JTM-45", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Plexi Lead", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_PLEXI_JUMP_PANEL, "Plexi Jump Panel", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JCM800, "JCM800", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JCM900, "JCM900", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JCM2000, "JCM2000", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_AC15, "AC-15", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_AC30TB, "AC-30 TB", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark IIC", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_IV, "Boogie Mark IV", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TRIPLE_RECTIFIER, "Triple Rectifier", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_LEGACY_VL100, "Legacy VL-100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SOLDANO_100, "Soldano 100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SUPERGROUP, "Supergroup", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_GA40, "GA-40", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_OR120, "OR-120", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_PV5150II, "PV 5150II", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_RG100, "RG100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JC120_JAZZ, "JC-120 Jazz", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SOLAR100, "Solar 100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SOLO, "Solo", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_METAL, "Metal", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BRIGHT, "Bright Clean", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CHUNK, "Chunk", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CLEAN, "Clean Tube", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLUES, "Blues", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_FUZZ, "Fuzz", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SPANK, "Spank", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_GSP2101_CLEAN_TUBE, "GSP2101 Clean Tube", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_GSP2101_SAT_TUBE, "GSP2101 Sat Tube", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CRUNCH, "Crunch", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MONSTER, "Monster", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TWEEDFACE, "Tweedface", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLACKBASS, "Blackbass", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_STONER_ROCK, "Stoner Rock", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_DARK_METAL, "Dark Metal", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TRANSISTOR, "Transistor", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BROWN_SOUND, "Brown Sound", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MOSH, "Mosh", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_ACOUSTIC, "Dread Acoustic", rp500_amp_settings2, G_N_ELEMENTS(rp500_amp_settings2)}, + {AMP_TYPE_JUMBO_ACOUSTIC, "Jumbo Acoustic", rp500_amp_settings2, G_N_ELEMENTS(rp500_amp_settings2)}, + {AMP_TYPE_DIRECT, "Direct", rp500_amp_settings3, G_N_ELEMENTS(rp500_amp_settings3)}, +}; + +static EffectGroup rp1000_amp_group[] = { + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BROWN_BASSMAN, "Brown Bassman", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_PLEXI_JTM_45, "Plexi JTM-45", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Plexi Lead", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_PLEXI_JUMP_PANEL, "Plexi Jump Panel", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JCM800, "JCM800", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JCM900, "JCM900", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JCM2000, "JCM2000", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_AC15, "AC-15", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_AC30TB, "AC-30 TB", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark IIC", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BOOGIE_MARK_IV, "Boogie Mark IV", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TRIPLE_RECTIFIER, "Triple Rectifier", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_22_CALIBR, ".22 Caliber", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_LEGACY_VL100, "Legacy VL-100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CHIEF, "Matchless Chieftan", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SOLDANO_100, "Soldano 100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SUPERGROUP, "Supergroup", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_GA40, "GA-40", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_OR120, "OR-120", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_PV5150II, "PV 5150II", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_RG100, "RG100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_JC120_JAZZ, "JC-120 Jazz", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SOLAR100, "Solar 100", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SOLO, "Solo", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_METAL, "Metal", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BRIGHT, "Bright Clean", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CHUNK, "Chunk", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CLEAN, "Clean Tube", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_HIGH_GAIN, "High Gain", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLUES, "Blues", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_FUZZ, "Fuzz", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_SPANK, "Spank", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_GSP2101_CLEAN_TUBE, "GSP2101 Clean Tube", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_GSP2101_SAT_TUBE, "GSP2101 Sat Tube", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_CRUNCH, "Crunch", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MONSTER, "Monster", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TWEEDFACE, "Tweedface", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BLACKBASS, "Blackbass", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_STONER_ROCK, "Stoner Rock", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_DARK_METAL, "Dark Metal", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_TRANSISTOR, "Transistor", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_BROWN_SOUND, "Brown Sound", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_MOSH, "Mosh", rp500_amp_settings, G_N_ELEMENTS(rp500_amp_settings)}, + {AMP_TYPE_ACOUSTIC, "Dread Acoustic", rp500_amp_settings2, G_N_ELEMENTS(rp500_amp_settings2)}, + {AMP_TYPE_JUMBO_ACOUSTIC, "Jumbo Acoustic", rp500_amp_settings2, G_N_ELEMENTS(rp500_amp_settings2)}, + {AMP_TYPE_DIRECT, "Direct", rp500_amp_settings3, G_N_ELEMENTS(rp500_amp_settings3)}, +}; + +static EffectGroup gnx3k_amp_group[] = { + {AMP_TYPE_DIRECT, "Direct", NULL, -1}, + {AMP_TYPE_TWEED_CHAMP, "Tweed Champ", NULL, -1}, + {AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", NULL, -1}, + {AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", NULL, -1}, + {AMP_TYPE_BROWN_BASSMAN, "Brown Bassman", NULL, -1}, + {AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", NULL, -1}, + {AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", NULL, -1}, + {AMP_TYPE_PLEXI_JTM_45, "Plexi JTM-45", NULL, -1}, + {AMP_TYPE_SUPER_LEAD_PLEXI, "Plexi Lead", NULL, -1}, + {AMP_TYPE_PLEXI_JUMP_PANEL, "Plexi Jump Panel", NULL, -1}, + {AMP_TYPE_MASTER_VOLUME, "Master Volume", NULL, -1}, + {AMP_TYPE_JCM800, "JCM800", NULL, -1}, + {AMP_TYPE_JCM900, "JCM900", NULL, -1}, + {AMP_TYPE_JCM2000, "JCM2000", NULL, -1}, + {AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark II", NULL, -1}, + {AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", NULL, -1}, + {AMP_TYPE_AC15, "AC-15", NULL, -1}, + {AMP_TYPE_AC30TB, "AC-30 TB", NULL, -1}, + {AMP_TYPE_HIWATT_100, "Hiwatt 100", NULL, -1}, + {AMP_TYPE_SOLO, "Solo", NULL, -1}, + {AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", NULL, -1}, + {AMP_TYPE_LEGACY_VL100, "Legacy VL-100", NULL, -1}, + {AMP_TYPE_GSP2101_CLEAN_TUBE, "GSP2101 Clean Tube", NULL, -1}, + {AMP_TYPE_GSP2101_SAT_TUBE, "GSP2101 Sat Tube", NULL, -1}, + {AMP_TYPE_SPANK, "Spank", NULL, -1}, + {AMP_TYPE_METAL, "Metal", NULL, -1}, + {AMP_TYPE_BRIGHT, "Bright Clean", NULL, -1}, + {AMP_TYPE_CHUNK, "Chunk", NULL, -1}, + {AMP_TYPE_CLEAN, "Clean Tube", NULL, -1}, + {AMP_TYPE_CRUNCH, "Crunch", NULL, -1}, + {AMP_TYPE_HIGH_GAIN, "High Gain", NULL, -1}, + {AMP_TYPE_BLUES, "Blues", NULL, -1}, + {AMP_TYPE_FUZZ, "Fuzz", NULL, -1}, + {AMP_TYPE_JUMBO_ACOUSTIC, "Jumbo Acoustic", NULL, -1}, + {AMP_TYPE_ACOUSTIC, "Dread Acoustic", NULL, -1}, + {AMP_TYPE_SVT_ROCK_BASS, "SVT Rock Bass", NULL, -1}, + {AMP_TYPE_SVT_CLASSIC_BASS, "SVT Classic Bass", NULL, -1}, + {AMP_TYPE_PEG_B15_BASS, "Peg B-15 Bass", NULL, -1}, + {AMP_TYPE_BASIC_BASS , "Basic Bass", NULL, -1}, + {AMP_TYPE_SHOWMAN_BASS , "Showman Bass", NULL, -1}, + {AMP_TYPE_ASH_MODERN_BASS , "Ash Modern Bass", NULL, -1}, + {AMP_TYPE_BRIT_BASS , "Brit Bass", NULL, -1}, + {AMP_TYPE_SOLAR_BASS , "Solar 200s Bass", NULL, -1}, + {AMP_TYPE_BOOGIE_BASS , "Boogie Bass", NULL, -1}, + {AMP_TYPE_HART_BASS , "Hart Bass", NULL, -1}, +}; + +static EffectGroup rp250_eq_group[] = { + {EQ_TYPE_BRIGHT, "Bright", rp250_eq_settings, G_N_ELEMENTS(rp250_eq_settings)}, + {EQ_TYPE_MIDBOOST, "Mid Boost", rp250_eq_settings, G_N_ELEMENTS(rp250_eq_settings)}, + {EQ_TYPE_SCOOP, "Scoop", rp250_eq_settings, G_N_ELEMENTS(rp250_eq_settings)}, + {EQ_TYPE_WARM, "Warm", rp250_eq_settings, G_N_ELEMENTS(rp250_eq_settings)}, +}; + +static EffectGroup rp355_eq_group_A[] = { + {EQ_TYPE_BRIGHT, "Bright", rp355_eq_settings_A, G_N_ELEMENTS(rp355_eq_settings_A)}, + {EQ_TYPE_MIDBOOST, "Mid Boost", rp355_eq_settings_A, G_N_ELEMENTS(rp355_eq_settings_A)}, + {EQ_TYPE_SCOOP, "Scoop", rp355_eq_settings_A, G_N_ELEMENTS(rp355_eq_settings_A)}, + {EQ_TYPE_WARM, "Warm", rp355_eq_settings_A, G_N_ELEMENTS(rp355_eq_settings_A)}, +}; + +static EffectGroup rp355_eq_group_B[] = { + {EQ_TYPE_BRIGHT, "Bright", rp355_eq_settings_B, G_N_ELEMENTS(rp355_eq_settings_B)}, + {EQ_TYPE_MIDBOOST, "Mid Boost", rp355_eq_settings_B, G_N_ELEMENTS(rp355_eq_settings_B)}, + {EQ_TYPE_SCOOP, "Scoop", rp355_eq_settings_B, G_N_ELEMENTS(rp355_eq_settings_B)}, + {EQ_TYPE_WARM, "Warm", rp355_eq_settings_B, G_N_ELEMENTS(rp355_eq_settings_B)}, +}; + +static EffectGroup rp500_eq_group[] = { + {-1, NULL, rp500_eq_settings, G_N_ELEMENTS(rp500_eq_settings)}, +}; + +static EffectGroup rp155_amp_cab_group[] = { + {AMP_CAB_DIRECT, "Direct", NULL, -1}, + {AMP_CAB_DELUXE, "Deluxe 1x12", NULL, -1}, + {AMP_CAB_TWIN, "Twin 2x12", NULL, -1}, + {AMP_CAB_BRITISH2_12, "British 2x12", NULL, -1}, + {AMP_CAB_BASSMAN, "Bassman 4x10", NULL, -1}, + {AMP_CAB_BRITISH4_12, "British 4x12", NULL, -1}, + {AMP_CAB_VINTAGE, "Vintage V30 4x12", NULL, -1}, + {AMP_CAB_DIGI_SOLO, "DigiTech Solo 4x12", NULL, -1}, + {AMP_CAB_DIGI_BRIGHT, "DigiTech Bright 2x12", NULL, -1}, + {AMP_CAB_DIGI_METAL, "DigiTech Metal 4x12", NULL, -1}, + {AMP_CAB_DIGI_ROCK, "DigiTech Rock 4x12", NULL, -1}, + {AMP_CAB_DIGI_ALT, "DigiTech Alt 4x12", NULL, -1}, + {AMP_CAB_DIGI_VNTG, "DigiTech Vntg 4x12", NULL, -1}, +}; + +static EffectGroup rp250_amp_cab_group[] = { + {AMP_CAB_DIRECT, "Direct", NULL, -1}, + {AMP_CAB_CHAMP, "Champ 1x8", NULL, -1}, + {AMP_CAB_DELUXE, "Deluxe 1x12", NULL, -1}, + {AMP_CAB_TWIN, "Twin 2x12", NULL, -1}, + {AMP_CAB_BRITISH2_12, "British 2x12", NULL, -1}, + {AMP_CAB_BASSMAN, "Bassman 4x10", NULL, -1}, + {AMP_CAB_BRITISH4_12, "British 4x12", NULL, -1}, + {AMP_CAB_BRITISH_GREEN, "British Green 4x12", NULL, -1}, + {AMP_CAB_VINTAGE, "Vintage V30 4x12", NULL, -1}, + {AMP_CAB_DIGI_SOLO, "DigiTech Solo 4x12", NULL, -1}, + {AMP_CAB_DIGI_BRIGHT, "DigiTech Bright 2x12", NULL, -1}, + {AMP_CAB_DIGI_METAL, "DigiTech Metal 4x12", NULL, -1}, + {AMP_CAB_DIGI_ROCK, "DigiTech Rock 4x12", NULL, -1}, + {AMP_CAB_DIGI_ALT, "DigiTech Alt 4x12", NULL, -1}, + {AMP_CAB_DIGI_VNTG, "DigiTech Vntg 4x12", NULL, -1}, +}; + +static EffectGroup rp355_amp_cab_group[] = { + {AMP_CAB_DIRECT, "Direct", NULL, -1}, + {AMP_CAB_CHAMP, "Champ 1x8", NULL, -1}, + {AMP_CAB_DELUXE, "Deluxe 1x12", NULL, -1}, + {AMP_CAB_DELUXE_REVERB, "Deluxe Reverb 1x12", NULL, -1}, + {AMP_CAB_BLONDE2_12, "Blonde 2x12", NULL, -1}, + {AMP_CAB_TWIN, "Twin 2x12", NULL, -1}, + {AMP_CAB_BRITISH2_12, "British 2x12", NULL, -1}, + {AMP_CAB_BASSMAN, "Bassman 4x10", NULL, -1}, + {AMP_CAB_BRITISH4_12, "British 4x12", NULL, -1}, + {AMP_CAB_BRITISH_GREEN, "British Green 4x12", NULL, -1}, + {AMP_CAB_FANE4_12, "Fane 4x12", NULL, -1}, + {AMP_CAB_BOUTIQUE4_12, "Boutique 4x12", NULL, -1}, + {AMP_CAB_VINTAGE, "Vintage V30 4x12", NULL, -1}, + {AMP_CAB_DIGI_SOLO, "DigiTech Solo 4x12", NULL, -1}, + {AMP_CAB_DIGI_BRIGHT, "DigiTech Bright 2x12", NULL, -1}, + {AMP_CAB_DIGI_METAL, "DigiTech Metal 4x12", NULL, -1}, + {AMP_CAB_DIGI_ROCK, "DigiTech Rock 4x12", NULL, -1}, + {AMP_CAB_DIGI_ALT, "DigiTech Alt 4x12", NULL, -1}, + {AMP_CAB_DIGI_VNTG, "DigiTech Vntg 4x12", NULL, -1}, +}; + +static EffectGroup rp500_amp_cab_group[] = { + {AMP_CAB_DIRECT, "Direct", NULL, -1}, + {AMP_CAB_CHAMP, "Champ", NULL, -1}, + {AMP_CAB_DELUXE, "Deluxe", NULL, -1}, + {AMP_CAB_DELUXE_REVERB, "Deluxe Reverb 1x12", NULL, -1}, + {AMP_CAB_BRITISH1_12, "British 1x12", NULL, -1}, + {AMP_CAB_GA1_12, "GA 1x12", NULL, -1}, + {AMP_CAB_BLONDE2_12, "Blonde 2x12", NULL, -1}, + {AMP_CAB_TWIN, "Twin 2x12", NULL, -1}, + {AMP_CAB_BRITISH2_12, "British 2x12", NULL, -1}, + {AMP_CAB_JAZZ2_12, "Jazz 2x12", NULL, -1}, + {AMP_CAB_BASSMAN, "Bassman 4x10", NULL, -1}, + {AMP_CAB_BRITISH4_12, "British 4x12", NULL, -1}, + {AMP_CAB_BRITISH_GREEN, "Greenback 4x12", NULL, -1}, + {AMP_CAB_FANE4_12, "Fane 4x12", NULL, -1}, + {AMP_CAB_BOUTIQUE4_12, "Boutique 4x12", NULL, -1}, + {AMP_CAB_VINTAGE, "Vintage 4x12", NULL, -1}, + {AMP_CAB_RECTO4_12, "Recto 4x12", NULL, -1}, + {AMP_CAB_DIGI_SOLO, "DigiTech Solo 4x12", NULL, -1}, + {AMP_CAB_DIGI_BRIGHT, "DigiTech Bright 2x12", NULL, -1}, + {AMP_CAB_DIGI_METAL, "DigiTech Metal 4x12", NULL, -1}, + {AMP_CAB_DIGI_ROCK, "DigiTech Rock 4x12", NULL, -1}, + {AMP_CAB_DIGI_ALT, "DigiTech Alt 4x12", NULL, -1}, + {AMP_CAB_DIGI_VNTG, "DigiTech Vintage 4x12", NULL, -1}, + {AMP_CAB_DIGI_CHUNK, "DigiTech Chunk 4x12", NULL, -1}, + {AMP_CAB_DIGI_SPANK2_12, "DigiTech Spank 2x12", NULL, -1}, + {AMP_CAB_DIGI_SPKR_COMP, "DigiTech Spkr Comp", NULL, -1}, +}; + +static EffectGroup rp1000_amp_cab_group[] = { + {AMP_CAB_DIRECT, "Direct", NULL, -1}, + {AMP_CAB_CHAMP, "Champ", NULL, -1}, + {AMP_CAB_DELUXE, "Deluxe", NULL, -1}, + {AMP_CAB_DELUXE_REVERB, "Deluxe Reverb 1x12", NULL, -1}, + {AMP_CAB_BRITISH1_12, "British 1x12", NULL, -1}, + {AMP_CAB_GA1_12, "GA 1x12", NULL, -1}, + {AMP_CAB_BLONDE2_12, "Blonde 2x12", NULL, -1}, + {AMP_CAB_TWIN, "Twin 2x12", NULL, -1}, + {AMP_CAB_BRITISH2_12, "British 2x12", NULL, -1}, + {AMP_CAB_JAZZ2_12, "Jazz 2x12", NULL, -1}, + {AMP_CAB_JBL_215, "JBL/Lansing Enclosure", NULL, -1}, + {AMP_CAB_BASSMAN, "Bassman 4x10", NULL, -1}, + {AMP_CAB_BRITISH4_12, "British 4x12", NULL, -1}, + {AMP_CAB_BRITISH_GREEN, "Greenback 4x12", NULL, -1}, + {AMP_CAB_FANE4_12, "Fane 4x12", NULL, -1}, + {AMP_CAB_BOUTIQUE4_12, "Boutique 4x12", NULL, -1}, + {AMP_CAB_VINTAGE, "Vintage 4x12", NULL, -1}, + {AMP_CAB_RECTO4_12, "Recto 4x12", NULL, -1}, + {AMP_CAB_DIGI_SOLO, "DigiTech Solo 4x12", NULL, -1}, + {AMP_CAB_DIGI_BRIGHT, "DigiTech Bright 2x12", NULL, -1}, + {AMP_CAB_DIGI_METAL, "DigiTech Metal 4x12", NULL, -1}, + {AMP_CAB_DIGI_ROCK, "DigiTech Rock 4x12", NULL, -1}, + {AMP_CAB_DIGI_ALT, "DigiTech Alt 4x12", NULL, -1}, + {AMP_CAB_DIGI_VNTG, "DigiTech Vintage 4x12", NULL, -1}, + {AMP_CAB_DIGI_CHUNK, "DigiTech Chunk 4x12", NULL, -1}, + {AMP_CAB_DIGI_SPANK2_12, "DigiTech Spank 2x12", NULL, -1}, + {AMP_CAB_DIGI_SPKR_COMP, "DigiTech Spkr Comp", NULL, -1}, +}; + +static EffectGroup gnx3k_amp_cab_group[] = { + {GNX_AMP_CAB_DIRECT, "Direct", NULL, -1}, + {GNX_AMP_CAB_TWEED1_8, "Tweed 1x8", NULL, -1}, + {GNX_AMP_CAB_TWEED1_12, "Tweed 1x12", NULL, -1}, + {GNX_AMP_CAB_BLACKFACE1_12, "Blackface 1x12", NULL, -1}, + {GNX_AMP_CAB_BRITISH1_12, "British 1x12", NULL, -1}, + {GNX_AMP_CAB_BLACKFACE2_12, "Blackface 2x12", NULL, -1}, + {GNX_AMP_CAB_BLONDE2_12, "Blonde 2x12", NULL, -1}, + {GNX_AMP_CAB_BRITISH2_12, "British 2x12", NULL, -1}, + {GNX_AMP_CAB_TWEED4_10, "Tweed 4x10", NULL, -1}, + {GNX_AMP_CAB_BRITISH_70_4_12, "British 70 4x12", NULL, -1}, + {GNX_AMP_CAB_BRITISH_GREEN4_12, "British Green 4x12", NULL, -1}, + {GNX_AMP_CAB_STRAIGHT_V30_4_12, "Straight V30 4x12", NULL, -1}, + {GNX_AMP_CAB_SLANT_V30_4_12, "Slant V30 4x12", NULL, -1}, + {GNX_AMP_CAB_FANE4_12, "Fane 4x12", NULL, -1}, + {GNX_AMP_CAB_2101_SPKR_COMP, "2101 Spkr Comp", NULL, -1}, + {GNX_AMP_CAB_DIGI_SPANK, "Digitech Spank 4x12", NULL, -1}, + {GNX_AMP_CAB_DIGI_SOLO, "Digitech Solo 4x12", NULL, -1}, + {GNX_AMP_CAB_DIGI_METAL, "Digitech Metal 4x12", NULL, -1}, + {GNX_AMP_CAB_DIGI_BRIGHT, "Digitech Bright 4x12", NULL, -1}, + {GNX_AMP_CAB_DIGI_CHUNK, "Digitech Chunk 4x12", NULL, -1}, + {GNX_AMP_CAB_JUMBO_ACOUSTIC, "Jumbo Acoustic", NULL, -1}, + {GNX_AMP_CAB_DREAD_ACOUSTIC, "Dread Acoustic", NULL, -1}, + {GNX_AMP_CAB_HART_BASS1_15, "Hart Bass 1x15", NULL, -1}, + {GNX_AMP_CAB_BASIC_BASS1_15, "Basic Bass 1x15", NULL, -1}, + {GNX_AMP_CAB_PORTA_BASS1_15, "Porta Bass 1x15", NULL, -1}, + {GNX_AMP_CAB_REFLEX1_18, "Reflex 1x18", NULL, -1}, + {GNX_AMP_CAB_SOLAR_BASS2_15, "Solar Bass 2x15", NULL, -1}, + {GNX_AMP_CAB_DE_BASS4_10, "DE Bass 4x10", NULL, -1}, + {GNX_AMP_CAB_ASH_BASS4_10, "Ash Bass 4x10", NULL, -1}, + {GNX_AMP_CAB_GOLIATH_BASS4_10, "Goliath Bass 4x10", NULL, -1}, + {GNX_AMP_CAB_HART_BASS4_10, "Hart Bass 4x10", NULL, -1}, + {GNX_AMP_CAB_SVT_BASS8_10, "SVT Bass 8x10", NULL, -1}, +}; + +static EffectGroup gnx3k_ch1_cab_tuning_group[] = { + {-1, NULL, gnx3k_ch1_cab_tuning_settings, G_N_ELEMENTS(gnx3k_ch1_cab_tuning_settings)}, +}; + +static EffectGroup gnx3k_ch2_cab_tuning_group[] = { + {-1, NULL, gnx3k_ch2_cab_tuning_settings, G_N_ELEMENTS(gnx3k_ch2_cab_tuning_settings)}, +}; + +static EffectGroup gnx3k_ch1_amp_eq_group[] = { + {-1, NULL, gnx3k_ch1_amp_eq_settings, G_N_ELEMENTS(gnx3k_ch1_amp_eq_settings)}, +}; + +static EffectGroup gnx3k_ch2_amp_eq_group[] = { + {-1, NULL, gnx3k_ch2_amp_eq_settings, G_N_ELEMENTS(gnx3k_ch2_amp_eq_settings)}, +}; + +/* LIBRARY_TONE, LIBRARY_POSITION */ +static EffectGroup tone_lib_group[] = { + {TONE_LIB_OVERDRIVE, "Overdrive", NULL, -1}, + {TONE_LIB_ROCK1, "Rock 1", NULL, -1}, + {TONE_LIB_ROCK2, "Rock 2", NULL, -1}, + {TONE_LIB_BLUES1, "Blues 1", NULL, -1}, + {TONE_LIB_BLUES2, "Blues 2", NULL, -1}, + {TONE_LIB_METAL1, "Metal 1", NULL, -1}, + {TONE_LIB_METAL2, "Metal 2", NULL, -1}, + {TONE_LIB_COUNTRY1, "Country 1", NULL, -1}, + {TONE_LIB_COUNTRY2, "Country 2", NULL, -1}, + {TONE_LIB_WARM_DRIVE, "Warm Drive", NULL, -1}, + {TONE_LIB_CRUNCH, "Crunch", NULL, -1}, + {TONE_LIB_TEXAS_TONE, "Texas Tone", NULL, -1}, + {TONE_LIB_ROCKABILLY, "Rockabilly", NULL, -1}, + {TONE_LIB_SOLO1, "Solo 1", NULL, -1}, + {TONE_LIB_SOLO2, "Solo 2", NULL, -1}, + {TONE_LIB_ROCKWAH, "Rock Wah", NULL, -1}, + {TONE_LIB_CHUNKY, "Chunky", NULL, -1}, + {TONE_LIB_SMOOTH, "Smooth", NULL, -1}, + {TONE_LIB_HEAVY, "Heavy", NULL, -1}, + {TONE_LIB_CLEAN1, "Clean 1", NULL, -1}, + {TONE_LIB_CLEAN2, "Clean 2", NULL, -1}, + {TONE_LIB_BRITISH1, "British 1", NULL, -1}, + {TONE_LIB_BRITISH2, "British 2", NULL, -1}, + {TONE_LIB_AMERICAN1, "American 1", NULL, -1}, + {TONE_LIB_AMERICAN2, "American 2", NULL, -1}, + {TONE_LIB_TUBE_DRIVE, "Tube Drive", NULL, -1}, + {TONE_LIB_DISTORTION, "Distortion", NULL, -1}, + {TONE_LIB_SCOOPED, "Scooped", NULL, -1}, + {TONE_LIB_PUNCHY, "Punchy", NULL, -1}, + {TONE_LIB_BRIGHT_CLEAN, "Bright Clean", NULL, -1}, +}; + +/* LIBRARY_EFFECTS, LIBRARY_POSITION */ +static EffectGroup effects_lib_group[] = { + {EFFECTS_LIB_CHORUS, "Chorus", NULL, -1}, + {EFFECTS_LIB_PHASER, "Phaser", NULL, -1}, + {EFFECTS_LIB_FLANGER, "Flanger", NULL, -1}, + {EFFECTS_LIB_PITCH, "Pitch", NULL, -1}, + {EFFECTS_LIB_TREMOLO, "Tremolo", NULL, -1}, + {EFFECTS_LIB_ROTARY, "Rotary", NULL, -1}, + {EFFECTS_LIB_ENVELOPE, "Envelope Filter", NULL, -1}, + {EFFECTS_LIB_DIGITAL, "Digital Delay", NULL, -1}, + {EFFECTS_LIB_ANALOG, "Analog Delay", NULL, -1}, + {EFFECTS_LIB_PONG, "Pong Delay", NULL, -1}, + {EFFECTS_LIB_MOD, "Mod Delay", NULL, -1}, + {EFFECTS_LIB_TAPE, "Tape Delay", NULL, -1}, + {EFFECTS_LIB_HALL, "Hall Reverb", NULL, -1}, + {EFFECTS_LIB_PLATE, "Plate Reverb", NULL, -1}, + {EFFECTS_LIB_SPRING, "Spring Reverb", NULL, -1}, + {EFFECTS_LIB_CHORUS_DIGITAL, "Chorus + Digital Delay", NULL, -1}, + {EFFECTS_LIB_CHORUS_DELAY_REVERB, "Chorus + Delay + Reverb", NULL, -1}, + {EFFECTS_LIB_FLANGER_ANALOG, "Flanger + Analog Delay", NULL, -1}, + {EFFECTS_LIB_PHASER_TAPE, "Phaser + Tape Delay", NULL, -1}, + {EFFECTS_LIB_PHASER_MOD, "Phaser + Mod Delay", NULL, -1}, + {EFFECTS_LIB_PHASER_ROOM, "Phaser + Room Reverb", NULL, -1}, + {EFFECTS_LIB_DIGITAL_HALL, "Digital Delay + Hall Reverb", NULL, -1}, + {EFFECTS_LIB_ANALOG_SPRING, "Analog Delay + Spring Reverb", NULL, -1}, + {EFFECTS_LIB_CHORUS_HALL, "Chorus + Hall Reverb", NULL, -1}, + {EFFECTS_LIB_PONG_HALL, "Pong Delay + Hall Reverb", NULL, -1}, + {EFFECTS_LIB_TAPE_SPRING, "Tape Delay + Spring Reverb", NULL, -1}, + {EFFECTS_LIB_TREMOLO_TAPE, "Tremolo + Tape Delay", NULL, -1}, + {EFFECTS_LIB_PITCH_DIGITAL, "Pitch + Digital Delay", NULL, -1}, + {EFFECTS_LIB_MOD_PLATE, "Mod Delay + Plate Reverb", NULL, -1}, + {EFFECTS_LIB_ROTARY_TAPE, "Rotary + Tape Delay", NULL, -1}, +}; + +static EffectGroup pickup_group[] = { + {PICKUP_TYPE_HB_SC, "HB>SC", NULL, -1}, + {PICKUP_TYPE_SC_HB, "SC>HB", NULL, -1}, +}; + +static EffectGroup pre_post_group[] = { + {CHORUSFX_PRE, "PRE AMP", NULL, -1}, + {CHORUSFX_POST, "POST AMP", NULL, -1}, +}; + +static EffectGroup delay_mult_group[] = { + {DELAY_3_QUARTR, "3 Quarter", NULL, -1}, + {DELAY_EIGHT, "Eighth", NULL, -1}, + {DELAY_DOTEIGHT, "Dot Eighth", NULL, -1}, + {DELAY_QUARTER, "Quarter", NULL, -1}, + {DELAY_HALF, "Half", NULL, -1}, +}; + +static Effect gnx3k_wah_effect[] = { + {NULL, WAH_ON_OFF, WAH_TYPE, WAH_POSITION, gnx3k_wah_group, G_N_ELEMENTS(gnx3k_wah_group)}, +}; + +static Effect wah_effect[] = { + {NULL, WAH_ON_OFF, WAH_TYPE, WAH_POSITION, wah_group, G_N_ELEMENTS(wah_group)}, +}; + +static Effect gnx3k_whammy_effect[] = { + {NULL, GNX3K_WHAM_ENABLE, GNX3K_WHAM_TYPE, GNX3K_WHAM_POSITION, gnx3k_whammy_group, G_N_ELEMENTS(gnx3k_whammy_group)}, +}; + +static Effect gnx3k_preset_effect[] = { + {NULL, -1, -1, -1, gnx3k_preset_group, G_N_ELEMENTS(gnx3k_preset_group)}, +}; + +static Effect rp250_comp_effect[] = { + {NULL, COMP_ON_OFF, COMP_TYPE, COMP_POSITION, rp250_comp_group, G_N_ELEMENTS(rp250_comp_group)}, +}; + +static Effect rp355_comp_effect[] = { + {NULL, COMP_ON_OFF, COMP_TYPE, COMP_POSITION, rp355_comp_group, G_N_ELEMENTS(rp355_comp_group)}, +}; + +static Effect gnx_comp_effect[] = { + {"Compressor", COMP_ON_OFF, -1, COMP_POSITION, gnx_comp_group, G_N_ELEMENTS(gnx_comp_group)}, +}; + +static Effect rp500_comp_effect[] = { + {NULL, COMP_ON_OFF, COMP_TYPE, COMP_POSITION, rp500_comp_group, G_N_ELEMENTS(rp500_comp_group)}, +}; + +static Effect rp155_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, rp155_dist_group, G_N_ELEMENTS(rp155_dist_group)}, +}; + +static Effect rp250_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, rp250_dist_group, G_N_ELEMENTS(rp250_dist_group)}, +}; + +static Effect rp355_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, rp355_dist_group, G_N_ELEMENTS(rp355_dist_group)}, +}; + +static Effect rp500_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, rp500_dist_group, G_N_ELEMENTS(rp500_dist_group)}, +}; + +static Effect rp1000_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, rp1000_dist_group, G_N_ELEMENTS(rp1000_dist_group)}, +}; + +static Effect gnx4_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, gnx4_dist_group, G_N_ELEMENTS(gnx4_dist_group)}, +}; + +static Effect gnx3k_dist_effect[] = { + {NULL, DIST_ON_OFF, DIST_TYPE, DIST_POSITION, gnx3k_dist_group, G_N_ELEMENTS(gnx3k_dist_group)}, +}; + +static Effect gnx3k_noisegate_effect[] = { + {NULL, NOISEGATE_ON_OFF, NOISEGATE_TYPE, NOISEGATE_POSITION, gnx3k_noisegate_group, G_N_ELEMENTS(gnx3k_noisegate_group)}, +}; + +static Effect noisegate_effect[] = { + {NULL, NOISEGATE_ON_OFF, NOISEGATE_TYPE, NOISEGATE_POSITION, noisegate_group, G_N_ELEMENTS(noisegate_group)}, +}; + +static Effect gnx4_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, gnx4_chorusfx_group, G_N_ELEMENTS(gnx4_chorusfx_group)}, +}; + +static Effect gnx3k_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, gnx3k_chorusfx_group, G_N_ELEMENTS(gnx3k_chorusfx_group)}, +}; + +static Effect rp155_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, rp155_chorusfx_group, G_N_ELEMENTS(rp155_chorusfx_group)}, +}; + +static Effect rp250_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, rp250_chorusfx_group, G_N_ELEMENTS(rp250_chorusfx_group)}, +}; + +static Effect rp255_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, rp255_chorusfx_group, G_N_ELEMENTS(rp255_chorusfx_group)}, +}; + +static Effect rp355_chorusfx_effect[] = { + {"Position",-1, CHORUSFX_PRE_POST,CHORUSFX_POSITION, pre_post_group,G_N_ELEMENTS(pre_post_group)}, + {NULL, CHORUSFX_ON_OFF,CHORUSFX_TYPE, CHORUSFX_POSITION, rp355_chorusfx_group, G_N_ELEMENTS(rp355_chorusfx_group)}, +}; + +static Effect rp500_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, rp500_chorusfx_group, G_N_ELEMENTS(rp500_chorusfx_group)}, +}; + +static Effect rp1000_chorusfx_effect[] = { + {NULL, CHORUSFX_ON_OFF, CHORUSFX_TYPE, CHORUSFX_POSITION, rp1000_chorusfx_group, G_N_ELEMENTS(rp1000_chorusfx_group)}, + {"Position",-1, CHORUSFX_PRE_POST,CHORUSFX_POSITION, pre_post_group,G_N_ELEMENTS(pre_post_group)}, +}; + +static Effect gnx3k_delay_effect[] = { + {NULL, DELAY_ON_OFF, DELAY_TYPE, DELAY_POSITION, gnx3k_delay_group, G_N_ELEMENTS(gnx3k_delay_group)}, +}; + +static Effect rp250_delay_effect[] = { + {NULL, DELAY_ON_OFF, DELAY_TYPE, DELAY_POSITION, rp250_delay_group, G_N_ELEMENTS(rp250_delay_group)}, +}; + +static Effect rp355_delay_effect[] = { + {NULL, DELAY_ON_OFF, DELAY_TYPE, DELAY_POSITION, rp355_delay_group, G_N_ELEMENTS(rp355_delay_group)}, +}; + +static Effect rp500_delay_effect[] = { + {NULL, DELAY_ON_OFF, DELAY_TYPE, DELAY_POSITION, rp500_delay_group, G_N_ELEMENTS(rp500_delay_group)}, +}; + +static Effect rp1000_delay_effect[] = { + {NULL, DELAY_ON_OFF, DELAY_TYPE, DELAY_POSITION, rp1000_delay_group, G_N_ELEMENTS(rp1000_delay_group)}, + {NULL, -1, DELAY_MULTIPLIER, DELAY_POSITION, delay_mult_group, G_N_ELEMENTS(delay_mult_group)}, +}; + +static Effect gnx3k_reverb_effect[] = { + {NULL, REVERB_ON_OFF, REVERB_TYPE, REVERB_POSITION, gnx3k_reverb_group, G_N_ELEMENTS(gnx3k_reverb_group)}, +}; + +static Effect reverb_effect[] = { + {NULL, REVERB_ON_OFF, REVERB_TYPE, REVERB_POSITION, reverb_group, G_N_ELEMENTS(reverb_group)}, +}; + +static Effect rp155_amp_effect[] = { + {NULL, AMP_ON_OFF, AMP_TYPE, AMP_POSITION, rp155_amp_group, G_N_ELEMENTS(rp155_amp_group)}, + {"Cabinet", -1, AMP_CAB_TYPE, AMP_CAB_POSITION, rp155_amp_cab_group, G_N_ELEMENTS(rp155_amp_cab_group)}, +}; + +static Effect rp250_amp_effect[] = { + {NULL, AMP_ON_OFF, AMP_TYPE, AMP_POSITION, rp250_amp_group, G_N_ELEMENTS(rp250_amp_group)}, + {"Cabinet", -1, AMP_CAB_TYPE, AMP_CAB_POSITION, rp250_amp_cab_group, G_N_ELEMENTS(rp250_amp_cab_group)}, +}; + +/* same cabs as rp250, but 3 new amp models */ +static Effect rp255_amp_effect[] = { + {NULL, AMP_ON_OFF, AMP_TYPE, AMP_POSITION, rp255_amp_group, G_N_ELEMENTS(rp255_amp_group)}, + {"Cabinet", -1, AMP_CAB_TYPE, AMP_CAB_POSITION, rp250_amp_cab_group, G_N_ELEMENTS(rp250_amp_cab_group)}, +}; + +static Effect rp355_select_amp_effect[] = { + {"Select Amp", -1, AMP_SELECT, AMP_SELECT_POSITION, rp355_amp_select_group, G_N_ELEMENTS(rp355_amp_select_group)}, +}; + +static Effect rp355_amp_effect_A[] = { + {NULL, AMP_ON_OFF, AMP_TYPE, AMP_POSITION, rp355_amp_group_A, G_N_ELEMENTS(rp355_amp_group_A)}, + {"Cabinet", -1, AMP_CAB_TYPE, AMP_CAB_POSITION, rp355_amp_cab_group, G_N_ELEMENTS(rp355_amp_cab_group)}, +}; + +static Effect rp355_amp_effect_B[] = { + {NULL, AMP_ON_OFF, AMP_TYPE, CH2_AMP_POSITION, rp355_amp_group_B, G_N_ELEMENTS(rp355_amp_group_B)}, + {"Cabinet", -1, AMP_CAB_TYPE, CH2_AMP_CAB_POSITION, rp355_amp_cab_group, G_N_ELEMENTS(rp355_amp_cab_group)}, +}; + +static Effect rp500_amp_effect[] = { + {NULL, AMP_ON_OFF, AMP_TYPE, AMP_POSITION, rp500_amp_group, G_N_ELEMENTS(rp500_amp_group)}, + {"Cabinet", -1, AMP_CAB_TYPE, AMP_CAB_POSITION, rp500_amp_cab_group, G_N_ELEMENTS(rp500_amp_cab_group)}, +}; + +static Effect rp1000_amp_effect[] = { + {"Amp Loop", AMP_LOOP_ON_OFF, -1, AMP_LOOP_POSITION, NULL, -1}, + {"Amp/Cab Bypass", AMP_BYPASS_ON_OFF, -1, AMP_BYPASS_POSITION, NULL, -1}, + {NULL, -1, AMP_TYPE, AMP_POSITION, rp1000_amp_group, G_N_ELEMENTS(rp1000_amp_group)}, + {NULL, -1, AMP_CAB_TYPE, AMP_CAB_POSITION, rp1000_amp_cab_group, G_N_ELEMENTS(rp1000_amp_cab_group)}, +}; + +static Effect gnx3k_channel_1_effect[] = { + {"EQ Enable", AMP_EQ_ON_OFF, AMP_TYPE, AMP_POSITION, gnx3k_amp_group, G_N_ELEMENTS(gnx3k_amp_group)}, + {NULL, -1, AMP_CAB_TYPE, AMP_CAB_POSITION, gnx3k_amp_cab_group, G_N_ELEMENTS(gnx3k_amp_cab_group)}, + {NULL, -1, -1, -1, gnx3k_ch1_cab_tuning_group, G_N_ELEMENTS(gnx3k_ch1_cab_tuning_group)}, + {NULL, -1, -1, -1, gnx3k_ch1_amp_eq_group, G_N_ELEMENTS(gnx3k_ch1_amp_eq_group)}, +}; + +static Effect gnx3k_channel_2_effect[] = { + {"EQ Enable", AMP_EQ_ON_OFF, AMP_TYPE, CH2_AMP_POSITION, gnx3k_amp_group, G_N_ELEMENTS(gnx3k_amp_group)}, + {NULL, -1, AMP_CAB_TYPE, CH2_AMP_CAB_POSITION, gnx3k_amp_cab_group, G_N_ELEMENTS(gnx3k_amp_cab_group)}, + {NULL, -1, -1, -1, gnx3k_ch2_cab_tuning_group, G_N_ELEMENTS(gnx3k_ch2_cab_tuning_group)}, + {NULL, -1, -1, -1, gnx3k_ch2_amp_eq_group, G_N_ELEMENTS(gnx3k_ch2_amp_eq_group)}, +}; + +static Effect rp250_eq_effect[] = { + {NULL, EQ_ON_OFF, EQ_TYPE, EQ_POSITION, rp250_eq_group, G_N_ELEMENTS(rp250_eq_group)}, +}; + +static Effect rp355_eq_effect_A[] = { + {NULL, EQ_ON_OFF, EQ_TYPE, EQ_POSITION, rp355_eq_group_A, G_N_ELEMENTS(rp355_eq_group_A)}, +}; + +static Effect rp355_eq_effect_B[] = { + {NULL, EQ_ON_OFF, EQ_TYPE, EQ_POSITION_B, rp355_eq_group_B, G_N_ELEMENTS(rp355_eq_group_B)}, +}; + +static Effect rp500_eq_effect[] = { + {"Enable Equalizer", EQ_ON_OFF, -1, EQ_POSITION, rp500_eq_group, G_N_ELEMENTS(rp500_eq_group)}, +}; + +static Effect pickup_misc_effect[] = { + {NULL, PICKUP_ON_OFF, PICKUP_TYPE, PICKUP_POSITION, pickup_group, G_N_ELEMENTS(pickup_group)}, + {NULL, -1, -1, -1, misc_group, G_N_ELEMENTS(misc_group)}, +}; + +static Effect pickup_effect[] = { + {NULL, PICKUP_ON_OFF, PICKUP_TYPE, PICKUP_POSITION, pickup_group, G_N_ELEMENTS(pickup_group)}, +}; + +static Effect gnx3k_amp_channel_effect[] = { + {NULL, -1, -1, -1, gnx3k_amp_channel_group, G_N_ELEMENTS(gnx3k_amp_channel_group)}, +}; + +/* in signal chain order */ +static EffectList rp155_effects[] = { + {"Pickup", pickup_misc_effect, G_N_ELEMENTS(pickup_misc_effect)}, + {"Wah", wah_effect, G_N_ELEMENTS(wah_effect)}, + {"Compressor", rp250_comp_effect, G_N_ELEMENTS(rp250_comp_effect)}, + {"Distortion", rp155_dist_effect, G_N_ELEMENTS(rp155_dist_effect)}, + {"Amplifier", rp155_amp_effect, G_N_ELEMENTS(rp155_amp_effect)}, + {"Equalizer", rp250_eq_effect, G_N_ELEMENTS(rp250_eq_effect)}, + {"Noisegate", noisegate_effect, G_N_ELEMENTS(noisegate_effect)}, + {"Chorus/FX", rp155_chorusfx_effect, G_N_ELEMENTS(rp155_chorusfx_effect)}, + {"Delay", rp250_delay_effect, G_N_ELEMENTS(rp250_delay_effect)}, + {"Reverb", reverb_effect, G_N_ELEMENTS(reverb_effect)}, +}; + +static EffectList rp250_effects[] = { + {"Wah", wah_effect, G_N_ELEMENTS(wah_effect)}, + {"Amplifier", rp250_amp_effect, G_N_ELEMENTS(rp250_amp_effect)}, + {"Equalizer", rp250_eq_effect, G_N_ELEMENTS(rp250_eq_effect)}, + {"Compressor", rp250_comp_effect, G_N_ELEMENTS(rp250_comp_effect)}, + {"Distortion", rp250_dist_effect, G_N_ELEMENTS(rp250_dist_effect)}, + {"Noisegate", noisegate_effect, G_N_ELEMENTS(noisegate_effect)}, + {"Chorus/FX", rp250_chorusfx_effect, G_N_ELEMENTS(rp250_chorusfx_effect)}, + {"Delay", rp250_delay_effect, G_N_ELEMENTS(rp250_delay_effect)}, + {"Reverb", reverb_effect, G_N_ELEMENTS(reverb_effect)}, + {"Pickup/Misc", pickup_misc_effect, G_N_ELEMENTS(pickup_misc_effect)}, +}; + +/* Almost like rp250, except for Amplifier and Chorus/FX */ +static EffectList rp255_effects[] = { + {"Wah", wah_effect, G_N_ELEMENTS(wah_effect)}, + {"Amplifier", rp255_amp_effect, G_N_ELEMENTS(rp255_amp_effect)}, + {"Equalizer", rp250_eq_effect, G_N_ELEMENTS(rp250_eq_effect)}, + {"Compressor", rp250_comp_effect, G_N_ELEMENTS(rp250_comp_effect)}, + {"Distortion", rp250_dist_effect, G_N_ELEMENTS(rp250_dist_effect)}, + {"Noisegate", noisegate_effect, G_N_ELEMENTS(noisegate_effect)}, + {"Chorus/FX", rp255_chorusfx_effect, G_N_ELEMENTS(rp255_chorusfx_effect)}, + {"Delay", rp250_delay_effect, G_N_ELEMENTS(rp250_delay_effect)}, + {"Reverb", reverb_effect, G_N_ELEMENTS(reverb_effect)}, + {"Pickup/Misc", pickup_misc_effect, G_N_ELEMENTS(pickup_misc_effect)}, +}; + +static EffectList rp355_effects[] = { + {"Pickup/Misc", pickup_misc_effect, G_N_ELEMENTS(pickup_misc_effect)}, + {"Wah", wah_effect, G_N_ELEMENTS(wah_effect)}, + {"Compressor", rp355_comp_effect, G_N_ELEMENTS(rp355_comp_effect)}, + {"Distortion", rp355_dist_effect, G_N_ELEMENTS(rp355_dist_effect)}, + {"Select Amp", rp355_select_amp_effect, G_N_ELEMENTS(rp355_select_amp_effect)}, + {"Amplifier A", rp355_amp_effect_A, G_N_ELEMENTS(rp355_amp_effect_A)}, + {"Equalizer A", rp355_eq_effect_A, G_N_ELEMENTS(rp355_eq_effect_A)}, + {"Amplifier B", rp355_amp_effect_B, G_N_ELEMENTS(rp355_amp_effect_B)}, + {"Equalizer B", rp355_eq_effect_B, G_N_ELEMENTS(rp355_eq_effect_B)}, + {"Noisegate", noisegate_effect, G_N_ELEMENTS(noisegate_effect)}, + {"Chorus/FX", rp355_chorusfx_effect, G_N_ELEMENTS(rp355_chorusfx_effect)}, + {"Delay", rp355_delay_effect, G_N_ELEMENTS(rp355_delay_effect)}, + {"Reverb", reverb_effect, G_N_ELEMENTS(reverb_effect)}, +}; + +static EffectList rp500_effects[] = { + {"Wah", wah_effect, G_N_ELEMENTS(wah_effect)}, + {"Amplifier", rp500_amp_effect, G_N_ELEMENTS(rp500_amp_effect)}, + {"Equalizer", rp500_eq_effect, G_N_ELEMENTS(rp500_eq_effect)}, + {"Compressor", rp500_comp_effect, G_N_ELEMENTS(rp500_comp_effect)}, + {"Distortion", rp500_dist_effect, G_N_ELEMENTS(rp500_dist_effect)}, + {"Noisegate", noisegate_effect, G_N_ELEMENTS(noisegate_effect)}, + {"Chorus/FX", rp500_chorusfx_effect, G_N_ELEMENTS(rp500_chorusfx_effect)}, + {"Delay", rp500_delay_effect, G_N_ELEMENTS(rp500_delay_effect)}, + {"Reverb", reverb_effect, G_N_ELEMENTS(reverb_effect)}, +}; + +static EffectList rp1000_effects[] = { + {"Wah", wah_effect, G_N_ELEMENTS(wah_effect)}, + {"Amplifier", rp1000_amp_effect, G_N_ELEMENTS(rp1000_amp_effect)}, + {"Equalizer", rp500_eq_effect, G_N_ELEMENTS(rp500_eq_effect)}, + {"Compressor", rp500_comp_effect, G_N_ELEMENTS(rp500_comp_effect)}, + {"Distortion", rp1000_dist_effect, G_N_ELEMENTS(rp1000_dist_effect)}, + {"Noisegate", noisegate_effect, G_N_ELEMENTS(noisegate_effect)}, + {"Chorus/FX", rp1000_chorusfx_effect, G_N_ELEMENTS(rp1000_chorusfx_effect)}, + {"Delay", rp1000_delay_effect, G_N_ELEMENTS(rp1000_delay_effect)}, + {"Reverb", reverb_effect, G_N_ELEMENTS(reverb_effect)}, +}; + +static EffectList gnx4_effects[] = { + {"Pickup", pickup_effect, G_N_ELEMENTS(pickup_effect)}, + {"Wah", gnx3k_wah_effect, G_N_ELEMENTS(gnx3k_wah_effect)}, + {"Compressor", gnx_comp_effect, G_N_ELEMENTS(gnx_comp_effect)}, + {"Whammy/IPS", gnx3k_whammy_effect, G_N_ELEMENTS(gnx3k_whammy_effect)}, + {"Stompbox", gnx4_dist_effect, G_N_ELEMENTS(gnx4_dist_effect)}, + {"Noisegate", gnx3k_noisegate_effect, G_N_ELEMENTS(gnx3k_noisegate_effect)}, + {"Chorus/Mod", gnx4_chorusfx_effect, G_N_ELEMENTS(gnx4_chorusfx_effect)}, + {"Delay", gnx3k_delay_effect, G_N_ELEMENTS(gnx3k_delay_effect)}, + {"Reverb", gnx3k_reverb_effect, G_N_ELEMENTS(gnx3k_reverb_effect)}, +}; + +static EffectList gnx3000_effects[] = { + {"Pickup", pickup_effect, G_N_ELEMENTS(pickup_effect)}, + {"Wah", gnx3k_wah_effect, G_N_ELEMENTS(gnx3k_wah_effect)}, + {"Whammy/IPS", gnx3k_whammy_effect, G_N_ELEMENTS(gnx3k_whammy_effect)}, + {"Preset Level", gnx3k_preset_effect, G_N_ELEMENTS(gnx3k_preset_effect)}, + {"Compressor", gnx_comp_effect, G_N_ELEMENTS(gnx_comp_effect)}, + {"Stompbox", gnx3k_dist_effect, G_N_ELEMENTS(gnx3k_dist_effect)}, + {"Noisegate", gnx3k_noisegate_effect, G_N_ELEMENTS(gnx3k_noisegate_effect)}, + {"Chorus/Mod", gnx3k_chorusfx_effect, G_N_ELEMENTS(gnx3k_chorusfx_effect)}, + {"Delay", gnx3k_delay_effect, G_N_ELEMENTS(gnx3k_delay_effect)}, + {"Reverb", gnx3k_reverb_effect, G_N_ELEMENTS(gnx3k_reverb_effect)}, +}; + +static EffectList gnx3000_genetx[] = { + {"Channel 1", gnx3k_channel_1_effect, G_N_ELEMENTS(gnx3k_channel_1_effect)}, + {"Channel 2", gnx3k_channel_2_effect, G_N_ELEMENTS(gnx3k_channel_2_effect)}, + {"Amp Channel", gnx3k_amp_channel_effect, G_N_ELEMENTS(gnx3k_amp_channel_effect)}, +}; + +static Banks rp_banks[] = { + {"User Presets", PRESETS_USER}, + {"System Presets", PRESETS_SYSTEM}, +}; + +static Banks gnx4_banks[] = { + {"Factory", PRESETS_SYSTEM}, + {"User Presets", PRESETS_USER}, + {"Flash Card", PRESETS_MEDIA_CARD}, +}; + +static Banks gnx3k_banks[] = { + {"User Presets", PRESETS_USER}, + {"Factory 1", PRESETS_SYSTEM}, + {"Factory 2", PRESETS_FACTORY2}, +}; + +static EffectPage rp155_pages[] = { + {"Effects", rp155_effects, G_N_ELEMENTS(rp155_effects), 2}, +}; + +static EffectPage rp250_pages[] = { + {"Effects", rp250_effects, G_N_ELEMENTS(rp250_effects), 2}, +}; + +static EffectPage rp255_pages[] = { + {"Effects", rp255_effects, G_N_ELEMENTS(rp255_effects), 2}, +}; + +static EffectPage rp355_pages[] = { + {"Effects", rp355_effects, G_N_ELEMENTS(rp355_effects), 2}, +}; + +static EffectPage rp500_pages[] = { + {"Effects", rp500_effects, G_N_ELEMENTS(rp500_effects), 2}, +}; + +static EffectPage rp1000_pages[] = { + {"Effects", rp1000_effects, G_N_ELEMENTS(rp1000_effects), 2}, +}; + +static EffectPage gnx4_pages[] = { + {"Effects", gnx4_effects, G_N_ELEMENTS(gnx4_effects), 2}, +}; + +static EffectPage gnx3000_pages[] = { + {"Effects", gnx3000_effects, G_N_ELEMENTS(gnx3000_effects), 2}, + {"Amp/GeNetX", gnx3000_genetx, G_N_ELEMENTS(gnx3000_genetx), 1}, +}; + +static Device rp155 = { + .name = "DigiTech RP155", + .family_id = 0x5E, + .product_id = 0x07, + .pages = rp155_pages, + .n_pages = G_N_ELEMENTS(rp155_pages), + .banks = rp_banks, + .n_banks = G_N_ELEMENTS(rp_banks), +}; + +static Device rp250 = { + .name = "DigiTech RP250", + .family_id = 0x5E, + .product_id = 0x02, + .pages = rp250_pages, + .n_pages = G_N_ELEMENTS(rp250_pages), + .banks = rp_banks, + .n_banks = G_N_ELEMENTS(rp_banks), +}; + +static Device rp255 = { + .name = "DigiTech RP255", + .family_id = 0x5E, + .product_id = 0x08, + .pages = rp255_pages, + .n_pages = G_N_ELEMENTS(rp255_pages), + .banks = rp_banks, + .n_banks = G_N_ELEMENTS(rp_banks), +}; + +static Device rp355 = { + .name = "DigiTech RP355", + .family_id = 0x5E, + .product_id = 0x09, + .pages = rp355_pages, + .n_pages = G_N_ELEMENTS(rp355_pages), + .banks = rp_banks, + .n_banks = G_N_ELEMENTS(rp_banks), +}; + +static Device rp500 = { + .name = "DigiTech RP500", + .family_id = 0x5E, + .product_id = 0x05, + .pages = rp500_pages, + .n_pages = G_N_ELEMENTS(rp500_pages), + .banks = rp_banks, + .n_banks = G_N_ELEMENTS(rp_banks), +}; + +static Device rp1000 = { + .name = "DigiTech RP1000", + .family_id = 0x05E, + .product_id = 0x06, + .pages = rp1000_pages, + .n_pages = G_N_ELEMENTS(rp1000_pages), + .banks = rp_banks, + .n_banks = G_N_ELEMENTS(rp_banks), +}; + +static Device gnx4 = { + .name = "DigiTech GNX4", + .family_id = 0x5C, + .product_id = 0x03, + .pages = gnx4_pages, + .n_pages = G_N_ELEMENTS(gnx4_pages), + .banks = gnx4_banks, + .n_banks = G_N_ELEMENTS(gnx4_banks), +}; + +static Device gnx3000 = { + .name = "DigiTech GNX3000", + .family_id = 0x5C, + .product_id = 0x04, + .pages = gnx3000_pages, + .n_pages = G_N_ELEMENTS(gnx3000_pages), + .banks = gnx3k_banks, + .n_banks = G_N_ELEMENTS(gnx3k_banks), +}; + +Device* supported_devices[] = { + &rp155, + &rp250, + &rp255, + &rp355, + &rp500, + &rp1000, + &gnx4, + &gnx3000, +}; + +int n_supported_devices = G_N_ELEMENTS(supported_devices); + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +typedef struct { + gchar *label; + guint id; + guint position; + EffectValues *values; +} Modifier; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +static Modifier modifiers[] = { + {"None", 0, 0, NULL}, + {"Pickup Enable", PICKUP_ON_OFF, PICKUP_POSITION, &values_on_off}, + {"Pickup Type", PICKUP_TYPE, PICKUP_POSITION, &values_pickup_type}, + {"Compressor Enable", COMP_ON_OFF, COMP_POSITION, &values_on_off}, + {"Compressor Sustain", COMP_SUSTAIN, COMP_POSITION, &values_0_to_99}, + {"Compressor Tone", COMP_TONE, COMP_POSITION, &values_0_to_99}, + {"Compressor Level", COMP_LEVEL, COMP_POSITION, &values_0_to_99}, + {"Compressor Attack", COMP_ATTACK, COMP_POSITION, &values_0_to_99}, + {"Dist Enable", DIST_ON_OFF, DIST_POSITION, &values_on_off}, + {"Dist Drive", DIST_SCREAMER_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Dist Tone", DIST_SCREAMER_TONE, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_SCREAMER_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Overdrive", DIST_808_OVERDRIVE, DIST_POSITION, &values_0_to_99}, + {"Dist Tone", DIST_808_TONE, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_808_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Drive", DIST_GUYOD_DRIVE, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_GUYOD_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Gain", DIST_DOD250_GAIN, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_DOD250_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Distortion", DIST_RODENT_DIST, DIST_POSITION, &values_0_to_99}, + {"Dist Filter", DIST_RODENT_FILTER, DIST_POSITION, &values_0_to_99}, + {"Dist Volume", DIST_RODENT_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Distortion", DIST_MX_DIST, DIST_POSITION, &values_0_to_99}, + {"Dist Output", DIST_MX_OUTPUT, DIST_POSITION, &values_0_to_99}, + {"Dist Distortion", DIST_DS_GAIN, DIST_POSITION, &values_0_to_99}, + {"Dist Tone", DIST_DS_TONE, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_DS_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Gain", DIST_GRUNGE_GRUNGE, DIST_POSITION, &values_0_to_99}, + {"Dist Face", DIST_GRUNGE_FACE, DIST_POSITION, &values_0_to_99}, + {"Dist Loud", DIST_GRUNGE_LOUD, DIST_POSITION, &values_0_to_99}, + {"Dist Butt", DIST_GRUNGE_BUTT, DIST_POSITION, &values_0_to_99}, + {"Dist Gain", DIST_ZONE_GAIN, DIST_POSITION, &values_0_to_99}, + {"Dist Mid Level", DIST_ZONE_MID_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_ZONE_LEVEL, DIST_POSITION, &values_0_to_99}, + {"Dist Low", DIST_ZONE_LOW, DIST_POSITION, &values_0_to_99}, + {"Dist Mid Freq", DIST_ZONE_MID_FREQ, DIST_POSITION, &values_0_to_99}, + {"Dist High", DIST_ZONE_HIGH, DIST_POSITION, &values_0_to_99}, + {"Dist Low", DIST_DEATH_LOW, DIST_POSITION, &values_0_to_99}, + {"Dist Mid", DIST_DEATH_MID, DIST_POSITION, &values_0_to_99}, + {"Dist Level", DIST_DEATH_LVL, DIST_POSITION, &values_0_to_99}, + {"Dist High", DIST_DEATH_HIGH, DIST_POSITION, &values_0_to_99}, + {"Dist Gunk", DIST_GONK_GONK, DIST_POSITION, &values_0_to_99}, + {"Dist Smear", DIST_GONK_SMEAR, DIST_POSITION, &values_0_to_99}, + {"Dist Suck", DIST_GONK_SUCK, DIST_POSITION, &values_0_to_99}, + {"Dist Heave", DIST_GONK_HEAVE, DIST_POSITION, &values_0_to_99}, + {"Dist Fuzz", DIST_FUZZY_FUZZ, DIST_POSITION, &values_0_to_99}, + {"Dist Volume", DIST_FUZZY_VOLUME, DIST_POSITION, &values_0_to_99}, + {"Dist Sustain", DIST_MP_SUSTAIN, DIST_POSITION, &values_0_to_99}, + {"Dist Tone", DIST_MP_TONE, DIST_POSITION, &values_0_to_99}, + {"Dist Volume", DIST_MP_VOLUME, DIST_POSITION, &values_0_to_99}, + {"Amp Channel Enable", AMP_ON_OFF, AMP_POSITION, &values_on_off}, + {"Amp Gain", AMP_GAIN, AMP_POSITION, &values_0_to_99}, + {"Amp Level", AMP_LEVEL, AMP_POSITION, &values_0_to_99}, + {"EQ Enable", EQ_ON_OFF, EQ_POSITION, &values_on_off}, + {"EQ Bass", EQ_BASS, EQ_POSITION, &values_eq_db}, + {"EQ Mid", EQ_MID, EQ_POSITION, &values_eq_db}, + {"EQ Treb", EQ_TREBLE, EQ_POSITION, &values_eq_db}, + {"Gate Enable", NOISEGATE_ON_OFF, NOISEGATE_POSITION, &values_on_off}, + {"Gate Pluck Sens", NOISEGATE_SWELL_SENS, NOISEGATE_POSITION, &values_0_to_99}, + {"Gate Threshold", NOISEGATE_GATE_TRESHOLD, NOISEGATE_POSITION, &values_0_to_99}, + {"Gate Attack", NOISEGATE_ATTACK, NOISEGATE_POSITION, &values_0_to_99}, + {"Gate Release", NOISEGATE_RELEASE, NOISEGATE_POSITION, &values_0_to_99}, + {"Gate Attenuation", NOISEGATE_ATTN, NOISEGATE_POSITION, &values_0_to_99}, + {"Chorus/FX Enable", CHORUSFX_ON_OFF, CHORUSFX_POSITION, &values_on_off}, + {"Phaser Speed", PHASER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Phaser Depth", PHASER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Phaser Regen", PHASER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Phaser Waveform", PHASER_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Phaser Level", PHASER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Chorus Speed", CHORUS_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Chorus Depth", CHORUS_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Chorus Level", CHORUS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Chorus Waveform", CHORUS_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Flanger Speed", FLANGER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Flanger Depth", FLANGER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Flanger Regen", FLANGER_REGEN, CHORUSFX_POSITION, &values_0_to_99}, + {"Flanger Waveform", FLANGER_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Flanger Level", FLANGER_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Flanger Width", MXR_FLANGER_WIDTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Flanger Manual", MXR_FLANGER_MANUAL, CHORUSFX_POSITION, &values_0_to_99}, + {"Vibrato Speed", VIBRATO_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Vibrato Depth", VIBRATO_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Rotary Speed", ROTARY_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Rotary Intensity", ROTARY_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Rotary Doppler", ROTARY_DOPPLER, CHORUSFX_POSITION, &values_0_to_99}, + {"Rotary Crossover", ROTARY_CROSSOVER, CHORUSFX_POSITION, &values_0_to_99}, + {"VibroPan Speed", VIBROPAN_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"VibroPan Depth", VIBROPAN_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"VibroPan VibratoPan", VIBROPAN_VIBRA, CHORUSFX_POSITION, &values_0_to_99}, + {"VibroPan Waveform", VIBROPAN_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Tremolo Speed", TREMOLO_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Tremolo Depth", TREMOLO_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Tremolo Waveform", TREMOLO_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Panner Speed", PANNER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Panner Depth", PANNER_DEPTH, CHORUSFX_POSITION, &values_0_to_99}, + {"Panner Waveform", PANNER_WAVE, CHORUSFX_POSITION, &values_waveform}, + {"Envelope Sens.", ENVELOPE_SENSITIVITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Envelope Range", ENVELOPE_RANGE, CHORUSFX_POSITION, &values_0_to_99}, + {"AutoYa Speed", AUTOYA_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"AutoYa Intensity", AUTOYA_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"AutoYa Range", AUTOYA_RANGE, CHORUSFX_POSITION, &values_0_to_49}, + {"YaYa Pedal", YAYA_PEDAL, CHORUSFX_POSITION, &values_0_to_99}, + {"YaYa Intensity", YAYA_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"YaYa Range", YAYA_RANGE, CHORUSFX_POSITION, &values_0_to_49}, + {"Step Filter Speed", STEP_FILTER_SPEED, CHORUSFX_POSITION, &values_0_to_99}, + {"Step Filter Intensity", STEP_FILTER_INTENSITY, CHORUSFX_POSITION, &values_0_to_99}, + {"Whammy Amount", WHAMMY_AMOUNT, CHORUSFX_POSITION, &values_whammy_amount}, + {"Whammy Pedal", WHAMMY_PEDAL, CHORUSFX_POSITION, &values_0_to_99}, + {"Whammy Mix", WHAMMY_MIX, CHORUSFX_POSITION, &values_0_to_99}, + {"Pitch Shift Amount", PITCH_AMOUNT, CHORUSFX_POSITION, &values_m24_to_24}, + {"Pitch Shift Mix", PITCH_MIX, CHORUSFX_POSITION, &values_0_to_99}, + {"Detune Amount", DETUNE_AMOUNT, CHORUSFX_POSITION, &values_m24_to_24}, + {"Detune Level", DETUNE_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"IPS Amount", IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, &values_ips_shift}, + {"IPS Key", IPS_KEY, CHORUSFX_POSITION, &values_ips_key}, + {"IPS Scale", IPS_SCALE, CHORUSFX_POSITION, &values_ips_scale}, + {"IPS Level", IPS_LEVEL, CHORUSFX_POSITION, &values_0_to_99}, + {"Delay Enable", DELAY_ON_OFF, DELAY_POSITION, &values_on_off}, + {"Delay Time", DELAY_TIME, DELAY_POSITION, &values_delay_time}, + {"Delay Repeats", DELAY_REPEATS, DELAY_POSITION, &values_delay_repeats}, + {"Delay Level", DELAY_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Delay Duck Thresh", DELAY_DUCK_THRESH, DELAY_POSITION, &values_0_to_99}, + {"Delay Duck Level", DELAY_DUCK_LEVEL, DELAY_POSITION, &values_0_to_99}, + {"Delay Mod Depth", DELAY_DEPTH, DELAY_POSITION, &values_0_to_99}, + {"Delay Tape Wow", DELAY_TAPE_WOW, DELAY_POSITION, &values_0_to_99}, + {"Delay Tape Flut", DELAY_TAPE_FLUTTER, DELAY_POSITION, &values_0_to_99}, + {"Reverb Enable", REVERB_ON_OFF, REVERB_POSITION, &values_on_off}, + {"Reverb Decay", REVERB_DECAY, REVERB_POSITION, &values_0_to_99}, + {"Reverb Liveliness", REVERB_LIVELINESS, REVERB_POSITION, &values_0_to_99}, + {"Reverb Level", REVERB_LEVEL, REVERB_POSITION, &values_0_to_99}, + {"Reverb Predelay", REVERB_PREDELAY, REVERB_POSITION, &values_0_to_15}, + {"Volume Pre FX", 2626, 13, &values_0_to_99}, + {"Volume Post FX", 2626, 17, &values_0_to_99}, +}; + +int n_modifiers = G_N_ELEMENTS(modifiers); + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * \param id modifier ID + * \param position modifier position + * + * Gets modifier info. + * + * \return Modifier which must not be freed, or NULL if no matching Modifier has been found. +*/ +static Modifier *get_modifier(guint id, guint position) +{ + gint x; + + for (x=0; x<n_modifiers; x++) + if ((modifiers[x].id == id) && (modifiers[x].position == position)) + return &(modifiers[x]); + + return NULL; +} + +/** + * \param values possible setting values + * + * Creates EffectSettings containing expression pedal min and max settings. + * + * \return EffectSettings which must be freed using effect_settings_free. + **/ +static EffectSettings *get_modifier_settings(EffectValues *values) +{ + if (values == NULL) + return NULL; + + /** \todo reuse exsisting settings if values is the same */ + EffectSettings *settings = g_slice_alloc0(2 * sizeof(EffectSettings)); + settings[0].id = EXP_MIN; + settings[1].id = EXP_MAX; + + settings[0].label = "Min"; + settings[1].label = "Max"; + + settings[0].position = settings[1].position = EXP_POSITION; + + settings[0].values = settings[1].values = values; + + return settings; +} + +/** + * \param settings settings to be freed + * + * Frees all memory used by EffectSettings. + **/ +static void effect_settings_free(EffectSettings *settings) +{ + g_slice_free1(2 * sizeof(EffectSettings), settings); +} + +/** + * Retrieves modifier linkable gruop from device. + * + * \return ModifierGroup which must be freed using modifier_group_free. + **/ +ModifierGroup *modifier_linkable_list() +{ + guint group_id; + guint count; + guint i; + + send_message(REQUEST_MODIFIER_LINKABLE_LIST, "\x00\x01", 2); + + GString *data = get_message_by_id(RECEIVE_MODIFIER_LINKABLE_LIST); + + unsigned char *str = (unsigned char*)data->str; + + group_id = (str[8] << 8) | str[9]; + count = (str[10] << 8) | str[11]; + + ModifierGroup *modifier_group = g_slice_new(ModifierGroup); + + modifier_group->type = EXP_TYPE; + modifier_group->position = EXP_POSITION; + + g_message("Group %d count %d", group_id, count); + EffectGroup *group = g_slice_alloc(count * sizeof(EffectGroup)); + + for (i=0; i<count; i++) { + guint id = (str[12 + (i*3)] << 8) | str[13 + (i*3)]; + guint position = str[14 + (i*3)]; + + group[i].type = (position << 16) | id; + + Modifier *modifier = get_modifier(id, position); + if (modifier) { + group[i].label = modifier->label; + group[i].settings = get_modifier_settings(modifier->values); + group[i].settings_amt = 2; + } else { + group[i].label = NULL; + group[i].settings = NULL; + } + + if (group[i].settings == NULL) + group[i].settings_amt = 0; + + g_message("ID: %d Position: %d Label: %s", id, position, modifier ? modifier->label : NULL); + } + + modifier_group->group = group; + modifier_group->group_amt = count; + + return modifier_group; +} + +/** + * \param modifier_group group to be freed + * + * Frees all memory used by ModifierGroup. + **/ +void modifier_group_free(ModifierGroup *modifier_group) +{ + g_return_if_fail(modifier_group != NULL); + + int x; + for (x=0; x<modifier_group->group_amt; x++) { + if (modifier_group->group[x].settings) + effect_settings_free(modifier_group->group[x].settings); + } + g_slice_free1(modifier_group->group_amt * sizeof(EffectGroup), + modifier_group->group); + g_slice_free(ModifierGroup, modifier_group); +} + +/** + * \param values EffectValues to examine + * \param min return location for minimum value + * \param max return location for maximum value + * \param custom return location for custom flag + * + * Retrieves information about provided EffectValues, custom is set to TRUE if values type isn't VALUE_TYPE_PLAIN. + **/ +void get_values_info(EffectValues *values, + gdouble *min, gdouble *max, gboolean *custom) +{ + g_return_if_fail(values != NULL); + + *min = values->min; + *custom = (values->type != VALUE_TYPE_PLAIN); + + while ((values->type & VALUE_TYPE_EXTRA) && (values->extra != NULL)) + values = values->extra; + + *max = values->max; +} + +/** + * \param device_id Device ID + * \param family_id Family ID + * \param product_id Product ID + * \param device Variable to hold device information + * + * Gets appropiate effect list basing on device, family and product IDs. + * + * \return TRUE if list and n_list were set, FALSE otherwise. + **/ +gboolean get_device_info(unsigned char device_id, unsigned char family_id, + unsigned char product_id, + Device **device) +{ + int x; + for (x = 0; x < G_N_ELEMENTS(supported_devices); x++) { + if (supported_devices[x]->product_id == product_id && supported_devices[x]->family_id == family_id) { + *device = supported_devices[x]; + return TRUE; + } + } + return FALSE; +} + diff --git a/effects.h b/effects.h new file mode 100644 index 0000000..40e95f7 --- /dev/null +++ b/effects.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#ifndef GDIGI_EFFECTS_H +#define GDIGI_EFFECTS_H + +#include <glib.h> + +enum { + VALUE_TYPE_PLAIN = 0, /**< value displayed directly */ + VALUE_TYPE_SUFFIX = 1 << 0, /**< use suffix for displaying */ + VALUE_TYPE_OFFSET = 1 << 1, /**< use value offset */ + VALUE_TYPE_STEP = 1 << 2, /**< use value step different than 1 */ + VALUE_TYPE_LABEL = 1 << 3, /**< use value labels (overrides any other option) */ + VALUE_TYPE_EXTRA = 1 << 4, /**< use extra values */ + VALUE_TYPE_DECIMAL= 1 << 5, /**< display decimal places */ +} ValueType; + +typedef struct _EffectValues { + gdouble min; /**< Minumum value */ + gdouble max; /**< Maximum value */ + gint type; /**< value type bitmask (ValueType) */ + + GStrv labels; /**< value labels */ + gint offset; /**< value offset */ + gdouble step; /**< value step */ + gchar *suffix; /**< value suffix */ + + struct _EffectValues *extra; + /**< additional value range, + use it when there're different range types */ + gint decimal; /**< amount of decimal places to display */ +} EffectValues; + +typedef struct { + gchar *label; /**< Parameter name */ + guint id; /**< ID (to set parameter) */ + guint position; /**< position */ + EffectValues *values; /**< valid parameter values */ +} EffectSettings; + +typedef struct { + guint type; /**< value (type) */ + gchar *label; /**< Effect name */ + EffectSettings *settings; /**< possible parameters */ + gint settings_amt; /**< possible parameters length */ +} EffectGroup; + +typedef struct { + gchar *label; /**< Group label */ + guint id; /**< ID to set effect on/off, or if it isn't on/off group then -1 */ + guint type; /**< ID to set effect type */ + guint position; /**< position */ + EffectGroup *group; /**< possible effect types */ + gint group_amt; /**< possible effect types length */ +} Effect; + +typedef struct { + gchar *label; /**< base effect name */ + Effect *effect; /**< list of supported effects */ + gint amt; /**< list of supported effects length */ +} EffectList; + +typedef struct { + guint type; /**< ID to set effect type */ + guint position; + EffectGroup *group; + gint group_amt; +} ModifierGroup; + +typedef struct { + gchar *name; + EffectList *effects; + gint n_effects; + gint n_rows; +} EffectPage; + +typedef struct { + gchar *name; + PresetBank bank; +} Banks; + +typedef struct { + gchar *name; + unsigned char family_id; + unsigned char product_id; + EffectPage *pages; + gint n_pages; + Banks *banks; + gint n_banks; +} Device; + +ModifierGroup *modifier_linkable_list(); +void modifier_group_free(ModifierGroup *modifier_group); +void get_values_info(EffectValues *values, + gdouble *min, gdouble *max, gboolean *custom); +gboolean get_device_info(unsigned char device_id, unsigned char family_id, + unsigned char product_id, + Device **device); + +#endif /* GDIGI_EFFECTS_H */ @@ -0,0 +1,74 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH GDIGI 1 "October 07, 2010" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp <n> insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +gdigi \- utility to control DigiTech effect pedals +.SH SYNOPSIS +.B gdigi +.RI [OPTION...] +.SH DESCRIPTION +gdigi is a tool aimed to provide X-Edit functionality to Linux users +.PP +Supported devices: +.IP \(bu +RP250 +.IP \(bu +RP255 +.IP \(bu +RP355 +.IP \(bu +RP500 +.IP \(bu +RP1000 +.IP \(bu +GNX3000 +.IP \(bu +GNX4K +.PP +.SH OPTIONS +These programs follow the usual GNU command line syntax, with long +options starting with two dashes (`\-'). +A summary of options is included below. +For a complete description, see the Info files. +.TP +.B \-?, \-\-help +Show summary of options. +.TP +.B \-\-help\-all +Show all help options. +.TP +.B \-\-help\-gtk +Show GTK+ options. +.TP +.B \-\-display=\fIDISPLAY\fR +X display to use. +.TP +.B \-d, \-\-device +MIDI device port to use. +.SH AUTHOR +gdigi was written by Tomasz Moń <desowin@gmail.com>. +.PP +Send comments, bug reports and patches to gdigi +mailinglist at Google Groups. +.PP +This manual page was written by Andrew O. Shadoura <bugzilla@tut.by>, +for the Debian project (but may be used by others). +.PP +Permission is granted to copy, distribute and/or modify this document under the +terms of the GNU General Public License as published by the Free Software +Foundation, under version 3 of the License. + @@ -0,0 +1,1241 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#include <stdio.h> +#include <gtk/gtk.h> +#include <gio/gio.h> +#include <getopt.h> +#include <alsa/asoundlib.h> +#include <alloca.h> +#include "gdigi.h" +#include "gui.h" + +static unsigned char device_id = 0x7F; +static unsigned char family_id = 0x7F; +static unsigned char product_id = 0x7F; + +static snd_rawmidi_t *output = NULL; +static snd_rawmidi_t *input = NULL; +static char *device_port = NULL; + +static GQueue *message_queue = NULL; +static GMutex *message_queue_mutex = NULL; +static GCond *message_queue_cond = NULL; + +/** + * Registers an error quark for gdigi if necessary. + * + * \return error quark used for gdigi errors + **/ +static GQuark gdigi_error_quark() +{ + static GQuark quark = 0; + + if (quark == 0) { + quark = g_quark_from_static_string("gdigi-error"); + } + + return quark; +} + +/** + * \param array data to calculate checksum + * \param length data length + * + * Calculates message checksum. + * + * \return calculated checksum. + **/ +static char calculate_checksum(gchar *array, gint length) +{ + int x; + int checksum = 0; + + for (x = 0; x<length; x++) { + checksum ^= array[x]; + } + + return checksum; +} + +/** + * Opens MIDI device. This function modifies global input and output variables. + * + * \return FALSE on success, TRUE on error. + **/ +gboolean open_device() +{ + int err; + + err = snd_rawmidi_open(&input, &output, device_port, SND_RAWMIDI_SYNC); + if (err) { + fprintf(stderr, "snd_rawmidi_open %s failed: %d\n", device_port, err); + return TRUE; + } + + err = snd_rawmidi_nonblock(output, 0); + if (err) { + fprintf(stderr, "snd_rawmidi_nonblock failed: %d\n", err); + return TRUE; + } + + snd_rawmidi_read(input, NULL, 0); /* trigger reading */ + + return FALSE; +} + +/** + * \param data data to be sent + * \param length data length + * + * Sends data to device. This function uses global output variable. + **/ +void send_data(char *data, int length) +{ + snd_rawmidi_write(output, data, length); +} + +/** + * \param data data to be packed + * \param len data length + * + * Packs data using method used on all newer DigiTech products. + * + * \return GString containing packed data + **/ +GString *pack_data(gchar *data, gint len) +{ + GString *packed; + gint i; + gint new_len; + unsigned char status; + gint offset; + gint status_byte; + + new_len = len + (len/7); + packed = g_string_sized_new(new_len); + status = 0; + offset = -1; + status_byte = 0; + + for (i=0; i<len; i++) { + if ((i % 7) == 0) { + packed->str[status_byte] = status; + status = 0; + status_byte = packed->len; + g_string_append_c(packed, '\0'); + } + g_string_append_c(packed, (data[i] & 0x7F)); + status |= (data[i] & 0x80) >> ((i%7) + 1); + } + packed->str[status_byte] = status; + + return packed; +} + +static void message_free_func(GString *msg, gpointer user_data) +{ + g_string_free(msg, TRUE); +} + +/** + * \param msg message to unpack + * + * Unpacks message data. This function modifies given GString. + **/ +static void unpack_message(GString *msg) +{ + int offset; + int x; + int i; + unsigned char status; + unsigned char *str; + gboolean stop = FALSE; + + g_return_if_fail(msg != NULL); + g_return_if_fail(msg->len > 9); + + offset = 1; + x = 0; + i = 8; + + str = (unsigned char*)msg->str; + do { + offset += 8; + status = str[offset-1]; + for (x=0; x<7 && !stop; x++) { + if (offset+x >= msg->len) { + i++; + stop = TRUE; + break; + } + if (str[offset+x] == 0xF7) { + if (x == 0) { + str[i] = status; + i++; + } + str[i] = 0xF7; + i++; + stop = TRUE; + break; + } + + str[i] = (((status << (x+1)) & 0x80) | str[x+offset]); + i++; + } + } while (!stop); + + g_string_truncate(msg, i); +} + +/** + * \param msg SysEx message + * + * Checks message ID. + * + * \return MessageID, or -1 on error. + **/ +MessageID get_message_id(GString *msg) +{ + /** \todo check if msg is valid SysEx message */ + g_return_val_if_fail(msg != NULL, -1); + g_return_val_if_fail(msg->str != NULL, -1); + + if (msg->len > 7) { + return (unsigned char)msg->str[7]; + } + return -1; +} + +void push_message(GString *msg) +{ + if (((unsigned char)msg->str[0] == 0xF0) && ((unsigned char)msg->str[msg->len-1] == 0xF7)) + g_message("Pushing correct message!"); + else + g_warning("Pushing incorrect message!"); + + int x; + for (x = 0; x<msg->len; x++) + printf("%02x ", (unsigned char)msg->str[x]); + printf("\n"); + + switch (get_message_id(msg)) { + case ACK: + g_message("Received ACK"); + g_string_free(msg, TRUE); + return; + + case NACK: + g_message("Received NACK"); + g_string_free(msg, TRUE); + return; + + case RECEIVE_PARAMETER_VALUE: + unpack_message(msg); + SettingParam *param = setting_param_new_from_data(&msg->str[8], NULL); + g_message("Received parameter change ID: %d Position: %d Value: %d", param->id, param->position, param->value); + + GDK_THREADS_ENTER(); + apply_setting_param_to_gui(param); + GDK_THREADS_LEAVE(); + + setting_param_free(param); + g_string_free(msg, TRUE); + return; + + case RECEIVE_DEVICE_NOTIFICATION: + unpack_message(msg); + unsigned char *str = (unsigned char*)msg->str; + switch (str[8]) { + case NOTIFY_PRESET_MOVED: + if (str[11] == PRESETS_EDIT_BUFFER && str[12] == 0) { + g_message("Loaded preset %d from bank %d", str[10], str[9]); + + GDK_THREADS_ENTER(); + g_timeout_add(0, apply_current_preset_to_gui, NULL); + GDK_THREADS_LEAVE(); + } else + g_message("%d %d moved to %d %d", str[9], str[10], str[11], str[12]); + default: + g_message("Received unhandled device notification"); + } + g_string_free(msg, TRUE); + return; + default: + g_mutex_lock(message_queue_mutex); + g_queue_push_tail(message_queue, msg); + g_cond_signal(message_queue_cond); + g_mutex_unlock(message_queue_mutex); + } +} + +gpointer read_data_thread(gboolean *stop) +{ + /* This is mostly taken straight from alsa-utils-1.0.19 amidi/amidi.c + by Clemens Ladisch <clemens@ladisch.de> */ + int err; + int npfds; + struct pollfd *pfds; + GString *string = NULL; + + npfds = snd_rawmidi_poll_descriptors_count(input); + pfds = alloca(npfds * sizeof(struct pollfd)); + snd_rawmidi_poll_descriptors(input, pfds, npfds); + + do { + unsigned char buf[256]; + int i, length; + unsigned short revents; + + /* SysEx messages can't contain bytes with 8th bit set. + memset our buffer to 0xFF, so if for some reason we'll get out of reply bounds, we'll catch it */ + memset(buf, sizeof(buf), 0xFF); + + err = poll(pfds, npfds, 200); + if (err < 0 && errno == EINTR) + break; + if (err < 0) { + g_error("poll failed: %s", strerror(errno)); + break; + } + if ((err = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) { + g_error("cannot get poll events: %s", snd_strerror(errno)); + break; + } + if (revents & (POLLERR | POLLHUP)) + break; + if (!(revents & POLLIN)) + continue; + + err = snd_rawmidi_read(input, buf, sizeof(buf)); + if (err == -EAGAIN) + continue; + if (err < 0) { + g_error("cannot read: %s", snd_strerror(err)); + break; + } + + length = 0; + for (i = 0; i < err; ++i) + if ((unsigned char)buf[i] != 0xFE) /* ignore active sensing */ + buf[length++] = buf[i]; + + i = 0; + + while (i < length) { + int pos; + int bytes; + + if (string == NULL) { + while (buf[i] != 0xF0 && i < length) + i++; + } + + pos = i; + + for (bytes = 0; (bytes<length-i) && (buf[i+bytes] != 0xF7); bytes++); + + if (buf[i+bytes] == 0xF7) bytes++; + + i += bytes; + + if (string == NULL) + string = g_string_new_len((gchar*)&buf[pos], bytes); + else + g_string_append_len(string, (gchar*)&buf[pos], bytes); + + if ((unsigned char)string->str[string->len-1] == 0xF7) { + /* push message on stack */ + push_message(string); + string = NULL; + } + } + } while (*stop == FALSE); + + if (string) { + g_string_free(string, TRUE); + string = NULL; + } + + return NULL; +} + +/** + * \param procedure procedure ID + * \param data unpacked message data + * \param len data length + * + * Creates SysEx message then sends it. This function uses folowing global variables: device_id, family_id and product_id. + **/ +void send_message(gint procedure, gchar *data, gint len) +{ + GString *msg = g_string_new_len("\xF0" /* SysEx status byte */ + "\x00\x00\x10", /* Manufacturer ID */ + 4); + g_string_append_printf(msg, + "%c%c%c" /* device, family, product ID */ + "%c", /* procedure */ + device_id, family_id, product_id, + procedure); + + if (len > 0) { + GString *tmp = pack_data(data, len); + g_string_append_len(msg, tmp->str, tmp->len); + g_string_free(tmp, TRUE); + } + + g_string_append_printf(msg, "%c\xF7", + calculate_checksum(&msg->str[1], msg->len - 1)); + + send_data(msg->str, msg->len); + + g_string_free(msg, TRUE); +} + +/** + * \param id MessageID of requested message + * + * Reads data from message queue until message with matching id is found. + * + * \return GString containing unpacked message. + **/ +GString *get_message_by_id(MessageID id) +{ + GString *data = NULL; + guint x, len; + gboolean found = FALSE; + + g_mutex_lock(message_queue_mutex); + do { + len = g_queue_get_length(message_queue); + for (x = 0; x<len; x++) { + data = g_queue_peek_nth(message_queue, x); + if (get_message_id(data) == id) { + found = TRUE; + g_queue_pop_nth(message_queue, x); + break; + } + } + + if (found == FALSE) + g_cond_wait(message_queue_cond, message_queue_mutex); + + } while (found == FALSE); + g_mutex_unlock(message_queue_mutex); + + unpack_message(data); + + return data; +} + +/** + * \param msg message to append value + * \param value value to append + * + * Packs value using scheme used on all newer DigiTech products. + **/ +void append_value(GString *msg, guint value) +{ + /* check how many bytes long the value is */ + guint temp = value; + gint n = 0; + do { + n++; + temp = temp >> 8; + } while (temp); + + if (n == 1) { + if (value & 0x80) + n = 2; + else + g_string_append_printf(msg, "%c", value); + } + + if (n > 1) { + gint x; + g_string_append_printf(msg, "%c", (n | 0x80)); + for (x=0; x<n; x++) { + g_string_append_printf(msg, "%c", + ((value >> (8*(n-x-1))) & 0xFF)); + } + } +} + +/** + * \param str pointer to value to unpack + * \param len return location for how many bytes value is encoded on (length is added to current value) + * + * Unpacks value using scheme used on all newer DigiTech products. + * + * \return unpacked value + **/ +guint unpack_value(gchar *str, int *len) +{ + guint value; + gint tmp; + + value = (unsigned char)str[0]; + if (len != NULL) + *len += 1; + + if (value > 0x80) { + tmp = value & 0x7F; + value = 0; + gint i; + for (i = 0; i<tmp; i++) { + value |= ((unsigned char)str[1+i] << (8*(tmp-i-1))); + } + + if (len != NULL) + *len += tmp; + } + + return value; +} + +/** + * Allocates memory for SettingParam. + * + * \return SettingParam which must be freed using setting_param_free. + **/ +SettingParam *setting_param_new() +{ + SettingParam *param = g_slice_new(SettingParam); + param->id = -1; + param->position = -1; + param->value = -1; + + return param; +} + +/** + * \param str pointer to setting param in message + * \param len return location for how many bytes value is encoded on (length is added to current value) + * + * Creates SettingParam basing on data. + * This function expects str to point on: + * -Parameter ID - 2 bytes + * -Parameter position - 1 byte + * -Parameter value - var + * + * \return newly created SettingParam which must be freed using setting_param_free. + **/ +SettingParam *setting_param_new_from_data(gchar *str, gint *len) +{ + gint id; + gint position; + guint value; + + id = ((unsigned char)str[0] << 8) | (unsigned char)str[1]; + position = (unsigned char)str[2]; + if (len != NULL) + *len += 3; + + value = unpack_value(&str[3], len); + + SettingParam *param = g_slice_new(SettingParam); + param->id = id; + param->position = position; + param->value = value; + + return param; +} + +/** + * \param param SettingParam to be freed + * + * Frees all memory used by SettingParam. + **/ +void setting_param_free(SettingParam *param) +{ + g_slice_free(SettingParam, param); +} + +/** + * Allocates memory for SettingGenetx. + * + * \return SettingGenetx which must be freed using setting_genetx_free. + **/ +SettingGenetx *setting_genetx_new() +{ + SettingGenetx *genetx = g_slice_new(SettingGenetx); + /* Older patches don't specify GeNetX version */ + genetx->version = GENETX_VERSION_1; + genetx->type = GENETX_TYPE_NOT_SET; + genetx->channel = -1; + genetx->name = NULL; + genetx->data = NULL; + + return genetx; +} + +/** + * \param genetx SettingGenetx to be freed + * + * Frees all memory used by SettingGenetx. + **/ +void setting_genetx_free(SettingGenetx *genetx) +{ + g_free(genetx->name); + if (genetx->data != NULL) { + g_string_free(genetx->data, TRUE); + } + g_slice_free(SettingGenetx, genetx); +} + +/** + * \param version GeNetX version + * \param type GeNetX type + * + * Retrieves SectionID for specified GeNetX version and type. + * + * \return SectionID specified by version and type, or -1 on error. + **/ +SectionID get_genetx_section_id(gint version, gint type) +{ + if (version == GENETX_VERSION_1) { + if (type == GENETX_TYPE_AMP) { + return SECTION_GENETX_AMP; + } else if (type == GENETX_TYPE_CABINET) { + return SECTION_GENETX_CABINET; + } + } else if (version == GENETX_VERSION_2) { + if (type == GENETX_TYPE_AMP) { + return SECTION_GENETX2_AMP; + } else if (type == GENETX_TYPE_CABINET) { + return SECTION_GENETX2_CABINET; + } + } + + g_message("This version of gdigi don't know what to do with this " + "GeNetX version (%d) and type (%d)", version, type); + + return -1; +} + +/** + * \param id Parameter ID + * \param position Parameter position + * \param value Parameter value + * + * Forms SysEx message to set parameter then sends it to device. + **/ +void set_option(guint id, guint position, guint value) +{ + GString *msg = g_string_sized_new(9); + g_string_append_printf(msg, "%c%c%c", + ((id & 0xFF00) >> 8), (id & 0xFF), + position); + append_value(msg, value); + send_message(RECEIVE_PARAMETER_VALUE, msg->str, msg->len); + g_string_free(msg, TRUE); +} + +/** + * \param section data section ID + * \param bank section-specific bank number + * \param index index of the desired object within the bank + * \param name object name + * \param data GString containing object data + * + * Forms RECEIVE_OBJECT SysEx message then sends it to device. + **/ +void send_object(SectionID section, guint bank, guint index, + gchar *name, GString *data) +{ + GString *msg = g_string_new(NULL); + + gint len = data->len; + + g_string_append_printf(msg, + "%c%c%c%c%s%c%c%c", + section, bank, + ((index & 0xFF00) >> 8), (index & 0xFF), + name, 0 /* NULL terminated string */, + ((len & 0xFF00) >> 8), (len & 0xFF)); + + g_string_append_len(msg, data->str, data->len); + + send_message(RECEIVE_OBJECT, msg->str, msg->len); + + g_string_free(msg, TRUE); +} + +/** + * \param params GList containing SettingParam + * + * Forms RECEIVE_PRESET_PARAMETERS SysEx message then sends it to device. + **/ +void send_preset_parameters(GList *params) +{ + GString *msg = g_string_sized_new(500); + GList *iter = params; + gint len = g_list_length(iter); + + g_string_append_printf(msg, "%c%c", + ((len & 0xFF00) >> 8), + (len & 0xFF)); + + while (iter) { + SettingParam *param = (SettingParam *) iter->data; + iter = iter->next; + + g_string_append_printf(msg, "%c%c%c", + ((param->id & 0xFF00) >> 8), + (param->id & 0xFF), + param->position); + + append_value(msg, param->value); + }; + + send_message(RECEIVE_PRESET_PARAMETERS, msg->str, msg->len); + + g_string_free(msg, TRUE); +} + +/** + * \param bank preset bank + * \param x preset index + * + * Switches to selected preset. + **/ +void switch_preset(guint bank, guint x) +{ + GString *msg = g_string_sized_new(6); + g_string_append_printf(msg, "%c%c%c%c%c%c", + bank, x, /* source */ + PRESETS_EDIT_BUFFER, 0, /* destination */ + 0, /* keep existing name */ + 1); /* load */ + send_message(MOVE_PRESET, msg->str, msg->len); + g_string_free(msg, TRUE); +} + +/** + * \param x preset index + * \param name preset name + * + * Stores current edit buffer in user presets bank. + **/ +void store_preset_name(int x, const gchar *name) +{ + GString *msg = g_string_sized_new(6); + g_string_append_printf(msg, "%c%c%c%c%s%c%c", + PRESETS_EDIT_BUFFER, 0, /* source */ + PRESETS_USER, x, /* destination */ + name, 0, /* name */ + 1); /* load */ + send_message(MOVE_PRESET, msg->str, msg->len); + g_string_free(msg, TRUE); +} + +/** + * \param x preset index + * \param name preset name + * + * Sets preset name. + **/ +void set_preset_name(int x, gchar *name) +{ + GString *msg = g_string_sized_new(12); + g_string_append_printf(msg, "%c%c%s%c", + PRESETS_USER, /* preset bank */ + x, /* preset index */ + name, 0); /* name */ + send_message(RECEIVE_PRESET_NAME, msg->str, msg->len); + g_string_free(msg, TRUE); +} + +/** + * \param bank preset bank + * + * Queries preset names. + * + * \return GStrv which must be freed with g_strfreev, or NULL on error. + **/ +GStrv query_preset_names(gchar bank) +{ + GString *data = NULL; + int x; /* used to iterate over whole reply */ + int n = 0; /* current preset number */ + int n_total; /* total number of presets */ + gchar **str_array = NULL; + + /* query user preset names */ + send_message(REQUEST_PRESET_NAMES, &bank, 1); + + /* read reply */ + data = get_message_by_id(RECEIVE_PRESET_NAMES); + + if (data != NULL) { + if (data->len >= 10) { + n_total = data->str[9]; + str_array = g_new(gchar*, n_total + 1); + str_array[n_total] = NULL; + } + + for (x=10; ((x<data->len) && (n<n_total)); x++) { + if ((unsigned char)data->str[x] == 0xF7) /* every message ends with 0xF7 */ + break; + + str_array[n] = g_strdup(&data->str[x]); + x += strlen(str_array[n]); + n++; + } + g_string_free(data, TRUE); + } + return str_array; +} + +/** + * Reads multiple messages and puts them into GList. + * + * \param id MessageID starting message sequence + * + * \return GList with SysEx messages, which must be freed using message_list_free. + **/ +GList *get_message_list(MessageID id) +{ + GString *data = NULL; + GList *list = NULL; + guint x, len; + gboolean found = FALSE; + gboolean done = FALSE; + + g_mutex_lock(message_queue_mutex); + do { + len = g_queue_get_length(message_queue); + + for (x = 0; x<len && (found == FALSE); x++) { + data = g_queue_peek_nth(message_queue, x); + if (get_message_id(data) == id) { + found = TRUE; + g_queue_pop_nth(message_queue, x); + unpack_message(data); + list = g_list_append(list, data); + break; + } + } + + if (found == TRUE) { + int i; + int amt; + + switch (id) { + case RECEIVE_PRESET_START: + for (i = 10; (i < data->len) && data->str[i]; i++); + amt = (unsigned char)data->str[i+2]; + break; + case RECEIVE_BULK_DUMP_START: + amt = ((unsigned char)data->str[8] << 8) | (unsigned char)data->str[9]; + break; + default: + g_error("get_message_list() doesn't support followning id: %d", id); + g_string_free(data, TRUE); + g_list_free(list); + return NULL; + } + + while (amt) { + g_message("%d messages left", amt); + data = g_queue_pop_nth(message_queue, x); + if (data == NULL) { + g_cond_wait(message_queue_cond, message_queue_mutex); + } else { + unpack_message(data); + list = g_list_append(list, data); + amt--; + } + } + + done = TRUE; + } else { + /* id not found in message queue */ + g_cond_wait(message_queue_cond, message_queue_mutex); + } + } while (done == FALSE); + g_mutex_unlock(message_queue_mutex); + + return list; +} + +/** + * \param list list to be freed + * + * Frees all memory used by message list. + **/ +void message_list_free(GList *list) +{ + g_return_if_fail(list != NULL); + + g_list_foreach(list, (GFunc) message_free_func, NULL); + g_list_free(list); +} + +/** + * Queries current edit buffer. + * + * \return GList with preset SysEx messages, which must be freed using message_list_free. + **/ +GList *get_current_preset() +{ + send_message(REQUEST_PRESET, "\x04\x00", 2); + return get_message_list(RECEIVE_PRESET_START); +} + +/** + * Creates backup file. + * + * \param file backup file handle + * \param error a GError + * + * \return FALSE on success, TRUE on error. + **/ +static gboolean create_backup_file(GFile *file, GError **error) +{ + GFileOutputStream *output = NULL; + GList *list = NULL, *iter = NULL; + const gchar header[] = {'\x01', '\x00'}; + gsize written; + gboolean val; + + if (error) + *error = NULL; + output = g_file_create(file, G_FILE_CREATE_NONE, NULL, error); + if (output == NULL) + return TRUE; + + if (error) + *error = NULL; + val = g_output_stream_write_all(G_OUTPUT_STREAM(output), header, + sizeof(header), &written, NULL, error); + if (val == FALSE) { + g_object_unref(output); + return TRUE; + } + + send_message(REQUEST_BULK_DUMP, "\x00", 1); + list = get_message_list(RECEIVE_BULK_DUMP_START); + + for (iter = list; iter; iter = g_list_next(iter)) { + GString *str; + guchar id; /* message id */ + guint32 len; /* message length */ + + str = (GString*) iter->data; + + id = get_message_id(str); + if (error) + *error = NULL; + val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &id, + sizeof(id), &written, NULL, error); + if (val == FALSE) { + message_list_free(list); + g_object_unref(output); + return TRUE; + } + + len = GUINT32_TO_LE(str->len - 10); + if (error) + *error = NULL; + val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &len, + sizeof(len), &written, NULL, error); + if (val == FALSE) { + message_list_free(list); + g_object_unref(output); + return TRUE; + } + + if (error) + *error = NULL; + val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &str->str[8], + str->len - 10, &written, NULL, error); + if (val == FALSE) { + message_list_free(list); + g_object_unref(output); + return TRUE; + } + } + + message_list_free(list); + + if (error) + *error = NULL; + val = g_output_stream_close(G_OUTPUT_STREAM(output), NULL, error); + g_object_unref(output); + return !val; +} + +/** + * Restores backup file. + * + * \param filename backup filename + * \param error a GError + * + * \return FALSE on success, TRUE on error. + **/ +static gboolean restore_backup_file(const gchar *filename, GError **error) +{ + gchar *data; + gsize length; + gsize x; + + if (g_file_get_contents(filename, &data, &length, error) == FALSE) + return TRUE; + + if (error) + *error = NULL; + + if (!(data[0] == 0x01 && data[1] == 0x00)) { + g_free(data); + g_set_error_literal(error, gdigi_error_quark(), 0, + "Magic byte doesn't match"); + return TRUE; + } + + x = 0x02; + while (x < length) { + gchar id; + guint32 len; + + id = data[x]; + x++; + + if (x+4 <= length) { + len = GUINT32_FROM_LE(*((guint32*) &data[x])); + x += 4; + } else { + g_free(data); + g_set_error_literal(error, gdigi_error_quark(), 0, + "Unexpected end of data"); + return TRUE; + } + + if (x+len <= length) { + send_message(id, &data[x], len); + x += len; + } else { + g_free(data); + g_set_error_literal(error, gdigi_error_quark(), 0, + "Unexpected end of data"); + return TRUE; + } + } + + g_free(data); + return FALSE; +} + +/** + * \param device_id Variable to hold device ID + * \param family_id Variable to hold family ID + * \param product_id Variable to hold product ID + * + * Requests device information. + * + * \return TRUE on success, FALSE on error. + **/ +static gboolean request_who_am_i(unsigned char *device_id, unsigned char *family_id, + unsigned char *product_id) +{ + send_message(REQUEST_WHO_AM_I, "\x7F\x7F\x7F", 3); + + GString *data = get_message_by_id(RECEIVE_WHO_AM_I); + if ((data != NULL) && (data->len > 11)) { + *device_id = data->str[8]; + *family_id = data->str[9]; + *product_id = data->str[10]; + g_string_free(data, TRUE); + return TRUE; + } + return FALSE; +} + +static void request_device_configuration() +{ + gint os_major, os_minor; + gint cpu_major, cpu_minor; + gint protocol_version; + gint current_bank, current_preset; + gint media_card; + + send_message(REQUEST_DEVICE_CONFIGURATION, NULL, 0); + + GString *data = get_message_by_id(RECEIVE_DEVICE_CONFIGURATION); + + if (data->len > 14) { + os_major = data->str[8]; + os_minor = (((data->str[9] & 0xF0) >> 4) * 10) | + (data->str[9] & 0x0F); + g_message("OS version: %d.%d", os_major, os_minor); + + cpu_major = data->str[10]; + cpu_minor = data->str[11]; + g_message("CPU version: %d.%d", cpu_major, cpu_minor); + + protocol_version = data->str[12]; + g_message("Protocol version: %d", protocol_version); + + current_bank = data->str[13]; + current_preset = data->str[14]; + g_message("Active bank: %d", current_bank); + g_message("Active preset: %d", current_preset); + + if (os_major >= 1) { + media_card = data->str[15]; + g_message("Media card present: %d", media_card); + } + } +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +static GOptionEntry options[] = { + {"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device_port, "MIDI device port to use", NULL}, + {NULL} +}; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * \param[out] devices GList containing numbers (packed into pointers) + * of connected DigiTech devices + * + * Checks available soundcards for DigiTech devices. + * + * \return the number of connected DigiTech devices. + **/ +static gint get_digitech_devices(GList **devices) +{ + gint card_num = -1; + gint number = 0; + snd_card_next(&card_num); + + while (card_num > -1) { + char* name; + snd_card_get_longname(card_num, &name); + gint count = strspn(name,"DigiTech"); + if (count > 0) + { + number++; + *devices = g_list_append(*devices, GINT_TO_POINTER(card_num)); + } + snd_card_next(&card_num); + } + + return number; +} + +int main(int argc, char *argv[]) { + GError *error = NULL; + GOptionContext *context; + static gboolean stop_read_thread = FALSE; + GThread *read_thread = NULL; + + g_thread_init(NULL); + gdk_threads_init(); + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, options, NULL); + g_option_context_add_group(context, gtk_get_option_group(TRUE)); + + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_message("option parsing failed: %s\n", error->message); + g_error_free(error); + g_option_context_free(context); + exit(EXIT_FAILURE); + } + + if (device_port == NULL) { + /* port not given explicitly in commandline - search for devices */ + GList *devices = NULL; + if (get_digitech_devices(&devices) <= 0) { + g_message("Couldn't find DigiTech devices!"); + exit(EXIT_FAILURE); + } + device_port = g_strdup_printf("hw:%d,0,0", + GPOINTER_TO_INT(devices->data)); + g_list_free(devices); + g_message("Found device %s", device_port); + } else { + g_message("Using device %s", device_port); + } + + g_option_context_free(context); + + if (open_device() == TRUE) { + show_error_message(NULL, "Failed to open MIDI device"); + } else { + message_queue = g_queue_new(); + message_queue_mutex = g_mutex_new(); + message_queue_cond = g_cond_new(); + read_thread = g_thread_create((GThreadFunc)read_data_thread, + &stop_read_thread, + TRUE, NULL); + + if (request_who_am_i(&device_id, &family_id, &product_id) == FALSE) { + show_error_message(NULL, "No suitable reply from device"); + } else { + Device *device = NULL; + + if (get_device_info(device_id, family_id, product_id, &device) == FALSE) { + if (unsupported_device_dialog(&device) == FALSE) { + g_message("Shutting down"); + } + } + + if (device != NULL) { + /* enable GUI mode */ + set_option(GUI_MODE_ON_OFF, USB_POSITION, 1); + + gui_create(device); + gtk_main(); + gui_free(); + + /* disable GUI mode */ + set_option(GUI_MODE_ON_OFF, USB_POSITION, 0); + } + } + } + + if (read_thread != NULL) { + stop_read_thread = TRUE; + g_thread_join(read_thread); + } + + if (message_queue_mutex != NULL) { + g_mutex_free(message_queue_mutex); + } + + if (message_queue != NULL) { + g_message("%d unread messages in queue", + g_queue_get_length(message_queue)); + g_queue_foreach(message_queue, (GFunc) message_free_func, NULL); + g_queue_free(message_queue); + } + + if (output != NULL) { + snd_rawmidi_drain(output); + snd_rawmidi_close(output); + } + + if (input != NULL) { + snd_rawmidi_drain(input); + snd_rawmidi_close(input); + } + + return EXIT_SUCCESS; +} diff --git a/gdigi.desktop b/gdigi.desktop new file mode 100644 index 0000000..804407a --- /dev/null +++ b/gdigi.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=gdigi +Exec=gdigi +Categories=GNOME;Audio;AudioVideo; + @@ -0,0 +1,1007 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#ifndef GDIGI_H +#define GDIGI_H + +#include <glib.h> +#include <glib-object.h> + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define GNX_CHANNEL_POSITION 7 +#define GNX_CHANNEL_AMP 260 +#define GNX_WARP 261 +#define GNX_AMP_WARP 262 +#define GNX_CABINET_WARP 263 +#define GNX_CHANNEL_FS_MODE 264 + +enum { + GNX3K_WAH_TYPE_CRY = 129, + GNX3K_WAH_TYPE_BOUTIQUE = 130, + GNX3K_WAH_TYPE_FULLRANGE = 131, + + WAH_TYPE_CRY = 132, + WAH_TYPE_FULLRANGE = 133, + WAH_TYPE_CLYDE = 134 +}; + +#define WAH_POSITION_MIN_MAX 20 + +#define WAH_MIN 8195 +#define WAH_MAX 8196 + +#define WAH_TYPE 128 +#define WAH_ON_OFF 129 +#define WAH_POSITION 3 + +#define WAH_LEVEL 133 + +enum { + COMP_TYPE_DIGI = 195, + COMP_TYPE_CS = 196, + COMP_TYPE_DYNA = 197 +}; + +#define GNX3K_WHAM_TYPE 768 +#define GNX3K_WHAM_ENABLE 769 +#define GNX3K_WHAM_POSITION 5 +#define GNX3K_DETUNE_AMOUNT 1670 +#define GNX3K_PITCH_AMOUNT 1732 +#define GNX3K_PITCH_LEVEL 1731 +#define GNX3K_TALK_LEVEL 2818 + +enum { + GNX3K_WHAM_TYPE_WHAMMY = 1344, + GNX3K_WHAM_TYPE_IPS = 1345, + GNX3K_WHAM_TYPE_DETUNE = 1346, + GNX3K_WHAM_TYPE_PITCH = 1347, + GNX3K_WHAM_TYPE_TALK1 = 1348, + GNX3K_WHAM_TYPE_TALK2 = 1349, + GNX3K_WHAM_TYPE_TALK3 = 1350, + GNX3K_WHAM_TYPE_TALK4 = 1351, + GNX3K_WHAM_TYPE_TALK5 = 1352 +}; + +#define COMP_TYPE 207 +#define COMP_ON_OFF 193 +#define COMP_POSITION 4 + +#define GNX3K_COMP_ATTACK 194 +#define GNX3K_COMP_RATIO 195 +#define GNX3K_COMP_THRESHOLD 200 +#define GNX3K_COMP_GAIN 201 + +#define COMP_SUSTAIN 208 +#define COMP_TONE 209 +#define COMP_ATTACK 211 +#define COMP_LEVEL 210 +#define COMP_SENSITIVITY 213 +#define COMP_OUTPUT 212 + +enum { + PICKUP_TYPE_HB_SC = 66, + PICKUP_TYPE_SC_HB = 65 +}; + +#define PICKUP_TYPE 64 +#define PICKUP_ON_OFF 65 +#define PICKUP_POSITION 2 + +enum { + DIST_TYPE_SCREAMER = 1280, + DIST_TYPE_808 = 1292, + DIST_TYPE_TS_MOD = 1301, + DIST_TYPE_SD_ODRV = 1302, + DIST_TYPE_OD_ODRV = 1299, + DIST_TYPE_SPARKDRIVE = 1286, + DIST_TYPE_GUYOD = 1285, + DIST_TYPE_DOD250 = 1283, + DIST_TYPE_REDLINE = 1297, + DIST_TYPE_AMPDRIVR = 1298, + DIST_TYPE_OC_DRIVE = 1300, + DIST_TYPE_RODENT = 1281, + DIST_TYPE_MX = 1291, + DIST_TYPE_DS = 1282, + DIST_TYPE_GRUNGE = 1287, + DIST_TYPE_ZONE = 1289, + DIST_TYPE_DEATH = 1294, + DIST_TYPE_GONK = 1293, + DIST_TYPE_8TAVIA = 1290, + DIST_TYPE_FUZZLATOR = 1295, + DIST_TYPE_CLASSIC_FUZZ = 1296, + DIST_TYPE_FUZZY = 1288, + DIST_TYPE_MP = 1284 +}; + +#define DIST_TYPE 2432 +#define DIST_ON_OFF 2433 +#define DIST_POSITION 6 + +#define DIST_SCREAMER_DRIVE 2434 +#define DIST_SCREAMER_TONE 2435 +#define DIST_SCREAMER_LVL 2436 + +#define DIST_808_OVERDRIVE 2473 +#define DIST_808_TONE 2474 +#define DIST_808_LVL 2475 + +#define DIST_TS_MOD_DRIVE 2562 +#define DIST_TS_MOD_TONE 2564 +#define DIST_TS_MOD_LVL 2563 + +#define DIST_SD_ODRV_DRIVE 2565 +#define DIST_SD_ODRV_TONE 2566 +#define DIST_SD_ODRV_LVL 2567 + +#define DIST_OD_ODRV_OVERDRIVE 2568 +#define DIST_OD_ODRV_LVL 2569 + +#define DIST_SPARKDRIVE_GAIN 2450 +#define DIST_SPARKDRIVE_TONE 2451 +#define DIST_SPARKDRIVE_CLEAN 2452 +#define DIST_SPARKDRIVE_VOLUME 2453 + +#define DIST_GUYOD_DRIVE 2448 +#define DIST_GUYOD_LVL 2449 + +#define DIST_DOD250_GAIN 2443 +#define DIST_DOD250_LVL 2444 + +#define DIST_REDLINE_GAIN 2488 +#define DIST_REDLINE_LOW 2489 +#define DIST_REDLINE_HIGH 2490 +#define DIST_REDLINE_LEVEL 2491 + +#define DIST_AMPDRIVR_GAIN 2570 +#define DIST_AMPDRIVR_MIDBOOST 2571 +#define DIST_AMPDRIVR_LVL 2572 + +#define DIST_OC_DRIVE_DRIVE 2492 +#define DIST_OC_DRIVE_TONE 2494 +#define DIST_OC_DRIVE_HP_LP 2493 +#define DIST_OC_DRIVE_LVL 2495 + +#define DIST_RODENT_DIST 2437 +#define DIST_RODENT_FILTER 2438 +#define DIST_RODENT_LVL 2439 + +#define DIST_MX_DIST 2468 +#define DIST_MX_OUTPUT 2469 + +#define DIST_DS_GAIN 2440 +#define DIST_DS_TONE 2441 +#define DIST_DS_LVL 2442 + +#define DIST_GRUNGE_GRUNGE 2454 +#define DIST_GRUNGE_FACE 2456 +#define DIST_GRUNGE_LOUD 2457 +#define DIST_GRUNGE_BUTT 2455 + +#define DIST_ZONE_GAIN 2460 +#define DIST_ZONE_LOW 2463 +#define DIST_ZONE_MID_LVL 2462 +#define DIST_ZONE_MID_FREQ 2461 +#define DIST_ZONE_HIGH 2464 +#define DIST_ZONE_LEVEL 2465 + +#define DIST_DEATH_LOW 2477 +#define DIST_DEATH_MID 2476 +#define DIST_DEATH_HIGH 2479 +#define DIST_DEATH_LVL 2478 + +#define DIST_GONK_GONK 2480 +#define DIST_GONK_SMEAR 2471 +#define DIST_GONK_SUCK 2470 +#define DIST_GONK_HEAVE 2472 + +#define DIST_8TAVIA_DRIVE 2466 +#define DIST_8TAVIA_VOLUME 2467 + +#define DIST_FUZZLATOR_FUZZ 2481 +#define DIST_FUZZLATOR_TONE 2482 +#define DIST_FUZZLATOR_LOOSETIGHT 2483 +#define DIST_FUZZLATOR_VOLUME 2484 + +#define DIST_CLASSIC_FUZZ_FUZZ 2485 +#define DIST_CLASSIC_FUZZ_TONE 2486 +#define DIST_CLASSIC_FUZZ_VOLUME 2487 + +#define DIST_FUZZY_FUZZ 2458 +#define DIST_FUZZY_VOLUME 2459 + +#define DIST_MP_SUSTAIN 2445 +#define DIST_MP_TONE 2446 +#define DIST_MP_VOLUME 2447 + +#define PRESET_POSITION 18 +#define PRESET_LEVEL 2626 + +enum { + AMP_TYPE_TWEED_CHAMP = 307, + AMP_TYPE_TWEED_DELUXE = 308, + AMP_TYPE_TWEED_BASSMAN = 309, + AMP_TYPE_BROWN_BASSMAN = 310, + AMP_TYPE_BLACKFACE_TWIN = 311, + AMP_TYPE_BLACKFACE_DELUXE = 312, + AMP_TYPE_PLEXI_JTM_45 = 313, + AMP_TYPE_SUPER_LEAD_PLEXI = 314, + AMP_TYPE_PLEXI_JUMP_PANEL = 315, + AMP_TYPE_MASTER_VOLUME = 316, + AMP_TYPE_JCM800 = 317, + AMP_TYPE_JCM900 = 318, + AMP_TYPE_JCM2000 = 319, + AMP_TYPE_AC15 = 322, + AMP_TYPE_AC30TB = 323, + AMP_TYPE_HIWATT_100 = 324, + AMP_TYPE_BOOGIE_MARK_II = 320, + AMP_TYPE_BOOGIE_MARK_IV = 371, + AMP_TYPE_DUAL_RECTIFIER = 321, + AMP_TYPE_TRIPLE_RECTIFIER = 370, + AMP_TYPE_22_CALIBR = 386, + AMP_TYPE_LEGACY_VL100 = 327, + AMP_TYPE_MATCHLESS_HC30 = 326, + AMP_TYPE_CHIEF = 385, + AMP_TYPE_SOLDANO_100 = 325, + AMP_TYPE_SUPERGROUP = 381, + AMP_TYPE_GA40 = 380, + AMP_TYPE_OR120 = 372, + AMP_TYPE_PV5150II = 373, + AMP_TYPE_RG100 = 374, + AMP_TYPE_JC120_JAZZ = 375, + AMP_TYPE_SOLAR100 = 376, + AMP_TYPE_SOLO = 331, + AMP_TYPE_METAL = 332, + AMP_TYPE_BRIGHT = 333, + AMP_TYPE_CHUNK = 334, + AMP_TYPE_CLEAN = 335, + AMP_TYPE_HIGH_GAIN = 337, + AMP_TYPE_BLUES = 338, + AMP_TYPE_FUZZ = 339, + AMP_TYPE_SPANK = 330, + AMP_TYPE_GSP2101_CLEAN_TUBE = 328, + AMP_TYPE_GSP2101_SAT_TUBE = 329, + AMP_TYPE_CRUNCH = 336, + AMP_TYPE_MONSTER = 377, + AMP_TYPE_TWEEDFACE = 378, + AMP_TYPE_BLACKBASS = 379, + AMP_TYPE_STONER_ROCK = 368, + AMP_TYPE_DARK_METAL = 369, + AMP_TYPE_TRANSISTOR = 382, + AMP_TYPE_BROWN_SOUND = 383, + AMP_TYPE_MOSH = 384, + AMP_TYPE_ACOUSTIC = 341, + AMP_TYPE_JUMBO_ACOUSTIC = 340, + AMP_TYPE_DIRECT = 306, + AMP_TYPE_SVT_ROCK_BASS = 342, + AMP_TYPE_SVT_CLASSIC_BASS = 343, + AMP_TYPE_PEG_B15_BASS = 344, + AMP_TYPE_BASIC_BASS = 345, + AMP_TYPE_SHOWMAN_BASS = 346, + AMP_TYPE_ASH_MODERN_BASS = 347, + AMP_TYPE_BRIT_BASS = 348, + AMP_TYPE_SOLAR_BASS = 349, + AMP_TYPE_BOOGIE_BASS = 350, + AMP_TYPE_HART_BASS = 351, +}; + +enum { + EQ_TYPE_BRIGHT = 1474, + EQ_TYPE_MIDBOOST = 1472, + EQ_TYPE_SCOOP = 1473, + EQ_TYPE_WARM = 1475 +}; + +#define AMP_TYPE 2496 +#define AMP_ON_OFF 265 +#define AMP_POSITION 8 +#define CH2_AMP_POSITION 10 + +#define AMP_LOOP_ON_OFF 3649 +#define AMP_LOOP_POSITION 33 + +#define AMP_BYPASS_ON_OFF 12361 +#define AMP_BYPASS_POSITION 0 + +#define AMP_SELECT 256 +#define AMP_SELECT_POSITION 7 + +#define AMP_CHANNEL_A 0 +#define AMP_CHANNEL_B 1 + +#define AMP_GAIN 2497 +#define AMP_LEVEL 2498 +#define AMP_BASS_FREQ 2499 +#define AMP_BASS_LEVEL 2500 +#define AMP_MID_FREQ 2501 +#define AMP_MID_LEVEL 2502 +#define AMP_TREBLE_FREQ 2503 +#define AMP_TREBLE_LEVEL 2504 +#define AMP_EQ_ON_OFF 2505 +#define AMP_PRESENCE 2506 +#define AMP_BASS 2507 +#define AMP_MID 2508 +#define AMP_TREBLE 2509 + +#define AMP_CAB_TYPE 2560 +#define AMP_CAB_TUNING 2561 +#define AMP_CAB_POSITION 9 +#define CH2_AMP_CAB_POSITION 11 + +enum { + AMP_CAB_DIRECT = 570, + AMP_CAB_CHAMP = 571, + AMP_CAB_DELUXE = 572, + AMP_CAB_DELUXE_REVERB = 573, + AMP_CAB_BRITISH1_12 = 623, + AMP_CAB_GA1_12 = 624, + AMP_CAB_BLONDE2_12 = 577, + AMP_CAB_TWIN = 576, + AMP_CAB_BRITISH2_12 = 613, + AMP_CAB_JAZZ2_12 = 626, + AMP_CAB_JBL_215 = 627, + AMP_CAB_BASSMAN = 579, + AMP_CAB_BRITISH4_12 = 614, + AMP_CAB_BRITISH_GREEN = 616, + AMP_CAB_FANE4_12 = 584, + AMP_CAB_BOUTIQUE4_12 = 583, + AMP_CAB_VINTAGE = 622, + AMP_CAB_RECTO4_12 = 625, + AMP_CAB_DIGI_SOLO = 609, + AMP_CAB_DIGI_BRIGHT = 611, + AMP_CAB_DIGI_METAL = 618, + AMP_CAB_DIGI_ROCK = 619, + AMP_CAB_DIGI_ALT = 620, + AMP_CAB_DIGI_VNTG = 621, + AMP_CAB_DIGI_CHUNK = 612, + AMP_CAB_DIGI_SPANK2_12 = 608, + AMP_CAB_DIGI_SPKR_COMP = 585 +}; + +enum { + GNX_AMP_CAB_DIRECT = 570, + GNX_AMP_CAB_TWEED1_8 = 571, + GNX_AMP_CAB_TWEED1_12 = 572, + GNX_AMP_CAB_BLACKFACE1_12 = 573, + GNX_AMP_CAB_BRITISH1_12 = 574, + GNX_AMP_CAB_BLACKFACE2_12 = 576, + GNX_AMP_CAB_BLONDE2_12 = 577, + GNX_AMP_CAB_BRITISH2_12 = 578, + GNX_AMP_CAB_TWEED4_10 = 579, + GNX_AMP_CAB_BRITISH_70_4_12 = 580, + GNX_AMP_CAB_BRITISH_GREEN4_12 = 581, + GNX_AMP_CAB_STRAIGHT_V30_4_12 = 582, + GNX_AMP_CAB_SLANT_V30_4_12 = 583, + GNX_AMP_CAB_FANE4_12 = 584, + GNX_AMP_CAB_2101_SPKR_COMP = 585, + GNX_AMP_CAB_JUMBO_ACOUSTIC = 606, + GNX_AMP_CAB_DREAD_ACOUSTIC = 607, + GNX_AMP_CAB_DIGI_SPANK = 608, + GNX_AMP_CAB_DIGI_SOLO = 609, + GNX_AMP_CAB_DIGI_METAL = 610, + GNX_AMP_CAB_DIGI_BRIGHT = 611, + GNX_AMP_CAB_DIGI_CHUNK = 612, + GNX_AMP_CAB_HART_BASS1_15 = 586, + GNX_AMP_CAB_BASIC_BASS1_15 = 587, + GNX_AMP_CAB_PORTA_BASS1_15 = 588, + GNX_AMP_CAB_REFLEX1_18 = 589, + GNX_AMP_CAB_SOLAR_BASS2_15 = 590, + GNX_AMP_CAB_DE_BASS4_10 = 591, + GNX_AMP_CAB_ASH_BASS4_10 = 592, + GNX_AMP_CAB_GOLIATH_BASS4_10 = 593, + GNX_AMP_CAB_HART_BASS4_10 = 594, + GNX_AMP_CAB_SVT_BASS8_10 = 595, +}; + +#define EQ_TYPE 3202 +#define EQ_ON_OFF 3212 +#define EQ_POSITION 24 +#define EQ_POSITION_B 25 + +#define EQ_BASS 3203 +#define EQ_MID 3204 +#define EQ_MID_HZ 3206 +#define EQ_TREBLE 3205 +#define EQ_PRESENCE 3207 +#define EQ_TREBLE_HZ 3211 +#define EQ_LOW_LEVEL 3203 +#define EQ_MID_LEVEL 3204 +#define EQ_HIGH_LEVEL 3205 +#define EQ_LOW_FREQ 3213 +#define EQ_MID_FREQ 3214 +#define EQ_HIGH_FREQ 3215 +#define EQ_LOW_BANDWIDTH 3216 +#define EQ_MID_BANDWIDTH 3217 +#define EQ_HIGH_BANDWIDTH 3218 + +enum { + NOISEGATE_GATE = 768, + NOISEGATE_SWELL = 769 +}; + +#define NOISEGATE_TYPE 704 +#define NOISEGATE_ON_OFF 705 +#define NOISEGATE_POSITION 12 + +#define GNX3K_GATE_ATTACK 706 + +/* available only in Gate mode */ +#define NOISEGATE_GATE_TRESHOLD 710 +/* available only in Swell mode */ +#define NOISEGATE_SWELL_SENS 711 +/* available in both Gate and Swell modes */ +#define NOISEGATE_ATTACK 712 +#define NOISEGATE_RELEASE 713 +#define NOISEGATE_ATTN 714 + +enum { + GNX3K_MOD_TYPE_CHORUS = 857, + GNX3K_MOD_TYPE_FLANGER = 858, + GNX3K_MOD_TYPE_TRIGFLANGER = 859, + GNX3K_MOD_TYPE_PHASER = 860, + GNX3K_MOD_TYPE_TRIGPHASER = 861, + GNX3K_MOD_TYPE_TREMOLO = 862, + GNX3K_MOD_TYPE_PANNER = 863, + GNX3K_MOD_TYPE_VIBRATO = 864, + GNX3K_MOD_TYPE_ROTARY = 865, + GNX3K_MOD_TYPE_AUTOYA = 866, + GNX3K_MOD_TYPE_YAYA = 867, + GNX3K_MOD_TYPE_SYNTHTALK = 868, + GNX3K_MOD_TYPE_ENVELOPE = 869, + GNX3K_MOD_TYPE_DETUNE = 870, + GNX3K_MOD_TYPE_PITCH = 871, + GNX3K_MOD_TYPE_UNOVIBE = 880, +}; + +enum { + CHORUS_TYPE_CE = 0x37B, + CHORUS_TYPE_TC = 0x37C, + CHORUS_TYPE_DUAL = 0x379, + CHORUS_TYPE_GLISTEN = 0x392, + CHORUS_TYPE_MULTI = 0x37a, + CHORUS_TYPE_VOO_DOO = 0x396, + CHORUS_TYPE_CLONE = 0x397, + CHORUS_TYPE_FLANGER = 0x37d, + CHORUS_TYPE_TRIGGERED_FLANGER = 0x37e, + CHORUS_TYPE_FLTFLANGER = 0x398, + CHORUS_TYPE_MXR_FLANGER = 0x37f, + CHORUS_TYPE_EH_FLANGER = 0x380, + CHORUS_TYPE_AD_FLANGER = 0x393, + CHORUS_TYPE_PHASER = 0x381, + CHORUS_TYPE_TRIGGERED_PHASER = 0x382, + CHORUS_TYPE_MX_PHASER = 0x383, + CHORUS_TYPE_EH_PHASER = 0x384, + CHORUS_TYPE_VIBRATO = 0x360, + CHORUS_TYPE_ROTARY = 0x361, + CHORUS_TYPE_VIBROPAN = 0x38f, + CHORUS_TYPE_UNOVIBE = 0x390, + CHORUS_TYPE_TREMOLO = 0x35e, + CHORUS_TYPE_SCATTER_TREM = 0x394, + CHORUS_TYPE_OPTO_TREMOLO = 0x388, + CHORUS_TYPE_BIAS_TREMOLO = 0x389, + CHORUS_TYPE_PANNER = 0x35f, + CHORUS_TYPE_ENVELOPE = 0x38a, + CHORUS_TYPE_FX25 = 0x38e, + CHORUS_TYPE_AUTOYA = 0x38b, + CHORUS_TYPE_YAYA = 0x38c, + CHORUS_TYPE_SYNTH_TALK = 0x391, + CHORUS_TYPE_STEP_FILTER = 0x38d, + CHORUS_TYPE_SAMPLE_HOLD = 0x395, + CHORUS_TYPE_WHAMMY = 0x540, + CHORUS_TYPE_PITCH_SHIFT = 0x543, + CHORUS_TYPE_DETUNE = 0x542, + CHORUS_TYPE_IPS = 0x541, + CHORUS_TYPE_OCTAVER = 0x385, +}; + +#define CHORUSFX_TYPE 768 +#define CHORUSFX_ON_OFF 769 +#define CHORUSFX_PRE_POST 770 +#define CHORUSFX_POSITION 14 +#define CHORUSFX_PRE 1543 +#define CHORUSFX_POST 1544 + +#define CHORUS_SPEED 837 +#define CHORUS_DEPTH 838 +#define CHORUS_PREDELAY 839 + +#define CHORUS_WIDTH 848 +#define CHORUS_INTENSITY 849 + +#define CHORUS_LEVEL 836 +#define CHORUS_WAVE 840 +#define CHORUS_BALANCE 841 + +#define CHORUS_RATE 850 + +#define FLANGER_SPEED 902 +#define FLANGER_DEPTH 903 +#define FLANGER_REGEN 904 +#define FLANGER_LEVEL 901 +#define FLANGER_WAVE 905 +#define FLANGER_BALANCE 906 + +#define TRIG_FLANGER_SPEED 1030 +#define TRIG_FLANGER_SENS 1031 +#define TRIG_FLANGER_LFO_START 1028 +#define TRIG_FLANGER_MIX 1029 +#define TRIG_FLANGER_LEVEL 1032 + +#define FLTFLANGER_FREQ 922 + +#define MXR_FLANGER_WIDTH 914 +#define MXR_FLANGER_MANUAL 917 + +#define EH_FLANGER_RATE 918 +#define EH_FLANGER_RANGE 919 +#define EH_FLANGER_COLOR 916 + +#define AD_FLANGER_ENHANCE 920 +#define AD_FLANGER_HARMONICS 921 + +#define PHASER_SPEED 962 +#define PHASER_DEPTH 963 +#define PHASER_REGEN 966 +#define PHASER_LEVEL 965 +#define PHASER_WAVE 967 +#define PHASER_BALANCE 968 + +#define TRIG_PHASER_SPEED 1094 +#define TRIG_PHASER_SENS 1095 +#define TRIG_PHASER_LFO_START 1092 +#define TRIG_PHASER_MIX 1093 +#define TRIG_PHASER_LEVEL 1096 + +#define MX_PHASER_INTENSITY 976 + +#define EH_PHASER_RATE 979 +#define EH_PHASER_COLOR 977 + +#define VIBRATO_SPEED 1284 +#define VIBRATO_DEPTH 1285 +#define VIBRATO_WAVEFORM 1286 + +#define ROTARY_SPEED 1346 +#define ROTARY_INTENSITY 1348 +#define ROTARY_MIX 1349 +#define ROTARY_DOPPLER 1350 +#define ROTARY_CROSSOVER 1351 +#define ROTARY_BALANCE 1352 + +#define VIBROPAN_SPEED 1314 +#define VIBROPAN_DEPTH 1315 +#define VIBROPAN_VIBRA 1316 +#define VIBROPAN_WAVE 1317 + +#define UNOVIBE_PEDAL_SPEED 2884 +#define UNOVIBE_INTENSITY 2883 +#define UNOVIBE_CHORUS_VIBRATO 2882 +#define UNOVIBE_VOLUME 2885 + +#define TREMOLO_SPEED 1156 +#define TREMOLO_DEPTH 1155 +#define TREMOLO_WAVE 1157 + +#define PANNER_SPEED 1220 +#define PANNER_DEPTH 1219 +#define PANNER_WAVE 1221 + +#define ENVELOPE_MIX 1604 +#define ENVELOPE_SENSITIVITY 1606 +#define ENVELOPE_RANGE 1605 +#define ENVELOPE_BALANCE 1607 +#define ENVELOPE_BLEND 1608 + +#define GNX3K_AUTOYA_RANGE 1476 +#define AUTOYA_MIX 1477 +#define AUTOYA_SPEED 1478 +#define AUTOYA_DEPTH 1479 +#define AUTOYA_BALANCE 1481 +#define AUTOYA_INTENSITY 1482 +#define AUTOYA_RANGE 1483 + +#define YAYA_PEDAL 1410 +#define GNX3K_YAYA_RANGE 1412 +#define YAYA_MIX 1413 +#define YAYA_DEPTH 1414 +#define YAYA_BALANCE 1416 +#define YAYA_INTENSITY 1417 +#define YAYA_RANGE 1418 + +#define SYNTH_TALK_ATTACK 1542 +#define GNX3K_SYNTH_TALK_RELEASE 1543 +#define SYNTH_TALK_RELEASE 1547 +#define SYNTH_TALK_SENS 1544 +#define SYNTH_TALK_VOX 1540 +#define SYNTH_TALK_BALANCE 1545 + +#define STEP_FILTER_SPEED 3010 +#define STEP_FILTER_INTENSITY 3011 + +#define SAMPLE_HOLD_SPEED 3012 +#define SAMPLE_HOLD_INTENSITY 3013 + +#define WHAMMY_AMOUNT 1797 +#define WHAMMY_PEDAL 1795 +#define WHAMMY_MIX 1796 + +#define PITCH_AMOUNT 1730 +#define PITCH_BALANCE 1733 +#define PITCH_MIX 1745 + +#define DETUNE_LEVEL 1667 +#define DETUNE_AMOUNT 1668 +#define DETUNE_BALANCE 1669 + +#define IPS_SHIFT_AMOUNT 2754 +#define IPS_KEY 2756 +#define IPS_SCALE 2755 +#define IPS_LEVEL 2757 + +#define OCTAVER_OCTAVE1 1746 +#define OCTAVER_OCTAVE2 1747 +#define OCTAVER_DRY_LEVEL 1748 + +enum { + DELAY_TYPE_ANALOG = 1046, + DELAY_TYPE_DIGITAL = 1045, + DELAY_TYPE_MODULATED = 1047, + DELAY_TYPE_PONG = 1048, + DELAY_TYPE_TAPE = 1049, + DELAY_TYPE_ECHOPLEX = 1050, + DELAY_TYPE_DM = 1051, + + DELAY_RP500_TYPE_DIGITAL = 1052, + DELAY_RP500_TYPE_ANALOG = 1053, + DELAY_RP500_TYPE_DM = 1058, + DELAY_RP500_TYPE_ECHOPLEX = 1057, + DELAY_RP500_TYPE_MODULATED = 1054, + DELAY_RP500_TYPE_PONG = 1055, + DELAY_RP500_TYPE_REVERSE = 1064, + DELAY_RP500_TYPE_TAPE = 1056, + + DELAY_RP1000_TYPE_LO_FI = 1065, + DELAY_RP1000_TYPE_2_TAP = 1066, + + DELAY_GNX3K_TYPE_MONO = 1027, + DELAY_GNX3K_TYPE_PINGPONG = 1028, + DELAY_GNX3K_TYPE_ANALOG = 1029, + DELAY_GNX3K_TYPE_ANAPONG = 1030, + DELAY_GNX3K_TYPE_SPREAD = 1031, +}; + +#define DELAY_TYPE 1856 +#define DELAY_ON_OFF 1857 +#define DELAY_POSITION 15 + +#define DELAY_TIME 1888 + +#define DELAY_MULTIPLIER 1904 +#define DELAY_3_QUARTR 2180 +#define DELAY_EIGHT 2179 +#define DELAY_DOTEIGHT 2178 +#define DELAY_QUARTER 2177 +#define DELAY_HALF 2176 + +#define DELAY_TAPE_WOW 1891 +#define DELAY_TAPE_FLUTTER 1892 + +#define DELAY_LEVEL 1860 +#define DELAY_REPEATS 1863 +#define DELAY_TAP_TIME 1868 +#define DELAY_DUCK_THRESH 1889 +#define DELAY_DUCK_LEVEL 1890 +#define DELAY_REPEAT_RATE 1898 +#define DELAY_REPEAT_RATE_DM 1894 +#define DELAY_ECHO 1895 +#define DELAY_INTENSITY 1896 +#define DELAY_ECHOPLEX_TIME 1897 +#define DELAY_TIME_0_760 1899 +#define DELAY_VOLUME 1893 +#define DELAY_REPEATS_0_99 1874 +#define DELAY_DEPTH 1873 +#define DELAY_TAP_TIME_0_4990 1900 +#define DELAY_MIX 1902 +#define DELAY_TIME_0_4650 1901 +#define DELAY_TAP_RATIO 1905 + +#define GNX3K_DELAY_TIME 1862 +#define GNX3K_DELAY_FEEDBACK 1863 +#define GNX3K_DELAY_DUCK_THRESH 1864 +#define GNX3K_DELAY_DUCK_ATTEN 1865 +#define GNX3K_DELAY_BALANCE 1866 +#define GNX3K_DELAY_SPREAD 1867 + +enum { + GNX3K_REVERB_TYPE_STUDIO = 1107, + GNX3K_REVERB_TYPE_ROOM = 1108, + GNX3K_REVERB_TYPE_CLUB = 1109, + GNX3K_REVERB_TYPE_PLATE = 1110, + GNX3K_REVERB_TYPE_HALL = 1111, + GNX3K_REVERB_TYPE_AMPHITHEATER = 1112, + GNX3K_REVERB_TYPE_CHURCH = 1113, + GNX3K_REVERB_TYPE_GARAGE = 1114, + GNX3K_REVERB_TYPE_ARENA = 1115, + GNX3K_REVERB_TYPE_SPRING = 1116, + + REVERB_TYPE_TWIN = 1146, + REVERB_TYPE_LEX_AMBIENCE = 1150, + REVERB_TYPE_LEX_STUDIO = 1149, + REVERB_TYPE_LEX_ROOM = 1148, + REVERB_TYPE_LEX_HALL = 1147, + REVERB_TYPE_EMT240_PLATE = 1151 +}; + +#define REVERB_TYPE 1920 +#define REVERB_ON_OFF 1921 +#define REVERB_POSITION 16 + +#define REVERB_PREDELAY 1922 +#define REVERB_DAMPING 1924 +#define REVERB_DECAY 1927 +#define REVERB_BALANCE 1928 +#define REVERB_LIVELINESS 1933 +#define REVERB_LEVEL 1925 + +#define EXP_TYPE 8194 +#define EXP_POSITION 19 + +#define EXP_MIN 8195 +#define EXP_MAX 8196 +#define LFO_TYPE 8258 +#define LFO1_POSITION 22 +#define LFO2_POSITION 23 + +#define LIBRARY_TONE 8704 +#define LIBRARY_EFFECTS 8705 +#define EFFECTS_LEVEL 8706 + +#define LIBRARY_POSITION 25 + +enum { + TONE_LIB_OVERDRIVE = 1793, + TONE_LIB_ROCK1 = 1794, + TONE_LIB_ROCK2 = 1795, + TONE_LIB_BLUES1 = 1796, + TONE_LIB_BLUES2 = 1797, + TONE_LIB_METAL1 = 1798, + TONE_LIB_METAL2 = 1799, + TONE_LIB_COUNTRY1 = 1800, + TONE_LIB_COUNTRY2 = 1801, + TONE_LIB_WARM_DRIVE = 1802, + TONE_LIB_CRUNCH = 1803, + TONE_LIB_TEXAS_TONE = 1804, + TONE_LIB_ROCKABILLY = 1805, + TONE_LIB_SOLO1 = 1806, + TONE_LIB_SOLO2 = 1807, + TONE_LIB_ROCKWAH = 1808, + TONE_LIB_CHUNKY = 1809, + TONE_LIB_SMOOTH = 1810, + TONE_LIB_HEAVY = 1811, + TONE_LIB_CLEAN1 = 1812, + TONE_LIB_CLEAN2 = 1813, + TONE_LIB_BRITISH1 = 1814, + TONE_LIB_BRITISH2 = 1815, + TONE_LIB_AMERICAN1 = 1816, + TONE_LIB_AMERICAN2 = 1817, + TONE_LIB_TUBE_DRIVE = 1818, + TONE_LIB_DISTORTION = 1819, + TONE_LIB_SCOOPED = 1820, + TONE_LIB_PUNCHY = 1821, + TONE_LIB_BRIGHT_CLEAN = 1822, + + /* setting LIBRARY_TONE to this option seems to crash device */ + TONE_LIB_CUSTOM = 1792 +}; + +enum { + EFFECTS_LIB_CHORUS = 1857, + EFFECTS_LIB_PHASER = 1858, + EFFECTS_LIB_FLANGER = 1859, + EFFECTS_LIB_PITCH = 1860, + EFFECTS_LIB_TREMOLO = 1861, + EFFECTS_LIB_ROTARY = 1862, + EFFECTS_LIB_ENVELOPE = 1863, + EFFECTS_LIB_DIGITAL = 1864, + EFFECTS_LIB_ANALOG = 1865, + EFFECTS_LIB_PONG = 1866, + EFFECTS_LIB_MOD = 1867, + EFFECTS_LIB_TAPE = 1868, + EFFECTS_LIB_HALL = 1869, + EFFECTS_LIB_PLATE = 1870, + EFFECTS_LIB_SPRING = 1871, + EFFECTS_LIB_CHORUS_DIGITAL = 1872, + EFFECTS_LIB_CHORUS_DELAY_REVERB = 1873, + EFFECTS_LIB_FLANGER_ANALOG = 1874, + EFFECTS_LIB_PHASER_TAPE = 1875, + EFFECTS_LIB_PHASER_MOD = 1876, + EFFECTS_LIB_PHASER_ROOM = 1877, + EFFECTS_LIB_DIGITAL_HALL = 1878, + EFFECTS_LIB_ANALOG_SPRING = 1879, + EFFECTS_LIB_CHORUS_HALL = 1880, + EFFECTS_LIB_PONG_HALL = 1881, + EFFECTS_LIB_TAPE_SPRING = 1882, + EFFECTS_LIB_TREMOLO_TAPE = 1883, + EFFECTS_LIB_PITCH_DIGITAL = 1884, + EFFECTS_LIB_MOD_PLATE = 1885, + EFFECTS_LIB_ROTARY_TAPE = 1886, + + /* setting EFFECTS_LIBRARY to this option seems to crash device */ + EFFECTS_LIB_CUSTOM = 1856 +}; + +#define USB_POSITION 0 +#define USB_AUDIO_PLAYBACK_MIX 12297 +#define USB_AUDIO_LEVEL 12307 + +#define GUI_MODE_ON_OFF 12298 + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +typedef enum { + PRESETS_SYSTEM = 0, + PRESETS_USER = 1, + PRESETS_ARTIST = 2, + + /* Version 1 and later */ + PRESETS_MEDIA_CARD = 3, + PRESETS_EDIT_BUFFER = 4, /* Current preset edit buffer, index must be 0 */ + PRESETS_FACTORY2 = 5, + + /* Version 2 and later */ + PRESETS_EXTERNAL = 6 +} PresetBank; + +typedef enum { + /* Version 0 only */ + NOTIFY_PRESET_LOADED = 0, + NOTIFY_PRESET_STORED = 1, + + NOTIFY_MODIFIER_GROUP_CHANGED = 2, + + /* Version 1 */ + NOTIFY_PRESET_MOVED = 3, + NOTIFY_OBJECT_MOVED = 4, + NOTIFY_OBJECT_RENAMED = 5, + NOTIFY_MEDIA_CARD_PRESENT_CHANGED = 6, + NOTIFY_ALL_GLOBALS_CHANGED = 7, + NOTIFY_PRESET_INDEX_TABLE_CHANGED = 8, + NOTIFY_PRESET_RENAMED = 9 +} NotifyCode; + +typedef enum { + REQUEST_WHO_AM_I = 0x01, + RECEIVE_WHO_AM_I = 0x02, + + REQUEST_DEVICE_CONFIGURATION = 0x08, + RECEIVE_DEVICE_CONFIGURATION = 0x09, + + REQUEST_GLOBAL_PARAMETERS = 0x10, + RECEIVE_GLOBAL_PARAMETERS = 0x11, + + REQUEST_BULK_DUMP = 0x18, + RECEIVE_BULK_DUMP_START = 0x19, + RECEIVE_BULK_DUMP_END = 0x1B, + + REQUEST_PRESET_NAMES = 0x21, + RECEIVE_PRESET_NAMES = 0x22, + + REQUEST_PRESET_NAME = 0x28, + RECEIVE_PRESET_NAME = 0x29, + + REQUEST_PRESET = 0x2A, + RECEIVE_PRESET_START = 0x2B, + RECEIVE_PRESET_END = 0x2C, + RECEIVE_PRESET_PARAMETERS = 0x2D, + + LOAD_EDIT_BUFFER_PRESET = 0x38, /* version 0 only + use move preset in later versions */ + + MOVE_PRESET = 0x39, + + REQUEST_MODIFIER_LINKABLE_LIST = 0x3A, + RECEIVE_MODIFIER_LINKABLE_LIST = 0x3B, + + REQUEST_PARAMETER_VALUE = 0x40, + RECEIVE_PARAMETER_VALUE = 0x41, + + /* version 1 and later */ + REQUEST_OBJECT_NAMES = 0x50, + RECEIVE_OBJECT_NAMES = 0x51, + REQUEST_OBJECT_NAME = 0x52, + RECEIVE_OBJECT_NAME = 0x53, + REQUEST_OBJECT = 0x54, + RECEIVE_OBJECT = 0x55, + MOVE_OBJECT = 0x56, + DELETE_OBJECT = 0x57, + REQUEST_TABLE = 0x5A, + RECEIVE_TABLE = 0x5B, + + RECEIVE_DEVICE_NOTIFICATION = 0x70, + + ACK = 0x7E, + NACK = 0x7F +} MessageID; + +typedef enum { + SECTION_GENETX_AMP = 0, + SECTION_GENETX_CABINET = 1, + SECTION_DRUM_PATTERN = 2, + SECTION_DRUM_KIT = 3, + SECTION_DRUM_SAMPLES = 4, + SECTION_SONG = 5, + SECTION_FOOTSWITCH = 6, + SECTION_GENETX2_AMP = 7, + SECTION_GENETX2_CABINET = 8, + SECTION_DEVICE_GUID = 9, + SECTION_DEVICE_NAME = 10, +} SectionID; + +typedef struct { + int id; + int position; + int value; +} SettingParam; + +enum { + GENETX_VERSION_1, + GENETX_VERSION_2 +}; + +enum { + GENETX_TYPE_NOT_SET = -1, + GENETX_TYPE_AMP, + GENETX_TYPE_CABINET +}; + +enum { + GENETX_CHANNEL1 = 0, + GENETX_CHANNEL2 = 1, + GENETX_CHANNEL1_CUSTOM = 2, + GENETX_CHANNEL2_CUSTOM = 3, + GENETX_CHANNEL_CURRENT = 4 +} ChannelBankIndex; + +typedef struct { + int version; + int type; + int channel; + gchar *name; + GString *data; +} SettingGenetx; + +void send_message(gint procedure, gchar *data, gint len); +MessageID get_message_id(GString *msg); +void append_value(GString *msg, guint value); +GString *get_message_by_id(MessageID id); +SettingParam *setting_param_new(); +SettingParam *setting_param_new_from_data(gchar *str, gint *len); +SettingGenetx *setting_genetx_new(); +void setting_genetx_free(SettingGenetx *genetx); +void setting_param_free(SettingParam *param); +SectionID get_genetx_section_id(gint version, gint type); +void set_option(guint id, guint position, guint value); +void send_object(SectionID section, guint bank, guint index, + gchar *name, GString *data); +void send_preset_parameters(GList *params); +void switch_preset(guint bank, guint x); +void store_preset_name(int x, const gchar *name); +void set_preset_level(int level); +GStrv query_preset_names(gchar bank); +void message_list_free(GList *list); +GList *get_current_preset(); + +#endif /* GDIGI_H */ diff --git a/gtkknob.c b/gtkknob.c new file mode 100644 index 0000000..d64a467 --- /dev/null +++ b/gtkknob.c @@ -0,0 +1,919 @@ +/***************************************************************************** + * + * Most of this code comes from gAlan 0.2.0, copyright (C) 1999 + * Tony Garnock-Jones, with modifications from Sean Bolton, + * copyright (C) 2004, William Weston copyright (C) 2007, + * Pete Shorthose copyright (C) 2007, and Tomasz Moń, + * copyright (C) 2009 + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *****************************************************************************/ + +#include <math.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include "gtkknob.h" + + +#ifndef M_PI +# define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_1_PI +# define M_1_PI 0.31830988618379067154 /* 1/pi */ +#endif + + +#define SCROLL_DELAY_LENGTH 250 +#define KNOB_SIZE 32 /* this should really be read from the knob image */ + +#define STATE_IDLE 0 +#define STATE_PRESSED 1 +#define STATE_DRAGGING 2 + +static void gtk_knob_class_init(GtkKnobClass *klass); +static void gtk_knob_init(GtkKnob *knob); +static void gtk_knob_destroy(GtkObject *object); +static void gtk_knob_realize(GtkWidget *widget); +static void gtk_knob_size_request(GtkWidget *widget, GtkRequisition *requisition); +static void gtk_knob_size_allocate(GtkWidget *widget, GtkAllocation *allocation); +static gint gtk_knob_expose(GtkWidget *widget, GdkEventExpose *event); +static gint gtk_knob_scroll(GtkWidget *widget, GdkEventScroll *event); +static gint gtk_knob_button_press(GtkWidget *widget, GdkEventButton *event); +static gint gtk_knob_button_release(GtkWidget *widget, GdkEventButton *event); +static gint gtk_knob_key_press(GtkWidget *widget, GdkEventKey *event); +static gint gtk_knob_motion_notify(GtkWidget *widget, GdkEventMotion *event); +static gint gtk_knob_timer(GtkKnob *knob); + +static void gtk_knob_update_mouse_update(GtkKnob *knob); +static void gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step); +static void gtk_knob_update(GtkKnob *knob); +static void gtk_knob_adjustment_changed(GtkAdjustment *adjustment, gpointer data); +static void gtk_knob_adjustment_value_changed(GtkAdjustment *adjustment, gpointer data); + +/* Local data */ + +static GtkWidgetClass *parent_class = NULL; + + +/***************************************************************************** + * + * gtk_knob_get_type() + * + *****************************************************************************/ +GType +gtk_knob_get_type(void) { + static GType knob_type = 0; + + if (!knob_type) { + static const GTypeInfo knob_info = { + sizeof (GtkKnobClass), + NULL, + NULL, + (GClassInitFunc) gtk_knob_class_init, + NULL, + NULL, + sizeof (GtkKnob), + 0, + (GInstanceInitFunc) gtk_knob_init, + }; + knob_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkKnob", &knob_info, 0); + } + + return knob_type; +} + + +/***************************************************************************** + * + * gtk_knob_class_init() + * + *****************************************************************************/ +static void +gtk_knob_class_init (GtkKnobClass *klass) { + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + + parent_class = g_type_class_peek_parent(klass); + + object_class->destroy = gtk_knob_destroy; + + widget_class->realize = gtk_knob_realize; + widget_class->expose_event = gtk_knob_expose; + widget_class->size_request = gtk_knob_size_request; + widget_class->size_allocate = gtk_knob_size_allocate; + widget_class->scroll_event = gtk_knob_scroll; + widget_class->button_press_event = gtk_knob_button_press; + widget_class->button_release_event = gtk_knob_button_release; + widget_class->key_press_event = gtk_knob_key_press; + widget_class->motion_notify_event = gtk_knob_motion_notify; +} + + +/***************************************************************************** + * + * gtk_knob_init() + * + *****************************************************************************/ +static void +gtk_knob_init (GtkKnob *knob) { + knob->policy = GTK_UPDATE_CONTINUOUS; + knob->state = STATE_IDLE; + knob->saved_x = 0; + knob->saved_y = 0; + knob->timer = 0; + knob->anim = NULL; + knob->mask = NULL; + knob->mask_gc = NULL; + knob->red_gc = NULL; + knob->old_value = 0.0; + knob->old_lower = 0.0; + knob->old_upper = 0.0; + knob->adjustment = NULL; +} + + +/***************************************************************************** + * + * gtk_knob_new() + * + *****************************************************************************/ +GtkWidget * +gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim) { + GtkKnob *knob; + + g_return_val_if_fail (anim != NULL, NULL); + g_return_val_if_fail (GDK_IS_PIXBUF (anim->pixbuf), NULL); + + knob = g_object_new (gtk_knob_get_type (), NULL); + + gtk_knob_set_animation (knob, anim); + + if (!adjustment) { + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, + 0.0, 0.0, 0.0); + } + + gtk_knob_set_adjustment (knob, adjustment); + + return GTK_WIDGET (knob); +} + + +/***************************************************************************** + * + * gtk_knob_destroy() + * + *****************************************************************************/ +static void +gtk_knob_destroy(GtkObject *object) { + GtkKnob *knob; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_KNOB (object)); + + knob = GTK_KNOB (object); + + gtk_knob_set_adjustment (knob, NULL); + /* FIXME: needs ref counting for automatic GtkKnobAnim cleanup + if (knob->anim) { + gtk_knob_anim_unref (knob->anim); + knob->anim = NULL; + } + */ + + if (knob->mask) { + g_object_unref (knob->mask); + knob->mask = NULL; + } + + if (knob->mask_gc) { + g_object_unref (knob->mask_gc); + knob->mask_gc = NULL; + } + if (knob->red_gc) { + g_object_unref (knob->red_gc); + knob->red_gc = NULL; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) { + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); + } +} + + +/***************************************************************************** + * + * gtk_knob_get_adjustment() + * + *****************************************************************************/ +GtkAdjustment* +gtk_knob_get_adjustment(GtkKnob *knob) { + + g_return_val_if_fail (knob != NULL, NULL); + g_return_val_if_fail (GTK_IS_KNOB (knob), NULL); + + return knob->adjustment; +} + + +/***************************************************************************** + * + * gtk_knob_set_update_policy() + * + *****************************************************************************/ +void +gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy) { + + g_return_if_fail (knob != NULL); + g_return_if_fail (GTK_IS_KNOB (knob)); + + knob->policy = policy; +} + + +/***************************************************************************** + * + * gtk_knob_set_adjustment() + * + *****************************************************************************/ +void +gtk_knob_set_adjustment(GtkKnob *knob, GtkAdjustment *adjustment) { + + g_return_if_fail (knob != NULL); + g_return_if_fail (GTK_IS_KNOB (knob)); + + if (knob->adjustment) { + g_signal_handlers_disconnect_matched(knob->adjustment, + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + knob); + g_object_unref (knob->adjustment); + } + + knob->adjustment = adjustment; + if (adjustment) { + g_object_ref_sink (adjustment); + + g_signal_connect (adjustment, "changed", + G_CALLBACK(gtk_knob_adjustment_changed), + knob); + g_signal_connect (adjustment, "value_changed", + G_CALLBACK(gtk_knob_adjustment_value_changed), + knob); + + knob->old_value = adjustment->value; + knob->old_lower = adjustment->lower; + knob->old_upper = adjustment->upper; + + gtk_knob_update (knob); + } +} + + +/***************************************************************************** + * + * gtk_knob_realize() + * + *****************************************************************************/ +static void +gtk_knob_realize(GtkWidget *widget) { + GtkKnob *knob; + GdkWindowAttr attributes; + gint attributes_mask; + GdkColor color = { 0, 0xffff, 0, 0 }; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_KNOB (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + knob = GTK_KNOB (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = + gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, + &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (widget->window, widget); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + knob->mask_gc = gdk_gc_new (widget->window); + gdk_gc_copy (knob->mask_gc, widget->style->bg_gc[GTK_STATE_NORMAL]); + gdk_gc_set_clip_mask (knob->mask_gc, knob->mask); + + knob->red_gc = gdk_gc_new (widget->window); + gdk_gc_copy (knob->red_gc, widget->style->bg_gc[GTK_STATE_NORMAL]); + gdk_colormap_alloc_color (attributes.colormap, &color, FALSE, TRUE); + gdk_gc_set_foreground (knob->red_gc, &color); +} + + +/***************************************************************************** + * + * gtk_knob_size_request() + * + *****************************************************************************/ +static void +gtk_knob_size_request (GtkWidget *widget, GtkRequisition *requisition) { + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_KNOB (widget)); + + requisition->width = GTK_KNOB (widget)->width; + requisition->height = GTK_KNOB (widget)->height; +} + + +/***************************************************************************** + * + * gtk_knob_size_allocate() + * + *****************************************************************************/ +static void +gtk_knob_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { + GtkKnob *knob; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_KNOB (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + knob = GTK_KNOB (widget); + + if (GTK_WIDGET_REALIZED (widget)) { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + } +} + + +/***************************************************************************** + * + * gtk_knob_expose() + * + *****************************************************************************/ +static gint +gtk_knob_expose(GtkWidget *widget, GdkEventExpose *event) { + GtkKnob *knob; + gfloat dx, dy; + gint frames; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE); + + if (event->count > 0) + return FALSE; + + knob = GTK_KNOB (widget); + + frames = ((knob->anim->width / knob->anim->frame_width) - 1); + dx = knob->adjustment->value - knob->adjustment->lower; /* value, from 0 */ + dy = knob->adjustment->upper - knob->adjustment->lower; /* range */ + + dx = (int)(frames * dx / dy) * knob->width; /* check this for height != width */ + + gdk_draw_pixbuf (widget->window, knob->mask_gc, knob->anim->pixbuf, + dx, 0, 0, 0, knob->width, knob->height, + GDK_RGB_DITHER_NONE, 0, 0); + + if (GTK_WIDGET_HAS_FOCUS(widget)) { + gtk_paint_focus (widget->style, widget->window, widget->state, + NULL, widget, NULL, 0, 0, + widget->allocation.width, widget->allocation.height); + } + + return FALSE; +} + + +/***************************************************************************** + * + * gtk_knob_scroll() + * + *****************************************************************************/ +static gint +gtk_knob_scroll(GtkWidget *widget, GdkEventScroll *event) { + GtkKnob *knob; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE); + + knob = GTK_KNOB (widget); + + switch (event->direction) { + case GDK_SCROLL_UP: + knob->adjustment->value += knob->adjustment->step_increment; + g_signal_emit_by_name (knob->adjustment, "value_changed"); + break; + case GDK_SCROLL_DOWN: + knob->adjustment->value -= knob->adjustment->step_increment; + g_signal_emit_by_name (knob->adjustment, "value_changed"); + break; + default: + break; + } + + return FALSE; +} + + +/***************************************************************************** + * + * gtk_knob_button_press() + * + *****************************************************************************/ +static gint +gtk_knob_button_press(GtkWidget *widget, GdkEventButton *event) { + GtkKnob *knob; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE); + + knob = GTK_KNOB (widget); + + switch (knob->state) { + case STATE_IDLE: + switch (event->button) { + case 1: + case 3: + if (!GTK_WIDGET_HAS_FOCUS(widget)) + gtk_widget_grab_focus(widget); + knob->state = STATE_PRESSED; + knob->saved_x = event->x; + knob->saved_y = event->y; + break; + case 2: + knob->adjustment->value = floor ((knob->adjustment->lower + + knob->adjustment->upper + 1.0) + * 0.5); + g_signal_emit_by_name (knob->adjustment, "value_changed"); + break; + } + break; + } + + return FALSE; +} + + +/***************************************************************************** + * + * gtk_knob_button_release() + * + *****************************************************************************/ +static gint +gtk_knob_button_release(GtkWidget *widget, GdkEventButton *event) { + GtkKnob *knob; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE); + + knob = GTK_KNOB (widget); + + switch (knob->state) { + + case STATE_PRESSED: + knob->state = STATE_IDLE; + break; + + case STATE_DRAGGING: + knob->state = STATE_IDLE; + + switch (event->button) { + case 1: + case 3: + if (knob->policy != GTK_UPDATE_CONTINUOUS + && knob->old_value != knob->adjustment->value) + { + g_signal_emit_by_name (knob->adjustment, "value_changed"); + } + break; + } + + break; + } + + return FALSE; +} + +static gint gtk_knob_key_press(GtkWidget *widget, GdkEventKey *event) +{ + GtkKnob *knob; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE); + + knob = GTK_KNOB (widget); + + switch (event->keyval) { + + case GDK_Up: + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gtk_adjustment_set_value (knob->adjustment, + knob->old_value + knob->adjustment->step_increment); + return TRUE; + } + return FALSE; + + case GDK_Down: + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gtk_adjustment_set_value (knob->adjustment, + knob->old_value - knob->adjustment->step_increment); + return TRUE; + } + return FALSE; + default: + break; + } + + return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event); +} + +/***************************************************************************** + * + * gtk_knob_motion_notify() + * + *****************************************************************************/ +static gint +gtk_knob_motion_notify(GtkWidget *widget, GdkEventMotion *event) { + GtkKnob *knob; + GdkModifierType mods; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + knob = GTK_KNOB (widget); + + x = event->x; + y = event->y; + + if (event->is_hint || (event->window != widget->window)) { + gdk_window_get_pointer (widget->window, &x, &y, &mods); + } + + switch (knob->state) { + + case STATE_PRESSED: + knob->state = STATE_DRAGGING; + /* fall through */ + + case STATE_DRAGGING: + if (mods & GDK_BUTTON1_MASK) { + gtk_knob_update_mouse (knob, x, y, TRUE); + return TRUE; + } + else if (mods & GDK_BUTTON3_MASK) { + gtk_knob_update_mouse (knob, x, y, FALSE); + return TRUE; + } + break; + } + + return FALSE; +} + + +/***************************************************************************** + * + * gtk_knob_timer() + * + *****************************************************************************/ +static gint +gtk_knob_timer(GtkKnob *knob) { + + g_return_val_if_fail (knob != NULL, FALSE); + g_return_val_if_fail (GTK_IS_KNOB (knob), FALSE); + g_return_val_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment), FALSE); + + if (knob->policy == GTK_UPDATE_DELAYED) { + g_signal_emit_by_name (knob->adjustment, "value_changed"); + } + + /* don't keep running this timer */ + return FALSE; +} + + +/***************************************************************************** + * + * gtk_knob_update_mouse_update() + * + *****************************************************************************/ +static void +gtk_knob_update_mouse_update(GtkKnob *knob) { + g_return_if_fail(GTK_IS_ADJUSTMENT (knob->adjustment)); + + if (knob->policy == GTK_UPDATE_CONTINUOUS) { + g_signal_emit_by_name (knob->adjustment, "value_changed"); + } + else { + gtk_widget_queue_draw (GTK_WIDGET (knob)); + + if (knob->policy == GTK_UPDATE_DELAYED) { + if (knob->timer) { + g_source_remove (knob->timer); + } + knob->timer = g_timeout_add (SCROLL_DELAY_LENGTH, + (GSourceFunc) gtk_knob_timer, + (gpointer) knob); + } + } +} + + +/***************************************************************************** + * + * gtk_knob_update_mouse() + * + *****************************************************************************/ +static void +gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step) { + gfloat old_value, new_value, dv, dh; + gfloat angle; + + g_return_if_fail (knob != NULL); + g_return_if_fail (GTK_IS_KNOB (knob)); + g_return_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment)); + + old_value = knob->adjustment->value; + + angle = atan2f (-y + (knob->height >> 1), x - (knob->width >> 1)); + + /* inverted cartesian graphics coordinate system */ + dv = knob->saved_y - y; + dh = x - knob->saved_x; + knob->saved_x = x; + knob->saved_y = y; + + if ((x >= 0) && (x <= knob->width)) { + dh = 0; /* dead zone */ + } else { + angle = cosf (angle); + dh *= angle * angle; + } + + new_value = knob->adjustment->value + + dv * (step ? knob->adjustment->step_increment : knob->adjustment->page_increment) + + dh * (knob->adjustment->upper - + knob->adjustment->lower) * 0.005; /* 0.005 == (1 / 200) */ + + new_value = MAX (MIN (new_value, knob->adjustment->upper), + knob->adjustment->lower); + + knob->adjustment->value = new_value; + + if (knob->adjustment->value != old_value) { + gtk_knob_update_mouse_update (knob); + } +} + + +/***************************************************************************** + * + * gtk_knob_update() + * + *****************************************************************************/ +static void +gtk_knob_update(GtkKnob *knob) { + gfloat new_value; + + g_return_if_fail (knob != NULL); + g_return_if_fail (GTK_IS_KNOB (knob)); + g_return_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment)); + + if (knob->adjustment->step_increment == 1) { + new_value = floor (knob->adjustment->value + 0.5); + } + else { + new_value = knob->adjustment->value; + } + + if (new_value < knob->adjustment->lower) { + new_value = knob->adjustment->lower; + } + + if (new_value > knob->adjustment->upper) { + new_value = knob->adjustment->upper; + } + + if (new_value != knob->adjustment->value) { + knob->adjustment->value = new_value; + g_signal_emit_by_name (knob->adjustment, "value_changed"); + } + + gtk_widget_queue_draw (GTK_WIDGET (knob)); +} + + +/***************************************************************************** + * + * gtk_knob_adjustment_changed() + * + *****************************************************************************/ +static void +gtk_knob_adjustment_changed(GtkAdjustment *adjustment, gpointer data) { + GtkKnob *knob; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + knob = GTK_KNOB (data); + + if ((knob->old_value != adjustment->value) || + (knob->old_lower != adjustment->lower) || + (knob->old_upper != adjustment->upper)) + { + gtk_knob_update (knob); + + knob->old_value = adjustment->value; + knob->old_lower = adjustment->lower; + knob->old_upper = adjustment->upper; + } +} + + +/***************************************************************************** + * + * gtk_knob_adjustment_value_changed() + * + *****************************************************************************/ +static void +gtk_knob_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) { + GtkKnob *knob; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + knob = GTK_KNOB (data); + + if (knob->old_value != adjustment->value) { + gtk_knob_update (knob); + knob->old_value = adjustment->value; + } +} + + +/***************************************************************************** + * + * gtk_knob_set_animation() + * + *****************************************************************************/ +void +gtk_knob_set_animation (GtkKnob *knob, GtkKnobAnim *anim) { + g_return_if_fail (knob != NULL); + g_return_if_fail (anim != NULL); + g_return_if_fail (GTK_IS_KNOB (knob)); + g_return_if_fail (GDK_IS_PIXBUF (anim->pixbuf)); + + knob->anim = (GtkKnobAnim *)anim; + knob->width = anim->frame_width; + knob->height = anim->height; + + if (GTK_WIDGET_REALIZED (knob)) { + gtk_widget_queue_resize (GTK_WIDGET (knob)); + } +} + + +/***************************************************************************** + * + * gtk_knob_animation_new_from_file() + * + *****************************************************************************/ +GtkKnobAnim * +gtk_knob_animation_new_from_file(gchar *filename) { + GtkKnobAnim *anim; + + anim = gtk_knob_animation_new_from_file_full (filename, -1, -1, KNOB_SIZE); + return anim; +} + +/***************************************************************************** + * + * gtk_knob_animation_new_from_inline() + * + *****************************************************************************/ +GtkKnobAnim * +gtk_knob_animation_new_from_inline(const guint8 *pixbuf) { + GtkKnobAnim *anim = g_new0 (GtkKnobAnim, 1); + + g_return_val_if_fail((pixbuf != NULL), NULL); + + anim->pixbuf = gdk_pixbuf_new_from_inline(-1, pixbuf, FALSE, NULL); + if (anim->pixbuf == NULL) { + g_free(anim); + return NULL; + } + + anim->height = gdk_pixbuf_get_height (anim->pixbuf); + anim->width = gdk_pixbuf_get_width (anim->pixbuf); + anim->frame_width = anim->height; + + return anim; +} + +/***************************************************************************** + * + * gtk_knob_new_from_file_full() + * + * frame_width: overrides the frame width (to make rectangular frames) + * but doesn't affect the image size width and height cause optional + * scaling if not set to -1 when they are derived from the native + * image size. + * + * FIXME: account for any problems where (width % frame_width != 0) + * + *****************************************************************************/ +GtkKnobAnim * +gtk_knob_animation_new_from_file_full(gchar *filename, gint frame_width, + gint width, gint height) { + GtkKnobAnim *anim = g_new0 (GtkKnobAnim, 1); + + g_return_val_if_fail ((filename != NULL), NULL); + + GError *gerror = NULL; + +#if GTK_MINOR_VERSION < 10 + if (!(anim->pixbuf = gdk_pixbuf_new_from_file (filename, &gerror))) { + g_error_free(gerror); + gerror = NULL; + return NULL; + } +#else /* GTK_MINOR_VERSION >= 10 */ + if (!(anim->pixbuf = gdk_pixbuf_new_from_file_at_size (filename, width, + height, &gerror))) { + g_error_free(gerror); + gerror = NULL; + return NULL; + } +#endif /* GTK_MINOR_VERSION < 10 */ + else { + anim->height = gdk_pixbuf_get_height (anim->pixbuf); + anim->width = gdk_pixbuf_get_width (anim->pixbuf); + anim->frame_width = (frame_width != -1) ? frame_width : anim->height; + } + + return anim; +} + +/***************************************************************************** + * + * gtk_knob_animation_free() + * + *****************************************************************************/ +void +gtk_knob_animation_free(GtkKnobAnim *anim) { + g_return_if_fail (anim != NULL); + + if (anim->pixbuf) + g_object_unref (anim->pixbuf); + + g_free (anim); +} diff --git a/gtkknob.h b/gtkknob.h new file mode 100644 index 0000000..46643b8 --- /dev/null +++ b/gtkknob.h @@ -0,0 +1,102 @@ +/***************************************************************************** + * + * Most of this code comes from gAlan 0.2.0, copyright (C) 1999 + * Tony Garnock-Jones, with modifications by Sean Bolton, + * copyright (C) 2004, and minor modifications by William Weston, + * copyright (C) 2007, Tomasz Moń, copyright (C) 2009 + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *****************************************************************************/ +#ifndef __GTK_KNOB_H__ +#define __GTK_KNOB_H__ + +#include <gtk/gtk.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define GTK_KNOB(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_knob_get_type(), GtkKnob) +#define GTK_KNOB_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, gtk_knob_get_type(), GtkKnobClass) +#define GTK_IS_KNOB(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_knob_get_type()) + +typedef struct _GtkKnob GtkKnob; +typedef struct _GtkKnobClass GtkKnobClass; +typedef struct _GtkKnobAnim GtkKnobAnim; + + /* better to make this an object and let widgets ref/deref it perhaps */ + struct _GtkKnobAnim { + GdkPixbuf *pixbuf; + gint width; /* derived from image width */ + gint height; /* derived from image height. */ + gint frame_width; /* derived from pixbuf (width / height) or provided override for rectangular frames */ + }; + + struct _GtkKnob { + GtkWidget widget; + + /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */ + guint policy : 2; + + /* State of widget (to do with user interaction) */ + guint8 state; + gint saved_x, saved_y; + + /* ID of update timer, or 0 if none */ + guint32 timer; + + /* knob animation */ + GtkKnobAnim *anim; + gint width, height; + + GdkBitmap *mask; + GdkGC *mask_gc; + GdkGC *red_gc; + + /* Old values from adjustment stored so we know when something changes */ + gfloat old_value; + gfloat old_lower; + gfloat old_upper; + + /* The adjustment object that stores the data for this knob */ + GtkAdjustment *adjustment; + }; + + struct _GtkKnobClass { + GtkWidgetClass parent_class; + }; + + + extern GtkWidget *gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim); + extern GType gtk_knob_get_type(void); + extern GtkAdjustment *gtk_knob_get_adjustment(GtkKnob *knob); + extern void gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy); + extern void gtk_knob_set_adjustment(GtkKnob *knob, GtkAdjustment *adjustment); + + GtkKnobAnim *gtk_knob_animation_new_from_inline(const guint8 *pixbuf); + GtkKnobAnim *gtk_knob_animation_new_from_file_full(gchar *filename, + gint frame_width, + gint width, + gint height); + + GtkKnobAnim *gtk_knob_animation_new_from_file(gchar *filename); + void gtk_knob_set_animation (GtkKnob *knob, GtkKnobAnim *anim); + void gtk_knob_animation_free(GtkKnobAnim *anim); + +#ifdef __cplusplus +} +#endif + +#endif @@ -0,0 +1,1265 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#include <gtk/gtk.h> +#include <string.h> +#include "gdigi.h" +#include "gui.h" +#include "effects.h" +#include "preset.h" +#include "gtkknob.h" +#include "knob.h" + +typedef struct { + GtkObject *widget; + + /* used for combo boxes, if widget isn't combo box, then both value and x are -1 */ + gint value; /**< effect type value */ + gint x; /**< combo box item number */ +} WidgetTreeElem; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +static GtkKnobAnim *knob_anim = NULL; /* animation used by knobs */ +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ +static GTree *widget_tree = NULL; /**< this tree contains lists containing WidgetTreeElem data elements */ +static gboolean allow_send = FALSE; /**< if FALSE GUI parameter changes won't be sent to device */ + +/** + * \param parent transient parent, or NULL for none + * \param message error description + * + * Shows error message dialog. + **/ +void show_error_message(GtkWidget *parent, gchar *message) +{ + g_return_if_fail(message != NULL); + + GtkWidget *msg = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + message); + + gtk_dialog_run(GTK_DIALOG(msg)); + gtk_widget_destroy(msg); +} + +/** + * \param value value to examine + * \param values EffectValues to check value against + * + * Examines whether value fits inside values range for given EffectValues. + * + * \return TRUE is value fits inside range, otherwise FALSE. + **/ +static gboolean check_value_range(gint value, EffectValues *values) +{ + if (((gint) values->min <= value) && (value <= (gint) values->max)) + return TRUE; + else + return FALSE; +} + +/** + * \param spin a GtkSpinButton + * \param new_val return value for valid input + * \param values signal user data, EffectValues for this parameter + * + * Custom GtkSpinButton "input" handler for EffectValues with non plain type. + * + * \return TRUE if new_val was set, otherwise FALSE. + **/ +static gboolean custom_value_input_cb(GtkSpinButton *spin, gdouble *new_val, EffectValues *values) +{ + gchar *text = g_strdup(gtk_entry_get_text(GTK_ENTRY(spin))); + gchar *err = NULL; + gdouble value; + + for (;;) { + if (values->type & VALUE_TYPE_LABEL) { + /** search labels for value */ + gint n; + for (n = 0; values->labels[n] != NULL; n++) { + if (g_strcmp0(values->labels[n], text) == 0) { + /* Value found */ + *new_val = values->min + (gdouble)n; + g_free(text); + return TRUE; + } + } + + /* Value not found */ + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + continue; + } else { + g_free(text); + return FALSE; + } + } + + if (values->type & VALUE_TYPE_SUFFIX) { + /* remove suffix from entry text */ + gchar *tmp; + + tmp = strstr(text, values->suffix); + if (tmp != NULL) { + gchar *temp = g_strndup(text, tmp - text); + g_free(text); + text = temp; + } + } + + g_strstrip(text); + + value = g_strtod(text, &err); + if (*err) { + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + continue; + } else { + g_free(text); + return FALSE; + } + } + + if (values->type & VALUE_TYPE_STEP) { + value /= values->step; + } + + if (values->type & VALUE_TYPE_OFFSET) { + value -= values->offset; + } + + if (check_value_range((gint) value, values) == FALSE) { + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + continue; + } else { + g_free(text); + return FALSE; + } + } + + *new_val = value; + + g_free(text); + + return TRUE; + } +} + +/** + * \param spin a GtkSpinButton + * \param values signal user data, EffectValues for this parameter + * + * Custom GtkSpinButton "output" handler for EffectValues with non plain type. + * + * \return TRUE if text was set, otherwise FALSE. + **/ +static gboolean custom_value_output_cb(GtkSpinButton *spin, EffectValues *values) +{ + GtkAdjustment *adj; + gchar *text; + gdouble value; + + adj = gtk_spin_button_get_adjustment(spin); + value = gtk_adjustment_get_value(adj); + + while (check_value_range(value, values) == FALSE) { + if (values->type & VALUE_TYPE_EXTRA) { + values = values->extra; + } else { + g_message("custom_value_output_cb called with out of bounds value"); + return FALSE; + } + } + + if (values->type & VALUE_TYPE_LABEL) { + gtk_entry_set_text(GTK_ENTRY(spin), values->labels[(gint) value - (gint) values->min]); + return TRUE; + } + + if (values->type & VALUE_TYPE_OFFSET) { + value += (gdouble) values->offset; + } + + if (values->type & VALUE_TYPE_STEP) { + value *= values->step; + } + + if (values->type & VALUE_TYPE_DECIMAL) { + text = g_strdup_printf("%.*f", values->decimal, value); + } else { + text = g_strdup_printf("%d", (gint) value); + } + + if (values->type & VALUE_TYPE_SUFFIX) { + gchar *tmp; + tmp = g_strdup_printf("%s %s", text, values->suffix); + g_free(text); + text = tmp; + } + + gtk_entry_set_text(GTK_ENTRY(spin), text); + g_free(text); + + return TRUE; +} + +/** + * \param adj the object which emitted the signal + * \param setting setting controlled by adj + * + * Sets effect value. + **/ +void value_changed_option_cb(GtkAdjustment *adj, EffectSettings *setting) +{ + g_return_if_fail(setting != NULL); + + if (allow_send) { + gdouble val; + g_object_get(G_OBJECT(adj), "value", &val, NULL); + set_option(setting->id, setting->position, (gint)val); + } +} + +/** + * \param button the object which emitted the signal + * \param effect effect controlled by button + * + * Turns effect on/off basing on state of button. + **/ +void toggled_cb(GtkToggleButton *button, Effect *effect) +{ + g_return_if_fail(effect != NULL); + + if (allow_send) { + guint val = gtk_toggle_button_get_active(button); + set_option(effect->id, effect->position, val); + } +} + +/** + * \param widget GtkObject to add to widget tree + * \param id object controlled ID + * \param position object controlled position + * \param value effect value type (if widget is GtkComboBox, otherwise -1) + * \param x combo box item number (if widget is GtkComboBox, otherwise -1) + * + * Adds widget to widget tree. + **/ +static WidgetTreeElem *widget_tree_add(GtkObject *widget, gint id, gint position, gint value, gint x) +{ + GList *list; + WidgetTreeElem *el; + gpointer key; + + el = g_slice_new(WidgetTreeElem); + el->widget = widget; + el->value = value; + el->x = x; + + key = GINT_TO_POINTER((position << 16) | id); + + list = g_tree_lookup(widget_tree, key); + + if (list == NULL) { + list = g_list_append(list, el); + g_tree_insert(widget_tree, key, list); + } else { + list = g_list_append(list, el); + + /* replace the list pointer */ + g_tree_steal(widget_tree, key); + g_tree_insert(widget_tree, key, list); + } + + return el; +} + +/** + * \param el widget tree element + * \param param parameter to set + * + * Sets widget tree element value to param value. + **/ +static void apply_widget_setting(WidgetTreeElem *el, SettingParam *param) +{ + if (el->value == -1) { + if (GTK_IS_TOGGLE_BUTTON(el->widget)) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(el->widget), (param->value == 0) ? FALSE : TRUE); + else if (GTK_IS_ADJUSTMENT(el->widget)) + gtk_adjustment_set_value(GTK_ADJUSTMENT(el->widget), (gdouble)param->value); + } else { /* combo box */ + if (el->value == param->value) + gtk_combo_box_set_active(GTK_COMBO_BOX(el->widget), el->x); + } +} + +/** + * \param param SettingParam to apply to GUI + * + * Applies SettingParam to GUI + **/ +void apply_setting_param_to_gui(SettingParam *param) +{ + gpointer key; + g_return_if_fail(param != NULL); + + allow_send = FALSE; + key = GINT_TO_POINTER((param->position << 16) | param->id); + GList *list = g_tree_lookup(widget_tree, key); + g_list_foreach(list, (GFunc)apply_widget_setting, param); + allow_send = TRUE; +} + +/** + * \param preset preset to sync + * + * Synces GUI with preset. + **/ +static void apply_preset_to_gui(Preset *preset) +{ + g_return_if_fail(preset != NULL); + g_return_if_fail(widget_tree != NULL); + + allow_send = FALSE; + + GList *iter = preset->params; + while (iter) { + gpointer key; + + SettingParam *param = iter->data; + iter = iter->next; + + if (param != NULL) { + key = GINT_TO_POINTER((param->position << 16) | param->id); + GList *list = g_tree_lookup(widget_tree, key); + g_list_foreach(list, (GFunc)apply_widget_setting, param); + } + } + + allow_send = TRUE; +} + +/** + * Synces GUI with device current edit buffer. + **/ +static void apply_current_preset() +{ + GList *list = get_current_preset(); + Preset *preset = create_preset_from_data(list); + message_list_free(list); + apply_preset_to_gui(preset); + preset_free(preset); +} + +gboolean apply_current_preset_to_gui(gpointer data) +{ + apply_current_preset(); + return FALSE; +} + +/** + * \param settings effect parameters + * \param amt amount of effect parameters + * \param widget_table hash table matching settings pointer with created table (may be NULL) + * + * Creates knobs that allow user to set effect parameters. + * + * \return GtkTable containing necessary widgets to set effect parameters. + **/ +GtkWidget *create_table(EffectSettings *settings, gint amt, GHashTable *widget_table) +{ + GtkWidget *table, *label, *widget, *knob; + GtkObject *adj; + int x; + + if (widget_table != NULL) { + table = g_hash_table_lookup(widget_table, settings); + if (table != NULL) + return table; + } + + table = gtk_table_new(3, amt, FALSE); + + for (x = 0; x<amt; x++) { + gdouble min, max; + gboolean custom; + + get_values_info(settings[x].values, &min, &max, &custom); + + label = gtk_label_new(settings[x].label); + adj = gtk_adjustment_new(0.0, min, max, + 1.0, /* step increment */ + MAX((max / 100), 5.0), /* page increment */ + 0.0); + knob = gtk_knob_new(GTK_ADJUSTMENT(adj), knob_anim); + + widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0); + gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), FALSE); + gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(widget), GTK_UPDATE_IF_VALID); + if (custom == TRUE) { + g_signal_connect(G_OBJECT(widget), "input", G_CALLBACK(custom_value_input_cb), settings[x].values); + g_signal_connect(G_OBJECT(widget), "output", G_CALLBACK(custom_value_output_cb), settings[x].values); + } + + widget_tree_add(adj, settings[x].id, settings[x].position, -1, -1); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2); + gtk_table_attach(GTK_TABLE(table), knob, 1, 2, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2); + gtk_table_attach(GTK_TABLE(table), widget, 2, 3, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2); + + g_signal_connect(G_OBJECT(adj), "value-changed", G_CALLBACK(value_changed_option_cb), &settings[x]); + + if (widget_table != NULL) { + g_hash_table_insert(widget_table, settings, table); + } + } + + return table; +} + +/** + * \param effect Effect that can be turned on/off + * + * Creates toggle button that allow user to turn effect on/off. + * + * \return GtkToggleButton + **/ +GtkWidget *create_on_off_button(Effect *effect) +{ + GtkWidget *button; + if (effect->label == NULL) + button = gtk_check_button_new(); + else + button = gtk_check_button_new_with_label(effect->label); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); + g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggled_cb), effect); + widget_tree_add(GTK_OBJECT(button), effect->id, effect->position, -1, -1); + return button; +} + +typedef struct { + gint type; /**< effect group type (value) */ + gint id; /**< option ID */ + gint position; /**< position */ + GtkWidget *child; /**< child widget */ +} EffectSettingsGroup; + +/** + * \param group group to be freed + * + * Frees all memory used by group + **/ +void effect_settings_group_free(EffectSettingsGroup *group) +{ + if (group->child != NULL) { + /* destroy widget without parent */ + if (gtk_widget_get_parent(group->child) == NULL) + gtk_widget_destroy(group->child); + + g_object_unref(group->child); + } + + g_slice_free(EffectSettingsGroup, group); +} + +/** + * \param widget the object which emitted the signal + * \param data user data (unused, can be anything) + * + * Switches effect type and shows widgets allowing to set selected effect type parameters. + **/ +void combo_box_changed_cb(GtkComboBox *widget, gpointer data) +{ + GtkWidget *child; + GtkWidget *vbox; + EffectSettingsGroup *settings = NULL; + gchar *name = NULL; + gint x; + g_object_get(G_OBJECT(widget), "active", &x, NULL); + + vbox = g_object_get_data(G_OBJECT(widget), "vbox"); + + if (x != -1) { + name = g_strdup_printf("SettingsGroup%d", x); + settings = g_object_get_data(G_OBJECT(widget), name); + g_free(name); + + if (settings != NULL && allow_send) + set_option(settings->id, settings->position, settings->type); + + child = g_object_get_data(G_OBJECT(widget), "active_child"); + if (child == settings->child) { + return; + } + + if (child != NULL) { + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(gtk_widget_get_parent(vbox))), child); + } + + if (settings->child != NULL) { + gtk_container_add(GTK_CONTAINER(gtk_widget_get_parent(gtk_widget_get_parent(vbox))), settings->child); + gtk_widget_show_all(gtk_widget_get_parent(gtk_widget_get_parent(vbox))); + } + g_object_set_data(G_OBJECT(widget), "active_child", settings->child); + } +} + +/** + * \param group Effect type groups + * \param amt amount of effect groups + * \param id ID to set effect type + * \param position position + * + * Creates widget allowing user to choose effect type. + * + * \return widget that allow user to set effect type. + **/ +GtkWidget *create_widget_container(EffectGroup *group, gint amt, gint id, gint position) +{ + GtkWidget *vbox; + GtkWidget *widget; + GtkWidget *combo_box = NULL; + GHashTable *widget_table; + EffectSettingsGroup *settings = NULL; + gchar *name = NULL; + gint x; + gint cmbox_no = -1; + + vbox = gtk_vbox_new(FALSE, 0); + + widget_table = g_hash_table_new(g_direct_hash, g_direct_equal); + + for (x = 0; x<amt; x++) { + if (group[x].label) { + if (combo_box == NULL) { + combo_box = gtk_combo_box_new_text(); + gtk_container_add(GTK_CONTAINER(vbox), combo_box); + g_signal_connect(G_OBJECT(combo_box), "changed", G_CALLBACK(combo_box_changed_cb), group); + g_object_set_data(G_OBJECT(combo_box), "vbox", vbox); + } + gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), group[x].label); + cmbox_no++; + + if ((group[x].settings != NULL) && (group[x].settings_amt > 0)) { + widget = create_table(group[x].settings, group[x].settings_amt, widget_table); + g_object_ref_sink(widget); + } else + widget = NULL; + + settings = g_slice_new(EffectSettingsGroup); + settings->id = id; + settings->type = group[x].type; + settings->position = position; + settings->child = widget; + + widget_tree_add(GTK_OBJECT(combo_box), id, position, group[x].type, x); + + name = g_strdup_printf("SettingsGroup%d", cmbox_no); + g_object_set_data_full(G_OBJECT(combo_box), name, settings, ((GDestroyNotify)effect_settings_group_free)); + g_free(name); + } else { + if ((group[x].settings != NULL) && (group[x].settings_amt > 0)) { + widget = create_table(group[x].settings, group[x].settings_amt, widget_table); + gtk_container_add(GTK_CONTAINER(vbox), widget); + } + } + } + + g_hash_table_destroy(widget_table); + + return vbox; +} + +/** + * \param widgets Effect descriptions + * \param amt amount of effect descriptions + * \param label frame label (can be NULL) + * + * Creates frame (with optional label) containing widgets allowing user to set effect options. + * + * \return widget that allow user to set effect options. + **/ +GtkWidget *create_vbox(Effect *widgets, gint amt, gchar *label) +{ + GtkWidget *vbox; + GtkWidget *widget; + GtkWidget *table; + GtkWidget *container; + GtkWidget *frame; + int x; + int y; + + frame = gtk_frame_new(label); + + vbox = gtk_vbox_new(FALSE, 0); + + table = gtk_table_new(2, amt, FALSE); + gtk_table_set_col_spacings(GTK_TABLE(table), 2); + + for (x = 0; x<amt; x++) { + if ((widgets[x].id != -1) && (widgets[x].position != -1)) { + widget = create_on_off_button(&widgets[x]); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1); + + if (widgets[x].label) + y = 1; + else + y = 0; + + } else if (widgets[x].label) { + widget = gtk_label_new(widgets[x].label); + gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1); + y = 0; + } else { + /* Default to 1 */ + if (x == 0) + y = 1; + } + + container = create_widget_container(widgets[x].group, widgets[x].group_amt, widgets[x].type, widgets[x].position); + gtk_table_attach_defaults(GTK_TABLE(table), container, 1-y, 2-y, x+y, x+y+1); + } + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 2); + + gtk_container_add(GTK_CONTAINER(frame), vbox); + return frame; +} + +enum { + PRESET_NAME_COLUMN = 0, + PRESET_NUMBER_COLUMN, + PRESET_BANK_COLUMN, + NUM_COLUMNS +}; + +/** + * \param treeview the object which emitted the signal + * \param path the GtkTreePath for the activated row + * \param column the GtkTreeViewColumn in which the activation occurred + * \param model model holding preset names + * + * Sets active device preset to preset selected by user. + **/ +void row_activate_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GtkTreeModel *model) { + GtkTreeIter iter; + gint id; + gint bank; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, PRESET_NUMBER_COLUMN, &id, PRESET_BANK_COLUMN, &bank, -1); + + if ((bank != -1) && (id != -1)) { + switch_preset(bank, id); + apply_current_preset(); + } +} + +/** + * \param model model to fill + * \param bank preset bank + * \param name preset bank description visible to user + * + * Appends to model preset names found in device preset bank. + **/ +static void fill_store_with_presets(GtkTreeStore *model, guint bank, gchar *name) +{ + GtkTreeIter iter; + GtkTreeIter child_iter; + int x; + + GStrv presets = query_preset_names(bank); + g_return_if_fail(presets != NULL); + + gtk_tree_store_append(model, &iter, NULL); + gtk_tree_store_set(model, &iter, + PRESET_NAME_COLUMN, name, + PRESET_NUMBER_COLUMN, -1, + PRESET_BANK_COLUMN, -1, + -1); + + for (x=0; x<g_strv_length(presets); x++) { + gchar *tmp = g_strdup_printf("%d - %s", x+1, presets[x]); + + gtk_tree_store_append(model, &child_iter, &iter); + gtk_tree_store_set(model, &child_iter, + PRESET_NAME_COLUMN, tmp, + PRESET_NUMBER_COLUMN, x, + PRESET_BANK_COLUMN, bank, + -1); + + g_free(tmp); + } + g_strfreev(presets); +} + +/** + * \param model model to fill + * + * Fills model with preset names found on device. + **/ +static void fill_store(GtkTreeStore *model) +{ + Device *device = g_object_get_data(G_OBJECT(model), "device"); + + g_return_if_fail(device != NULL); + + gint i; + for (i=0; i<device->n_banks; i++) + fill_store_with_presets(model, + device->banks[i].bank, + device->banks[i].name); +} + +/** + * \param device device information + * + * Creates treeview showing list of presets available on device. + * + * \return treeview containing all preset names found on device. + **/ +GtkWidget *create_preset_tree(Device *device) +{ + GtkWidget *treeview; + GtkTreeStore *store; + GtkCellRenderer *renderer; + + store = gtk_tree_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); + g_object_set_data(G_OBJECT(store), "device", device); + fill_store(store); + + treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(store); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview), + -1, "Preset name", + renderer, "text", + PRESET_NAME_COLUMN, NULL); + + g_object_set(G_OBJECT(treeview), "headers-visible", FALSE, NULL); + g_signal_connect(G_OBJECT(treeview), "realize", G_CALLBACK(gtk_tree_view_expand_all), NULL); + g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(row_activate_cb), GTK_TREE_MODEL(store)); + + return treeview; +} + +/** + * \param window application toplevel window + * \param default_name default preset name + * + * Shows window allowing user to store current edit buffer. + **/ +static void show_store_preset_window(GtkWidget *window, gchar *default_name) +{ + GtkWidget *dialog, *cmbox, *entry, *table, *label, *vbox; + GStrv names; + int x; + + dialog = gtk_dialog_new_with_buttons("Store preset", + GTK_WINDOW(window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL); + + vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + + table = gtk_table_new(2, 2, FALSE); + gtk_container_add(GTK_CONTAINER(vbox), table); + + cmbox = gtk_combo_box_new_text(); + names = query_preset_names(PRESETS_USER); + for (x=0; x<g_strv_length(names); x++) { + gchar *title = g_strdup_printf("%d - %s", x+1, names[x]); + gtk_combo_box_append_text(GTK_COMBO_BOX(cmbox), title); + g_free(title); + } + g_strfreev(names); + gtk_table_attach_defaults(GTK_TABLE(table), cmbox, 1, 2, 0, 1); + + entry = gtk_entry_new(); + if (default_name != NULL) + gtk_entry_set_text(GTK_ENTRY(entry), default_name); + gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2); + + label = gtk_label_new("Preset slot:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + + label = gtk_label_new("Preset name:"); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + + gtk_widget_show_all(vbox); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + gint number = gtk_combo_box_get_active(GTK_COMBO_BOX(cmbox)); + if (number != -1) { + store_preset_name(number, gtk_entry_get_text(GTK_ENTRY(entry))); + } + } + + gtk_widget_destroy(dialog); +} + +/** + * \param action the object which emitted the signal + * + * Shows store preset window. + **/ +static void action_store_cb(GtkAction *action) +{ + GtkWidget *window = g_object_get_data(G_OBJECT(action), "window"); + show_store_preset_window(window, NULL); +} + +/** + * \param action the object which emitted the signal + * + * Shows about dialog. + **/ +static void action_show_about_dialog_cb(GtkAction *action) +{ + static const gchar * const authors[] = { + "Tomasz Moń <desowin@gmail.com>", + NULL + }; + static const gchar copyright[] = "Copyright \xc2\xa9 2009 Tomasz Moń"; + static const gchar website[] = "http://desowin.org/gdigi/"; + + GtkWidget *window = g_object_get_data(G_OBJECT(action), "window"); + + gtk_show_about_dialog(GTK_WINDOW(window), + "authors", authors, + "copyright", copyright, + "website", website, + NULL); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +typedef struct { + gchar *name; + gchar *suffix; +} SupportedFileTypes; + +static SupportedFileTypes file_types[] = { + {"RP155Preset", "*.rp155p"}, + {"RP250Preset", "*.rp250p"}, + {"RP255Preset", "*.rp255p"}, + {"RP355Preset", "*.rp355p"}, + {"RP500Preset", "*.rp500p"}, + {"RP1000Preset", "*.rp1000p"}, + {"GNX4 Preset", "*.g4p"}, + {"GNX3kPreset", "*.g3kp"}, +}; + +static guint n_file_types = G_N_ELEMENTS(file_types); + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * \param action the object which emitted the signal + * + * Shows file chooser dialog. + * If user opens valid preset file, the preset gets applied to edit buffer and store preset window is shown. + **/ +static void action_open_preset_cb(GtkAction *action) +{ + static GtkWidget *dialog = NULL; + + if (dialog != NULL) + return; + + GtkWidget *window = g_object_get_data(G_OBJECT(action), "window"); + + dialog = gtk_file_chooser_dialog_new("Open Preset", GTK_WINDOW(window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + GtkFileFilter *filter; + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, "All Supported Types"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + + int x; + for (x=0; x<n_file_types; x++) { + GtkFileFilter *current_filter = gtk_file_filter_new(); + + gtk_file_filter_set_name(current_filter, file_types[x].name); + gtk_file_filter_add_pattern(current_filter, file_types[x].suffix); + gtk_file_filter_add_pattern(filter, file_types[x].suffix); + + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), current_filter); + } + + gboolean loaded = FALSE; + while (!loaded && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + GError *error = NULL; + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + Preset *preset = create_preset_from_xml_file(filename, &error); + if (error) { + show_error_message(window, error->message); + g_error_free(error); + error = NULL; + } else if (preset != NULL) { + apply_preset_to_gui(preset); + + gtk_widget_hide(dialog); + + GString *start = g_string_new(NULL); + g_string_append_printf(start, + "%c%c%s%c%c%c", + PRESETS_EDIT_BUFFER, 0, + preset->name, 0 /* NULL terminated string */, + 0 /* modified */, + /* messages to follow */ + preset->genetxs ? 10 : 2); + + send_message(RECEIVE_PRESET_START, start->str, start->len); + send_preset_parameters(preset->params); + if (preset->genetxs != NULL) { + gint i; + + /* GNX4 sends messages in following order: + * Section Bank Index + * 0x00 0x04 0x0000 + * 0x00 0x04 0x0001 + * 0x01 0x04 0x0000 + * 0x01 0x04 0x0001 + * 0x00 0x04 0x0002 + * 0x00 0x04 0x0003 + * 0x01 0x04 0x0002 + * 0x01 0x04 0x0003 + */ + + /* GNX3000 sends messages in following order: + * Section Bank Index + * 0x07 0x04 0x0000 + * 0x07 0x04 0x0001 + * 0x08 0x04 0x0000 + * 0x08 0x04 0x0001 + * 0x07 0x04 0x0002 + * 0x07 0x04 0x0003 + * 0x08 0x04 0x0002 + * 0x08 0x04 0x0003 + */ + for (i = 0; i < 2; i++) { + GList *iter = preset->genetxs; + + while (iter) { + SectionID section; + guint bank, index; + + SettingGenetx *genetx = (SettingGenetx *) iter->data; + iter = iter->next; + + section = get_genetx_section_id(genetx->version, + genetx->type); + bank = 0x04; + + if (i == 0) { + index = genetx->channel; + } else { + if (genetx->channel == GENETX_CHANNEL1) { + index = GENETX_CHANNEL1_CUSTOM; + } else if (genetx->channel == GENETX_CHANNEL2) { + index = GENETX_CHANNEL2_CUSTOM; + } + } + + send_object(section, bank, index, + genetx->name, genetx->data); + } + } + } + send_message(RECEIVE_PRESET_END, NULL, 0); + + show_store_preset_window(window, preset->name); + + g_string_free(start, TRUE); + preset_free(preset); + loaded = TRUE; + } + g_free(filename); + } + + gtk_widget_destroy(dialog); + dialog = NULL; +} + +/** + * \param list widget tree list to be freed + * + * Frees all memory used by widget tree list. + */ +static void widget_tree_elem_free(GList *list) +{ + GList *iter; + for (iter = list; iter; iter = iter->next) { + g_slice_free(WidgetTreeElem, iter->data); + } + g_list_free(list); +} + +/** + * \param action the object which emitted the signal + * + * Destroys action object "window" data, then stops gtk main loop. + **/ +static void action_quit_cb(GtkAction *action) +{ + GtkWidget *window = g_object_get_data(G_OBJECT(action), "window"); + + gtk_widget_destroy(window); + gtk_main_quit(); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +static GtkActionEntry entries[] = { + {"File", NULL, "_File"}, + {"Preset", NULL, "_Preset"}, + {"Help", NULL, "_Help"}, + {"Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open preset file", G_CALLBACK(action_open_preset_cb)}, + {"Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q", "Quit", G_CALLBACK(action_quit_cb)}, + {"Store", NULL, "_Store", "<control>S", "Store", G_CALLBACK(action_store_cb)}, + {"About", GTK_STOCK_ABOUT, "_About", "<control>A", "About", G_CALLBACK(action_show_about_dialog_cb)}, +}; +static guint n_entries = G_N_ELEMENTS(entries); + +static const gchar *menu_info = +"<ui>" +" <menubar name='MenuBar'>" +" <menu action='File'>" +" <menuitem action='Open'/>" +" <separator/>" +" <menuitem action='Quit'/>" +" </menu>" +" <menu action='Preset'>" +" <menuitem action='Store'/>" +" </menu>" +" <menu action='Help'>" +" <menuitem action='About'/>" +" </menu>" +" </menubar>" +"</ui>"; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * \param ui GtkUIManager to lookup actions + * \param path path to action + * \param window toplevel window + * + * Sets action object "window" data to toplevel window. + **/ +static void add_action_data(GtkUIManager *ui, const gchar *path, GtkWidget *window) +{ + GtkAction *action; + + action = gtk_ui_manager_get_action(ui, path); + g_return_if_fail(action != NULL); + + g_object_set_data(G_OBJECT(action), "window", window); +} + +/** + * \param window toplevel window + * \param vbox vbox to hold menubar + * + * Creates menubar (adds accel group to toplevel window as well) and packs it into vbox. + **/ +static void add_menubar(GtkWidget *window, GtkWidget *vbox) +{ + GtkUIManager *ui; + GtkActionGroup *actions; + GError *error = NULL; + + actions = gtk_action_group_new("Actions"); + gtk_action_group_add_actions(actions, entries, n_entries, NULL); + + ui = gtk_ui_manager_new(); + gtk_ui_manager_insert_action_group(ui, actions, 0); + g_object_unref(actions); + gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui)); + + if (!gtk_ui_manager_add_ui_from_string(ui, menu_info, -1, &error)) { + g_message("building menus failed: %s", error->message); + g_error_free(error); + error = NULL; + } + gtk_box_pack_start(GTK_BOX(vbox), + gtk_ui_manager_get_widget(ui, "/MenuBar"), + FALSE, FALSE, 0); + + add_action_data(ui, "/MenuBar/File/Quit", window); + add_action_data(ui, "/MenuBar/File/Open", window); + add_action_data(ui, "/MenuBar/Preset/Store", window); + add_action_data(ui, "/MenuBar/Help/About", window); + + g_object_unref(ui); +} + +static gint widget_tree_key_compare_func(gconstpointer a, gconstpointer b, gpointer data) +{ + gint position_a = GPOINTER_TO_INT(a) & 0xFF0000; + gint position_b = GPOINTER_TO_INT(b) & 0xFF0000; + + if (position_a > position_b) { + return 1; + } else if (position_a == position_b) { + gint val_a = GPOINTER_TO_INT(a) & 0xFFFF; + gint val_b = GPOINTER_TO_INT(b) & 0xFFFF; + return val_a - val_b; + } else + return -1; +} + +/** + * Creates main window. + **/ +void gui_create(Device *device) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *widget; + GtkWidget *notebook; + GtkWidget *sw; /* scrolled window to carry preset treeview */ + gint x; + gint i; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "gdigi"); + + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox); + + add_menubar(window, vbox); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(vbox), hbox); + + sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX(hbox), sw, FALSE, FALSE, 0); + + widget = create_preset_tree(device); + gtk_container_add(GTK_CONTAINER(sw), widget); + + notebook = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 2); + + knob_anim = gtk_knob_animation_new_from_inline(knob_pixbuf); + + widget_tree = g_tree_new_full(widget_tree_key_compare_func, + NULL, /* key compare data */ + NULL, /* key destroy func */ + (GDestroyNotify) widget_tree_elem_free); + + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), device->n_pages > 1 ? TRUE : FALSE); + + for (i = 0; i<device->n_pages; i++) { + GtkWidget *label = NULL; + vbox = gtk_vbox_new(FALSE, 0); + label = gtk_label_new(device->pages[i].name); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); + + for (x = 0; x<device->pages[i].n_effects; x++) { + if ((x % ((device->pages[i].n_effects+1)/device->pages[i].n_rows)) == 0) { + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2); + } + widget = create_vbox(device->pages[i].effects[x].effect, device->pages[i].effects[x].amt, device->pages[i].effects[x].label); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2); + } + } + + apply_current_preset(); + gtk_widget_show_all(window); + + g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL); +} + +/** + * Frees memory allocated by gui_create which is not explicitly freed when main window is destroyed. + **/ +void gui_free() +{ + g_tree_destroy(widget_tree); + widget_tree = NULL; + + gtk_knob_animation_free(knob_anim); + knob_anim = NULL; +} + +/** + * \param device Variable to hold device information + * + * Displays dialogbox stating that device is unsupported. + * + * \return TRUE if user selects "compability mode", otherwise FALSE. + **/ +gboolean unsupported_device_dialog(Device **device) +{ + extern Device* supported_devices[]; + extern int n_supported_devices; + + GtkWidget *dialog; + GtkWidget *label; + GtkWidget *combo_box; + GtkWidget *vbox; + int x; + + dialog = gtk_dialog_new_with_buttons("Unsupported device", + NULL, GTK_DIALOG_MODAL, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL); + + vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + + label = gtk_label_new("Your device appears to be unsupported by gdigi.\n" + "As some of the settings may be common between different devices,\n" + "you can now select compability mode with one of the supported devices.\n" + "Please take a look at gdigi's HACKING file."); + gtk_container_add(GTK_CONTAINER(vbox), label); + + combo_box = gtk_combo_box_new_text(); + for (x=0; x<n_supported_devices; x++) { + gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), supported_devices[x]->name); + } + + gtk_container_add(GTK_CONTAINER(vbox), combo_box); + + gtk_widget_show_all(vbox); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + gint number = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box)); + if (number != -1 && number <n_supported_devices) { + g_message("Starting %s compability mode", supported_devices[number]->name); + *device = supported_devices[number]; + gtk_widget_destroy(dialog); + return TRUE; + } + } + + gtk_widget_destroy(dialog); + return FALSE; +} @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#ifndef GDIGI_GUI_H +#define GDIGI_GUI_H + +#include <glib.h> +#include "effects.h" + +void show_error_message(GtkWidget *parent, gchar *message); +void apply_setting_param_to_gui(SettingParam *param); +gboolean apply_current_preset_to_gui(gpointer data); +void gui_create(Device *device); +void gui_free(); +gboolean unsupported_device_dialog(Device **device); + +#endif /* GDIGI_GUI_H */ diff --git a/knob.png b/knob.png Binary files differnew file mode 100644 index 0000000..3290361 --- /dev/null +++ b/knob.png diff --git a/preset.c b/preset.c new file mode 100644 index 0000000..839f635 --- /dev/null +++ b/preset.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#include <gio/gio.h> +#include <expat.h> +#include <string.h> +#include "preset.h" +#include "gdigi.h" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +enum { + PARSER_TYPE_NOT_SET = -1, + PARSER_TYPE_PRESET_NAME = 0, + PARSER_TYPE_PARAM_ID, + PARSER_TYPE_PARAM_POSITION, + PARSER_TYPE_PARAM_VALUE, + PARSER_TYPE_PARAM_NAME, + PARSER_TYPE_PARAM_TEXT, + PARSER_TYPE_GENETX_VERSION, + PARSER_TYPE_GENETX_TYPE, + PARSER_TYPE_GENETX_CHANNEL, + PARSER_TYPE_GENETX_NAME, + PARSER_TYPE_GENETX_DATA +}; + +enum { + SECTION_NOT_SET = -1, + SECTION_PARAMS, + SECTION_GENETX +}; + +typedef struct { + int depth; + int id; + int section; + Preset *preset; +} AppData; + +static void XMLCALL start(void *data, const char *el, const char **attr) { + AppData *ad = (AppData *) data; + + ad->id = PARSER_TYPE_NOT_SET; + if (g_strcmp0(el, "Name") == 0) { + if (ad->depth == 1) { + ad->id = PARSER_TYPE_PRESET_NAME; + } else if (ad->depth == 3) { + if (ad->section == SECTION_PARAMS) { + ad->id = PARSER_TYPE_PARAM_NAME; + } else if (ad->section == SECTION_GENETX) { + ad->id = PARSER_TYPE_GENETX_NAME; + } + } + } + + if (g_strcmp0(el, "Params") == 0) { + ad->section = SECTION_PARAMS; + if (ad->preset->params != NULL) + g_message("Params aleady exists!"); + } else if (g_strcmp0(el, "Param") == 0) { + SettingParam *param = setting_param_new(); + ad->preset->params = g_list_prepend(ad->preset->params, param); + } else if (g_strcmp0(el, "ID") == 0) { + ad->id = PARSER_TYPE_PARAM_ID; + } else if (g_strcmp0(el, "Position") == 0) { + ad->id = PARSER_TYPE_PARAM_POSITION; + } else if (g_strcmp0(el, "Value") == 0) { + ad->id = PARSER_TYPE_PARAM_VALUE; + } else if (g_strcmp0(el, "Text") == 0) { + ad->id = PARSER_TYPE_PARAM_TEXT; + } else if (g_strcmp0(el, "Genetx") == 0) { + ad->section = SECTION_GENETX; + if (ad->preset->genetxs != NULL) + g_message("Genetx already exists!"); + } else if (g_strcmp0(el, "GenetxModel") == 0) { + SettingGenetx *genetx = setting_genetx_new(); + ad->preset->genetxs = g_list_prepend(ad->preset->genetxs, genetx); + } else if (g_strcmp0(el, "Version") == 0) { + ad->id = PARSER_TYPE_GENETX_VERSION; + } else if (g_strcmp0(el, "Type") == 0) { + ad->id = PARSER_TYPE_GENETX_TYPE; + } else if (g_strcmp0(el, "Channel") == 0) { + ad->id = PARSER_TYPE_GENETX_CHANNEL; + } else if (g_strcmp0(el, "Data") == 0) { + ad->id = PARSER_TYPE_GENETX_DATA; + } + + ad->depth++; +} + +static void XMLCALL end(void *data, const char *el) { + AppData *ad = (AppData *) data; + ad->depth--; + ad->id = PARSER_TYPE_NOT_SET; +} + +static void XMLCALL text_cb(void *data, const char* text, int len) +{ + AppData *ad = (AppData *) data; + + if ((ad == NULL) || (ad->preset == NULL)) + return; + + if (ad->id == PARSER_TYPE_PRESET_NAME) { + if (ad->preset->name != NULL) + g_free(ad->preset->name); + ad->preset->name = g_strndup(text, len); + } + + if (ad->section == SECTION_PARAMS) { + if (ad->preset->params == NULL) + return; + + SettingParam *param = (SettingParam *) ad->preset->params->data; + if (param == NULL) + return; + + gchar *value = g_strndup(text, len); + + switch (ad->id) { + case PARSER_TYPE_PARAM_ID: + param->id = atoi(value); + break; + case PARSER_TYPE_PARAM_POSITION: + param->position = atoi(value); + break; + case PARSER_TYPE_PARAM_VALUE: + param->value = atoi(value); + break; + } + + g_free(value); + } else if (ad->section == SECTION_GENETX) { + if (ad->preset->genetxs == NULL) + return; + + SettingGenetx *genetx = (SettingGenetx *) ad->preset->genetxs->data; + if (genetx == NULL) + return; + + gchar *value = g_strndup(text, len); + + switch (ad->id) { + case PARSER_TYPE_GENETX_VERSION: + if (g_strcmp0(value, "Version1") == 0) { + genetx->version = GENETX_VERSION_1; + } else if (g_strcmp0(value, "Version2") == 0) { + genetx->version = GENETX_VERSION_2; + } else { + g_message("Unknown GeNetX version: %s", value); + } + break; + case PARSER_TYPE_GENETX_TYPE: + if (g_strcmp0(value, "Amp") == 0) { + genetx->type = GENETX_TYPE_AMP; + } else if (g_strcmp0(value, "Cabinet") == 0) { + genetx->type = GENETX_TYPE_CABINET; + } else { + g_message("Unknown GeNetX type: %s", value); + } + break; + case PARSER_TYPE_GENETX_CHANNEL: + if (g_strcmp0(value, "Channel1") == 0) { + genetx->channel = GENETX_CHANNEL1; + } else if (g_strcmp0(value, "Channel2") == 0) { + genetx->channel = GENETX_CHANNEL2; + } else { + g_message("Unknown GeNetX channel: %s", value); + } + break; + case PARSER_TYPE_GENETX_NAME: + /* reassign pointer */ + genetx->name = value; + value = NULL; + break; + case PARSER_TYPE_GENETX_DATA: + { + guchar *data = NULL; + gsize length = 0; + + data = g_base64_decode(value, &length); + genetx->data = g_string_new_len((gchar *) data, length); + + g_free(data); + break; + } + } + + g_free(value); + } +} + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * \param filename valid path to file + * \param error return location for an error + * + * Tries to open file pointed by path, then parses it. + * + * \return Preset which must be freed using preset_free, or NULL on error. + **/ +Preset *create_preset_from_xml_file(gchar *filename, GError **error) +{ + GError *err = NULL; + gchar *contents; + + if (g_file_get_contents(filename, &contents, NULL, &err) == FALSE) { + g_message("Failed to get %s contents: %s", filename, err->message); + *error = g_error_copy(err); + g_error_free(err); + return NULL; + } + + AppData *ad = g_slice_new(AppData); + ad->depth = 0; + ad->preset = g_slice_new(Preset); + ad->preset->name = NULL; + ad->preset->params = NULL; + ad->preset->genetxs = NULL; + ad->id = PARSER_TYPE_NOT_SET; + + XML_Parser p; + p = XML_ParserCreate(NULL); + XML_SetUserData(p, (void *) ad); + XML_SetElementHandler(p, start, end); + XML_SetCharacterDataHandler(p, text_cb); + + if (XML_Parse(p, contents, strlen(contents), XML_TRUE) != XML_STATUS_OK) { + g_set_error(error, 0, 0, "Parse error at line %d:\n%s", + (int)XML_GetCurrentLineNumber(p), + XML_ErrorString(XML_GetErrorCode(p))); + preset_free(ad->preset); + g_slice_free(AppData, ad); + g_free(contents); + return NULL; + } + + Preset *preset = ad->preset; + preset->params = g_list_reverse(preset->params); + preset->genetxs = g_list_reverse(preset->genetxs); + + XML_ParserFree(p); + g_slice_free(AppData, ad); + + g_free(contents); + return preset; +} + +/** + * \param list list containing unpacked preset SysEx messages. + * + * Parses message + * + * \return Preset which must be freed using preset_free, or NULL on error. + **/ +Preset *create_preset_from_data(GList *list) +{ + GString *data; + GList *iter; + gint total, n, x; + gint bank, number, modified; + gchar *name; + + g_return_val_if_fail(list != NULL, NULL); + + Preset *preset = g_slice_new(Preset); + preset->name = NULL; + preset->params = NULL; + preset->genetxs = NULL; + + iter = list; + for (iter = list; iter; iter = g_list_next(iter)) { + data = (GString*) iter->data; + switch (get_message_id(data)) { + case RECEIVE_PRESET_START: + bank = (unsigned char)data->str[8]; + number = (unsigned char)data->str[9]; + name = g_strdup(&data->str[10]); + modified = (unsigned char)data->str[11+strlen(name)]; + + if ((bank == PRESETS_EDIT_BUFFER) && (number == 0)) { + g_message("Received current edit buffer"); + } else { + g_message("Received preset %d from bank %d", number, bank); + } + + g_message("Modified flag: %d Name: %s", modified, name); + preset->name = name; + break; + case RECEIVE_PRESET_PARAMETERS: + x = 0x09; + n = 0; + total = (unsigned char)data->str[x]; + x++; + + do { + SettingParam *param = setting_param_new_from_data(&data->str[x], &x); + n++; + preset->params = g_list_prepend(preset->params, param); + g_message("%d ID %d Position %d Value %d", n, param->id, param->position, param->value); + } while ((x < data->len) && n<total); + g_message("TOTAL %d", total); + preset->params = g_list_reverse(preset->params); + break; + case RECEIVE_PRESET_END: + break; + default: + g_message("Unhandled message in preset messages list"); + } + } + + return preset; +} + +/** + * \param preset preset to be freed + * + * Frees all memory used by preset. + **/ +void preset_free(Preset *preset) +{ + g_return_if_fail(preset != NULL); + + if (preset->params != NULL) { + GList *iter; + for (iter = preset->params; iter; iter = iter->next) { + setting_param_free((SettingParam*)iter->data); + } + g_list_free(preset->params); + } + + if (preset->genetxs != NULL) { + GList *iter; + for (iter = preset->genetxs; iter; iter = iter->next) { + setting_genetx_free((SettingGenetx*)iter->data); + } + g_list_free(preset->genetxs); + } + + g_free(preset->name); + + g_slice_free(Preset, preset); +} diff --git a/preset.h b/preset.h new file mode 100644 index 0000000..95d92d7 --- /dev/null +++ b/preset.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2009 Tomasz Moń <desowin@gmail.com> + * + * 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; under version 3 of the License. + * + * 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 <http://www.gnu.org/licenses>. + */ + +#ifndef GDIGI_PRESET_H +#define GDIGI_PRESET_H + +#include <glib.h> + +typedef struct { + gchar *name; + GList *params; + GList *genetxs; +} Preset; + +Preset *create_preset_from_xml_file(gchar *filename, GError **error); +Preset *create_preset_from_data(GList *list); +void preset_free(Preset *preset); + +#endif /* GDIGI_PRESET_H */ |