giada-0.11.2/000077500000000000000000000000001264622563000126465ustar00rootroot00000000000000giada-0.11.2/.travis.yml000066400000000000000000000027521264622563000147650ustar00rootroot00000000000000sudo: required dist: trusty language: cpp compiler: gcc notifications: email: recipients: - giadaloopmachine@gmail.com on_success: never on_failure: always before_install: - sudo apt-get update -qq - sudo apt-get install -y libsndfile1-dev libsamplerate0-dev libfltk1.3-dev libasound2-dev libxpm-dev libpulse-dev libjack-dev before_script: # Download and build latest version of RtMidi - wget http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-2.1.0.tar.gz - tar -xvf rtmidi-2.1.0.tar.gz - cd rtmidi-2.1.0 && ./configure --with-jack --with-alsa && make && sudo make install || true - cd .. # Download and install latest version of Jansson - wget http://www.digip.org/jansson/releases/jansson-2.7.tar.gz - tar -xvf jansson-2.7.tar.gz - cd jansson-2.7 && ./configure && make && sudo make install || true - sudo ldconfig - cd .. # Download wav file for testing purposes - wget http://download.wavetlan.com/SVV/Media/HTTP/WAV/Media-Convert/Media-Convert_test3_PCM_Stereo_VBR_16SS_11025Hz.wav -O test.wav # Download midimaps package for testing purposes - wget https://github.com/monocasual/giada-midimaps/archive/master.zip -O giada-midimaps-master.zip - unzip giada-midimaps-master.zip - mkdir -p $HOME/.giada/midimaps - cp giada-midimaps-master/midimaps/* $HOME/.giada/midimaps # Build Giada - ./autogen.sh - ./configure --target=linux --enable-vst script: make && make check after_failure: cat $TRAVIS_BUILD_DIR/test-suite.log giada-0.11.2/COPYING000066400000000000000000001045131264622563000137050ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . giada-0.11.2/ChangeLog000066400000000000000000000742521264622563000144320ustar00rootroot00000000000000 -------------------------------------------------------------------------------- Giada - Your Hardcore Loopmachine. Developed by Monocasual Laboratories www.giadamusic.com CHANGELOG -------------------------------------------------------------------------------- 0.11.2 --- 2016 . 01 . 16 - New JSON-based midimap files - Add new channel by right-clicking anywhere on a column - Show warning if patch is using the deprecated file format - Do not force 32 bit compilation on OS X - Fix warnings and errors on GCC 5.3 - Fix a bug that prevented MIDI Jack from being selected on Linux 0.11.1 --- 2015 . 12 . 22 - Ability to clone channels - New JSON-based configuration file - Port all vectors from old gVector to std::vector - Deactivate all other MIDI fields when changing MIDI system in Config window - Minor optimizations in configuration panel, Audio tab - Assume 'none' as default sound system - Include Catch header file in source package - Update Travis CI environment to Ubuntu Trusty - Fix missing sanitization after reading configuration file - Fix garbage text in device info window - Fix wrong config value if no midimaps are available - Fix garbage text while printing device and port names 0.11.0 --- 2015 . 12 . 02 - New JSON-based patch system - Properly store column width in patch - Port all const char* strings to std::string in patch/project glue layer - Switch to SemVer-like internal versioning system - More source code reorganization - Fix potential memory leaks in Mixer - Fix missing static link of RtMidi on Linux - Unable to store pitch values > 2.0 (fixed) - Missing assigned key after opening patch (fixed) 0.10.2 --- 2015 . 10 . 21 - Setup Travis CI automated builds - Add base framework for unit testing (with Catch) - Improve behavior of Loop Once family when the sequencer is halted - Fix empty sample path in sample channels when saving a Project - Fix disabled "edit actions" for sample channels - Fix missing pthreadGC2.dll in Windows build 0.10.1 --- 2015 . 08 . 26 - Massive source folders refactoring - Improved usability of "play" buttons for channels - Remove support for patches created with Giada < 0.6.x - Fix check for configured soundsystem (would break compilation on g++5) - Small fixes and cleanup in Makefile.am 0.10.0 --- 2015 . 07 . 05 - MIDI lightning output - Other minor fixes 0.9.6 --- 2015 . 05 . 11 - Keyboard binding for MIDI channels - Support for multiple files in drag-n-drop operations - Different color for wait/end statuses - Small improvements to Keyboard grabber widget - Fix random crashes with Jack enabled - Fix weird behavior with multiple drag and drop - Code refactoring 0.9.5 --- 2015 . 03 . 28 - Better column resize algorithm - New patch loading system with permanent MIDI mapping - Ability to clear assigned keys (keyboard mode) - Improved zoom icons in editors - Fix deprecation warning in configure.ac 0.9.4 --- 2015 . 02 . 24 - Drag-n-drop now works also in existing channels - Store 'resize recordings' flag in giada.conf - Better management of duplicate samples - Add more VST debug information - Minor fixes and tweaks 0.9.3 --- 2015 . 02 . 01 - New GUI improvement: responsive and resizable columns - Upgrade to FLTK 1.3.3 - More robust column handling mechanism - Support for MIDI devices without note-off message (@blablack) - Fix segfaults when saving a patch with missing plugins - Fix many minor graphical bugs - Fix wrong vector assignment in MIDI send event - Fix reloaded patches with no right tempo/beats displayed - Fix random odd frames when adding/moving events in Piano Roll - Minor internal cleanup 0.9.2 --- 2014 . 11 . 29 - New grid layout in Sample Editor - Load samples via drag n drop - Add new utility functions: gTrim and gStripFileUrl - Fix "normalize" button position in Sample Editor - Minor waveform drawing optimizations - Add missing files for RtAudio-mod compilation - All one-shot mode, if fired manually, get the first frame truncated (fixed) 0.9.1 --- 2014 . 09 . 24 - Bring back custom version of rtAudio in source package - Automatically turn up volume when adding new channel - Updated 'misc' tab in configuration panel - Fix startup crash on OS X - Fix missing jack headers 0.9.0 --- 2014 . 08 . 18 - New full-screen GUI - Multi-column support - Advanced logging system - Upgrade to RtAudio 4.1.1 and RtMidi 2.1.0 - Removed embedded RtAudio (thanks to Arty) - Fix wrong processing of VST MIDI events on 64 bit version - Fix stretched buttons when resizing sample editor window - "Clear all samples" destroys channels (fixed) - "Free channel" messes up loop / mute buttons (fixes) - Fix potential recordings with odd frames 0.8.4 --- 2014 . 03 . 27 - New mode 'Loop Bar Once' - Several small improvements and cleanups to internal utils functions - Fixed missing title in several subwindows - (win) Fix runtime error when loading a new project - Fix chan reset when clicking on waveform - Properly close subwindows after a channel has been deleted - Fix 'reload' button not working for samples with updated names 0.8.3 --- 2014 . 02 . 14 - Experimental MIDI timing output with MTC and MIDI clock - Expose Sequencer x2 and /2 via MIDI - New pitch operators x2 and /2 - Internal xfade process restored - "set key..." becomes "setup keyboard input" for sample channels - MIDI events are now saved as unsigned int in patch - Same expression on both sides of '|' in recorder.cpp (fixed) - Muted channels leak some glitches on 'kill' event (fixed) - Piano roll can't be edited anymore if beats == 32 (fixed) - Noise when adding new MIDI channel (fixed) - Boost and Normalize not working (fixed) - Multiple copies of every file used by the patch (fixed) - Samples with -1, -2, ... -n suffix are not included in patch (fixed) - Segfaults when quantizing samples (fixed) 0.8.2 --- 2014 . 01 . 13 - Pitch control exposed via MIDI - New tools in Sample Editor (linear fade in/out, smooth edges) - Implemented vstEvent->deltaFrames, gaining more precision with vst MIDI events - Add Fl::lock/Fl::unlock dynamics to glue_ calls where needed - Avoid pitch sliding when changing pitch of a sample in status OFF - Update copyright info in source files - Internal fade in and fade out restored - Add 'Giada' keyword to desktop file - Fix annoying glitches when playing very short samples - Fix random crashes when controlling giada via MIDI - Fix missing MIDI mapping for read-actions button 0.8.1 --- 2013 . 12 . 09 - New, high-quality pitch control based on libsamplerate - New set of functions 'spread sample to beat/song' [known issues] - Internal crossfades have been temporarily disabled. Some clicks may occur 0.8.0 --- 2013 . 11 . 03 - Initial MIDI input support - Fix freeze when recording audio inputs on a second channel - Fix 'R' button to show up even if the channel has no actions - Fix weird drawings of keypress actions in action editor - Free channel: delete 'R' button as well - Shift+key does not kill loop mode channels in a wait status - Fix issue with 'R' button and newly added actions - Remove "left"/"right" labels from main buttons 0.7.3 --- 2013 . 09 . 14 - Experimental 64 bit compilation (Linux only) - Massive internal cleanup of channel/gui channel layers - Set default mode to full volume on sample load - Set default mode to oneshot basic - Faster drawings in piano roll - Visual aids in piano roll - Scroll to pointer in piano roll - Several minor improvements in piano roll's usability - Revised VST Carbon window popup system - Minor improvements in startInputRec/stopInputRec procedure - Fix compile error using local type Plugin* in Channel's constructor - Fix segfault in OSX when working with VST windows 0.7.2 --- 2013 . 07 . 27 - Initial MIDI output support - Mute now affects channels with VSTi signals - Lots of deb package improvements - Complete rewrite of VST GUI part on OS X - Don't send MIDI mute on sample channels - Send MIDI mute for MIDI channels in play mode - Fix wrong looping due to VST processing in mixer::masterPlay - Fix jack crashes when using Giada with ALSA - Fix VST random crashes on OSX, bus error - Fix input device set to -1 after a system change 0.7.1 --- 2013 . 06 . 27 - Initial Jack Transport support - Send global note off when sequencer is being stopped - Send note off when deleting notes in Piano Roll - Store position and size of Piano Roll in conf file - Avoid overlap MIDI notes in Piano Roll - MIDI channel refactoring - MIDI channels now behave like loop-mode ones - Fix graphical bugs in Action Editor, sample mode - Fix refresh issue in Piano Roll when deleting items - Lots of invisible cleanups and improvements 0.7.0 --- 2013 . 06 . 05 - Initial MIDI output implementation - Initial VSTi (instrument) support - New piano roll widget in action editor - New chan mode: MIDI vs SAMPLE - Fix E-MU Tracker Pre not correctly listed in audio in/output 0.6.4 --- 2013 . 05 . 07 - Resizable plugin parameter window - New and standard package name format -. - Implement RtAudio::getCompiledApi() to fetch compiled APIs - Implement audioMasterGetSampleRate, audioMasterGetLanguage VST opcodes - Add drop-down menu for buffer size values in config panel - Enhance project portability between OSes - Lots of fixes and improvements for VST strings and parameters - Avoid segfault when loading recs from a patch with files not found - Always remember selected program when shifting up/down plugins - Fix wrong size of single_press displayed in action editor - Fix volume actions resized with value set to zero - Fix volume envelope always over the cover area - Fix src package extracts to current dir - Fix segfault in loadpatch process if plugin GUIs are open - Fix segfault when closing patch with plugins in BAD status 0.6.3 --- 2013 . 04 . 23 - New 'solo' button - Portable project system - New 'Single Endless' channel mode - GUI enhancements for channels in WAIT or ENDING status - Minor fixes & cleanups 0.6.2 --- 2013 . 04 . 05 - New volume envelope widget - Zoom with mouse wheel in the action editor - Graphical enhancements & speedups for the action editor - Loop-repeat doesn't stop when put in ending mode (fixed) - Fix draw errors when zooming too much the action editor - Set silence in wave editor messes up the waveform (fixed) - Wrong slashes in file path when saving a patch in Windows (fixed) - Many, many code improvements and bugs fixed 0.6.1 --- 2013 . 03 . 21 - Unlimited number of channels - Deep internal refactoring, mixer/GUI layers - Fix random crashes on exit - Fix crashes when closing Giada with VST windows opened - Always free Master In plugin stack on exit - Lots of other minor bugs fixed and small enhancements 0.6.0 --- 2013 . 03 . 02 - New, full-screen, redesigned sample editor - Zoom with mouse wheel in sample editor - Use kernelAudio::defaultIn/defaultOut for DEFAULT_SOUNDDEV_OUT - Volume knob in main window now updates the editor - Sound system issues in OS X (fixed) - Output device info dialog refers to wrong device (fixed) 0.5.8 --- 2013 . 02 . 07 - Internal samplerate conversion (with libsamplerate) - Bring channels automatically to full volume on sample load - Ability to set the audio device frequency - New "internal mute" feature - fix for deprecated VST opcode 14 - fix deb package issues on Ubuntu 12.10 / KXStudio 0.5.7 --- 2013 . 01 . 21 - visual grid + snapping in the action editor - implement more audioMasterCanDo's in pluginHost - limit zoom in actionEditor - revise zoom behavior in actionEditor, now more comfortable - fix forward declaration & inclusion of several headers - implemented VST opcode 32 - implemented VST opcode 33 - implemented VST opcode 34 - update website link in tar files - update copyright info for 2013 0.5.6 --- 2013 . 01 . 03 - New overdub mode for live recording - Support for VST programs, aka presets - Lots of VST opcodes implemented - Fix crash when removing a plugin from the stack - Fix pops when going to beat 0 - Fix compilation issues without --enable-vst - Many invisible optimizations and small bugs fixed 0.5.5 --- 2012 . 12 . 15 - "Hear what you're playing" feature - Fx processing on the input side - Ability to add different action types (Action Editor) - Desktop integration on Linux (via deb package) - Upgrade to FLTK 1.3.2 - Remove "the action might stop the channel" when loading new samples - Fix wrong positioning of zoom tools (Action Editor) - Fix unwanted interactions on the grey area (Action Editor) - Fix wrong memory alloc during the VST processing - VST don't show up in OS X (fixed) - Minor internal refactoring + bugfixing 0.5.4 --- 2012 . 11 . 24 - VST GUI support - Better subwindow management - Implemented many other VST opcodes - Missing plugins are now shown in the list with a 'dead' state - Refresh action editor when changing beats (via beat operator or beat window) - Graphical improvements in the action editor - Resizable action editor doesn't work well (fixed) - Fix auto fadeout for SINGLE_PRESS channels - Fix compilation without --enable-vst - Fix for a wrong prototype definition of the VST hostCallback 0.5.3 --- 2012 . 10 . 26 - Live beat manipulators (x2)(/2) - New sub-windows management, faster and more comfortable - New optional hard limiter on the output side - Action Editor window recalls x,y,w,h zoom and position - Usability improvements while handling an action (action editor) - Refresh actionEditor window when switching channel mode or delete actions - Unable to delete a killchan action (action editor) (fixed) - Don't show ACTION_KILLCHAN in a singlepress channel (action editor) - Libsndfile no longer statically linked in Linux - Fixed a typo in config: "when the sequeCer is halted" - redefinition of DEFAULT_PITCH in wingdi.h (windows) (fixed) - Upgrade to FLTK 1.3.0 - Other internal optimizations - Other small bugs fixed 0.5.2 --- 2012 . 10 . 05 - Add ability to handle actions for loop-mode channels - Add ability to record live mute actions for loop-mode channels - Lots of live action recording improvements - Enhanced usability for the action editor - More verbose output if kernel audio fails to start - Several internal optimizations 0.5.1 --- 2012 . 09 . 13 - First implementation of the Action Editor - Added compatibility with Ubuntu >= 10.04 0.5.0 --- 2012 . 07 . 23 - New custom project folder (.gprj) - Sample names are now made unique - Fixed unwanted time stretching while exporting a mono sample - Lots of minor internal improvements 0.4.12 --- 2012 . 07 . 01 - VST parameters and stacks are now stored in patch file - Upgrade to RtAudio 0.4.11 - PulseAudio support in Linux (thanks to RtAudio 0.4.11) - Revised .deb package - Enhanced "normalize" function in wave editor - Several memory issues fixed - Internal enhancements and minor bugs fixed 0.4.11 --- 2012 . 06 . 10 - VST stack for each channel - Custom paths for plugins, samples and patches - Crash in config panel if device is busy (fixed) - Graphical bug in the input meter (fixed) - ParamLabel added in the VST parameter list 0.4.10 --- 2012 . 05 . 30 - Ability to shift up an down VST plugins - Enhanced patch/conf architecture - Ability to edit a sample while playing - Mutex controls in VST processing - Lots of security issues fixed while changing pitch dinamically - Enhanced sub-window system - Several minor bugs fixed 0.4.9 --- 2012 . 05 . 12 - No more mandatory inputs - Pitch value properly stored inside the patch - Several small VST host improvements - Enhanced window management - Ability to browse files while playing with main GUI (non-modal browser) - Improved error checking in KernelAudio - Wrong style for lower scrollbar in Browser (fixed) - Fixed compilation on 64 bit systems (thanks to Speps@Archlinux) - Samplerate no longer hardcoded, auto-detected with JACK - Minor internal improvements and bugfixing 0.4.8 --- 2012 . 04 . 21 - Initial VST support (experimental) - Pitch controller (experimental, no filtering) - OSX bundles are now correctly handled by the file browser - Fixed several memory leaks - Minor internal improvements 0.4.7 --- 2012 . 03 . 31 - Cut, trim & silence operations in sample editor - New "Reload sample" button added - Lots of optimizations in the waveform drawing routines - The sample is no longer editable while in play mode - Fixed potential startup crashes while using Giada with Jack Audio - Other minor fixes applied to the configuration panel - Fixed compilation on 64 bit systems (thanks to Speps@Archlinux) 0.4.6 --- 2012 . 03 . 11 - New device information panel - The device configuration now shows only active and available devices - Channel panel no longer pops up during a recording process - GUI beautifications and other minor graphical fixes - Program icon added in all subwindows - Action records no longer available during a take, and vice versa - Fixed a serious bug that swapped input and output devices - Fixed loop behavior in ending mode - Fixed clicks when stopping a muted channel in loop 0.4.5 --- 2012 . 02 . 25 - Complete GUI redesign - New "start/stop action recs" button - Lots of internal cleanups and micro refactorings - Small drawing glithes in Editor and status box (fixed) - An invalid patch puts Giada to init state (fixed) - Fixed button repeat on start/stop, action rec, input rec - Checks against takes with unique name - Message "this action may stop the channel" always shown (fixed) - Channel no longer freeable while a take is in progress 0.4.4 --- 2012 . 02 . 04 - New input/output channel selector - Rewind bypasses the quantizer if triggered via mouse (fixed) - Fixed library paths in configure and makefile (thanks to Yann C.) - Added AUTHORS and NEWS files to the source package (thanks to Yann C.) - More robust sample export procedure - Issues with mute buttons when opening a patch (fixed) - Several usability improvements - Minor code cleanups and optimizations 0.4.3 --- 2012 . 01 . 21 - New "save project" feature - Ability to export a single sample to disk - More feedback when removing/clearing actions and samples - Sequencer starts automatically when action-rec button is pressed - Alert if patch name is empty while saving it - Channels now store internally the name of the samples - Missing "--no devices found--" in input devices menu (fixed) - Alert added if there are no empty channels for recording - "Edit->Clear all actions" no longer works (fixed) - END button could be used as a channel trigger (fixed) - Recorders are available even if device status is wrong (fixed) - Missing sample rewind if channel is muted (fixed) - Quantizer doesn't work if framesize is odd (fixed) - Random segfault when closing Giada (fixed) - Lots of code cleanups - Other minor improvements and optimizations 0.4.2 --- 2012 . 01 . 09 - Live sampling from external input with meter and delay compensation - Check against uneven values and overflow in buffersize field - Wrong normalized values if volume level is 0.0 (fixed) - Boost dial goes crazy if normalized > 20.0 dB (fixed) - Boost dial goes crazy if normalized < 0.0 dB (fixed) - Unwanted noise click if a muted channel is being rewinded (fixed) - Mute doesn't work well for single-shot samples (fixed) - Wrong FLTK headers (fixed, thanks to Yann C.) - Moving chanStart/chanEnd swaps stereo image (fixed) - Reset to init state doesn't reset mute buttons (fixed) - Wrong chanStart value if > 0 (fixed) 0.4.1 --- 2011 . 12 . 07 - Complete mixer engine refactoring - Faster audio buffer allocation - Global beat system revisited - Autocrossfade between samples is now enabled by default - No more recorded actions on odd frames - Unintentional channel swapping fixed - Unable to list all sound systems and sound devs under OSX (fixed) - Missing graceful stop of audio streaming under OSX (fixed) 0.4.0 --- 2011 . 11 . 16 - Support for all major uncompressed file formats (with libsndfile) - Enhanced mono > stereo conversion - Fixed drawing issues for the start/stop labels inside the waveform - Enhanced backward compatibility with old patches - Support for compilation on OS X and Windows 0.3.6 --- 2011 . 11 . 02 - Initial Mac OS X release - (Windows) Ability to list and browse all active drives - Change some internal routines plus minor optimizations - Added -pedantic and -Werror flag to the compiler - Crash if clicking on mute in an empty channel (fixed) - Chan status changes if an empty channel is being muted (fixed) 0.3.5 --- 2011 . 10 . 22 - Pan controller added - New GNU-style source code packaging - Revamped .deb package - Program icon missing under Windows (fixed) - Crash if a sample in patch is missing from the filesystem (fixed) - Unable to rewind to beat 1 if quantizer is on and seq stopped (fixed) - Several minor glitches fixed 0.3.4 --- 2011 . 10 . 10 - Full source code released under GPL license - Autosmooth is now toggleable via setup - Faster loading process of patch files - Various internal cleanups and optimizations - Fixed incorrect reading of boost values from patch - Fixed a potential bug that prevented the config panel to appear - Fixed stereo swap bug - Minor graphical revisions 0.3.3 --- 2011 . 09 . 28 - New "normalize" function - More editing tools added inside the sample editor - Waveform beautifications - Fixed interaction bugs for boost and volume controls 0.3.2 --- 2011 . 09 . 19 - New "mute" button inside the main window - Waveform is now updated when the boost value changes - Zoomin/zoomout relative to the scrollbar position - Fixed garbage output if the volume was "-inf" (windows version) - Fixed several rendering issues for short waveforms 0.3.1 --- 2011 . 09 . 12 - Boost volume + fine volume control in sample editor - Start/End handles inside the editor are now draggable via mouse - Fixed scrollbar issues in sample editor - Start/end points are now always drawn in the foreground - Waveform no longer overflow if a value is greater than the window - (linux) giada.conf is saved inside the hidden folder /home/.giada - patch loading process is now faster and cleaner - Update to rtAudio 4.0.10 0.3.0 --- 2011 . 09 . 01 - New sample editor window - Ability to set start/end points within a sample - Update to rtAudio 4.0.9 - Fixed an string overflow inside a patch - Fixed a missing memory free if a sample is unreadable - Several internal updates and optimizations 0.2.7 --- 2011 . 07. 22 - New way to handle recorded channels as loops - Fixed retrig for backspace key (rewind) - Enhanced rewind with quantization support - Main and alert windows now appear centered on screen - Sanity check against old patches without metronome information - Rewind now affects loops in rec-reading mode 0.2.6 --- 2011 . 07 . 11 - Internal metronome - Fixed some glitches in config panel - Minor cleanups 0.2.5 --- 2011 . 06 . 20 - Configuration panel redesign - Several new control options - Progress feedback when loading patches - Internal optimizations - Updated docs 0.2.4 --- 2011 . 06 . 08 - New loop repeat mode - Ability to save patches anywhere in the filesystem - Sub-beat management - Sound meter has been revisited and improved - Several patch enhancements - Core audio optimizations 0.2.3 --- 2011 . 05 . 18 - ASIO support for Windows version - Enhanced security when reading values from a patch - Ability to disable the recordings when the sequencer is paused - Master volume and rec status are now saved inside the patch - Device selection fixed and improved - Sequencer flickering in Windows has been fixed - Feedback added if a sample from a patch is unreadable or corrupted - Minor internal optimizations 0.2.2 --- 2011 . 05 . 04 - New open-source patch system - A patch can now be loaded from any location of the filesystem - Enhanced file browser coords system - Lots of minor improvements to the sample loading/unloading procedure - (win) Init path of file browser now starts from %userProfile%/Desktop - Wrong handling of "/" chars fixed in config menu - Fixed potential hangs on quit - Fixed clicks when stopping sequencer/sample - Minor gui beautifications 0.2.1 --- 2011 . 04 . 26 - Windows version 0.2.0 --- 2011 . 04 . 19 - Full JACK and ALSA support with RtAudio - New list of sound devices in menu window - Enhanced shutdown procedure to prevent potential crashes - Some GUI glitches fixed - Fixed random locks when the screensaver is active 0.1.8 --- 2011 . 04 . 13 - new functions: free al samples/recordings, reset to init patch - main menu redesign - the file browser is now resizable - GUI feedback for samples in play mode - some fixes when unloading a sample 0.1.7 --- 2011 . 04 . 07 - Ability to remove only action recordings or mute recordings - Shift+key now stops the sample if the master play is deactivated - Frame 0 was always processed at the end of the sequencer - Minor internal improvements 0.1.6 --- 2011 . 03 . 29 - Autocrossfade to prevent clicks - Internal improvements and bugfixing 0.1.5 --- 2011 . 03 . 10 - decimal bpm adjustment - ability to shrink/expand actions when changing the global beats - improved GUI for beats and bpm controllers - improved routines for action management - actions are now updated when you change bpm 0.1.4 --- 2011 . 03 . 04 - ability to save recorded actions - status box now shows if a recorded chan is deactivated - recorder is reset correctly when you load a new patch - minor improvements 0.1.3 --- 2011 . 02 . 26 - action recorder (first implementation) - quantization procedure slightly optimized - minor graphical adjustments - expanded documentation 0.1.2 --- 2011 . 02 . 08 - master volume controller - improved sound meter with more accuracy - improved verifications when reading or writing a patch - beat counter is now always reset to 1 after a patch is loaded - made loading wave files more robust, plus memory optimizations - minor crashes fixed 0.1.1 --- 2011 . 01 . 26 - expansion to 32 channels - GUI restyling - live quantizer - fixed wrong handling of "mute" value when loading a patch - minor internal improvements 0.1.0 --- 2011 . 01 . 18 - ability to mute channels - stop and rewind buttons now affect only channels in loop mode - undo for ending loops - internal patch improvements to provide backward compatibility - better behaviour when exceeding the total amount of available memory - fixed random reversals of stereo field at the end of the beat bar - fixed a potential segmentation fault when freeing a sample 0.0.12 --- 2011 . 01 . 11 - ability to free a channel - "stop" button to suspend the general program - new "stop-to-end" mode for looped channels - new "full stop" key combination - enhanced mouse interaction - minor bugfixing 0.0.11 --- 2010 . 12 . 28 - customizable keys - GUI layer optimizations and improvements - overwrite confirmation when saving a patch - the browser always displays the patch folder when loading a new patch - browser url is now read-only to prevent manipulations 0.0.10 --- 2010 . 12 . 16 - new "single-mode retrig" mode added - expansion to 16 channels - new advanced file browser with the ability to navigate the filesystem - audio configuration now uses the "default" device, if not changed - graphical restyling for audio channels - fixed a random crash on startup, due to a wrong thread synch 0.0.9 --- 2010 . 12 . 08 - new loop once mode - new graphical beat meter - rewind-program button added - heavy buttons and controls restyling - reinforced header verification when a new patch is opened for reading - some bugfixing for the loading procedure of a patch - fixed a potential crash while a new sample is being loaded 0.0.8 --- 2010 . 11 . 28 - fixed a critical crash while loading a sample - GUI warning when loading a sample or a patch into an active channel - little optimization during the search for data into waves - all popup windows are now modal (always on top) - fixed a potential crash in case of malformed wave files 0.0.7 --- 2010 . 11 . 18 - new peak meter with clip warning and system status report - any "ok" button is associated to the "return" key (for fast inputs) - graphical improvements for checkboxes, buttons, smaller fonts in browsers - graphical feedback for missing samples - internal optimizations 0.0.6 --- 2010 . 11 . 01 - new 32 bit floating point audio engine - support for any wave bit-rate, from 8 bit pcm to 32 float - Giada now prompts when a sound card error occurs - removed the hard-limiting system, now useless - the "save patch" panel now shows the actual patchname in use - alphabetic sort into the file browser - fixed an annoying gui flickering - patch volume information are now handled correctly - minor internal optimizations - fixed a memory leak when loading a new patch - other memory optimizations 0.0.5 --- 2010 . 10 . 21 - Patch-based system: load/save your setup from/to a binary file - New audio configuration panel - New configuration file (giada.conf) where to store data - Complete implementation of the double click startup - Fixed a bug related to the confirm-on-quit window - Minor GUI beautifications - Extended documentation 0.0.4 --- 2010 . 10 . 11 - New internal sample-accurate loop engine - Ability to configure the period size through ini file - First implementation of the double click startup - Debug information are now properly tagged, reporting the interested layer 0.0.3 --- 2010 . 10 . 02 - (giada) New official logo - (giada) Ability to load single-channel samples - (giada) Capital letter consistency between GUI buttons - (giada) Added "cancel" button to the browser window - (giada) Endianness verification - (giada) Cleanup of the audio initialization procedure - (giada) Several internal optimization for audio playback - (giada) ALSA layer now tells if an underrun occurs - (giada) Internal memory allocation improvements - (giada) Fixed an unallocated hardware parameter into ALSA configuration - (wa) Information about wave endianness - Added a "Requirements" section to the readme file 0.0.2 --- 2010 . 09 . 17 - (giada) More visual feedbacks if a key is pressed - (giada) Added a graphical alert if a sample is in an incorrect format - (giada) Confirm on exit - (giada) Graphical improvements for the browser window - (giada) Browser window doesn't close itself anymore if a sample format is incorrect - (giada) Added "-- no sample --" for empty channels - (giada) Startup no longer fails if a sample from the ini file is not found - (giada) Internal optimization for the sample loading routine - (giada) More graphical consistency between subwindows - (giada) The sample name is now trucated to fit into its box, preventing overflow - (giada) Other minor GUI tweaks - (giada) Internal memory improvements to prevent a bad bug of allocation with malformed wave files - (wa) More information about sample size - (wa) Added calculations and comparison between data sizes 0.0.1 --- 2010 . 09 . 06 (initial release) giada-0.11.2/Makefile.am000066400000000000000000000166251264622563000147140ustar00rootroot00000000000000channelAUTOMAKOPTIONS = foreign AM_CXXFLAGS = -Wall -pedantic -Werror # make giada ------------------------------------------------------------------- bin_PROGRAMS = giada giada_SOURCES = \ src/main.cpp \ src/core/const.h \ src/core/channel.h \ src/core/channel.cpp \ src/core/sampleChannel.h \ src/core/sampleChannel.cpp \ src/core/midiChannel.h \ src/core/midiChannel.cpp \ src/core/midiMapConf.h \ src/core/midiMapConf.cpp \ src/core/conf.h \ src/core/conf.cpp \ src/core/kernelAudio.h \ src/core/kernelAudio.cpp \ src/core/pluginHost.h \ src/core/pluginHost.cpp \ src/core/mixerHandler.h \ src/core/mixerHandler.cpp \ src/core/init.h \ src/core/init.cpp \ src/core/plugin.h \ src/core/plugin.cpp \ src/core/wave.h \ src/core/wave.cpp \ src/core/waveFx.h \ src/core/waveFx.cpp \ src/core/kernelMidi.h \ src/core/kernelMidi.cpp \ src/core/graphics.h \ src/core/graphics.cpp \ src/core/patch_DEPR_.h \ src/core/patch_DEPR_.cpp \ src/core/patch.h \ src/core/patch.cpp \ src/core/recorder.h \ src/core/recorder.cpp \ src/core/mixer.h \ src/core/mixer.cpp \ src/core/dataStorageIni.h \ src/core/dataStorageIni.cpp \ src/core/dataStorageJson.h \ src/core/dataStorageJson.cpp \ src/glue/glue.h \ src/glue/glue.cpp \ src/glue/storage.h \ src/glue/storage.cpp \ src/glue/channel.h \ src/glue/channel.cpp \ src/gui/dialogs/gd_keyGrabber.h \ src/gui/dialogs/gd_keyGrabber.cpp \ src/gui/dialogs/gd_about.h \ src/gui/dialogs/gd_about.cpp \ src/gui/dialogs/gd_mainWindow.h \ src/gui/dialogs/gd_mainWindow.cpp \ src/gui/dialogs/gd_beatsInput.h \ src/gui/dialogs/gd_beatsInput.cpp \ src/gui/dialogs/gd_warnings.h \ src/gui/dialogs/gd_warnings.cpp \ src/gui/dialogs/gd_bpmInput.h \ src/gui/dialogs/gd_bpmInput.cpp \ src/gui/dialogs/gd_browser.h \ src/gui/dialogs/gd_browser.cpp \ src/gui/dialogs/gd_config.h \ src/gui/dialogs/gd_config.cpp \ src/gui/dialogs/gd_devInfo.h \ src/gui/dialogs/gd_devInfo.cpp \ src/gui/dialogs/gd_pluginList.h \ src/gui/dialogs/gd_pluginList.cpp \ src/gui/dialogs/gd_pluginWindow.h \ src/gui/dialogs/gd_pluginWindow.cpp \ src/gui/dialogs/gd_editor.h \ src/gui/dialogs/gd_editor.cpp \ src/gui/dialogs/gd_pluginWindowGUI.h \ src/gui/dialogs/gd_pluginWindowGUI.cpp \ src/gui/dialogs/gd_midiOutput.h \ src/gui/dialogs/gd_midiOutput.cpp \ src/gui/dialogs/gd_midiInput.h \ src/gui/dialogs/gd_midiInput.cpp \ src/gui/dialogs/gd_actionEditor.h \ src/gui/dialogs/gd_actionEditor.cpp \ src/gui/elems/ge_column.h \ src/gui/elems/ge_column.cpp \ src/gui/elems/ge_sampleChannel.h \ src/gui/elems/ge_sampleChannel.cpp \ src/gui/elems/ge_midiChannel.h \ src/gui/elems/ge_midiChannel.cpp \ src/gui/elems/ge_midiIoTools.h \ src/gui/elems/ge_midiIoTools.cpp \ src/gui/elems/ge_mixed.h \ src/gui/elems/ge_mixed.cpp \ src/gui/elems/ge_waveform.h \ src/gui/elems/ge_waveform.cpp \ src/gui/elems/ge_browser.h \ src/gui/elems/ge_browser.cpp \ src/gui/elems/ge_actionWidget.h \ src/gui/elems/ge_actionWidget.cpp \ src/gui/elems/ge_envelopeChannel.h \ src/gui/elems/ge_envelopeChannel.cpp \ src/gui/elems/ge_pianoRoll.h \ src/gui/elems/ge_pianoRoll.cpp \ src/gui/elems/ge_channel.h \ src/gui/elems/ge_channel.cpp \ src/gui/elems/ge_muteChannel.h \ src/gui/elems/ge_muteChannel.cpp \ src/gui/elems/ge_actionChannel.h \ src/gui/elems/ge_actionChannel.cpp \ src/gui/elems/ge_window.h \ src/gui/elems/ge_window.cpp \ src/gui/elems/ge_status.h \ src/gui/elems/ge_status.cpp \ src/gui/elems/ge_keyboard.h \ src/gui/elems/ge_keyboard.cpp \ src/gui/elems/ge_waveTools.h \ src/gui/elems/ge_waveTools.cpp \ src/gui/elems/ge_modeBox.h \ src/gui/elems/ge_modeBox.cpp \ src/gui/elems/ge_controller.h \ src/gui/elems/ge_controller.cpp \ src/gui/elems/ge_channelButton.h \ src/gui/elems/ge_channelButton.cpp \ src/utils/log.h \ src/utils/log.cpp \ src/utils/gui_utils.h \ src/utils/gui_utils.cpp \ src/utils/gvector.h \ src/utils/utils.h \ src/utils/utils.cpp # Check for environment: these vars are defined via AM_CONDITIONAL # inside configure.ac if LINUX giada_LDADD = -lsndfile -lfltk -lXext -lX11 -lXft -lXpm -lm \ src/deps/rtaudio-mod/librtaudio.a -ljack -lasound -lpthread -ldl \ -lpulse-simple -lpulse -lsamplerate -lrtmidi -ljansson endif if WINDOWS giada_LDADD = -lrtaudio -ldsound -lwsock32 -lm -lfltk -lwininet -lgdi32 \ -lshell32 -lvfw32 -lrpcrt4 -luuid -lcomctl32 -lole32 -lws2_32 \ -lsndfile -lsamplerate -lrtmidi -lwinmm -lsetupapi -lksuser \ -lpthreadGC2 -ljansson giada_LDFLAGS = -mwindows -static giada_SOURCES += resource.rc endif if OSX # for 32 bit compilation: # export CXXFLAGS="-m32" # export LDFLAGS="-m32" giada_LDADD = -lsndfile -lm -lpthread -lfltk -lrtmidi -lrtaudio \ -lsamplerate -ljansson giada_LDFLAGS = -framework CoreAudio -framework Cocoa -framework Carbon \ -framework CoreMIDI -framework CoreFoundation endif # used only under MinGW to compile the resource.rc file (program icon) resource.o: windres src/ext/resource.rc -o resource.o # custom rtaudio src/deps/rtaudio-mod/librtaudio.a: @cd src/deps/rtaudio-mod; echo "Building RtAudio for Linux..."; \ ./configure --with-jack --with-alsa --with-pulse; \ make; # make test -------------------------------------------------------------------- TESTS = giada_tests check_PROGRAMS = giada_tests giada_tests_SOURCES = \ tests/main.cpp \ tests/conf.cpp \ tests/wave.cpp \ tests/patch.cpp \ tests/midiMapConf.cpp \ tests/utils.cpp \ src/core/conf.cpp \ src/core/wave.cpp \ src/core/midiMapConf.cpp \ src/core/patch.cpp \ src/core/dataStorageIni.cpp \ src/core/dataStorageJson.cpp \ src/utils/utils.cpp \ src/utils/log.cpp giada_tests_LDADD = -ljansson -lsndfile -lsamplerate giada_tests_CXXFLAGS = -std=c++11 # make rename ------------------------------------------------------------------ if LINUX rename: mv giada giada_lin endif if WINDOWS rename: mv giada giada_win.exe endif if OSX rename: mv giada giada_osx endif giada-0.11.2/README.md000066400000000000000000000066031264622563000141320ustar00rootroot00000000000000# Giada - Your Hardcore Loopmachine Official website: http://www.giadamusic.com | Travis CI status: [![Build Status](https://travis-ci.org/monocasual/giada.svg?branch=master)](https://travis-ci.org/monocasual/giada) ## What is Giada? Giada is a free, minimal, hardcore audio tool for DJs, live performers and electronic musicians. How does it work? Just pick up your channel, fill it with samples or MIDI events and start the show by using this tiny piece of software as a loop machine, drum machine, sequencer, live sampler or yet as a plugin/effect host. Giada aims to be a compact and portable virtual device for Linux, Mac OS X and Windows for production use and live sets. ➔➔➔ [See Giada in action!](http://www.youtube.com/user/GiadaLoopMachine) ![Giada Loop Machine screenshot](http://giadamusic.com/public/img/screenshots/giada-loop-machine-screenshot-14-carousel.jpg) ## Main features * Ultra-lightweight internal design; * multi-thread/multi-core support; * 32-bit floating point audio engine; * ALSA, JACK + Transport, CoreAudio, ASIO and DirectSound full support; * high quality internal resampler; * unlimited number of channels (controllable via computer keyboard); * several playback modes and combinations; * BPM and beat sync with sample-accurate loop engine; * VST and VSTi (instrument) plugin support; * MIDI input and output support, featuring custom [MIDI lightning messages](https://github.com/monocasual/giada-midimaps); * super-sleek, built-in wave editor; * live sampler from external inputs; * live action recorder with automatic quantizer; * piano Roll editor; * portable patch storage system, based on super-hackable JSON files; * support for all major uncompressed file formats; * test-driven development style supported by [Travis CI](https://travis-ci.org/monocasual/giada) and [Catch](https://github.com/philsquared/Catch) * under a constant stage of development; * 100% open-source GPL v3. ## License Giada is available under the terms of the GNU General Public License. Take a look at the COPYING file for further informations. ## Documentation Docs are available online on the official website: http://www.giadamusic.com/documentation Found a typo or a terrible mistake? Feel free to clone the [website repository](https://github.com/monocasual/giada-www) and send us your pull requests. ## Build Giada from source We do our best to make the compilation process as simple as possible. You can find all the information in the [official docs page](http://giadamusic.com/documentation/show/compiling-from-source). ## Bugs, requests and questions for non-developers Feel free to ask anything on our end-user forum: http://www.giadamusic.com/forum ## Copyright Giada is Copyright (C) 2010-2016 by Giovanni A. Zuliani | Monocasual Giada - Your Hardcore Loopmachine 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. Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see . giada-0.11.2/autogen.sh000077500000000000000000001345321264622563000146570ustar00rootroot00000000000000#!/bin/sh # a u t o g e n . s h # # Copyright (c) 2005-2009 United States Government as represented by # the U.S. Army Research Laboratory. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ### # # Script for automatically preparing the sources for compilation by # performing the myriad of necessary steps. The script attempts to # detect proper version support, and outputs warnings about particular # systems that have autotool peculiarities. # # Basically, if everything is set up and installed correctly, the # script will validate that minimum versions of the GNU Build System # tools are installed, account for several common configuration # issues, and then simply run autoreconf for you. # # If autoreconf fails, which can happen for many valid configurations, # this script proceeds to run manual preparation steps effectively # providing a POSIX shell script (mostly complete) reimplementation of # autoreconf. # # The AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER # environment variables and corresponding _OPTIONS variables (e.g. # AUTORECONF_OPTIONS) may be used to override the default automatic # detection behaviors. Similarly the _VERSION variables will override # the minimum required version numbers. # # Examples: # # To obtain help on usage: # ./autogen.sh --help # # To obtain verbose output: # ./autogen.sh --verbose # # To skip autoreconf and prepare manually: # AUTORECONF=false ./autogen.sh # # To verbosely try running with an older (unsupported) autoconf: # AUTOCONF_VERSION=2.50 ./autogen.sh --verbose # # Author: # Christopher Sean Morrison # # Patches: # Sebastian Pipping # ###################################################################### # set to minimum acceptable version of autoconf if [ "x$AUTOCONF_VERSION" = "x" ] ; then AUTOCONF_VERSION=2.52 fi # set to minimum acceptable version of automake if [ "x$AUTOMAKE_VERSION" = "x" ] ; then AUTOMAKE_VERSION=1.6.0 fi # set to minimum acceptable version of libtool if [ "x$LIBTOOL_VERSION" = "x" ] ; then LIBTOOL_VERSION=1.4.2 fi ################## # ident function # ################## ident ( ) { # extract copyright from header __copyright="`grep Copyright $AUTOGEN_SH | head -${HEAD_N}1 | awk '{print $4}'`" if [ "x$__copyright" = "x" ] ; then __copyright="`date +%Y`" fi # extract version from CVS Id string __id="$Id: autogen.sh 33925 2009-03-01 23:27:06Z brlcad $" __version="`echo $__id | sed 's/.*\([0-9][0-9][0-9][0-9]\)[-\/]\([0-9][0-9]\)[-\/]\([0-9][0-9]\).*/\1\2\3/'`" if [ "x$__version" = "x" ] ; then __version="" fi echo "autogen.sh build preparation script by Christopher Sean Morrison" echo " + config.guess download patch by Sebastian Pipping (2008-12-03)" echo "revised 3-clause BSD-style license, copyright (c) $__copyright" echo "script version $__version, ISO/IEC 9945 POSIX shell script" } ################## # USAGE FUNCTION # ################## usage ( ) { echo "Usage: $AUTOGEN_SH [-h|--help] [-v|--verbose] [-q|--quiet] [-d|--download] [--version]" echo " --help Help on $NAME_OF_AUTOGEN usage" echo " --verbose Verbose progress output" echo " --quiet Quiet suppressed progress output" echo " --download Download the latest config.guess from gnulib" echo " --version Only perform GNU Build System version checks" echo echo "Description: This script will validate that minimum versions of the" echo "GNU Build System tools are installed and then run autoreconf for you." echo "Should autoreconf fail, manual preparation steps will be run" echo "potentially accounting for several common preparation issues. The" echo "AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER," echo "PROJECT, & CONFIGURE environment variables and corresponding _OPTIONS" echo "variables (e.g. AUTORECONF_OPTIONS) may be used to override the" echo "default automatic detection behavior." echo ident return 0 } ########################## # VERSION_ERROR FUNCTION # ########################## version_error ( ) { if [ "x$1" = "x" ] ; then echo "INTERNAL ERROR: version_error was not provided a version" exit 1 fi if [ "x$2" = "x" ] ; then echo "INTERNAL ERROR: version_error was not provided an application name" exit 1 fi $ECHO $ECHO "ERROR: To prepare the ${PROJECT} build system from scratch," $ECHO " at least version $1 of $2 must be installed." $ECHO $ECHO "$NAME_OF_AUTOGEN does not need to be run on the same machine that will" $ECHO "run configure or make. Either the GNU Autotools will need to be installed" $ECHO "or upgraded on this system, or $NAME_OF_AUTOGEN must be run on the source" $ECHO "code on another system and then transferred to here. -- Cheers!" $ECHO } ########################## # VERSION_CHECK FUNCTION # ########################## version_check ( ) { if [ "x$1" = "x" ] ; then echo "INTERNAL ERROR: version_check was not provided a minimum version" exit 1 fi _min="$1" if [ "x$2" = "x" ] ; then echo "INTERNAL ERROR: version check was not provided a comparison version" exit 1 fi _cur="$2" # needed to handle versions like 1.10 and 1.4-p6 _min="`echo ${_min}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" _cur="`echo ${_cur}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" _min_major="`echo $_min | cut -d. -f1`" _min_minor="`echo $_min | cut -d. -f2`" _min_patch="`echo $_min | cut -d. -f3`" _cur_major="`echo $_cur | cut -d. -f1`" _cur_minor="`echo $_cur | cut -d. -f2`" _cur_patch="`echo $_cur | cut -d. -f3`" if [ "x$_min_major" = "x" ] ; then _min_major=0 fi if [ "x$_min_minor" = "x" ] ; then _min_minor=0 fi if [ "x$_min_patch" = "x" ] ; then _min_patch=0 fi if [ "x$_cur_minor" = "x" ] ; then _cur_major=0 fi if [ "x$_cur_minor" = "x" ] ; then _cur_minor=0 fi if [ "x$_cur_patch" = "x" ] ; then _cur_patch=0 fi $VERBOSE_ECHO "Checking if ${_cur_major}.${_cur_minor}.${_cur_patch} is greater than ${_min_major}.${_min_minor}.${_min_patch}" if [ $_min_major -lt $_cur_major ] ; then return 0 elif [ $_min_major -eq $_cur_major ] ; then if [ $_min_minor -lt $_cur_minor ] ; then return 0 elif [ $_min_minor -eq $_cur_minor ] ; then if [ $_min_patch -lt $_cur_patch ] ; then return 0 elif [ $_min_patch -eq $_cur_patch ] ; then return 0 fi fi fi return 1 } ###################################### # LOCATE_CONFIGURE_TEMPLATE FUNCTION # ###################################### locate_configure_template ( ) { _pwd="`pwd`" if test -f "./configure.ac" ; then echo "./configure.ac" elif test -f "./configure.in" ; then echo "./configure.in" elif test -f "$_pwd/configure.ac" ; then echo "$_pwd/configure.ac" elif test -f "$_pwd/configure.in" ; then echo "$_pwd/configure.in" elif test -f "$PATH_TO_AUTOGEN/configure.ac" ; then echo "$PATH_TO_AUTOGEN/configure.ac" elif test -f "$PATH_TO_AUTOGEN/configure.in" ; then echo "$PATH_TO_AUTOGEN/configure.in" fi } ################## # argument check # ################## ARGS="$*" PATH_TO_AUTOGEN="`dirname $0`" NAME_OF_AUTOGEN="`basename $0`" AUTOGEN_SH="$PATH_TO_AUTOGEN/$NAME_OF_AUTOGEN" LIBTOOL_M4="${PATH_TO_AUTOGEN}/misc/libtool.m4" if [ "x$HELP" = "x" ] ; then HELP=no fi if [ "x$QUIET" = "x" ] ; then QUIET=no fi if [ "x$VERBOSE" = "x" ] ; then VERBOSE=no fi if [ "x$VERSION_ONLY" = "x" ] ; then VERSION_ONLY=no fi if [ "x$DOWNLOAD" = "x" ] ; then DOWNLOAD=no fi if [ "x$AUTORECONF_OPTIONS" = "x" ] ; then AUTORECONF_OPTIONS="-i -f" fi if [ "x$AUTOCONF_OPTIONS" = "x" ] ; then AUTOCONF_OPTIONS="-f" fi if [ "x$AUTOMAKE_OPTIONS" = "x" ] ; then AUTOMAKE_OPTIONS="-a -c -f" fi ALT_AUTOMAKE_OPTIONS="-a -c" if [ "x$LIBTOOLIZE_OPTIONS" = "x" ] ; then LIBTOOLIZE_OPTIONS="--automake -c -f" fi ALT_LIBTOOLIZE_OPTIONS="--automake --copy --force" if [ "x$ACLOCAL_OPTIONS" = "x" ] ; then ACLOCAL_OPTIONS="" fi if [ "x$AUTOHEADER_OPTIONS" = "x" ] ; then AUTOHEADER_OPTIONS="" fi if [ "x$CONFIG_GUESS_URL" = "x" ] ; then CONFIG_GUESS_URL="http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=build-aux/config.guess;hb=HEAD" fi for arg in $ARGS ; do case "x$arg" in x--help) HELP=yes ;; x-[hH]) HELP=yes ;; x--quiet) QUIET=yes ;; x-[qQ]) QUIET=yes ;; x--verbose) VERBOSE=yes ;; x-[dD]) DOWNLOAD=yes ;; x--download) DOWNLOAD=yes ;; x-[vV]) VERBOSE=yes ;; x--version) VERSION_ONLY=yes ;; *) echo "Unknown option: $arg" echo usage exit 1 ;; esac done ##################### # environment check # ##################### # sanity check before recursions potentially begin if [ ! -f "$AUTOGEN_SH" ] ; then echo "INTERNAL ERROR: $AUTOGEN_SH does not exist" if [ ! "x$0" = "x$AUTOGEN_SH" ] ; then echo "INTERNAL ERROR: dirname/basename inconsistency: $0 != $AUTOGEN_SH" fi exit 1 fi # force locale setting to C so things like date output as expected LC_ALL=C # commands that this script expects for __cmd in echo head tail pwd ; do echo "test" | $__cmd > /dev/null 2>&1 if [ $? != 0 ] ; then echo "INTERNAL ERROR: '${__cmd}' command is required" exit 2 fi done echo "test" | grep "test" > /dev/null 2>&1 if test ! x$? = x0 ; then echo "INTERNAL ERROR: grep command is required" exit 1 fi echo "test" | sed "s/test/test/" > /dev/null 2>&1 if test ! x$? = x0 ; then echo "INTERNAL ERROR: sed command is required" exit 1 fi # determine the behavior of echo case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac # determine the behavior of head case "x`echo 'head' | head -n 1 2>&1`" in *xhead*) HEAD_N="n " ;; *) HEAD_N="" ;; esac # determine the behavior of tail case "x`echo 'tail' | tail -n 1 2>&1`" in *xtail*) TAIL_N="n " ;; *) TAIL_N="" ;; esac VERBOSE_ECHO=: ECHO=: if [ "x$QUIET" = "xyes" ] ; then if [ "x$VERBOSE" = "xyes" ] ; then echo "Verbose output quelled by quiet option. Further output disabled." fi else ECHO=echo if [ "x$VERBOSE" = "xyes" ] ; then echo "Verbose output enabled" VERBOSE_ECHO=echo fi fi # allow a recursive run to disable further recursions if [ "x$RUN_RECURSIVE" = "x" ] ; then RUN_RECURSIVE=yes fi ################################################ # check for help arg and bypass version checks # ################################################ if [ "x`echo $ARGS | sed 's/.*[hH][eE][lL][pP].*/help/'`" = "xhelp" ] ; then HELP=yes fi if [ "x$HELP" = "xyes" ] ; then usage $ECHO "---" $ECHO "Help was requested. No preparation or configuration will be performed." exit 0 fi ####################### # set up signal traps # ####################### untrap_abnormal ( ) { for sig in 1 2 13 15; do trap - $sig done } # do this cleanup whenever we exit. trap ' # start from the root if test -d "$START_PATH" ; then cd "$START_PATH" fi # restore/delete backup files if test "x$PFC_INIT" = "x1" ; then recursive_restore fi ' 0 # trap SIGHUP (1), SIGINT (2), SIGPIPE (13), SIGTERM (15) for sig in 1 2 13 15; do trap ' $ECHO "" $ECHO "Aborting $NAME_OF_AUTOGEN: caught signal '$sig'" # start from the root if test -d "$START_PATH" ; then cd "$START_PATH" fi # clean up on abnormal exit $VERBOSE_ECHO "rm -rf autom4te.cache" rm -rf autom4te.cache if test -f "acinclude.m4.$$.backup" ; then $VERBOSE_ECHO "cat acinclude.m4.$$.backup > acinclude.m4" chmod u+w acinclude.m4 cat acinclude.m4.$$.backup > acinclude.m4 $VERBOSE_ECHO "rm -f acinclude.m4.$$.backup" rm -f acinclude.m4.$$.backup fi { (exit 1); exit 1; } ' $sig done ############################# # look for a configure file # ############################# if [ "x$CONFIGURE" = "x" ] ; then CONFIGURE="`locate_configure_template`" if [ ! "x$CONFIGURE" = "x" ] ; then $VERBOSE_ECHO "Found a configure template: $CONFIGURE" fi else $ECHO "Using CONFIGURE environment variable override: $CONFIGURE" fi if [ "x$CONFIGURE" = "x" ] ; then if [ "x$VERSION_ONLY" = "xyes" ] ; then CONFIGURE=/dev/null else $ECHO $ECHO "A configure.ac or configure.in file could not be located implying" $ECHO "that the GNU Build System is at least not used in this directory. In" $ECHO "any case, there is nothing to do here without one of those files." $ECHO $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`" exit 1 fi fi #################### # get project name # #################### if [ "x$PROJECT" = "x" ] ; then PROJECT="`grep AC_INIT $CONFIGURE | grep -v '.*#.*AC_INIT' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_INIT(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" if [ "x$PROJECT" = "xAC_INIT" ] ; then # projects might be using the older/deprecated arg-less AC_INIT .. look for AM_INIT_AUTOMAKE instead PROJECT="`grep AM_INIT_AUTOMAKE $CONFIGURE | grep -v '.*#.*AM_INIT_AUTOMAKE' | tail -${TAIL_N}1 | sed 's/^[ ]*AM_INIT_AUTOMAKE(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" fi if [ "x$PROJECT" = "xAM_INIT_AUTOMAKE" ] ; then PROJECT="project" fi if [ "x$PROJECT" = "x" ] ; then PROJECT="project" fi else $ECHO "Using PROJECT environment variable override: $PROJECT" fi $ECHO "Preparing the $PROJECT build system...please wait" $ECHO ######################## # check for autoreconf # ######################## HAVE_AUTORECONF=no if [ "x$AUTORECONF" = "x" ] ; then for AUTORECONF in autoreconf ; do $VERBOSE_ECHO "Checking autoreconf version: $AUTORECONF --version" $AUTORECONF --version > /dev/null 2>&1 if [ $? = 0 ] ; then HAVE_AUTORECONF=yes break fi done else HAVE_AUTORECONF=yes $ECHO "Using AUTORECONF environment variable override: $AUTORECONF" fi ########################## # autoconf version check # ########################## _acfound=no if [ "x$AUTOCONF" = "x" ] ; then for AUTOCONF in autoconf ; do $VERBOSE_ECHO "Checking autoconf version: $AUTOCONF --version" $AUTOCONF --version > /dev/null 2>&1 if [ $? = 0 ] ; then _acfound=yes break fi done else _acfound=yes $ECHO "Using AUTOCONF environment variable override: $AUTOCONF" fi _report_error=no if [ ! "x$_acfound" = "xyes" ] ; then $ECHO "ERROR: Unable to locate GNU Autoconf." _report_error=yes else _version="`$AUTOCONF --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" if [ "x$_version" = "x" ] ; then _version="0.0.0" fi $ECHO "Found GNU Autoconf version $_version" version_check "$AUTOCONF_VERSION" "$_version" if [ $? -ne 0 ] ; then _report_error=yes fi fi if [ "x$_report_error" = "xyes" ] ; then version_error "$AUTOCONF_VERSION" "GNU Autoconf" exit 1 fi ########################## # automake version check # ########################## _amfound=no if [ "x$AUTOMAKE" = "x" ] ; then for AUTOMAKE in automake ; do $VERBOSE_ECHO "Checking automake version: $AUTOMAKE --version" $AUTOMAKE --version > /dev/null 2>&1 if [ $? = 0 ] ; then _amfound=yes break fi done else _amfound=yes $ECHO "Using AUTOMAKE environment variable override: $AUTOMAKE" fi _report_error=no if [ ! "x$_amfound" = "xyes" ] ; then $ECHO $ECHO "ERROR: Unable to locate GNU Automake." _report_error=yes else _version="`$AUTOMAKE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" if [ "x$_version" = "x" ] ; then _version="0.0.0" fi $ECHO "Found GNU Automake version $_version" version_check "$AUTOMAKE_VERSION" "$_version" if [ $? -ne 0 ] ; then _report_error=yes fi fi if [ "x$_report_error" = "xyes" ] ; then version_error "$AUTOMAKE_VERSION" "GNU Automake" exit 1 fi ######################## # check for libtoolize # ######################## HAVE_LIBTOOLIZE=yes HAVE_ALT_LIBTOOLIZE=no _ltfound=no if [ "x$LIBTOOLIZE" = "x" ] ; then LIBTOOLIZE=libtoolize $VERBOSE_ECHO "Checking libtoolize version: $LIBTOOLIZE --version" $LIBTOOLIZE --version > /dev/null 2>&1 if [ ! $? = 0 ] ; then HAVE_LIBTOOLIZE=no $ECHO if [ "x$HAVE_AUTORECONF" = "xno" ] ; then $ECHO "Warning: libtoolize does not appear to be available." else $ECHO "Warning: libtoolize does not appear to be available. This means that" $ECHO "the automatic build preparation via autoreconf will probably not work." $ECHO "Preparing the build by running each step individually, however, should" $ECHO "work and will be done automatically for you if autoreconf fails." fi # look for some alternates for tool in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do $VERBOSE_ECHO "Checking libtoolize alternate: $tool --version" _glibtoolize="`$tool --version > /dev/null 2>&1`" if [ $? = 0 ] ; then $VERBOSE_ECHO "Found $tool --version" _glti="`which $tool`" if [ "x$_glti" = "x" ] ; then $VERBOSE_ECHO "Cannot find $tool with which" continue; fi if test ! -f "$_glti" ; then $VERBOSE_ECHO "Cannot use $tool, $_glti is not a file" continue; fi _gltidir="`dirname $_glti`" if [ "x$_gltidir" = "x" ] ; then $VERBOSE_ECHO "Cannot find $tool path with dirname of $_glti" continue; fi if test ! -d "$_gltidir" ; then $VERBOSE_ECHO "Cannot use $tool, $_gltidir is not a directory" continue; fi HAVE_ALT_LIBTOOLIZE=yes LIBTOOLIZE="$tool" $ECHO $ECHO "Fortunately, $tool was found which means that your system may simply" $ECHO "have a non-standard or incomplete GNU Autotools install. If you have" $ECHO "sufficient system access, it may be possible to quell this warning by" $ECHO "running:" $ECHO sudo -V > /dev/null 2>&1 if [ $? = 0 ] ; then $ECHO " sudo ln -s $_glti $_gltidir/libtoolize" $ECHO else $ECHO " ln -s $_glti $_gltidir/libtoolize" $ECHO $ECHO "Run that as root or with proper permissions to the $_gltidir directory" $ECHO fi _ltfound=yes break fi done else _ltfound=yes fi else _ltfound=yes $ECHO "Using LIBTOOLIZE environment variable override: $LIBTOOLIZE" fi ############################ # libtoolize version check # ############################ _report_error=no if [ ! "x$_ltfound" = "xyes" ] ; then $ECHO $ECHO "ERROR: Unable to locate GNU Libtool." _report_error=yes else _version="`$LIBTOOLIZE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" if [ "x$_version" = "x" ] ; then _version="0.0.0" fi $ECHO "Found GNU Libtool version $_version" version_check "$LIBTOOL_VERSION" "$_version" if [ $? -ne 0 ] ; then _report_error=yes fi fi if [ "x$_report_error" = "xyes" ] ; then version_error "$LIBTOOL_VERSION" "GNU Libtool" exit 1 fi ##################### # check for aclocal # ##################### if [ "x$ACLOCAL" = "x" ] ; then for ACLOCAL in aclocal ; do $VERBOSE_ECHO "Checking aclocal version: $ACLOCAL --version" $ACLOCAL --version > /dev/null 2>&1 if [ $? = 0 ] ; then break fi done else $ECHO "Using ACLOCAL environment variable override: $ACLOCAL" fi ######################## # check for autoheader # ######################## if [ "x$AUTOHEADER" = "x" ] ; then for AUTOHEADER in autoheader ; do $VERBOSE_ECHO "Checking autoheader version: $AUTOHEADER --version" $AUTOHEADER --version > /dev/null 2>&1 if [ $? = 0 ] ; then break fi done else $ECHO "Using AUTOHEADER environment variable override: $AUTOHEADER" fi ######################### # check if version only # ######################### $VERBOSE_ECHO "Checking whether to only output version information" if [ "x$VERSION_ONLY" = "xyes" ] ; then $ECHO ident $ECHO "---" $ECHO "Version requested. No preparation or configuration will be performed." exit 0 fi ################################# # PROTECT_FROM_CLOBBER FUNCTION # ################################# protect_from_clobber ( ) { PFC_INIT=1 # protect COPYING & INSTALL from overwrite by automake. the # automake force option will (inappropriately) ignore the existing # contents of a COPYING and/or INSTALL files (depending on the # version) instead of just forcing *missing* files like it does # for AUTHORS, NEWS, and README. this is broken but extremely # prevalent behavior, so we protect against it by keeping a backup # of the file that can later be restored. for file in COPYING INSTALL ; do if test -f ${file} ; then if test -f ${file}.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "Already backed up ${file} in `pwd`" else $VERBOSE_ECHO "Backing up ${file} in `pwd`" $VERBOSE_ECHO "cp -p ${file} ${file}.$$.protect_from_automake.backup" cp -p ${file} ${file}.$$.protect_from_automake.backup fi fi done } ############################## # RECURSIVE_PROTECT FUNCTION # ############################## recursive_protect ( ) { # for projects using recursive configure, run the build # preparation steps for the subdirectories. this function assumes # START_PATH was set to pwd before recursion begins so that # relative paths work. # git 'r done, protect COPYING and INSTALL from being clobbered protect_from_clobber if test -d autom4te.cache ; then $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it" $VERBOSE_ECHO "rm -rf autom4te.cache" rm -rf autom4te.cache fi # find configure template _configure="`locate_configure_template`" if [ "x$_configure" = "x" ] ; then return fi # $VERBOSE_ECHO "Looking for configure template found `pwd`/$_configure" # look for subdirs # $VERBOSE_ECHO "Looking for subdirs in `pwd`" _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" CHECK_DIRS="" for dir in $_det_config_subdirs ; do if test -d "`pwd`/$dir" ; then CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\"" fi done # process subdirs if [ ! "x$CHECK_DIRS" = "x" ] ; then $VERBOSE_ECHO "Recursively scanning the following directories:" $VERBOSE_ECHO " $CHECK_DIRS" for dir in $CHECK_DIRS ; do $VERBOSE_ECHO "Protecting files from automake in $dir" cd "$START_PATH" eval "cd $dir" # recursively git 'r done recursive_protect done fi } # end of recursive_protect ############################# # RESTORE_CLOBBERED FUNCION # ############################# restore_clobbered ( ) { # The automake (and autoreconf by extension) -f/--force-missing # option may overwrite COPYING and INSTALL even if they do exist. # Here we restore the files if necessary. spacer=no for file in COPYING INSTALL ; do if test -f ${file}.$$.protect_from_automake.backup ; then if test -f ${file} ; then # compare entire content, restore if needed if test "x`cat ${file}`" != "x`cat ${file}.$$.protect_from_automake.backup`" ; then if test "x$spacer" = "xno" ; then $VERBOSE_ECHO spacer=yes fi # restore the backup $VERBOSE_ECHO "Restoring ${file} from backup (automake -f likely clobbered it)" $VERBOSE_ECHO "rm -f ${file}" rm -f ${file} $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}" mv ${file}.$$.protect_from_automake.backup ${file} fi # check contents elif test -f ${file}.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "mv ${file}.$$.protect_from_automake.backup ${file}" mv ${file}.$$.protect_from_automake.backup ${file} fi # -f ${file} # just in case $VERBOSE_ECHO "rm -f ${file}.$$.protect_from_automake.backup" rm -f ${file}.$$.protect_from_automake.backup fi # -f ${file}.$$.protect_from_automake.backup done CONFIGURE="`locate_configure_template`" if [ "x$CONFIGURE" = "x" ] ; then return fi _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" if test ! -d "$_aux_dir" ; then _aux_dir=. fi for file in config.guess config.sub ltmain.sh ; do if test -f "${_aux_dir}/${file}" ; then $VERBOSE_ECHO "rm -f \"${_aux_dir}/${file}.backup\"" rm -f "${_aux_dir}/${file}.backup" fi done } # end of restore_clobbered ############################## # RECURSIVE_RESTORE FUNCTION # ############################## recursive_restore ( ) { # restore COPYING and INSTALL from backup if they were clobbered # for each directory recursively. # git 'r undone restore_clobbered # find configure template _configure="`locate_configure_template`" if [ "x$_configure" = "x" ] ; then return fi # look for subdirs _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" CHECK_DIRS="" for dir in $_det_config_subdirs ; do if test -d "`pwd`/$dir" ; then CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\"" fi done # process subdirs if [ ! "x$CHECK_DIRS" = "x" ] ; then $VERBOSE_ECHO "Recursively scanning the following directories:" $VERBOSE_ECHO " $CHECK_DIRS" for dir in $CHECK_DIRS ; do $VERBOSE_ECHO "Checking files for automake damage in $dir" cd "$START_PATH" eval "cd $dir" # recursively git 'r undone recursive_restore done fi } # end of recursive_restore ####################### # INITIALIZE FUNCTION # ####################### initialize ( ) { # this routine performs a variety of directory-specific # initializations. some are sanity checks, some are preventive, # and some are necessary setup detection. # # this function sets: # CONFIGURE # SEARCH_DIRS # CONFIG_SUBDIRS ################################## # check for a configure template # ################################## CONFIGURE="`locate_configure_template`" if [ "x$CONFIGURE" = "x" ] ; then $ECHO $ECHO "A configure.ac or configure.in file could not be located implying" $ECHO "that the GNU Build System is at least not used in this directory. In" $ECHO "any case, there is nothing to do here without one of those files." $ECHO $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`" exit 1 fi ##################### # detect an aux dir # ##################### _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" if test ! -d "$_aux_dir" ; then _aux_dir=. else $VERBOSE_ECHO "Detected auxillary directory: $_aux_dir" fi ################################ # detect a recursive configure # ################################ CONFIG_SUBDIRS="" _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $CONFIGURE | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" for dir in $_det_config_subdirs ; do if test -d "`pwd`/$dir" ; then $VERBOSE_ECHO "Detected recursive configure directory: `pwd`/$dir" CONFIG_SUBDIRS="$CONFIG_SUBDIRS `pwd`/$dir" fi done ########################################################### # make sure certain required files exist for GNU projects # ########################################################### _marker_found="" _marker_found_message_intro='Detected non-GNU marker "' _marker_found_message_mid='" in ' for marker in foreign cygnus ; do _marker_found_message=${_marker_found_message_intro}${marker}${_marker_found_message_mid} _marker_found="`grep 'AM_INIT_AUTOMAKE.*'${marker} $CONFIGURE`" if [ ! "x$_marker_found" = "x" ] ; then $VERBOSE_ECHO "${_marker_found_message}`basename \"$CONFIGURE\"`" break fi if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then _marker_found="`grep 'AUTOMAKE_OPTIONS.*'${marker} Makefile.am`" if [ ! "x$_marker_found" = "x" ] ; then $VERBOSE_ECHO "${_marker_found_message}Makefile.am" break fi fi done if [ "x${_marker_found}" = "x" ] ; then _suggest_foreign=no for file in AUTHORS COPYING ChangeLog INSTALL NEWS README ; do if [ ! -f $file ] ; then $VERBOSE_ECHO "Touching ${file} since it does not exist" _suggest_foreign=yes touch $file fi done if [ "x${_suggest_foreign}" = "xyes" ] ; then $ECHO $ECHO "Warning: Several files expected of projects that conform to the GNU" $ECHO "coding standards were not found. The files were automatically added" $ECHO "for you since you do not have a 'foreign' declaration specified." $ECHO $ECHO "Considered adding 'foreign' to AM_INIT_AUTOMAKE in `basename \"$CONFIGURE\"`" if test -f "`dirname \"$CONFIGURE\"/Makefile.am`" ; then $ECHO "or to AUTOMAKE_OPTIONS in your top-level Makefile.am file." fi $ECHO fi fi ################################################## # make sure certain generated files do not exist # ################################################## for file in config.guess config.sub ltmain.sh ; do if test -f "${_aux_dir}/${file}" ; then $VERBOSE_ECHO "mv -f \"${_aux_dir}/${file}\" \"${_aux_dir}/${file}.backup\"" mv -f "${_aux_dir}/${file}" "${_aux_dir}/${file}.backup" fi done ############################ # search alternate m4 dirs # ############################ SEARCH_DIRS="" for dir in m4 ; do if [ -d $dir ] ; then $VERBOSE_ECHO "Found extra aclocal search directory: $dir" SEARCH_DIRS="$SEARCH_DIRS -I $dir" fi done ###################################### # remove any previous build products # ###################################### if test -d autom4te.cache ; then $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it" $VERBOSE_ECHO "rm -rf autom4te.cache" rm -rf autom4te.cache fi # tcl/tk (and probably others) have a customized aclocal.m4, so can't delete it # if test -f aclocal.m4 ; then # $VERBOSE_ECHO "Found an aclocal.m4 file, deleting it" # $VERBOSE_ECHO "rm -f aclocal.m4" # rm -f aclocal.m4 # fi } # end of initialize() ############## # initialize # ############## # stash path START_PATH="`pwd`" # Before running autoreconf or manual steps, some prep detection work # is necessary or useful. Only needs to occur once per directory, but # does need to traverse the entire subconfigure hierarchy to protect # files from being clobbered even by autoreconf. recursive_protect # start from where we started cd "$START_PATH" # get ready to process initialize ######################################### # DOWNLOAD_GNULIB_CONFIG_GUESS FUNCTION # ######################################### # TODO - should make sure wget/curl exist and/or work before trying to # use them. download_gnulib_config_guess () { # abuse gitweb to download gnulib's latest config.guess via HTTP config_guess_temp="config.guess.$$.download" ret=1 for __cmd in wget curl fetch ; do $VERBOSE_ECHO "Checking for command ${__cmd}" ${__cmd} --version > /dev/null 2>&1 ret=$? if [ ! $ret = 0 ] ; then continue fi __cmd_version=`${__cmd} --version | head -n 1 | sed -e 's/^[^0-9]\+//' -e 's/ .*//'` $VERBOSE_ECHO "Found ${__cmd} ${__cmd_version}" opts="" case ${__cmd} in wget) opts="-O" ;; curl) opts="-o" ;; fetch) opts="-t 5 -f" ;; esac $VERBOSE_ECHO "Running $__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" eval "$__cmd \"${CONFIG_GUESS_URL}\" $opts \"${config_guess_temp}\"" > /dev/null 2>&1 if [ $? = 0 ] ; then mv -f "${config_guess_temp}" ${_aux_dir}/config.guess ret=0 break fi done if [ ! $ret = 0 ] ; then $ECHO "Warning: config.guess download failed from: $CONFIG_GUESS_URL" rm -f "${config_guess_temp}" fi } ############################## # LIBTOOLIZE_NEEDED FUNCTION # ############################## libtoolize_needed () { ret=1 # means no, don't need libtoolize for feature in AC_PROG_LIBTOOL AM_PROG_LIBTOOL LT_INIT ; do $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" found="`grep \"^$feature.*\" $CONFIGURE`" if [ ! "x$found" = "x" ] ; then ret=0 # means yes, need to run libtoolize break fi done return ${ret} } ############################################ # prepare build via autoreconf or manually # ############################################ reconfigure_manually=no if [ "x$HAVE_AUTORECONF" = "xyes" ] ; then $ECHO $ECHO $ECHO_N "Automatically preparing build ... $ECHO_C" $VERBOSE_ECHO "$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS" autoreconf_output="`$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$autoreconf_output" if [ ! $ret = 0 ] ; then if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then if [ ! "x`echo \"$autoreconf_output\" | grep libtoolize | grep \"No such file or directory\"`" = "x" ] ; then $ECHO $ECHO "Warning: autoreconf failed but due to what is usually a common libtool" $ECHO "misconfiguration issue. This problem is encountered on systems that" $ECHO "have installed libtoolize under a different name without providing a" $ECHO "symbolic link or without setting the LIBTOOLIZE environment variable." $ECHO $ECHO "Restarting the preparation steps with LIBTOOLIZE set to $LIBTOOLIZE" export LIBTOOLIZE RUN_RECURSIVE=no export RUN_RECURSIVE untrap_abnormal $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" exit $? fi fi $ECHO "Warning: $AUTORECONF failed" if test -f ltmain.sh ; then $ECHO "libtoolize being run by autoreconf is not creating ltmain.sh in the auxillary directory like it should" fi $ECHO "Attempting to run the preparation steps individually" reconfigure_manually=yes else if [ "x$DOWNLOAD" = "xyes" ] ; then if libtoolize_needed ; then download_gnulib_config_guess fi fi fi else reconfigure_manually=yes fi ############################ # LIBTOOL_FAILURE FUNCTION # ############################ libtool_failure ( ) { # libtool is rather error-prone in comparison to the other # autotools and this routine attempts to compensate for some # common failures. the output after a libtoolize failure is # parsed for an error related to AC_PROG_LIBTOOL and if found, we # attempt to inject a project-provided libtool.m4 file. _autoconf_output="$1" if [ "x$RUN_RECURSIVE" = "xno" ] ; then # we already tried the libtool.m4, don't try again return 1 fi if test -f "$LIBTOOL_M4" ; then found_libtool="`$ECHO $_autoconf_output | grep AC_PROG_LIBTOOL`" if test ! "x$found_libtool" = "x" ; then if test -f acinclude.m4 ; then rm -f acinclude.m4.$$.backup $VERBOSE_ECHO "cat acinclude.m4 > acinclude.m4.$$.backup" cat acinclude.m4 > acinclude.m4.$$.backup fi $VERBOSE_ECHO "cat \"$LIBTOOL_M4\" >> acinclude.m4" chmod u+w acinclude.m4 cat "$LIBTOOL_M4" >> acinclude.m4 # don't keep doing this RUN_RECURSIVE=no export RUN_RECURSIVE untrap_abnormal $ECHO $ECHO "Restarting the preparation steps with libtool macros in acinclude.m4" $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" exit $? fi fi } ########################### # MANUAL_AUTOGEN FUNCTION # ########################### manual_autogen ( ) { ################################################## # Manual preparation steps taken are as follows: # # aclocal [-I m4] # # libtoolize --automake -c -f # # aclocal [-I m4] # # autoconf -f # # autoheader # # automake -a -c -f # ################################################## ########### # aclocal # ########### $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS" aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$aclocal_output" if [ ! $ret = 0 ] ; then $ECHO "ERROR: $ACLOCAL failed" && exit 2 ; fi ############## # libtoolize # ############## if libtoolize_needed ; then if [ "x$HAVE_LIBTOOLIZE" = "xyes" ] ; then $VERBOSE_ECHO "$LIBTOOLIZE $LIBTOOLIZE_OPTIONS" libtoolize_output="`$LIBTOOLIZE $LIBTOOLIZE_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$libtoolize_output" if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi else if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then $VERBOSE_ECHO "$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS" libtoolize_output="`$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$libtoolize_output" if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi fi fi ########### # aclocal # ########### # re-run again as instructed by libtoolize $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS" aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$aclocal_output" # libtoolize might put ltmain.sh in the wrong place if test -f ltmain.sh ; then if test ! -f "${_aux_dir}/ltmain.sh" ; then $ECHO $ECHO "Warning: $LIBTOOLIZE is creating ltmain.sh in the wrong directory" $ECHO $ECHO "Fortunately, the problem can be worked around by simply copying the" $ECHO "file to the appropriate location (${_aux_dir}/). This has been done for you." $ECHO $VERBOSE_ECHO "cp -p ltmain.sh \"${_aux_dir}/ltmain.sh\"" cp -p ltmain.sh "${_aux_dir}/ltmain.sh" $ECHO $ECHO_N "Continuing build preparation ... $ECHO_C" fi fi # ltmain.sh if [ "x$DOWNLOAD" = "xyes" ] ; then download_gnulib_config_guess fi fi # libtoolize_needed ############ # autoconf # ############ $VERBOSE_ECHO $VERBOSE_ECHO "$AUTOCONF $AUTOCONF_OPTIONS" autoconf_output="`$AUTOCONF $AUTOCONF_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$autoconf_output" if [ ! $ret = 0 ] ; then # retry without the -f and check for usage of macros that are too new ac2_59_macros="AC_C_RESTRICT AC_INCLUDES_DEFAULT AC_LANG_ASSERT AC_LANG_WERROR AS_SET_CATFILE" ac2_55_macros="AC_COMPILER_IFELSE AC_FUNC_MBRTOWC AC_HEADER_STDBOOL AC_LANG_CONFTEST AC_LANG_SOURCE AC_LANG_PROGRAM AC_LANG_CALL AC_LANG_FUNC_TRY_LINK AC_MSG_FAILURE AC_PREPROC_IFELSE" ac2_54_macros="AC_C_BACKSLASH_A AC_CONFIG_LIBOBJ_DIR AC_GNU_SOURCE AC_PROG_EGREP AC_PROG_FGREP AC_REPLACE_FNMATCH AC_FUNC_FNMATCH_GNU AC_FUNC_REALLOC AC_TYPE_MBSTATE_T" macros_to_search="" ac_major="`echo ${AUTOCONF_VERSION}. | cut -d. -f1 | sed 's/[^0-9]//g'`" ac_minor="`echo ${AUTOCONF_VERSION}. | cut -d. -f2 | sed 's/[^0-9]//g'`" if [ $ac_major -lt 2 ] ; then macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros" else if [ $ac_minor -lt 54 ] ; then macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros" elif [ $ac_minor -lt 55 ] ; then macros_to_search="$ac2_59_macros $ac2_55_macros" elif [ $ac_minor -lt 59 ] ; then macros_to_search="$ac2_59_macros" fi fi configure_ac_macros=__none__ for feature in $macros_to_search ; do $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" found="`grep \"^$feature.*\" $CONFIGURE`" if [ ! "x$found" = "x" ] ; then if [ "x$configure_ac_macros" = "x__none__" ] ; then configure_ac_macros="$feature" else configure_ac_macros="$feature $configure_ac_macros" fi fi done if [ ! "x$configure_ac_macros" = "x__none__" ] ; then $ECHO $ECHO "Warning: Unsupported macros were found in $CONFIGURE" $ECHO $ECHO "The `basename \"$CONFIGURE\"` file was scanned in order to determine if any" $ECHO "unsupported macros are used that exceed the minimum version" $ECHO "settings specified within this file. As such, the following macros" $ECHO "should be removed from configure.ac or the version numbers in this" $ECHO "file should be increased:" $ECHO $ECHO "$configure_ac_macros" $ECHO $ECHO $ECHO_N "Ignorantly continuing build preparation ... $ECHO_C" fi ################### # autoconf, retry # ################### $VERBOSE_ECHO $VERBOSE_ECHO "$AUTOCONF" autoconf_output="`$AUTOCONF 2>&1`" ret=$? $VERBOSE_ECHO "$autoconf_output" if [ ! $ret = 0 ] ; then # test if libtool is busted libtool_failure "$autoconf_output" # let the user know what went wrong cat <"]) fi case "$target" in linux) os=linux ;; windows) os=windows ;; osx) os=osx ;; *) AC_MSG_ERROR(["Unrecognised target OS: $target"]) ;; esac AM_CONDITIONAL(LINUX, test "x$os" = "xlinux") AM_CONDITIONAL(WINDOWS, test "x$os" = "xwindows") AM_CONDITIONAL(OSX, test "x$os" = "xosx") # ------------------------------------------------------------------------------ # --enable-vst. VST compilation is disabled by default # # WITH_VST will be passed to gcc as -DWITH_VST # # AC_ARG_ENABLE ( # feature, [--enable-] + [feature], eg --enable-vst # help-string, # [action-if-given], == gcc ... -DWITH_VST # [action-if-not-given]) not used here AC_ARG_ENABLE( vst, AS_HELP_STRING([--enable-vst], [enable vst support]), [AC_DEFINE(WITH_VST)] ) # ------------------------------------------------------------------------------ # Check for C++ compiler AC_PROG_CXX # Check for C compiler (TODO - is that really needed?) AC_PROG_CC # Check for make AC_PROG_MAKE_SET # ------------------------------------------------------------------------------ # Check for libraries. AC_CHECK_LIB( [pthread], [pthread_exit], [], [AC_MSG_ERROR([error: library 'pthread' not found!])] ) # ------------------------------------------------------------------------------ # Check for generic headers (fltk, rtaudio and libsndfile are static, # we ask if headers are available) AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [FL/Fl.H], [], [AC_MSG_ERROR([library 'fltk' not found!])] ) AC_LANG_POP AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [RtMidi.h], [], [AC_MSG_ERROR([library 'rtMidi' not found!])] ) AC_LANG_POP AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [jansson.h], [], [AC_MSG_ERROR([library 'Jansson' not found!])] ) AC_LANG_POP AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [sndfile.h], [], [AC_MSG_ERROR([library 'libsndfile' not found!])] ) AC_LANG_POP #~ AC_LANG_PUSH([C++]) #~ AC_CHECK_HEADER( #~ [RtAudio.h], #~ [], #~ [AC_MSG_ERROR([library 'RtAudio' not found!])] #~ ) #~ AC_LANG_POP # brutal and temporary hack for OS X: don't use pkg-config if test "x$os" = "xosx"; then AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [samplerate.h], [], [AC_MSG_ERROR([library 'samplerate' not found!])] ) AC_LANG_POP else # PKG_CHECK_MODULES( # SAMPLERATE, # samplerate >= 0.1.8, # [], # AC_MSG_ERROR([library 'libsamplerate' not found!]) # ) AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [samplerate.h], [], [AC_MSG_ERROR([library 'samplerate' not found!])] ) AC_LANG_POP fi # ------------------------------------------------------------------------------ # Check for linux header files. if test "x$os" = "xlinux"; then AC_LANG_PUSH([C++]) AC_CHECK_HEADER( [X11/xpm.h], [], [AC_MSG_ERROR([missing xpm.h, maybe you need to install the libxpm-dev package?])] ) AC_LANG_POP fi # ------------------------------------------------------------------------------ # finalizing AC_CONFIG_FILES([Makefile]) AC_OUTPUT giada-0.11.2/src/000077500000000000000000000000001264622563000134355ustar00rootroot00000000000000giada-0.11.2/src/core/000077500000000000000000000000001264622563000143655ustar00rootroot00000000000000giada-0.11.2/src/core/.dirstamp000066400000000000000000000000001264622563000161770ustar00rootroot00000000000000giada-0.11.2/src/core/channel.cpp000066400000000000000000000237411264622563000165100ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../utils/log.h" #include "../gui/elems/ge_channel.h" #include "channel.h" #include "pluginHost.h" #include "kernelMidi.h" #include "patch_DEPR_.h" #include "patch.h" #include "wave.h" #include "mixer.h" #include "mixerHandler.h" #include "conf.h" #include "patch.h" #include "waveFx.h" #include "midiMapConf.h" extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; extern MidiMapConf G_MidiMap; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif Channel::Channel(int type, int status, int bufferSize) : bufferSize(bufferSize), type (type), status (status), key (0), volume (DEFAULT_VOL), volume_i (1.0f), volume_d (0.0f), panLeft (1.0f), panRight (1.0f), mute_i (false), mute_s (false), mute (false), solo (false), hasActions(false), recStatus (REC_STOPPED), vChan (NULL), guiChannel(NULL), midiIn (true), midiInKeyPress (0x0), midiInKeyRel (0x0), midiInKill (0x0), midiInVolume (0x0), midiInMute (0x0), midiInSolo (0x0), midiOutL (false), midiOutLplaying(0x0), midiOutLmute (0x0), midiOutLsolo (0x0) { vChan = (float *) malloc(bufferSize * sizeof(float)); if (!vChan) gLog("[Channel::allocVchan] unable to alloc memory for vChan\n"); memset(vChan, 0, bufferSize * sizeof(float)); } /* -------------------------------------------------------------------------- */ Channel::~Channel() { status = STATUS_OFF; if (vChan) free(vChan); } /* -------------------------------------------------------------------------- */ void Channel::copy(const Channel *src) { key = src->key; volume = src->volume; volume_i = src->volume_i; volume_d = src->volume_d; panLeft = src->panLeft; panRight = src->panRight; mute_i = src->mute_i; mute_s = src->mute_s; mute = src->mute; solo = src->solo; hasActions = src->hasActions; recStatus = src->recStatus; midiIn = src->midiIn; midiInKeyPress = src->midiInKeyPress; midiInKeyRel = src->midiInKeyRel; midiInKill = src->midiInKill; midiInVolume = src->midiInVolume; midiInMute = src->midiInMute; midiInSolo = src->midiInSolo; midiOutL = src->midiOutL; midiOutLplaying = src->midiOutLplaying; midiOutLmute = src->midiOutLmute; midiOutLsolo = src->midiOutLsolo; /* clone plugins */ #ifdef WITH_VST for (unsigned i=0; iplugins.size(); i++) G_PluginHost.clonePlugin(*src->plugins.at(i), PluginHost::CHANNEL, this); #endif /* clone actions */ for (unsigned i=0; ichan == src->index) recorder::rec(index, a->type, a->frame, a->iValue, a->fValue); } } } /* -------------------------------------------------------------------------- */ void Channel::sendMidiLmessage(uint32_t learn, const MidiMapConf::message_t &msg) { gLog("[channel::sendMidiLmessage] learn=%#X, chan=%d, msg=%#X, offset=%d\n", learn, msg.channel, msg.value, msg.offset); /* isolate 'channel' from learnt message and offset it as requested by 'nn' * in the midimap configuration file. */ uint32_t out = ((learn & 0x00FF0000) >> 16) << msg.offset; /* merge the previously prepared channel into final message, and finally * send it. */ out |= msg.value | (msg.channel << 24); kernelMidi::send(out); } /* -------------------------------------------------------------------------- */ void Channel::readPatchMidiIn_DEPR_(int i) { midiIn = G_Patch_DEPR_.getMidiValue(i, "In"); midiInKeyPress = G_Patch_DEPR_.getMidiValue(i, "InKeyPress"); midiInKeyRel = G_Patch_DEPR_.getMidiValue(i, "InKeyRel"); midiInKill = G_Patch_DEPR_.getMidiValue(i, "InKill"); midiInVolume = G_Patch_DEPR_.getMidiValue(i, "InVolume"); midiInMute = G_Patch_DEPR_.getMidiValue(i, "InMute"); midiInSolo = G_Patch_DEPR_.getMidiValue(i, "InSolo"); } void Channel::readPatchMidiOut_DEPR_(int i) { midiOutL = G_Patch_DEPR_.getMidiValue(i, "OutL"); midiOutLplaying = G_Patch_DEPR_.getMidiValue(i, "OutLplaying"); midiOutLmute = G_Patch_DEPR_.getMidiValue(i, "OutLmute"); midiOutLsolo = G_Patch_DEPR_.getMidiValue(i, "OutLsolo"); } /* -------------------------------------------------------------------------- */ bool Channel::isPlaying() { return status & (STATUS_PLAY | STATUS_ENDING); } /* -------------------------------------------------------------------------- */ int Channel::writePatch(int i, bool isProject) { Patch::channel_t pch; pch.type = type; pch.key = key; pch.index = index; pch.column = guiChannel->getColumnIndex(); pch.mute = mute; pch.mute_s = mute_s; pch.solo = solo; pch.volume = volume; pch.panLeft = panLeft; pch.panRight = panRight; pch.midiIn = midiIn; pch.midiInKeyPress = midiInKeyPress; pch.midiInKeyRel = midiInKeyRel; pch.midiInKill = midiInKill; pch.midiInVolume = midiInVolume; pch.midiInMute = midiInMute; pch.midiInSolo = midiInSolo; pch.midiOutL = midiOutL; pch.midiOutLplaying = midiOutLplaying; pch.midiOutLmute = midiOutLmute; pch.midiOutLsolo = midiOutLsolo; for (unsigned i=0; ichan == index) { Patch::action_t pac; pac.type = action->type; pac.frame = action->frame; pac.fValue = action->fValue; pac.iValue = action->iValue; pch.actions.push_back(pac); } } } #ifdef WITH_VST unsigned numPlugs = G_PluginHost.countPlugins(PluginHost::CHANNEL, this); for (unsigned i=0; istatus) { Patch::plugin_t pp; pp.path = pPlugin->pathfile; pp.bypass = pPlugin->bypass; for (int k=0; kgetNumParams(); k++) pp.params.push_back(pPlugin->getParam(k)); pch.plugins.push_back(pp); } } #endif G_Patch.channels.push_back(pch); return G_Patch.channels.size() - 1; } /* -------------------------------------------------------------------------- */ int Channel::readPatch(const string &path, int i) { int ret = 1; Patch::channel_t *pch = &G_Patch.channels.at(i); key = pch->key; type = pch->type; index = pch->index; mute = pch->mute; mute_s = pch->mute_s; solo = pch->solo; volume = pch->volume; panLeft = pch->panLeft; panRight = pch->panRight; midiIn = pch->midiIn; midiInKeyPress = pch->midiInKeyPress; midiInKeyRel = pch->midiInKeyRel; midiInKill = pch->midiInKill; midiInVolume = pch->midiInVolume; midiInMute = pch->midiInMute; midiInSolo = pch->midiInSolo; midiOutL = pch->midiOutL; midiOutLplaying = pch->midiOutLplaying; midiOutLmute = pch->midiOutLmute; midiOutLsolo = pch->midiOutLsolo; for (unsigned k=0; kactions.size(); k++) { Patch::action_t *ac = &pch->actions.at(k); recorder::rec(index, ac->type, ac->frame, ac->iValue, ac->fValue); } #ifdef WITH_VST for (unsigned k=0; kplugins.size(); k++) { Patch::plugin_t *ppl = &pch->plugins.at(k); Plugin *plugin = G_PluginHost.addPlugin(ppl->path.c_str(), PluginHost::CHANNEL, this); if (plugin != NULL) { plugin->bypass = ppl->bypass; for (unsigned j=0; jparams.size(); j++) plugin->setParam(j, ppl->params.at(j)); ret &= 1; } else ret &= 0; } #endif return ret; } /* -------------------------------------------------------------------------- */ void Channel::sendMidiLmute() { if (!midiOutL || midiOutLmute == 0x0) return; if (mute) sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOn); else sendMidiLmessage(midiOutLsolo, G_MidiMap.muteOff); } /* -------------------------------------------------------------------------- */ void Channel::sendMidiLsolo() { if (!midiOutL || midiOutLsolo == 0x0) return; if (solo) sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOn); else sendMidiLmessage(midiOutLsolo, G_MidiMap.soloOff); } /* -------------------------------------------------------------------------- */ void Channel::sendMidiLplay() { if (!midiOutL || midiOutLplaying == 0x0) return; switch (status) { case STATUS_OFF: sendMidiLmessage(midiOutLplaying, G_MidiMap.stopped); break; case STATUS_PLAY: sendMidiLmessage(midiOutLplaying, G_MidiMap.playing); break; case STATUS_WAIT: sendMidiLmessage(midiOutLplaying, G_MidiMap.waiting); break; case STATUS_ENDING: sendMidiLmessage(midiOutLplaying, G_MidiMap.stopping); } } giada-0.11.2/src/core/channel.h000066400000000000000000000142701264622563000161520ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef CHANNEL_H #define CHANNEL_H #include #include "../utils/utils.h" #include "midiMapConf.h" #include "const.h" #include "recorder.h" using std::vector; #ifdef WITH_VST /* before including aeffetx(x).h we must define __cdecl, otherwise VST * headers can't be compiled correctly. In windows __cdecl is already * defined. */ #ifdef __GNUC__ #ifndef _WIN32 #define __cdecl #endif #endif #include "../deps/vst/aeffectx.h" #endif using std::string; class Channel { protected: /* bufferSize * size of every buffer in this channel (vChan, pChan) */ int bufferSize; /* sendMidiLMessage * compose a MIDI message by merging bytes from MidiMap conf class, and send * it to KernelMidi. */ void sendMidiLmessage(uint32_t learn, const MidiMapConf::message_t &msg); public: Channel(int type, int status, int bufferSize); virtual ~Channel(); /* copy * Make a shallow copy (no vChan/pChan allocation) of another channel. */ virtual void copy(const Channel *src) = 0; /* writePatch * Fill a patch with channel values. Returns the index of the last * Patch::channel_t added. */ virtual int writePatch(int i, bool isProject); /* readPatch * Fill channel with data from patch. */ virtual int readPatch_DEPR_(const char *file, int i) = 0; virtual int readPatch(const string &basePath, int i); /* process * merge vChannels into buffer, plus plugin processing (if any). */ virtual void process(float *buffer) = 0; /* start * action to do when channel starts. doQuantize = false (don't * quantize) when Mixer is reading actions from Recorder::. */ virtual void start(int frame, bool doQuantize) = 0; /* stop * action to do when channel is stopped normally (via key or MIDI). */ virtual void stop() = 0; /* kill * action to do when channel stops abruptly. */ virtual void kill(int frame) = 0; /* mute * action to do when channel is muted. If internal == true, set * internal mute without altering main mute. */ virtual void setMute (bool internal) = 0; virtual void unsetMute(bool internal) = 0; /* empty * free any associated resources (e.g. waveform for SAMPLE). */ virtual void empty() = 0; /* stopBySeq * action to do when channel is stopped by sequencer. */ virtual void stopBySeq() = 0; /* quantize * start channel according to quantizer. Index = array index of * mixer::channels, used by recorder. LocalFrame = frame within buffer. * GloalFrame = actual frame from mixer. */ virtual void quantize(int index, int localFrame, int globalFrame) = 0; /* onZero * action to do when frame goes to zero, i.e. sequencer restart. */ virtual void onZero(int frame) = 0; /* onBar * action to do when a bar has passed. */ virtual void onBar(int frame) = 0; /* parseAction * do something on a recorded action. Parameters: * action *a - action to parse * localFrame - frame number of the processed buffer * globalFrame - actual frame in Mixer */ virtual void parseAction(recorder::action *a, int localFrame, int globalFrame) = 0; /* rewind * rewind channel when rewind button is pressed. */ virtual void rewind() = 0; /* ------------------------------------------------------------------------ */ int index; // unique id int type; // midi or sample int status; // status: see const.h int key; // keyboard button float volume; // global volume float volume_i; // internal volume float volume_d; // delta volume (for envelope) float panLeft; float panRight; bool mute_i; // internal mute bool mute_s; // previous mute status after being solo'd bool mute; // global mute bool solo; bool hasActions; // has something recorded int recStatus; // status of recordings (waiting, ending, ...) float *vChan; // virtual channel class gChannel *guiChannel; // pointer to a gChannel object, part of the GUI // TODO - midi structs, please bool midiIn; // enable midi input uint32_t midiInKeyPress; uint32_t midiInKeyRel; uint32_t midiInKill; uint32_t midiInVolume; uint32_t midiInMute; uint32_t midiInSolo; /* midiOutL* * Enable MIDI lightning output, plus a set of midi lighting event to be sent * to a device. Those events basically contains the MIDI channel, everything * else gets stripped out. */ bool midiOutL; uint32_t midiOutLplaying; uint32_t midiOutLmute; uint32_t midiOutLsolo; #ifdef WITH_VST vector plugins; #endif /* ------------------------------------------------------------------------ */ /* isPlaying * tell wether the channel is playing or is stopped. */ bool isPlaying(); /* readPatchMidiIn * read from patch all midi-related parameters such as keypress, mute * and so on. */ void readPatchMidiIn_DEPR_(int i); void readPatchMidiOut_DEPR_(int i); /* sendMidiL* * send MIDI lightning events to a physical device. */ void sendMidiLmute(); void sendMidiLsolo(); void sendMidiLplay(); }; #endif giada-0.11.2/src/core/conf.cpp000066400000000000000000000416501264622563000160240ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * conf * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "conf.h" #include "const.h" #include "../utils/utils.h" #include "../utils/log.h" using std::string; Conf::Conf() { /* Initialize confFilePath, i.e. the configuration file. In windows it is in * the same dir of the .exe, while in Linux and OS X in ~/.giada */ #if defined(__linux__) || defined(__APPLE__) confFilePath = gGetHomePath() + gGetSlash() + CONF_FILENAME; confDirPath = gGetHomePath() + gGetSlash(); #elif defined(_WIN32) confFilePath = CONF_FILENAME; confDirPath = ""; #endif } /* -------------------------------------------------------------------------- */ int Conf::createConfigFolder() { #if defined(__linux__) || defined(__APPLE__) if (gDirExists(confDirPath)) return 1; gLog("[Conf::createConfigFolder] .giada folder not present. Updating...\n"); if (gMkdir(confDirPath)) { gLog("[Conf::createConfigFolder] status: ok\n"); return 1; } else { gLog("[Conf::createConfigFolder] status: error!\n"); return 0; } #else // windows return 1; #endif } /* -------------------------------------------------------------------------- */ void Conf::init() { header = "GIADACFG"; logMode = LOG_MODE_MUTE; soundSystem = DEFAULT_SOUNDSYS; soundDeviceOut = DEFAULT_SOUNDDEV_OUT; soundDeviceIn = DEFAULT_SOUNDDEV_IN; samplerate = DEFAULT_SAMPLERATE; buffersize = DEFAULT_BUFSIZE; delayComp = DEFAULT_DELAYCOMP; limitOutput = false; rsmpQuality = 0; midiPortIn = DEFAULT_MIDI_PORT_IN; noNoteOff = false; midiMapPath = ""; midiPortOut = DEFAULT_MIDI_PORT_OUT; midiSync = MIDI_SYNC_NONE; midiTCfps = 25.0f; midiInRewind = 0x0; midiInStartStop = 0x0; midiInActionRec = 0x0; midiInInputRec = 0x0; midiInVolumeIn = 0x0; midiInVolumeOut = 0x0; midiInBeatDouble = 0x0; midiInBeatHalf = 0x0; midiInMetronome = 0x0; pluginPath = ""; patchPath = ""; samplePath = ""; recsStopOnChanHalt = false; chansStopOnSeqHalt = false; treatRecsAsLoops = false; resizeRecordings = true; actionEditorZoom = 100; actionEditorGridOn = false; actionEditorGridVal = 1; mainWindowX = 0; mainWindowY = 0; mainWindowW = GUI_WIDTH; mainWindowH = GUI_HEIGHT; pianoRollY = -1; pianoRollH = 422; } /* -------------------------------------------------------------------------- */ int Conf::read() { init(); jRoot = json_load_file(confFilePath.c_str(), 0, &jError); if (!jRoot) { gLog("[Conf::read] unable to read configuration file! Error on line %d: %s\n", jError.line, jError.text); return 0; } if (!checkObject(jRoot, "root element")) { json_decref(jRoot); return 0; } if (!setString(jRoot, CONF_KEY_HEADER, header)) return 0; if (!setInt(jRoot, CONF_KEY_LOG_MODE, logMode)) return 0; if (!setInt(jRoot, CONF_KEY_SOUND_SYSTEM, soundSystem)) return 0; if (!setInt(jRoot, CONF_KEY_SOUND_DEVICE_OUT, soundDeviceOut)) return 0; if (!setInt(jRoot, CONF_KEY_SOUND_DEVICE_IN, soundDeviceIn)) return 0; if (!setInt(jRoot, CONF_KEY_CHANNELS_OUT, channelsOut)) return 0; if (!setInt(jRoot, CONF_KEY_CHANNELS_IN, channelsIn)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLERATE, samplerate)) return 0; if (!setInt(jRoot, CONF_KEY_BUFFER_SIZE, buffersize)) return 0; if (!setInt(jRoot, CONF_KEY_DELAY_COMPENSATION, delayComp)) return 0; if (!setBool(jRoot, CONF_KEY_LIMIT_OUTPUT, limitOutput)) return 0; if (!setInt(jRoot, CONF_KEY_RESAMPLE_QUALITY, rsmpQuality)) return 0; if (!setInt(jRoot, CONF_KEY_MIDI_SYSTEM, midiSystem)) return 0; if (!setInt(jRoot, CONF_KEY_MIDI_PORT_OUT, midiPortOut)) return 0; if (!setInt(jRoot, CONF_KEY_MIDI_PORT_IN, midiPortIn)) return 0; if (!setBool(jRoot, CONF_KEY_NO_NOTE_OFF, noNoteOff)) return 0; if (!setString(jRoot, CONF_KEY_MIDIMAP_PATH, midiMapPath)) return 0; if (!setString(jRoot, CONF_KEY_LAST_MIDIMAP, lastFileMap)) return 0; if (!setInt(jRoot, CONF_KEY_MIDI_SYNC, midiSync)) return 0; if (!setFloat(jRoot, CONF_KEY_MIDI_TC_FPS, midiTCfps)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_REWIND, midiInRewind)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_START_STOP, midiInStartStop)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_ACTION_REC, midiInActionRec)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_INPUT_REC, midiInInputRec)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_METRONOME, midiInMetronome)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_VOLUME_IN, midiInVolumeIn)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_VOLUME_OUT, midiInVolumeOut)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_BEAT_DOUBLE, midiInBeatDouble)) return 0; if (!setUint32(jRoot, CONF_KEY_MIDI_IN_BEAT_HALF, midiInBeatHalf)) return 0; if (!setBool(jRoot, CONF_KEY_RECS_STOP_ON_CHAN_HALT, recsStopOnChanHalt)) return 0; if (!setBool(jRoot, CONF_KEY_CHANS_STOP_ON_SEQ_HALT, chansStopOnSeqHalt)) return 0; if (!setBool(jRoot, CONF_KEY_TREAT_RECS_AS_LOOPS, treatRecsAsLoops)) return 0; if (!setBool(jRoot, CONF_KEY_RESIZE_RECORDINGS, resizeRecordings)) return 0; if (!setString(jRoot, CONF_KEY_PLUGINS_PATH, pluginPath)) return 0; if (!setString(jRoot, CONF_KEY_PATCHES_PATH, patchPath)) return 0; if (!setString(jRoot, CONF_KEY_SAMPLES_PATH, samplePath)) return 0; if (!setInt(jRoot, CONF_KEY_MAIN_WINDOW_X, mainWindowX)) return 0; if (!setInt(jRoot, CONF_KEY_MAIN_WINDOW_Y, mainWindowY)) return 0; if (!setInt(jRoot, CONF_KEY_MAIN_WINDOW_W, mainWindowW)) return 0; if (!setInt(jRoot, CONF_KEY_MAIN_WINDOW_H, mainWindowH)) return 0; if (!setInt(jRoot, CONF_KEY_BROWSER_X, browserX)) return 0; if (!setInt(jRoot, CONF_KEY_BROWSER_Y, browserY)) return 0; if (!setInt(jRoot, CONF_KEY_BROWSER_W, browserW)) return 0; if (!setInt(jRoot, CONF_KEY_BROWSER_H, browserH)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_X, actionEditorX)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_Y, actionEditorY)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_W, actionEditorW)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_H, actionEditorH)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_ZOOM, actionEditorZoom)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_GRID_VAL, actionEditorGridVal)) return 0; if (!setInt(jRoot, CONF_KEY_ACTION_EDITOR_GRID_ON, actionEditorGridOn)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_X, sampleEditorX)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_Y, sampleEditorY)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_W, sampleEditorW)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_H, sampleEditorH)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_GRID_VAL, sampleEditorGridVal)) return 0; if (!setInt(jRoot, CONF_KEY_SAMPLE_EDITOR_GRID_ON, sampleEditorGridOn)) return 0; if (!setInt(jRoot, CONF_KEY_PIANO_ROLL_Y, pianoRollY)) return 0; if (!setInt(jRoot, CONF_KEY_PIANO_ROLL_H, pianoRollH)) return 0; if (!setInt(jRoot, CONF_KEY_PLUGIN_LIST_X, pluginListX)) return 0; if (!setInt(jRoot, CONF_KEY_PLUGIN_LIST_Y, pluginListY)) return 0; if (!setInt(jRoot, CONF_KEY_CONFIG_X, configX)) return 0; if (!setInt(jRoot, CONF_KEY_CONFIG_Y, configY)) return 0; if (!setInt(jRoot, CONF_KEY_BPM_X, bpmX)) return 0; if (!setInt(jRoot, CONF_KEY_BPM_Y, bpmY)) return 0; if (!setInt(jRoot, CONF_KEY_BEATS_X, beatsX)) return 0; if (!setInt(jRoot, CONF_KEY_BEATS_Y, beatsY)) return 0; if (!setInt(jRoot, CONF_KEY_ABOUT_X, aboutX)) return 0; if (!setInt(jRoot, CONF_KEY_ABOUT_Y, aboutY)) return 0; json_decref(jRoot); sanitize(); return 1; } /* -------------------------------------------------------------------------- */ int Conf::write() { if (!createConfigFolder()) return 0; jRoot = json_object(); json_object_set_new(jRoot, CONF_KEY_HEADER, json_string(header.c_str())); json_object_set_new(jRoot, CONF_KEY_LOG_MODE, json_integer(logMode)); json_object_set_new(jRoot, CONF_KEY_SOUND_SYSTEM, json_integer(soundSystem)); json_object_set_new(jRoot, CONF_KEY_SOUND_DEVICE_OUT, json_integer(soundDeviceOut)); json_object_set_new(jRoot, CONF_KEY_SOUND_DEVICE_IN, json_integer(soundDeviceIn)); json_object_set_new(jRoot, CONF_KEY_CHANNELS_OUT, json_integer(channelsOut)); json_object_set_new(jRoot, CONF_KEY_CHANNELS_IN, json_integer(channelsIn)); json_object_set_new(jRoot, CONF_KEY_SAMPLERATE, json_integer(samplerate)); json_object_set_new(jRoot, CONF_KEY_BUFFER_SIZE, json_integer(buffersize)); json_object_set_new(jRoot, CONF_KEY_DELAY_COMPENSATION, json_integer(delayComp)); json_object_set_new(jRoot, CONF_KEY_LIMIT_OUTPUT, json_boolean(limitOutput)); json_object_set_new(jRoot, CONF_KEY_RESAMPLE_QUALITY, json_integer(rsmpQuality)); json_object_set_new(jRoot, CONF_KEY_MIDI_SYSTEM, json_integer(midiSystem)); json_object_set_new(jRoot, CONF_KEY_MIDI_PORT_OUT, json_integer(midiPortOut)); json_object_set_new(jRoot, CONF_KEY_MIDI_PORT_IN, json_integer(midiPortIn)); json_object_set_new(jRoot, CONF_KEY_NO_NOTE_OFF, json_boolean(noNoteOff)); json_object_set_new(jRoot, CONF_KEY_MIDIMAP_PATH, json_string(midiMapPath.c_str())); json_object_set_new(jRoot, CONF_KEY_LAST_MIDIMAP, json_string(lastFileMap.c_str())); json_object_set_new(jRoot, CONF_KEY_MIDI_SYNC, json_integer(midiSync)); json_object_set_new(jRoot, CONF_KEY_MIDI_TC_FPS, json_real(midiTCfps)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_REWIND, json_integer(midiInRewind)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_START_STOP, json_integer(midiInStartStop)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_ACTION_REC, json_integer(midiInActionRec)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_INPUT_REC, json_integer(midiInInputRec)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_METRONOME, json_integer(midiInMetronome)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_VOLUME_IN, json_integer(midiInVolumeIn)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_VOLUME_OUT, json_integer(midiInVolumeOut)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_BEAT_DOUBLE, json_integer(midiInBeatDouble)); json_object_set_new(jRoot, CONF_KEY_MIDI_IN_BEAT_HALF, json_integer(midiInBeatHalf)); json_object_set_new(jRoot, CONF_KEY_RECS_STOP_ON_CHAN_HALT, json_boolean(recsStopOnChanHalt)); json_object_set_new(jRoot, CONF_KEY_CHANS_STOP_ON_SEQ_HALT, json_boolean(chansStopOnSeqHalt)); json_object_set_new(jRoot, CONF_KEY_TREAT_RECS_AS_LOOPS, json_boolean(treatRecsAsLoops)); json_object_set_new(jRoot, CONF_KEY_RESIZE_RECORDINGS, json_boolean(resizeRecordings)); json_object_set_new(jRoot, CONF_KEY_PLUGINS_PATH, json_string(pluginPath.c_str())); json_object_set_new(jRoot, CONF_KEY_PATCHES_PATH, json_string(patchPath.c_str())); json_object_set_new(jRoot, CONF_KEY_SAMPLES_PATH, json_string(samplePath.c_str())); json_object_set_new(jRoot, CONF_KEY_MAIN_WINDOW_X, json_integer(mainWindowX)); json_object_set_new(jRoot, CONF_KEY_MAIN_WINDOW_Y, json_integer(mainWindowY)); json_object_set_new(jRoot, CONF_KEY_MAIN_WINDOW_W, json_integer(mainWindowW)); json_object_set_new(jRoot, CONF_KEY_MAIN_WINDOW_H, json_integer(mainWindowH)); json_object_set_new(jRoot, CONF_KEY_BROWSER_X, json_integer(browserX)); json_object_set_new(jRoot, CONF_KEY_BROWSER_Y, json_integer(browserY)); json_object_set_new(jRoot, CONF_KEY_BROWSER_W, json_integer(browserW)); json_object_set_new(jRoot, CONF_KEY_BROWSER_H, json_integer(browserH)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_X, json_integer(actionEditorX)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_Y, json_integer(actionEditorY)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_W, json_integer(actionEditorW)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_H, json_integer(actionEditorH)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_ZOOM, json_integer(actionEditorZoom)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_GRID_VAL, json_integer(actionEditorGridVal)); json_object_set_new(jRoot, CONF_KEY_ACTION_EDITOR_GRID_ON, json_integer(actionEditorGridOn)); json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_X, json_integer(sampleEditorX)); json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_Y, json_integer(sampleEditorY)); json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_W, json_integer(sampleEditorW)); json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_H, json_integer(sampleEditorH)); json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_GRID_VAL, json_integer(sampleEditorGridVal)); json_object_set_new(jRoot, CONF_KEY_SAMPLE_EDITOR_GRID_ON, json_integer(sampleEditorGridOn)); json_object_set_new(jRoot, CONF_KEY_PIANO_ROLL_Y, json_integer(pianoRollY)); json_object_set_new(jRoot, CONF_KEY_PIANO_ROLL_H, json_integer(pianoRollH)); json_object_set_new(jRoot, CONF_KEY_PLUGIN_LIST_X, json_integer(pluginListX)); json_object_set_new(jRoot, CONF_KEY_PLUGIN_LIST_Y, json_integer(pluginListY)); json_object_set_new(jRoot, CONF_KEY_CONFIG_X, json_integer(configX)); json_object_set_new(jRoot, CONF_KEY_CONFIG_Y, json_integer(configY)); json_object_set_new(jRoot, CONF_KEY_BPM_X, json_integer(bpmX)); json_object_set_new(jRoot, CONF_KEY_BPM_Y, json_integer(bpmY)); json_object_set_new(jRoot, CONF_KEY_BEATS_X, json_integer(beatsX)); json_object_set_new(jRoot, CONF_KEY_BEATS_Y, json_integer(beatsY)); json_object_set_new(jRoot, CONF_KEY_ABOUT_X, json_integer(aboutX)); json_object_set_new(jRoot, CONF_KEY_ABOUT_Y, json_integer(aboutY)); if (json_dump_file(jRoot, confFilePath.c_str(), JSON_INDENT(2)) != 0) { gLog("[Conf::write] unable to write configuration file!\n"); return 0; } return 1; } /* -------------------------------------------------------------------------- */ void Conf::sanitize() { if (!(soundSystem & SYS_API_ANY)) soundSystem = DEFAULT_SOUNDSYS; if (soundDeviceOut < 0) soundDeviceOut = DEFAULT_SOUNDDEV_OUT; if (soundDeviceIn < -1) soundDeviceIn = DEFAULT_SOUNDDEV_IN; if (channelsOut < 0) channelsOut = 0; if (channelsIn < 0) channelsIn = 0; if (buffersize < 8 || buffersize > 4096) buffersize = DEFAULT_BUFSIZE; if (delayComp < 0) delayComp = DEFAULT_DELAYCOMP; if (midiPortOut < -1) midiPortOut = DEFAULT_MIDI_SYSTEM; if (midiPortOut < -1) midiPortOut = DEFAULT_MIDI_PORT_OUT; if (midiPortIn < -1) midiPortIn = DEFAULT_MIDI_PORT_IN; if (browserX < 0) browserX = 0; if (browserY < 0) browserY = 0; if (browserW < 396) browserW = 396; if (browserH < 302) browserH = 302; if (actionEditorX < 0) actionEditorX = 0; if (actionEditorY < 0) actionEditorY = 0; if (actionEditorW < 640) actionEditorW = 640; if (actionEditorH < 176) actionEditorH = 176; if (actionEditorZoom < 100) actionEditorZoom = 100; if (actionEditorGridVal < 0) actionEditorGridVal = 0; if (actionEditorGridOn < 0) actionEditorGridOn = 0; if (pianoRollH <= 0) pianoRollH = 422; if (sampleEditorX < 0) sampleEditorX = 0; if (sampleEditorY < 0) sampleEditorY = 0; if (sampleEditorW < 500) sampleEditorW = 500; if (sampleEditorH < 292) sampleEditorH = 292; if (sampleEditorGridVal < 0) sampleEditorGridVal = 0; if (sampleEditorGridOn < 0) sampleEditorGridOn = 0; if (configX < 0) configX = 0; if (configY < 0) configY = 0; if (pluginListX < 0) pluginListX = 0; if (pluginListY < 0) pluginListY = 0; if (bpmX < 0) bpmX = 0; if (bpmY < 0) bpmY = 0; if (beatsX < 0) beatsX = 0; if (beatsY < 0) beatsY = 0; if (aboutX < 0) aboutX = 0; if (aboutY < 0) aboutY = 0; if (samplerate < 8000) samplerate = DEFAULT_SAMPLERATE; if (rsmpQuality < 0 || rsmpQuality > 4) rsmpQuality = 0; } giada-0.11.2/src/core/conf.h000066400000000000000000000057351264622563000154750ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * conf * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef __CONF_H__ #define __CONF_H__ #include #include #include "dataStorageJson.h" using std::string; class Conf : public DataStorageJson { private: string confFilePath; string confDirPath; /* init * Init Conf with default values. */ void init(); /* sanitize * Avoid funky values from config file. */ void sanitize(); /* createConfigFolder * Create local folder where to put the configuration file. Path differs from * OS to OS. */ int createConfigFolder(); public: Conf(); string header; int logMode; int soundSystem; int soundDeviceOut; int soundDeviceIn; int channelsOut; int channelsIn; int samplerate; int buffersize; int delayComp; bool limitOutput; int rsmpQuality; int midiSystem; int midiPortOut; int midiPortIn; bool noNoteOff; string midiMapPath; string lastFileMap; int midiSync; // see const.h float midiTCfps; uint32_t midiInRewind; uint32_t midiInStartStop; uint32_t midiInActionRec; uint32_t midiInInputRec; uint32_t midiInMetronome; uint32_t midiInVolumeIn; uint32_t midiInVolumeOut; uint32_t midiInBeatDouble; uint32_t midiInBeatHalf; bool recsStopOnChanHalt; bool chansStopOnSeqHalt; bool treatRecsAsLoops; bool resizeRecordings; string pluginPath; string patchPath; string samplePath; int mainWindowX, mainWindowY, mainWindowW, mainWindowH; int browserX, browserY, browserW, browserH; int actionEditorX, actionEditorY, actionEditorW, actionEditorH, actionEditorZoom; int actionEditorGridVal; int actionEditorGridOn; int sampleEditorX, sampleEditorY, sampleEditorW, sampleEditorH; int sampleEditorGridVal; int sampleEditorGridOn; int pianoRollY, pianoRollH; int pluginListX, pluginListY; int configX, configY; int bpmX, bpmY; int beatsX, beatsY; int aboutX, aboutY; int read(); int write(); }; #endif giada-0.11.2/src/core/const.h000066400000000000000000000452231264622563000156720ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * const.h * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef CONST_H #define CONST_H /* -- version --------------------------------------------------------------- */ #define G_VERSION_STR "0.11.2" #define G_APP_NAME "Giada" #define G_VERSION_MAJOR 0 #define G_VERSION_MINOR 11 #define G_VERSION_PATCH 2 #define CONF_FILENAME "giada.conf" /* -- GUI ------------------------------------------------------------------- */ #ifdef _WIN32 #define GUI_SLEEP 1000/24 #else #define GUI_SLEEP 1000000/24 // == 1.000.000 / 24 == 1/24 sec == 24 Hz #endif #define GUI_WIDTH 810 #define GUI_HEIGHT 510 #define COLOR_BD_0 fl_rgb_color(78, 78, 78) // border off #define COLOR_BD_1 fl_rgb_color(188, 188, 188) // border on #define COLOR_BG_0 fl_rgb_color(37, 37, 37) // bg off #define COLOR_BG_1 fl_rgb_color(78, 78, 78) // bg on (clicked) #define COLOR_BG_2 fl_rgb_color(177, 142, 142) // bg active (play, for some widgets) #define COLOR_BG_3 fl_rgb_color(28, 32, 80) // bg input rec #define COLOR_BG_4 fl_rgb_color(113, 31, 31) // bg action rec #define COLOR_ALERT fl_rgb_color(239, 75, 53) // peak meter alert #define COLOR_TEXT_0 fl_rgb_color(200, 200, 200) #define COLOR_TEXT_1 fl_rgb_color(25, 25, 25) // TODO - duplicate! #define COLOR_BG_MAIN fl_rgb_color(25, 25, 25) // windows background #define COLOR_BG_DARK fl_rgb_color(0, 0, 0) // inputs background /* -- MIN/MAX values -------------------------------------------------------- */ #define MAX_BEATS 32 #define MAX_BARS 32 #define MAX_PATCHNAME_LEN 32 #define DB_MIN_SCALE 60.0f #define MAX_VST_EVENTS 32 #define MIN_COLUMN_WIDTH 140 /* -- kernel audio ---------------------------------------------------------- */ #define SYS_API_NONE 0x00 // 0000 0000 #define SYS_API_JACK 0x01 // 0000 0001 #define SYS_API_ALSA 0x02 // 0000 0010 #define SYS_API_DS 0x04 // 0000 0100 #define SYS_API_ASIO 0x08 // 0000 1000 #define SYS_API_CORE 0x10 // 0001 0000 #define SYS_API_PULSE 0x20 // 0010 0000 #define SYS_API_ANY 0x3F // 0011 1111 #define KERNEL_OK 0 #define KERNEL_UNDERRUN -1 #define KERNEL_CRITICAL -2 /* -- kernel midi ----------------------------------------------------------- */ #define MIDI_API_JACK 0x01 // 0000 0001 #define MIDI_API_ALSA 0x02 // 0000 0010 /* -- default system -------------------------------------------------------- */ #if defined(__linux__) #define DEFAULT_SOUNDSYS SYS_API_NONE #elif defined(_WIN32) #define DEFAULT_SOUNDSYS SYS_API_DS #elif defined(__APPLE__) #define DEFAULT_SOUNDSYS SYS_API_CORE #endif #define DEFAULT_SOUNDDEV_OUT 0 /// FIXME - please override with rtAudio::getDefaultDevice (or similar) #define DEFAULT_SOUNDDEV_IN -1 // no recording by default: input disabled #define DEFAULT_MIDI_SYSTEM 0 #define DEFAULT_MIDI_PORT_IN -1 #define DEFAULT_MIDI_PORT_OUT -1 #define DEFAULT_SAMPLERATE 44100 #define DEFAULT_BUFSIZE 1024 #define DEFAULT_DELAYCOMP 0 #define DEFAULT_VOL 0.0f #define DEFAULT_BOOST 0.0f #define gDEFAULT_PITCH 1.0f // ugly and temporary fix to avoid conflicts with wingdi.h (Windows only). #define DEFAULT_OUT_VOL 1.0f #define DEFAULT_IN_VOL 0.0f #define DEFAULT_CHANMODE SINGLE_BASIC #define DEFAULT_BPM 120.0f #define DEFAULT_BEATS 4 #define DEFAULT_BARS 1 #define DEFAULT_QUANTIZE 0 // quantizer off #define DEFAULT_FADEOUT_STEP 0.01f // micro-fadeout speed #define DEFAULT_COLUMN_WIDTH 380 /* -- mixer statuses and modes ---------------------------------------------- */ #define LOOP_BASIC 0x01 // 0000 0001 chanMode #define LOOP_ONCE 0x02 // 0000 0010 chanMode #define SINGLE_BASIC 0x04 // 0000 0100 chanMode #define SINGLE_PRESS 0x08 // 0000 1000 chanMode #define SINGLE_RETRIG 0x10 // 0001 0000 chanMode #define LOOP_REPEAT 0x20 // 0010 0000 chanMode #define SINGLE_ENDLESS 0x40 // 0100 0000 chanMode #define LOOP_ONCE_BAR 0x80 // 1000 0000 chanMode #define LOOP_ANY 0xA3 // 1010 0011 chanMode - any loop mode #define SINGLE_ANY 0x5C // 0101 1100 chanMode - any single mode #define STATUS_ENDING 0x01 // 0000 0001 chanStatus - ending (loop mode only) #define STATUS_WAIT 0x02 // 0000 0010 chanStatus - waiting for start (loop mode only) #define STATUS_PLAY 0x04 // 0000 0100 chanStatus - playing #define STATUS_OFF 0x08 // 0000 1000 chanStatus - off #define STATUS_EMPTY 0x10 // 0001 0000 chanStatus - not loaded (empty chan) #define STATUS_MISSING 0x20 // 0010 0000 chanStatus - not found #define STATUS_WRONG 0x40 // 0100 0000 chanStatus - something wrong (freq, bitrate, ...) #define REC_WAITING 0x01 // 0000 0001 #define REC_ENDING 0x02 // 0000 0010 #define REC_READING 0x04 // 0000 0100 #define REC_STOPPED 0x08 // 0000 1000 /* -- actions --------------------------------------------------------------- */ #define ACTION_KEYPRESS 0x01 // 0000 0001 #define ACTION_KEYREL 0x02 // 0000 0010 #define ACTION_KILLCHAN 0x04 // 0000 0100 #define ACTION_MUTEON 0x08 // 0000 1000 #define ACTION_MUTEOFF 0x10 // 0001 0000 #define ACTION_VOLUME 0x20 // 0010 0000 #define ACTION_MIDI 0x40 // 0100 0000 #define ACTION_KEYS 0x03 // 0000 0011 any key #define ACTION_MUTES 0x24 // 0001 1000 any mute #define RANGE_CHAR 0x01 // range for MIDI (0-127) #define RANGE_FLOAT 0x02 // range for volumes and VST params (0.0-1.0) /* -- mixerHandler signals -------------------------------------------------- */ #define SAMPLE_LOADED_OK 0x01 #define SAMPLE_LEFT_EMPTY 0x02 #define SAMPLE_NOT_VALID 0x04 #define SAMPLE_MULTICHANNEL 0x08 #define SAMPLE_WRONG_BIT 0x10 #define SAMPLE_WRONG_ENDIAN 0x20 #define SAMPLE_WRONG_FORMAT 0x40 #define SAMPLE_READ_ERROR 0x80 #define SAMPLE_PATH_TOO_LONG 0x100 /** FIXME - add to SAMPLE_ series those for when exporting */ /* -- log modes ------------------------------------------------------------- */ #define LOG_MODE_STDOUT 0x01 #define LOG_MODE_FILE 0x02 #define LOG_MODE_MUTE 0x04 /* -- browser types --------------------------------------------------------- */ #define BROWSER_LOAD_PATCH 0x00 #define BROWSER_LOAD_SAMPLE 0x01 #define BROWSER_SAVE_PATCH 0x02 #define BROWSER_SAVE_SAMPLE 0x04 #define BROWSER_SAVE_PROJECT 0x08 #define BROWSER_LOAD_PLUGIN 0x10 /* -- channel types --------------------------------------------------------- */ #define CHANNEL_SAMPLE 0x01 #define CHANNEL_MIDI 0x02 /* -- unique IDs of mainWin's subwindows ------------------------------------ */ /* -- wid > 0 are reserved by gg_keyboard ----------------------------------- */ #define WID_BEATS -1 #define WID_BPM -2 #define WID_ABOUT -3 #define WID_FILE_BROWSER -4 #define WID_CONFIG -5 #define WID_FX_LIST -6 #define WID_ACTION_EDITOR -7 #define WID_SAMPLE_EDITOR -8 #define WID_FX -9 #define WID_KEY_GRABBER -10 /* -- patch signals --------------------------------------------------------- */ #define PATCH_UNREADABLE 0x01 #define PATCH_INVALID 0x02 #define PATCH_READ_OK 0x04 #define PATCH_WRONG_PLUGINS 0x08 // currently unused #define PATCH_WRONG_SAMPLES 0x10 // currently unused /* -- midimap signals ------------------------------------------------------- */ #define MIDIMAP_NOT_SPECIFIED 0x00 #define MIDIMAP_UNREADABLE 0x01 #define MIDIMAP_INVALID 0x02 #define MIDIMAP_READ_OK 0x04 /* -- MIDI signals ------------------------------------------------------------- * all signals are set to channel 0 (where channels are considered). * It's up to the caller to bitmask them with the proper channel number. */ /* channel voices messages - controller (0xB0) is a special subset of * this family: it drives knobs, volume, faders and such. */ #define MIDI_CONTROLLER 0xB0 << 24 #define MIDI_NOTE_ON 0x90 << 24 #define MIDI_NOTE_OFF 0x80 << 24 #define MIDI_ALL_NOTES_OFF (MIDI_CONTROLLER) | (0x7B << 16) #define MIDI_VOLUME (MIDI_CONTROLLER) | (0x07 << 16) /* system common / real-time messages. Single bytes */ #define MIDI_SYSEX 0xF0 #define MIDI_MTC_QUARTER 0xF1 #define MIDI_POSITION_PTR 0xF2 #define MIDI_CLOCK 0xF8 #define MIDI_START 0xFA #define MIDI_CONTINUE 0xFB #define MIDI_STOP 0xFC #define MIDI_EOX 0xF7 // end of sysex /* channels */ #define MIDI_CHAN_0 0x00 << 24 #define MIDI_CHAN_1 0x01 << 24 #define MIDI_CHAN_2 0x02 << 24 #define MIDI_CHAN_3 0x03 << 24 #define MIDI_CHAN_4 0x04 << 24 #define MIDI_CHAN_5 0x05 << 24 #define MIDI_CHAN_6 0x06 << 24 #define MIDI_CHAN_7 0x07 << 24 #define MIDI_CHAN_8 0x08 << 24 #define MIDI_CHAN_9 0x09 << 24 #define MIDI_CHAN_10 0x0A << 24 #define MIDI_CHAN_11 0x0B << 24 #define MIDI_CHAN_12 0x0C << 24 #define MIDI_CHAN_13 0x0D << 24 #define MIDI_CHAN_14 0x0E << 24 #define MIDI_CHAN_15 0x0F << 24 const int MIDI_CHANS[16] = { MIDI_CHAN_0, MIDI_CHAN_1, MIDI_CHAN_2, MIDI_CHAN_3, MIDI_CHAN_4, MIDI_CHAN_5, MIDI_CHAN_6, MIDI_CHAN_7, MIDI_CHAN_8, MIDI_CHAN_9, MIDI_CHAN_10, MIDI_CHAN_11, MIDI_CHAN_12, MIDI_CHAN_13, MIDI_CHAN_14, MIDI_CHAN_15 }; /* midi sync constants */ #define MIDI_SYNC_NONE 0x00 #define MIDI_SYNC_CLOCK_M 0x01 #define MIDI_SYNC_CLOCK_S 0x02 #define MIDI_SYNC_MTC_M 0x04 #define MIDI_SYNC_MTC_S 0x08 /* JSON patch keys */ #define PATCH_KEY_HEADER "header" #define PATCH_KEY_VERSION "version" #define PATCH_KEY_VERSION_MAJOR "version_major" #define PATCH_KEY_VERSION_MINOR "version_minor" #define PATCH_KEY_VERSION_PATCH "version_patch" #define PATCH_KEY_NAME "name" #define PATCH_KEY_BPM "bpm" #define PATCH_KEY_BARS "bars" #define PATCH_KEY_BEATS "beats" #define PATCH_KEY_QUANTIZE "quantize" #define PATCH_KEY_MASTER_VOL_IN "master_vol_in" #define PATCH_KEY_MASTER_VOL_OUT "master_vol_out" #define PATCH_KEY_METRONOME "metronome" #define PATCH_KEY_LAST_TAKE_ID "last_take_id" #define PATCH_KEY_SAMPLERATE "samplerate" #define PATCH_KEY_COLUMNS "columns" #define PATCH_KEY_MASTER_OUT_PLUGINS "master_out_plugins" #define PATCH_KEY_MASTER_IN_PLUGINS "master_in_plugins" #define PATCH_KEY_CHANNELS "channels" #define PATCH_KEY_CHANNEL_TYPE "type" #define PATCH_KEY_CHANNEL_INDEX "index" #define PATCH_KEY_CHANNEL_COLUMN "column" #define PATCH_KEY_CHANNEL_MUTE "mute" #define PATCH_KEY_CHANNEL_MUTE_S "mute_s" #define PATCH_KEY_CHANNEL_SOLO "solo" #define PATCH_KEY_CHANNEL_VOLUME "volume" #define PATCH_KEY_CHANNEL_PAN_LEFT "pan_left" #define PATCH_KEY_CHANNEL_PAN_RIGHT "pan_right" #define PATCH_KEY_CHANNEL_MIDI_IN "midi_in" #define PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS "midi_in_keypress" #define PATCH_KEY_CHANNEL_MIDI_IN_KEYREL "midi_in_keyrel" #define PATCH_KEY_CHANNEL_MIDI_IN_KILL "midi_in_kill" #define PATCH_KEY_CHANNEL_MIDI_IN_VOLUME "midi_in_volume" #define PATCH_KEY_CHANNEL_MIDI_IN_MUTE "midi_in_mute" #define PATCH_KEY_CHANNEL_MIDI_IN_SOLO "midi_in_solo" #define PATCH_KEY_CHANNEL_MIDI_OUT_L "midi_out_l" #define PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING "midi_out_l_playing" #define PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE "midi_out_l_mute" #define PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO "midi_out_l_solo" #define PATCH_KEY_CHANNEL_SAMPLE_PATH "sample_path" #define PATCH_KEY_CHANNEL_KEY "key" #define PATCH_KEY_CHANNEL_MODE "mode" #define PATCH_KEY_CHANNEL_BEGIN "begin" #define PATCH_KEY_CHANNEL_END "end" #define PATCH_KEY_CHANNEL_BOOST "boost" #define PATCH_KEY_CHANNEL_REC_ACTIVE "rec_active" #define PATCH_KEY_CHANNEL_PITCH "pitch" #define PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS "midi_in_read_actions" #define PATCH_KEY_CHANNEL_MIDI_IN_PITCH "midi_in_pitch" #define PATCH_KEY_CHANNEL_MIDI_OUT "midi_out" #define PATCH_KEY_CHANNEL_MIDI_OUT_CHAN "midi_out_chan" #define PATCH_KEY_CHANNEL_PLUGINS "plugins" #define PATCH_KEY_CHANNEL_ACTIONS "actions" #define PATCH_KEY_ACTION_TYPE "type" #define PATCH_KEY_ACTION_FRAME "frame" #define PATCH_KEY_ACTION_F_VALUE "f_value" #define PATCH_KEY_ACTION_I_VALUE "i_value" #define PATCH_KEY_PLUGIN_PATH "path" #define PATCH_KEY_PLUGIN_BYPASS "bypass" #define PATCH_KEY_PLUGIN_PARAMS "params" #define PATCH_KEY_COLUMN_INDEX "index" #define PATCH_KEY_COLUMN_WIDTH "width" #define PATCH_KEY_COLUMN_CHANNELS "channels" /* JSON config keys */ #define CONF_KEY_HEADER "header" #define CONF_KEY_LOG_MODE "log_mode" #define CONF_KEY_SOUND_SYSTEM "sound_system" #define CONF_KEY_SOUND_DEVICE_IN "sound_device_in" #define CONF_KEY_SOUND_DEVICE_OUT "sound_device_out" #define CONF_KEY_CHANNELS_IN "channels_in" #define CONF_KEY_CHANNELS_OUT "channels_out" #define CONF_KEY_SAMPLERATE "samplerate" #define CONF_KEY_BUFFER_SIZE "buffer_size" #define CONF_KEY_DELAY_COMPENSATION "delay_compensation" #define CONF_KEY_LIMIT_OUTPUT "limit_output" #define CONF_KEY_RESAMPLE_QUALITY "resample_quality" #define CONF_KEY_MIDI_SYSTEM "midi_system" #define CONF_KEY_MIDI_PORT_OUT "midi_port_out" #define CONF_KEY_MIDI_PORT_IN "midi_port_in" #define CONF_KEY_NO_NOTE_OFF "no_note_off" #define CONF_KEY_MIDIMAP_PATH "midimap_path" #define CONF_KEY_LAST_MIDIMAP "last_midimap" #define CONF_KEY_MIDI_SYNC "midi_sync" #define CONF_KEY_MIDI_TC_FPS "midi_tc_fps" #define CONF_KEY_MIDI_IN_REWIND "midi_in_rewind" #define CONF_KEY_MIDI_IN_START_STOP "midi_in_start_stop" #define CONF_KEY_MIDI_IN_ACTION_REC "midi_in_action_rec" #define CONF_KEY_MIDI_IN_INPUT_REC "midi_in_input_rec" #define CONF_KEY_MIDI_IN_METRONOME "midi_in_metronome" #define CONF_KEY_MIDI_IN_VOLUME_IN "midi_in_volume_in" #define CONF_KEY_MIDI_IN_VOLUME_OUT "midi_in_volume_out" #define CONF_KEY_MIDI_IN_BEAT_DOUBLE "midi_in_beat_doble" #define CONF_KEY_MIDI_IN_BEAT_HALF "midi_in_beat_half" #define CONF_KEY_RECS_STOP_ON_CHAN_HALT "recs_stop_on_chan_halt" #define CONF_KEY_CHANS_STOP_ON_SEQ_HALT "chans_stop_on_seq_halt" #define CONF_KEY_TREAT_RECS_AS_LOOPS "treat_recs_as_loops" #define CONF_KEY_RESIZE_RECORDINGS "resize_recordings" #define CONF_KEY_PLUGINS_PATH "plugins_path" #define CONF_KEY_PATCHES_PATH "patches_path" #define CONF_KEY_SAMPLES_PATH "samples_path" #define CONF_KEY_MAIN_WINDOW_X "main_window_x" #define CONF_KEY_MAIN_WINDOW_Y "main_window_y" #define CONF_KEY_MAIN_WINDOW_W "main_window_w" #define CONF_KEY_MAIN_WINDOW_H "main_window_h" #define CONF_KEY_BROWSER_X "browser_x" #define CONF_KEY_BROWSER_Y "browser_y" #define CONF_KEY_BROWSER_W "browser_w" #define CONF_KEY_BROWSER_H "browser_h" #define CONF_KEY_ACTION_EDITOR_X "action_editor_x" #define CONF_KEY_ACTION_EDITOR_Y "action_editor_y" #define CONF_KEY_ACTION_EDITOR_W "action_editor_w" #define CONF_KEY_ACTION_EDITOR_H "action_editor_h" #define CONF_KEY_ACTION_EDITOR_ZOOM "action_editor_zoom" #define CONF_KEY_ACTION_EDITOR_GRID_VAL "action_editor_grid_val" #define CONF_KEY_ACTION_EDITOR_GRID_ON "action_editor_grid_on" #define CONF_KEY_SAMPLE_EDITOR_X "sample_editor_x" #define CONF_KEY_SAMPLE_EDITOR_Y "sample_editor_y" #define CONF_KEY_SAMPLE_EDITOR_W "sample_editor_w" #define CONF_KEY_SAMPLE_EDITOR_H "sample_editor_h" #define CONF_KEY_SAMPLE_EDITOR_GRID_VAL "sample_editor_grid_val" #define CONF_KEY_SAMPLE_EDITOR_GRID_ON "sample_editor_grid_on" #define CONF_KEY_PIANO_ROLL_Y "piano_roll_y" #define CONF_KEY_PIANO_ROLL_H "piano_roll_h" #define CONF_KEY_PLUGIN_LIST_X "plugin_list_x" #define CONF_KEY_PLUGIN_LIST_Y "plugin_list_y" #define CONF_KEY_CONFIG_X "config_x" #define CONF_KEY_CONFIG_Y "config_y" #define CONF_KEY_BPM_X "bpm_x" #define CONF_KEY_BPM_Y "bpm_y" #define CONF_KEY_BEATS_X "beats_x" #define CONF_KEY_BEATS_Y "beats_y" #define CONF_KEY_ABOUT_X "about_x" #define CONF_KEY_ABOUT_Y "about_y" /* JSON midimaps keys */ #define MIDIMAP_KEY_BRAND "brand" #define MIDIMAP_KEY_DEVICE "device" #define MIDIMAP_KEY_INIT_COMMANDS "init_commands" #define MIDIMAP_KEY_MUTE_ON "mute_on" #define MIDIMAP_KEY_MUTE_OFF "mute_off" #define MIDIMAP_KEY_SOLO_ON "solo_on" #define MIDIMAP_KEY_SOLO_OFF "solo_off" #define MIDIMAP_KEY_WAITING "waiting" #define MIDIMAP_KEY_PLAYING "playing" #define MIDIMAP_KEY_STOPPING "stopping" #define MIDIMAP_KEY_STOPPED "stopped" #define MIDIMAP_KEY_CHANNEL "channel" #define MIDIMAP_KEY_MESSAGE "message" #endif giada-0.11.2/src/core/dataStorageIni.cpp000066400000000000000000000037441264622563000177770ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * dataStorageIni * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include #include "../utils/log.h" #include "dataStorageIni.h" #include "const.h" std::string DataStorageIni::getValue(const char *in) { /* on each call reset the pointe to the beginning of the file. Not so * good but necessary if you want to pick up random values from the * file. */ fseek(fp, 0L, SEEK_SET); std::string out = ""; while (!feof(fp)) { char buffer[MAX_LINE_LEN]; if (fgets(buffer, MAX_LINE_LEN, fp) == NULL) { gLog("[DataStorageIni::getValue] key '%s' not found\n", in); return ""; } if (buffer[0] == '#') continue; unsigned len = strlen(in); if (strncmp(buffer, in, len) == 0) { for (unsigned i=len+1; i. * * -------------------------------------------------------------------------- */ #ifndef __DATA_STORAGE_INI_H__ #define __DATA_STORAGE_INI_H__ #include #include #include #define MAX_LINE_LEN 1024 class DataStorageIni { protected: FILE *fp; std::string getValue(const char *in); }; #endif giada-0.11.2/src/core/dataStorageJson.cpp000066400000000000000000000101301264622563000201540ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * dataStorageIni * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "dataStorageJson.h" using std::string; bool DataStorageJson::setString(json_t *jRoot, const char *key, string &output) { json_t *jObject = json_object_get(jRoot, key); if (!json_is_string(jObject)) { gLog("[dataStorageJson::setString] key '%s' is not a string!\n", key); json_decref(jRoot); return false; } output = json_string_value(jObject); return true; } /* -------------------------------------------------------------------------- */ bool DataStorageJson::setFloat(json_t *jRoot, const char *key, float &output) { json_t *jObject = json_object_get(jRoot, key); if (!jObject) { gLog("[dataStorageJson::setFloat] key '%s' not found, using default value\n", key); output = 0.0f; return true; } if (!json_is_real(jObject)) { gLog("[dataStorageJson::setFloat] key '%s' is not a float!\n", key); json_decref(jRoot); return false; } output = json_real_value(jObject); return true; } /* -------------------------------------------------------------------------- */ bool DataStorageJson::setUint32(json_t *jRoot, const char *key, uint32_t &output) { json_t *jObject = json_object_get(jRoot, key); if (!jObject) { gLog("[dataStorageJson::setUint32] key '%s' not found, using default value\n", key); output = 0; return true; } if (!json_is_integer(jObject)) { gLog("[dataStorageJson::setUint32] key '%s' is not an integer!\n", key); json_decref(jRoot); return false; } output = json_integer_value(jObject); return true; } /* -------------------------------------------------------------------------- */ bool DataStorageJson::setBool(json_t *jRoot, const char *key, bool &output) { json_t *jObject = json_object_get(jRoot, key); if (!jObject) { gLog("[dataStorageJson::setBool] key '%s' not found, using default value\n", key); output = false; return true; } if (!json_is_boolean(jObject)) { gLog("[dataStorageJson::setBool] key '%s' is not a boolean!\n", key); json_decref(jRoot); return false; } output = json_boolean_value(jObject); return true; } /* -------------------------------------------------------------------------- */ bool DataStorageJson::setInt(json_t *jRoot, const char *key, int &output) { return setUint32(jRoot, key, (uint32_t&) output); } /* -------------------------------------------------------------------------- */ bool DataStorageJson::checkObject(json_t *jRoot, const char *key) { if (!json_is_object(jRoot)) { gLog("[DataStorageJson::checkObject] malformed json: %s is not an object!\n", key); json_decref(jRoot); return false; } return true; } /* -------------------------------------------------------------------------- */ bool DataStorageJson::checkArray(json_t *jRoot, const char *key) { if (!json_is_array(jRoot)) { gLog("[DataStorageJson::checkObject] malformed json: %s is not an array!\n", key); json_decref(jRoot); return false; } return true; } giada-0.11.2/src/core/dataStorageJson.h000066400000000000000000000036461264622563000176370ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * dataStorageIni * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef __DATA_STORAGE_JSON_H__ #define __DATA_STORAGE_JSON_H__ #include #include using std::string; class DataStorageJson { protected: json_t *jRoot; json_error_t jError; bool setString(json_t *jRoot, const char *key, string &output); bool setFloat(json_t *jRoot, const char *key, float &output); bool setUint32(json_t *jRoot, const char *key, uint32_t &output); bool setInt(json_t *jRoot, const char *key, int &output); bool setBool(json_t *jRoot, const char *key, bool &output); /* checkObject check whether the jRoot object is a valid json object {} */ bool checkObject(json_t *jRoot, const char *key); /* checkArray check whether the jRoot object is a valid json array [] */ bool checkArray(json_t *jRoot, const char *key); }; #endif giada-0.11.2/src/core/graphics.cpp000066400000000000000000001675001264622563000167020ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * graphics * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "graphics.h" const char *giada_logo_xpm[] = { "300 82 8 1", " c #181917", ". c #333432", "+ c #484A47", "@ c #5F615E", "# c #767875", "$ c #8D8F8C", "% c #A5A7A4", "& c #C5C7C4", " .#%%&$ ", " ..#%&&&&&# ", " +@#$%&&&&&&&&&@ ", " .. +&&&&&&&&&&&&&&. ", " +$%%#+ +%&&&&&&&&&&&&&. ", " #&&&&&%+ .+@@$&&&&&&&&&%. ", " #&&&&&&&$ +&&&&&&&&# ", " .&&&&&&&&%. #&&&&&&&@ ", " @&&&&&&&&$ +&&&&&&&+ ", " $&&&&&&&&# .&&&&&&&. ", " #&&&&&&&&. +&&&&&&%. ", " .&&&&&&&@ @&&&&&&$. ", " @&&&&&@ $&&&&&&# ", " .##@. %&&&&&&@ ", " &&&&&&&+ ", " .&&&&&&%. ", " @&&&&&&$. ", " .+@@###@+. ...... ... ++@@###@@. ....... .+@@###@@+. #&&&&&&# .+@@###@@+ ....... ", " .@$%%&&&&&&&%$+ +%%%%%%. .+@#$%%$. .@$%&&&&&&&&%$@. $%%%%%%+ .@#%%&&&&&&&&%$@ %&&&&&&@ .@$%%&&&&&&&%$#. @%%%%%%@ ", " #%&&&&&&&&&&&&&&$. #&&&&&& +@#$$%%%&&&&&%. .$%&&&&&&&&&&&&&&%@ .&&&&&&&+ #%&&&&&&&&&&&&&&&$+ &&&&&&&@ #%&&&&&&&&&&&&&&%#. %&&&&&&@ ", " +%&&&&&&&&&&&&&&&&&%@ .&&&&&&% .%&&&&&&&&&&&&$ #%&&&&&&&&&&&&&&&&&&$ +&&&&&&%. @%&&&&&&&&&&&&&&&&&&&# .&&&&&&%+ @%&&&&&&&&&&&&&&&&&&%. &&&&&&&+ ", " #&&&&&&&&&#+....@$&&&&@@&&&&&&$ .&&&&&&&&&&&&&# +%&&&&&&&&%#+....+#%&&&$#&&&&&&$. .$&&&&&&&&&$+.....@%&&&&$@&&&&&&%. .$&&&&&&&&&#@.....#%&&&%+&&&&&&%. ", " $&&&&&&&&@ .%&&&&&&&&&&@ .@$&&&&&&&&&&@ +%&&&&&&&%@ .#&&&&&&&&&&$ .%&&&&&&&&@ .$&&&&&&&&&&$ .%&&&&&&&&#. @&&&&&&&&&&%. ", " $&&&&&&&%. @&&&&&&&&&+ .%&&&&&&&%+ @&&&&&&&&# +%&&&&&&&&# +%&&&&&&&$. @&&&&&&&&&# .%&&&&&&&$. .%&&&&&&&&$ ", " %&&&&&&&# @&&&&&&&&. +%&&&&&&%. @&&&&&&&&# .%&&&&&&&@ +%&&&&&&&# @&&&&&&&&@ +%&&&&&&&# %&&&&&&&@ ", " $&&&&&&&$ #&&&&&&%. %&&&&&&% +&&&&&&&&@ +&&&&&&%+ .%&&&&&&&# @&&&&&&&+ .%&&&&&&&# &&&&&&&+ ", " @&&&&&&&$. #&&&&&&$ %&&&&&&$ .%&&&&&&&@ @&&&&&&%. .$&&&&&&&$ +&&&&&&%+ $&&&&&&&$ .&&&&&&&+ ", " +&&&&&&&%+ %&&&&&&# %&&&&&&# $&&&&&&&$ $&&&&&&% @&&&&&&&% #&&&&&&%. #&&&&&&&%. @&&&&&&%. ", " %&&&&&&&# &&&&&&&+ .%&&&&&&@ @&&&&&&&$ %&&&&&&$ +&&&&&&&&+ $&&&&&&$ +&&&&&&&%. $&&&&&&$. ", " @&&&&&&&%. .&&&&&&&. +%&&&&&%. .&&&&&&&&. .%&&&&&&# $&&&&&&&# %&&&&&&# .$&&&&&&&@ %&&&&&&# ", " .%&&&&&&&@ @&&&&&&&. @&&&&&&% @&&&&&&&# @&&&&&&&+ +&&&&&&&&. +&&&&&&&@ +&&&&&&&% .&&&&&&&@ ", " @&&&&&&&% $&&&&&&%. #&&&&&&% &&&&&&&&. #&&&&&&%. %&&&&&&&# @&&&&&&%+ .$&&&&&&&@ +&&&&&&&+ ", " .$&&&&&&&# %&&&&&&# $&&&&&&# #&&&&&&&# $&&&&&&% +&&&&&&&&. $&&&&&&%. +&&&&&&&% #&&&&&&%+ ", " +%&&&&&&&+ .&&&&&&&@ .%&&&&&&@ %&&&&&&&+ .%&&&&&&$ $&&&&&&&$ %&&&&&&% #&&&&&&&# %&&&&&&%. ", " @&&&&&&&% +&&&&&&&+ +%&&&&&&+ .&&&&&&&%. +&&&&&&&# &&&&&&&&+ +%&&&&&&$ .%&&&&&&&. &&&&&&&$ ", " $&&&&&&&@ #&&&&&&&. @&&&&&&&. #&&&&&&&# #&&&&&&&@ +&&&&&&&%. @&&&&&&&# .&&&&&&&% +&&&&&&&# ", " .%&&&&&&&. %&&&&&&%. #&&&&&&% %&&&&&&&+ $&&&&&&&+ #&&&&&&&$. $&&&&&&&+ @&&&&&&&@ #&&&&&&&@ ", " +&&&&&&&& &&&&&&&$. #&&&&&&$ &&&&&&&%. .%&&&&&&& %&&&&&&&# .%&&&&&&%. $&&&&&&&+ $&&&&&&%+ ", " +&&&&&&&$ +&&&&&&&# .$&&&&&&# .&&&&&&&$. +&&&&&&&% %&&&&&&&+ +%&&&&&&% %&&&&&&&. .%&&&&&&%. ", " @&&&&&&&@ $&&&&&&&@ .%&&&&&&+ +&&&&&&&# #&&&&&&&$ &&&&&&&&+ #&&&&&&&% &&&&&&&% @&&&&&&&$ ", " @&&&&&&&+ &&&&&&&&+ +%&&&&&&. @&&&&&&&@ .%&&&&&&&@ .&&&&&&&%. .%&&&&&&&# &&&&&&&# $&&&&&&&$ ", " #&&&&&&&. @&&&&&&&%. @&&&&&&& @&&&&&&&@ @&&&&&&&&+ .&&&&&&&%. @&&&&&&&&@ .&&&&&&&# +%&&&&&&&# ", " #&&&&&&&. %&&&&&&&$. #&&&&&&% #&&&&&&&+ .$&&&&&&&&. .&&&&&&&$. .$&&&&&&&&. .&&&&&&&@ $&&&&&&&&@ ", " #&&&&&&& #&&&&&&&&$ $&&&&&&# @&&&&&&&+ @&&&&&&&&& .&&&&&&&$. @&&&&&&&&& .&&&&&&&+ +%&&&&&&&%+ ", " @&&&&&&& .%&&&&&&&&# .%&&&&&&@ @&&&&&&%+ .%&&&&&&&&% &&&&&&&$. .%&&&&&&&&% &&&&&&&+ $&&&&&&&&%. ", " @&&&&&&&. $&&&&&&&&&@ +%&&&&&&. +&&&&&&&@ @&&&&&&&&&$ &&&&&&&%. #&&&&&&&&&$ &&&&&&&@ +&&&&&&&&&% ", " +&&&&&&&+ @&&&&&&&&&%+ +&&&&&&& &&&&&&&@ +&&&&&&&&&&# $&&&&&&%+ @&&&&&&&&&&# $&&&&&&# .%&&&&&&&&&% ", " .%&&&&&&@ +%&&$&&&&&&%. +&&&&&&& %&&&&&&# .&&&&&&&&&&&@ @&&&&&&&+ +&&&$%&&&&&&@ @&&&&&&$ .$&&&&&&&&&&$ ", " #&&&&&&$ .$&&##&&&&&&$ @&&&&&&& @&&&&&&%. .%&&%@%&&&&&&@ .&&&&&&&# .&&&$+%&&&&&&. .&&&&&&&. .#&&%@%&&&&&&$ ", " +&&&&&&&. .%&&% $&&&&&&# +&&&&&&&. +.&&&&&&&@ .%&&%+.%&&&&&&$ @+$&&&&&&&+ +&&&% +&&&&&&&+ .+ $&&&&&&$ .$&&&@ %&&&&&&% .# ", " $&&&&&&$ +%&&&+ %&&&&&&@ +&&&&&&&@ #&$#&&&&&&%+ @&&&&@ .$&&&&&&&+ #&&@&&&&&&&$. .#&&&%. +%&&&&&&# .$&$ +&&&&&&&+ +%&&&# $&&&&&&&# +&&$ ", " +%&&&&&&#. +#&&&%@ .%&&&&&&+ .%&&&&&&&+ .$&&%.%&&&&&&%+ +#&&&&@ #&&&&&&&%@..+@$&&&+@&&&&&&&%+ .@%&&&%+ .%&&&&&&&+ +%&&$. #&&&&&&%@ +#&&&&# @&&&&&&&&@...+#&&&# ", " @&&&&&&&$@+..++#%&&&%+ +&&&&&&%. $&&&&&&&%#@@#%&&%. .%&&&&&&%@+...+@$&&&&%+ +%&&&&&&&&%$%&&&&+ $&&&&&&&&$#@+@@#%&&&&$. #&&&&&&&&#@+@$&&&$. .$&&&&&&&#+...++#%&&&&@ .%&&&&&&&&%$%&&&&# ", " @&&&&&&&&%%%%&&&&&$. @&&&&&&% +%&&&&&&&&&&&&&$. +%&&&&&&&&%$%%&&&&&$. #&&&&&&&&&&&&&%+ .$&&&&&&&&&&&&&&&&&&# .%&&&&&&&&&&&&&&# .$&&&&&&&&%$%%&&&&&%+ @&&&&&&&&&&&&&%@ ", " @%&&&&&&&&&&&&&%@. #&&&&&&$ #&&&&&&&&&&&%@. .$&&&&&&&&&&&&&&%@. .%&&&&&&&&&&&#. @&&&&&&&&&&&&&&&$+ +&&&&&&&&&&&&%+ .#&&&&&&&&&&&&&&&#. $&&&&&&&&&&&$+ ", " .#%&&&&&&&&&%+. %&&&&&&# +%&&&&&&&%#. +$&&&&&&&&&&%@. .$&&&&&&&&#+ .#&&&&&&&&&&%#. .$&&&&&&&&%@. +$&&&&&&&&&&%@. .@&&&&&&&&$+. ", " .+#$%%$#+.. .%&&&&&&+ .@#$%$#+. .@#$%%$#@+ +@$%$#+. .+#$%%$#@+. +@$%$$@. .+#$%%$#@+. .@$%$#@. ", " +&&&&&&%. ", " #&&&&&&% ", " .%&&&&&&@ ", " @&&&&&&%. ", " $&&&&&&$ ", " @&&&&&&&+ ", " @#$#+ .$&&&&&&$ ", " $&&&&&# #&&&&&&% ", "#&&&&&&&@ @&&&&&&&+ ", "%&&&&&&&%. @&&&&&&%+ ", "%&&&&&&&&# #&&&&&&%. ", "@&&&&&&&&&@ .$&&&&&&#. ", " $&&&&&&&&&$+ +$&&&&&&%+ ", " +&&&&&&&&&&%#@@#$%&&&&&&&#. +. .+ +@. ++ .+ +++++ +. .+ ++ +++++. .++++. +@. .@+ .++++. .+++++++ +. +@. .+@. .++++. ++. ++. .+. .+@. .+ +. .+ .+. .+ .+++++++ ", " .$&&&&&&&&&&&&&&&&&&&%@ $%. %@ +&&%&%. .$$ +& .&&&&&&# .%@ +&. %&+ $&&&&&%. @&&&&&%. +&&%&%. .%&%&&+ #&&&&&&@ +&&&&&&%. &# +&&%&%. @&&%&%. +&&&&&&@ $&% +%&+ .$&@ @&&%&$. $% .%$ $% +&%. +%. +&&&&&&$. ", " +$%%&&&&&&&&&&%$@. +&# #% +&# %% $$ +& .&+ @&@ .%@ +&. +$&$ $$ .%% @% .%&. .&$ .%$. %%. #&+ #& .$&+ +&. &# +&# $%. @&# .%%. +&. $&+ $%&+ #%&+ .&%$ @&# +%$ $% .%# $% +&%$ +%. +&. ", " .++@###@@+. #&. .&+ $%. .&@ $$ +& .&+ %$ .%@ +&. ##$% $$ @&. @% %$ $%. @&. @&+ %$. #& .%@ +&. &# %% .&# %% .&@ +&. &# $#%$ $#&+ @%@%. %% @%+ $% .%# $% +&+%+ +%. +&. ", " .%$ $$ .&# %% $$ +& .&+ %$ .%@ +&. .%@+&+ $$ @&. @% #& &# +. %% #&. #& .%@ +&. &# .&@ $$ +&+ .$$ +&. %# $#@& +$@&+ $#.%@ +&@ .+. $% .%# $% +& $$ +%. +&. ", " @&#&. .&@ $& $$ +& .&#+++#&+ .%%####$&. +%. %$ $%.++@&$ @% +&..&@ &$ @&+ #&++++$%. +&$###@ &# +&+ #%.@&. #% +&+ ..#&+ $#.&@ ##+&+ .&..$$ @&. $&$###$&# $% +& +%@ +%. +&####+ ", " %&@ +&+ #& $$ +& .&%$$%%@ .%%####$&. #$ #& $&$$%&#. @% +&++&@ &# +&+ #&$$%&%+ +&$$$$# &# @&. #%.@&. #%.+%%%%%%@ $# $% .$+.&+ @% @%. @&. $&$###$&# $% +& #%.+%. +&$$$$@ ", " #&. .&@ $% $$ +& .&#+.$%. .%@ +&. .$%##$&+ $%.+@&@ @% +&..&@ &$ @&. #&+++$$ +&+ &# +&. #% @&. $$ +&#@@++ $# +&.+$.+&+ $%@#$&+ @&. $% .%# $% +& .%@+%. +&. ", " @& .%# &$ $$ +% .&+ .%@ .%@ +&. +%$###&$ $$ $% @% $& &$ .$+ $% #%. #& +&+ +&. &# .&@ .%$ +&@ .%# +&. $# .%### +&+ .&####&# .&@ .$+ $% .%# $% +& @%@%. +&. ", " @& #%. @&. #%. $% .&+ $% .%@ +&. @$. #& $$ +&+ @% +&@ #&. #&. +&+ .%@ #& .%# +&. &# $% +&+ %% @&+ +&. $# #&%+ +&+ @% #%. %% #%. $% .%# $% +& .$%%. +&. ", " @& .%%+.@&# .%%++#&@ .&+ +&+ .%@ +&. $# .&+ $$ %$ @&+++#&%. $%+.#&# #&@.+%%. #& @%. +&@+++++. &$++++. .%%+.@%# .%%..@&# +&. $# +&$ +&+ %# +&+ .%%+.#&# $% .%# $% +& +&&. +&@++++. %&", " @& .$&&%@ +%&&&@ .&+ %$ .%@ +&..%+ %$ $$ @&. @&&&&%@ .$%&&# @%&&$. #& .%@ +&&&&&&%+ &&&&&&$. .$&&%# .$&&%@ +&. $# .%# +&+.&. .%# .$&&&@ $% .%# $% +& $&. +&&&&&&%. &&"}; const char *loopRepeat_xpm[] = { "18 18 8 1", " c #181917", ". c #242523", "+ c #323331", "@ c #4D4F4C", "# c #646663", "$ c #787A77", "% c #919390", "& c #BFC1BD", "..................", "..................", "..................", "...&%#......#%&...", "...&&&%+..+%&&&...", "...$%&&%..%&&%$...", ".....$&&##&&$.....", "......%&%%&%......", "......$&&&&$......", "......$&&&&$......", "......%&%%&%......", ".....$&&##&&$.....", "...$%&&%..%&&%$...", "...&&&%+..+%&&&...", "...&%#......#%&...", "..................", "..................", ".................."}; const char *loopBasic_xpm[] = { "18 18 8 1", " c #181917", ". c #242523", "+ c #313230", "@ c #4D4F4C", "# c #666765", "$ c #787A77", "% c #919390", "& c #BEC0BD", "..................", "..................", "..................", "......#%&&%#......", "....+%&&&&&&%+....", "....%&&&%%&&&%....", "...#&&%+..+%&&#...", "...%&&+....+&&%...", "...&&%......%&&...", "...&&%......%&&...", "...%&&+....+&&%...", "...#&&%+..+%&&#...", "....%&&&%%&&&%....", "....+%&&&&&&%+....", "......#%&&%#......", "..................", "..................", ".................."}; const char *loopOnce_xpm[] = { "18 18 8 1", " c #181917", ". c #242523", "+ c #323331", "@ c #4D4F4C", "# c #646663", "$ c #787A77", "% c #919390", "& c #BFC1BD", "..................", "..................", "..................", "......$%&&%#......", "....+&&&&&&&&+....", "...+&&&&$$&&&&+...", "...$&&$....$&&$...", "...%&&......%&%...", "..................", "..................", "...%&&+.....&&&...", "...#&&$....$&&#...", "....%&&&%$&&&%....", "....+%&&&&&&%+....", "......#%&&%#......", "..................", "..................", ".................."}; const char *loopOnceBar_xpm[] = { "18 18 8 1", " c #242523", ". c #393A38", "+ c #545553", "@ c #747673", "# c #A3A5A2", "$ c #ADAFAC", "% c #B5B7B4", "& c #C7C9C6", " ", " ", " ", " @$&%#@ ", " .$&&&&&&$. ", " %&&#@@#&&$ ", " @&&@ @&&@ ", " %&# +%$+ #&$ ", " %&&% ", " %&&% ", " $&# +%%+ #&$ ", " @&&@ @&&@ ", " $&&#@@#&&$ ", " .$&&&&&&$. ", " @#&&#@ ", " ", " ", " "}; const char *oneshotBasic_xpm[] = { "18 18 8 1", " c #181917", ". c #242523", "+ c #313230", "@ c #4D4F4C", "# c #666765", "$ c #787A77", "% c #919390", "& c #BEC0BD", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "...$$$$$$$$$$$$...", "...&&&&&&&&&&&&...", "...&&&&&&&&&&&&...", "..................", "..................", ".................."}; const char *oneshotRetrig_xpm[] = { "18 18 8 1", " c #181917", ". c #242523", "+ c #313230", "@ c #4D4F4C", "# c #666765", "$ c #787A77", "% c #919390", "& c #BEC0BD", "..................", "..................", "..................", "..................", "..................", "...$$$$$$$#@......", "...&&&&&&&&&&@....", "...&&&&&&&&&&&+...", "..........+$&&%...", "............%&&...", "............%&&...", "...........+&&%...", "...$$$$$$$%&&&#...", "...&&&&&&&&&&%....", "...&&&&&&&&%#.....", "..................", "..................", ".................."}; const char *oneshotPress_xpm[] = { "18 18 8 1", " c #181917", ". c #242523", "+ c #313230", "@ c #4D4F4C", "# c #666765", "$ c #787A77", "% c #919390", "& c #BEC0BD", "..................", "..................", "..................", "..................", "..................", "..................", "...+%&%+..........", "...%&&&%..........", "...&&&&&..........", "...$&&&$..........", "...+$&$+..........", "..................", "...$$$$$$$$$$$$...", "...&&&&&&&&&&&&...", "...&&&&&&&&&&&&...", "..................", "..................", ".................."}; const char *oneshotEndless_xpm[] = { "18 18 6 1", " c #242523", ". c #464745", "+ c #6D6F6C", "@ c #888A87", "# c #ADAFAC", "$ c #C6C8C5", " ", " ", " ", " ", " ", " .++. ", " @$$$$#. ", " @$$$$$$$. ", " .$$#. +$$@ ", " +$$. @$# ", " +$$ @$$ ", " .$$+ #$# ", " @@@$$$@@#$$+ ", " $$$$$$$$$$@ ", " $$$$$$$$#+ ", " ", " ", " "}; const char *updirOff_xpm[] = { "18 18 8 1", " c #242523", ". c #332F2E", "+ c #54494A", "@ c #6B5A5C", "# c #866C6B", "$ c #967B7A", "% c #987D7C", "& c #B18E8F", " ", " ", " ", " ", " @@ ", " #&&# ", " .#&&&&#. ", " .$&&&&&&$. ", " +@%&&&&%@+ ", " #&&&&# ", " #&&&&# ", " #&&&&# ", " #&&&&# ", " #&&&&# ", " .... ", " ", " ", " "}; const char *updirOn_xpm[] = { "18 18 8 1", " c #4D4F4C", ". c #555150", "+ c #706465", "@ c #7D6B6E", "# c #877373", "$ c #957978", "% c #9F8382", "& c #B18E8F", " ", " ", " ", " ", " ## ", " #&&# ", " .$&&&&$. ", " .%&&&&&&%. ", " +@%&&&&%@+ ", " $&&&&$ ", " $&&&&$ ", " $&&&&$ ", " $&&&&$ ", " $&&&&$ ", " .... ", " ", " ", " "}; const char *pause_xpm[] = { "23 23 8 1", " c #4D4F4C", ". c #514E53", "+ c #5C4F61", "@ c #6F507E", "# c #855098", "$ c #9551AE", "% c #A652C5", "& c #AE52D1", " ", " ", " ", " ", " ", " #+ ", " &%#. ", " &&&%@ ", " &&&&&$+ ", " &&&&&&&#. ", " &&&&&&&&%@ ", " &&&&&&&&&&# ", " &&&&&&&&%@. ", " &&&&&&&#. ", " &&&&&$+ ", " &&&%@ ", " &&#. ", " $+ ", " ", " ", " ", " ", " "}; const char *play_xpm[] = { "23 23 8 1", " c #242523", ". c #393534", "+ c #574B4C", "@ c #6E5B5A", "# c #7C6663", "$ c #8C7170", "% c #A48384", "& c #B18E8F", " ", " ", " ", " ", " ", " $. ", " &&@ ", " &&&%+ ", " &&&&&$. ", " &&&&&&&@ ", " &&&&&&&&%+ ", " &&&&&&&&&&# ", " &&&&&&&&%+ ", " &&&&&&&#. ", " &&&&&$. ", " &&&%+ ", " &&@ ", " $. ", " ", " ", " ", " ", " "}; const char *rewindOff_xpm[] = { "23 23 8 1", " c #242523", ". c #393534", "+ c #574B4C", "@ c #6E5B5A", "# c #7C6663", "$ c #8C7170", "% c #A48384", "& c #B18E8F", " ", " ", " ", " ", " ", " .$ ", " @&& ", " +%&&& ", " .$&&&&& ", " @&&&&&&& ", " +%&&&&&&&& ", " #&&&&&&&&&& ", " +%&&&&&&&& ", " .#&&&&&&& ", " .$&&&&& ", " +%&&& ", " @&& ", " .$ ", " ", " ", " ", " ", " "}; const char *rewindOn_xpm[] = { "23 23 8 1", " c #4D4F4C", ". c #514E53", "+ c #5C4F61", "@ c #6F507E", "# c #855098", "$ c #9551AE", "% c #A652C5", "& c #AE52D1", " ", " ", " ", " ", " ", " +# ", " .#%& ", " @%&&& ", " +$&&&&& ", " .#&&&&&&& ", " @%&&&&&&&& ", " #&&&&&&&&&& ", " .@%&&&&&&&& ", " .#&&&&&&& ", " +$&&&&& ", " @%&&& ", " .#&& ", " +$ ", " ", " ", " ", " ", " "}; // 18x18 /* const unsigned char giada_icon[] = { 0x00, 0x00, 0x00, 0xfc, 0xff, 0x00, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01, 0x3e, 0xf0, 0x01, 0x1e, 0xe0, 0x01, 0x0e, 0xc3, 0x01, 0x8e, 0xff, 0x01, 0x8e, 0xc1, 0x01, 0x8e, 0xc1, 0x01, 0x8e, 0xc7, 0x01, 0x0e, 0xc7, 0x01, 0x1e, 0xc0, 0x01, 0x3e, 0xf0, 0x01, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00 }; */ const char *giada_icon[] = { "65 65 11 1", " c None", ". c #000000", "+ c #000100", "@ c #FFFFFF", "# c #FDFFFC", "$ c #CBCDC9", "% c #292B28", "& c #626461", "* c #484A47", "= c #888A87", "- c #A7A9A6", "....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++....", ".@@@#####################$%+++++++++++++%&&*%+++++++&##%+++++....", ".@@#####################&++++++++++++=$#######-*+++++&$+++++++...", ".@@####################&++++++++++%-############$*+++++++++++++..", "+#####################*++++++++++&################-++++++++++++%+", "+####################*++++++++++=##################$+++++++++++*+", "+###################*++++++++++$####################$++++++++++=+", "+##################=++++++++++-######################-+++++++++-+", "+#################$++++++++++=#######################=+++++++++$+", "+#################%+++++++++*########################*+++++++++#+", "+################*++++++++++#########################%++++++++*#+", "+###############-++++++++++=########################$+++++++++&#+", "+###############%+++++++++%#########################-+++++++++-#+", "+##############-++++++++++-#########################&+++++++++$#+", "+##############%+++++++++%##########################*+++++++++##+", "+#############-++++++++++-##########################+++++++++%##+", "+#############%++++++++++##########################$+++++++++*##+", "+############$++++++++++&##########################=+++++++++=##+", "+############=++++++++++$##########################&+++++++++-##+", "+############*+++++++++%###########################%+++++++++$##+", "+############++++++++++=###########################++++++++++###+", "+###########$++++++++++$##########################-+++++++++*###+", "+###########=++++++++++###########################=+++++++++&###+", "+###########*+++++++++%###########################*+++++++++-###+", "+###########%+++++++++&###########################++++++++++$###+", "+###########%+++++++++-##########################=++++++++++####+", "+###########++++++++++$##########################%+++++++++%####+", "+###########++++++++++##########################$++++++++++&####+", "+##########$++++++++++##########################&++++++++++=####+", "+##########$+++++++++%#########################$+++++++++++-####+", "+##########$+++++++++%#########################&+++++++++++$####+", "+###########+++++++++*########################$++++++++++++#####+", "+###########+++++++++*########################*+++++++++++*#####+", "+###########%++++++++%#######################=++++++++++++&#####+", "+###########&+++++++++######################$+++++++++++++-#####+", "+###########=+++++++++$#####################%+++%+++++++++$#####+", "+###########$+++++++++$####################&+++%=+++++++++######+", "+############%++++++++&###################=++++$&++++++++%######+", "+############-+++++++++$#################&++++=#*++++++++&######+", "+#############+++++++++&################*++++*##+++++++++=######+", "+#############=+++++++++-#############$%++++%###+++++++++-######+", "+##############*+++++++++=##########$*+++++%###$+++++++++#######+", "+###############++++++++++&$######$&++++++&####=+++++++++#######+", "+###############$++++++++++++%&*%++++++++=#####&++++++++*#######+", "+################$%+++++++++++++++++++++-######%++++++++=#######+", "+##################&++++++++++++++++++=########+++++++++-#######+", "+###################$%+++++++++++++%=#########$+++++++++########+", "+#####################$=%++++++%*=-###########=++++++++%########+", "+##########################$$$################*++++++++&########+", "+#############################################+++++++++=########+", "+############################################$+++++++++$########+", "+############################################&++++++++%#########+", "+############################################+++++++++=#########+", "+###########################################=+++++++++##########+", "+###########################################%++++++++*##########+", "+##########################################=+++++++++-##########+", "+#########-==$############################$+++++++++&###########+", "+#######=++++++-##########################*+++++++++############+", "+######$++++++++$########################=+++++++++-############+", "+######=+++++++++$######################-+++++++++&#############+", "+######=+++++++++*#####################$+++++++++&##############.", ".@#####=++++++++++-###################-+++++++++=##############@.", ".@@####=++++++++++%##################=+++++++++=#############@@@.", ".@@@###=+++++++++++*###############$*++++++++%$##############@@@.", "....++++++++++++++++++++++++++++++++++++++++++++++++++++++++....."}; const char *recOff_xpm[] = { "23 23 8 1", " c #242523", ". c #342F2E", "+ c #3F3B3A", "@ c #594F4F", "# c #7A6663", "$ c #8C7170", "% c #A68384", "& c #B18E8F", " ", " ", " ", " ", " ", " @$%%$@ ", " .$&&&&&&$. ", " $&&&&&&&&$ ", " @&&&#++#&&&@ ", " $&&# #&&$ ", " %&&+ +&&% ", " %&&+ +&&% ", " $&&# #&&$ ", " @&&&#++#&&&@ ", " $&&&&&&&&$ ", " .$&&&&&&$. ", " @$%%$@ ", " ", " ", " ", " ", " ", " "}; const char *recOn_xpm[] = { "23 23 8 1", " c #4D4F4C", ". c #5F4E50", "+ c #6E4F50", "@ c #8C5050", "# c #AE5454", "$ c #BB5253", "% c #C55352", "& c #E85557", " ", " ", " ", " ", " ", " @$&&$@ ", " .%&&&&&&%. ", " %&&&&&&&&% ", " @&&&#++#&&&@ ", " $&&# #&&$ ", " &&&+ +&&& ", " &&&+ +&&& ", " $&&# #&&$ ", " @&&&#++#&&&@ ", " %&&&&&&&&% ", " .%&&&&&&%. ", " @$&&$@ ", " ", " ", " ", " ", " ", " "}; const char *inputRecOn_xpm[] = { "23 23 8 1", " c #524D4C", ". c #4D4F4C", "+ c #5D4F50", "@ c #8C5050", "# c #BB5253", "$ c #C45251", "% c #DD5256", "& c #EA5657", ".......................", ".......................", ".......................", ".......................", ".......................", "........ @#%%#@ .......", ".......+$&&&&&&$+......", "...... $&&&&&&&&$ .....", "......@&&&&&&&&&&@.....", "......#&&&&&&&&&&#.....", "......%&&&&&&&&&&%.....", "......%&&&&&&&&&&%.....", "......#&&&&&&&&&&#.....", "......@&&&&&&&&&&@.....", ".......$&&&&&&&&$......", ".......+$&&&&&&$+......", "........ @#%%#@ .......", ".......................", ".......................", ".......................", ".......................", ".......................", "......................."}; const char *inputRecOff_xpm[] = { "23 23 8 1", " c #242523", ". c #252724", "+ c #332F2E", "@ c #594E4F", "# c #896E6D", "$ c #8D7271", "% c #A68384", "& c #B18E8F", " ", " ", " ", " ", " ", " .@#%%#@. ", " +$&&&&&&$+ ", " .$&&&&&&&&$. ", " @&&&&&&&&&&@ ", " #&&&&&&&&&&# ", " %&&&&&&&&&&% ", " %&&&&&&&&&&% ", " #&&&&&&&&&&# ", " @&&&&&&&&&&@ ", " $&&&&&&&&$ ", " +$&&&&&&$+ ", " .@#%%#@. ", " ", " ", " ", " ", " ", " "}; const char *muteOff_xpm[] = { "18 18 8 1", " c #242523", ". c #2E2F2D", "+ c #3B3C3A", "@ c #525451", "# c #6F716E", "$ c #878986", "% c #ADAFAC", "& c #C6C8C5", " ", " ", " ", " ", " ++. .++ ", " +&&$ $&&+ ", " +&&% %&&+ ", " +&%&++&%&+ ", " +&$&##&$&+ ", " +&#%$$%#&+ ", " +&#$%%$#&+ ", " +&#@&&@#&+ ", " +&#+&&+#&+ ", " .#@ ## @#. ", " ", " ", " ", " "}; const char *muteOn_xpm[] = { "18 18 8 1", " c #4D4F4C", ". c #585A57", "+ c #616260", "@ c #7A7C79", "# c #888A87", "$ c #989A97", "% c #B2B4B1", "& c #C6C8C5", " ", " ", " ", " ", " .. .. ", " +&&$ $&&+ ", " +&&% %&&+ ", " +&%&++&%&+ ", " +&$&@@&$&+ ", " +&#%$$%#&+ ", " +&#$&&$#&+ ", " +&#@&&@#&+ ", " +&#.&&.#&+ ", " .#+ ## +#. ", " ", " ", " ", " "}; const char *readActionOff_xpm[] = { "18 18 8 1", " c #242523", ". c #393B38", "+ c #555754", "@ c #6B6D6A", "# c #7F807E", "$ c #9C9E9B", "% c #B1B3B0", "& c #C3C5C2", " ", " ", " ", " ", " .... ", " %&&&&%+ ", " %&@@@&& ", " %% $&. ", " %&@@#&$ ", " %&&&&@ ", " %% +&$ ", " %% #&# ", " %% %&+ ", " @@ .#+ ", " ", " ", " ", " "}; const char *readActionOn_xpm[] = { "18 18 8 1", " c #4D4F4C", ". c #696B68", "+ c #7A7C79", "@ c #888A87", "# c #939592", "$ c #A7A9A6", "% c #B7B9B6", "& c #C4C6C3", " ", " ", " ", " ", " ", " %&&&&%. ", " %&++@&& ", " %% $& ", " %&@@#&$ ", " %&&&&@ ", " %% +&$ ", " %% #&# ", " %% %&. ", " +@ .@+ ", " ", " ", " ", " "}; const char *metronomeOff_xpm[] = { "13 13 8 1", " c #242523", ". c #2D2928", "+ c #34302F", "@ c #443D3C", "# c #4F4445", "$ c #685659", "% c #826A68", "& c #A18282", " ", " ", " . . ", " #% %# ", " .&+ +&. ", " %$ $% ", " @& &@ ", " &@ @& ", " $% %$ ", " +&. .&+ ", " %# #% ", " . . ", " "}; const char *metronomeOn_xpm[] = { "13 13 8 1", " c #4D4F4C", ". c #565150", "+ c #645C5C", "@ c #716465", "# c #837070", "$ c #8F7775", "% c #977C7B", "& c #A68787", " ", " ", " . . ", " @% %@ ", " .&. .&. ", " $# #$ ", " +& &+ ", " &+ +& ", " #$ $# ", " .&. .&. ", " %@ @% ", " . . ", " "}; const char *zoomInOff_xpm[] = { "18 18 8 1", " c None", ". c #252525", "+ c #262626", "@ c #535353", "# c #ACACAC", "$ c #AEAEAE", "% c #B1B1B1", "& c #C4C4C4", "++++++++++++++++++", "+................+", "+................+", "+................+", "+................+", "+.......@@.......+", "+.......#$.......+", "+.......#$.......+", "+....@%%&&%%@....+", "+....@%%&&%%@....+", "+.......#$.......+", "+.......#$.......+", "+.......@@.......+", "+................+", "+................+", "+................+", "+................+", "++++++++++++++++++"}; const char *zoomInOn_xpm[] = { "18 18 8 1", " c None", ". c #4E4E4E", "+ c #707070", "@ c #717171", "# c #B3B3B3", "$ c #B5B5B5", "% c #B7B7B7", "& c #C5C5C5", "..................", "..................", "..................", "..................", "..................", "........++........", "........#$........", "........#$........", ".....@%%&&%%@.....", ".....@%%&&%%@.....", "........#$........", "........#$........", "........++........", "..................", "..................", "..................", "..................", ".................."}; const char *zoomOutOff_xpm[] = { "18 18 5 1", " c None", ". c #252525", "+ c #262626", "@ c #9C9C9C", "# c #BBBBBB", "++++++++++++++++++", "+................+", "+................+", "+................+", "+................+", "+................+", "+................+", "+................+", "+......@##@......+", "+......@##@......+", "+................+", "+................+", "+................+", "+................+", "+................+", "+................+", "+................+", "++++++++++++++++++"}; const char *zoomOutOn_xpm[] = { "18 18 4 1", " c None", ". c #4E4E4E", "+ c #A7A7A7", "@ c #BEBEBE", "..................", "..................", "..................", "..................", "..................", "..................", "..................", "..................", ".......+@@+.......", ".......+@@+.......", "..................", "..................", "..................", "..................", "..................", "..................", "..................", ".................."}; const char *scrollRightOff_xpm[] = { "12 12 8 1", " c #181917", ". c #242523", "+ c #2E2F2D", "@ c #4D4F4C", "# c #5D5F5C", "$ c #828481", "% c #9B9D9A", "& c #BCBEBB", "............", "............", "...+........", "...&$@......", "...$&&%@....", "....+#%&%...", "....+#%&%...", "...$&&%#....", "...&$@......", "...+........", "............", "............"}; const char *scrollLeftOff_xpm[] = { "12 12 8 1", " c #181917", ". c #242523", "+ c #2E2F2D", "@ c #4D4F4C", "# c #5D5F5C", "$ c #828481", "% c #9B9D9A", "& c #BCBEBB", "............", "............", "........+...", "......@$&...", "....@%&&$...", "...%&%#+....", "...%&%#+....", "....#%&&$...", "......@$&...", "........+...", "............", "............"}; const char *scrollLeftOn_xpm[] = { "12 12 8 1", " c #4D4F4C", ". c #6B6D6A", "+ c #7B7D7A", "@ c #969895", "# c #A6A8A5", "$ c #B4B6B3", "% c #C0C2BF", "& c #FEFFFC", " ", " ", " ", " .@$ ", " +#%%@ ", " $%#+ ", " %%#+ ", " +$%%@ ", " .#$ ", " ", " ", " "}; const char *scrollRightOn_xpm[] = { "12 12 8 1", " c #4D4F4C", ". c #6B6D6A", "+ c #7B7D7A", "@ c #969895", "# c #A6A8A5", "$ c #B4B6B3", "% c #C0C2BF", "& c #FEFFFC", " ", " ", " ", " %@. ", " @%%#. ", " +#%# ", " +#%# ", " @%%#+ ", " %@. ", " ", " ", " "}; const char *soloOn_xpm[] = { "18 18 8 1", " c #4D4F4C", ". c #616360", "+ c #737572", "@ c #838582", "# c #929491", "$ c #A5A7A4", "% c #B1B3B0", "& c #C6C8C5", " ", " ", " ", " ", " .@+. ", " #&&&&# ", " .&$ %&. ", " &%+ .. ", " #&&&$. ", " .@$&&. ", " .#. @&@ ", " .&$. #&+ ", " #&&&&$ ", " .+@+ ", " ", " ", " ", " "}; const char *soloOff_xpm[] = { "18 18 8 1", " c #242523", ". c #3D3F3D", "+ c #525451", "@ c #666865", "# c #80827F", "$ c #979996", "% c #A7A9A6", "& c #C6C8C5", " ", " ", " ", " ", " .@@. ", " #&&&&# ", " .&$ %&. ", " &%+ .. ", " #&&&$+ ", " .@%&&. ", " +#. @&@ ", " .&$..#&+ ", " #&&&&$ ", " .@@+ ", " ", " ", " ", " "}; #ifdef WITH_VST const char *fxOff_xpm[] = { "18 18 8 1", " c #242523", ". c #40423F", "+ c #4D4E4C", "@ c #686A67", "# c #7B7D7A", "$ c #919390", "% c #AEB0AD", "& c #C1C3C0", " ", " ", " ", " ", " ", " ..... . . ", " $&&&$ $% @&. ", " $$ .&#&@ ", " $%##. @&$ ", " $%##. #&% ", " $$ .&@&# ", " $$ %$ @&. ", " .. + +. ", " ", " ", " ", " ", " "}; const char *fxOn_xpm[] = { "18 18 8 1", " c #4D4F4C", ". c #565855", "+ c #636562", "@ c #80827F", "# c #8E908D", "$ c #9FA19E", "% c #B1B3B0", "& c #C1C3C0", " ", " ", " ", " ", " ", " .++++ +. +. ", " $&&&$ $% @&. ", " $$ .&#&@ ", " $%##+ @&$ ", " $%##+ #&% ", " $$ +&@&# ", " $$ %$ @&+ ", " ++ .+. ++ ", " ", " ", " ", " ", " "}; const char *fxShiftUpOff_xpm[] = { "18 18 7 1", " c #242523", ". c #4D4F4C", "+ c #A3A5A2", "@ c #868885", "# c #C1C3C0", "$ c #313330", "% c #626361", " ", " ", " ", " ", " ", " ", " .+@ ", " @+#. ", " $#%+@ ", " %# %#$ ", " +@ $#% ", " $#. @+ ", " $. $. ", " ", " ", " ", " ", " "}; const char *fxShiftUpOn_xpm[] = { "18 18 5 1", " c #4D4F4C", ". c #70726F", "+ c #A5A7A4", "@ c #C1C3BF", "# c #8E908D", " ", " ", " ", " ", " ", " ", " .++ ", " +@@. ", " @.+# ", " .@ .@ ", " +# @. ", " .@. #+ ", " . . ", " ", " ", " ", " ", " "}; const char *fxShiftDownOff_xpm[] = { "18 18 7 1", " c #242523", ". c #4D4F4C", "+ c #A3A5A2", "@ c #313330", "# c #626361", "$ c #868885", "% c #C1C3C0", " ", " ", " ", " ", " ", " ", " .+@ #$ ", " @%# +$ ", " $+ .%@ ", " .%@$+ ", " +$%# ", " #%%@ ", " @.. ", " ", " ", " ", " ", " "}; const char *fxShiftDownOn_xpm[] = { "18 18 5 1", " c #4D4F4C", ". c #70726F", "+ c #A5A7A4", "@ c #C1C3BF", "# c #8E908D", " ", " ", " ", " ", " ", " ", " .+ .+ ", " @. +# ", " #+ .@. ", " .@.#+ ", " +#@. ", " #@@ ", " .. ", " ", " ", " ", " ", " "}; const char *vstLogo_xpm[] = { "65 38 8 1", " c #161715", ". c #2B2D2A", "+ c #474846", "@ c #6A6C69", "# c #8C8E8B", "$ c #A8AAA7", "% c #C7C9C6", "& c #EEF0ED", " @#############################################################+ ", "@#.............................................................$+", "#. .#", "#. .#", "#. ...... .. .#", "#. .@$$$####$%$#@.+&$ .#", "#. .#$$#+. +#$%%%%$ .#", "#. .$$#$ .#$$%$ .#", "#. ............. ....$$$$$ ++$$%$+@@@@@@@@@@@@@@@ .#", "#. ##$$$$$$%%%%@ %%&&&&%%$@ %&@#$$@@$%%&&&%%%&&&&& .#", "#. +$$$$$%@ .&%####%$@ $&$.$# #$%%%& @&%& .#", "#. +$$$$$% +&$###$%%&&$@. $&. #$%%%&. .%& .#", "#. @$$$$%$ %##$##$%&&&&&&%#.%# #$$%%&. @& .#", "#. $$$$$%+ #& #$$%%&&&&&&&%%$$@ #$$%%&. + .#", "#. .$$$$$% +&+ .#%&&&&&&&&%$$#$$# #$$%%&. .#", "#. @$$$$%$ %$ @%&&&&&&%$$###$$ #$$%%&. .#", "#. #$$$%%@ #& . +$&&&%$####$%$ #$$%%&. .#", "#. $$$%%% .&@ +%# .@$$$###$$% #$$$%&. .#", "#. +%$%%%$$% +$$+ #$#$$$% @$$$%&. .#", "#. #%%%%%&. +%$$ ##$$%$ @$$$%%. .#", "#. $$%%%@ +%$$$. #$$$%. @$$$$%. .#", "#. +%%%$ +%$$#$@ +$$%$ @#$$$%+ .#", "#. @%%. +%%%$$$$#@++.++@#$$$@ @@##$$$%%%$$@ .#", "#. #@ +&# .@@###$$$###@. @+++@@@@###$@ .#", "#. .#", "#. .#", "#. .#", "#. .#", "#. .#", "#. .@$$$$$$$$ .$%%%%%%# .#", "#. ....... .@@@@@@@@@. .#", "#. ........ @@@+@@@@@@@@@@+ .#", "@# ......... .####@@@@@@@@@@@+ #@", " @$$$$$$$$$$$$$$$.......... .@@@@@@@@@@@@@@@@@$$$$$$$$$$$$$$$$@ ", " ......... .@@@@@@@@@@@@@@@. ", " ........ @@@@@@@@@@. ", " ........... .@@@@@@@@@ ", " .......... .@@@@@@@@ "}; const char *fxRemoveOff_xpm[] = { "18 18 9 1", " c None", ". c #242623", "+ c #2F312E", "@ c #393A38", "# c #484A47", "$ c #5D5F5C", "% c #8E908D", "& c #9B9D9A", "* c #BDBFBC", "..................", "..................", "..................", "..................", "..................", ".....+#@..@#+.....", "......&*++*&......", "......@*%%*@......", ".......$**$.......", ".......#**#.......", "......+*&&*+......", "......%*@@*%......", "......@@..@@......", "..................", "..................", "..................", "..................", ".................."}; const char *fxRemoveOn_xpm[] = { "18 18 9 1", " c None", ". c #4D4F4C", "+ c #575956", "@ c #5C5D5B", "# c #666865", "$ c #787977", "% c #9C9E9B", "& c #A6A8A5", "* c #BFC1BE", "..................", "..................", "..................", "..................", "..................", "......#@..@#......", "......&*++*&......", "......@*%%*@......", ".......$**$.......", ".......#**#.......", "......+*&&*+......", "......%*@+*%......", "......@+..+@......", "..................", "..................", "..................", "..................", ".................."}; #endif // #ifdef WITH_VST const char *beatsDivideOn_xpm[] = { "13 13 13 1", " c None", ". c #595B58", "+ c #5B5D5A", "@ c #5F615E", "# c #686967", "$ c #737572", "% c #787A77", "& c #80827F", "* c #8F918E", "= c #959794", "- c #9A9C99", "; c #C4C6C3", "> c #C7C9C6", ".............", ".............", ".............", ".............", ".....#>#.....", "....+@%@+....", "...*>>>>>*...", "....+@%@+....", ".....#>#.....", ".............", ".............", ".............", "............."}; const char *beatsDivideOff_xpm[] = { "13 13 13 1", " c None", ". c #242523", "+ c #262825", "@ c #2D2E2C", "# c #3A3B39", "$ c #494B48", "% c #525451", "& c #595B58", "* c #5F615E", "= c #787A77", "- c #858784", "; c #C3C5C1", "> c #C7C9C6", ".............", ".............", ".............", "......+......", ".....#>#.....", "...++@%@++...", "...=>>>>>=...", "...++@%@++...", ".....#>#.....", "......+......", ".............", ".............", "............."}; const char *beatsMultiplyOn_xpm[] = { "13 13 13 1", " c None", ". c #595B58", "+ c #5B5D5A", "@ c #5F615E", "# c #686967", "$ c #737572", "% c #787A77", "& c #80827F", "* c #8F918E", "= c #959794", "- c #9A9C99", "; c #C4C6C3", "> c #C7C9C6", ".............", ".............", ".............", "....$...$....", "...$;&.&;$...", "....&;-;&....", ".....->-.....", "....&;=;&....", "...$;&.&;$...", "...+$...$....", ".............", ".............", "............."}; const char *beatsMultiplyOff_xpm[] = { "13 13 12 1", " c #242523", ". c #262825", "+ c #2D2E2C", "@ c #3A3B39", "# c #494B48", "$ c #525451", "% c #595B58", "& c #5F615E", "* c #787A77", "= c #858784", "- c #C3C5C1", "; c #C7C9C6", " ", " ", " ", " .# #. ", " #-& &-# ", " &-=-& ", " =;= ", " %-*-& ", " #-% %-# ", " .# #. ", " ", " ", " "}; const char *channelStop_xpm[] = { "18 18 8 1", " c #242523", ". c #312D2C", "+ c #413A3A", "@ c #615253", "# c #73605F", "$ c #7A6663", "% c #9C7E7D", "& c #B08D8E", " ", " ", " ", " ", " ##. ", " $&%@ ", " $&&&%+ ", " $&&&&&$. ", " $&&&&&&&@ ", " $&&&&&&&@. ", " $&&&&&$. ", " $&&&%+ ", " $&&@ ", " $#. ", " . ", " ", " ", " "}; const char *channelPlay_xpm[] = { "18 18 8 1", " c #4D4F4C", ". c #554E56", "+ c #5A4D59", "@ c #605068", "# c #775086", "$ c #8A509C", "% c #9E50B5", "& c #AD52D0", " ", " ", " ", " . ", " $$. ", " $&%# ", " $&&&%@ ", " $&&&&&$. ", " $&&&&&&&#. ", " $&&&&&&&#. ", " $&&&&&$+ ", " $&&&%@ ", " $&&# ", " $$. ", " . ", " ", " ", " "}; giada-0.11.2/src/core/graphics.h000066400000000000000000000060241264622563000163400ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * graphics * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GRAPHICS_H #define GRAPHICS_H extern const char *giada_logo_xpm[]; extern const char *loopRepeat_xpm[]; extern const char *loopBasic_xpm[]; extern const char *loopOnce_xpm[]; extern const char *loopOnceBar_xpm[]; extern const char *oneshotBasic_xpm[]; extern const char *oneshotRetrig_xpm[]; extern const char *oneshotPress_xpm[]; extern const char *oneshotEndless_xpm[]; extern const char *updirOff_xpm[]; extern const char *updirOn_xpm[]; extern const char *pause_xpm[]; extern const char *play_xpm[]; extern const char *zoomInOff_xpm[]; extern const char *zoomInOn_xpm[]; extern const char *zoomOutOff_xpm[]; extern const char *zoomOutOn_xpm[]; extern const char *scrollLeftOff_xpm[]; extern const char *scrollLeftOn_xpm[]; extern const char *scrollRightOff_xpm[]; extern const char *scrollRightOn_xpm[]; extern const char *rewindOff_xpm[]; extern const char *rewindOn_xpm[]; extern const char *recOff_xpm[]; extern const char *recOn_xpm[]; extern const char *metronomeOff_xpm[]; extern const char *metronomeOn_xpm[]; extern const char *inputRecOn_xpm[]; extern const char *inputRecOff_xpm[]; extern const char *beatsDivideOn_xpm[]; extern const char *beatsDivideOff_xpm[]; extern const char *beatsMultiplyOn_xpm[]; extern const char *beatsMultiplyOff_xpm[]; extern const char *muteOff_xpm[]; extern const char *muteOn_xpm[]; extern const char *soloOff_xpm[]; extern const char *soloOn_xpm[]; extern const char *readActionOn_xpm[]; extern const char *readActionOff_xpm[]; extern const char *channelStop_xpm[]; extern const char *channelPlay_xpm[]; #ifdef WITH_VST extern const char *fxOff_xpm[]; extern const char *fxOn_xpm[]; extern const char *fxShiftUpOn_xpm[]; extern const char *fxShiftUpOff_xpm[]; extern const char *fxShiftDownOn_xpm[]; extern const char *fxShiftDownOff_xpm[]; extern const char *fxRemoveOff_xpm[]; extern const char *fxRemoveOn_xpm[]; extern const char *vstLogo_xpm[]; #endif extern const char *giada_icon[]; #endif giada-0.11.2/src/core/init.cpp000066400000000000000000000126641264622563000160450ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * init * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "../utils/utils.h" #include "../utils/gui_utils.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_warnings.h" #include "init.h" #include "mixer.h" #include "wave.h" #include "const.h" #include "mixerHandler.h" #include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "pluginHost.h" #include "recorder.h" #include "midiMapConf.h" #include "kernelMidi.h" extern Mixer G_Mixer; extern bool G_audio_status; extern bool G_quit; extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Conf G_Conf; extern MidiMapConf G_MidiMap; extern gdMainWindow *mainWin; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif void init_prepareParser() { time_t t; time (&t); gLog("[init] Giada " G_VERSION_STR " - %s", ctime(&t)); G_Conf.read(); G_Patch_DEPR_.setDefault(); G_Patch.init(); if (!gLog_init(G_Conf.logMode)) gLog("[init] log init failed! Using default stdout\n"); gLog("[init] configuration file ready\n"); } /* -------------------------------------------------------------------------- */ void init_prepareKernelAudio() { kernelAudio::openDevice( G_Conf.soundSystem, G_Conf.soundDeviceOut, G_Conf.soundDeviceIn, G_Conf.channelsOut, G_Conf.channelsIn, G_Conf.samplerate, G_Conf.buffersize); G_Mixer.init(); recorder::init(); } /* -------------------------------------------------------------------------- */ void init_prepareKernelMIDI() { kernelMidi::setApi(G_Conf.midiSystem); kernelMidi::openOutDevice(G_Conf.midiPortOut); kernelMidi::openInDevice(G_Conf.midiPortIn); } /* -------------------------------------------------------------------------- */ void init_prepareMidiMap() { G_MidiMap.init(); G_MidiMap.setDefault_DEPR_(); G_MidiMap.setDefault(); /* read with deprecated method first. If it fails, try with the new one. */ // TODO - do the opposite: if json fails, go with deprecated one if (G_MidiMap.read(G_Conf.midiMapPath) != MIDIMAP_READ_OK) { gLog("[init_prepareMidiMap] JSON-based midimap read failed, trying with the deprecated one...\n"); if (G_MidiMap.readMap_DEPR_(G_Conf.midiMapPath) == MIDIMAP_INVALID) gLog("[init_prepareMidiMap] unable to read deprecated midimap. Nothing to do\n"); } } /* -------------------------------------------------------------------------- */ void init_startGUI(int argc, char **argv) { char win_label[32]; sprintf(win_label, "%s - %s", G_APP_NAME, !strcmp(G_Patch_DEPR_.name, "") ? "(default patch)" : G_Patch_DEPR_.name); mainWin = new gdMainWindow(GUI_WIDTH, GUI_HEIGHT, win_label, argc, argv); mainWin->resize(G_Conf.mainWindowX, G_Conf.mainWindowY, G_Conf.mainWindowW, G_Conf.mainWindowH); /* never update the GUI elements if G_audio_status is bad, segfaults * are around the corner */ if (G_audio_status) gu_updateControls(); if (!G_audio_status) gdAlert( "Your soundcard isn't configured correctly.\n" "Check the configuration and restart Giada." ); } /* -------------------------------------------------------------------------- */ void init_startKernelAudio() { if (G_audio_status) kernelAudio::startStream(); #ifdef WITH_VST G_PluginHost.allocBuffers(); #endif } /* -------------------------------------------------------------------------- */ void init_shutdown() { G_quit = true; /* store position and size of the main window for the next startup */ G_Conf.mainWindowX = mainWin->x(); G_Conf.mainWindowY = mainWin->y(); G_Conf.mainWindowW = mainWin->w(); G_Conf.mainWindowH = mainWin->h(); /* close any open subwindow, especially before cleaning PluginHost to * avoid mess */ gu_closeAllSubwindows(); gLog("[init] all subwindows closed\n"); /* write configuration file */ if (!G_Conf.write()) gLog("[init] error while saving configuration file!\n"); else gLog("[init] configuration saved\n"); /* if G_audio_status we close the kernelAudio FIRST, THEN the mixer. * The opposite could cause random segfaults (even now with RtAudio?). */ if (G_audio_status) { kernelAudio::closeDevice(); G_Mixer.close(); gLog("[init] Mixer closed\n"); } recorder::clearAll(); gLog("[init] Recorder cleaned up\n"); #ifdef WITH_VST G_PluginHost.freeAllStacks(); gLog("[init] Plugin Host cleaned up\n"); #endif gLog("[init] Giada " G_VERSION_STR " closed\n\n"); gLog_close(); } giada-0.11.2/src/core/init.h000066400000000000000000000027041264622563000155040ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * init * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef INIT_H #define INIT_H #include #include #ifdef __APPLE__ #include #endif void init_prepareParser(); void init_startGUI(int argc, char **argv); void init_prepareKernelAudio(); void init_prepareKernelMIDI(); void init_prepareMidiMap(); void init_startKernelAudio(); void init_shutdown(); #endif giada-0.11.2/src/core/kernelAudio.cpp000066400000000000000000000234751264622563000173460ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelAudio * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include #include "../utils/log.h" #include "../glue/glue.h" #include "kernelAudio.h" #include "mixer.h" #include "conf.h" extern Mixer G_Mixer; extern Conf G_Conf; extern bool G_audio_status; namespace kernelAudio { RtAudio *system = NULL; unsigned numDevs = 0; bool inputEnabled = 0; unsigned realBufsize = 0; int api = 0; int openDevice( int _api, int outDev, int inDev, int outChan, int inChan, int samplerate, int buffersize) { api = _api; gLog("[KA] using system 0x%x\n", api); #if defined(__linux__) if (api == SYS_API_JACK && hasAPI(RtAudio::UNIX_JACK)) system = new RtAudio(RtAudio::UNIX_JACK); else if (api == SYS_API_ALSA && hasAPI(RtAudio::LINUX_ALSA)) system = new RtAudio(RtAudio::LINUX_ALSA); else if (api == SYS_API_PULSE && hasAPI(RtAudio::LINUX_PULSE)) system = new RtAudio(RtAudio::LINUX_PULSE); #elif defined(_WIN32) if (api == SYS_API_DS && hasAPI(RtAudio::WINDOWS_DS)) system = new RtAudio(RtAudio::WINDOWS_DS); else if (api == SYS_API_ASIO && hasAPI(RtAudio::WINDOWS_ASIO)) system = new RtAudio(RtAudio::WINDOWS_ASIO); #elif defined(__APPLE__) if (api == SYS_API_CORE && hasAPI(RtAudio::MACOSX_CORE)) system = new RtAudio(RtAudio::MACOSX_CORE); #endif else { G_audio_status = false; return 0; } //gLog("[KA] %d\n", sizeof(system->rtapi_)); gLog("[KA] Opening devices %d (out), %d (in), f=%d...\n", outDev, inDev, samplerate); numDevs = system->getDeviceCount(); if (numDevs < 1) { gLog("[KA] no devices found with this API\n"); closeDevice(); G_audio_status = false; return 0; } else { gLog("[KA] %d device(s) found\n", numDevs); for (unsigned i=0; iopenStream( &outParams, // output params inDev != -1 ? &inParams : NULL, // input params if inDevice is selected RTAUDIO_FLOAT32, // audio format samplerate, // sample rate &realBufsize, // buffer size in byte &G_Mixer.masterPlay, // audio callback NULL, // user data (unused) &options); G_audio_status = true; #if defined(__linux__) if (api == SYS_API_JACK) jackSetSyncCb(); #endif return 1; } catch (RtAudioError &e) { gLog("[KA] system init error: %s\n", e.getMessage().c_str()); closeDevice(); G_audio_status = false; return 0; } } /* -------------------------------------------------------------------------- */ int startStream() { try { system->startStream(); gLog("[KA] latency = %lu\n", system->getStreamLatency()); return 1; } catch (RtAudioError &e) { gLog("[KA] Start stream error: %s\n", e.getMessage().c_str()); return 0; } } /* -------------------------------------------------------------------------- */ int stopStream() { try { system->stopStream(); return 1; } catch (RtAudioError &e) { gLog("[KA] Stop stream error\n"); return 0; } } /* -------------------------------------------------------------------------- */ string getDeviceName(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).name; } catch (RtAudioError &e) { gLog("[KA] invalid device ID = %d\n", dev); return ""; } } /* -------------------------------------------------------------------------- */ int closeDevice() { if (system->isStreamOpen()) { #if defined(__linux__) || defined(__APPLE__) system->abortStream(); // stopStream seems to lock the thread #elif defined(_WIN32) system->stopStream(); // on Windows it's the opposite #endif system->closeStream(); delete system; system = NULL; } return 1; } /* -------------------------------------------------------------------------- */ unsigned getMaxInChans(int dev) { if (dev == -1) return 0; try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).inputChannels; } catch (RtAudioError &e) { gLog("[KA] Unable to get input channels\n"); return 0; } } /* -------------------------------------------------------------------------- */ unsigned getMaxOutChans(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).outputChannels; } catch (RtAudioError &e) { gLog("[KA] Unable to get output channels\n"); return 0; } } /* -------------------------------------------------------------------------- */ bool isProbed(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).probed; } catch (RtAudioError &e) { return 0; } } /* -------------------------------------------------------------------------- */ unsigned getDuplexChans(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).duplexChannels; } catch (RtAudioError &e) { return 0; } } /* -------------------------------------------------------------------------- */ bool isDefaultIn(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultInput; } catch (RtAudioError &e) { return 0; } } /* -------------------------------------------------------------------------- */ bool isDefaultOut(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).isDefaultOutput; } catch (RtAudioError &e) { return 0; } } /* -------------------------------------------------------------------------- */ int getTotalFreqs(unsigned dev) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.size(); } catch (RtAudioError &e) { return 0; } } /* -------------------------------------------------------------------------- */ int getFreq(unsigned dev, int i) { try { return ((RtAudio::DeviceInfo) system->getDeviceInfo(dev)).sampleRates.at(i); } catch (RtAudioError &e) { return 0; } } /* -------------------------------------------------------------------------- */ int getDefaultIn() { return system->getDefaultInputDevice(); } int getDefaultOut() { return system->getDefaultOutputDevice(); } /* -------------------------------------------------------------------------- */ int getDeviceByName(const char *name) { for (unsigned i=0; i APIs; RtAudio::getCompiledApi(APIs); for (unsigned i=0; i #include #include jack_client_t *jackGetHandle() { return (jack_client_t*) system->rtapi_->__HACK__getJackClient(); } void jackStart() { if (api == SYS_API_JACK) { jack_client_t *client = jackGetHandle(); jack_transport_start(client); } } void jackStop() { if (api == SYS_API_JACK) { jack_client_t *client = jackGetHandle(); jack_transport_stop(client); } } void jackSetSyncCb() { jack_client_t *client = jackGetHandle(); jack_set_sync_callback(client, jackSyncCb, NULL); //jack_set_sync_timeout(client, 8); } int jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg) { switch (state) { case JackTransportStopped: gLog("[KA] Jack transport stopped, frame=%d\n", pos->frame); glue_stopSeq(false); // false = not from GUI if (pos->frame == 0) glue_rewindSeq(); break; case JackTransportRolling: gLog("[KA] Jack transport rolling\n"); break; case JackTransportStarting: gLog("[KA] Jack transport starting, frame=%d\n", pos->frame); glue_startSeq(false); // false = not from GUI if (pos->frame == 0) glue_rewindSeq(); break; default: gLog("[KA] Jack transport [unknown]\n"); } return 1; } #endif } giada-0.11.2/src/core/kernelAudio.h000066400000000000000000000056351264622563000170110ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelAudio * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef KERNELAUDIO_H #define KERNELAUDIO_H #include "../deps/rtaudio-mod/RtAudio.h" #if defined(__linux__) #include #include #include #endif using std::string; namespace kernelAudio { int openDevice( int api, int outDev, int inDev, int outChan, int inChan, int samplerate, int buffersize); int closeDevice(); int startStream(); int stopStream(); bool isProbed (unsigned dev); bool isDefaultIn (unsigned dev); bool isDefaultOut (unsigned dev); string getDeviceName (unsigned dev); unsigned getMaxInChans (int dev); unsigned getMaxOutChans (unsigned dev); unsigned getDuplexChans (unsigned dev); int getTotalFreqs (unsigned dev); int getFreq (unsigned dev, int i); int getDeviceByName (const char *name); int getDefaultOut (); int getDefaultIn (); bool hasAPI (int API); string getRtAudioVersion(); #ifdef __linux__ jack_client_t *jackGetHandle(); void jackStart(); void jackStop(); void jackSetSyncCb(); int jackSyncCb(jack_transport_state_t state, jack_position_t *pos, void *arg); #endif /* *** how to avoid multiple definition of *** * When you declare a variable in a header file, every source file that * includes that header, either directly or indirectly, gets its own * separate copy of the variable. Then when you go to link all the .o * files together, the linker sees that the variable is instantiated * in a bunch of .o files. Make it extern in the header file and * instantiate it in memory.cpp. */ extern RtAudio *system; extern unsigned numDevs; extern bool inputEnabled; extern unsigned realBufsize; // reale bufsize from the soundcard extern int api; } #endif giada-0.11.2/src/core/kernelMidi.cpp000066400000000000000000000246301264622563000171610ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelMidi * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "../glue/glue.h" #include "kernelMidi.h" #include "mixer.h" #include "channel.h" #include "sampleChannel.h" #include "pluginHost.h" #include "conf.h" #include "midiMapConf.h" extern bool G_midiStatus; extern Conf G_Conf; extern Mixer G_Mixer; extern MidiMapConf G_MidiMap; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif using std::string; namespace kernelMidi { int api = 0; // one api for both in & out RtMidiOut *midiOut = NULL; RtMidiIn *midiIn = NULL; unsigned numOutPorts = 0; unsigned numInPorts = 0; cb_midiLearn *cb_learn = NULL; void *cb_data = NULL; void __sendMidiLightningInitMsgs__() { for(unsigned i=0; igetPortCount(); gLog("[KM] %d output MIDI ports found\n", numOutPorts); for (unsigned i=0; i 0) { try { midiOut->openPort(port, getOutPortName(port)); gLog("[KM] MIDI out port %d open\n", port); /* TODO - it shold send midiLightning message only if there is a map loaded and available in G_MidiMap. */ __sendMidiLightningInitMsgs__(); return 1; } catch (RtMidiError &error) { gLog("[KM] unable to open MIDI out port %d: %s\n", port, error.getMessage().c_str()); G_midiStatus = false; return 0; } } else return 2; } /* -------------------------------------------------------------------------- */ int openInDevice(int port) { try { midiIn = new RtMidiIn((RtMidi::Api) api, "Giada MIDI input"); G_midiStatus = true; } catch (RtMidiError &error) { gLog("[KM] MIDI in device error: %s\n", error.getMessage().c_str()); G_midiStatus = false; return 0; } /* print input ports */ numInPorts = midiIn->getPortCount(); gLog("[KM] %d input MIDI ports found\n", numInPorts); for (unsigned i=0; i 0) { try { midiIn->openPort(port, getInPortName(port)); midiIn->ignoreTypes(true, false, true); // ignore all system/time msgs, for now gLog("[KM] MIDI in port %d open\n", port); midiIn->setCallback(&callback); return 1; } catch (RtMidiError &error) { gLog("[KM] unable to open MIDI in port %d: %s\n", port, error.getMessage().c_str()); G_midiStatus = false; return 0; } } else return 2; } /* -------------------------------------------------------------------------- */ bool hasAPI(int API) { std::vector APIs; RtMidi::getCompiledApi(APIs); for (unsigned i=0; igetPortName(p); } catch (RtMidiError &error) { return ""; } } string getInPortName(unsigned p) { try { return midiIn->getPortName(p); } catch (RtMidiError &error) { return ""; } } /* -------------------------------------------------------------------------- */ void send(uint32_t data) { if (!G_midiStatus) return; std::vector msg(1, getB1(data)); msg.push_back(getB2(data)); msg.push_back(getB3(data)); midiOut->sendMessage(&msg); gLog("[KM] send msg=0x%X (%X %X %X)\n", data, msg[0], msg[1], msg[2]); } /* -------------------------------------------------------------------------- */ void send(int b1, int b2, int b3) { if (!G_midiStatus) return; std::vector msg(1, b1); if (b2 != -1) msg.push_back(b2); if (b3 != -1) msg.push_back(b3); midiOut->sendMessage(&msg); //gLog("[KM] send msg=(%X %X %X)\n", b1, b2, b3); } /* -------------------------------------------------------------------------- */ void callback(double t, std::vector *msg, void *data) { /* 0.8.0 - for now we handle other midi signals (common and real-time * messages) as unknown, for debugging purposes */ if (msg->size() < 3) { gLog("[KM] MIDI received - unkown signal - size=%d, value=0x", (int) msg->size()); for (unsigned i=0; isize(); i++) gLog("%X", (int) msg->at(i)); gLog("\n"); return; } /* in this place we want to catch two things: a) note on/note off * from a keyboard and b) knob/wheel/slider movements from a * controller */ uint32_t input = getIValue(msg->at(0), msg->at(1), msg->at(2)); uint32_t chan = input & 0x0F000000; uint32_t value = input & 0x0000FF00; uint32_t pure = 0x00; if (!G_Conf.noNoteOff) pure = input & 0xFFFF0000; // input without 'value' byte else pure = input & 0xFFFFFF00; // input with 'value' byte gLog("[KM] MIDI received - 0x%X (chan %d)", input, chan >> 24); /* start dispatcher. If midi learn is on don't parse channels, just * learn incoming midi signal. Otherwise process master events first, * then each channel in the stack. This way incoming signals don't * get processed by glue_* when midi learning is on. */ if (cb_learn) { gLog("\n"); cb_learn(pure, cb_data); } else { /* process master events */ if (pure == G_Conf.midiInRewind) { gLog(" >>> rewind (global) (pure=0x%X)", pure); glue_rewindSeq(); } else if (pure == G_Conf.midiInStartStop) { gLog(" >>> startStop (global) (pure=0x%X)", pure); glue_startStopSeq(); } else if (pure == G_Conf.midiInActionRec) { gLog(" >>> actionRec (global) (pure=0x%X)", pure); glue_startStopActionRec(); } else if (pure == G_Conf.midiInInputRec) { gLog(" >>> inputRec (global) (pure=0x%X)", pure); glue_startStopInputRec(false, false); // update gui, no popup messages } else if (pure == G_Conf.midiInMetronome) { gLog(" >>> metronome (global) (pure=0x%X)", pure); glue_startStopMetronome(false); } else if (pure == G_Conf.midiInVolumeIn) { float vf = (value >> 8)/127.0f; gLog(" >>> input volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf); glue_setInVol(vf, false); } else if (pure == G_Conf.midiInVolumeOut) { float vf = (value >> 8)/127.0f; gLog(" >>> output volume (global) (pure=0x%X, value=%d, float=%f)", pure, value >> 8, vf); glue_setOutVol(vf, false); } else if (pure == G_Conf.midiInBeatDouble) { gLog(" >>> sequencer x2 (global) (pure=0x%X)", pure); glue_beatsMultiply(); } else if (pure == G_Conf.midiInBeatHalf) { gLog(" >>> sequencer /2 (global) (pure=0x%X)", pure); glue_beatsDivide(); } /* process channels */ for (unsigned i=0; imidiIn) continue; if (pure == ch->midiInKeyPress) { gLog(" >>> keyPress, ch=%d (pure=0x%X)", ch->index, pure); glue_keyPress(ch, false, false); } else if (pure == ch->midiInKeyRel) { gLog(" >>> keyRel ch=%d (pure=0x%X)", ch->index, pure); glue_keyRelease(ch, false, false); } else if (pure == ch->midiInMute) { gLog(" >>> mute ch=%d (pure=0x%X)", ch->index, pure); glue_setMute(ch, false); } else if (pure == ch->midiInSolo) { gLog(" >>> solo ch=%d (pure=0x%X)", ch->index, pure); ch->solo ? glue_setSoloOn(ch, false) : glue_setSoloOff(ch, false); } else if (pure == ch->midiInVolume) { float vf = (value >> 8)/127.0f; gLog(" >>> volume ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf); glue_setChanVol(ch, vf, false); } else if (pure == ((SampleChannel*)ch)->midiInPitch) { float vf = (value >> 8)/(127/4.0f); // [0-127] ~> [0.0 4.0] gLog(" >>> pitch ch=%d (pure=0x%X, value=%d, float=%f)", ch->index, pure, value >> 8, vf); glue_setPitch(NULL, (SampleChannel*)ch, vf, false); } else if (pure == ((SampleChannel*)ch)->midiInReadActions) { gLog(" >>> start/stop read actions ch=%d (pure=0x%X)", ch->index, pure); glue_startStopReadingRecs((SampleChannel*)ch, false); } } gLog("\n"); } } /* -------------------------------------------------------------------------- */ std::string getRtMidiVersion() { return midiOut->getVersion(); } /* -------------------------------------------------------------------------- */ } // namespace giada-0.11.2/src/core/kernelMidi.h000066400000000000000000000053531264622563000166270ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * KernelMidi * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef KERNELMIDI_H #define KERNELMIDI_H #include #include #include "channel.h" using std::string; namespace kernelMidi { extern int api; // one api for both in & out extern unsigned numOutPorts; extern unsigned numInPorts; typedef void (cb_midiLearn) (uint32_t, void *); /* cb_learn * callback prepared by the gdMidiGrabber window and called by * kernelMidi. It contains things to do once the midi message has been * stored. */ extern cb_midiLearn *cb_learn; extern void *cb_data; void startMidiLearn(cb_midiLearn *cb, void *data); void stopMidiLearn(); inline int getB1(uint32_t iValue) { return (iValue >> 24) & 0xFF; } inline int getB2(uint32_t iValue) { return (iValue >> 16) & 0xFF; } inline int getB3(uint32_t iValue) { return (iValue >> 8) & 0xFF; } inline uint32_t getIValue(int b1, int b2, int b3) { return (b1 << 24) | (b2 << 16) | (b3 << 8) | (0x00); } /* send * send a MIDI message 's' (uint32_t). */ void send(uint32_t s); /* send (2) * send separate bytes of MIDI message. */ void send(int b1, int b2=-1, int b3=-1); /* setApi * set the Api in use for both in & out messages. */ void setApi(int api); /* open/close/in/outDevice */ int openOutDevice(int port); int openInDevice(int port); int closeInDevice(); int closeOutDevice(); /* getIn/OutPortName * return the name of the port 'p'. */ string getInPortName(unsigned p); string getOutPortName(unsigned p); bool hasAPI(int API); /* callback * master callback for input events. */ void callback(double t, std::vector *msg, void *data); string getRtMidiVersion(); } #endif giada-0.11.2/src/core/midiChannel.cpp000066400000000000000000000204221264622563000173040ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../utils/log.h" #include "midiChannel.h" #include "channel.h" #include "pluginHost.h" #include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "kernelMidi.h" extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif MidiChannel::MidiChannel(int bufferSize) : Channel (CHANNEL_MIDI, STATUS_OFF, bufferSize), midiOut (false), midiOutChan(MIDI_CHANS[0]) { #ifdef WITH_VST // init VstEvents stack freeVstMidiEvents(true); #endif } /* -------------------------------------------------------------------------- */ MidiChannel::~MidiChannel() {} /* -------------------------------------------------------------------------- */ void MidiChannel::copy(const Channel *_src) { Channel::copy(_src); MidiChannel *src = (MidiChannel *) _src; midiOut = src->midiOut; midiOutChan = src->midiOutChan; } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void MidiChannel::freeVstMidiEvents(bool init) { if (events.numEvents == 0 && !init) return; memset(events.events, 0, sizeof(VstEvent*) * MAX_VST_EVENTS); events.numEvents = 0; events.reserved = 0; } #endif /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void MidiChannel::addVstMidiEvent(uint32_t msg) { addVstMidiEvent(G_PluginHost.createVstMidiEvent(msg)); } #endif /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void MidiChannel::addVstMidiEvent(VstMidiEvent *e) { if (events.numEvents < MAX_VST_EVENTS) { events.events[events.numEvents] = (VstEvent*) e; events.numEvents++; /* gLog("[MidiChannel] VstMidiEvent added - numEvents=%d offset=%d note=%d number=%d velo=%d\n", events.numEvents, e->deltaFrames, e->midiData[0], e->midiData[1], e->midiData[2] );*/ } else gLog("[MidiChannel] channel %d VstEvents = %d > MAX_VST_EVENTS, nothing to do\n", index, events.numEvents); } #endif /* -------------------------------------------------------------------------- */ void MidiChannel::onBar(int frame) {} /* -------------------------------------------------------------------------- */ void MidiChannel::stop() {} /* -------------------------------------------------------------------------- */ void MidiChannel::empty() {} /* -------------------------------------------------------------------------- */ void MidiChannel::quantize(int index, int localFrame, int globalFrame) {} /* -------------------------------------------------------------------------- */ #ifdef WITH_VST VstEvents *MidiChannel::getVstEvents() { return (VstEvents *) &events; } #endif /* -------------------------------------------------------------------------- */ void MidiChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) { if (a->type == ACTION_MIDI) sendMidi(a, localFrame/2); } /* -------------------------------------------------------------------------- */ void MidiChannel::onZero(int frame) { if (status == STATUS_ENDING) { status = STATUS_OFF; sendMidiLplay(); } else if (status == STATUS_WAIT) { status = STATUS_PLAY; sendMidiLplay(); } } /* -------------------------------------------------------------------------- */ void MidiChannel::setMute(bool internal) { mute = true; // internal mute does not exist for midi (for now) if (midiOut) kernelMidi::send(MIDI_ALL_NOTES_OFF); #ifdef WITH_VST addVstMidiEvent(MIDI_ALL_NOTES_OFF); #endif sendMidiLmute(); } /* -------------------------------------------------------------------------- */ void MidiChannel::unsetMute(bool internal) { mute = false; // internal mute does not exist for midi (for now) sendMidiLmute(); } /* -------------------------------------------------------------------------- */ void MidiChannel::process(float *buffer) { #ifdef WITH_VST G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this); freeVstMidiEvents(); #endif for (int j=0; jmidiOut; midiOutChan = pch->midiOutChan; return SAMPLE_LOADED_OK; /// TODO - change name, it's meaningless here } /* -------------------------------------------------------------------------- */ void MidiChannel::sendMidi(recorder::action *a, int localFrame) { if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) { if (midiOut) kernelMidi::send(a->iValue | MIDI_CHANS[midiOutChan]); #ifdef WITH_VST a->event->deltaFrames = localFrame; addVstMidiEvent(a->event); #endif } } void MidiChannel::sendMidi(uint32_t data) { if (status & (STATUS_PLAY | STATUS_ENDING) && !mute) { if (midiOut) kernelMidi::send(data | MIDI_CHANS[midiOutChan]); #ifdef WITH_VST addVstMidiEvent(data); #endif } } /* -------------------------------------------------------------------------- */ void MidiChannel::rewind() { if (midiOut) kernelMidi::send(MIDI_ALL_NOTES_OFF); #ifdef WITH_VST addVstMidiEvent(MIDI_ALL_NOTES_OFF); #endif } /* -------------------------------------------------------------------------- */ int MidiChannel::writePatch(int i, bool isProject) { int pchIndex = Channel::writePatch(i, isProject); Patch::channel_t *pch = &G_Patch.channels.at(pchIndex); pch->midiOut = midiOut; pch->midiOutChan = midiOutChan; return 0; } giada-0.11.2/src/core/midiChannel.h000066400000000000000000000074141264622563000167570ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef MIDI_CHANNEL_H #define MIDI_CHANNEL_H #include "channel.h" #ifdef WITH_VST /* before including aeffetx(x).h we must define __cdecl, otherwise VST * headers can't be compiled correctly. In windows __cdecl is already * defined. */ #ifdef __GNUC__ #ifndef _WIN32 #define __cdecl #endif #endif #include "../deps/vst/aeffectx.h" #endif class MidiChannel : public Channel { public: MidiChannel(int bufferSize); ~MidiChannel(); bool midiOut; // enable midi output uint8_t midiOutChan; // midi output channel void copy (const Channel *src); void process (float *buffer); void start (int frame, bool doQuantize); void kill (int frame); void empty (); void stopBySeq (); void stop (); void rewind (); void setMute (bool internal); void unsetMute (bool internal); int readPatch_DEPR_ (const char *file, int i); int readPatch (const string &basePath, int i); int writePatch (int i, bool isProject); void quantize (int index, int localFrame, int globalFrame); void onZero (int frame); void onBar (int frame); void parseAction(recorder::action *a, int localFrame, int globalFrame); /* ---------------------------------------------------------------- */ /* sendMidi * send Midi event to the outside world. */ void sendMidi(recorder::action *a, int localFrame); void sendMidi(uint32_t data); #ifdef WITH_VST /* getVstEvents * return a pointer to gVstEvents. */ VstEvents *getVstEvents(); /* freeVstMidiEvents * empty vstEvents structure. Init: use the method for channel * initialization. */ void freeVstMidiEvents(bool init=false); /* addVstMidiEvent * take a composite MIDI event, decompose it and add it to channel. The * other version creates a VstMidiEvent on the fly. */ void addVstMidiEvent(struct VstMidiEvent *e); void addVstMidiEvent(uint32_t msg); #endif /* ---------------------------------------------------------------- */ #ifdef WITH_VST /* VST struct containing MIDI events. When ready, events are sent to * each plugin in the channel. * * Anatomy of VstEvents * -------------------- * * VstInt32 numEvents = number of Events in array * VstIntPtr reserved = zero (Reserved for future use) * VstEvent *events[n] = event pointer array, variable size * * Note that by default VstEvents only holds three events- if you want * it to hold more, create an equivalent struct with a larger array, * and then cast it to a VstEvents object when you've populated it. * That's what we do with gVstEvents! */ struct gVstEvents { VstInt32 numEvents; VstIntPtr reserved; VstEvent *events[MAX_VST_EVENTS]; } events; #endif }; #endif giada-0.11.2/src/core/midiMapConf.cpp000066400000000000000000000272361264622563000172710ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * midiMapConf * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include "midiMapConf.h" #include "const.h" #include "../utils/utils.h" #include "../utils/log.h" using std::string; using std::vector; void MidiMapConf::init() { midimapsPath = gGetHomePath() + gGetSlash() + "midimaps" + gGetSlash(); /* scan dir of midi maps and load the filenames into <>maps. */ gLog("[MidiMapConf::init] scanning midimaps directory...\n"); DIR *dp; dirent *ep; dp = opendir(midimapsPath.c_str()); if (!dp) { gLog("[MidiMapConf::init] unable to scan midimaps directory!\n"); return; } while ((ep = readdir(dp))) { if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) continue; // TODO - check if is a valid midimap file (verify headers) gLog("[MidiMapConf::init] found midimap '%s'\n", ep->d_name); maps.push_back(ep->d_name); } gLog("[MidiMapConf::init] total midimaps found: %d\n", maps.size()); closedir(dp); } /* -------------------------------------------------------------------------- */ void MidiMapConf::setDefault() { brand = ""; device = ""; muteOn.channel = 0; muteOn.valueStr = ""; muteOn.offset = -1; muteOn.value = 0; muteOff.channel = 0; muteOff.valueStr = ""; muteOff.offset = -1; muteOff.value = 0; soloOn.channel = 0; soloOn.valueStr = ""; soloOn.offset = -1; soloOn.value = 0; soloOff.channel = 0; soloOff.valueStr = ""; soloOff.offset = -1; soloOff.value = 0; waiting.channel = 0; waiting.valueStr = ""; waiting.offset = -1; waiting.value = 0; playing.channel = 0; playing.valueStr = ""; playing.offset = -1; playing.value = 0; stopping.channel = 0; stopping.valueStr = ""; stopping.offset = -1; stopping.value = 0; stopped.channel = 0; stopped.valueStr = ""; stopped.offset = -1; stopped.value = 0; } /* -------------------------------------------------------------------------- */ int MidiMapConf::read(const string &file) { if (file.empty()) { gLog("[MidiMapConf::read] midimap not specified, nothing to do\n"); return MIDIMAP_NOT_SPECIFIED; } gLog("[MidiMapConf::read] reading midimap file '%s'\n", file.c_str()); string path = midimapsPath + file; jRoot = json_load_file(path.c_str(), 0, &jError); if (!jRoot) { gLog("[MidiMapConf::read] unreadable midimap file. Error on line %d: %s\n", jError.line, jError.text); return MIDIMAP_UNREADABLE; } if (!setString(jRoot, MIDIMAP_KEY_BRAND, brand)) return MIDIMAP_UNREADABLE; if (!setString(jRoot, MIDIMAP_KEY_DEVICE, device)) return MIDIMAP_UNREADABLE; if (!readInitCommands(jRoot)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &muteOn, MIDIMAP_KEY_MUTE_ON)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &muteOff, MIDIMAP_KEY_MUTE_OFF)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &soloOn, MIDIMAP_KEY_SOLO_ON)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &soloOff, MIDIMAP_KEY_SOLO_OFF)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &waiting, MIDIMAP_KEY_WAITING)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &playing, MIDIMAP_KEY_PLAYING)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &stopping, MIDIMAP_KEY_STOPPING)) return MIDIMAP_UNREADABLE; if (!readCommand(jRoot, &stopped, MIDIMAP_KEY_STOPPED)) return MIDIMAP_UNREADABLE; /* parse messages */ parse(&muteOn); parse(&muteOff); parse(&soloOn); parse(&soloOff); parse(&waiting); parse(&playing); parse(&stopping); parse(&stopped); return MIDIMAP_READ_OK; } /* -------------------------------------------------------------------------- */ bool MidiMapConf::readInitCommands(json_t *jContainer) { json_t *jInitCommands = json_object_get(jContainer, MIDIMAP_KEY_INIT_COMMANDS); if (!checkArray(jInitCommands, MIDIMAP_KEY_INIT_COMMANDS)) return 0; size_t commandIndex; json_t *jInitCommand; json_array_foreach(jInitCommands, commandIndex, jInitCommand) { string indexStr = "init command " + gItoa(commandIndex); if (!checkObject(jInitCommand, indexStr.c_str())) return 0; message_t message; if (!setInt(jInitCommand, MIDIMAP_KEY_CHANNEL, message.channel)) return 0; if (!setString(jInitCommand, MIDIMAP_KEY_MESSAGE, message.valueStr)) return 0; message.value = strtoul(message.valueStr.c_str(), NULL, 16); initCommands.push_back(message); } return 1; } /* -------------------------------------------------------------------------- */ bool MidiMapConf::readCommand(json_t *jContainer, message_t *msg, const string &key) { json_t *jCommand = json_object_get(jContainer, key.c_str()); if (!checkObject(jCommand, key.c_str())) return 0; if (!setInt(jCommand, MIDIMAP_KEY_CHANNEL, msg->channel)) return 0; if (!setString(jCommand, MIDIMAP_KEY_MESSAGE, msg->valueStr)) return 0; return 1; } /* -------------------------------------------------------------------------- */ void MidiMapConf::parse(message_t *message) { /* Remove '0x' part from the original string. */ string input = message->valueStr.replace(0, 2, ""); /* Then transform string value into the actual uint32_t value, by parsing * each char (i.e. nibble) in the original string. Substitute 'n' with * zeros. */ string output; for (unsigned i=0, p=24; ioffset == -1) // do it once message->offset = p; } else output += input[i]; } /* from string to uint32_t */ message->value = strtoul(output.c_str(), NULL, 16); gLog("[MidiMapConf::parse] parsed chan=%d valueStr=%s value=%#x, offset=%d\n", message->channel, message->valueStr.c_str(), message->value, message->offset); } /* -------------------------------------------------------------------------- */ void MidiMapConf::setDefault_DEPR_() { brand = ""; device = ""; for (int i=0; i ic; gSplit(getValue("init_commands"), ";", &ic); for (unsigned i=0; i<(unsigned)MAX_INIT_COMMANDS && i. * * -------------------------------------------------------------------------- */ #ifndef __MIDIMAPCONF_H__ #define __MIDIMAPCONF_H__ #include #include #include #include "dataStorageIni.h" #include "dataStorageJson.h" #include "../utils/utils.h" #if defined(__APPLE__) #include #endif using std::string; using std::vector; class MidiMapConf : public DataStorageIni, public DataStorageJson { public: struct message_t { int channel; string valueStr; int offset; uint32_t value; }; string brand; string device; vector initCommands; message_t muteOn; message_t muteOff; message_t soloOn; message_t soloOff; message_t waiting; message_t playing; message_t stopping; message_t stopped; /* midimapsPath * path of midimap files, different between OSes. */ string midimapsPath; /* maps * Maps are the available .giadamap files. Each element of the vector * represents a .giadamap filename. */ vector maps; /* init Parse the midi maps folders and find the available maps. */ void init(); /* setDefault Set default values in case no maps are available/choosen. */ void setDefault(); /* read Read a midi map from file 'file'. */ int read(const string &file); /* --- DEPRECATED STUFF --------------------------------------------------- */ /* --- DEPRECATED STUFF --------------------------------------------------- */ /* --- DEPRECATED STUFF --------------------------------------------------- */ static const int MAX_INIT_COMMANDS = 32; static const int MAX_MIDI_BYTES = 4; static const int MAX_MIDI_NIBBLES = 8; /* init_* * init_commands. These messages are sent to the physical device as a wake up * signal. */ int init_channels[MAX_INIT_COMMANDS]; uint32_t init_messages[MAX_INIT_COMMANDS]; /* events * [event]Channel: the MIDI output channel to send the event to * [event]notePos: the byte where the note is stored ('nn' placeholder) * [event]offset: the note offset (i.e. of 'nn' placeholder) */ int muteOnChan; int muteOnOffset; uint32_t muteOnMsg; int muteOffChan; int muteOffOffset; uint32_t muteOffMsg; int soloOnChan; int soloOnOffset; uint32_t soloOnMsg; int soloOffChan; int soloOffOffset; uint32_t soloOffMsg; int waitingChan; int waitingOffset; uint32_t waitingMsg; int playingChan; int playingOffset; uint32_t playingMsg; int stoppingChan; int stoppingOffset; uint32_t stoppingMsg; int stoppedChan; int stoppedOffset; uint32_t stoppedMsg; /* setDefault Set default values in case no maps are available/choosen. */ void setDefault_DEPR_(); /* readMap Read a midi map from file 'file'. */ int readMap_DEPR_(string file); private: bool readInitCommands(json_t *jContainer); bool readCommand(json_t *jContainer, message_t *msg, const string &key); void parse(message_t *message); /* --- DEPRECATED STUFF --------------------------------------------------- */ /* --- DEPRECATED STUFF --------------------------------------------------- */ /* --- DEPRECATED STUFF --------------------------------------------------- */ void close_DEPR_(); void parse_DEPR_(string key, int *chan, uint32_t *msg, int *offset); }; #endif giada-0.11.2/src/core/mixer.cpp000066400000000000000000000436001264622563000162200ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * mixer * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "../utils/gui_utils.h" #include "mixer.h" #include "init.h" #include "wave.h" #include "recorder.h" #include "pluginHost.h" #include "patch_DEPR_.h" #include "conf.h" #include "mixerHandler.h" #include "channel.h" #include "sampleChannel.h" #include "midiChannel.h" #include "kernelMidi.h" extern Mixer G_Mixer; extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif Mixer::Mixer() : vChanInput(NULL), vChanInToOut(NULL) {} /* -------------------------------------------------------------------------- */ Mixer::~Mixer() {} /* -------------------------------------------------------------------------- */ #define TICKSIZE 38 float Mixer::tock[TICKSIZE] = { 0.059033, 0.117240, 0.173807, 0.227943, 0.278890, 0.325936, 0.368423, 0.405755, 0.437413, 0.462951, 0.482013, 0.494333, 0.499738, 0.498153, 0.489598, 0.474195, 0.452159, 0.423798, 0.389509, 0.349771, 0.289883, 0.230617, 0.173194, 0.118739, 0.068260, 0.022631, -0.017423, -0.051339, -0.078721, -0.099345, -0.113163, -0.120295, -0.121028, -0.115804, -0.105209, -0.089954, -0.070862, -0.048844 }; float Mixer::tick[TICKSIZE] = { 0.175860, 0.341914, 0.488904, 0.608633, 0.694426, 0.741500, 0.747229, 0.711293, 0.635697, 0.524656, 0.384362, 0.222636, 0.048496, -0.128348, -0.298035, -0.451105, -0.579021, -0.674653, -0.732667, -0.749830, -0.688924, -0.594091, -0.474481, -0.340160, -0.201360, -0.067752, 0.052194, 0.151746, 0.226280, 0.273493, 0.293425, 0.288307, 0.262252, 0.220811, 0.170435, 0.117887, 0.069639, 0.031320 }; /* -------------------------------------------------------------------------- */ void Mixer::init() { quanto = 1; docross = false; rewindWait = false; running = false; ready = true; waitRec = 0; actualFrame = 0; bpm = DEFAULT_BPM; bars = DEFAULT_BARS; beats = DEFAULT_BEATS; quantize = DEFAULT_QUANTIZE; metronome = false; tickTracker = 0; tockTracker = 0; tickPlay = false; tockPlay = false; outVol = DEFAULT_OUT_VOL; inVol = DEFAULT_IN_VOL; peakOut = 0.0f; peakIn = 0.0f; chanInput = NULL; inputTracker = 0; actualBeat = 0; midiTCstep = 0; midiTCrate = (G_Conf.samplerate / G_Conf.midiTCfps) * 2; // dealing with stereo vals midiTCframes = 0; midiTCseconds = 0; midiTCminutes = 0; midiTChours = 0; /* alloc virtual input channels. vChanInput malloc is done in * updateFrameBars, because of its variable size */ /** TODO - set kernelAudio::realBufsize * 2 as private member */ vChanInput = NULL; vChanInToOut = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float)); pthread_mutex_init(&mutex_recs, NULL); pthread_mutex_init(&mutex_chans, NULL); pthread_mutex_init(&mutex_plugins, NULL); updateFrameBars(); rewind(); } /* -------------------------------------------------------------------------- */ Channel *Mixer::addChannel(int type) { Channel *ch; int bufferSize = kernelAudio::realBufsize*2; if (type == CHANNEL_SAMPLE) ch = new SampleChannel(bufferSize); else ch = new MidiChannel(bufferSize); while (true) { int lockStatus = pthread_mutex_trylock(&mutex_chans); if (lockStatus == 0) { channels.push_back(ch); pthread_mutex_unlock(&mutex_chans); break; } } ch->index = getNewIndex(); gLog("[mixer] channel index=%d added, type=%d, total=%d\n", ch->index, ch->type, channels.size()); return ch; } /* -------------------------------------------------------------------------- */ int Mixer::getNewIndex() { /* always skip last channel: it's the last one just added */ if (channels.size() == 1) return 0; int index = 0; for (unsigned i=0; iindex > index) index = channels.at(i)->index; } index += 1; return index; } /* -------------------------------------------------------------------------- */ int Mixer::deleteChannel(Channel *ch) { int index = -1; for (unsigned i=0; iindex); return 0; } int lockStatus; while (true) { lockStatus = pthread_mutex_trylock(&mutex_chans); if (lockStatus == 0) { channels.erase(channels.begin() + index); delete ch; pthread_mutex_unlock(&mutex_chans); return 1; } //else // gLog("[mixer::deleteChannel] waiting for mutex...\n"); } } /* -------------------------------------------------------------------------- */ Channel *Mixer::getChannelByIndex(int index) { for (unsigned i=0; iindex == index) return channels.at(i); gLog("[mixer::getChannelByIndex] channel at index %d not found!\n", index); return NULL; } /* -------------------------------------------------------------------------- */ void Mixer::sendMIDIsync() { if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { if (actualFrame % (framesPerBeat/24) == 0) kernelMidi::send(MIDI_CLOCK, -1, -1); } else if (G_Conf.midiSync == MIDI_SYNC_MTC_M) { /* check if a new timecode frame has passed. If so, send MIDI TC * quarter frames. 8 quarter frames, divided in two branches: * 1-4 and 5-8. We check timecode frame's parity: if even, send * range 1-4, if odd send 5-8. */ if (actualFrame % midiTCrate == 0) { /* frame low nibble * frame high nibble * seconds low nibble * seconds high nibble */ if (midiTCframes % 2 == 0) { kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes & 0x0F) | 0x00, -1); kernelMidi::send(MIDI_MTC_QUARTER, (midiTCframes >> 4) | 0x10, -1); kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds & 0x0F) | 0x20, -1); kernelMidi::send(MIDI_MTC_QUARTER, (midiTCseconds >> 4) | 0x30, -1); } /* minutes low nibble * minutes high nibble * hours low nibble * hours high nibble SMPTE frame rate */ else { kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes & 0x0F) | 0x40, -1); kernelMidi::send(MIDI_MTC_QUARTER, (midiTCminutes >> 4) | 0x50, -1); kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours & 0x0F) | 0x60, -1); kernelMidi::send(MIDI_MTC_QUARTER, (midiTChours >> 4) | 0x70, -1); } midiTCframes++; /* check if total timecode frames are greater than timecode fps: * if so, a second has passed */ if (midiTCframes > G_Conf.midiTCfps) { midiTCframes = 0; midiTCseconds++; if (midiTCseconds >= 60) { midiTCminutes++; midiTCseconds = 0; if (midiTCminutes >= 60) { midiTChours++; midiTCminutes = 0; } } //gLog("%d:%d:%d:%d\n", midiTChours, midiTCminutes, midiTCseconds, midiTCframes); } } } } /* -------------------------------------------------------------------------- */ void Mixer::sendMIDIrewind() { midiTCframes = 0; midiTCseconds = 0; midiTCminutes = 0; midiTChours = 0; /* For cueing the slave to a particular start point, Quarter Frame * messages are not used. Instead, an MTC Full Frame message should * be sent. The Full Frame is a SysEx message that encodes the entire * SMPTE time in one message */ if (G_Conf.midiSync == MIDI_SYNC_MTC_M) { kernelMidi::send(MIDI_SYSEX, 0x7F, 0x00); // send msg on channel 0 kernelMidi::send(0x01, 0x01, 0x00); // hours 0 kernelMidi::send(0x00, 0x00, 0x00); // mins, secs, frames 0 kernelMidi::send(MIDI_EOX, -1, -1); // end of sysex } } /* -------------------------------------------------------------------------- */ int Mixer::masterPlay( void *out_buf, void *in_buf, unsigned n_frames, double streamTime, RtAudioStreamStatus status, void *userData) { return G_Mixer.__masterPlay(out_buf, in_buf, n_frames); } /* -------------------------------------------------------------------------- */ int Mixer::__masterPlay(void *out_buf, void *in_buf, unsigned bufferFrames) { if (!ready) return 0; float *outBuf = ((float *) out_buf); float *inBuf = ((float *) in_buf); bufferFrames *= 2; // stereo peakOut = 0.0f; // reset peak calculator peakIn = 0.0f; // reset peak calculator /* always clean each buffer */ memset(outBuf, 0, sizeof(float) * bufferFrames); // out memset(vChanInToOut, 0, sizeof(float) * bufferFrames); // inToOut vChan pthread_mutex_lock(&mutex_chans); for (unsigned i=0; itype == CHANNEL_SAMPLE) ((SampleChannel*)channels.at(i))->clear(); pthread_mutex_unlock(&mutex_chans); for (unsigned j=0; j peakIn) peakIn = inBuf[j] * inVol; /* "hear what you're playing" - process, copy and paste the input buffer * onto the output buffer */ if (inToOut) { vChanInToOut[j] = inBuf[j] * inVol; vChanInToOut[j+1] = inBuf[j+1] * inVol; } } /* operations to do if the sequencer is running: * - compute quantizer * - time check for LOOP_REPEAT * - reset loops at beat 0 * - read recorded actions * - reset actualFrame */ if (running) { /* line in recording */ if (chanInput != NULL && kernelAudio::inputEnabled) { /* delay comp: wait until waitRec reaches delayComp. WaitRec * returns to 0 in mixerHandler, as soon as the recording ends */ if (waitRec < G_Conf.delayComp) waitRec += 2; else { vChanInput[inputTracker] += inBuf[j] * inVol; vChanInput[inputTracker+1] += inBuf[j+1] * inVol; inputTracker += 2; if (inputTracker >= totalFrames) inputTracker = 0; } } /* quantizer computations: quantize rewind and all channels. */ if (quantize > 0 && quanto > 0) { if (actualFrame % (quanto) == 0) { // is quanto! if (rewindWait) { rewindWait = false; rewind(); } pthread_mutex_lock(&mutex_chans); for (unsigned k=0; kquantize(k, j, actualFrame); // j == localFrame pthread_mutex_unlock(&mutex_chans); } } /* reset LOOP_REPEAT, if a bar has passed */ if (actualFrame % framesPerBar == 0 && actualFrame != 0) { if (metronome) tickPlay = true; pthread_mutex_lock(&mutex_chans); for (unsigned k=0; konBar(j); pthread_mutex_unlock(&mutex_chans); } /* reset loops on beat 0 */ if (actualFrame == 0) { pthread_mutex_lock(&mutex_chans); for (unsigned k=0; konZero(j); pthread_mutex_unlock(&mutex_chans); } /* reading all actions recorded */ pthread_mutex_lock(&mutex_recs); for (unsigned y=0; ychan; Channel *ch = getChannelByIndex(index); ch->parseAction(recorder::global.at(y).at(z), j, actualFrame); } break; } } pthread_mutex_unlock(&mutex_recs); /* increase actualFrame */ actualFrame += 2; /* if actualFrame > totalFrames the sequencer returns to frame 0, * beat 0. This must be the last operation. */ if (actualFrame > totalFrames) { actualFrame = 0; actualBeat = 0; } else if (actualFrame % framesPerBeat == 0 && actualFrame > 0) { actualBeat++; /* avoid tick and tock to overlap when a new bar has passed (which * is also a beat) */ if (metronome && !tickPlay) tockPlay = true; } sendMIDIsync(); } // if (running) /* sum channels, CHANNEL_SAMPLE only */ pthread_mutex_lock(&mutex_chans); for (unsigned k=0; ktype == CHANNEL_SAMPLE) ((SampleChannel*)channels.at(k))->sum(j, running); } pthread_mutex_unlock(&mutex_chans); /* metronome play */ /** FIXME - move this one after the peak meter calculation */ if (tockPlay) { outBuf[j] += tock[tockTracker]; outBuf[j+1] += tock[tockTracker]; tockTracker++; if (tockTracker >= TICKSIZE-1) { tockPlay = false; tockTracker = 0; } } if (tickPlay) { outBuf[j] += tick[tickTracker]; outBuf[j+1] += tick[tickTracker]; tickTracker++; if (tickTracker >= TICKSIZE-1) { tickPlay = false; tickTracker = 0; } } } // end loop J /* final loop: sum virtual channels and process plugins. */ pthread_mutex_lock(&mutex_chans); for (unsigned k=0; kprocess(outBuf); pthread_mutex_unlock(&mutex_chans); /* processing fxs master in & out, if any. */ #ifdef WITH_VST pthread_mutex_lock(&mutex_plugins); G_PluginHost.processStack(outBuf, PluginHost::MASTER_OUT); G_PluginHost.processStack(vChanInToOut, PluginHost::MASTER_IN); pthread_mutex_unlock(&mutex_plugins); #endif /* post processing master fx + peak calculation. */ for (unsigned j=0; j peakOut) peakOut = outBuf[j]; if (G_Conf.limitOutput) { if (outBuf[j] > 1.0f) outBuf[j] = 1.0f; else if (outBuf[j] < -1.0f) outBuf[j] = -1.0f; if (outBuf[j+1] > 1.0f) outBuf[j+1] = 1.0f; else if (outBuf[j+1] < -1.0f) outBuf[j+1] = -1.0f; } } return 0; } /* -------------------------------------------------------------------------- */ void Mixer::updateFrameBars() { /* seconds ....... total time of play (in seconds) of the whole * sequencer. 60 / bpm == how many seconds lasts one bpm * totalFrames ... number of frames in the whole sequencer, x2 because * it's stereo * framesPerBar .. n. of frames within a bar * framesPerBeat . n. of frames within a beat */ float seconds = (60.0f / bpm) * beats; totalFrames = G_Conf.samplerate * seconds * 2; framesPerBar = totalFrames / bars; framesPerBeat = totalFrames / beats; framesInSequencer = framesPerBeat * MAX_BEATS; /* big troubles if frames are odd. */ if (totalFrames % 2 != 0) totalFrames--; if (framesPerBar % 2 != 0) framesPerBar--; if (framesPerBeat % 2 != 0) framesPerBeat--; updateQuanto(); /* realloc input virtual channel, if not NULL. TotalFrames is changed! */ if (vChanInput != NULL) free(vChanInput); vChanInput = (float*) malloc(totalFrames * sizeof(float)); if (!vChanInput) gLog("[Mixer] vChanInput realloc error!\n"); } /* -------------------------------------------------------------------------- */ int Mixer::close() { running = false; while (channels.size() > 0) deleteChannel(channels.at(0)); if (vChanInput) { free(vChanInput); vChanInput = NULL; } if (vChanInToOut) { free(vChanInToOut); vChanInToOut = NULL; } return 1; } /* -------------------------------------------------------------------------- */ bool Mixer::isSilent() { for (unsigned i=0; istatus == STATUS_PLAY) return false; return true; } /* -------------------------------------------------------------------------- */ void Mixer::rewind() { actualFrame = 0; actualBeat = 0; if (running) for (unsigned i=0; irewind(); sendMIDIrewind(); } /* -------------------------------------------------------------------------- */ void Mixer::updateQuanto() { /* big troubles if frames are odd. */ if (quantize != 0) quanto = framesPerBeat / quantize; if (quanto % 2 != 0) quanto++; } /* -------------------------------------------------------------------------- */ bool Mixer::hasLogicalSamples() { for (unsigned i=0; itype == CHANNEL_SAMPLE) if (((SampleChannel*)channels.at(i))->wave) if (((SampleChannel*)channels.at(i))->wave->isLogical) return true; return false; } /* -------------------------------------------------------------------------- */ bool Mixer::hasEditedSamples() { for (unsigned i=0; itype == CHANNEL_SAMPLE) if (((SampleChannel*)channels.at(i))->wave) if (((SampleChannel*)channels.at(i))->wave->isEdited) return true; return false; } /* -------------------------------------------------------------------------- */ bool Mixer::mergeVirtualInput() { if (vChanInput == NULL) { gLog("[Mixer] virtual input channel not alloc'd\n"); return false; } else { #ifdef WITH_VST G_PluginHost.processStackOffline(vChanInput, PluginHost::MASTER_IN, 0, totalFrames); #endif int numFrames = totalFrames*sizeof(float); memcpy(chanInput->wave->data, vChanInput, numFrames); memset(vChanInput, 0, numFrames); // clear vchan return true; } } giada-0.11.2/src/core/mixer.h000066400000000000000000000116101264622563000156610ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * mixer * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef MIXER_H #define MIXER_H #include #include #include #include "const.h" #include "kernelAudio.h" #include "../utils/utils.h" using std::vector; class Mixer { public: Mixer(); ~Mixer(); void init(); int close(); /* addChannel * add a new channel without any wave inside of it. */ class Channel *addChannel(int type); /* deleteChannel * completely remove a channel from the stack. */ int deleteChannel(class Channel *ch); /* masterPlay * core method (callback) */ static int masterPlay( void *out_buf, void *in_buf, unsigned n_frames, double streamTime, RtAudioStreamStatus status, void *userData ); int __masterPlay(void *out_buf, void *in_buf, unsigned n_frames); /* updateFrameBars * updates bpm, frames, beats and so on. */ void updateFrameBars(); /* isSilent * is mixer silent? */ bool isSilent(); /* rewind * rewind sequencer to sample 0. */ void rewind(); /* updateQuanto * recomputes the quanto between two quantizations */ void updateQuanto(); /* hasLogicalSamples * true if 1 or more samples are logical (memory only, such as takes) */ bool hasLogicalSamples(); /* hasEditedSamples * true if 1 or more samples was edited via gEditor */ bool hasEditedSamples(); /* mergeVirtualInput * memcpy the virtual channel input in the channel designed for input * recording. Called by mixerHandler on stopInputRec() */ bool mergeVirtualInput(); /* getChannelByIndex * return channel with given index 'i'. */ Channel *getChannelByIndex(int i); /* getLastChannel * Return last channel in the stack. */ inline Channel* getLastChannel() { return channels.back(); } /* ---------------------------------------------------------------- */ enum { // const - what to do when a fadeout ends DO_STOP = 0x01, DO_MUTE = 0x02, DO_MUTE_I = 0x04 }; enum { // const - fade types FADEOUT = 0x01, XFADE = 0x02 }; vector channels; bool running; bool ready; float *vChanInput; // virtual channel for recording float *vChanInToOut; // virtual channel in->out bridge (hear what you're playin) int frameSize; float outVol; float inVol; float peakOut; float peakIn; int quanto; char quantize; bool metronome; float bpm; int bars; int beats; int waitRec; // delayComp guard bool docross; // crossfade guard bool rewindWait; // rewind guard, if quantized int framesPerBar; // frames in one bar int framesPerBeat; // frames in one beat int framesInSequencer; // frames in the whole sequencer int totalFrames; // frames in the selected range (e.g. 4/4) int actualFrame; int actualBeat; #define TICKSIZE 38 static float tock[TICKSIZE]; static float tick[TICKSIZE]; int tickTracker, tockTracker; bool tickPlay, tockPlay; // 1 = play, 0 = stop /* chanInput * the active channel during a recording. NULL = no channels active */ class SampleChannel *chanInput; /* inputTracker * position of the sample in the input side (recording) */ int inputTracker; /* inToOut * copy, process and paste the input into the output, in order to * obtain a "hear what you're playing" feature. */ bool inToOut; pthread_mutex_t mutex_recs; pthread_mutex_t mutex_chans; pthread_mutex_t mutex_plugins; private: int midiTCstep; // part of MTC to send (0 to 7) int midiTCrate; // send MTC data every midiTCrate frames int midiTCframes; int midiTCseconds; int midiTCminutes; int midiTChours; /* getNewIndex * compute new index value for new channels */ int getNewIndex(); /* sendMIDIsync * generate MIDI sync output data */ void sendMIDIsync(); /* sendMIDIrewind * rewind timecode to beat 0 and also send a MTC full frame to cue * the slave */ void sendMIDIrewind(); }; #endif giada-0.11.2/src/core/mixerHandler.cpp000066400000000000000000000160051264622563000175150ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * mixerHandler * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #if defined(__linux__) #include #include #include #endif #include #include "../utils/utils.h" #include "../utils/log.h" #include "../glue/glue.h" #include "../glue/channel.h" #include "mixerHandler.h" #include "kernelMidi.h" #include "mixer.h" #include "const.h" #include "init.h" #include "pluginHost.h" #include "plugin.h" #include "waveFx.h" #include "conf.h" #include "patch_DEPR_.h" #include "patch.h" #include "recorder.h" #include "channel.h" #include "sampleChannel.h" #include "wave.h" extern Mixer G_Mixer; extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif using std::vector; #ifdef WITH_VST static int __mh_readPatchPlugins__(vector *list, int type) { int ret = 1; for (unsigned i=0; isize(); i++) { Patch::plugin_t *ppl = &list->at(i); Plugin *plugin = G_PluginHost.addPlugin(ppl->path.c_str(), type, NULL); if (plugin != NULL) { plugin->bypass = ppl->bypass; for (unsigned j=0; jparams.size(); j++) plugin->setParam(j, ppl->params.at(j)); ret &= 1; } else ret &= 0; } return ret; } #endif /* -------------------------------------------------------------------------- */ void mh_stopSequencer() { G_Mixer.running = false; for (unsigned i=0; istopBySeq(); } /* -------------------------------------------------------------------------- */ bool mh_uniqueSolo(Channel *ch) { int solos = 0; for (unsigned i=0; isolo) solos++; if (solos > 1) return false; } return true; } /* -------------------------------------------------------------------------- */ /** TODO - revision needed: mh should not call glue_addChannel */ void mh_loadPatch_DEPR_(bool isProject, const char *projPath) { G_Mixer.init(); G_Mixer.ready = false; // put it in wait mode int numChans = G_Patch_DEPR_.getNumChans(); for (int i=0; ireadPatch_DEPR_(samplePath.c_str(), i); } G_Mixer.outVol = G_Patch_DEPR_.getOutVol(); G_Mixer.inVol = G_Patch_DEPR_.getInVol(); G_Mixer.bpm = G_Patch_DEPR_.getBpm(); G_Mixer.bars = G_Patch_DEPR_.getBars(); G_Mixer.beats = G_Patch_DEPR_.getBeats(); G_Mixer.quantize = G_Patch_DEPR_.getQuantize(); G_Mixer.metronome = G_Patch_DEPR_.getMetronome(); G_Patch_DEPR_.lastTakeId = G_Patch_DEPR_.getLastTakeId(); G_Patch_DEPR_.samplerate = G_Patch_DEPR_.getSamplerate(); /* rewind and update frames in Mixer (it's vital) */ G_Mixer.rewind(); G_Mixer.updateFrameBars(); G_Mixer.ready = true; } /* -------------------------------------------------------------------------- */ void mh_readPatch() { G_Mixer.ready = false; G_Mixer.outVol = G_Patch.masterVolOut; G_Mixer.inVol = G_Patch.masterVolIn; G_Mixer.bpm = G_Patch.bpm; G_Mixer.bars = G_Patch.bars; G_Mixer.beats = G_Patch.beats; G_Mixer.quantize = G_Patch.quantize; G_Mixer.metronome = G_Patch.metronome; #ifdef WITH_VST __mh_readPatchPlugins__(&G_Patch.masterInPlugins, PluginHost::MASTER_IN); __mh_readPatchPlugins__(&G_Patch.masterOutPlugins, PluginHost::MASTER_OUT); #endif /* rewind and update frames in Mixer (it's essential) */ G_Mixer.rewind(); G_Mixer.updateFrameBars(); G_Mixer.ready = true; } /* -------------------------------------------------------------------------- */ void mh_rewindSequencer() { if (G_Mixer.quantize > 0 && G_Mixer.running) // quantize rewind G_Mixer.rewindWait = true; else G_Mixer.rewind(); } /* -------------------------------------------------------------------------- */ SampleChannel *mh_startInputRec() { /* search for the next available channel */ SampleChannel *chan = NULL; for (unsigned i=0; itype == CHANNEL_SAMPLE) if (((SampleChannel*) G_Mixer.channels.at(i))->canInputRec()) { chan = (SampleChannel*) G_Mixer.channels.at(i); break; } } /* no chans available? */ if (chan == NULL) return NULL; Wave *w = new Wave(); if (!w->allocEmpty(G_Mixer.totalFrames, G_Conf.samplerate)) return NULL; /* increase lastTakeId until the sample name TAKE-[n] is unique */ char name[32]; sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId); while (!mh_uniqueSamplename(chan, name)) { G_Patch_DEPR_.lastTakeId++; G_Patch.lastTakeId++; sprintf(name, "TAKE-%d", G_Patch_DEPR_.lastTakeId); } chan->allocEmpty(G_Mixer.totalFrames, G_Patch_DEPR_.lastTakeId); G_Mixer.chanInput = chan; /* start to write from the actualFrame, not the beginning */ /** FIXME: move this before wave allocation*/ G_Mixer.inputTracker = G_Mixer.actualFrame; gLog( "[mh] start input recs using chan %d with size %d, frame=%d\n", chan->index, G_Mixer.totalFrames, G_Mixer.inputTracker ); return chan; } /* -------------------------------------------------------------------------- */ SampleChannel *mh_stopInputRec() { gLog("[mh] stop input recs\n"); G_Mixer.mergeVirtualInput(); SampleChannel *ch = G_Mixer.chanInput; G_Mixer.chanInput = NULL; G_Mixer.waitRec = 0; // if delay compensation is in use return ch; } /* -------------------------------------------------------------------------- */ bool mh_uniqueSamplename(SampleChannel *ch, const char *name) { for (unsigned i=0; itype == CHANNEL_SAMPLE) { SampleChannel *other = (SampleChannel*) G_Mixer.channels.at(i); if (other->wave != NULL) if (!strcmp(name, other->wave->name.c_str())) return false; } } } return true; } giada-0.11.2/src/core/mixerHandler.h000066400000000000000000000042721264622563000171650ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * mixerHandler * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef MIXERHANDLER_H #define MIXERHANDLER_H #include #include "recorder.h" #include "patch.h" using std::vector; /* stopSequencer * stop the sequencer, with special case if samplesStopOnSeqHalt is * true. */ void mh_stopSequencer(); void mh_rewindSequencer(); /* uniqueSolo * true if ch is the only solo'd channel in mixer. */ bool mh_uniqueSolo(class Channel *ch); /* loadPatch * load a path or a project (if isProject) into Mixer. If isProject, path * must contain the address of the project folder. */ void mh_loadPatch_DEPR_(bool isProject, const char *projPath=0); void mh_readPatch(); /* startInputRec - record from line in * creates a new empty wave in the first available channels and returns * the chan number chosen, otherwise -1 if there are no more empty * channels available. */ SampleChannel *mh_startInputRec(); SampleChannel *mh_stopInputRec(); /* uniqueSamplename * return true if samplename 'n' is unique. Requires SampleChannel *ch * in order to skip check against itself. */ bool mh_uniqueSamplename(class SampleChannel *ch, const char *name); #endif giada-0.11.2/src/core/patch.cpp000066400000000000000000000474451264622563000162060ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * patch * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "../utils/utils.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/elems/ge_keyboard.h" #include "patch.h" #include "const.h" #include "init.h" #include "recorder.h" #include "conf.h" #include "pluginHost.h" #include "wave.h" #include "mixer.h" #include "channel.h" extern Mixer G_Mixer; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif extern gdMainWindow *mainWin; void Patch::init() { columns.clear(); channels.clear(); #ifdef WITH_VST masterInPlugins.clear(); masterOutPlugins.clear(); #endif header = "GIADAPTC"; lastTakeId = 0; samplerate = DEFAULT_SAMPLERATE; } /* -------------------------------------------------------------------------- */ int Patch::write(const string &file) { jRoot = json_object(); writeCommons(jRoot); writeColumns(jRoot, &columns); writeChannels(jRoot, &channels); #ifdef WITH_VST writePlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS); writePlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS); #endif if (json_dump_file(jRoot, file.c_str(), JSON_COMPACT) != 0) { gLog("[Patch::write] unable to write patch file!\n"); return 0; } return 1; } /* -------------------------------------------------------------------------- */ int Patch::read(const string &file) { jRoot = json_load_file(file.c_str(), 0, &jError); if (!jRoot) { gLog("[Patch::read] unable to read patch file! Error on line %d: %s\n", jError.line, jError.text); return PATCH_UNREADABLE; } if (!checkObject(jRoot, "root element")) return PATCH_INVALID; init(); /* TODO json_decref also when PATCH_INVALID */ if (!readCommons(jRoot)) return setInvalid(); if (!readColumns(jRoot)) return setInvalid(); if (!readChannels(jRoot)) return setInvalid(); #ifdef WITH_VST if (!readPlugins(jRoot, &masterInPlugins, PATCH_KEY_MASTER_IN_PLUGINS)) return setInvalid(); if (!readPlugins(jRoot, &masterOutPlugins, PATCH_KEY_MASTER_OUT_PLUGINS)) return setInvalid(); #endif json_decref(jRoot); sanitize(); return PATCH_READ_OK; } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void Patch::writePlugins(json_t *jContainer, vector *plugins, const char *key) { json_t *jPlugins = json_array(); for (unsigned j=0; jsize(); j++) { json_t *jPlugin = json_object(); plugin_t plugin = plugins->at(j); json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_PATH, json_string(plugin.path.c_str())); json_object_set_new(jPlugin, PATCH_KEY_PLUGIN_BYPASS, json_boolean(plugin.bypass)); json_array_append_new(jPlugins, jPlugin); /* plugin params */ json_t *jPluginParams = json_array(); for (unsigned z=0; z *columns) { json_t *jColumns = json_array(); for (unsigned i=0; isize(); i++) { json_t *jColumn = json_object(); column_t column = columns->at(i); json_object_set_new(jColumn, PATCH_KEY_COLUMN_INDEX, json_integer(column.index)); json_object_set_new(jColumn, PATCH_KEY_COLUMN_WIDTH, json_integer(column.width)); json_array_append_new(jColumns, jColumn); } json_object_set_new(jContainer, PATCH_KEY_COLUMNS, jColumns); } /* -------------------------------------------------------------------------- */ void Patch::writeActions(json_t *jContainer, vector *actions) { json_t *jActions = json_array(); for (unsigned k=0; ksize(); k++) { json_t *jAction = json_object(); action_t action = actions->at(k); json_object_set_new(jAction, PATCH_KEY_ACTION_TYPE, json_integer(action.type)); json_object_set_new(jAction, PATCH_KEY_ACTION_FRAME, json_integer(action.frame)); json_object_set_new(jAction, PATCH_KEY_ACTION_F_VALUE, json_real(action.fValue)); json_object_set_new(jAction, PATCH_KEY_ACTION_I_VALUE, json_integer(action.iValue)); json_array_append_new(jActions, jAction); } json_object_set_new(jContainer, PATCH_KEY_CHANNEL_ACTIONS, jActions); } /* -------------------------------------------------------------------------- */ void Patch::writeCommons(json_t *jContainer) { json_object_set_new(jContainer, PATCH_KEY_HEADER, json_string(header.c_str())); json_object_set_new(jContainer, PATCH_KEY_VERSION, json_string(version.c_str())); json_object_set_new(jContainer, PATCH_KEY_VERSION_MAJOR, json_integer(versionMajor)); json_object_set_new(jContainer, PATCH_KEY_VERSION_MINOR, json_integer(versionMinor)); json_object_set_new(jContainer, PATCH_KEY_VERSION_PATCH, json_integer(versionPatch)); json_object_set_new(jContainer, PATCH_KEY_NAME, json_string(name.c_str())); json_object_set_new(jContainer, PATCH_KEY_BPM, json_real(bpm)); json_object_set_new(jContainer, PATCH_KEY_BARS, json_integer(bars)); json_object_set_new(jContainer, PATCH_KEY_BEATS, json_integer(beats)); json_object_set_new(jContainer, PATCH_KEY_QUANTIZE, json_integer(quantize)); json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_IN, json_real(masterVolIn)); json_object_set_new(jContainer, PATCH_KEY_MASTER_VOL_OUT, json_real(masterVolOut)); json_object_set_new(jContainer, PATCH_KEY_METRONOME, json_integer(metronome)); json_object_set_new(jContainer, PATCH_KEY_LAST_TAKE_ID, json_integer(lastTakeId)); json_object_set_new(jContainer, PATCH_KEY_SAMPLERATE, json_integer(samplerate)); } /* -------------------------------------------------------------------------- */ void Patch::writeChannels(json_t *jContainer, vector *channels) { json_t *jChannels = json_array(); for (unsigned i=0; isize(); i++) { json_t *jChannel = json_object(); channel_t channel = channels->at(i); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_TYPE, json_integer(channel.type)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_INDEX, json_integer(channel.index)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_COLUMN, json_integer(channel.column)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE, json_integer(channel.mute)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MUTE_S, json_integer(channel.mute_s)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SOLO, json_integer(channel.solo)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_VOLUME, json_real(channel.volume)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PAN_LEFT, json_real(channel.panLeft)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PAN_RIGHT, json_real(channel.panRight)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN, json_boolean(channel.midiIn)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS, json_integer(channel.midiInKeyPress)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL, json_integer(channel.midiInKeyRel)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL, json_integer(channel.midiInKill)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME, json_integer(channel.midiInVolume)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE, json_integer(channel.midiInMute)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO, json_integer(channel.midiInSolo)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L, json_boolean(channel.midiOutL)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING, json_integer(channel.midiOutLplaying)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE, json_integer(channel.midiOutLmute)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO, json_integer(channel.midiOutLsolo)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH, json_string(channel.samplePath.c_str())); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_KEY, json_integer(channel.key)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MODE, json_integer(channel.mode)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BEGIN, json_integer(channel.begin)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_END, json_integer(channel.end)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_BOOST, json_real(channel.boost)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE, json_integer(channel.recActive)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_PITCH, json_real(channel.pitch)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, json_integer(channel.midiInReadActions)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH, json_integer(channel.midiInPitch)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT, json_integer(channel.midiOut)); json_object_set_new(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, json_integer(channel.midiOutChan)); json_array_append_new(jChannels, jChannel); writeActions(jChannel, &channel.actions); #ifdef WITH_VST writePlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS); #endif } json_object_set_new(jContainer, PATCH_KEY_CHANNELS, jChannels); } /* -------------------------------------------------------------------------- */ bool Patch::readCommons(json_t *jContainer) { if (!setString(jContainer, PATCH_KEY_HEADER, header)) return 0; if (!setString(jContainer, PATCH_KEY_VERSION, version)) return 0; if (!setInt (jContainer, PATCH_KEY_VERSION_MAJOR, versionMajor)) return 0; if (!setInt (jContainer, PATCH_KEY_VERSION_MINOR, versionMinor)) return 0; if (!setInt (jContainer, PATCH_KEY_VERSION_PATCH, versionPatch)) return 0; if (!setString(jContainer, PATCH_KEY_NAME, name)) return 0; if (!setFloat (jContainer, PATCH_KEY_BPM, bpm)) return 0; if (!setInt (jContainer, PATCH_KEY_BARS, bars)) return 0; if (!setInt (jContainer, PATCH_KEY_BEATS, beats)) return 0; if (!setInt (jContainer, PATCH_KEY_QUANTIZE, quantize)) return 0; if (!setFloat (jContainer, PATCH_KEY_MASTER_VOL_IN, masterVolIn)) return 0; if (!setFloat (jContainer, PATCH_KEY_MASTER_VOL_OUT, masterVolOut)) return 0; if (!setInt (jContainer, PATCH_KEY_METRONOME, metronome)) return 0; if (!setInt (jContainer, PATCH_KEY_LAST_TAKE_ID, lastTakeId)) return 0; if (!setInt (jContainer, PATCH_KEY_SAMPLERATE, samplerate)) return 0; return 1; } /* -------------------------------------------------------------------------- */ bool Patch::readColumns(json_t *jContainer) { json_t *jColumns = json_object_get(jContainer, PATCH_KEY_COLUMNS); if (!checkArray(jColumns, PATCH_KEY_COLUMNS)) return 0; size_t columnIndex; json_t *jColumn; json_array_foreach(jColumns, columnIndex, jColumn) { string columnIndexStr = "column " + gItoa(columnIndex); if (!checkObject(jColumn, columnIndexStr.c_str())) return 0; column_t column; if (!setInt(jColumn, PATCH_KEY_COLUMN_INDEX, column.index)) return 0; if (!setInt(jColumn, PATCH_KEY_COLUMN_WIDTH, column.width)) return 0; columns.push_back(column); } return 1; } /* -------------------------------------------------------------------------- */ bool Patch::readChannels(json_t *jContainer) { json_t *jChannels = json_object_get(jContainer, PATCH_KEY_CHANNELS); if (!checkArray(jChannels, PATCH_KEY_CHANNELS)) return 0; size_t channelIndex; json_t *jChannel; json_array_foreach(jChannels, channelIndex, jChannel) { string channelIndexStr = "channel " + gItoa(channelIndex); if (!checkObject(jChannel, channelIndexStr.c_str())) return 0; channel_t channel; if (!setInt (jChannel, PATCH_KEY_CHANNEL_TYPE, channel.type)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_INDEX, channel.index)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_COLUMN, channel.column)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_MUTE, channel.mute)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_MUTE_S, channel.mute_s)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_SOLO, channel.solo)) return 0; if (!setFloat (jChannel, PATCH_KEY_CHANNEL_VOLUME, channel.volume)) return 0; if (!setFloat (jChannel, PATCH_KEY_CHANNEL_PAN_LEFT, channel.panRight)) return 0; if (!setFloat (jChannel, PATCH_KEY_CHANNEL_PAN_RIGHT, channel.panLeft)) return 0; if (!setBool (jChannel, PATCH_KEY_CHANNEL_MIDI_IN, channel.midiIn)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYPRESS, channel.midiInKeyPress)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KEYREL, channel.midiInKeyRel)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_KILL, channel.midiInKill)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_VOLUME, channel.midiInVolume)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_MUTE, channel.midiInMute)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_SOLO, channel.midiInSolo)) return 0; if (!setBool (jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L, channel.midiOutL)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_PLAYING, channel.midiOutLplaying)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_MUTE, channel.midiOutLmute)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_L_SOLO, channel.midiOutLsolo)) return 0; if (!setString(jChannel, PATCH_KEY_CHANNEL_SAMPLE_PATH, channel.samplePath)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_KEY, channel.key)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_MODE, channel.mode)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_BEGIN, channel.begin)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_END, channel.end)) return 0; if (!setFloat (jChannel, PATCH_KEY_CHANNEL_BOOST, channel.boost)) return 0; if (!setInt (jChannel, PATCH_KEY_CHANNEL_REC_ACTIVE, channel.recActive)) return 0; if (!setFloat (jChannel, PATCH_KEY_CHANNEL_PITCH, channel.pitch)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_READ_ACTIONS, channel.midiInReadActions)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_IN_PITCH, channel.midiInPitch)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT, channel.midiOut)) return 0; if (!setUint32(jChannel, PATCH_KEY_CHANNEL_MIDI_OUT_CHAN, channel.midiOutChan)) return 0; readActions(jChannel, &channel); #ifdef WITH_VST readPlugins(jChannel, &channel.plugins, PATCH_KEY_CHANNEL_PLUGINS); #endif channels.push_back(channel); } return 1; } /* -------------------------------------------------------------------------- */ bool Patch::readActions(json_t *jContainer, channel_t *channel) { json_t *jActions = json_object_get(jContainer, PATCH_KEY_CHANNEL_ACTIONS); if (!checkArray(jActions, PATCH_KEY_CHANNEL_ACTIONS)) return 0; size_t actionIndex; json_t *jAction; json_array_foreach(jActions, actionIndex, jAction) { if (!checkObject(jAction, "")) // TODO pass actionIndex as string return 0; action_t action; if (!setInt (jAction, PATCH_KEY_ACTION_TYPE, action.type)) return 0; if (!setInt (jAction, PATCH_KEY_ACTION_FRAME, action.frame)) return 0; if (!setFloat (jAction, PATCH_KEY_ACTION_F_VALUE, action.fValue)) return 0; if (!setUint32(jAction, PATCH_KEY_ACTION_I_VALUE, action.iValue)) return 0; channel->actions.push_back(action); } return 1; } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST bool Patch::readPlugins(json_t *jContainer, vector *container, const char *key) { json_t *jPlugins = json_object_get(jContainer, key); if (!checkArray(jPlugins, key)) return 0; size_t pluginIndex; json_t *jPlugin; json_array_foreach(jPlugins, pluginIndex, jPlugin) { if (!checkObject(jPlugin, "")) // TODO pass pluginIndex as string return 0; plugin_t plugin; if (!setString (jPlugin, PATCH_KEY_PLUGIN_PATH, plugin.path)) return 0; if (!setBool (jPlugin, PATCH_KEY_PLUGIN_BYPASS, plugin.bypass)) return 0; /* read plugin params */ json_t *jParams = json_object_get(jPlugin, PATCH_KEY_PLUGIN_PARAMS); if (!checkArray(jParams, PATCH_KEY_PLUGIN_PARAMS)) return 0; size_t paramIndex; json_t *jParam; json_array_foreach(jParams, paramIndex, jParam) plugin.params.push_back(json_real_value(jParam)); container->push_back(plugin); } return 1; } #endif /* -------------------------------------------------------------------------- */ void Patch::sanitize() { bpm = bpm < 20.0f || bpm > 999.0f ? DEFAULT_BPM : bpm; bars = bars <= 0 || bars > 32 ? DEFAULT_BARS : bars; beats = beats <= 0 || beats > 32 ? DEFAULT_BEATS : beats; quantize = quantize < 0 || quantize > 8 ? DEFAULT_QUANTIZE : quantize; masterVolIn = masterVolIn < 0.0f || masterVolIn > 1.0f ? DEFAULT_VOL : masterVolIn; masterVolOut = masterVolOut < 0.0f || masterVolOut > 1.0f ? DEFAULT_VOL : masterVolOut; samplerate = samplerate <= 0 ? DEFAULT_SAMPLERATE : samplerate; for (unsigned i=0; iindex = col->index < 0 ? 0 : col->index; col->width = col->width < MIN_COLUMN_WIDTH ? MIN_COLUMN_WIDTH : col->width; } for (unsigned i=0; ivolume = ch->volume < 0.0f || ch->volume > 1.0f ? DEFAULT_VOL : ch->volume; ch->panLeft = ch->panLeft < 0.0f || ch->panLeft > 1.0f ? 1.0f : ch->panLeft; ch->panRight = ch->panRight < 0.0f || ch->panRight > 1.0f ? 1.0f : ch->panRight; ch->boost = ch->boost < 1.0f ? DEFAULT_BOOST : ch->boost; ch->pitch = ch->pitch < 0.1f || ch->pitch > 4.0f ? gDEFAULT_PITCH : ch->pitch; } } /* -------------------------------------------------------------------------- */ int Patch::setInvalid() { json_decref(jRoot); return PATCH_INVALID; } giada-0.11.2/src/core/patch.h000066400000000000000000000103031264622563000156320ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * patch * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef __PATCH_H__ #define __PATCH_H__ #include #include #include #include "../utils/utils.h" #include "dataStorageJson.h" #include "const.h" using std::string; using std::vector; class Patch : public DataStorageJson { public: struct action_t { int type; int frame; float fValue; uint32_t iValue; }; #ifdef WITH_VST struct plugin_t { string path; bool bypass; vector params; }; #endif struct channel_t { int type; int index; int column; int mute; int mute_s; int solo; float volume; float panLeft; float panRight; bool midiIn; uint32_t midiInKeyPress; uint32_t midiInKeyRel; uint32_t midiInKill; uint32_t midiInVolume; uint32_t midiInMute; uint32_t midiInSolo; bool midiOutL; uint32_t midiOutLplaying; uint32_t midiOutLmute; uint32_t midiOutLsolo; // sample channel string samplePath; int key; int mode; int begin; int end; float boost; int recActive; float pitch; uint32_t midiInReadActions; uint32_t midiInPitch; // midi channel uint32_t midiOut; uint32_t midiOutChan; vector actions; #ifdef WITH_VST vector plugins; #endif }; struct column_t { int index; int width; vector channels; }; string header; string version; int versionMajor; int versionMinor; int versionPatch; string name; float bpm; int bars; int beats; int quantize; float masterVolIn; float masterVolOut; int metronome; int lastTakeId; int samplerate; // original samplerate when the patch was saved vector columns; vector channels; #ifdef WITH_VST vector masterInPlugins; vector masterOutPlugins; #endif /* init * Init Patch with default values. */ void init(); /* read/write * Read/write patch to/from file. */ int write(const string &file); int read (const string &file); private: /* sanitize * Internal sanity check. */ void sanitize(); /* setInvalid * Helper function used to return invalid status while reading. */ int setInvalid(); /* readers */ bool readCommons (json_t *jContainer); bool readChannels(json_t *jContainer); #ifdef WITH_VST bool readPlugins (json_t *jContainer, vector *container, const char* key); #endif bool readActions (json_t *jContainer, channel_t *channel); bool readColumns (json_t *jContainer); /* writers */ void writeCommons (json_t *jContainer); void writeChannels(json_t *jContainer, vector *channels); #ifdef WITH_VST void writePlugins (json_t *jContainer, vector *plugins, const char* key); #endif void writeActions (json_t *jContainer, vector *actions); void writeColumns (json_t *jContainer, vector *columns); }; #endif giada-0.11.2/src/core/patch_DEPR_.cpp000066400000000000000000000324171264622563000171500ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * patch * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "../utils/utils.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/elems/ge_keyboard.h" #include "patch_DEPR_.h" #include "init.h" #include "recorder.h" #include "conf.h" #include "pluginHost.h" #include "wave.h" #include "mixer.h" #include "channel.h" extern Mixer G_Mixer; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif extern gdMainWindow *mainWin; int Patch_DEPR_::open(const char *file) { fp = fopen(file, "r"); if (fp == NULL) return PATCH_UNREADABLE; if (getValue("header") != "GIADAPTC") return PATCH_INVALID; version = atof(getValue("versionf").c_str()); gLog("[patch_DEPR_] open patch version %f\n", version); return PATCH_READ_OK; } /* -------------------------------------------------------------------------- */ void Patch_DEPR_::setDefault() { name[0] = '\0'; lastTakeId = 0; samplerate = DEFAULT_SAMPLERATE; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::close() { return fclose(fp); } /* -------------------------------------------------------------------------- */ void Patch_DEPR_::getName() { std::string out = getValue("patchname"); strncpy(name, out.c_str(), MAX_PATCHNAME_LEN); } /* -------------------------------------------------------------------------- */ std::string Patch_DEPR_::getSamplePath(int c) { char tmp[16]; sprintf(tmp, "samplepath%d", c); return getValue(tmp); } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getPitch(int c) { char tmp[16]; sprintf(tmp, "chanPitch%d", c); float out = atof(getValue(tmp).c_str()); if (out > 2.0f || out < 0.1f) return 1.0f; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getNumChans() { if (version == 0.0) // backward compatibility with version < 0.6.1 return 32; return atoi(getValue("channels").c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getNumColumns() { return atoi(getValue("columns").c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getColumn(int c) { if (version == 0.0) // backward compatibility with version < 0.6.1 return 0; char tmp[16]; sprintf(tmp, "chanColumn%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getIndex(int c) { if (version == 0.0) // backward compatibility with version < 0.6.1 return c; char tmp[16]; sprintf(tmp, "chanIndex%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getVol(int c) { char tmp[16]; sprintf(tmp, "chanvol%d", c); float out = atof(getValue(tmp).c_str()); if (out > 1.0f || out < 0.0f) return DEFAULT_VOL; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getMode(int c) { char tmp[16]; sprintf(tmp, "chanmode%d", c); int out = atoi(getValue(tmp).c_str()); if (out & (LOOP_ANY | SINGLE_ANY)) return out; return DEFAULT_CHANMODE; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getMute(int c) { char tmp[16]; sprintf(tmp, "chanMute%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getMute_s(int c) { char tmp[16]; sprintf(tmp, "chanMute_s%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getSolo(int c) { char tmp[16]; sprintf(tmp, "chanSolo%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getType(int c) { char tmp[16]; sprintf(tmp, "chanType%d", c); int out = atoi(getValue(tmp).c_str()); if (out == 0) return CHANNEL_SAMPLE; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getBegin(int c) { char tmp[16]; if (version < 0.73f) sprintf(tmp, "chanstart%d", c); else sprintf(tmp, "chanBegin%d", c); int out = atoi(getValue(tmp).c_str()); if (out < 0) return 0; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getEnd(int c, unsigned size) { char tmp[16]; sprintf(tmp, "chanend%d", c); /* if chanEnd doesn't exist, it returns an atoi(empty string) == 0. * good in theory, a disaster in practice. */ std::string val = getValue(tmp); if (val == "") return size; unsigned out = atoi(val.c_str()); if (out <= 0 || out > size) return size; return out; } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getBoost(int c) { char tmp[16]; sprintf(tmp, "chanBoost%d", c); float out = atof(getValue(tmp).c_str()); if (out < 1.0f) return DEFAULT_BOOST; return out; } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getPanLeft(int c) { char tmp[16]; sprintf(tmp, "chanPanLeft%d", c); std::string val = getValue(tmp); if (val == "") return 1.0f; float out = atof(val.c_str()); if (out < 0.0f || out > 1.0f) return 1.0f; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getKey(int c) { if (version == 0.0) // backward compatibility with version < 0.6.1 return 0; char tmp[16]; sprintf(tmp, "chanKey%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getPanRight(int c) { char tmp[16]; sprintf(tmp, "chanPanRight%d", c); std::string val = getValue(tmp); if (val == "") return 1.0f; float out = atof(val.c_str()); if (out < 0.0f || out > 1.0f) return 1.0f; return out; } /* -------------------------------------------------------------------------- */ bool Patch_DEPR_::getRecActive(int c) { char tmp[16]; sprintf(tmp, "chanRecActive%d", c); return atoi(getValue(tmp).c_str()); } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getOutVol() { return atof(getValue("outVol").c_str()); } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getInVol() { return atof(getValue("inVol").c_str()); } /* -------------------------------------------------------------------------- */ float Patch_DEPR_::getBpm() { float out = atof(getValue("bpm").c_str()); if (out < 20.0f || out > 999.0f) return DEFAULT_BPM; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getBars() { int out = atoi(getValue("bars").c_str()); if (out <= 0 || out > 32) return DEFAULT_BARS; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getBeats() { int out = atoi(getValue("beats").c_str()); if (out <= 0 || out > 32) return DEFAULT_BEATS; return out; } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getQuantize() { int out = atoi(getValue("quantize").c_str()); if (out < 0 || out > 8) return DEFAULT_QUANTIZE; return out; } /* -------------------------------------------------------------------------- */ bool Patch_DEPR_::getMetronome() { return atoi(getValue("metronome").c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getLastTakeId() { return atoi(getValue("lastTakeId").c_str()); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::getSamplerate() { int out = atoi(getValue("samplerate").c_str()); if (out <= 0) return DEFAULT_SAMPLERATE; return out; } /* -------------------------------------------------------------------------- */ uint32_t Patch_DEPR_::getMidiValue(int i, const char *c) { char tmp[32]; sprintf(tmp, "chanMidi%s%d", c, i); return strtoul(getValue(tmp).c_str(), NULL, 10); } /* -------------------------------------------------------------------------- */ int Patch_DEPR_::readRecs() { gLog("[patch_DEPR_] Reading recs...\n"); unsigned numrecs = atoi(getValue("numrecs").c_str()); for (unsigned i=0; istatus & ~(STATUS_WRONG | STATUS_MISSING | STATUS_EMPTY)) { if (version < 0.83f) recorder::rec(ch->index, type, frame, iValue_fix, fValue); else recorder::rec(ch->index, type, frame, iValue, fValue); } } } return 1; } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST int Patch_DEPR_::readPlugins() { gLog("[patch_DEPR_] Reading plugins...\n"); int globalOut = 1; /* master plugins */ globalOut &= readMasterPlugins(PluginHost::MASTER_IN); globalOut &= readMasterPlugins(PluginHost::MASTER_OUT); /* channel plugins */ for (unsigned i=0; iindex); int np = atoi(getValue(tmp).c_str()); for (int j=0; jindex, j); Plugin *plugin = G_PluginHost.addPlugin(getValue(tmp).c_str(), PluginHost::CHANNEL, ch); if (plugin != NULL) { sprintf(tmp, "chan%d_p%dnumParams", ch->index, j); int nparam = atoi(getValue(tmp).c_str()); Plugin *pPlugin = G_PluginHost.getPluginByIndex(j, PluginHost::CHANNEL, ch); sprintf(tmp, "chan%d_p%dbypass", ch->index, j); pPlugin->bypass = atoi(getValue(tmp).c_str()); for (int k=0; kindex, j, k); float pval = atof(getValue(tmp).c_str()); pPlugin->setParam(k, pval); } globalOut &= 1; } else globalOut &= 0; } } return globalOut; } #endif /* -------------------------------------------------------------------------- */ #ifdef WITH_VST int Patch_DEPR_::readMasterPlugins(int type) { int nmp; char chr; int res = 1; if (type == PluginHost::MASTER_IN) { chr = 'I'; nmp = atoi(getValue("masterIPlugins").c_str()); } else { chr = 'O'; nmp = atoi(getValue("masterOPlugins").c_str()); } for (int i=0; ibypass = atoi(getValue(tmp).c_str()); sprintf(tmp, "master%c_p%dnumParams", chr, i); int nparam = atoi(getValue(tmp).c_str()); for (int j=0; jsetParam(j, pval); } res &= 1; } else res &= 0; } return res; } #endif giada-0.11.2/src/core/patch_DEPR_.h000066400000000000000000000052221264622563000166070ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * patch * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef __PATCH_DEPR_H__ #define __PATCH_DEPR_H__ #include #include #include #include "dataStorageIni.h" #include "const.h" class Patch_DEPR_ : public DataStorageIni { private: int readMasterPlugins(int type); public: char name[MAX_PATCHNAME_LEN]; float version; int lastTakeId; int samplerate; int open(const char *file); void setDefault(); int close(); void getName (); int getNumChans (); int getNumColumns (); std::string getSamplePath (int i); float getVol (int i); int getMode (int i); int getMute (int i); int getMute_s (int i); int getSolo (int i); int getBegin (int i); int getEnd (int i, unsigned sampleSize); float getBoost (int i); float getPanLeft (int i); float getPanRight (int i); float getPitch (int i); bool getRecActive (int i); int getColumn (int i); int getIndex (int i); int getType (int i); int getKey (int i); uint32_t getMidiValue (int i, const char *c); float getOutVol (); float getInVol (); float getBpm (); int getBars (); int getBeats (); int getQuantize (); bool getMetronome (); int getLastTakeId (); int getSamplerate (); int readRecs(); #ifdef WITH_VST int readPlugins(); #endif }; #endif giada-0.11.2/src/core/plugin.cpp000066400000000000000000000307231264622563000163740ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifdef WITH_VST #include "../utils/log.h" #include "plugin.h" int Plugin::id_generator = 0; /* -------------------------------------------------------------------------- */ Plugin::Plugin() : module (NULL), entryPoint(NULL), plugin (NULL), id (id_generator++), program (-1), bypass (false), suspended (false) {} /* -------------------------------------------------------------------------- */ Plugin::~Plugin() { unload(); } /* -------------------------------------------------------------------------- */ int Plugin::unload() { if (module == NULL) return 1; #if defined(_WIN32) FreeLibrary((HMODULE)module); // FIXME - error checking return 1; #elif defined(__linux__) return dlclose(module) == 0 ? 1 : 0; #elif defined(__APPLE__) /* we must unload bundles but because bundles may be in use for other plug-in types it is important (and mandatory on certain plug-ins, e.g. Korg) to do a check on the retain count. */ CFIndex retainCount = CFGetRetainCount(module); if (retainCount == 1) { gLog("[plugin] retainCount == 1, can unload dlyb\n"); CFBundleUnloadExecutable(module); CFRelease(module); } else gLog("[plugin] retainCount > 1 (%d), leave dlyb alone\n", (int) retainCount); return 1; #endif } /* -------------------------------------------------------------------------- */ int Plugin::load(const char *fname) { strcpy(pathfile, fname); #if defined(_WIN32) module = LoadLibrary(pathfile); #elif defined(__linux__) module = dlopen(pathfile, RTLD_LAZY); #elif defined(__APPLE__) /* creates the path to the bundle. In OSX vsts are stored inside the * so-called bundles, just a directory with '.vst' extension. Finally * we open the bundle with CFBundleCreate. */ CFStringRef pathStr = CFStringCreateWithCString(NULL, pathfile, kCFStringEncodingASCII); CFURLRef bundleUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStr, kCFURLPOSIXPathStyle, true); if(bundleUrl == NULL) { gLog("[plugin] unable to create URL reference for plugin\n"); status = 0; return 0; } module = CFBundleCreate(kCFAllocatorDefault, bundleUrl); #endif if (module) { /* release (free) any old string */ #ifdef __APPLE__ CFRelease(pathStr); CFRelease(bundleUrl); #endif //strcpy(pathfile, fname); ??????????? status = 1; return 1; } else { #if defined(_WIN32) gLog("[plugin] unable to load %s, error: %d\n", fname, (int) GetLastError()); #elif defined(__linux__) gLog("[plugin] unable to load %s, error: %s\n", fname, dlerror()); #elif defined(__APPLE__) gLog("[plugin] unable to create bundle reference\n"); CFRelease(pathStr); CFRelease(bundleUrl); #endif status = 0; return 0; } } /* -------------------------------------------------------------------------- */ int Plugin::init(VstIntPtr VSTCALLBACK (*HostCallback) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt)) { #if defined(_WIN32) entryPoint = (vstPluginFuncPtr) GetProcAddress((HMODULE)module, "VSTPluginMain"); if (!entryPoint) entryPoint = (vstPluginFuncPtr) GetProcAddress((HMODULE)module, "main"); #elif defined(__linux__) /* bad stuff here: main() is a function pointer, dlsym(module, "main") * returns a pointer to an object (void*) which should be casted to * a pointer to function (main(), precisely). Unfortunately the standard * forbids the conversion from void* to function pointer. So we do a raw * mem copy from tmp to entryPoint. */ void *tmp; tmp = dlsym(module, "VSTPluginMain"); if (!tmp) tmp = dlsym(module, "main"); memcpy(&entryPoint, &tmp, sizeof(tmp)); #elif defined(__APPLE__) /* same also for Unix/OSX. */ void *tmp = NULL; tmp = CFBundleGetFunctionPointerForName(module, CFSTR("VSTPluginMain")); if (!tmp) { gLog("[plugin] entryPoint 'VSTPluginMain' not found\n"); tmp = CFBundleGetFunctionPointerForName(module, CFSTR("main_macho")); // VST SDK < 2.4 } if (!tmp) { gLog("[plugin] entryPoint 'main_macho' not found\n"); tmp = CFBundleGetFunctionPointerForName(module, CFSTR("main")); } if (tmp) memcpy(&entryPoint, &tmp, sizeof(tmp)); else gLog("[plugin] entryPoint 'main' not found\n"); #endif /* if entry point is found, add to plugin a pointer to hostCallback. Or * in other words bind the callback to the plugin. */ if (entryPoint) { gLog("[plugin] entryPoint found\n"); plugin = entryPoint(HostCallback); if (!plugin) { gLog("[plugin] failed to create effect instance!\n"); return 0; } } else { gLog("[plugin] entryPoint not found, unable to proceed\n"); return 0; } /* check the magicNumber */ /** WARNING: on Windows one can load any DLL! Why!?! */ if(plugin->magic == kEffectMagic) { gLog("[plugin] magic number OK\n"); return 1; } else { gLog("[plugin] magic number is bad\n"); return 0; } } /* -------------------------------------------------------------------------- */ int Plugin::setup(int samplerate, int frames) { /* init plugin through the dispatcher with some basic infos */ plugin->dispatcher(plugin, effOpen, 0, 0, 0, 0); plugin->dispatcher(plugin, effSetSampleRate, 0, 0, 0, samplerate); plugin->dispatcher(plugin, effSetBlockSize, 0, frames, 0, 0); /* check SDK compatibility */ if (getSDKVersion() != kVstVersion) gLog("[plugin] warning: different VST version (host: %d, plugin: %d)\n", kVstVersion, getSDKVersion()); return 1; } /* -------------------------------------------------------------------------- */ AEffect *Plugin::getPlugin() { return plugin; } /* -------------------------------------------------------------------------- */ int Plugin::getId() { return id; } /* -------------------------------------------------------------------------- */ int Plugin::getSDKVersion() { return plugin->dispatcher(plugin, effGetVstVersion, 0, 0, 0, 0); } /* -------------------------------------------------------------------------- */ void Plugin::getName(char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetEffectName, 0, 0, tmp, 0); tmp[kVstMaxEffectNameLen-1] = '\0'; strncpy(out, tmp, kVstMaxEffectNameLen); } /* -------------------------------------------------------------------------- */ void Plugin::getVendor(char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetVendorString, 0, 0, tmp, 0); tmp[kVstMaxVendorStrLen-1] = '\0'; strncpy(out, tmp, kVstMaxVendorStrLen); } /* -------------------------------------------------------------------------- */ void Plugin::getProduct(char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetProductString, 0, 0, tmp, 0); tmp[kVstMaxProductStrLen-1] = '\0'; strncpy(out, tmp, kVstMaxProductStrLen); } /* -------------------------------------------------------------------------- */ int Plugin::getNumPrograms() { return plugin->numPrograms; } /* -------------------------------------------------------------------------- */ int Plugin::setProgram(int index) { plugin->dispatcher(plugin, effBeginSetProgram, 0, 0, 0, 0); plugin->dispatcher(plugin, effSetProgram, 0, index, 0, 0); gLog("[plugin] program changed, index %d\n", index); program = index; return plugin->dispatcher(plugin, effEndSetProgram, 0, 0, 0, 0); } /* -------------------------------------------------------------------------- */ int Plugin::getNumParams() const { return plugin->numParams; } /* -------------------------------------------------------------------------- */ int Plugin::getNumInputs() { return plugin->numInputs; } /* -------------------------------------------------------------------------- */ int Plugin::getNumOutputs() { return plugin->numOutputs; } /* -------------------------------------------------------------------------- */ void Plugin::getProgramName(int index, char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetProgramNameIndexed, index, 0, tmp, 0); tmp[kVstMaxProgNameLen-1] = '\0'; strncpy(out, tmp, kVstMaxProgNameLen); } /* -------------------------------------------------------------------------- */ void Plugin::getParamName(int index, char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetParamName, index, 0, tmp, 0); tmp[kVstMaxParamStrLen-1] = '\0'; strncpy(out, tmp, kVstMaxParamStrLen); } /* -------------------------------------------------------------------------- */ void Plugin::getParamLabel(int index, char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetParamLabel, index, 0, tmp, 0); tmp[kVstMaxParamStrLen-1] = '\0'; strncpy(out, tmp, kVstMaxParamStrLen); } /* -------------------------------------------------------------------------- */ void Plugin::getParamDisplay(int index, char *out) { char tmp[128] = "\0"; plugin->dispatcher(plugin, effGetParamDisplay, index, 0, tmp, 0); tmp[kVstMaxParamStrLen-1] = '\0'; strncpy(out, tmp, kVstMaxParamStrLen); } /* -------------------------------------------------------------------------- */ float Plugin::getParam(int index) const { return plugin->getParameter(plugin, index); } /* -------------------------------------------------------------------------- */ void Plugin::setParam(int index, float value) { plugin->setParameter(plugin, index, value); } /* -------------------------------------------------------------------------- */ bool Plugin::hasGui() { return plugin->flags & effFlagsHasEditor; } /* -------------------------------------------------------------------------- */ void Plugin::openGui(void *w) { long val = 0; #ifdef __linux__ val = (long) w; #endif plugin->dispatcher(plugin, effEditOpen, 0, val, w, 0); } /* -------------------------------------------------------------------------- */ void Plugin::closeGui() { plugin->dispatcher(plugin, effEditClose, 0, 0, 0, 0); } /* -------------------------------------------------------------------------- */ int Plugin::getGuiWidth() { ERect *pErect = NULL; plugin->dispatcher(plugin, effEditGetRect, 0, 0, &pErect, 0); return pErect->top + pErect->right; } /* -------------------------------------------------------------------------- */ int Plugin::getGuiHeight() { ERect *pErect = NULL; plugin->dispatcher(plugin, effEditGetRect, 0, 0, &pErect, 0); return pErect->top + pErect->bottom; } /* -------------------------------------------------------------------------- */ void Plugin::idle() { plugin->dispatcher(plugin, effEditIdle, 0, 0, NULL, 0); } /* -------------------------------------------------------------------------- */ void Plugin::processAudio(float **in, float **out, long frames) { plugin->processReplacing(plugin, in, out, frames); } /* -------------------------------------------------------------------------- */ void Plugin::processEvents(VstEvents *events) { plugin->dispatcher(plugin, effProcessEvents, 0, 0, events, 0.0); } /* -------------------------------------------------------------------------- */ void Plugin::resume() { plugin->dispatcher(plugin, effMainsChanged, 0, 1, 0, 0); suspended = false; } /* -------------------------------------------------------------------------- */ void Plugin::suspend() { plugin->dispatcher(plugin, effMainsChanged, 0, 0, 0, 0); suspended = true; } /* -------------------------------------------------------------------------- */ void Plugin::close() { plugin->dispatcher(plugin, effClose, 0, 0, 0, 0); } /* -------------------------------------------------------------------------- */ void Plugin::getRect(ERect **out) { plugin->dispatcher(plugin, effEditGetRect, 0, 0, out, 0); } #endif giada-0.11.2/src/core/plugin.h000066400000000000000000000101471264622563000160370ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * plugin * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifdef WITH_VST #ifndef __PLUGIN_H #define __PLUGIN_H #include /* before including aeffetx(x).h we must define __cdecl, otherwise VST * headers can't be compiled correctly. In windows __cdecl is already * defined. */ #ifdef __GNUC__ #ifndef _WIN32 #define __cdecl #endif #endif #include "../deps/vst/aeffectx.h" #if defined(_WIN32) #include #elif defined(__linux__) #include #include #elif defined(__APPLE__) #include #endif #include // PATH_MAX // Plugin's entry point typedef AEffect* (*vstPluginFuncPtr)(audioMasterCallback host); class Plugin { private: #if defined(_WIN32) || defined(__linux__) void *module; // dll, so, ... #elif defined(__APPLE__) CFBundleRef module; // OSX bundle #endif vstPluginFuncPtr entryPoint; // VST entry point AEffect *plugin; // real plugin /* each plugin has an unique ID */ static int id_generator; int id; /* program * selected program. -1 if no program available */ int program; /* unload * free plugin from memory. Calls dlclose and similars. */ int unload(); public: Plugin(); ~Plugin(); int load(const char *fname); int init(VstIntPtr VSTCALLBACK (*HostCallback)(AEffect*, VstInt32, VstInt32, VstIntPtr, void*, float)); int setup(int samplerate, int frames); AEffect *getPlugin(); /* get[Item]. * Wrappers called by host when it wants info from the plugin. */ int getId(); int getSDKVersion(); void getName (char *out); void getVendor (char *out); void getProduct(char *out); int getNumPrograms(); // list all programs int setProgram(int index); // load a program int getNumParams() const; int getNumInputs(); int getNumOutputs(); void getProgramName(int index, char *out); // program = preset void getParamName(int index, char *out); void getParamLabel(int index, char *out); // parameter's value(0, -39, ...) void getParamDisplay(int index, char *out); // parameter's unit measurement (dB, Pan, ...) float getParam(int index) const; void getRect(ERect **out); void setParam(int index, float value); bool hasGui(); void openGui(void *w); void closeGui(); int getGuiWidth(); int getGuiHeight(); void idle(); void processAudio (float **in, float **out, long frames); void processEvents(VstEvents *events); void resume(); void suspend(); void close(); inline int getProgram() { return program; } /* there's a specific opcode for the bypass, but we don't trust the * plugin's developers. */ bool bypass; /* the status of the plugin: * 1: ok * 0: missing (file not found) */ int status; /* suspended * true after suspend(), false after resume(). A suspended plugin isn't * processed by pluginHost. */ bool suspended; /* pathfile * full filename path */ char pathfile[PATH_MAX]; /* window * plugin must know its window in case of a resize via opcode */ class gWindow *window; }; #endif #endif // #ifdef WITH_VST giada-0.11.2/src/core/pluginHost.cpp000066400000000000000000000450411264622563000172310ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * pluginHost * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifdef WITH_VST #include #include "../gui/dialogs/gd_mainWindow.h" #include "../utils/log.h" #include "pluginHost.h" #include "conf.h" #include "const.h" #include "mixer.h" #include "channel.h" #include "sampleChannel.h" #include "midiChannel.h" #include "kernelMidi.h" extern Conf G_Conf; extern Mixer G_Mixer; extern PluginHost G_PluginHost; extern unsigned G_beats; extern gdMainWindow *mainWin; using std::vector; PluginHost::PluginHost() { /* initially we fill vstTimeInfo with trash. Only when the plugin requests * the opcode we load the right infos from G_Mixer. */ vstTimeInfo.samplePos = 0.0; vstTimeInfo.sampleRate = G_Conf.samplerate; vstTimeInfo.nanoSeconds = 0.0; vstTimeInfo.ppqPos = 0.0; vstTimeInfo.tempo = 120.0; vstTimeInfo.barStartPos = 0.0; vstTimeInfo.cycleStartPos = 0.0; vstTimeInfo.cycleEndPos = 0.0; vstTimeInfo.timeSigNumerator = 4; vstTimeInfo.timeSigDenominator = 4; vstTimeInfo.smpteOffset = 0; vstTimeInfo.smpteFrameRate = 1; vstTimeInfo.samplesToNextClock = 0; vstTimeInfo.flags = 0; } /* -------------------------------------------------------------------------- */ PluginHost::~PluginHost() {} /* -------------------------------------------------------------------------- */ int PluginHost::clonePlugin(const Plugin &src, int stackType, Channel *ch) { Plugin *p = addPlugin(src.pathfile, stackType, ch); if (!p) { gLog("[PluginHost::clonePlugin] unable to add new plugin to stack!\n"); return 0; } for (int k=0; ksetParam(k, src.getParam(k)); } return 1; } /* -------------------------------------------------------------------------- */ int PluginHost::allocBuffers() { /** FIXME - ERROR CHECKING! */ /* never, ever use G_Conf.buffersize to alloc these chunks of memory. * If you use JACK, that value would be meaningless. Always refer to * kernelAudio::realBufsize. */ int bufSize = kernelAudio::realBufsize*sizeof(float); bufferI = (float **) malloc(2 * sizeof(float*)); bufferI[0] = (float *) malloc(bufSize); bufferI[1] = (float *) malloc(bufSize); bufferO = (float **) malloc(2 * sizeof(float*)); bufferO[0] = (float *) malloc(bufSize); bufferO[1] = (float *) malloc(bufSize); memset(bufferI[0], 0, bufSize); memset(bufferI[1], 0, bufSize); memset(bufferO[0], 0, bufSize); memset(bufferO[1], 0, bufSize); gLog("[pluginHost] buffers allocated, buffersize = %d\n", 2*kernelAudio::realBufsize); //printOpcodes(); return 1; } /* -------------------------------------------------------------------------- */ VstIntPtr VSTCALLBACK PluginHost::HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) { return G_PluginHost.gHostCallback(effect, opcode, index, value, ptr, opt); } /* -------------------------------------------------------------------------- */ VstIntPtr PluginHost::gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) { /* warning: VST headers compiled with DECLARE_VST_DEPRECATED. */ switch (opcode) { /* 0 - Called after a control has changed in the editor and when * the associated parameter should be automated. Index contains the * param, opt the value. Thanks, but we don't need it now. It will * be useful when recording actions from VST (in the future). */ case audioMasterAutomate: return 0; /* 1 - host version (2.4) */ case audioMasterVersion: return kVstVersion; /* 3 - Give idle time to Host application, e.g. if plug-in editor is * doing mouse tracking in a modal loop. This a is multithread app, * we don't need it. */ case audioMasterIdle: return 0; /* 6 - tells the host that the plugin is an instrument. Deprecated. */ case DECLARE_VST_DEPRECATED(audioMasterWantMidi): return 0; /* 7 - time infos */ case audioMasterGetTime: vstTimeInfo.samplePos = G_Mixer.actualFrame; vstTimeInfo.sampleRate = G_Conf.samplerate; vstTimeInfo.tempo = G_Mixer.bpm; vstTimeInfo.timeSigNumerator = G_Mixer.beats; vstTimeInfo.timeSigDenominator = G_Mixer.bars; vstTimeInfo.ppqPos = (G_Mixer.actualFrame / (float) G_Conf.samplerate) * (float) G_Mixer.bpm / 60.0f; return (VstIntPtr) &vstTimeInfo; /* ? - requires a pointer to VstEvents. No vstEvents so far (v0.5.4) */ case audioMasterProcessEvents: return 0; /* 13 - tells that numInputs/numOutputs are changed. Not supported and * not needed. */ case audioMasterIOChanged: return false; /* 14 - plugin needs idle calls (outside its editor window). Deprecated */ case DECLARE_VST_DEPRECATED(audioMasterNeedIdle): return 0; /* 15 - requests to resize the editor window. w = index, h = value*/ case audioMasterSizeWindow: { gWindow *window = NULL; for (unsigned i=0; igetPlugin() == effect) window = masterOut.at(i)->window; for (unsigned i=0; igetPlugin() == effect) window = masterIn.at(i)->window; for (unsigned i=0; iplugins.size() && !window; j++) if (ch->plugins.at(j)->getPlugin() == effect) window = ch->plugins.at(j)->window; } if (window) { gLog("[pluginHost] audioMasterSizeWindow: resizing window from plugin %p\n", (void*) effect); if (index == 1 || value == 1) gLog("[pluginHost] warning: non-sense values!\n"); else window->size((int)index, (int)value); return 1; } else { gLog("[pluginHost] audioMasterSizeWindow: window from plugin %p not found\n", (void*) effect); return 0; } } /* 16 - sample rate */ case audioMasterGetSampleRate: return G_Conf.samplerate; /* ?? - buffer size */ case audioMasterGetBlockSize: return kernelAudio::realBufsize; case audioMasterGetInputLatency: gLog("[pluginHost] requested opcode 'audioMasterGetInputLatency' (%d)\n", opcode); return 0; case audioMasterGetOutputLatency: gLog("[pluginHost] requested opcode 'audioMasterGetOutputLatency' (%d)\n", opcode); return 0; /* 23 - wants to know what kind of process is that. * kVstProcessLevelRealtime = currently in audio thread (where * process is called). */ case audioMasterGetCurrentProcessLevel: return kVstProcessLevelRealtime; /* 32 - vendor name */ case audioMasterGetVendorString: strcpy((char*)ptr, "Monocasual"); return 1; /* 32 - product name */ case audioMasterGetProductString: strcpy((char*)ptr, "Giada"); return 1; /* 33 - product version */ case audioMasterGetVendorVersion: return (int) (G_VERSION_MAJOR * 100) + (G_VERSION_MINOR * 10) + G_VERSION_PATCH; /* 37 - Plugin asks Host if it implements the feature text. */ case audioMasterCanDo: gLog("[pluginHost] audioMasterCanDo: %s\n", (char*)ptr); if (!strcmp((char*)ptr, "sizeWindow") || !strcmp((char*)ptr, "sendVstTimeInfo") || !strcmp((char*)ptr, "sendVstMidiEvent") || !strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime")) return 1; // we can do all of that else return 0; /* 42 - Something has changed, update the host's 'multi-fx' display. * Not supported right now, return 0. This opcode deals with the program * changes, more infos http://www.asseca.com/vst-24-specs/amUpdateDisplay.html */ case audioMasterUpdateDisplay: return 0; case audioMasterGetLanguage: return kVstLangEnglish; /* ?? */ case audioMasterGetAutomationState: gLog("[pluginHost] requested opcode 'audioMasterGetAutomationState' (%d)\n", opcode); return 0; /* 43 - It tells the Host that if it needs to, it has to record * automation data for this control. In other words this opcode is fired * when the user starts to tweak a parameter with the mouse. * Useful when the plugin actions will be recorded. */ case audioMasterBeginEdit: return 0; /* 44 - no more interaction for the user, started with the previous * opcode. */ case audioMasterEndEdit: return 0; default: gLog("[pluginHost] FIXME: host callback called with opcode %d\n", opcode); return 0; } } /* -------------------------------------------------------------------------- */ Plugin *PluginHost::addPlugin(const char *fname, int stackType, Channel *ch) { Plugin *p = new Plugin(); bool success = true; vector *pStack; pStack = getStack(stackType, ch); if (!p->load(fname)) { //delete p; //return 0; success = false; } /* if the load failed we add a 'dead' plugin into the stack. This is * useful to report a missing plugin. */ if (!success) { pStack->push_back(p); return NULL; } /* otherwise let's try to initialize it. */ else { /* try to init the plugin. If fails, delete it and return error. */ if (!p->init(&PluginHost::HostCallback)) { delete p; return NULL; } /* plugin setup */ p->setup(G_Conf.samplerate, kernelAudio::realBufsize); /* try to add the new plugin until succeed */ int lockStatus; while (true) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins); if (lockStatus == 0) { pStack->push_back(p); pthread_mutex_unlock(&G_Mixer.mutex_plugins); break; } } char name[256]; p->getName(name); gLog("[pluginHost] plugin id=%d loaded (%s), stack type=%d, stack size=%d\n", p->getId(), name, stackType, pStack->size()); /* p->resume() is suggested. Who knows... */ p->resume(); return p; } } /* -------------------------------------------------------------------------- */ void PluginHost::processStack(float *buffer, int stackType, Channel *ch) { vector *pStack = getStack(stackType, ch); /* empty stack, stack not found or mixer not ready: do nothing */ /// TODO - join evaluation if (!G_Mixer.ready) return; if (pStack == NULL) return; if (pStack->size() == 0) return; /* converting buffer from Giada to VST */ for (unsigned i=0; isize(); i++) { /// TODO - join evaluation if (pStack->at(i)->status != 1) continue; if (pStack->at(i)->suspended) continue; if (pStack->at(i)->bypass) continue; if (ch) { // process events if it's a channel stack if (ch->type == CHANNEL_MIDI) { ///gLog("events: %d\n", (((MidiChannel*)ch)->getVstEvents())->numEvents); pStack->at(i)->processEvents(((MidiChannel*)ch)->getVstEvents()); } } pStack->at(i)->processAudio(bufferI, bufferO, kernelAudio::realBufsize); bufferI = bufferO; } /* converting buffer from VST to Giada. A note for the future: if we * overwrite (=) (as we do now) it's SEND, if we add (+) it's INSERT. */ for (unsigned i=0; i *pStack = getStack(stackType, ch); for (unsigned i=0; isize(); i++) { if (pStack->at(i)->getId() == id) return pStack->at(i); } return NULL; } /* -------------------------------------------------------------------------- */ Plugin *PluginHost::getPluginByIndex(int index, int stackType, Channel *ch) { vector *pStack = getStack(stackType, ch); if (pStack->size() == 0) return NULL; if ((unsigned) index >= pStack->size()) return NULL; return pStack->at(index); } /* -------------------------------------------------------------------------- */ void PluginHost::freeStack(int stackType, Channel *ch) { vector *pStack; pStack = getStack(stackType, ch); if (pStack->size() == 0) return; int lockStatus; while (true) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins); if (lockStatus == 0) { for (unsigned i=0; isize(); i++) { if (pStack->at(i)->status == 1) { // only if plugin is ok pStack->at(i)->suspend(); pStack->at(i)->close(); } delete pStack->at(i); } pStack->clear(); pthread_mutex_unlock(&G_Mixer.mutex_plugins); break; } } } /* -------------------------------------------------------------------------- */ void PluginHost::freeAllStacks() { freeStack(PluginHost::MASTER_OUT); freeStack(PluginHost::MASTER_IN); for (unsigned i=0; i *pStack; pStack = getStack(stackType, ch); /* try to delete the plugin until succeed. G_Mixer has priority. */ for (unsigned i=0; isize(); i++) if (pStack->at(i)->getId() == id) { if (pStack->at(i)->status == 0) { // no frills if plugin is missing delete pStack->at(i); pStack->erase(pStack->begin() + i); return; } else { int lockStatus; while (true) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins); if (lockStatus == 0) { pStack->at(i)->suspend(); pStack->at(i)->close(); delete pStack->at(i); pStack->erase(pStack->begin() + i); pthread_mutex_unlock(&G_Mixer.mutex_plugins); gLog("[pluginHost] plugin id=%d removed\n", id); return; } //else //gLog("[pluginHost] waiting for mutex...\n"); } } } gLog("[pluginHost] plugin id=%d not found\n", id); } /* -------------------------------------------------------------------------- */ void PluginHost::swapPlugin(unsigned indexA, unsigned indexB, int stackType, Channel *ch) { vector *pStack = getStack(stackType, ch); int lockStatus; while (true) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_plugins); if (lockStatus == 0) { //pStack->swap(indexA, indexB); std::swap(pStack->at(indexA), pStack->at(indexB)); // FIXME - will it work??? pthread_mutex_unlock(&G_Mixer.mutex_plugins); gLog("[pluginHost] plugin at index %d and %d swapped\n", indexA, indexB); return; } //else //gLog("[pluginHost] waiting for mutex...\n"); } } /* -------------------------------------------------------------------------- */ int PluginHost::getPluginIndex(int id, int stackType, Channel *ch) { vector *pStack = getStack(stackType, ch); for (unsigned i=0; isize(); i++) if (pStack->at(i)->getId() == id) return i; return -1; } /* -------------------------------------------------------------------------- */ vector *PluginHost::getStack(int stackType, Channel *ch) { switch(stackType) { case MASTER_OUT: return &masterOut; case MASTER_IN: return &masterIn; case CHANNEL: return &ch->plugins; default: return NULL; } } /* -------------------------------------------------------------------------- */ VstMidiEvent *PluginHost::createVstMidiEvent(uint32_t msg) { VstMidiEvent *e = (VstMidiEvent*) malloc(sizeof(VstMidiEvent)); /* type = two types of events: MIDI event and MIDI system exclusive * (aka sysex, not implemented). */ e->type = kVstMidiType; e->byteSize = sizeof(VstMidiEvent); /* deltaFrames = sample frames related to the current block start * sample position. */ e->deltaFrames = 0; /* flags = kVstMidiEventIsRealtime means that this event is played * live (not in playback from a sequencer track). This allows the * Plug-In to handle these flagged events with higher priority, * especially when the Plug-In has a big latency */ e->flags = kVstMidiEventIsRealtime; /* midiData = 1 to 3 MIDI bytes; midiData[3] is reserved (zero) */ e->midiData[0] = kernelMidi::getB1(msg); // note on/off + channel e->midiData[1] = kernelMidi::getB2(msg); // note number e->midiData[2] = kernelMidi::getB3(msg); // velocity e->midiData[3] = 0; /* noteLength = (in sample frames) of entire note, if available, * else 0 */ e->noteLength = 0; /* noteOffset = offset (in sample frames) into note from note start * if available, else 0 */ e->noteOffset = 0; /* noteOffVelocity = Note Off Velocity [0, 127]. */ e->noteOffVelocity = 0; return e; } /* -------------------------------------------------------------------------- */ unsigned PluginHost::countPlugins(int stackType, Channel *ch) { vector *pStack = getStack(stackType, ch); return pStack->size(); } #endif // #ifdef WITH_VST giada-0.11.2/src/core/pluginHost.h000066400000000000000000000100261264622563000166710ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * pluginHost * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifdef WITH_VST #ifndef __PLUGIN_HOST_ #define __PLUGIN_HOST_ #include #include "../utils/utils.h" #include "../gui/elems/ge_window.h" #include "plugin.h" #include "init.h" #include "const.h" using std::vector; class PluginHost { private: /* VSTs have a different buffer model: * * buffer[0] = channel left * buffer[1] = channel right * buffer[0][....] = all signals from left chan * buffer[1][....] = all signals from right chan */ float **bufferI; float **bufferO; /* VST struct containing infos on tempo (bpm, freq, smtpe, ...). */ VstTimeInfo vstTimeInfo; public: /* stack types. Use them together with getStack() in order to geta * pointer to the right stack. */ enum stackType { MASTER_OUT, MASTER_IN, CHANNEL }; /* stack of Plugins */ vector masterOut; vector masterIn; PluginHost(); ~PluginHost(); int clonePlugin(const Plugin &src, int stackType, class Channel *ch); int allocBuffers(); /* The plugin can ask the host if it supports a given capability, * which is done through the HostCallback() function. * * Why static? This is a callback attached to each plugin in the stack * and C++ callback functions need to be static when declared in class. * * OPCODE LIST: * base version: vstsdk2.4/pluginterfaces/aeffect.h (vst 1.x) * enhanced v. : vstsdk2.4/pluginterfaces/effectx.h (vst 2.x) */ static VstIntPtr VSTCALLBACK HostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); VstIntPtr gHostCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); /* addPlugin * Add a new plugin to the stack. If the operation goes well, returns a pointer * to the newly inserted plugin. */ Plugin *addPlugin(const char *fname, int stackType, class Channel *ch=NULL); void processEvents(float *buffer, class Channel *ch); /* processStack * apply the fx list to the buffer. */ void processStack(float *buffer, int stackType, class Channel *ch=NULL); /* processStackOffline * apply the fx list to a longer chunk of data */ void processStackOffline(float *buffer, int stackType, class Channel *ch, int size); /* createVstMidiEvent * return a pointer to a new VstMidiEvent structure. */ VstMidiEvent *createVstMidiEvent(uint32_t msg); vector *getStack(int stackType, class Channel *ch=NULL); Plugin *getPluginById(int id, int stackType, class Channel *ch=NULL); Plugin *getPluginByIndex(int index, int stackType, class Channel *ch=NULL); int getPluginIndex(int id, int stackType, class Channel *ch=NULL); unsigned countPlugins(int stackType, class Channel *ch=NULL); void freeStack(int stackType, class Channel *ch=NULL); void freeAllStacks(); void freePlugin(int id, int stackType, class Channel *ch=NULL); void swapPlugin(unsigned indexA, unsigned indexB, int stackType, class Channel *ch=NULL); }; #endif #endif // #ifdef WITH_VST giada-0.11.2/src/core/recorder.cpp000066400000000000000000000424631264622563000167070ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * recorder * Action recorder. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "recorder.h" #include "const.h" #include "mixer.h" #include "mixerHandler.h" #include "kernelAudio.h" #include "pluginHost.h" #include "kernelMidi.h" #include "patch_DEPR_.h" #include "conf.h" #include "channel.h" #include "sampleChannel.h" #include "../utils/log.h" #include "../utils/utils.h" #ifdef WITH_VST extern PluginHost G_PluginHost; #endif extern Mixer G_Mixer; extern Patch_DEPR_ f_patch; extern Conf G_Conf; namespace recorder { vector frames; vector< vector > global; vector actions; bool active = false; bool sortedActions = false; composite cmp; /* ------------------------------------------------------------------ */ void init() { sortedActions = false; active = false; clearAll(); } /* ------------------------------------------------------------------ */ bool canRec(Channel *ch) { /* NO recording if: * recorder is inactive * mixer is not running * mixer is recording a take in this channel ch * channel is empty */ if (!active || !G_Mixer.running || G_Mixer.chanInput == ch || (ch->type == CHANNEL_SAMPLE && ((SampleChannel*)ch)->wave == NULL)) return 0; return 1; } /* ------------------------------------------------------------------ */ void rec(int index, int type, int frame, uint32_t iValue, float fValue) { /* make sure frame is even */ if (frame % 2 != 0) frame++; /* allocating the action */ action *a = (action*) malloc(sizeof(action)); a->chan = index; a->type = type; a->frame = frame; a->iValue = iValue; a->fValue = fValue; /* check if the frame exists in the stack. If it exists, we don't extend * the stack, but we add (or push) a new action to it. */ int frameToExpand = frames.size(); for (int i=0; ichan == index && ac->type == type && ac->frame == frame && ac->iValue == iValue && ac->fValue == fValue) return; } global.at(frameToExpand).push_back(a); // expand array } /* if WITH_VST create a new VST event and attach it to our action. * Nota bene: the VST event occurs on localFrame=0: this is a * user-generated event after all! */ #ifdef WITH_VST if (type == ACTION_MIDI) a->event = G_PluginHost.createVstMidiEvent(a->iValue); #endif /* don't activate the channel (readActions == false), it's up to * the other layers */ Channel *ch = G_Mixer.getChannelByIndex(index); ch->hasActions = true; sortedActions = false; gLog("[REC] action recorded, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", a->type, a->frame, a->chan, a->iValue, a->iValue, a->fValue); //print(); } /* ------------------------------------------------------------------ */ void clearChan(int index) { gLog("[REC] clearing chan %d...\n", index); for (unsigned i=0; ichan == index) { #ifdef WITH_VST if (a->type == ACTION_MIDI) free(a->event); #endif free(a); global.at(i).erase(global.at(i).begin() + j); } else j++; } } Channel *ch = G_Mixer.getChannelByIndex(index); ch->hasActions = false; optimize(); //print(); } /* ------------------------------------------------------------------ */ void clearAction(int index, char act) { gLog("[REC] clearing action %d from chan %d...\n", act, index); for (unsigned i=0; ichan == index && (act & a->type) == a->type) { // bitmask free(a); global.at(i).erase(global.at(i).begin() + j); } else j++; } } Channel *ch = G_Mixer.getChannelByIndex(index); ch->hasActions = false; /// FIXME - why this? Isn't it useless if we call chanHasActions? optimize(); chanHasActions(index); /// FIXME //print(); } /* ------------------------------------------------------------------ */ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue, float fValue) { /* make sure frame is even */ if (frame % 2 != 0) frame++; /* find the frame 'frame' */ bool found = false; for (unsigned i=0; ichan == chan && a->type == (type & a->type)); if (checkValues) doit &= (a->iValue == iValue && a->fValue == fValue); if (doit) { int lockStatus = 0; while (lockStatus == 0) { lockStatus = pthread_mutex_trylock(&G_Mixer.mutex_recs); if (lockStatus == 0) { #ifdef WITH_VST if (type == ACTION_MIDI) free(a->event); #endif free(a); global.at(i).erase(global.at(i).begin() + j); pthread_mutex_unlock(&G_Mixer.mutex_recs); found = true; break; } else gLog("[REC] delete action: waiting for mutex...\n"); } } } } } if (found) { optimize(); chanHasActions(chan); gLog("[REC] action deleted, type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", type, frame, chan, iValue, iValue, fValue); } else gLog("[REC] unable to delete action, not found! type=%d frame=%d chan=%d iValue=%d (%X) fValue=%f\n", type, frame, chan, iValue, iValue, fValue); } /* ------------------------------------------------------------------ */ void deleteActions(int chan, int frame_a, int frame_b, char type) { sortActions(); vector dels; for (unsigned i=0; i frame_a && frames.at(i) < frame_b) dels.push_back(frames.at(i)); for (unsigned i=0; i 0) { for (unsigned i=0; itype == ACTION_MIDI) free(global.at(i).at(k)->event); #endif free(global.at(i).at(k)); // free action } global.at(i).clear(); // free action container global.erase(global.begin() + i); } } for (unsigned i=0; ihasActions = false; if (G_Mixer.channels.at(i)->type == CHANNEL_SAMPLE) ((SampleChannel*)G_Mixer.channels.at(i))->readActions = false; } global.clear(); frames.clear(); } /* ------------------------------------------------------------------ */ void optimize() { /* do something until the i frame is empty. */ unsigned i = 0; while (true) { if (i == global.size()) return; if (global.at(i).size() == 0) { global.erase(global.begin() + i); frames.erase(frames.begin() + i); } else i++; } sortActions(); } /* ------------------------------------------------------------------ */ void sortActions() { if (sortedActions) return; for (unsigned i=0; i frames.at(i)) { std::swap(frames.at(j), frames.at(i)); std::swap(global.at(j), global.at(i)); } sortedActions = true; //print(); } /* ------------------------------------------------------------------ */ void updateBpm(float oldval, float newval, int oldquanto) { for (unsigned i=0; i 0 && scarto <= 6) frames.at(i) = frames.at(i) + scarto; } /* never ever have odd frames. */ if (frames.at(i) % 2 != 0) frames.at(i)++; } /* update structs */ for (unsigned i=0; iframe = frames.at(i); } } //print(); } /* ------------------------------------------------------------------ */ void updateSamplerate(int systemRate, int patchRate) { /* diff ratio: systemRate / patchRate * e.g. 44100 / 96000 = 0.4... */ if (systemRate == patchRate) return; gLog("[REC] systemRate (%d) != patchRate (%d), converting...\n", systemRate, patchRate); float ratio = systemRate / (float) patchRate; for (unsigned i=0; iframe = frames.at(i); } } } /* ------------------------------------------------------------------ */ void expand(int old_fpb, int new_fpb) { /* this algorithm requires multiple passages if we expand from e.g. 2 * to 16 beats, precisely 16 / 2 - 1 = 7 times (-1 is the first group, * which exists yet). If we expand by a non-multiple, the result is zero, * due to float->int implicit cast */ unsigned pass = (int) (new_fpb / old_fpb) - 1; if (pass == 0) pass = 1; unsigned init_fs = frames.size(); for (unsigned z=1; z<=pass; z++) { for (unsigned i=0; ichan, a->type, newframe, a->iValue, a->fValue); } } } gLog("[REC] expanded recs\n"); //print(); } /* ------------------------------------------------------------------ */ void shrink(int new_fpb) { /* easier than expand(): here we delete eveything beyond old_framesPerBars. */ unsigned i=0; while (true) { if (i == frames.size()) break; if (frames.at(i) >= new_fpb) { for (unsigned k=0; khasActions = false; return; } for (unsigned i=0; ihasActions; i++) { for (unsigned j=0; jhasActions; j++) { if (global.at(i).at(j)->chan == index) ch->hasActions = true; } } } /* ------------------------------------------------------------------ */ int getNextAction(int chan, char type, int frame, action **out, uint32_t iValue) { sortActions(); // mandatory unsigned i=0; while (i < frames.size() && frames.at(i) <= frame) i++; if (i == frames.size()) // no further actions past 'frame' return -1; for (; ichan == chan && (type & a->type) == a->type) { if (iValue == 0 || (iValue != 0 && a->iValue == iValue)) { *out = global.at(i).at(j); return 1; } } } return -2; // no 'type' actions found } /* ------------------------------------------------------------------ */ int getAction(int chan, char action, int frame, struct action **out) { for (unsigned i=0; iframe && action == global.at(i).at(j)->type && chan == global.at(i).at(j)->chan) { *out = global.at(i).at(j); return 1; } return 0; } /* ------------------------------------------------------------------ */ void startOverdub(int index, char actionMask, int frame) { /* prepare the composite struct */ if (actionMask == ACTION_KEYS) { cmp.a1.type = ACTION_KEYPRESS; cmp.a2.type = ACTION_KEYREL; } else { cmp.a1.type = ACTION_MUTEON; cmp.a2.type = ACTION_MUTEOFF; } cmp.a1.chan = index; cmp.a2.chan = index; cmp.a1.frame = frame; // cmp.a2.frame doesn't exist yet /* avoid underlying action truncation: if action2.type == nextAction: * you are in the middle of a composite action, truncation needed */ rec(index, cmp.a1.type, frame); action *act = NULL; int res = getNextAction(index, cmp.a1.type | cmp.a2.type, cmp.a1.frame, &act); if (res == 1) { if (act->type == cmp.a2.type) { int truncFrame = cmp.a1.frame-kernelAudio::realBufsize; if (truncFrame < 0) truncFrame = 0; gLog("[REC] add truncation at frame %d, type=%d\n", truncFrame, cmp.a2.type); rec(index, cmp.a2.type, truncFrame); } } SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(index); ch->readActions = false; // don't use disableRead() } /* ------------------------------------------------------------------ */ void stopOverdub(int frame) { cmp.a2.frame = frame; bool ringLoop = false; bool nullLoop = false; /* ring loop verification, i.e. a composite action with key_press at * frame N and key_release at frame M, with M <= N */ if (cmp.a2.frame < cmp.a1.frame) { ringLoop = true; gLog("[REC] ring loop! frame1=%d < frame2=%d\n", cmp.a1.frame, cmp.a2.frame); rec(cmp.a2.chan, cmp.a2.type, G_Mixer.totalFrames); // record at the end of the sequencer } else if (cmp.a2.frame == cmp.a1.frame) { nullLoop = true; gLog("[REC] null loop! frame1=%d == frame2=%d\n", cmp.a1.frame, cmp.a2.frame); deleteAction(cmp.a1.chan, cmp.a1.frame, cmp.a1.type, false); // false == don't check values } SampleChannel *ch = (SampleChannel*) G_Mixer.getChannelByIndex(cmp.a2.chan); ch->readActions = false; // don't use disableRead() /* remove any nested action between keypress----keyrel, then record */ if (!nullLoop) deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a1.type); deleteActions(cmp.a2.chan, cmp.a1.frame, cmp.a2.frame, cmp.a2.type); if (!ringLoop && !nullLoop) { rec(cmp.a2.chan, cmp.a2.type, cmp.a2.frame); /* avoid underlying action truncation, if keyrel happens inside a * composite action */ action *act = NULL; int res = getNextAction(cmp.a2.chan, cmp.a1.type | cmp.a2.type, cmp.a2.frame, &act); if (res == 1) { if (act->type == cmp.a2.type) { gLog("[REC] add truncation at frame %d, type=%d\n", act->frame, act->type); deleteAction(act->chan, act->frame, act->type, false); // false == don't check values } } } } /* ------------------------------------------------------------------ */ void print() { gLog("[REC] ** print debug **\n"); for (unsigned i=0; itype, global.at(i).at(j)->chan, global.at(i).at(j)->frame); } } } } // namespace giada-0.11.2/src/core/recorder.h000066400000000000000000000123201264622563000163410ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * recorder * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef RECORDER_H #define RECORDER_H #include #include #include #include "../utils/utils.h" #include "const.h" #include "mixer.h" #ifdef WITH_VST /* before including aeffetx(x).h we must define __cdecl, otherwise VST * headers can't be compiled correctly. In windows __cdecl is already * defined. */ #ifdef __GNUC__ #ifndef _WIN32 #define __cdecl #endif #endif #include "../deps/vst/aeffectx.h" #endif using std::vector; /* * [global0]-->[vector<_action*>0]-->[a0][a1][a2] 0[frames1] * [global1]-->[vector<_action*>1]-->[a0][a1][a2] 1[frames2] * [global2]-->[vector<_action*>2]-->[a0][a1][a2] 2[frames3] * [global3]-->[vector<_action*>3]-->[a0][a1][a2] 3[frames4] * */ namespace recorder { /* action * struct containing fields to describe an atomic action. Note from * VST sdk: parameter values, like all VST parameters, are declared as * floats with an inclusive range of 0.0 to 1.0 (fValue). */ struct action { int chan; // channel index, i.e. Channel->index int type; int frame; // redundant info, used by helper functions float fValue; // used only for envelopes (volumes, vst params). uint32_t iValue; // used only for MIDI events /* if VST store here a pointer to a vstEvent. */ #ifdef WITH_VST VstMidiEvent *event; #endif }; /* composite * a group of two actions (keypress+keyrel, muteon+muteoff) used during * the overdub process */ struct composite { action a1; action a2; }; extern vector frames; // frame counter (sentinel) frames.size == global.size extern vector< vector > global; // container of containers of actions extern vector actions; // container of actions extern bool active; extern bool sortedActions; // are actions sorted via sortActions()? /* init * everything starts from here. */ void init(); /* chanHasActions * Check if the channel has at least one action recorded. If false, sets * ch->hasActions = false. Used after an action deletion. */ void chanHasActions(int chan); /* canRec * can a channel rec an action? Call this one BEFORE rec(). */ bool canRec(Channel *ch); /* rec * record an action. */ void rec(int chan, int action, int frame, uint32_t iValue=0, float fValue=0.0f); /* clearChan * clear all actions from a channel. */ void clearChan(int chan); /* clearAction * clear the 'action' action type from a channel. */ void clearAction(int chan, char action); /* deleteAction * delete ONE action. Useful in the action editor. 'type' can be a mask. */ void deleteAction(int chan, int frame, char type, bool checkValues, uint32_t iValue=0, float fValue=0.0); /* deleteActions * delete A RANGE of actions from frame_a to frame_b in channel 'chan'. * 'type' can be a bitmask. Exclusive range (frame_a, frame_b). */ void deleteActions(int chan, int frame_a, int frame_b, char type); /* clearAll * delete everything. */ void clearAll(); /* optimize * clear frames without actions. */ void optimize(); /* sortActions * sorts actions by frame, asc mode. */ void sortActions(); /* updateBpm * reassign frames by calculating the new bpm value. */ void updateBpm(float oldval, float newval, int oldquanto); /* updateSamplerate * reassign frames taking in account the samplerate. If f_system == * f_patch nothing changes, otherwise the conversion is mandatory. */ void updateSamplerate(int systemRate, int patchRate); void expand(int old_fpb, int new_fpb); void shrink(int new_fpb); /* getNextAction * return the nearest action in chan 'chan' of type 'action' starting * from 'frame'. Action can be a bitmask. If iValue != -1 search for * next action with iValue == iValue: useful for MIDI key_release. */ int getNextAction(int chan, char action, int frame, struct action **out, uint32_t iValue=0); /* getAction * return a pointer to action in chan 'chan' of type 'action' at frame * 'frame'. */ int getAction(int chan, char action, int frame, struct action **out); /* start/endOverdub */ void startOverdub(int chan, char action, int frame); void stopOverdub(int frame); /* print * debug of the frame stack. */ void print(); } // namespace #endif giada-0.11.2/src/core/sampleChannel.cpp000066400000000000000000000622311264622563000176470ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * channel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../utils/log.h" #include "sampleChannel.h" #include "patch_DEPR_.h" #include "patch.h" #include "conf.h" #include "wave.h" #include "pluginHost.h" #include "waveFx.h" #include "mixerHandler.h" #include "kernelMidi.h" extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Mixer G_Mixer; extern Conf G_Conf; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif using std::string; SampleChannel::SampleChannel(int bufferSize) : Channel (CHANNEL_SAMPLE, STATUS_EMPTY, bufferSize), frameRewind (-1), wave (NULL), tracker (0), begin (0), end (0), pitch (gDEFAULT_PITCH), boost (1.0f), mode (DEFAULT_CHANMODE), qWait (false), fadeinOn (false), fadeinVol (1.0f), fadeoutOn (false), fadeoutVol (1.0f), fadeoutTracker (0), fadeoutStep (DEFAULT_FADEOUT_STEP), readActions (true), midiInReadActions(0x0), midiInPitch (0x0) { rsmp_state = src_new(SRC_LINEAR, 2, NULL); pChan = (float *) malloc(kernelAudio::realBufsize * 2 * sizeof(float)); } /* -------------------------------------------------------------------------- */ SampleChannel::~SampleChannel() { if (wave) delete wave; src_delete(rsmp_state); free(pChan); } /* -------------------------------------------------------------------------- */ void SampleChannel::copy(const Channel *_src) { Channel::copy(_src); SampleChannel *src = (SampleChannel *) _src; tracker = src->tracker; begin = src->begin; end = src->end; boost = src->boost; mode = src->mode; qWait = src->qWait; fadeinOn = src->fadeinOn; fadeinVol = src->fadeinVol; fadeoutOn = src->fadeoutOn; fadeoutVol = src->fadeoutVol; fadeoutTracker = src->fadeoutTracker; fadeoutStep = src->fadeoutStep; fadeoutType = src->fadeoutType; fadeoutEnd = src->fadeoutEnd; setPitch(src->pitch); if (src->wave) { Wave *w = new Wave(*src->wave); // invoke Wave's copy constructor pushWave(w); generateUniqueSampleName(); } } /* -------------------------------------------------------------------------- */ void SampleChannel::generateUniqueSampleName() { string oldName = wave->name; int k = 1; // Start from k = 1, zero is too nerdy while (!mh_uniqueSamplename(this, wave->name.c_str())) { wave->updateName((oldName + "-" + gItoa(k)).c_str()); k++; } } /* -------------------------------------------------------------------------- */ void SampleChannel::clear() { /** TODO - these memsets can be done only if status PLAY (if below), * but it would require extra clearPChan calls when samples stop */ memset(vChan, 0, sizeof(float) * bufferSize); memset(pChan, 0, sizeof(float) * bufferSize); if (status & (STATUS_PLAY | STATUS_ENDING)) { tracker = fillChan(vChan, tracker, 0); if (fadeoutOn && fadeoutType == XFADE) { gLog("[clear] filling pChan fadeoutTracker=%d\n", fadeoutTracker); fadeoutTracker = fillChan(pChan, fadeoutTracker, 0); } } } /* -------------------------------------------------------------------------- */ void SampleChannel::calcVolumeEnv(int frame) { /* method: check this frame && next frame, then calculate delta */ recorder::action *a0 = NULL; recorder::action *a1 = NULL; int res; /* get this action on frame 'frame'. It's unlikely that the action * is not found. */ res = recorder::getAction(index, ACTION_VOLUME, frame, &a0); if (res == 0) return; /* get the action next to this one. * res == -1: a1 not found, this is the last one. Rewind the search * and use action at frame number 0 (actions[0]). * res == -2 ACTION_VOLUME not found. This should never happen */ res = recorder::getNextAction(index, ACTION_VOLUME, frame, &a1); if (res == -1) res = recorder::getAction(index, ACTION_VOLUME, 0, &a1); volume_i = a0->fValue; volume_d = ((a1->fValue - a0->fValue) / ((a1->frame - a0->frame) / 2)) * 1.003f; } /* -------------------------------------------------------------------------- */ void SampleChannel::hardStop(int frame) { if (frame != 0) // clear data in range [frame, bufferSize-1] clearChan(vChan, frame); status = STATUS_OFF; sendMidiLplay(); reset(frame); } /* -------------------------------------------------------------------------- */ void SampleChannel::onBar(int frame) { ///if (mode == LOOP_REPEAT && status == STATUS_PLAY) /// //setXFade(frame); /// reset(frame); if (mode == LOOP_REPEAT) { if (status == STATUS_PLAY) //setXFade(frame); reset(frame); } else if (mode == LOOP_ONCE_BAR) { if (status == STATUS_WAIT) { status = STATUS_PLAY; tracker = fillChan(vChan, tracker, frame); sendMidiLplay(); } } } /* -------------------------------------------------------------------------- */ int SampleChannel::save(const char *path) { return wave->writeData(path); } /* -------------------------------------------------------------------------- */ void SampleChannel::setBegin(unsigned v) { begin = v; tracker = begin; } /* -------------------------------------------------------------------------- */ void SampleChannel::setEnd(unsigned v) { end = v; } /* -------------------------------------------------------------------------- */ void SampleChannel::setPitch(float v) { pitch = v; rsmp_data.src_ratio = 1/pitch; /* if status is off don't slide between frequencies */ if (status & (STATUS_OFF | STATUS_WAIT)) src_set_ratio(rsmp_state, 1/pitch); } /* -------------------------------------------------------------------------- */ void SampleChannel::rewind() { /* rewind LOOP_ANY or SINGLE_ANY only if it's in read-record-mode */ if (wave != NULL) { if ((mode & LOOP_ANY) || (recStatus == REC_READING && (mode & SINGLE_ANY))) reset(0); // rewind is user-generated events, always on frame 0 } } /* -------------------------------------------------------------------------- */ void SampleChannel::parseAction(recorder::action *a, int localFrame, int globalFrame) { if (readActions == false) return; switch (a->type) { case ACTION_KEYPRESS: if (mode & SINGLE_ANY) start(localFrame, false); break; case ACTION_KEYREL: if (mode & SINGLE_ANY) stop(); break; case ACTION_KILLCHAN: if (mode & SINGLE_ANY) kill(localFrame); break; case ACTION_MUTEON: setMute(true); // internal mute break; case ACTION_MUTEOFF: unsetMute(true); // internal mute break; case ACTION_VOLUME: calcVolumeEnv(globalFrame); break; } } /* -------------------------------------------------------------------------- */ void SampleChannel::sum(int frame, bool running) { if (wave == NULL || status & ~(STATUS_PLAY | STATUS_ENDING)) return; if (frame != frameRewind) { /* volume envelope, only if seq is running */ if (running) { volume_i += volume_d; if (volume_i < 0.0f) volume_i = 0.0f; else if (volume_i > 1.0f) volume_i = 1.0f; } /* fadein or fadeout processes. If mute, delete any signal. */ /** TODO - big issue: fade[in/out]Vol * internal_volume might be a * bad choice: it causes glitches when muting on and off during a * volume envelope. */ if (mute || mute_i) { vChan[frame] = 0.0f; vChan[frame+1] = 0.0f; } else if (fadeinOn) { if (fadeinVol < 1.0f) { vChan[frame] *= fadeinVol * volume_i; vChan[frame+1] *= fadeinVol * volume_i; fadeinVol += 0.01f; } else { fadeinOn = false; fadeinVol = 0.0f; } } else if (fadeoutOn) { if (fadeoutVol > 0.0f) { // fadeout ongoing if (fadeoutType == XFADE) { vChan[frame] *= volume_i; vChan[frame+1] *= volume_i; vChan[frame] = pChan[frame] * fadeoutVol * volume_i; vChan[frame+1] = pChan[frame+1] * fadeoutVol * volume_i; } else { vChan[frame] *= fadeoutVol * volume_i; vChan[frame+1] *= fadeoutVol * volume_i; } fadeoutVol -= fadeoutStep; } else { // fadeout end fadeoutOn = false; fadeoutVol = 1.0f; /* QWait ends with the end of the xfade */ if (fadeoutType == XFADE) { qWait = false; } else { if (fadeoutEnd == DO_MUTE) mute = true; else if (fadeoutEnd == DO_MUTE_I) mute_i = true; else // DO_STOP hardStop(frame); } } } else { vChan[frame] *= volume_i; vChan[frame+1] *= volume_i; } } else { // at this point the sample has reached the end */ if (mode & (SINGLE_BASIC | SINGLE_PRESS | SINGLE_RETRIG) || (mode == SINGLE_ENDLESS && status == STATUS_ENDING) || (mode & LOOP_ANY && !running)) // stop loops when the seq is off { status = STATUS_OFF; sendMidiLplay(); } /* LOOP_ONCE or LOOP_ONCE_BAR: if ending (i.e. the user requested their * termination), kill 'em. Let them wait otherwise. But don't put back in * wait mode those already stopped by the conditionals above. */ if (mode & (LOOP_ONCE | LOOP_ONCE_BAR)) { if (status == STATUS_ENDING) status = STATUS_OFF; else if (status != STATUS_OFF) status = STATUS_WAIT; } /* check for end of samples. SINGLE_ENDLESS runs forever unless * it's in ENDING mode. */ reset(frame); } } /* -------------------------------------------------------------------------- */ void SampleChannel::onZero(int frame) { if (wave == NULL) return; if (mode & LOOP_ANY) { /* do a crossfade if the sample is playing. Regular chanReset * instead if it's muted, otherwise a click occurs */ if (status == STATUS_PLAY) { /* if (mute || mute_i) reset(frame); else setXFade(frame); */ reset(frame); } else if (status == STATUS_ENDING) hardStop(frame); } if (status == STATUS_WAIT) { /// FIXME - should be inside previous if! status = STATUS_PLAY; sendMidiLplay(); tracker = fillChan(vChan, tracker, frame); } if (recStatus == REC_ENDING) { recStatus = REC_STOPPED; setReadActions(false); // rec stop } else if (recStatus == REC_WAITING) { recStatus = REC_READING; setReadActions(true); // rec start } } /* -------------------------------------------------------------------------- */ void SampleChannel::quantize(int index, int localFrame, int globalFrame) { /* skip if LOOP_ANY or not in quantizer-wait mode */ if ((mode & LOOP_ANY) || !qWait) return; /* no fadeout if the sample starts for the first time (from a * STATUS_OFF), it would be meaningless. */ if (status == STATUS_OFF) { status = STATUS_PLAY; sendMidiLplay(); qWait = false; tracker = fillChan(vChan, tracker, localFrame); /// FIXME: ??? } else //setXFade(localFrame); reset(localFrame); /* this is the moment in which we record the keypress, if the * quantizer is on. SINGLE_PRESS needs overdub */ if (recorder::canRec(this)) { if (mode == SINGLE_PRESS) recorder::startOverdub(index, ACTION_KEYS, globalFrame); else recorder::rec(index, ACTION_KEYPRESS, globalFrame); } } /* -------------------------------------------------------------------------- */ int SampleChannel::getPosition() { if (status & ~(STATUS_EMPTY | STATUS_MISSING | STATUS_OFF)) // if is not (...) return tracker - begin; else return -1; } /* -------------------------------------------------------------------------- */ void SampleChannel::setMute(bool internal) { if (internal) { /* global mute is on? don't waste time with fadeout, just mute it * internally */ if (mute) mute_i = true; else { if (isPlaying()) setFadeOut(DO_MUTE_I); else mute_i = true; } } else { /* internal mute is on? don't waste time with fadeout, just mute it * globally */ if (mute_i) mute = true; else { /* sample in play? fadeout needed. Else, just mute it globally */ if (isPlaying()) setFadeOut(DO_MUTE); else mute = true; } } sendMidiLmute(); } /* -------------------------------------------------------------------------- */ void SampleChannel::unsetMute(bool internal) { if (internal) { if (mute) mute_i = false; else { if (isPlaying()) setFadeIn(internal); else mute_i = false; } } else { if (mute_i) mute = false; else { if (isPlaying()) setFadeIn(internal); else mute = false; } } sendMidiLmute(); } /* -------------------------------------------------------------------------- */ void SampleChannel::calcFadeoutStep() { if (end - tracker < (1 / DEFAULT_FADEOUT_STEP) * 2) fadeoutStep = ceil((end - tracker) / volume) * 2; /// or volume_i ??? else fadeoutStep = DEFAULT_FADEOUT_STEP; } /* -------------------------------------------------------------------------- */ void SampleChannel::setReadActions(bool v) { if (v) readActions = true; else { readActions = false; if (G_Conf.recsStopOnChanHalt) kill(0); /// FIXME - wrong frame value } } /* -------------------------------------------------------------------------- */ void SampleChannel::setFadeIn(bool internal) { if (internal) mute_i = false; // remove mute before fading in else mute = false; fadeinOn = true; fadeinVol = 0.0f; } /* -------------------------------------------------------------------------- */ void SampleChannel::setFadeOut(int actionPostFadeout) { calcFadeoutStep(); fadeoutOn = true; fadeoutVol = 1.0f; fadeoutType = FADEOUT; fadeoutEnd = actionPostFadeout; } /* -------------------------------------------------------------------------- */ void SampleChannel::setXFade(int frame) { gLog("[xFade] frame=%d tracker=%d\n", frame, tracker); calcFadeoutStep(); fadeoutOn = true; fadeoutVol = 1.0f; fadeoutType = XFADE; fadeoutTracker = fillChan(pChan, tracker, 0, false); reset(frame); } /* -------------------------------------------------------------------------- */ /* on reset, if frame > 0 and in play, fill again pChan to create * something like this: * * |abcdefabcdefab*abcdefabcde| * [old data-----]*[new data--] * * */ void SampleChannel::reset(int frame) { //fadeoutTracker = tracker; // store old frame number for xfade tracker = begin; mute_i = false; if (frame > 0 && status & (STATUS_PLAY | STATUS_ENDING)) tracker = fillChan(vChan, tracker, frame); } /* -------------------------------------------------------------------------- */ void SampleChannel::empty() { status = STATUS_OFF; if (wave) { delete wave; wave = NULL; } status = STATUS_EMPTY; sendMidiLplay(); } /* -------------------------------------------------------------------------- */ void SampleChannel::pushWave(Wave *w) { wave = w; status = STATUS_OFF; sendMidiLplay(); begin = 0; end = wave->size; } /* -------------------------------------------------------------------------- */ bool SampleChannel::allocEmpty(int frames, int takeId) { Wave *w = new Wave(); if (!w->allocEmpty(frames, G_Conf.samplerate)) return false; char wname[32]; sprintf(wname, "TAKE-%d", takeId); w->pathfile = gGetCurrentPath()+"/"+wname; // FIXME - use gGetSlash() in utils.h w->name = wname; wave = w; status = STATUS_OFF; begin = 0; end = wave->size; sendMidiLplay(); return true; } /* -------------------------------------------------------------------------- */ void SampleChannel::process(float *buffer) { #ifdef WITH_VST G_PluginHost.processStack(vChan, PluginHost::CHANNEL, this); #endif for (int j=0; j FILENAME_MAX) return SAMPLE_PATH_TOO_LONG; Wave *w = new Wave(); if (!w->open(file)) { gLog("[SampleChannel] %s: read error\n", file); delete w; return SAMPLE_READ_ERROR; } if (w->channels() > 2) { gLog("[SampleChannel] %s: unsupported multichannel wave\n", file); delete w; return SAMPLE_MULTICHANNEL; } if (!w->readData()) { delete w; return SAMPLE_READ_ERROR; } if (w->channels() == 1) /** FIXME: error checking */ wfx_monoToStereo(w); if (w->rate() != G_Conf.samplerate) { gLog("[SampleChannel] input rate (%d) != system rate (%d), conversion needed\n", w->rate(), G_Conf.samplerate); w->resample(G_Conf.rsmpQuality, G_Conf.samplerate); } pushWave(w); generateUniqueSampleName(); gLog("[SampleChannel] %s loaded in channel %d\n", file, index); return SAMPLE_LOADED_OK; } /* -------------------------------------------------------------------------- */ int SampleChannel::readPatch_DEPR_(const char *f, int i) { int res = load(f); volume = G_Patch_DEPR_.getVol(i); key = G_Patch_DEPR_.getKey(i); index = G_Patch_DEPR_.getIndex(i); mode = G_Patch_DEPR_.getMode(i); mute = G_Patch_DEPR_.getMute(i); mute_s = G_Patch_DEPR_.getMute_s(i); solo = G_Patch_DEPR_.getSolo(i); boost = G_Patch_DEPR_.getBoost(i); panLeft = G_Patch_DEPR_.getPanLeft(i); panRight = G_Patch_DEPR_.getPanRight(i); readActions = G_Patch_DEPR_.getRecActive(i); recStatus = readActions ? REC_READING : REC_STOPPED; readPatchMidiIn_DEPR_(i); midiInReadActions = G_Patch_DEPR_.getMidiValue(i, "InReadActions"); midiInPitch = G_Patch_DEPR_.getMidiValue(i, "InPitch"); readPatchMidiOut_DEPR_(i); if (res == SAMPLE_LOADED_OK) { setBegin(G_Patch_DEPR_.getBegin(i)); setEnd (G_Patch_DEPR_.getEnd(i, wave->size)); setPitch(G_Patch_DEPR_.getPitch(i)); } else { // volume = DEFAULT_VOL; // mode = DEFAULT_CHANMODE; // status = STATUS_WRONG; // key = 0; if (res == SAMPLE_LEFT_EMPTY) status = STATUS_EMPTY; else if (res == SAMPLE_READ_ERROR) status = STATUS_MISSING; sendMidiLplay(); } return res; } /* -------------------------------------------------------------------------- */ int SampleChannel::readPatch(const string &basePath, int i) { /* load channel's data first: if the sample is missing or wrong, the channel * is not completely blank. */ Channel::readPatch("", i); Patch::channel_t *pch = &G_Patch.channels.at(i); mode = pch->mode; boost = pch->boost; readActions = pch->recActive; recStatus = readActions ? REC_READING : REC_STOPPED; midiInReadActions = pch->midiInReadActions; midiInPitch = pch->midiInPitch; int res = load((basePath + pch->samplePath).c_str()); if (res == SAMPLE_LOADED_OK) { setBegin(pch->begin); setEnd (pch->end); setPitch(pch->pitch); } else { if (res == SAMPLE_LEFT_EMPTY) status = STATUS_EMPTY; else if (res == SAMPLE_READ_ERROR) status = STATUS_MISSING; sendMidiLplay(); // FIXME - why sending MIDI lightning if sample status is wrong? } return res; } /* -------------------------------------------------------------------------- */ bool SampleChannel::canInputRec() { return wave == NULL; } /* -------------------------------------------------------------------------- */ void SampleChannel::start(int frame, bool doQuantize) { switch (status) { case STATUS_EMPTY: case STATUS_MISSING: case STATUS_WRONG: { return; } case STATUS_OFF: { if (mode & LOOP_ANY) { status = STATUS_WAIT; sendMidiLplay(); } else { if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize) qWait = true; else { /* fillChan only if frame != 0. If you call fillChan on frame == 0 * a duplicate call to fillChan occurs with loss of data. */ status = STATUS_PLAY; sendMidiLplay(); if (frame != 0) tracker = fillChan(vChan, tracker, frame); } } break; } case STATUS_PLAY: { if (mode == SINGLE_BASIC) setFadeOut(DO_STOP); else if (mode == SINGLE_RETRIG) { if (G_Mixer.quantize > 0 && G_Mixer.running && doQuantize) qWait = true; else reset(frame); } else if (mode & (LOOP_ANY | SINGLE_ENDLESS)) { status = STATUS_ENDING; sendMidiLplay(); } break; } case STATUS_WAIT: { status = STATUS_OFF; sendMidiLplay(); break; } case STATUS_ENDING: { status = STATUS_PLAY; sendMidiLplay(); break; } } } /* -------------------------------------------------------------------------- */ int SampleChannel::writePatch(int i, bool isProject) { int pchIndex = Channel::writePatch(i, isProject); Patch::channel_t *pch = &G_Patch.channels.at(pchIndex); if (wave != NULL) { pch->samplePath = wave->pathfile; if (isProject) pch->samplePath = gBasename(wave->pathfile); // make it portable } else pch->samplePath = ""; pch->mode = mode; pch->begin = begin; pch->end = end; pch->boost = boost; pch->recActive = readActions; pch->pitch = pitch; pch->midiInReadActions = midiInReadActions; pch->midiInPitch = midiInPitch; return 0; } /* -------------------------------------------------------------------------- */ void SampleChannel::clearChan(float *dest, int start) { memset(dest+start, 0, sizeof(float)*(bufferSize-start)); } /* -------------------------------------------------------------------------- */ int SampleChannel::fillChan(float *dest, int start, int offset, bool rewind) { int position; // return value: the new position if (pitch == 1.0f) { /* case 1: 'dest' lies within the original sample boundaries (start- * end) */ if (start+bufferSize-offset <= end) { memcpy(dest+offset, wave->data+start, (bufferSize-offset)*sizeof(float)); position = start+bufferSize-offset; if (rewind) frameRewind = -1; } /* case2: 'dest' lies outside the end of the sample, OR the sample * is smaller than 'dest' */ else { memcpy(dest+offset, wave->data+start, (end-start)*sizeof(float)); position = end; if (rewind) frameRewind = end-start+offset; } } else { rsmp_data.data_in = wave->data+start; // source data rsmp_data.input_frames = (end-start)/2; // how many readable bytes rsmp_data.data_out = dest+offset; // destination (processed data) rsmp_data.output_frames = (bufferSize-offset)/2; // how many bytes to process rsmp_data.end_of_input = false; src_process(rsmp_state, &rsmp_data); int gen = rsmp_data.output_frames_gen*2; // frames generated by this call position = start + rsmp_data.input_frames_used*2; // position goes forward of frames_used (i.e. read from wave) if (rewind) { if (gen == bufferSize-offset) frameRewind = -1; else frameRewind = gen+offset; } } return position; } giada-0.11.2/src/core/sampleChannel.h000066400000000000000000000125411264622563000173130ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * sampleChannel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef SAMPLE_CHANNEL_H #define SAMPLE_CHANNEL_H #include #include "channel.h" class SampleChannel : public Channel { private: /* rsmp_state, rsmp_data * structs from libsamplerate */ SRC_STATE *rsmp_state; SRC_DATA rsmp_data; /* pChan * extra virtual channel for processing resampled data. */ float *pChan; /* frameRewind * exact frame in which a rewind occurs */ int frameRewind; /* fillChan * copy from wave to *dest and resample data from wave, if necessary. * Start to fill pChan from byte 'offset'. If rewind=false don't * rewind internal tracker. Returns new sample position, in frames */ int fillChan(float *dest, int start, int offset, bool rewind=true); /* clearChan * set data to zero from start to bufferSize-1. */ void clearChan(float *dest, int start); /* calcFadeoutStep * how many frames are left before the end of the sample? Is there * enough room for a complete fadeout? Should we shorten it? */ void calcFadeoutStep(); /* calcVolumeEnv * compute any changes in volume done via envelope tool */ void calcVolumeEnv(int frame); /* generateUniqueSampleName * Sample name must be unique. Generate a new samplename with the "-[n]" * suffix. */ void generateUniqueSampleName(); public: SampleChannel(int bufferSize); ~SampleChannel(); void copy (const Channel *src); void clear (); void process (float *buffer); void start (int frame, bool doQuantize); void kill (int frame); void empty (); void stopBySeq (); void stop (); void rewind (); void setMute (bool internal); void unsetMute (bool internal); void reset (int frame); int load (const char *file); int readPatch_DEPR_ (const char *file, int i); int readPatch (const string &basePath, int i); int writePatch (int i, bool isProject); void quantize (int index, int localFrame, int globalFrame); void onZero (int frame); void onBar (int frame); void parseAction(recorder::action *a, int localFrame, int globalFrame); /* fade methods * prepare channel for fade, mixer will take care of the process * during master play. */ void setFadeIn (bool internal); void setFadeOut (int actionPostFadeout); void setXFade (int frame); /* pushWave * add a new wave to an existing channel. */ void pushWave(class Wave *w); /* getPosition * returns the position of an active sample. If EMPTY o MISSING * returns -1. */ int getPosition(); /* sum * add sample frames to virtual channel. Frame = processed frame in * Mixer. Running = is Mixer in play? */ void sum(int frame, bool running); /* setPitch * updates the pitch value and chanStart+chanEnd accordingly. */ void setPitch(float v); /* setStart/end * change begin/end read points in sample. */ void setBegin(unsigned v); void setEnd (unsigned v); /* save * save sample to file. */ int save(const char *path); /* hardStop * stop the channel immediately, no further checks. */ void hardStop(int frame); /* allocEmpty * alloc an empty wave used in input recordings. */ bool allocEmpty(int frames, int takeId); /* canInputRec * true if channel can host a new wave from input recording. */ bool canInputRec(); /* setReadActions * if enabled, recorder will read actions from this channel */ void setReadActions(bool v); /* ---------------------------------------------------------------- */ class Wave *wave; int tracker; // chan position int begin; int end; float pitch; float boost; int mode; // mode: see const.h bool qWait; // quantizer wait bool fadeinOn; float fadeinVol; bool fadeoutOn; float fadeoutVol; // fadeout volume int fadeoutTracker; // tracker fadeout, xfade only float fadeoutStep; // fadeout decrease int fadeoutType; // xfade or fadeout int fadeoutEnd; // what to do when fadeout ends /* recorder:: stuff */ bool readActions; // read actions or not /* midi stuff */ uint32_t midiInReadActions; uint32_t midiInPitch; /* const - what to do when a fadeout ends */ enum { DO_STOP = 0x01, DO_MUTE = 0x02, DO_MUTE_I = 0x04 }; /* const - fade types */ enum { FADEOUT = 0x01, XFADE = 0x02 }; }; #endif giada-0.11.2/src/core/wave.cpp000066400000000000000000000142221264622563000160340ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * wave * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include #include // memcpy #include #include "../utils/utils.h" #include "../utils/log.h" #include "wave.h" #include "init.h" Wave::Wave() : data (NULL), size (0), isLogical(0), isEdited (0) {} /* -------------------------------------------------------------------------- */ Wave::~Wave() { clear(); } /* -------------------------------------------------------------------------- */ Wave::Wave(const Wave &other) : data (NULL), size (0), isLogical(false), isEdited (false) { size = other.size; data = new float[size]; memcpy(data, other.data, size * sizeof(float)); memcpy(&inHeader, &other.inHeader, sizeof(other.inHeader)); pathfile = other.pathfile; name = other.name; isLogical = true; } /* -------------------------------------------------------------------------- */ int Wave::open(const char *f) { pathfile = f; name = gStripExt(gBasename(f).c_str()); fileIn = sf_open(f, SFM_READ, &inHeader); if (fileIn == NULL) { gLog("[wave] unable to read %s. %s\n", f, sf_strerror(fileIn)); pathfile = ""; name = ""; return 0; } isLogical = false; isEdited = false; return 1; } /* -------------------------------------------------------------------------- */ /* how to read and write with libsndfile: * * a frame consists of all items (samples) that belong to the same * point in time. So in each frame there are as many items as there * are channels. * * Quindi: * frame = [item, item, ...] * In pratica: * frame1 = [itemLeft, itemRight] * frame2 = [itemLeft, itemRight] * ... */ int Wave::readData() { size = inHeader.frames * inHeader.channels; data = (float *) malloc(size * sizeof(float)); if (data == NULL) { gLog("[wave] unable to allocate memory\n"); return 0; } if (sf_read_float(fileIn, data, size) != size) gLog("[wave] warning: incomplete read!\n"); sf_close(fileIn); return 1; } /* -------------------------------------------------------------------------- */ int Wave::writeData(const char *f) { /* prepare the header for output file */ outHeader.samplerate = inHeader.samplerate; outHeader.channels = inHeader.channels; outHeader.format = inHeader.format; fileOut = sf_open(f, SFM_WRITE, &outHeader); if (fileOut == NULL) { gLog("[wave] unable to open %s for exporting\n", f); return 0; } int out = sf_write_float(fileOut, data, size); if (out != (int) size) { gLog("[wave] error while exporting %s! %s\n", f, sf_strerror(fileOut)); return 0; } isLogical = false; isEdited = false; sf_close(fileOut); return 1; } /* -------------------------------------------------------------------------- */ void Wave::clear() { if (data != NULL) { free(data); data = NULL; pathfile = ""; size = 0; } } /* -------------------------------------------------------------------------- */ int Wave::allocEmpty(unsigned __size, unsigned samplerate) { /* the caller must pass a __size for stereo values */ /// FIXME - this way if malloc fails size becomes wrong size = __size; data = (float *) malloc(size * sizeof(float)); if (data == NULL) { gLog("[wave] unable to allocate memory\n"); return 0; } memset(data, 0, sizeof(float) * size); /// FIXME - is it useful? inHeader.samplerate = samplerate; inHeader.channels = 2; inHeader.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; // wave only isLogical = true; return 1; } /* -------------------------------------------------------------------------- */ int Wave::resample(int quality, int newRate) { float ratio = newRate / (float) inHeader.samplerate; int newSize = ceil(size * ratio); if (newSize % 2 != 0) // libsndfile goes crazy with odd size in case of saving newSize++; float *tmp = (float *) malloc(newSize * sizeof(float)); if (!tmp) { gLog("[wave] unable to allocate memory for resampling\n"); return -1; } SRC_DATA src_data; src_data.data_in = data; src_data.input_frames = size/2; // in frames, i.e. /2 (stereo) src_data.data_out = tmp; src_data.output_frames = newSize/2; // in frames, i.e. /2 (stereo) src_data.src_ratio = ratio; gLog("[wave] resampling: new size=%d (%d frames)\n", newSize, newSize/2); int ret = src_simple(&src_data, quality, 2); if (ret != 0) { gLog("[wave] resampling error: %s\n", src_strerror(ret)); return 0; } free(data); data = tmp; size = newSize; inHeader.samplerate = newRate; return 1; } /* -------------------------------------------------------------------------- */ std::string Wave::basename() const { return gStripExt(gBasename(pathfile.c_str()).c_str()); } std::string Wave::extension() const { return gGetExt(pathfile.c_str()); } /* -------------------------------------------------------------------------- */ void Wave::updateName(const char *n) { std::string ext = gGetExt(pathfile.c_str()); name = gStripExt(gBasename(n).c_str()); pathfile = gDirname(pathfile.c_str()) + gGetSlash() + name + "." + ext; isLogical = true; /* a wave with updated name must become logical, since the underlying * file does not exist yet. */ } giada-0.11.2/src/core/wave.h000066400000000000000000000046001264622563000155000ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * wave * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef WAVE_H #define WAVE_H #include #include #include class Wave { private: SNDFILE *fileIn; SNDFILE *fileOut; SF_INFO inHeader; SF_INFO outHeader; public: Wave(); ~Wave(); Wave(const Wave &other); std::string pathfile; // full path + sample name std::string name; // sample name (changeable) float *data; int size; // wave size (size in stereo: size / 2) bool isLogical; // memory only (a take) bool isEdited; // edited via editor inline int rate () { return inHeader.samplerate; } inline int channels() { return inHeader.channels; } inline int frames () { return inHeader.frames; } inline void rate (int v) { inHeader.samplerate = v; } inline void channels(int v) { inHeader.channels = v; } inline void frames (int v) { inHeader.frames = v; } std::string basename () const; std::string extension() const; void updateName(const char *n); int open (const char *f); int readData (); int writeData (const char *f); void clear (); /* allocEmpty * alloc an empty waveform. */ int allocEmpty(unsigned size, unsigned samplerate); /* resample * simple algorithm for one-shot resampling. */ int resample(int quality, int newRate); }; #endif giada-0.11.2/src/core/waveFx.cpp000066400000000000000000000113651264622563000163370ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * waveFx * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../utils/log.h" #include "waveFx.h" #include "channel.h" #include "mixer.h" #include "wave.h" extern Mixer G_Mixer; float wfx_normalizeSoft(Wave *w) { float peak = 0.0f; float abs = 0.0f; for (int i=0; isize; i++) { // i++: both L and R samples abs = fabs(w->data[i]); if (abs > peak) peak = abs; } /* peak == 0.0f: don't normalize the silence * peak > 1.0f: don't reduce the amplitude, just leave it alone */ if (peak == 0.0f || peak > 1.0f) return 1.0f; return 1.0f / peak; } /* ------------------------------------------------------------------ */ bool wfx_monoToStereo(Wave *w) { unsigned newSize = w->size * 2; float *dataNew = (float *) malloc(newSize * sizeof(float)); if (dataNew == NULL) { gLog("[wfx] unable to allocate memory for mono>stereo conversion\n"); return 0; } for (int i=0, j=0; isize; i++) { dataNew[j] = w->data[i]; dataNew[j+1] = w->data[i]; j+=2; } free(w->data); w->data = dataNew; w->size = newSize; w->frames(w->frames()*2); w->channels(2); return 1; } /* ------------------------------------------------------------------ */ void wfx_silence(Wave *w, int a, int b) { /* stereo values */ a = a * 2; b = b * 2; gLog("[wfx] silencing from %d to %d\n", a, b); for (int i=a; idata[i] = 0.0f; w->data[i+1] = 0.0f; } w->isEdited = true; return; } /* ------------------------------------------------------------------ */ int wfx_cut(Wave *w, int a, int b) { a = a * 2; b = b * 2; if (a < 0) a = 0; if (b > w->size) b = w->size; /* create a new temp wave and copy there the original one, skipping * the a-b range */ unsigned newSize = w->size-(b-a); float *temp = (float *) malloc(newSize * sizeof(float)); if (temp == NULL) { gLog("[wfx] unable to allocate memory for cutting\n"); return 0; } gLog("[wfx] cutting from %d to %d, new size=%d (video=%d)\n", a, b, newSize, newSize/2); for (int i=0, k=0; isize; i++) { if (i < a || i >= b) { // left margin always included, in order to keep temp[k] = w->data[i]; // the stereo pair k++; } } free(w->data); w->data = temp; w->size = newSize; //w->inHeader.frames -= b-a; w->frames(w->frames() - b - a); w->isEdited = true; gLog("[wfx] cutting done\n"); return 1; } /* ------------------------------------------------------------------ */ int wfx_trim(Wave *w, int a, int b) { a = a * 2; b = b * 2; if (a < 0) a = 0; if (b > w->size) b = w->size; int newSize = b - a; float *temp = (float *) malloc(newSize * sizeof(float)); if (temp == NULL) { gLog("[wfx] unable to allocate memory for trimming\n"); return 0; } gLog("[wfx] trimming from %d to %d (area = %d)\n", a, b, b-a); for (int i=a, k=0; idata[i]; free(w->data); w->data = temp; w->size = newSize; //w->inHeader.frames = b-a; w->frames(b - a); w->isEdited = true; return 1; } /* ------------------------------------------------------------------ */ void wfx_fade(Wave *w, int a, int b, int type) { float m = type == 0 ? 0.0f : 1.0f; float d = 1.0f/(float)(b-a); if (type == 1) d = -d; a *= 2; b *= 2; for (int i=a; idata[i] *= m; w->data[i+1] *= m; m += d; } } /* ------------------------------------------------------------------ */ void wfx_smooth(Wave *w, int a, int b) { int d = 32; // 64 if stereo data /* do nothing if fade edges (both of 32 samples) are > than selected * portion of wave. d*2 => count both edges, (b-a)*2 => stereo * values. */ if (d*2 > (b-a)*2) { gLog("[WFX] selection is too small, nothing to do\n"); return; } wfx_fade(w, a, a+d, 0); wfx_fade(w, b-d, b, 1); } giada-0.11.2/src/core/waveFx.h000066400000000000000000000033101264622563000157730ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * waveFx * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef WAVEFX_H #define WAVEFX_H /* normalizeSoft * normalize the wave by returning the dB value for the boost volume. It * doesn't deal with data in memory. */ float wfx_normalizeSoft(class Wave *w); bool wfx_monoToStereo(class Wave *w); void wfx_silence(class Wave *w, int a, int b); int wfx_cut(class Wave *w, int a, int b); int wfx_trim(class Wave *w, int a, int b); /* fade * fade in or fade out selection. Fade In = type 0, Fade Out = type 1 */ void wfx_fade(class Wave *w, int a, int b, int type); /* smooth * smooth edges of selection. */ void wfx_smooth(class Wave *w, int a, int b); #endif giada-0.11.2/src/deps/000077500000000000000000000000001264622563000143705ustar00rootroot00000000000000giada-0.11.2/src/deps/rtaudio-mod/000077500000000000000000000000001264622563000166145ustar00rootroot00000000000000giada-0.11.2/src/deps/rtaudio-mod/Makefile.in000066400000000000000000000034071264622563000206650ustar00rootroot00000000000000### Do not edit -- Generated by 'configure --with-whatever' from Makefile.in ### RtAudio library Makefile RM = /bin/rm LN = /bin/ln OBJECTS = RtAudio.o @objects@ LIBNAME = librtaudio STATIC = $(LIBNAME).a SHARED = @sharedlib@ RELEASE = 4.1.1 MAJOR = 4 LIBRARIES = $(STATIC) $(SHARED) CC = @CXX@ AR = @AR@ RANLIB = @RANLIB@ DEFS = @CPPFLAGS@ CFLAGS = @CXXFLAGS@ -Iinclude -fPIC PREFIX = @prefix@ all : $(LIBRARIES) tests: cd tests && $(MAKE) all $(LIBRARIES): $(OBJECTS) $(AR) ruv $(STATIC) $(OBJECTS) ranlib $(STATIC) $(CC) -fPIC @libflags@ $(OBJECTS) @LIBS@ $(LN) -sf @sharedname@ $(SHARED) $(LN) -sf @sharedname@ $(SHARED).$(MAJOR) %.o : %.cpp $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@ %.o : include/%.cpp $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $@ install: install --mode=755 $(STATIC) $(PREFIX)/lib/ install --mode=755 @sharedname@ $(PREFIX)/lib/ $(LN) -sf @sharedname@ $(PREFIX)/lib/$(SHARED) $(LN) -sf @sharedname@ $(PREFIX)/lib/$(SHARED).$(MAJOR) install --mode=644 $(LIBNAME).pc $(PREFIX)/lib/pkgconfig install --mode=644 RtAudio.h $(PREFIX)/include/ install --mode=755 rtaudio-config $(PREFIX)/bin/ uninstall: -@rm -vf $(patsubst %,$(PREFIX)/lib/%, $(LIBRARIES) $(SHARED).$(MAJOR) $(SHARED).$(RELEASE)) -@rm -vf $(PREFIX)/lib/pkgconfig/$(LIBNAME).pc -@rm -vf $(PREFIX)/bin/rtaudio-config clean : $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)* $(RM) -f $(OBJECTS) $(RM) -f *~ cd tests && $(MAKE) clean distclean: $(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)* $(RM) -f $(OBJECTS) $(RM) -f *~ $(RM) -rf config.log config.status autom4te.cache Makefile rtaudio-config $(LIBNAME).pc cd tests && $(MAKE) distclean strip : strip $(LIBRARIES) ranlib $(LIBRARIES) cd tests && $(MAKE) strip .PHONY: clean distclean strip install uninstall giada-0.11.2/src/deps/rtaudio-mod/RtAudio.cpp000066400000000000000000013117461264622563000207040ustar00rootroot00000000000000/************************************************************************/ /*! \class RtAudio \brief Realtime audio i/o C++ classes. RtAudio provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, Jack, and OSS), Macintosh OS X (CoreAudio and Jack), and Windows (DirectSound, ASIO and WASAPI) operating systems. RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/ RtAudio: realtime audio i/o C++ classes Copyright (c) 2001-2014 Gary P. Scavone Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is asked to send the modifications to the original developer so that they can be incorporated into the canonical version. This is, however, not a binding provision of this license. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /************************************************************************/ // RtAudio: Version 4.1.1 #include "RtAudio.h" #include #include #include #include // Static variable definitions. const unsigned int RtApi::MAX_SAMPLE_RATES = 14; const unsigned int RtApi::SAMPLE_RATES[] = { 4000, 5512, 8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000 }; #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__) #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A) #define MUTEX_DESTROY(A) DeleteCriticalSection(A) #define MUTEX_LOCK(A) EnterCriticalSection(A) #define MUTEX_UNLOCK(A) LeaveCriticalSection(A) #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) // pthread API #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) #define MUTEX_DESTROY(A) pthread_mutex_destroy(A) #define MUTEX_LOCK(A) pthread_mutex_lock(A) #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A) #else #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions #define MUTEX_DESTROY(A) abs(*A) // dummy definitions #endif // *************************************************** // // // RtAudio definitions. // // *************************************************** // std::string RtAudio :: getVersion( void ) throw() { return RTAUDIO_VERSION; } void RtAudio :: getCompiledApi( std::vector &apis ) throw() { apis.clear(); // The order here will control the order of RtAudio's API search in // the constructor. #if defined(__UNIX_JACK__) apis.push_back( UNIX_JACK ); #endif #if defined(__LINUX_ALSA__) apis.push_back( LINUX_ALSA ); #endif #if defined(__LINUX_PULSE__) apis.push_back( LINUX_PULSE ); #endif #if defined(__LINUX_OSS__) apis.push_back( LINUX_OSS ); #endif #if defined(__WINDOWS_ASIO__) apis.push_back( WINDOWS_ASIO ); #endif #if defined(__WINDOWS_WASAPI__) apis.push_back( WINDOWS_WASAPI ); #endif #if defined(__WINDOWS_DS__) apis.push_back( WINDOWS_DS ); #endif #if defined(__MACOSX_CORE__) apis.push_back( MACOSX_CORE ); #endif #if defined(__RTAUDIO_DUMMY__) apis.push_back( RTAUDIO_DUMMY ); #endif } void RtAudio :: openRtApi( RtAudio::Api api ) { if ( rtapi_ ) delete rtapi_; rtapi_ = 0; #if defined(__UNIX_JACK__) if ( api == UNIX_JACK ) rtapi_ = new RtApiJack(); #endif #if defined(__LINUX_ALSA__) if ( api == LINUX_ALSA ) rtapi_ = new RtApiAlsa(); #endif #if defined(__LINUX_PULSE__) if ( api == LINUX_PULSE ) rtapi_ = new RtApiPulse(); #endif #if defined(__LINUX_OSS__) if ( api == LINUX_OSS ) rtapi_ = new RtApiOss(); #endif #if defined(__WINDOWS_ASIO__) if ( api == WINDOWS_ASIO ) rtapi_ = new RtApiAsio(); #endif #if defined(__WINDOWS_WASAPI__) if ( api == WINDOWS_WASAPI ) rtapi_ = new RtApiWasapi(); #endif #if defined(__WINDOWS_DS__) if ( api == WINDOWS_DS ) rtapi_ = new RtApiDs(); #endif #if defined(__MACOSX_CORE__) if ( api == MACOSX_CORE ) rtapi_ = new RtApiCore(); #endif #if defined(__RTAUDIO_DUMMY__) if ( api == RTAUDIO_DUMMY ) rtapi_ = new RtApiDummy(); #endif } RtAudio :: RtAudio( RtAudio::Api api ) { rtapi_ = 0; if ( api != UNSPECIFIED ) { // Attempt to open the specified API. openRtApi( api ); if ( rtapi_ ) return; // No compiled support for specified API value. Issue a debug // warning and continue as if no API was specified. std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl; } // Iterate through the compiled APIs and return as soon as we find // one with at least one device or we reach the end of the list. std::vector< RtAudio::Api > apis; getCompiledApi( apis ); for ( unsigned int i=0; igetDeviceCount() ) break; } if ( rtapi_ ) return; // It should not be possible to get here because the preprocessor // definition __RTAUDIO_DUMMY__ is automatically defined if no // API-specific definitions are passed to the compiler. But just in // case something weird happens, we'll thow an error. std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n"; throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) ); } RtAudio :: ~RtAudio() throw() { if ( rtapi_ ) delete rtapi_; } void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options, RtAudioErrorCallback errorCallback ) { return rtapi_->openStream( outputParameters, inputParameters, format, sampleRate, bufferFrames, callback, userData, options, errorCallback ); } // *************************************************** // // // Public RtApi definitions (see end of file for // private or protected utility functions). // // *************************************************** // RtApi :: RtApi() { stream_.state = STREAM_CLOSED; stream_.mode = UNINITIALIZED; stream_.apiHandle = 0; stream_.userBuffer[0] = 0; stream_.userBuffer[1] = 0; MUTEX_INITIALIZE( &stream_.mutex ); showWarnings_ = true; firstErrorOccurred_ = false; } RtApi :: ~RtApi() { MUTEX_DESTROY( &stream_.mutex ); } void RtApi :: openStream( RtAudio::StreamParameters *oParams, RtAudio::StreamParameters *iParams, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options, RtAudioErrorCallback errorCallback ) { if ( stream_.state != STREAM_CLOSED ) { errorText_ = "RtApi::openStream: a stream is already open!"; error( RtAudioError::INVALID_USE ); return; } // Clear stream information potentially left from a previously open stream. clearStreamInfo(); if ( oParams && oParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one."; error( RtAudioError::INVALID_USE ); return; } if ( iParams && iParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one."; error( RtAudioError::INVALID_USE ); return; } if ( oParams == NULL && iParams == NULL ) { errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!"; error( RtAudioError::INVALID_USE ); return; } if ( formatBytes(format) == 0 ) { errorText_ = "RtApi::openStream: 'format' parameter value is undefined."; error( RtAudioError::INVALID_USE ); return; } unsigned int nDevices = getDeviceCount(); unsigned int oChannels = 0; if ( oParams ) { oChannels = oParams->nChannels; if ( oParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: output device parameter value is invalid."; error( RtAudioError::INVALID_USE ); return; } } unsigned int iChannels = 0; if ( iParams ) { iChannels = iParams->nChannels; if ( iParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: input device parameter value is invalid."; error( RtAudioError::INVALID_USE ); return; } } bool result; if ( oChannels > 0 ) { result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel, sampleRate, format, bufferFrames, options ); if ( result == false ) { error( RtAudioError::SYSTEM_ERROR ); return; } } if ( iChannels > 0 ) { result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel, sampleRate, format, bufferFrames, options ); if ( result == false ) { if ( oChannels > 0 ) closeStream(); error( RtAudioError::SYSTEM_ERROR ); return; } } stream_.callbackInfo.callback = (void *) callback; stream_.callbackInfo.userData = userData; stream_.callbackInfo.errorCallback = (void *) errorCallback; if ( options ) options->numberOfBuffers = stream_.nBuffers; stream_.state = STREAM_STOPPED; } unsigned int RtApi :: getDefaultInputDevice( void ) { // Should be implemented in subclasses if possible. return 0; } unsigned int RtApi :: getDefaultOutputDevice( void ) { // Should be implemented in subclasses if possible. return 0; } void RtApi :: closeStream( void ) { // MUST be implemented in subclasses! return; } bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, unsigned int /*firstChannel*/, unsigned int /*sampleRate*/, RtAudioFormat /*format*/, unsigned int * /*bufferSize*/, RtAudio::StreamOptions * /*options*/ ) { // MUST be implemented in subclasses! return FAILURE; } void RtApi :: tickStreamTime( void ) { // Subclasses that do not provide their own implementation of // getStreamTime should call this function once per buffer I/O to // provide basic stream time support. stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate ); #if defined( HAVE_GETTIMEOFDAY ) gettimeofday( &stream_.lastTickTimestamp, NULL ); #endif } long RtApi :: getStreamLatency( void ) { verifyStream(); long totalLatency = 0; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) totalLatency = stream_.latency[0]; if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) totalLatency += stream_.latency[1]; return totalLatency; } double RtApi :: getStreamTime( void ) { verifyStream(); #if defined( HAVE_GETTIMEOFDAY ) // Return a very accurate estimate of the stream time by // adding in the elapsed time since the last tick. struct timeval then; struct timeval now; if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 ) return stream_.streamTime; gettimeofday( &now, NULL ); then = stream_.lastTickTimestamp; return stream_.streamTime + ((now.tv_sec + 0.000001 * now.tv_usec) - (then.tv_sec + 0.000001 * then.tv_usec)); #else return stream_.streamTime; #endif } void RtApi :: setStreamTime( double time ) { verifyStream(); if ( time >= 0.0 ) stream_.streamTime = time; } unsigned int RtApi :: getStreamSampleRate( void ) { verifyStream(); return stream_.sampleRate; } // *************************************************** // // // OS/API-specific methods. // // *************************************************** // #if defined(__MACOSX_CORE__) // The OS X CoreAudio API is designed to use a separate callback // procedure for each of its audio devices. A single RtAudio duplex // stream using two different devices is supported here, though it // cannot be guaranteed to always behave correctly because we cannot // synchronize these two callbacks. // // A property listener is installed for over/underrun information. // However, no functionality is currently provided to allow property // listeners to trigger user handlers because it is unclear what could // be done if a critical stream parameter (buffer size, sample rate, // device disconnect) notification arrived. The listeners entail // quite a bit of extra code and most likely, a user program wouldn't // be prepared for the result anyway. However, we do provide a flag // to the client callback function to inform of an over/underrun. // A structure to hold various information related to the CoreAudio API // implementation. struct CoreHandle { AudioDeviceID id[2]; // device ids #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) AudioDeviceIOProcID procId[2]; #endif UInt32 iStream[2]; // device stream index (or first if using multiple) UInt32 nStreams[2]; // number of streams to use bool xrun[2]; char *deviceBuffer; pthread_cond_t condition; int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. CoreHandle() :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; } }; RtApiCore:: RtApiCore() { #if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER ) // This is a largely undocumented but absolutely necessary // requirement starting with OS-X 10.6. If not called, queries and // updates to various audio device properties are not handled // correctly. CFRunLoopRef theRunLoop = NULL; AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); if ( result != noErr ) { errorText_ = "RtApiCore::RtApiCore: error setting run loop property!"; error( RtAudioError::WARNING ); } #endif } RtApiCore :: ~RtApiCore() { // The subclass destructor gets called before the base class // destructor, so close an existing stream before deallocating // apiDeviceId memory. if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiCore :: getDeviceCount( void ) { // Find out how many audio devices there are, if any. UInt32 dataSize; AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize ); if ( result != noErr ) { errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!"; error( RtAudioError::WARNING ); return 0; } return dataSize / sizeof( AudioDeviceID ); } unsigned int RtApiCore :: getDefaultInputDevice( void ) { unsigned int nDevices = getDeviceCount(); if ( nDevices <= 1 ) return 0; AudioDeviceID id; UInt32 dataSize = sizeof( AudioDeviceID ); AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id ); if ( result != noErr ) { errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device."; error( RtAudioError::WARNING ); return 0; } dataSize *= nDevices; AudioDeviceID deviceList[ nDevices ]; property.mSelector = kAudioHardwarePropertyDevices; result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList ); if ( result != noErr ) { errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs."; error( RtAudioError::WARNING ); return 0; } for ( unsigned int i=0; i= nDevices ) { errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!"; error( RtAudioError::INVALID_USE ); return info; } AudioDeviceID deviceList[ nDevices ]; UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList ); if ( result != noErr ) { errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs."; error( RtAudioError::WARNING ); return info; } AudioDeviceID id = deviceList[ device ]; // Get the device name. info.name.erase(); CFStringRef cfname; dataSize = sizeof( CFStringRef ); property.mSelector = kAudioObjectPropertyManufacturer; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() ); int length = CFStringGetLength(cfname); char *mname = (char *)malloc(length * 3 + 1); #if defined( UNICODE ) || defined( _UNICODE ) CFStringGetCString(cfname, mname, length * 3 + 1, kCFStringEncodingUTF8); #else CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding()); #endif info.name.append( (const char *)mname, strlen(mname) ); info.name.append( ": " ); CFRelease( cfname ); free(mname); property.mSelector = kAudioObjectPropertyName; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() ); length = CFStringGetLength(cfname); char *name = (char *)malloc(length * 3 + 1); #if defined( UNICODE ) || defined( _UNICODE ) CFStringGetCString(cfname, name, length * 3 + 1, kCFStringEncodingUTF8); #else CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding()); #endif info.name.append( (const char *)name, strlen(name) ); CFRelease( cfname ); free(name); // Get the output stream "configuration". AudioBufferList *bufferList = nil; property.mSelector = kAudioDevicePropertyStreamConfiguration; property.mScope = kAudioDevicePropertyScopeOutput; // property.mElement = kAudioObjectPropertyElementWildcard; dataSize = 0; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != noErr || dataSize == 0 ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc( dataSize ); if ( bufferList == NULL ) { errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList."; error( RtAudioError::WARNING ); return info; } result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList ); if ( result != noErr || dataSize == 0 ) { free( bufferList ); errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Get output channel information. unsigned int i, nStreams = bufferList->mNumberBuffers; for ( i=0; imBuffers[i].mNumberChannels; free( bufferList ); // Get the input stream "configuration". property.mScope = kAudioDevicePropertyScopeInput; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != noErr || dataSize == 0 ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc( dataSize ); if ( bufferList == NULL ) { errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList."; error( RtAudioError::WARNING ); return info; } result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList ); if (result != noErr || dataSize == 0) { free( bufferList ); errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Get input channel information. nStreams = bufferList->mNumberBuffers; for ( i=0; imBuffers[i].mNumberChannels; free( bufferList ); // If device opens for both playback and capture, we determine the channels. if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // Probe the device sample rates. bool isInput = false; if ( info.outputChannels == 0 ) isInput = true; // Determine the supported sample rates. property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != kAudioHardwareNoError || dataSize == 0 ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } UInt32 nRanges = dataSize / sizeof( AudioValueRange ); AudioValueRange rangeList[ nRanges ]; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList ); if ( result != kAudioHardwareNoError ) { errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // The sample rate reporting mechanism is a bit of a mystery. It // seems that it can either return individual rates or a range of // rates. I assume that if the min / max range values are the same, // then that represents a single supported rate and if the min / max // range values are different, the device supports an arbitrary // range of values (though there might be multiple ranges, so we'll // use the most conservative range). Float64 minimumRate = 1.0, maximumRate = 10000000000.0; bool haveValueRange = false; info.sampleRates.clear(); for ( UInt32 i=0; i minimumRate ) minimumRate = rangeList[i].mMinimum; if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum; } } if ( haveValueRange ) { for ( unsigned int k=0; k= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) info.sampleRates.push_back( SAMPLE_RATES[k] ); } } // Sort and remove any redundant values std::sort( info.sampleRates.begin(), info.sampleRates.end() ); info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() ); if ( info.sampleRates.size() == 0 ) { errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // CoreAudio always uses 32-bit floating point data for PCM streams. // Thus, any other "physical" formats supported by the device are of // no interest to the client. info.nativeFormats = RTAUDIO_FLOAT32; if ( info.outputChannels > 0 ) if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true; if ( info.inputChannels > 0 ) if ( getDefaultInputDevice() == device ) info.isDefaultInput = true; info.probed = true; return info; } static OSStatus callbackHandler( AudioDeviceID inDevice, const AudioTimeStamp* /*inNow*/, const AudioBufferList* inInputData, const AudioTimeStamp* /*inInputTime*/, AudioBufferList* outOutputData, const AudioTimeStamp* /*inOutputTime*/, void* infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiCore *object = (RtApiCore *) info->object; if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false ) return kAudioHardwareUnspecifiedError; else return kAudioHardwareNoError; } static OSStatus xrunListener( AudioObjectID /*inDevice*/, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void* handlePointer ) { CoreHandle *handle = (CoreHandle *) handlePointer; for ( UInt32 i=0; ixrun[1] = true; else handle->xrun[0] = true; } } return kAudioHardwareNoError; } static OSStatus rateListener( AudioObjectID inDevice, UInt32 /*nAddresses*/, const AudioObjectPropertyAddress /*properties*/[], void* ratePointer ) { Float64 *rate = (Float64 *) ratePointer; UInt32 dataSize = sizeof( Float64 ); AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate ); return kAudioHardwareNoError; } bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) { // Get device ID unsigned int nDevices = getDeviceCount(); if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiCore::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!"; return FAILURE; } AudioDeviceID deviceList[ nDevices ]; UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList ); if ( result != noErr ) { errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs."; return FAILURE; } AudioDeviceID id = deviceList[ device ]; // Setup for stream mode. bool isInput = false; if ( mode == INPUT ) { isInput = true; property.mScope = kAudioDevicePropertyScopeInput; } else property.mScope = kAudioDevicePropertyScopeOutput; // Get the stream "configuration". AudioBufferList *bufferList = nil; dataSize = 0; property.mSelector = kAudioDevicePropertyStreamConfiguration; result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize ); if ( result != noErr || dataSize == 0 ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc( dataSize ); if ( bufferList == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList."; return FAILURE; } result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList ); if (result != noErr || dataSize == 0) { free( bufferList ); errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Search for one or more streams that contain the desired number of // channels. CoreAudio devices can have an arbitrary number of // streams and each stream can have an arbitrary number of channels. // For each stream, a single buffer of interleaved samples is // provided. RtAudio prefers the use of one stream of interleaved // data or multiple consecutive single-channel streams. However, we // now support multiple consecutive multi-channel streams of // interleaved data as well. UInt32 iStream, offsetCounter = firstChannel; UInt32 nStreams = bufferList->mNumberBuffers; bool monoMode = false; bool foundStream = false; // First check that the device supports the requested number of // channels. UInt32 deviceChannels = 0; for ( iStream=0; iStreammBuffers[iStream].mNumberChannels; if ( deviceChannels < ( channels + firstChannel ) ) { free( bufferList ); errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count."; errorText_ = errorStream_.str(); return FAILURE; } // Look for a single stream meeting our needs. UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0; for ( iStream=0; iStreammBuffers[iStream].mNumberChannels; if ( streamChannels >= channels + offsetCounter ) { firstStream = iStream; channelOffset = offsetCounter; foundStream = true; break; } if ( streamChannels > offsetCounter ) break; offsetCounter -= streamChannels; } // If we didn't find a single stream above, then we should be able // to meet the channel specification with multiple streams. if ( foundStream == false ) { monoMode = true; offsetCounter = firstChannel; for ( iStream=0; iStreammBuffers[iStream].mNumberChannels; if ( streamChannels > offsetCounter ) break; offsetCounter -= streamChannels; } firstStream = iStream; channelOffset = offsetCounter; Int32 channelCounter = channels + offsetCounter - streamChannels; if ( streamChannels > 1 ) monoMode = false; while ( channelCounter > 0 ) { streamChannels = bufferList->mBuffers[++iStream].mNumberChannels; if ( streamChannels > 1 ) monoMode = false; channelCounter -= streamChannels; streamCount++; } } free( bufferList ); // Determine the buffer size. AudioValueRange bufferRange; dataSize = sizeof( AudioValueRange ); property.mSelector = kAudioDevicePropertyBufferFrameSizeRange; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum; else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum; // Set the buffer size. For multiple streams, I'm assuming we only // need to make this setting for the master channel. UInt32 theSize = (UInt32) *bufferSize; dataSize = sizeof( UInt32 ); property.mSelector = kAudioDevicePropertyBufferFrameSize; result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // If attempting to setup a duplex stream, the bufferSize parameter // MUST be the same in both directions! *bufferSize = theSize; if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.bufferSize = *bufferSize; stream_.nBuffers = 1; // Try to set "hog" mode ... it's not clear to me this is working. if ( options && options->flags & RTAUDIO_HOG_DEVICE ) { pid_t hog_pid; dataSize = sizeof( hog_pid ); property.mSelector = kAudioDevicePropertyHogMode; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!"; errorText_ = errorStream_.str(); return FAILURE; } if ( hog_pid != getpid() ) { hog_pid = getpid(); result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!"; errorText_ = errorStream_.str(); return FAILURE; } } } // Check and if necessary, change the sample rate for the device. Float64 nominalRate; dataSize = sizeof( Float64 ); property.mSelector = kAudioDevicePropertyNominalSampleRate; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate."; errorText_ = errorStream_.str(); return FAILURE; } // Only change the sample rate if off by more than 1 Hz. if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) { // Set a property listener for the sample rate change Float64 reportedRate = 0.0; AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } nominalRate = (Float64) sampleRate; result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate ); if ( result != noErr ) { AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate ); errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Now wait until the reported nominal rate is what we just set. UInt32 microCounter = 0; while ( reportedRate != nominalRate ) { microCounter += 5000; if ( microCounter > 5000000 ) break; usleep( 5000 ); } // Remove the property listener. AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate ); if ( microCounter > 5000000 ) { errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Now set the stream format for all streams. Also, check the // physical format of the device and change that if necessary. AudioStreamBasicDescription description; dataSize = sizeof( AudioStreamBasicDescription ); property.mSelector = kAudioStreamPropertyVirtualFormat; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Set the sample rate and data format id. However, only make the // change if the sample rate is not within 1.0 of the desired // rate and the format is not linear pcm. bool updateFormat = false; if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) { description.mSampleRate = (Float64) sampleRate; updateFormat = true; } if ( description.mFormatID != kAudioFormatLinearPCM ) { description.mFormatID = kAudioFormatLinearPCM; updateFormat = true; } if ( updateFormat ) { result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Now check the physical format. property.mSelector = kAudioStreamPropertyPhysicalFormat; result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description ); if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ")."; errorText_ = errorStream_.str(); return FAILURE; } //std::cout << "Current physical stream format:" << std::endl; //std::cout << " mBitsPerChan = " << description.mBitsPerChannel << std::endl; //std::cout << " aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl; //std::cout << " bytesPerFrame = " << description.mBytesPerFrame << std::endl; //std::cout << " sample rate = " << description.mSampleRate << std::endl; if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) { description.mFormatID = kAudioFormatLinearPCM; //description.mSampleRate = (Float64) sampleRate; AudioStreamBasicDescription testDescription = description; UInt32 formatFlags; // We'll try higher bit rates first and then work our way down. std::vector< std::pair > physicalFormats; formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger; physicalFormats.push_back( std::pair( 32, formatFlags ) ); formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back( std::pair( 32, formatFlags ) ); physicalFormats.push_back( std::pair( 24, formatFlags ) ); // 24-bit packed formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh ); physicalFormats.push_back( std::pair( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low formatFlags |= kAudioFormatFlagIsAlignedHigh; physicalFormats.push_back( std::pair( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back( std::pair( 16, formatFlags ) ); physicalFormats.push_back( std::pair( 8, formatFlags ) ); bool setPhysicalFormat = false; for( unsigned int i=0; iflags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; stream_.deviceInterleaved[mode] = true; if ( monoMode == true ) stream_.deviceInterleaved[mode] = false; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; if ( streamCount == 1 ) { if ( stream_.nUserChannels[mode] > 1 && stream_.userInterleaved != stream_.deviceInterleaved[mode] ) stream_.doConvertBuffer[mode] = true; } else if ( monoMode && stream_.userInterleaved ) stream_.doConvertBuffer[mode] = true; // Allocate our CoreHandle structure for the stream. CoreHandle *handle = 0; if ( stream_.apiHandle == 0 ) { try { handle = new CoreHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory."; goto error; } if ( pthread_cond_init( &handle->condition, NULL ) ) { errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) handle; } else handle = (CoreHandle *) stream_.apiHandle; handle->iStream[mode] = firstStream; handle->nStreams[mode] = streamCount; handle->id[mode] = id; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); // stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) ); memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory."; goto error; } // If possible, we will make use of the CoreAudio stream buffers as // "device buffers". However, we can't do this if using multiple // streams. if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.sampleRate = sampleRate; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; stream_.callbackInfo.object = (void *) this; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) { if ( streamCount > 1 ) setConvertInfo( mode, 0 ); else setConvertInfo( mode, channelOffset ); } if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device ) // Only one callback procedure per device. stream_.mode = DUPLEX; else { #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] ); #else // deprecated in favor of AudioDeviceCreateIOProcID() result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo ); #endif if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ")."; errorText_ = errorStream_.str(); goto error; } if ( stream_.mode == OUTPUT && mode == INPUT ) stream_.mode = DUPLEX; else stream_.mode = mode; } // Setup the device property listener for over/underload. property.mSelector = kAudioDeviceProcessorOverload; property.mScope = kAudioObjectPropertyScopeGlobal; result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle ); return SUCCESS; error: if ( handle ) { pthread_cond_destroy( &handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.state = STREAM_CLOSED; return FAILURE; } void RtApiCore :: closeStream( void ) { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiCore::closeStream(): no open stream to close!"; error( RtAudioError::WARNING ); return; } CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[0], callbackHandler ); #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] ); #else // deprecated in favor of AudioDeviceDestroyIOProcID() AudioDeviceRemoveIOProc( handle->id[0], callbackHandler ); #endif } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[1], callbackHandler ); #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] ); #else // deprecated in favor of AudioDeviceDestroyIOProcID() AudioDeviceRemoveIOProc( handle->id[1], callbackHandler ); #endif } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } // Destroy pthread condition variable. pthread_cond_destroy( &handle->condition ); delete handle; stream_.apiHandle = 0; stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiCore :: startStream( void ) { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiCore::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } OSStatus result = noErr; CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = AudioDeviceStart( handle->id[0], callbackHandler ); if ( result != noErr ) { errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { result = AudioDeviceStart( handle->id[1], callbackHandler ); if ( result != noErr ) { errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ")."; errorText_ = errorStream_.str(); goto unlock; } } handle->drainCounter = 0; handle->internalDrain = false; stream_.state = STREAM_RUNNING; unlock: if ( result == noErr ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiCore :: stopStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiCore::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } OSStatus result = noErr; CoreHandle *handle = (CoreHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled } result = AudioDeviceStop( handle->id[0], callbackHandler ); if ( result != noErr ) { errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { result = AudioDeviceStop( handle->id[1], callbackHandler ); if ( result != noErr ) { errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ")."; errorText_ = errorStream_.str(); goto unlock; } } stream_.state = STREAM_STOPPED; unlock: if ( result == noErr ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiCore :: abortStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiCore::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } CoreHandle *handle = (CoreHandle *) stream_.apiHandle; handle->drainCounter = 2; stopStream(); } // This function will be called by a spawned thread when the user // callback function signals that the stream should be stopped or // aborted. It is better to handle it this way because the // callbackEvent() function probably should return before the AudioDeviceStop() // function is called. static void *coreStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiCore *object = (RtApiCore *) info->object; object->stopStream(); pthread_exit( NULL ); } bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, const AudioBufferList *inBufferList, const AudioBufferList *outBufferList ) { if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS; if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtAudioError::WARNING ); return FAILURE; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; CoreHandle *handle = (CoreHandle *) stream_.apiHandle; // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > 3 ) { ThreadHandle threadId; stream_.state = STREAM_STOPPING; if ( handle->internalDrain == true ) pthread_create( &threadId, NULL, coreStopStream, info ); else // external call to stopStream() pthread_cond_signal( &handle->condition ); return SUCCESS; } AudioDeviceID outputDevice = handle->id[0]; // Invoke user callback to get fresh output data UNLESS we are // draining stream or duplex mode AND the input/output devices are // different AND this function is called for the input device. if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( cbReturnValue == 2 ) { stream_.state = STREAM_STOPPING; handle->drainCounter = 2; abortStream(); return SUCCESS; } else if ( cbReturnValue == 1 ) { handle->drainCounter = 1; handle->internalDrain = true; } } if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) { if ( handle->drainCounter > 1 ) { // write zeros to the output stream if ( handle->nStreams[0] == 1 ) { memset( outBufferList->mBuffers[handle->iStream[0]].mData, 0, outBufferList->mBuffers[handle->iStream[0]].mDataByteSize ); } else { // fill multiple streams with zeros for ( unsigned int i=0; inStreams[0]; i++ ) { memset( outBufferList->mBuffers[handle->iStream[0]+i].mData, 0, outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize ); } } } else if ( handle->nStreams[0] == 1 ) { if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData, stream_.userBuffer[0], stream_.convertInfo[0] ); } else { // copy from user buffer memcpy( outBufferList->mBuffers[handle->iStream[0]].mData, stream_.userBuffer[0], outBufferList->mBuffers[handle->iStream[0]].mDataByteSize ); } } else { // fill multiple streams Float32 *inBuffer = (Float32 *) stream_.userBuffer[0]; if ( stream_.doConvertBuffer[0] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); inBuffer = (Float32 *) stream_.deviceBuffer; } if ( stream_.deviceInterleaved[0] == false ) { // mono mode UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize; for ( unsigned int i=0; imBuffers[handle->iStream[0]+i].mData, (void *)&inBuffer[i*stream_.bufferSize], bufferBytes ); } } else { // fill multiple multi-channel streams with interleaved data UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset; Float32 *out, *in; bool inInterleaved = ( stream_.userInterleaved ) ? true : false; UInt32 inChannels = stream_.nUserChannels[0]; if ( stream_.doConvertBuffer[0] ) { inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode inChannels = stream_.nDeviceChannels[0]; } if ( inInterleaved ) inOffset = 1; else inOffset = stream_.bufferSize; channelsLeft = inChannels; for ( unsigned int i=0; inStreams[0]; i++ ) { in = inBuffer; out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData; streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels; outJump = 0; // Account for possible channel offset in first stream if ( i == 0 && stream_.channelOffset[0] > 0 ) { streamChannels -= stream_.channelOffset[0]; outJump = stream_.channelOffset[0]; out += outJump; } // Account for possible unfilled channels at end of the last stream if ( streamChannels > channelsLeft ) { outJump = streamChannels - channelsLeft; streamChannels = channelsLeft; } // Determine input buffer offsets and skips if ( inInterleaved ) { inJump = inChannels; in += inChannels - channelsLeft; } else { inJump = 1; in += (inChannels - channelsLeft) * inOffset; } for ( unsigned int i=0; idrainCounter ) { handle->drainCounter++; goto unlock; } AudioDeviceID inputDevice; inputDevice = handle->id[1]; if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) { if ( handle->nStreams[1] == 1 ) { if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer convertBuffer( stream_.userBuffer[1], (char *) inBufferList->mBuffers[handle->iStream[1]].mData, stream_.convertInfo[1] ); } else { // copy to user buffer memcpy( stream_.userBuffer[1], inBufferList->mBuffers[handle->iStream[1]].mData, inBufferList->mBuffers[handle->iStream[1]].mDataByteSize ); } } else { // read from multiple streams Float32 *outBuffer = (Float32 *) stream_.userBuffer[1]; if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer; if ( stream_.deviceInterleaved[1] == false ) { // mono mode UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize; for ( unsigned int i=0; imBuffers[handle->iStream[1]+i].mData, bufferBytes ); } } else { // read from multiple multi-channel streams UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset; Float32 *out, *in; bool outInterleaved = ( stream_.userInterleaved ) ? true : false; UInt32 outChannels = stream_.nUserChannels[1]; if ( stream_.doConvertBuffer[1] ) { outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode outChannels = stream_.nDeviceChannels[1]; } if ( outInterleaved ) outOffset = 1; else outOffset = stream_.bufferSize; channelsLeft = outChannels; for ( unsigned int i=0; inStreams[1]; i++ ) { out = outBuffer; in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData; streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels; inJump = 0; // Account for possible channel offset in first stream if ( i == 0 && stream_.channelOffset[1] > 0 ) { streamChannels -= stream_.channelOffset[1]; inJump = stream_.channelOffset[1]; in += inJump; } // Account for possible unread channels at end of the last stream if ( streamChannels > channelsLeft ) { inJump = streamChannels - channelsLeft; streamChannels = channelsLeft; } // Determine output buffer offsets and skips if ( outInterleaved ) { outJump = outChannels; out += outChannels - channelsLeft; } else { outJump = 1; out += (outChannels - channelsLeft) * outOffset; } for ( unsigned int i=0; i #include #include // A structure to hold various information related to the Jack API // implementation. struct JackHandle { jack_client_t *client; jack_port_t **ports[2]; std::string deviceName[2]; bool xrun[2]; pthread_cond_t condition; int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. JackHandle() :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; } }; /* --- Monocasual hack ---------------------------------------------- */ #ifdef __linux__ void *RtApi :: __HACK__getJackClient() { JackHandle *handle = (JackHandle *) stream_.apiHandle; return (void*) handle->client; } #endif /* ------------------------------------------------------------------ */ static void jackSilentError( const char * ) {}; RtApiJack :: RtApiJack() { // Nothing to do here. #if !defined(__RTAUDIO_DEBUG__) // Turn off Jack's internal error reporting. jack_set_error_function( &jackSilentError ); #endif } RtApiJack :: ~RtApiJack() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiJack :: getDeviceCount( void ) { // See if we can become a jack client. jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption; jack_status_t *status = NULL; jack_client_t *client = jack_client_open( "RtApiJackCount", options, status ); if ( client == 0 ) return 0; const char **ports; std::string port, previousPort; unsigned int nChannels = 0, nDevices = 0; ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). size_t iColon = 0; do { port = (char *) ports[ nChannels ]; iColon = port.find(":"); if ( iColon != std::string::npos ) { port = port.substr( 0, iColon + 1 ); if ( port != previousPort ) { nDevices++; previousPort = port; } } } while ( ports[++nChannels] ); free( ports ); } jack_client_close( client ); return nDevices; } RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption jack_status_t *status = NULL; jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status ); if ( client == 0 ) { errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!"; error( RtAudioError::WARNING ); return info; } const char **ports; std::string port, previousPort; unsigned int nPorts = 0, nDevices = 0; ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). size_t iColon = 0; do { port = (char *) ports[ nPorts ]; iColon = port.find(":"); if ( iColon != std::string::npos ) { port = port.substr( 0, iColon ); if ( port != previousPort ) { if ( nDevices == device ) info.name = port; nDevices++; previousPort = port; } } } while ( ports[++nPorts] ); free( ports ); } if ( device >= nDevices ) { jack_client_close( client ); errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!"; error( RtAudioError::INVALID_USE ); return info; } // Get the current jack server sample rate. info.sampleRates.clear(); info.sampleRates.push_back( jack_get_sample_rate( client ) ); // Count the available ports containing the client name as device // channels. Jack "input ports" equal RtAudio output channels. unsigned int nChannels = 0; ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput ); if ( ports ) { while ( ports[ nChannels ] ) nChannels++; free( ports ); info.outputChannels = nChannels; } // Jack "output ports" equal RtAudio input channels. nChannels = 0; ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput ); if ( ports ) { while ( ports[ nChannels ] ) nChannels++; free( ports ); info.inputChannels = nChannels; } if ( info.outputChannels == 0 && info.inputChannels == 0 ) { jack_client_close(client); errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!"; error( RtAudioError::WARNING ); return info; } // If device opens for both playback and capture, we determine the channels. if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // Jack always uses 32-bit floats. info.nativeFormats = RTAUDIO_FLOAT32; // Jack doesn't provide default devices so we'll use the first available one. if ( device == 0 && info.outputChannels > 0 ) info.isDefaultOutput = true; if ( device == 0 && info.inputChannels > 0 ) info.isDefaultInput = true; jack_client_close(client); info.probed = true; return info; } static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiJack *object = (RtApiJack *) info->object; if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1; return 0; } // This function will be called by a spawned thread when the Jack // server signals that it is shutting down. It is necessary to handle // it this way because the jackShutdown() function must return before // the jack_deactivate() function (in closeStream()) will return. static void *jackCloseStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiJack *object = (RtApiJack *) info->object; object->closeStream(); pthread_exit( NULL ); } static void jackShutdown( void *infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiJack *object = (RtApiJack *) info->object; // Check current stream state. If stopped, then we'll assume this // was called as a result of a call to RtApiJack::stopStream (the // deactivation of a client handle causes this function to be called). // If not, we'll assume the Jack server is shutting down or some // other problem occurred and we should close the stream. if ( object->isStreamRunning() == false ) return; ThreadHandle threadId; pthread_create( &threadId, NULL, jackCloseStream, info ); std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl; } static int jackXrun( void *infoPointer ) { JackHandle *handle = (JackHandle *) infoPointer; if ( handle->ports[0] ) handle->xrun[0] = true; if ( handle->ports[1] ) handle->xrun[1] = true; return 0; } bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) { JackHandle *handle = (JackHandle *) stream_.apiHandle; // Look for jack server and try to become a client (only do once per stream). jack_client_t *client = 0; if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) { jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption; jack_status_t *status = NULL; if ( options && !options->streamName.empty() ) client = jack_client_open( options->streamName.c_str(), jackoptions, status ); else client = jack_client_open( "RtApiJack", jackoptions, status ); if ( client == 0 ) { errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!"; error( RtAudioError::WARNING ); return FAILURE; } } else { // The handle must have been created on an earlier pass. client = handle->client; } const char **ports; std::string port, previousPort, deviceName; unsigned int nPorts = 0, nDevices = 0; ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). size_t iColon = 0; do { port = (char *) ports[ nPorts ]; iColon = port.find(":"); if ( iColon != std::string::npos ) { port = port.substr( 0, iColon ); if ( port != previousPort ) { if ( nDevices == device ) deviceName = port; nDevices++; previousPort = port; } } } while ( ports[++nPorts] ); free( ports ); } if ( device >= nDevices ) { errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!"; return FAILURE; } // Count the available ports containing the client name as device // channels. Jack "input ports" equal RtAudio output channels. unsigned int nChannels = 0; unsigned long flag = JackPortIsInput; if ( mode == INPUT ) flag = JackPortIsOutput; ports = jack_get_ports( client, deviceName.c_str(), NULL, flag ); if ( ports ) { while ( ports[ nChannels ] ) nChannels++; free( ports ); } // Compare the jack ports for specified client to the requested number of channels. if ( nChannels < (channels + firstChannel) ) { errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Check the jack server sample rate. unsigned int jackRate = jack_get_sample_rate( client ); if ( sampleRate != jackRate ) { jack_client_close( client ); errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.sampleRate = jackRate; // Get the latency of the JACK port. ports = jack_get_ports( client, deviceName.c_str(), NULL, flag ); if ( ports[ firstChannel ] ) { // Added by Ge Wang jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency); // the range (usually the min and max are equal) jack_latency_range_t latrange; latrange.min = latrange.max = 0; // get the latency range jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange ); // be optimistic, use the min! stream_.latency[mode] = latrange.min; //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) ); } free( ports ); // The jack server always uses 32-bit floating-point data. stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; stream_.userFormat = format; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; // Jack always uses non-interleaved buffers. stream_.deviceInterleaved[mode] = false; // Jack always provides host byte-ordered data. stream_.doByteSwap[mode] = false; // Get the buffer size. The buffer size and number of buffers // (periods) is set when the jack server is started. stream_.bufferSize = (int) jack_get_buffer_size( client ); *bufferSize = stream_.bufferSize; stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate our JackHandle structure for the stream. if ( handle == 0 ) { try { handle = new JackHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory."; goto error; } if ( pthread_cond_init(&handle->condition, NULL) ) { errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) handle; handle->client = client; } handle->deviceName[mode] = deviceName; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; if ( mode == OUTPUT ) bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); else { // mode == INPUT bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] ); if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]); if ( bufferBytes < bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } // Allocate memory for the Jack ports (channels) identifiers. handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels ); if ( handle->ports[mode] == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory."; goto error; } stream_.device[mode] = device; stream_.channelOffset[mode] = firstChannel; stream_.state = STREAM_STOPPED; stream_.callbackInfo.object = (void *) this; if ( stream_.mode == OUTPUT && mode == INPUT ) // We had already set up the stream for output. stream_.mode = DUPLEX; else { stream_.mode = mode; jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo ); jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle ); jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo ); } // Register our ports. char label[64]; if ( mode == OUTPUT ) { for ( unsigned int i=0; iports[0][i] = jack_port_register( handle->client, (const char *)label, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); } } else { for ( unsigned int i=0; iports[1][i] = jack_port_register( handle->client, (const char *)label, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); } } // Setup the buffer conversion information structure. We don't use // buffers to do channel offsets, so we override that parameter // here. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 ); return SUCCESS; error: if ( handle ) { pthread_cond_destroy( &handle->condition ); jack_client_close( handle->client ); if ( handle->ports[0] ) free( handle->ports[0] ); if ( handle->ports[1] ) free( handle->ports[1] ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiJack :: closeStream( void ) { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiJack::closeStream(): no open stream to close!"; error( RtAudioError::WARNING ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; if ( handle ) { if ( stream_.state == STREAM_RUNNING ) jack_deactivate( handle->client ); jack_client_close( handle->client ); } if ( handle ) { if ( handle->ports[0] ) free( handle->ports[0] ); if ( handle->ports[1] ) free( handle->ports[1] ); pthread_cond_destroy( &handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiJack :: startStream( void ) { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiJack::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; int result = jack_activate( handle->client ); if ( result ) { errorText_ = "RtApiJack::startStream(): unable to activate JACK client!"; goto unlock; } const char **ports; // Get the list of available ports. if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = 1; ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput); if ( ports == NULL) { errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!"; goto unlock; } // Now make the port connections. Since RtAudio wasn't designed to // allow the user to select particular channels of a device, we'll // just open the first "nChannels" ports with offset. for ( unsigned int i=0; iclient, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] ); if ( result ) { free( ports ); errorText_ = "RtApiJack::startStream(): error connecting output ports!"; goto unlock; } } free(ports); } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { result = 1; ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput ); if ( ports == NULL) { errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!"; goto unlock; } // Now make the port connections. See note above. for ( unsigned int i=0; iclient, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) ); if ( result ) { free( ports ); errorText_ = "RtApiJack::startStream(): error connecting input ports!"; goto unlock; } } free(ports); } handle->drainCounter = 0; handle->internalDrain = false; stream_.state = STREAM_RUNNING; unlock: if ( result == 0 ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiJack :: stopStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiJack::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled } } jack_deactivate( handle->client ); stream_.state = STREAM_STOPPED; } void RtApiJack :: abortStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiJack::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } JackHandle *handle = (JackHandle *) stream_.apiHandle; handle->drainCounter = 2; stopStream(); } // This function will be called by a spawned thread when the user // callback function signals that the stream should be stopped or // aborted. It is necessary to handle it this way because the // callbackEvent() function must return before the jack_deactivate() // function will return. static void *jackStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiJack *object = (RtApiJack *) info->object; object->stopStream(); pthread_exit( NULL ); } bool RtApiJack :: callbackEvent( unsigned long nframes ) { if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS; if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtAudioError::WARNING ); return FAILURE; } if ( stream_.bufferSize != nframes ) { errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!"; error( RtAudioError::WARNING ); return FAILURE; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; JackHandle *handle = (JackHandle *) stream_.apiHandle; // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > 3 ) { ThreadHandle threadId; stream_.state = STREAM_STOPPING; if ( handle->internalDrain == true ) pthread_create( &threadId, NULL, jackStopStream, info ); else pthread_cond_signal( &handle->condition ); return SUCCESS; } // Invoke user callback first, to get fresh output data. if ( handle->drainCounter == 0 ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( cbReturnValue == 2 ) { stream_.state = STREAM_STOPPING; handle->drainCounter = 2; ThreadHandle id; pthread_create( &id, NULL, jackStopStream, info ); return SUCCESS; } else if ( cbReturnValue == 1 ) { handle->drainCounter = 1; handle->internalDrain = true; } } jack_default_audio_sample_t *jackbuffer; unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t ); if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter > 1 ) { // write zeros to the output stream for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); memset( jackbuffer, 0, bufferBytes ); } } else if ( stream_.doConvertBuffer[0] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes ); } } else { // no buffer conversion for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes ); } } } // Don't bother draining input if ( handle->drainCounter ) { handle->drainCounter++; goto unlock; } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { if ( stream_.doConvertBuffer[1] ) { for ( unsigned int i=0; iports[1][i], (jack_nframes_t) nframes ); memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes ); } convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } else { // no buffer conversion for ( unsigned int i=0; iports[1][i], (jack_nframes_t) nframes ); memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes ); } } } unlock: RtApi::tickStreamTime(); return SUCCESS; } //******************** End of __UNIX_JACK__ *********************// #endif #if defined(__WINDOWS_ASIO__) // ASIO API on Windows // The ASIO API is designed around a callback scheme, so this // implementation is similar to that used for OS-X CoreAudio and Linux // Jack. The primary constraint with ASIO is that it only allows // access to a single driver at a time. Thus, it is not possible to // have more than one simultaneous RtAudio stream. // // This implementation also requires a number of external ASIO files // and a few global variables. The ASIO callback scheme does not // allow for the passing of user data, so we must create a global // pointer to our callbackInfo structure. // // On unix systems, we make use of a pthread condition variable. // Since there is no equivalent in Windows, I hacked something based // on information found in // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html. #include "asiosys.h" #include "asio.h" #include "iasiothiscallresolver.h" #include "asiodrivers.h" #include static AsioDrivers drivers; static ASIOCallbacks asioCallbacks; static ASIODriverInfo driverInfo; static CallbackInfo *asioCallbackInfo; static bool asioXRun; struct AsioHandle { int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. ASIOBufferInfo *bufferInfos; HANDLE condition; AsioHandle() :drainCounter(0), internalDrain(false), bufferInfos(0) {} }; // Function declarations (definitions at end of section) static const char* getAsioErrorString( ASIOError result ); static void sampleRateChanged( ASIOSampleRate sRate ); static long asioMessages( long selector, long value, void* message, double* opt ); RtApiAsio :: RtApiAsio() { // ASIO cannot run on a multi-threaded appartment. You can call // CoInitialize beforehand, but it must be for appartment threading // (in which case, CoInitilialize will return S_FALSE here). coInitialized_ = false; HRESULT hr = CoInitialize( NULL ); if ( FAILED(hr) ) { errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)"; error( RtAudioError::WARNING ); } coInitialized_ = true; drivers.removeCurrentDriver(); driverInfo.asioVersion = 2; // See note in DirectSound implementation about GetDesktopWindow(). driverInfo.sysRef = GetForegroundWindow(); } RtApiAsio :: ~RtApiAsio() { if ( stream_.state != STREAM_CLOSED ) closeStream(); if ( coInitialized_ ) CoUninitialize(); } unsigned int RtApiAsio :: getDeviceCount( void ) { return (unsigned int) drivers.asioGetNumDev(); } RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; // Get device ID unsigned int nDevices = getDeviceCount(); if ( nDevices == 0 ) { errorText_ = "RtApiAsio::getDeviceInfo: no devices found!"; error( RtAudioError::INVALID_USE ); return info; } if ( device >= nDevices ) { errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!"; error( RtAudioError::INVALID_USE ); return info; } // If a stream is already open, we cannot probe other devices. Thus, use the saved results. if ( stream_.state != STREAM_CLOSED ) { if ( device >= devices_.size() ) { errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened."; error( RtAudioError::WARNING ); return info; } return devices_[ device ]; } char driverName[32]; ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } info.name = driverName; if ( !drivers.loadDriver( driverName ) ) { errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } result = ASIOInit( &driverInfo ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Determine the device channel information. long inputChannels, outputChannels; result = ASIOGetChannels( &inputChannels, &outputChannels ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } info.outputChannels = outputChannels; info.inputChannels = inputChannels; if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // Determine the supported sample rates. info.sampleRates.clear(); for ( unsigned int i=0; i 0 ) if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true; if ( info.inputChannels > 0 ) if ( getDefaultInputDevice() == device ) info.isDefaultInput = true; info.probed = true; drivers.removeCurrentDriver(); return info; } static void bufferSwitch( long index, ASIOBool /*processNow*/ ) { RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object; object->callbackEvent( index ); } void RtApiAsio :: saveDeviceInfo( void ) { devices_.clear(); unsigned int nDevices = getDeviceCount(); devices_.resize( nDevices ); for ( unsigned int i=0; isaveDeviceInfo(); if ( !drivers.loadDriver( driverName ) ) { errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ")."; errorText_ = errorStream_.str(); return FAILURE; } result = ASIOInit( &driverInfo ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Check the device channel count. long inputChannels, outputChannels; result = ASIOGetChannels( &inputChannels, &outputChannels ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ")."; errorText_ = errorStream_.str(); return FAILURE; } if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) || ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.nDeviceChannels[mode] = channels; stream_.nUserChannels[mode] = channels; stream_.channelOffset[mode] = firstChannel; // Verify the sample rate is supported. result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Get the current sample rate ASIOSampleRate currentRate; result = ASIOGetSampleRate( ¤tRate ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate."; errorText_ = errorStream_.str(); return FAILURE; } // Set the sample rate only if necessary if ( currentRate != sampleRate ) { result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } } // Determine the driver data type. ASIOChannelInfo channelInfo; channelInfo.channel = 0; if ( mode == OUTPUT ) channelInfo.isInput = false; else channelInfo.isInput = true; result = ASIOGetChannelInfo( &channelInfo ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format."; errorText_ = errorStream_.str(); return FAILURE; } // Assuming WINDOWS host is always little-endian. stream_.doByteSwap[mode] = false; stream_.userFormat = format; stream_.deviceFormat[mode] = 0; if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) { stream_.deviceFormat[mode] = RTAUDIO_SINT16; if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) { stream_.deviceFormat[mode] = RTAUDIO_SINT32; if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT64; if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true; } else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) { stream_.deviceFormat[mode] = RTAUDIO_SINT24; if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true; } if ( stream_.deviceFormat[mode] == 0 ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; } // Set the buffer size. For a duplex stream, this will end up // setting the buffer size based on the input constraints, which // should be ok. long minSize, maxSize, preferSize, granularity; result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity ); if ( result != ASE_OK ) { drivers.removeCurrentDriver(); errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size."; errorText_ = errorStream_.str(); return FAILURE; } if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; else if ( granularity == -1 ) { // Make sure bufferSize is a power of two. int log2_of_min_size = 0; int log2_of_max_size = 0; for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { if ( minSize & ((long)1 << i) ) log2_of_min_size = i; if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; } long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); int min_delta_num = log2_of_min_size; for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); if (current_delta < min_delta) { min_delta = current_delta; min_delta_num = i; } } *bufferSize = ( (unsigned int)1 << min_delta_num ); if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; } else if ( granularity != 0 ) { // Set to an even multiple of granularity, rounding up. *bufferSize = (*bufferSize + granularity-1) / granularity * granularity; } if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) { drivers.removeCurrentDriver(); errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!"; return FAILURE; } stream_.bufferSize = *bufferSize; stream_.nBuffers = 2; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; // ASIO always uses non-interleaved buffers. stream_.deviceInterleaved[mode] = false; // Allocate, if necessary, our AsioHandle structure for the stream. AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( handle == 0 ) { try { handle = new AsioHandle; } catch ( std::bad_alloc& ) { //if ( handle == NULL ) { drivers.removeCurrentDriver(); errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory."; return FAILURE; } handle->bufferInfos = 0; // Create a manual-reset event. handle->condition = CreateEvent( NULL, // no security TRUE, // manual-reset FALSE, // non-signaled initially NULL ); // unnamed stream_.apiHandle = (void *) handle; } // Create the ASIO internal buffers. Since RtAudio sets up input // and output separately, we'll have to dispose of previously // created output buffers for a duplex stream. long inputLatency, outputLatency; if ( mode == INPUT && stream_.mode == OUTPUT ) { ASIODisposeBuffers(); if ( handle->bufferInfos ) free( handle->bufferInfos ); } // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure. bool buffersAllocated = false; unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) ); if ( handle->bufferInfos == NULL ) { errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ")."; errorText_ = errorStream_.str(); goto error; } ASIOBufferInfo *infos; infos = handle->bufferInfos; for ( i=0; iisInput = ASIOFalse; infos->channelNum = i + stream_.channelOffset[0]; infos->buffers[0] = infos->buffers[1] = 0; } for ( i=0; iisInput = ASIOTrue; infos->channelNum = i + stream_.channelOffset[1]; infos->buffers[0] = infos->buffers[1] = 0; } // Set up the ASIO callback structure and create the ASIO data buffers. asioCallbacks.bufferSwitch = &bufferSwitch; asioCallbacks.sampleRateDidChange = &sampleRateChanged; asioCallbacks.asioMessage = &asioMessages; asioCallbacks.bufferSwitchTimeInfo = NULL; result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers."; errorText_ = errorStream_.str(); goto error; } buffersAllocated = true; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate necessary internal buffers unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.sampleRate = sampleRate; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; asioCallbackInfo = &stream_.callbackInfo; stream_.callbackInfo.object = (void *) this; if ( stream_.mode == OUTPUT && mode == INPUT ) // We had already set up an output stream. stream_.mode = DUPLEX; else stream_.mode = mode; // Determine device latencies result = ASIOGetLatencies( &inputLatency, &outputLatency ); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING); // warn but don't fail } else { stream_.latency[0] = outputLatency; stream_.latency[1] = inputLatency; } // Setup the buffer conversion information structure. We don't use // buffers to do channel offsets, so we override that parameter // here. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 ); return SUCCESS; error: if ( buffersAllocated ) ASIODisposeBuffers(); drivers.removeCurrentDriver(); if ( handle ) { CloseHandle( handle->condition ); if ( handle->bufferInfos ) free( handle->bufferInfos ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiAsio :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAsio::closeStream(): no open stream to close!"; error( RtAudioError::WARNING ); return; } if ( stream_.state == STREAM_RUNNING ) { stream_.state = STREAM_STOPPED; ASIOStop(); } ASIODisposeBuffers(); drivers.removeCurrentDriver(); AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( handle ) { CloseHandle( handle->condition ); if ( handle->bufferInfos ) free( handle->bufferInfos ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } bool stopThreadCalled = false; void RtApiAsio :: startStream() { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiAsio::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } AsioHandle *handle = (AsioHandle *) stream_.apiHandle; ASIOError result = ASIOStart(); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device."; errorText_ = errorStream_.str(); goto unlock; } handle->drainCounter = 0; handle->internalDrain = false; ResetEvent( handle->condition ); stream_.state = STREAM_RUNNING; asioXRun = false; unlock: stopThreadCalled = false; if ( result == ASE_OK ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiAsio :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } AsioHandle *handle = (AsioHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; WaitForSingleObject( handle->condition, INFINITE ); // block until signaled } } stream_.state = STREAM_STOPPED; ASIOError result = ASIOStop(); if ( result != ASE_OK ) { errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device."; errorText_ = errorStream_.str(); } if ( result == ASE_OK ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiAsio :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } // The following lines were commented-out because some behavior was // noted where the device buffers need to be zeroed to avoid // continuing sound, even when the device buffers are completely // disposed. So now, calling abort is the same as calling stop. // AsioHandle *handle = (AsioHandle *) stream_.apiHandle; // handle->drainCounter = 2; stopStream(); } // This function will be called by a spawned thread when the user // callback function signals that the stream should be stopped or // aborted. It is necessary to handle it this way because the // callbackEvent() function must return before the ASIOStop() // function will return. static unsigned __stdcall asioStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiAsio *object = (RtApiAsio *) info->object; object->stopStream(); _endthreadex( 0 ); return 0; } bool RtApiAsio :: callbackEvent( long bufferIndex ) { if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS; if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtAudioError::WARNING ); return FAILURE; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; AsioHandle *handle = (AsioHandle *) stream_.apiHandle; // Check if we were draining the stream and signal if finished. if ( handle->drainCounter > 3 ) { stream_.state = STREAM_STOPPING; if ( handle->internalDrain == false ) SetEvent( handle->condition ); else { // spawn a thread to stop the stream unsigned threadId; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream, &stream_.callbackInfo, 0, &threadId ); } return SUCCESS; } // Invoke user callback to get fresh output data UNLESS we are // draining stream. if ( handle->drainCounter == 0 ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && asioXRun == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; asioXRun = false; } if ( stream_.mode != OUTPUT && asioXRun == true ) { status |= RTAUDIO_INPUT_OVERFLOW; asioXRun = false; } int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( cbReturnValue == 2 ) { stream_.state = STREAM_STOPPING; handle->drainCounter = 2; unsigned threadId; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream, &stream_.callbackInfo, 0, &threadId ); return SUCCESS; } else if ( cbReturnValue == 1 ) { handle->drainCounter = 1; handle->internalDrain = true; } } unsigned int nChannels, bufferBytes, i, j; nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1]; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] ); if ( handle->drainCounter > 1 ) { // write zeros to the output stream for ( i=0, j=0; ibufferInfos[i].isInput != ASIOTrue ) memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes ); } } else if ( stream_.doConvertBuffer[0] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); if ( stream_.doByteSwap[0] ) byteSwapBuffer( stream_.deviceBuffer, stream_.bufferSize * stream_.nDeviceChannels[0], stream_.deviceFormat[0] ); for ( i=0, j=0; ibufferInfos[i].isInput != ASIOTrue ) memcpy( handle->bufferInfos[i].buffers[bufferIndex], &stream_.deviceBuffer[j++*bufferBytes], bufferBytes ); } } else { if ( stream_.doByteSwap[0] ) byteSwapBuffer( stream_.userBuffer[0], stream_.bufferSize * stream_.nUserChannels[0], stream_.userFormat ); for ( i=0, j=0; ibufferInfos[i].isInput != ASIOTrue ) memcpy( handle->bufferInfos[i].buffers[bufferIndex], &stream_.userBuffer[0][bufferBytes*j++], bufferBytes ); } } } // Don't bother draining input if ( handle->drainCounter ) { handle->drainCounter++; goto unlock; } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]); if (stream_.doConvertBuffer[1]) { // Always interleave ASIO input data. for ( i=0, j=0; ibufferInfos[i].isInput == ASIOTrue ) memcpy( &stream_.deviceBuffer[j++*bufferBytes], handle->bufferInfos[i].buffers[bufferIndex], bufferBytes ); } if ( stream_.doByteSwap[1] ) byteSwapBuffer( stream_.deviceBuffer, stream_.bufferSize * stream_.nDeviceChannels[1], stream_.deviceFormat[1] ); convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } else { for ( i=0, j=0; ibufferInfos[i].isInput == ASIOTrue ) { memcpy( &stream_.userBuffer[1][bufferBytes*j++], handle->bufferInfos[i].buffers[bufferIndex], bufferBytes ); } } if ( stream_.doByteSwap[1] ) byteSwapBuffer( stream_.userBuffer[1], stream_.bufferSize * stream_.nUserChannels[1], stream_.userFormat ); } } unlock: // The following call was suggested by Malte Clasen. While the API // documentation indicates it should not be required, some device // drivers apparently do not function correctly without it. ASIOOutputReady(); RtApi::tickStreamTime(); return SUCCESS; } static void sampleRateChanged( ASIOSampleRate sRate ) { // The ASIO documentation says that this usually only happens during // external sync. Audio processing is not stopped by the driver, // actual sample rate might not have even changed, maybe only the // sample rate status of an AES/EBU or S/PDIF digital input at the // audio device. RtApi *object = (RtApi *) asioCallbackInfo->object; try { object->stopStream(); } catch ( RtAudioError &exception ) { std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl; return; } std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl; } static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ ) { long ret = 0; switch( selector ) { case kAsioSelectorSupported: if ( value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest || value == kAsioLatenciesChanged // The following three were added for ASIO 2.0, you don't // necessarily have to support them. || value == kAsioSupportsTimeInfo || value == kAsioSupportsTimeCode || value == kAsioSupportsInputMonitor) ret = 1L; break; case kAsioResetRequest: // Defer the task and perform the reset of the driver during the // next "safe" situation. You cannot reset the driver right now, // as this code is called from the driver. Reset the driver is // done by completely destruct is. I.e. ASIOStop(), // ASIODisposeBuffers(), Destruction Afterwards you initialize the // driver again. std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl; ret = 1L; break; case kAsioResyncRequest: // This informs the application that the driver encountered some // non-fatal data loss. It is used for synchronization purposes // of different media. Added mainly to work around the Win16Mutex // problems in Windows 95/98 with the Windows Multimedia system, // which could lose data because the Mutex was held too long by // another thread. However a driver can issue it in other // situations, too. // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl; asioXRun = true; ret = 1L; break; case kAsioLatenciesChanged: // This will inform the host application that the drivers were // latencies changed. Beware, it this does not mean that the // buffer sizes have changed! You might need to update internal // delay data. std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl; ret = 1L; break; case kAsioEngineVersion: // Return the supported ASIO version of the host application. If // a host application does not implement this selector, ASIO 1.0 // is assumed by the driver. ret = 2L; break; case kAsioSupportsTimeInfo: // Informs the driver whether the // asioCallbacks.bufferSwitchTimeInfo() callback is supported. // For compatibility with ASIO 1.0 drivers the host application // should always support the "old" bufferSwitch method, too. ret = 0; break; case kAsioSupportsTimeCode: // Informs the driver whether application is interested in time // code info. If an application does not need to know about time // code, the driver has less work to do. ret = 0; break; } return ret; } static const char* getAsioErrorString( ASIOError result ) { struct Messages { ASIOError value; const char*message; }; static const Messages m[] = { { ASE_NotPresent, "Hardware input or output is not present or available." }, { ASE_HWMalfunction, "Hardware is malfunctioning." }, { ASE_InvalidParameter, "Invalid input parameter." }, { ASE_InvalidMode, "Invalid mode." }, { ASE_SPNotAdvancing, "Sample position not advancing." }, { ASE_NoClock, "Sample clock or rate cannot be determined or is not present." }, { ASE_NoMemory, "Not enough memory to complete the request." } }; for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i ) if ( m[i].value == result ) return m[i].message; return "Unknown error."; } //******************** End of __WINDOWS_ASIO__ *********************// #endif #if defined(__WINDOWS_WASAPI__) // Windows WASAPI API // Authored by Marcus Tomlinson , April 2014 // - Introduces support for the Windows WASAPI API // - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required // - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface // - Includes automatic internal conversion of sample rate and buffer size between hardware and the user #ifndef INITGUID #define INITGUID #endif #include #include #include #include //============================================================================= #define SAFE_RELEASE( objectPtr )\ if ( objectPtr )\ {\ objectPtr->Release();\ objectPtr = NULL;\ } typedef HANDLE ( __stdcall *TAvSetMmThreadCharacteristicsPtr )( LPCWSTR TaskName, LPDWORD TaskIndex ); //----------------------------------------------------------------------------- // WASAPI dictates stream sample rate, format, channel count, and in some cases, buffer size. // Therefore we must perform all necessary conversions to user buffers in order to satisfy these // requirements. WasapiBuffer ring buffers are used between HwIn->UserIn and UserOut->HwOut to // provide intermediate storage for read / write synchronization. class WasapiBuffer { public: WasapiBuffer() : buffer_( NULL ), bufferSize_( 0 ), inIndex_( 0 ), outIndex_( 0 ) {} ~WasapiBuffer() { delete buffer_; } // sets the length of the internal ring buffer void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) { delete buffer_; buffer_ = ( char* ) calloc( bufferSize, formatBytes ); bufferSize_ = bufferSize; inIndex_ = 0; outIndex_ = 0; } // attempt to push a buffer into the ring buffer at the current "in" index bool pushBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format ) { if ( !buffer || // incoming buffer is NULL bufferSize == 0 || // incoming buffer has no data bufferSize > bufferSize_ ) // incoming buffer too large { return false; } unsigned int relOutIndex = outIndex_; unsigned int inIndexEnd = inIndex_ + bufferSize; if ( relOutIndex < inIndex_ && inIndexEnd >= bufferSize_ ) { relOutIndex += bufferSize_; } // "in" index can end on the "out" index but cannot begin at it if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) { return false; // not enough space between "in" index and "out" index } // copy buffer from external to internal int fromZeroSize = inIndex_ + bufferSize - bufferSize_; fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize; int fromInSize = bufferSize - fromZeroSize; switch( format ) { case RTAUDIO_SINT8: memcpy( &( ( char* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( char ) ); memcpy( buffer_, &( ( char* ) buffer )[fromInSize], fromZeroSize * sizeof( char ) ); break; case RTAUDIO_SINT16: memcpy( &( ( short* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( short ) ); memcpy( buffer_, &( ( short* ) buffer )[fromInSize], fromZeroSize * sizeof( short ) ); break; case RTAUDIO_SINT24: memcpy( &( ( S24* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( S24 ) ); memcpy( buffer_, &( ( S24* ) buffer )[fromInSize], fromZeroSize * sizeof( S24 ) ); break; case RTAUDIO_SINT32: memcpy( &( ( int* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( int ) ); memcpy( buffer_, &( ( int* ) buffer )[fromInSize], fromZeroSize * sizeof( int ) ); break; case RTAUDIO_FLOAT32: memcpy( &( ( float* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( float ) ); memcpy( buffer_, &( ( float* ) buffer )[fromInSize], fromZeroSize * sizeof( float ) ); break; case RTAUDIO_FLOAT64: memcpy( &( ( double* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( double ) ); memcpy( buffer_, &( ( double* ) buffer )[fromInSize], fromZeroSize * sizeof( double ) ); break; } // update "in" index inIndex_ += bufferSize; inIndex_ %= bufferSize_; return true; } // attempt to pull a buffer from the ring buffer from the current "out" index bool pullBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format ) { if ( !buffer || // incoming buffer is NULL bufferSize == 0 || // incoming buffer has no data bufferSize > bufferSize_ ) // incoming buffer too large { return false; } unsigned int relInIndex = inIndex_; unsigned int outIndexEnd = outIndex_ + bufferSize; if ( relInIndex < outIndex_ && outIndexEnd >= bufferSize_ ) { relInIndex += bufferSize_; } // "out" index can begin at and end on the "in" index if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) { return false; // not enough space between "out" index and "in" index } // copy buffer from internal to external int fromZeroSize = outIndex_ + bufferSize - bufferSize_; fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize; int fromOutSize = bufferSize - fromZeroSize; switch( format ) { case RTAUDIO_SINT8: memcpy( buffer, &( ( char* ) buffer_ )[outIndex_], fromOutSize * sizeof( char ) ); memcpy( &( ( char* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( char ) ); break; case RTAUDIO_SINT16: memcpy( buffer, &( ( short* ) buffer_ )[outIndex_], fromOutSize * sizeof( short ) ); memcpy( &( ( short* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( short ) ); break; case RTAUDIO_SINT24: memcpy( buffer, &( ( S24* ) buffer_ )[outIndex_], fromOutSize * sizeof( S24 ) ); memcpy( &( ( S24* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( S24 ) ); break; case RTAUDIO_SINT32: memcpy( buffer, &( ( int* ) buffer_ )[outIndex_], fromOutSize * sizeof( int ) ); memcpy( &( ( int* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( int ) ); break; case RTAUDIO_FLOAT32: memcpy( buffer, &( ( float* ) buffer_ )[outIndex_], fromOutSize * sizeof( float ) ); memcpy( &( ( float* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( float ) ); break; case RTAUDIO_FLOAT64: memcpy( buffer, &( ( double* ) buffer_ )[outIndex_], fromOutSize * sizeof( double ) ); memcpy( &( ( double* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( double ) ); break; } // update "out" index outIndex_ += bufferSize; outIndex_ %= bufferSize_; return true; } private: char* buffer_; unsigned int bufferSize_; unsigned int inIndex_; unsigned int outIndex_; }; //----------------------------------------------------------------------------- // In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate // between HW and the user. The convertBufferWasapi function is used to perform this conversion // between HwIn->UserIn and UserOut->HwOut during the stream callback loop. // This sample rate converter favors speed over quality, and works best with conversions between // one rate and its multiple. void convertBufferWasapi( char* outBuffer, const char* inBuffer, const unsigned int& channelCount, const unsigned int& inSampleRate, const unsigned int& outSampleRate, const unsigned int& inSampleCount, unsigned int& outSampleCount, const RtAudioFormat& format ) { // calculate the new outSampleCount and relative sampleStep float sampleRatio = ( float ) outSampleRate / inSampleRate; float sampleStep = 1.0f / sampleRatio; float inSampleFraction = 0.0f; outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio ); // frame-by-frame, copy each relative input sample into it's corresponding output sample for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ ) { unsigned int inSample = ( unsigned int ) inSampleFraction; switch ( format ) { case RTAUDIO_SINT8: memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) ); break; case RTAUDIO_SINT16: memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) ); break; case RTAUDIO_SINT24: memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) ); break; case RTAUDIO_SINT32: memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) ); break; case RTAUDIO_FLOAT32: memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) ); break; case RTAUDIO_FLOAT64: memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) ); break; } // jump to next in sample inSampleFraction += sampleStep; } } //----------------------------------------------------------------------------- // A structure to hold various information related to the WASAPI implementation. struct WasapiHandle { IAudioClient* captureAudioClient; IAudioClient* renderAudioClient; IAudioCaptureClient* captureClient; IAudioRenderClient* renderClient; HANDLE captureEvent; HANDLE renderEvent; WasapiHandle() : captureAudioClient( NULL ), renderAudioClient( NULL ), captureClient( NULL ), renderClient( NULL ), captureEvent( NULL ), renderEvent( NULL ) {} }; //============================================================================= RtApiWasapi::RtApiWasapi() : coInitialized_( false ), deviceEnumerator_( NULL ) { // WASAPI can run either apartment or multi-threaded HRESULT hr = CoInitialize( NULL ); if ( !FAILED( hr ) ) coInitialized_ = true; // Instantiate device enumerator hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL, CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ), ( void** ) &deviceEnumerator_ ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator"; error( RtAudioError::DRIVER_ERROR ); } } //----------------------------------------------------------------------------- RtApiWasapi::~RtApiWasapi() { if ( stream_.state != STREAM_CLOSED ) closeStream(); SAFE_RELEASE( deviceEnumerator_ ); // If this object previously called CoInitialize() if ( coInitialized_ ) CoUninitialize(); } //============================================================================= unsigned int RtApiWasapi::getDeviceCount( void ) { unsigned int captureDeviceCount = 0; unsigned int renderDeviceCount = 0; IMMDeviceCollection* captureDevices = NULL; IMMDeviceCollection* renderDevices = NULL; // Count capture devices errorText_.clear(); HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection."; goto Exit; } hr = captureDevices->GetCount( &captureDeviceCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count."; goto Exit; } // Count render devices hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection."; goto Exit; } hr = renderDevices->GetCount( &renderDeviceCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count."; goto Exit; } Exit: // release all references SAFE_RELEASE( captureDevices ); SAFE_RELEASE( renderDevices ); if ( errorText_.empty() ) return captureDeviceCount + renderDeviceCount; error( RtAudioError::DRIVER_ERROR ); return 0; } //----------------------------------------------------------------------------- RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; unsigned int captureDeviceCount = 0; unsigned int renderDeviceCount = 0; std::wstring deviceName; std::string defaultDeviceName; bool isCaptureDevice = false; PROPVARIANT deviceNameProp; PROPVARIANT defaultDeviceNameProp; IMMDeviceCollection* captureDevices = NULL; IMMDeviceCollection* renderDevices = NULL; IMMDevice* devicePtr = NULL; IMMDevice* defaultDevicePtr = NULL; IAudioClient* audioClient = NULL; IPropertyStore* devicePropStore = NULL; IPropertyStore* defaultDevicePropStore = NULL; WAVEFORMATEX* deviceFormat = NULL; WAVEFORMATEX* closestMatchFormat = NULL; // probed info.probed = false; // Count capture devices errorText_.clear(); RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR; HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection."; goto Exit; } hr = captureDevices->GetCount( &captureDeviceCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count."; goto Exit; } // Count render devices hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection."; goto Exit; } hr = renderDevices->GetCount( &renderDeviceCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count."; goto Exit; } // validate device index if ( device >= captureDeviceCount + renderDeviceCount ) { errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index."; errorType = RtAudioError::INVALID_USE; goto Exit; } // determine whether index falls within capture or render devices if ( device >= renderDeviceCount ) { hr = captureDevices->Item( device - renderDeviceCount, &devicePtr ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle."; goto Exit; } isCaptureDevice = true; } else { hr = renderDevices->Item( device, &devicePtr ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle."; goto Exit; } isCaptureDevice = false; } // get default device name if ( isCaptureDevice ) { hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle."; goto Exit; } } else { hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle."; goto Exit; } } hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store."; goto Exit; } PropVariantInit( &defaultDeviceNameProp ); hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName."; goto Exit; } deviceName = defaultDeviceNameProp.pwszVal; defaultDeviceName = std::string( deviceName.begin(), deviceName.end() ); // name hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store."; goto Exit; } PropVariantInit( &deviceNameProp ); hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName."; goto Exit; } deviceName = deviceNameProp.pwszVal; info.name = std::string( deviceName.begin(), deviceName.end() ); // is default if ( isCaptureDevice ) { info.isDefaultInput = info.name == defaultDeviceName; info.isDefaultOutput = false; } else { info.isDefaultInput = false; info.isDefaultOutput = info.name == defaultDeviceName; } // channel count hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client."; goto Exit; } hr = audioClient->GetMixFormat( &deviceFormat ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format."; goto Exit; } if ( isCaptureDevice ) { info.inputChannels = deviceFormat->nChannels; info.outputChannels = 0; info.duplexChannels = 0; } else { info.inputChannels = 0; info.outputChannels = deviceFormat->nChannels; info.duplexChannels = 0; } // sample rates info.sampleRates.clear(); // allow support for all sample rates as we have a built-in sample rate converter for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) { info.sampleRates.push_back( SAMPLE_RATES[i] ); } // native format info.nativeFormats = 0; if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE && ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) ) { if ( deviceFormat->wBitsPerSample == 32 ) { info.nativeFormats |= RTAUDIO_FLOAT32; } else if ( deviceFormat->wBitsPerSample == 64 ) { info.nativeFormats |= RTAUDIO_FLOAT64; } } else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM || ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE && ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) ) { if ( deviceFormat->wBitsPerSample == 8 ) { info.nativeFormats |= RTAUDIO_SINT8; } else if ( deviceFormat->wBitsPerSample == 16 ) { info.nativeFormats |= RTAUDIO_SINT16; } else if ( deviceFormat->wBitsPerSample == 24 ) { info.nativeFormats |= RTAUDIO_SINT24; } else if ( deviceFormat->wBitsPerSample == 32 ) { info.nativeFormats |= RTAUDIO_SINT32; } } // probed info.probed = true; Exit: // release all references PropVariantClear( &deviceNameProp ); PropVariantClear( &defaultDeviceNameProp ); SAFE_RELEASE( captureDevices ); SAFE_RELEASE( renderDevices ); SAFE_RELEASE( devicePtr ); SAFE_RELEASE( defaultDevicePtr ); SAFE_RELEASE( audioClient ); SAFE_RELEASE( devicePropStore ); SAFE_RELEASE( defaultDevicePropStore ); CoTaskMemFree( deviceFormat ); CoTaskMemFree( closestMatchFormat ); if ( !errorText_.empty() ) error( errorType ); return info; } //----------------------------------------------------------------------------- unsigned int RtApiWasapi::getDefaultOutputDevice( void ) { for ( unsigned int i = 0; i < getDeviceCount(); i++ ) { if ( getDeviceInfo( i ).isDefaultOutput ) { return i; } } return 0; } //----------------------------------------------------------------------------- unsigned int RtApiWasapi::getDefaultInputDevice( void ) { for ( unsigned int i = 0; i < getDeviceCount(); i++ ) { if ( getDeviceInfo( i ).isDefaultInput ) { return i; } } return 0; } //----------------------------------------------------------------------------- void RtApiWasapi::closeStream( void ) { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiWasapi::closeStream: No open stream to close."; error( RtAudioError::WARNING ); return; } if ( stream_.state != STREAM_STOPPED ) stopStream(); // clean up stream memory SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient ) SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient ) if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent ) CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent ); if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent ) CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent ); delete ( WasapiHandle* ) stream_.apiHandle; stream_.apiHandle = NULL; for ( int i = 0; i < 2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } // update stream state stream_.state = STREAM_CLOSED; } //----------------------------------------------------------------------------- void RtApiWasapi::startStream( void ) { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiWasapi::startStream: The stream is already running."; error( RtAudioError::WARNING ); return; } // update stream state stream_.state = STREAM_RUNNING; // create WASAPI stream thread stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL ); if ( !stream_.callbackInfo.thread ) { errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread."; error( RtAudioError::THREAD_ERROR ); } else { SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority ); ResumeThread( ( void* ) stream_.callbackInfo.thread ); } } //----------------------------------------------------------------------------- void RtApiWasapi::stopStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiWasapi::stopStream: The stream is already stopped."; error( RtAudioError::WARNING ); return; } // inform stream thread by setting stream state to STREAM_STOPPING stream_.state = STREAM_STOPPING; // wait until stream thread is stopped while( stream_.state != STREAM_STOPPED ) { Sleep( 1 ); } // Wait for the last buffer to play before stopping. Sleep( 1000 * stream_.bufferSize / stream_.sampleRate ); // stop capture client if applicable if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) { HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream."; error( RtAudioError::DRIVER_ERROR ); return; } } // stop render client if applicable if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) { HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream."; error( RtAudioError::DRIVER_ERROR ); return; } } // close thread handle if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) { errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread."; error( RtAudioError::THREAD_ERROR ); return; } stream_.callbackInfo.thread = (ThreadHandle) NULL; } //----------------------------------------------------------------------------- void RtApiWasapi::abortStream( void ) { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiWasapi::abortStream: The stream is already stopped."; error( RtAudioError::WARNING ); return; } // inform stream thread by setting stream state to STREAM_STOPPING stream_.state = STREAM_STOPPING; // wait until stream thread is stopped while ( stream_.state != STREAM_STOPPED ) { Sleep( 1 ); } // stop capture client if applicable if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) { HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream."; error( RtAudioError::DRIVER_ERROR ); return; } } // stop render client if applicable if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) { HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream."; error( RtAudioError::DRIVER_ERROR ); return; } } // close thread handle if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) { errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread."; error( RtAudioError::THREAD_ERROR ); return; } stream_.callbackInfo.thread = (ThreadHandle) NULL; } //----------------------------------------------------------------------------- bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int* bufferSize, RtAudio::StreamOptions* options ) { bool methodResult = FAILURE; unsigned int captureDeviceCount = 0; unsigned int renderDeviceCount = 0; IMMDeviceCollection* captureDevices = NULL; IMMDeviceCollection* renderDevices = NULL; IMMDevice* devicePtr = NULL; WAVEFORMATEX* deviceFormat = NULL; unsigned int bufferBytes; stream_.state = STREAM_STOPPED; // create API Handle if not already created if ( !stream_.apiHandle ) stream_.apiHandle = ( void* ) new WasapiHandle(); // Count capture devices errorText_.clear(); RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR; HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection."; goto Exit; } hr = captureDevices->GetCount( &captureDeviceCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count."; goto Exit; } // Count render devices hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection."; goto Exit; } hr = renderDevices->GetCount( &renderDeviceCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count."; goto Exit; } // validate device index if ( device >= captureDeviceCount + renderDeviceCount ) { errorType = RtAudioError::INVALID_USE; errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index."; goto Exit; } // determine whether index falls within capture or render devices if ( device >= renderDeviceCount ) { if ( mode != INPUT ) { errorType = RtAudioError::INVALID_USE; errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device."; goto Exit; } // retrieve captureAudioClient from devicePtr IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; hr = captureDevices->Item( device - renderDeviceCount, &devicePtr ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle."; goto Exit; } hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &captureAudioClient ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client."; goto Exit; } hr = captureAudioClient->GetMixFormat( &deviceFormat ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format."; goto Exit; } stream_.nDeviceChannels[mode] = deviceFormat->nChannels; captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] ); } else { if ( mode != OUTPUT ) { errorType = RtAudioError::INVALID_USE; errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device."; goto Exit; } // retrieve renderAudioClient from devicePtr IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; hr = renderDevices->Item( device, &devicePtr ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle."; goto Exit; } hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &renderAudioClient ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client."; goto Exit; } hr = renderAudioClient->GetMixFormat( &deviceFormat ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format."; goto Exit; } stream_.nDeviceChannels[mode] = deviceFormat->nChannels; renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] ); } // fill stream data if ( ( stream_.mode == OUTPUT && mode == INPUT ) || ( stream_.mode == INPUT && mode == OUTPUT ) ) { stream_.mode = DUPLEX; } else { stream_.mode = mode; } stream_.device[mode] = device; stream_.doByteSwap[mode] = false; stream_.sampleRate = sampleRate; stream_.bufferSize = *bufferSize; stream_.nBuffers = 1; stream_.nUserChannels[mode] = channels; stream_.channelOffset[mode] = firstChannel; stream_.userFormat = format; stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; stream_.deviceInterleaved[mode] = true; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] || stream_.nUserChannels != stream_.nDeviceChannels ) stream_.doConvertBuffer[mode] = true; else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 ); // Allocate necessary internal buffers bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 ); if ( !stream_.userBuffer[mode] ) { errorType = RtAudioError::MEMORY_ERROR; errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory."; goto Exit; } if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) stream_.callbackInfo.priority = 15; else stream_.callbackInfo.priority = 0; ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback ///! TODO: RTAUDIO_HOG_DEVICE // Exclusive mode methodResult = SUCCESS; Exit: //clean up SAFE_RELEASE( captureDevices ); SAFE_RELEASE( renderDevices ); SAFE_RELEASE( devicePtr ); CoTaskMemFree( deviceFormat ); // if method failed, close the stream if ( methodResult == FAILURE ) closeStream(); if ( !errorText_.empty() ) error( errorType ); return methodResult; } //============================================================================= DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr ) { if ( wasapiPtr ) ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread(); return 0; } DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr ) { if ( wasapiPtr ) ( ( RtApiWasapi* ) wasapiPtr )->stopStream(); return 0; } DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr ) { if ( wasapiPtr ) ( ( RtApiWasapi* ) wasapiPtr )->abortStream(); return 0; } //----------------------------------------------------------------------------- void RtApiWasapi::wasapiThread() { // as this is a new thread, we must CoInitialize it CoInitialize( NULL ); HRESULT hr; IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient; IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient; IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient; IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient; HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent; HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent; WAVEFORMATEX* captureFormat = NULL; WAVEFORMATEX* renderFormat = NULL; float captureSrRatio = 0.0f; float renderSrRatio = 0.0f; WasapiBuffer captureBuffer; WasapiBuffer renderBuffer; // declare local stream variables RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback; BYTE* streamBuffer = NULL; unsigned long captureFlags = 0; unsigned int bufferFrameCount = 0; unsigned int numFramesPadding = 0; unsigned int convBufferSize = 0; bool callbackPushed = false; bool callbackPulled = false; bool callbackStopped = false; int callbackResult = 0; // convBuffer is used to store converted buffers between WASAPI and the user char* convBuffer = NULL; unsigned int convBuffSize = 0; unsigned int deviceBuffSize = 0; errorText_.clear(); RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR; // Attempt to assign "Pro Audio" characteristic to thread HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" ); if ( AvrtDll ) { DWORD taskIndex = 0; TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" ); AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex ); FreeLibrary( AvrtDll ); } // start capture stream if applicable if ( captureAudioClient ) { hr = captureAudioClient->GetMixFormat( &captureFormat ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format."; goto Exit; } captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate ); // initialize capture stream according to desire buffer size float desiredBufferSize = stream_.bufferSize * captureSrRatio; REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec ); if ( !captureClient ) { hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, desiredBufferPeriod, desiredBufferPeriod, captureFormat, NULL ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client."; goto Exit; } hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ), ( void** ) &captureClient ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle."; goto Exit; } // configure captureEvent to trigger on every available capture buffer captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if ( !captureEvent ) { errorType = RtAudioError::SYSTEM_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event."; goto Exit; } hr = captureAudioClient->SetEventHandle( captureEvent ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle."; goto Exit; } ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient; ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent; } unsigned int inBufferSize = 0; hr = captureAudioClient->GetBufferSize( &inBufferSize ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size."; goto Exit; } // scale outBufferSize according to stream->user sample rate ratio unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT]; inBufferSize *= stream_.nDeviceChannels[INPUT]; // set captureBuffer size captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) ); // reset the capture stream hr = captureAudioClient->Reset(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream."; goto Exit; } // start the capture stream hr = captureAudioClient->Start(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream."; goto Exit; } } // start render stream if applicable if ( renderAudioClient ) { hr = renderAudioClient->GetMixFormat( &renderFormat ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format."; goto Exit; } renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate ); // initialize render stream according to desire buffer size float desiredBufferSize = stream_.bufferSize * renderSrRatio; REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec ); if ( !renderClient ) { hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, desiredBufferPeriod, desiredBufferPeriod, renderFormat, NULL ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client."; goto Exit; } hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ), ( void** ) &renderClient ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle."; goto Exit; } // configure renderEvent to trigger on every available render buffer renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if ( !renderEvent ) { errorType = RtAudioError::SYSTEM_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event."; goto Exit; } hr = renderAudioClient->SetEventHandle( renderEvent ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle."; goto Exit; } ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient; ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent; } unsigned int outBufferSize = 0; hr = renderAudioClient->GetBufferSize( &outBufferSize ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size."; goto Exit; } // scale inBufferSize according to user->stream sample rate ratio unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT]; outBufferSize *= stream_.nDeviceChannels[OUTPUT]; // set renderBuffer size renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) ); // reset the render stream hr = renderAudioClient->Reset(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream."; goto Exit; } // start the render stream hr = renderAudioClient->Start(); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream."; goto Exit; } } if ( stream_.mode == INPUT ) { convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ); deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ); } else if ( stream_.mode == OUTPUT ) { convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ); deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ); } else if ( stream_.mode == DUPLEX ) { convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ), ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) ); deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ), stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) ); } convBuffer = ( char* ) malloc( convBuffSize ); stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize ); if ( !convBuffer || !stream_.deviceBuffer ) { errorType = RtAudioError::MEMORY_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory."; goto Exit; } // stream process loop while ( stream_.state != STREAM_STOPPING ) { if ( !callbackPulled ) { // Callback Input // ============== // 1. Pull callback buffer from inputBuffer // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count // Convert callback buffer to user format if ( captureAudioClient ) { // Pull callback buffer from inputBuffer callbackPulled = captureBuffer.pullBuffer( convBuffer, ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT], stream_.deviceFormat[INPUT] ); if ( callbackPulled ) { // Convert callback buffer to user sample rate convertBufferWasapi( stream_.deviceBuffer, convBuffer, stream_.nDeviceChannels[INPUT], captureFormat->nSamplesPerSec, stream_.sampleRate, ( unsigned int ) ( stream_.bufferSize * captureSrRatio ), convBufferSize, stream_.deviceFormat[INPUT] ); if ( stream_.doConvertBuffer[INPUT] ) { // Convert callback buffer to user format convertBuffer( stream_.userBuffer[INPUT], stream_.deviceBuffer, stream_.convertInfo[INPUT] ); } else { // no further conversion, simple copy deviceBuffer to userBuffer memcpy( stream_.userBuffer[INPUT], stream_.deviceBuffer, stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) ); } } } else { // if there is no capture stream, set callbackPulled flag callbackPulled = true; } // Execute Callback // ================ // 1. Execute user callback method // 2. Handle return value from callback // if callback has not requested the stream to stop if ( callbackPulled && !callbackStopped ) { // Execute user callback method callbackResult = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT], stream_.bufferSize, getStreamTime(), captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0, stream_.callbackInfo.userData ); // Handle return value from callback if ( callbackResult == 1 ) { // instantiate a thread to stop this thread HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL ); if ( !threadHandle ) { errorType = RtAudioError::THREAD_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread."; goto Exit; } else if ( !CloseHandle( threadHandle ) ) { errorType = RtAudioError::THREAD_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle."; goto Exit; } callbackStopped = true; } else if ( callbackResult == 2 ) { // instantiate a thread to stop this thread HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL ); if ( !threadHandle ) { errorType = RtAudioError::THREAD_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread."; goto Exit; } else if ( !CloseHandle( threadHandle ) ) { errorType = RtAudioError::THREAD_ERROR; errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle."; goto Exit; } callbackStopped = true; } } } // Callback Output // =============== // 1. Convert callback buffer to stream format // 2. Convert callback buffer to stream sample rate and channel count // 3. Push callback buffer into outputBuffer if ( renderAudioClient && callbackPulled ) { if ( stream_.doConvertBuffer[OUTPUT] ) { // Convert callback buffer to stream format convertBuffer( stream_.deviceBuffer, stream_.userBuffer[OUTPUT], stream_.convertInfo[OUTPUT] ); } // Convert callback buffer to stream sample rate convertBufferWasapi( convBuffer, stream_.deviceBuffer, stream_.nDeviceChannels[OUTPUT], stream_.sampleRate, renderFormat->nSamplesPerSec, stream_.bufferSize, convBufferSize, stream_.deviceFormat[OUTPUT] ); // Push callback buffer into outputBuffer callbackPushed = renderBuffer.pushBuffer( convBuffer, convBufferSize * stream_.nDeviceChannels[OUTPUT], stream_.deviceFormat[OUTPUT] ); } else { // if there is no render stream, set callbackPushed flag callbackPushed = true; } // Stream Capture // ============== // 1. Get capture buffer from stream // 2. Push capture buffer into inputBuffer // 3. If 2. was successful: Release capture buffer if ( captureAudioClient ) { // if the callback input buffer was not pulled from captureBuffer, wait for next capture event if ( !callbackPulled ) { WaitForSingleObject( captureEvent, INFINITE ); } // Get capture buffer from stream hr = captureClient->GetBuffer( &streamBuffer, &bufferFrameCount, &captureFlags, NULL, NULL ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer."; goto Exit; } if ( bufferFrameCount != 0 ) { // Push capture buffer into inputBuffer if ( captureBuffer.pushBuffer( ( char* ) streamBuffer, bufferFrameCount * stream_.nDeviceChannels[INPUT], stream_.deviceFormat[INPUT] ) ) { // Release capture buffer hr = captureClient->ReleaseBuffer( bufferFrameCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer."; goto Exit; } } else { // Inform WASAPI that capture was unsuccessful hr = captureClient->ReleaseBuffer( 0 ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer."; goto Exit; } } } else { // Inform WASAPI that capture was unsuccessful hr = captureClient->ReleaseBuffer( 0 ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer."; goto Exit; } } } // Stream Render // ============= // 1. Get render buffer from stream // 2. Pull next buffer from outputBuffer // 3. If 2. was successful: Fill render buffer with next buffer // Release render buffer if ( renderAudioClient ) { // if the callback output buffer was not pushed to renderBuffer, wait for next render event if ( callbackPulled && !callbackPushed ) { WaitForSingleObject( renderEvent, INFINITE ); } // Get render buffer from stream hr = renderAudioClient->GetBufferSize( &bufferFrameCount ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size."; goto Exit; } hr = renderAudioClient->GetCurrentPadding( &numFramesPadding ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding."; goto Exit; } bufferFrameCount -= numFramesPadding; if ( bufferFrameCount != 0 ) { hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer."; goto Exit; } // Pull next buffer from outputBuffer // Fill render buffer with next buffer if ( renderBuffer.pullBuffer( ( char* ) streamBuffer, bufferFrameCount * stream_.nDeviceChannels[OUTPUT], stream_.deviceFormat[OUTPUT] ) ) { // Release render buffer hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer."; goto Exit; } } else { // Inform WASAPI that render was unsuccessful hr = renderClient->ReleaseBuffer( 0, 0 ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer."; goto Exit; } } } else { // Inform WASAPI that render was unsuccessful hr = renderClient->ReleaseBuffer( 0, 0 ); if ( FAILED( hr ) ) { errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer."; goto Exit; } } } // if the callback buffer was pushed renderBuffer reset callbackPulled flag if ( callbackPushed ) { callbackPulled = false; } // tick stream time RtApi::tickStreamTime(); } Exit: // clean up CoTaskMemFree( captureFormat ); CoTaskMemFree( renderFormat ); free ( convBuffer ); CoUninitialize(); // update stream state stream_.state = STREAM_STOPPED; if ( errorText_.empty() ) return; else error( errorType ); } //******************** End of __WINDOWS_WASAPI__ *********************// #endif #if defined(__WINDOWS_DS__) // Windows DirectSound API // Modified by Robin Davies, October 2005 // - Improvements to DirectX pointer chasing. // - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30. // - Auto-call CoInitialize for DSOUND and ASIO platforms. // Various revisions for RtAudio 4.0 by Gary Scavone, April 2007 // Changed device query structure for RtAudio 4.0.7, January 2010 #include #include #include #if defined(__MINGW32__) // missing from latest mingw winapi #define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */ #define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */ #define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */ #define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */ #endif #define MINIMUM_DEVICE_BUFFER_SIZE 32768 #ifdef _MSC_VER // if Microsoft Visual C++ #pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually. #endif static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize ) { if ( pointer > bufferSize ) pointer -= bufferSize; if ( laterPointer < earlierPointer ) laterPointer += bufferSize; if ( pointer < earlierPointer ) pointer += bufferSize; return pointer >= earlierPointer && pointer < laterPointer; } // A structure to hold various information related to the DirectSound // API implementation. struct DsHandle { unsigned int drainCounter; // Tracks callback counts when draining bool internalDrain; // Indicates if stop is initiated from callback or not. void *id[2]; void *buffer[2]; bool xrun[2]; UINT bufferPointer[2]; DWORD dsBufferSize[2]; DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by. HANDLE condition; DsHandle() :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; } }; // Declarations for utility functions, callbacks, and structures // specific to the DirectSound implementation. static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR description, LPCTSTR module, LPVOID lpContext ); static const char* getErrorString( int code ); static unsigned __stdcall callbackHandler( void *ptr ); struct DsDevice { LPGUID id[2]; bool validId[2]; bool found; std::string name; DsDevice() : found(false) { validId[0] = false; validId[1] = false; } }; struct DsProbeData { bool isInput; std::vector* dsDevices; }; RtApiDs :: RtApiDs() { // Dsound will run both-threaded. If CoInitialize fails, then just // accept whatever the mainline chose for a threading model. coInitialized_ = false; HRESULT hr = CoInitialize( NULL ); if ( !FAILED( hr ) ) coInitialized_ = true; } RtApiDs :: ~RtApiDs() { if ( coInitialized_ ) CoUninitialize(); // balanced call. if ( stream_.state != STREAM_CLOSED ) closeStream(); } // The DirectSound default output is always the first device. unsigned int RtApiDs :: getDefaultOutputDevice( void ) { return 0; } // The DirectSound default input is always the first input device, // which is the first capture device enumerated. unsigned int RtApiDs :: getDefaultInputDevice( void ) { return 0; } unsigned int RtApiDs :: getDeviceCount( void ) { // Set query flag for previously found devices to false, so that we // can check for any devices that have disappeared. for ( unsigned int i=0; i indices; for ( unsigned int i=0; i(dsDevices.size()); } RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; if ( dsDevices.size() == 0 ) { // Force a query of all devices getDeviceCount(); if ( dsDevices.size() == 0 ) { errorText_ = "RtApiDs::getDeviceInfo: no devices found!"; error( RtAudioError::INVALID_USE ); return info; } } if ( device >= dsDevices.size() ) { errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!"; error( RtAudioError::INVALID_USE ); return info; } HRESULT result; if ( dsDevices[ device ].validId[0] == false ) goto probeInput; LPDIRECTSOUND output; DSCAPS outCaps; result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto probeInput; } outCaps.dwSize = sizeof( outCaps ); result = output->GetCaps( &outCaps ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!"; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto probeInput; } // Get output channel information. info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1; // Get sample rate information. info.sampleRates.clear(); for ( unsigned int k=0; k= (unsigned int) outCaps.dwMinSecondarySampleRate && SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) info.sampleRates.push_back( SAMPLE_RATES[k] ); } // Get format information. if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16; if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8; output->Release(); if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true; if ( dsDevices[ device ].validId[1] == false ) { info.name = dsDevices[ device ].name; info.probed = true; return info; } probeInput: LPDIRECTSOUNDCAPTURE input; result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } DSCCAPS inCaps; inCaps.dwSize = sizeof( inCaps ); result = input->GetCaps( &inCaps ); if ( FAILED( result ) ) { input->Release(); errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Get input channel information. info.inputChannels = inCaps.dwChannels; // Get sample rate and format information. std::vector rates; if ( inCaps.dwChannels >= 2 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( info.nativeFormats & RTAUDIO_SINT16 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 ); } else if ( info.nativeFormats & RTAUDIO_SINT8 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 ); } } else if ( inCaps.dwChannels == 1 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16; if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8; if ( info.nativeFormats & RTAUDIO_SINT16 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 ); } else if ( info.nativeFormats & RTAUDIO_SINT8 ) { if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 ); if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 ); if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 ); if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 ); } } else info.inputChannels = 0; // technically, this would be an error input->Release(); if ( info.inputChannels == 0 ) return info; // Copy the supported rates to the info structure but avoid duplication. bool found; for ( unsigned int i=0; i 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; if ( device == 0 ) info.isDefaultInput = true; // Copy name and return. info.name = dsDevices[ device ].name; info.probed = true; return info; } bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) { if ( channels + firstChannel > 2 ) { errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device."; return FAILURE; } size_t nDevices = dsDevices.size(); if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiDs::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!"; return FAILURE; } if ( mode == OUTPUT ) { if ( dsDevices[ device ].validId[0] == false ) { errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!"; errorText_ = errorStream_.str(); return FAILURE; } } else { // mode == INPUT if ( dsDevices[ device ].validId[1] == false ) { errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!"; errorText_ = errorStream_.str(); return FAILURE; } } // According to a note in PortAudio, using GetDesktopWindow() // instead of GetForegroundWindow() is supposed to avoid problems // that occur when the application's window is not the foreground // window. Also, if the application window closes before the // DirectSound buffer, DirectSound can crash. In the past, I had // problems when using GetDesktopWindow() but it seems fine now // (January 2010). I'll leave it commented here. // HWND hWnd = GetForegroundWindow(); HWND hWnd = GetDesktopWindow(); // Check the numberOfBuffers parameter and limit the lowest value to // two. This is a judgement call and a value of two is probably too // low for capture, but it should work for playback. int nBuffers = 0; if ( options ) nBuffers = options->numberOfBuffers; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2; if ( nBuffers < 2 ) nBuffers = 3; // Check the lower range of the user-specified buffer size and set // (arbitrarily) to a lower bound of 32. if ( *bufferSize < 32 ) *bufferSize = 32; // Create the wave format structure. The data format setting will // be determined later. WAVEFORMATEX waveFormat; ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) ); waveFormat.wFormatTag = WAVE_FORMAT_PCM; waveFormat.nChannels = channels + firstChannel; waveFormat.nSamplesPerSec = (unsigned long) sampleRate; // Determine the device buffer size. By default, we'll use the value // defined above (32K), but we will grow it to make allowances for // very large software buffer sizes. DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE; DWORD dsPointerLeadTime = 0; void *ohandle = 0, *bhandle = 0; HRESULT result; if ( mode == OUTPUT ) { LPDIRECTSOUND output; result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } DSCAPS outCaps; outCaps.dwSize = sizeof( outCaps ); result = output->GetCaps( &outCaps ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Check channel information. if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) { errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback."; errorText_ = errorStream_.str(); return FAILURE; } // Check format information. Use 16-bit format unless not // supported or user requests 8-bit. if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT && !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) { waveFormat.wBitsPerSample = 16; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } else { waveFormat.wBitsPerSample = 8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } stream_.userFormat = format; // Update wave format structure and buffer information. waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels; // If the user wants an even bigger buffer, increase the device buffer size accordingly. while ( dsPointerLeadTime * 2U > dsBufferSize ) dsBufferSize *= 2; // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes. // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE ); // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes. result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Even though we will write to the secondary buffer, we need to // access the primary buffer to set the correct output format // (since the default is 8-bit, 22 kHz!). Setup the DS primary // buffer description. DSBUFFERDESC bufferDescription; ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) ); bufferDescription.dwSize = sizeof( DSBUFFERDESC ); bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; // Obtain the primary buffer LPDIRECTSOUNDBUFFER buffer; result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Set the primary DS buffer sound format. result = buffer->SetFormat( &waveFormat ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Setup the secondary DS buffer description. ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) ); bufferDescription.dwSize = sizeof( DSBUFFERDESC ); bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE ); // Force hardware mixing bufferDescription.dwBufferBytes = dsBufferSize; bufferDescription.lpwfxFormat = &waveFormat; // Try to create the secondary DS buffer. If that doesn't work, // try to use software mixing. Otherwise, there's a problem. result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE ); // Force software mixing result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { output->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } } // Get the buffer size ... might be different from what we specified. DSBCAPS dsbcaps; dsbcaps.dwSize = sizeof( DSBCAPS ); result = buffer->GetCaps( &dsbcaps ); if ( FAILED( result ) ) { output->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } dsBufferSize = dsbcaps.dwBufferBytes; // Lock the DS buffer LPVOID audioPtr; DWORD dataLen; result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { output->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Zero the DS buffer ZeroMemory( audioPtr, dataLen ); // Unlock the DS buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { output->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } ohandle = (void *) output; bhandle = (void *) buffer; } if ( mode == INPUT ) { LPDIRECTSOUNDCAPTURE input; result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } DSCCAPS inCaps; inCaps.dwSize = sizeof( inCaps ); result = input->GetCaps( &inCaps ); if ( FAILED( result ) ) { input->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Check channel information. if ( inCaps.dwChannels < channels + firstChannel ) { errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels."; return FAILURE; } // Check format information. Use 16-bit format unless user // requests 8-bit. DWORD deviceFormats; if ( channels + firstChannel == 2 ) { deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08; if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) { waveFormat.wBitsPerSample = 8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } else { // assume 16-bit is supported waveFormat.wBitsPerSample = 16; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } } else { // channel == 1 deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08; if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) { waveFormat.wBitsPerSample = 8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } else { // assume 16-bit is supported waveFormat.wBitsPerSample = 16; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } } stream_.userFormat = format; // Update wave format structure and buffer information. waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels; // If the user wants an even bigger buffer, increase the device buffer size accordingly. while ( dsPointerLeadTime * 2U > dsBufferSize ) dsBufferSize *= 2; // Setup the secondary DS buffer description. DSCBUFFERDESC bufferDescription; ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) ); bufferDescription.dwSize = sizeof( DSCBUFFERDESC ); bufferDescription.dwFlags = 0; bufferDescription.dwReserved = 0; bufferDescription.dwBufferBytes = dsBufferSize; bufferDescription.lpwfxFormat = &waveFormat; // Create the capture buffer. LPDIRECTSOUNDCAPTUREBUFFER buffer; result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL ); if ( FAILED( result ) ) { input->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Get the buffer size ... might be different from what we specified. DSCBCAPS dscbcaps; dscbcaps.dwSize = sizeof( DSCBCAPS ); result = buffer->GetCaps( &dscbcaps ); if ( FAILED( result ) ) { input->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } dsBufferSize = dscbcaps.dwBufferBytes; // NOTE: We could have a problem here if this is a duplex stream // and the play and capture hardware buffer sizes are different // (I'm actually not sure if that is a problem or not). // Currently, we are not verifying that. // Lock the capture buffer LPVOID audioPtr; DWORD dataLen; result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { input->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } // Zero the buffer ZeroMemory( audioPtr, dataLen ); // Unlock the buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { input->Release(); buffer->Release(); errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!"; errorText_ = errorStream_.str(); return FAILURE; } ohandle = (void *) input; bhandle = (void *) buffer; } // Set various stream parameters DsHandle *handle = 0; stream_.nDeviceChannels[mode] = channels + firstChannel; stream_.nUserChannels[mode] = channels; stream_.bufferSize = *bufferSize; stream_.channelOffset[mode] = firstChannel; stream_.deviceInterleaved[mode] = true; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; // Set flag for buffer conversion stream_.doConvertBuffer[mode] = false; if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode]) stream_.doConvertBuffer[mode] = true; if (stream_.userFormat != stream_.deviceFormat[mode]) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate necessary internal buffers long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= (long) bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } // Allocate our DsHandle structures for the stream. if ( stream_.apiHandle == 0 ) { try { handle = new DsHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory."; goto error; } // Create a manual-reset event. handle->condition = CreateEvent( NULL, // no security TRUE, // manual-reset FALSE, // non-signaled initially NULL ); // unnamed stream_.apiHandle = (void *) handle; } else handle = (DsHandle *) stream_.apiHandle; handle->id[mode] = ohandle; handle->buffer[mode] = bhandle; handle->dsBufferSize[mode] = dsBufferSize; handle->dsPointerLeadTime[mode] = dsPointerLeadTime; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; if ( stream_.mode == OUTPUT && mode == INPUT ) // We had already set up an output stream. stream_.mode = DUPLEX; else stream_.mode = mode; stream_.nBuffers = nBuffers; stream_.sampleRate = sampleRate; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); // Setup the callback thread. if ( stream_.callbackInfo.isRunning == false ) { unsigned threadId; stream_.callbackInfo.isRunning = true; stream_.callbackInfo.object = (void *) this; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler, &stream_.callbackInfo, 0, &threadId ); if ( stream_.callbackInfo.thread == 0 ) { errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!"; goto error; } // Boost DS thread priority SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST ); } return SUCCESS; error: if ( handle ) { if ( handle->buffer[0] ) { // the object pointer can be NULL and valid LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0]; LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; if ( buffer ) buffer->Release(); object->Release(); } if ( handle->buffer[1] ) { LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1]; LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; if ( buffer ) buffer->Release(); object->Release(); } CloseHandle( handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.state = STREAM_CLOSED; return FAILURE; } void RtApiDs :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiDs::closeStream(): no open stream to close!"; error( RtAudioError::WARNING ); return; } // Stop the callback thread. stream_.callbackInfo.isRunning = false; WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE ); CloseHandle( (HANDLE) stream_.callbackInfo.thread ); DsHandle *handle = (DsHandle *) stream_.apiHandle; if ( handle ) { if ( handle->buffer[0] ) { // the object pointer can be NULL and valid LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0]; LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; if ( buffer ) { buffer->Stop(); buffer->Release(); } object->Release(); } if ( handle->buffer[1] ) { LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1]; LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; if ( buffer ) { buffer->Stop(); buffer->Release(); } object->Release(); } CloseHandle( handle->condition ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiDs :: startStream() { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiDs::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } DsHandle *handle = (DsHandle *) stream_.apiHandle; // Increase scheduler frequency on lesser windows (a side-effect of // increasing timer accuracy). On greater windows (Win2K or later), // this is already in effect. timeBeginPeriod( 1 ); buffersRolling = false; duplexPrerollBytes = 0; if ( stream_.mode == DUPLEX ) { // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize. duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] ); } HRESULT result = 0; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; result = buffer->Play( 0, 0, DSBPLAY_LOOPING ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!"; errorText_ = errorStream_.str(); goto unlock; } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; result = buffer->Start( DSCBSTART_LOOPING ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!"; errorText_ = errorStream_.str(); goto unlock; } } handle->drainCounter = 0; handle->internalDrain = false; ResetEvent( handle->condition ); stream_.state = STREAM_RUNNING; unlock: if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR ); } void RtApiDs :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiDs::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } HRESULT result = 0; LPVOID audioPtr; DWORD dataLen; DsHandle *handle = (DsHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( handle->drainCounter == 0 ) { handle->drainCounter = 2; WaitForSingleObject( handle->condition, INFINITE ); // block until signaled } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); // Stop the buffer and clear memory LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; result = buffer->Stop(); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Lock the buffer and clear it so that if we start to play again, // we won't have old data playing. result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Zero the DS buffer ZeroMemory( audioPtr, dataLen ); // Unlock the DS buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!"; errorText_ = errorStream_.str(); goto unlock; } // If we start playing again, we must begin at beginning of buffer. handle->bufferPointer[0] = 0; } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; audioPtr = NULL; dataLen = 0; stream_.state = STREAM_STOPPED; if ( stream_.mode != DUPLEX ) MUTEX_LOCK( &stream_.mutex ); result = buffer->Stop(); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Lock the buffer and clear it so that if we start to play again, // we won't have old data playing. result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!"; errorText_ = errorStream_.str(); goto unlock; } // Zero the DS buffer ZeroMemory( audioPtr, dataLen ); // Unlock the DS buffer result = buffer->Unlock( audioPtr, dataLen, NULL, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!"; errorText_ = errorStream_.str(); goto unlock; } // If we start recording again, we must begin at beginning of buffer. handle->bufferPointer[1] = 0; } unlock: timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows. MUTEX_UNLOCK( &stream_.mutex ); if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR ); } void RtApiDs :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiDs::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } DsHandle *handle = (DsHandle *) stream_.apiHandle; handle->drainCounter = 2; stopStream(); } void RtApiDs :: callbackEvent() { if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) { Sleep( 50 ); // sleep 50 milliseconds return; } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtAudioError::WARNING ); return; } CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; DsHandle *handle = (DsHandle *) stream_.apiHandle; // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > stream_.nBuffers + 2 ) { stream_.state = STREAM_STOPPING; if ( handle->internalDrain == false ) SetEvent( handle->condition ); else stopStream(); return; } // Invoke user callback to get fresh output data UNLESS we are // draining stream. if ( handle->drainCounter == 0 ) { RtAudioCallback callback = (RtAudioCallback) info->callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); if ( cbReturnValue == 2 ) { stream_.state = STREAM_STOPPING; handle->drainCounter = 2; abortStream(); return; } else if ( cbReturnValue == 1 ) { handle->drainCounter = 1; handle->internalDrain = true; } } HRESULT result; DWORD currentWritePointer, safeWritePointer; DWORD currentReadPointer, safeReadPointer; UINT nextWritePointer; LPVOID buffer1 = NULL; LPVOID buffer2 = NULL; DWORD bufferSize1 = 0; DWORD bufferSize2 = 0; char *buffer; long bufferBytes; MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } if ( buffersRolling == false ) { if ( stream_.mode == DUPLEX ) { //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] ); // It takes a while for the devices to get rolling. As a result, // there's no guarantee that the capture and write device pointers // will move in lockstep. Wait here for both devices to start // rolling, and then set our buffer pointers accordingly. // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600 // bytes later than the write buffer. // Stub: a serious risk of having a pre-emptive scheduling round // take place between the two GetCurrentPosition calls... but I'm // really not sure how to solve the problem. Temporarily boost to // Realtime priority, maybe; but I'm not sure what priority the // DirectSound service threads run at. We *should* be roughly // within a ms or so of correct. LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; DWORD startSafeWritePointer, startSafeReadPointer; result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } while ( true ) { result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break; Sleep( 1 ); } //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] ); handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0]; if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0]; handle->bufferPointer[1] = safeReadPointer; } else if ( stream_.mode == OUTPUT ) { // Set the proper nextWritePosition after initial startup. LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; result = dsWriteBuffer->GetCurrentPosition( ¤tWritePointer, &safeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0]; if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0]; } buffersRolling = true; } if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0]; if ( handle->drainCounter > 1 ) { // write zeros to the output stream bufferBytes = stream_.bufferSize * stream_.nUserChannels[0]; bufferBytes *= formatBytes( stream_.userFormat ); memset( stream_.userBuffer[0], 0, bufferBytes ); } // Setup parameters and do buffer conversion if necessary. if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0]; bufferBytes *= formatBytes( stream_.deviceFormat[0] ); } else { buffer = stream_.userBuffer[0]; bufferBytes = stream_.bufferSize * stream_.nUserChannels[0]; bufferBytes *= formatBytes( stream_.userFormat ); } // No byte swapping necessary in DirectSound implementation. // Ahhh ... windoze. 16-bit data is signed but 8-bit data is // unsigned. So, we need to convert our signed 8-bit data here to // unsigned. if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 ) for ( int i=0; idsBufferSize[0]; nextWritePointer = handle->bufferPointer[0]; DWORD endWrite, leadPointer; while ( true ) { // Find out where the read and "safe write" pointers are. result = dsBuffer->GetCurrentPosition( ¤tWritePointer, &safeWritePointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } // We will copy our output buffer into the region between // safeWritePointer and leadPointer. If leadPointer is not // beyond the next endWrite position, wait until it is. leadPointer = safeWritePointer + handle->dsPointerLeadTime[0]; //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl; if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize; if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset endWrite = nextWritePointer + bufferBytes; // Check whether the entire write region is behind the play pointer. if ( leadPointer >= endWrite ) break; // If we are here, then we must wait until the leadPointer advances // beyond the end of our next write region. We use the // Sleep() function to suspend operation until that happens. double millis = ( endWrite - leadPointer ) * 1000.0; millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate); if ( millis < 1.0 ) millis = 1.0; Sleep( (DWORD) millis ); } if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize ) || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { // We've strayed into the forbidden zone ... resync the read pointer. handle->xrun[0] = true; nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes; if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize; handle->bufferPointer[0] = nextWritePointer; endWrite = nextWritePointer + bufferBytes; } // Lock free space in the buffer result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1, &bufferSize1, &buffer2, &bufferSize2, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } // Copy our buffer into the DS buffer CopyMemory( buffer1, buffer, bufferSize1 ); if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 ); // Update our buffer offset and unlock sound buffer dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize; handle->bufferPointer[0] = nextWritePointer; } // Don't bother draining input if ( handle->drainCounter ) { handle->drainCounter++; goto unlock; } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { // Setup parameters. if ( stream_.doConvertBuffer[1] ) { buffer = stream_.deviceBuffer; bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1]; bufferBytes *= formatBytes( stream_.deviceFormat[1] ); } else { buffer = stream_.userBuffer[1]; bufferBytes = stream_.bufferSize * stream_.nUserChannels[1]; bufferBytes *= formatBytes( stream_.userFormat ); } LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1]; long nextReadPointer = handle->bufferPointer[1]; DWORD dsBufferSize = handle->dsBufferSize[1]; // Find out where the write and "safe read" pointers are. result = dsBuffer->GetCurrentPosition( ¤tReadPointer, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset DWORD endRead = nextReadPointer + bufferBytes; // Handling depends on whether we are INPUT or DUPLEX. // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode, // then a wait here will drag the write pointers into the forbidden zone. // // In DUPLEX mode, rather than wait, we will back off the read pointer until // it's in a safe position. This causes dropouts, but it seems to be the only // practical way to sync up the read and write pointers reliably, given the // the very complex relationship between phase and increment of the read and write // pointers. // // In order to minimize audible dropouts in DUPLEX mode, we will // provide a pre-roll period of 0.5 seconds in which we return // zeros from the read buffer while the pointers sync up. if ( stream_.mode == DUPLEX ) { if ( safeReadPointer < endRead ) { if ( duplexPrerollBytes <= 0 ) { // Pre-roll time over. Be more agressive. int adjustment = endRead-safeReadPointer; handle->xrun[1] = true; // Two cases: // - large adjustments: we've probably run out of CPU cycles, so just resync exactly, // and perform fine adjustments later. // - small adjustments: back off by twice as much. if ( adjustment >= 2*bufferBytes ) nextReadPointer = safeReadPointer-2*bufferBytes; else nextReadPointer = safeReadPointer-bufferBytes-adjustment; if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize; } else { // In pre=roll time. Just do it. nextReadPointer = safeReadPointer - bufferBytes; while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize; } endRead = nextReadPointer + bufferBytes; } } else { // mode == INPUT while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) { // See comments for playback. double millis = (endRead - safeReadPointer) * 1000.0; millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate); if ( millis < 1.0 ) millis = 1.0; Sleep( (DWORD) millis ); // Wake up and find out where we are now. result = dsBuffer->GetCurrentPosition( ¤tReadPointer, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset } } // Lock free space in the buffer result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1, &bufferSize1, &buffer2, &bufferSize2, 0 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } if ( duplexPrerollBytes <= 0 ) { // Copy our buffer into the DS buffer CopyMemory( buffer, buffer1, bufferSize1 ); if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 ); } else { memset( buffer, 0, bufferSize1 ); if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 ); duplexPrerollBytes -= bufferSize1 + bufferSize2; } // Update our buffer offset and unlock sound buffer nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize; dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!"; errorText_ = errorStream_.str(); error( RtAudioError::SYSTEM_ERROR ); return; } handle->bufferPointer[1] = nextReadPointer; // No byte swapping necessary in DirectSound implementation. // If necessary, convert 8-bit data from unsigned to signed. if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 ) for ( int j=0; jobject; bool* isRunning = &info->isRunning; while ( *isRunning == true ) { object->callbackEvent(); } _endthreadex( 0 ); return 0; } #include "tchar.h" static std::string convertTChar( LPCTSTR name ) { #if defined( UNICODE ) || defined( _UNICODE ) int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); std::string s( length-1, '\0' ); WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL); #else std::string s( name ); #endif return s; } static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR description, LPCTSTR /*module*/, LPVOID lpContext ) { struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext; std::vector& dsDevices = *probeInfo.dsDevices; HRESULT hr; bool validDevice = false; if ( probeInfo.isInput == true ) { DSCCAPS caps; LPDIRECTSOUNDCAPTURE object; hr = DirectSoundCaptureCreate( lpguid, &object, NULL ); if ( hr != DS_OK ) return TRUE; caps.dwSize = sizeof(caps); hr = object->GetCaps( &caps ); if ( hr == DS_OK ) { if ( caps.dwChannels > 0 && caps.dwFormats > 0 ) validDevice = true; } object->Release(); } else { DSCAPS caps; LPDIRECTSOUND object; hr = DirectSoundCreate( lpguid, &object, NULL ); if ( hr != DS_OK ) return TRUE; caps.dwSize = sizeof(caps); hr = object->GetCaps( &caps ); if ( hr == DS_OK ) { if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO ) validDevice = true; } object->Release(); } // If good device, then save its name and guid. std::string name = convertTChar( description ); //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" ) if ( lpguid == NULL ) name = "Default Device"; if ( validDevice ) { for ( unsigned int i=0; i #include // A structure to hold various information related to the ALSA API // implementation. struct AlsaHandle { snd_pcm_t *handles[2]; bool synchronized; bool xrun[2]; pthread_cond_t runnable_cv; bool runnable; AlsaHandle() :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; } }; static void *alsaCallbackHandler( void * ptr ); RtApiAlsa :: RtApiAlsa() { // Nothing to do here. } RtApiAlsa :: ~RtApiAlsa() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiAlsa :: getDeviceCount( void ) { unsigned nDevices = 0; int result, subdevice, card; char name[64]; snd_ctl_t *handle; // Count cards and devices card = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); result = snd_ctl_open( &handle, name, 0 ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto nextcard; } subdevice = -1; while( 1 ) { result = snd_ctl_pcm_next_device( handle, &subdevice ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); break; } if ( subdevice < 0 ) break; nDevices++; } nextcard: snd_ctl_close( handle ); snd_card_next( &card ); } result = snd_ctl_open( &handle, "default", 0 ); if (result == 0) { nDevices++; snd_ctl_close( handle ); } return nDevices; } RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; unsigned nDevices = 0; int result, subdevice, card; char name[64]; snd_ctl_t *chandle; // Count cards and devices card = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto nextcard; } subdevice = -1; while( 1 ) { result = snd_ctl_pcm_next_device( chandle, &subdevice ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); break; } if ( subdevice < 0 ) break; if ( nDevices == device ) { sprintf( name, "hw:%d,%d", card, subdevice ); goto foundDevice; } nDevices++; } nextcard: snd_ctl_close( chandle ); snd_card_next( &card ); } result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK ); if ( result == 0 ) { if ( nDevices == device ) { strcpy( name, "default" ); goto foundDevice; } nDevices++; } if ( nDevices == 0 ) { errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!"; error( RtAudioError::INVALID_USE ); return info; } if ( device >= nDevices ) { errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!"; error( RtAudioError::INVALID_USE ); return info; } foundDevice: // If a stream is already open, we cannot probe the stream devices. // Thus, use the saved results. if ( stream_.state != STREAM_CLOSED && ( stream_.device[0] == device || stream_.device[1] == device ) ) { snd_ctl_close( chandle ); if ( device >= devices_.size() ) { errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened."; error( RtAudioError::WARNING ); return info; } return devices_[ device ]; } int openMode = SND_PCM_ASYNC; snd_pcm_stream_t stream; snd_pcm_info_t *pcminfo; snd_pcm_info_alloca( &pcminfo ); snd_pcm_t *phandle; snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca( ¶ms ); // First try for playback unless default device (which has subdev -1) stream = SND_PCM_STREAM_PLAYBACK; snd_pcm_info_set_stream( pcminfo, stream ); if ( subdevice != -1 ) { snd_pcm_info_set_device( pcminfo, subdevice ); snd_pcm_info_set_subdevice( pcminfo, 0 ); result = snd_ctl_pcm_info( chandle, pcminfo ); if ( result < 0 ) { // Device probably doesn't support playback. goto captureProbe; } } result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto captureProbe; } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any( phandle, params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto captureProbe; } // Get output channel information. unsigned int value; result = snd_pcm_hw_params_get_channels_max( params, &value ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); goto captureProbe; } info.outputChannels = value; snd_pcm_close( phandle ); captureProbe: stream = SND_PCM_STREAM_CAPTURE; snd_pcm_info_set_stream( pcminfo, stream ); // Now try for capture unless default device (with subdev = -1) if ( subdevice != -1 ) { result = snd_ctl_pcm_info( chandle, pcminfo ); snd_ctl_close( chandle ); if ( result < 0 ) { // Device probably doesn't support capture. if ( info.outputChannels == 0 ) return info; goto probeParameters; } } else snd_ctl_close( chandle ); result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); if ( info.outputChannels == 0 ) return info; goto probeParameters; } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any( phandle, params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); if ( info.outputChannels == 0 ) return info; goto probeParameters; } result = snd_pcm_hw_params_get_channels_max( params, &value ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); if ( info.outputChannels == 0 ) return info; goto probeParameters; } info.inputChannels = value; snd_pcm_close( phandle ); // If device opens for both playback and capture, we determine the channels. if ( info.outputChannels > 0 && info.inputChannels > 0 ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; // ALSA doesn't provide default devices so we'll use the first available one. if ( device == 0 && info.outputChannels > 0 ) info.isDefaultOutput = true; if ( device == 0 && info.inputChannels > 0 ) info.isDefaultInput = true; probeParameters: // At this point, we just need to figure out the supported data // formats and sample rates. We'll proceed by opening the device in // the direction with the maximum number of channels, or playback if // they are equal. This might limit our sample rate options, but so // be it. if ( info.outputChannels >= info.inputChannels ) stream = SND_PCM_STREAM_PLAYBACK; else stream = SND_PCM_STREAM_CAPTURE; snd_pcm_info_set_stream( pcminfo, stream ); result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK); if ( result < 0 ) { errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // The device is open ... fill the parameter structure. result = snd_pcm_hw_params_any( phandle, params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Test our discrete set of sample rate values. info.sampleRates.clear(); for ( unsigned int i=0; i= 0 ) { sprintf( name, "hw:%s,%d", cardname, subdevice ); free( cardname ); } info.name = name; // That's all ... close the device and return snd_pcm_close( phandle ); info.probed = true; return info; } void RtApiAlsa :: saveDeviceInfo( void ) { devices_.clear(); unsigned int nDevices = getDeviceCount(); devices_.resize( nDevices ); for ( unsigned int i=0; iflags & RTAUDIO_ALSA_USE_DEFAULT ) snprintf(name, sizeof(name), "%s", "default"); else { // Count cards and devices card = -1; snd_card_next( &card ); while ( card >= 0 ) { sprintf( name, "hw:%d", card ); result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } subdevice = -1; while( 1 ) { result = snd_ctl_pcm_next_device( chandle, &subdevice ); if ( result < 0 ) break; if ( subdevice < 0 ) break; if ( nDevices == device ) { sprintf( name, "hw:%d,%d", card, subdevice ); snd_ctl_close( chandle ); goto foundDevice; } nDevices++; } snd_ctl_close( chandle ); snd_card_next( &card ); } result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK ); if ( result == 0 ) { if ( nDevices == device ) { strcpy( name, "default" ); goto foundDevice; } nDevices++; } if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!"; return FAILURE; } } foundDevice: // The getDeviceInfo() function will not work for a device that is // already open. Thus, we'll probe the system before opening a // stream and save the results for use by getDeviceInfo(). if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once this->saveDeviceInfo(); snd_pcm_stream_t stream; if ( mode == OUTPUT ) stream = SND_PCM_STREAM_PLAYBACK; else stream = SND_PCM_STREAM_CAPTURE; snd_pcm_t *phandle; int openMode = SND_PCM_ASYNC; result = snd_pcm_open( &phandle, name, stream, openMode ); if ( result < 0 ) { if ( mode == OUTPUT ) errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output."; else errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input."; errorText_ = errorStream_.str(); return FAILURE; } // Fill the parameter structure. snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_alloca( &hw_params ); result = snd_pcm_hw_params_any( phandle, hw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } #if defined(__RTAUDIO_DEBUG__) fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" ); snd_pcm_hw_params_dump( hw_params, out ); #endif // Set access ... check user preference. if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) { stream_.userInterleaved = false; result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED ); if ( result < 0 ) { result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ); stream_.deviceInterleaved[mode] = true; } else stream_.deviceInterleaved[mode] = false; } else { stream_.userInterleaved = true; result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ); if ( result < 0 ) { result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED ); stream_.deviceInterleaved[mode] = false; } else stream_.deviceInterleaved[mode] = true; } if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Determine how to set the device format. stream_.userFormat = format; snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN; if ( format == RTAUDIO_SINT8 ) deviceFormat = SND_PCM_FORMAT_S8; else if ( format == RTAUDIO_SINT16 ) deviceFormat = SND_PCM_FORMAT_S16; else if ( format == RTAUDIO_SINT24 ) deviceFormat = SND_PCM_FORMAT_S24; else if ( format == RTAUDIO_SINT32 ) deviceFormat = SND_PCM_FORMAT_S32; else if ( format == RTAUDIO_FLOAT32 ) deviceFormat = SND_PCM_FORMAT_FLOAT; else if ( format == RTAUDIO_FLOAT64 ) deviceFormat = SND_PCM_FORMAT_FLOAT64; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) { stream_.deviceFormat[mode] = format; goto setFormat; } // The user requested format is not natively supported by the device. deviceFormat = SND_PCM_FORMAT_FLOAT64; if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT64; goto setFormat; } deviceFormat = SND_PCM_FORMAT_FLOAT; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S32; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT32; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S24; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT24; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S16; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT16; goto setFormat; } deviceFormat = SND_PCM_FORMAT_S8; if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) { stream_.deviceFormat[mode] = RTAUDIO_SINT8; goto setFormat; } // If we get here, no supported format was found. snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; setFormat: result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Determine whether byte-swaping is necessary. stream_.doByteSwap[mode] = false; if ( deviceFormat != SND_PCM_FORMAT_S8 ) { result = snd_pcm_format_cpu_endian( deviceFormat ); if ( result == 0 ) stream_.doByteSwap[mode] = true; else if (result < 0) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } } // Set the sample rate. result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Determine the number of channels for this device. We support a possible // minimum device channel number > than the value requested by the user. stream_.nUserChannels[mode] = channels; unsigned int value; result = snd_pcm_hw_params_get_channels_max( hw_params, &value ); unsigned int deviceChannels = value; if ( result < 0 || deviceChannels < channels + firstChannel ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } result = snd_pcm_hw_params_get_channels_min( hw_params, &value ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } deviceChannels = value; if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel; stream_.nDeviceChannels[mode] = deviceChannels; // Set the device channels. result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // Set the buffer (or period) size. int dir = 0; snd_pcm_uframes_t periodSize = *bufferSize; result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } *bufferSize = periodSize; // Set the buffer number, which in ALSA is referred to as the "period". unsigned int periods = 0; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2; if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers; if ( periods < 2 ) periods = 4; // a fairly safe default value result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } // If attempting to setup a duplex stream, the bufferSize parameter // MUST be the same in both directions! if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.bufferSize = *bufferSize; // Install the hardware configuration result = snd_pcm_hw_params( phandle, hw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } #if defined(__RTAUDIO_DEBUG__) fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n"); snd_pcm_hw_params_dump( hw_params, out ); #endif // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns. snd_pcm_sw_params_t *sw_params = NULL; snd_pcm_sw_params_alloca( &sw_params ); snd_pcm_sw_params_current( phandle, sw_params ); snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize ); snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX ); snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 ); // The following two settings were suggested by Theo Veenker //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize ); //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 ); // here are two options for a fix //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX ); snd_pcm_uframes_t val; snd_pcm_sw_params_get_boundary( sw_params, &val ); snd_pcm_sw_params_set_silence_size( phandle, sw_params, val ); result = snd_pcm_sw_params( phandle, sw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); return FAILURE; } #if defined(__RTAUDIO_DEBUG__) fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n"); snd_pcm_sw_params_dump( sw_params, out ); #endif // Set flags for buffer conversion stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate the ApiHandle if necessary and then save. AlsaHandle *apiInfo = 0; if ( stream_.apiHandle == 0 ) { try { apiInfo = (AlsaHandle *) new AlsaHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory."; goto error; } if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) apiInfo; apiInfo->handles[0] = 0; apiInfo->handles[1] = 0; } else { apiInfo = (AlsaHandle *) stream_.apiHandle; } apiInfo->handles[mode] = phandle; phandle = 0; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.sampleRate = sampleRate; stream_.nBuffers = periods; stream_.device[mode] = device; stream_.state = STREAM_STOPPED; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); // Setup thread if necessary. if ( stream_.mode == OUTPUT && mode == INPUT ) { // We had already set up an output stream. stream_.mode = DUPLEX; // Link the streams if possible. apiInfo->synchronized = false; if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 ) apiInfo->synchronized = true; else { errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices."; error( RtAudioError::WARNING ); } } else { stream_.mode = mode; // Setup callback thread. stream_.callbackInfo.object = (void *) this; // Set the thread attributes for joinable and realtime scheduling // priority (optional). The higher priority will only take affect // if the program is run as root or suid. Note, under Linux // processes with CAP_SYS_NICE privilege, a user can change // scheduling policy and priority (thus need not be root). See // POSIX "capabilities". pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) { // We previously attempted to increase the audio callback priority // to SCHED_RR here via the attributes. However, while no errors // were reported in doing so, it did not work. So, now this is // done in the alsaCallbackHandler function. stream_.callbackInfo.doRealtime = true; int priority = options->priority; int min = sched_get_priority_min( SCHED_RR ); int max = sched_get_priority_max( SCHED_RR ); if ( priority < min ) priority = min; else if ( priority > max ) priority = max; stream_.callbackInfo.priority = priority; } #endif stream_.callbackInfo.isRunning = true; result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo ); pthread_attr_destroy( &attr ); if ( result ) { stream_.callbackInfo.isRunning = false; errorText_ = "RtApiAlsa::error creating callback thread!"; goto error; } } return SUCCESS; error: if ( apiInfo ) { pthread_cond_destroy( &apiInfo->runnable_cv ); if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] ); if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] ); delete apiInfo; stream_.apiHandle = 0; } if ( phandle) snd_pcm_close( phandle ); for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.state = STREAM_CLOSED; return FAILURE; } void RtApiAlsa :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAlsa::closeStream(): no open stream to close!"; error( RtAudioError::WARNING ); return; } AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; stream_.callbackInfo.isRunning = false; MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { apiInfo->runnable = true; pthread_cond_signal( &apiInfo->runnable_cv ); } MUTEX_UNLOCK( &stream_.mutex ); pthread_join( stream_.callbackInfo.thread, NULL ); if ( stream_.state == STREAM_RUNNING ) { stream_.state = STREAM_STOPPED; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) snd_pcm_drop( apiInfo->handles[0] ); if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) snd_pcm_drop( apiInfo->handles[1] ); } if ( apiInfo ) { pthread_cond_destroy( &apiInfo->runnable_cv ); if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] ); if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] ); delete apiInfo; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiAlsa :: startStream() { // This method calls snd_pcm_prepare if the device isn't already in that state. verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiAlsa::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); int result = 0; snd_pcm_state_t state; AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { state = snd_pcm_state( handle[0] ); if ( state != SND_PCM_STATE_PREPARED ) { result = snd_pcm_prepare( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } } if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) { result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open state = snd_pcm_state( handle[1] ); if ( state != SND_PCM_STATE_PREPARED ) { result = snd_pcm_prepare( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } } stream_.state = STREAM_RUNNING; unlock: apiInfo->runnable = true; pthread_cond_signal( &apiInfo->runnable_cv ); MUTEX_UNLOCK( &stream_.mutex ); if ( result >= 0 ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiAlsa :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); int result = 0; AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( apiInfo->synchronized ) result = snd_pcm_drop( handle[0] ); else result = snd_pcm_drain( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) { result = snd_pcm_drop( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } unlock: apiInfo->runnable = false; // fixes high CPU usage when stopped MUTEX_UNLOCK( &stream_.mutex ); if ( result >= 0 ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiAlsa :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); int result = 0; AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = snd_pcm_drop( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) { result = snd_pcm_drop( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); goto unlock; } } unlock: apiInfo->runnable = false; // fixes high CPU usage when stopped MUTEX_UNLOCK( &stream_.mutex ); if ( result >= 0 ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiAlsa :: callbackEvent() { AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; if ( stream_.state == STREAM_STOPPED ) { MUTEX_LOCK( &stream_.mutex ); while ( !apiInfo->runnable ) pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex ); if ( stream_.state != STREAM_RUNNING ) { MUTEX_UNLOCK( &stream_.mutex ); return; } MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtAudioError::WARNING ); return; } int doStopStream = 0; RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; apiInfo->xrun[0] = false; } if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; apiInfo->xrun[1] = false; } doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); if ( doStopStream == 2 ) { abortStream(); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) goto unlock; int result; char *buffer; int channels; snd_pcm_t **handle; snd_pcm_sframes_t frames; RtAudioFormat format; handle = (snd_pcm_t **) apiInfo->handles; if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { // Setup parameters. if ( stream_.doConvertBuffer[1] ) { buffer = stream_.deviceBuffer; channels = stream_.nDeviceChannels[1]; format = stream_.deviceFormat[1]; } else { buffer = stream_.userBuffer[1]; channels = stream_.nUserChannels[1]; format = stream_.userFormat; } // Read samples from device in interleaved/non-interleaved format. if ( stream_.deviceInterleaved[1] ) result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize ); else { void *bufs[channels]; size_t offset = stream_.bufferSize * formatBytes( format ); for ( int i=0; ixrun[1] = true; result = snd_pcm_prepare( handle[1] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } error( RtAudioError::WARNING ); goto tryOutput; } // Do byte swapping if necessary. if ( stream_.doByteSwap[1] ) byteSwapBuffer( buffer, stream_.bufferSize * channels, format ); // Do buffer conversion if necessary. if ( stream_.doConvertBuffer[1] ) convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); // Check stream latency result = snd_pcm_delay( handle[1], &frames ); if ( result == 0 && frames > 0 ) stream_.latency[1] = frames; } tryOutput: if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Setup parameters and do buffer conversion if necessary. if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); channels = stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer[0]; channels = stream_.nUserChannels[0]; format = stream_.userFormat; } // Do byte swapping if necessary. if ( stream_.doByteSwap[0] ) byteSwapBuffer(buffer, stream_.bufferSize * channels, format); // Write samples to device in interleaved/non-interleaved format. if ( stream_.deviceInterleaved[0] ) result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize ); else { void *bufs[channels]; size_t offset = stream_.bufferSize * formatBytes( format ); for ( int i=0; ixrun[0] = true; result = snd_pcm_prepare( handle[0] ); if ( result < 0 ) { errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } } else { errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << "."; errorText_ = errorStream_.str(); } error( RtAudioError::WARNING ); goto unlock; } // Check stream latency result = snd_pcm_delay( handle[0], &frames ); if ( result == 0 && frames > 0 ) stream_.latency[0] = frames; } unlock: MUTEX_UNLOCK( &stream_.mutex ); RtApi::tickStreamTime(); if ( doStopStream == 1 ) this->stopStream(); } static void *alsaCallbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiAlsa *object = (RtApiAlsa *) info->object; bool *isRunning = &info->isRunning; #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) if ( &info->doRealtime ) { pthread_t tID = pthread_self(); // ID of this thread sched_param prio = { info->priority }; // scheduling priority of thread pthread_setschedparam( tID, SCHED_RR, &prio ); } #endif while ( *isRunning == true ) { pthread_testcancel(); object->callbackEvent(); } pthread_exit( NULL ); } //******************** End of __LINUX_ALSA__ *********************// #endif #if defined(__LINUX_PULSE__) // Code written by Peter Meerwald, pmeerw@pmeerw.net // and Tristan Matthews. #include #include #include static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000, 44100, 48000, 96000, 0}; struct rtaudio_pa_format_mapping_t { RtAudioFormat rtaudio_format; pa_sample_format_t pa_format; }; static const rtaudio_pa_format_mapping_t supported_sampleformats[] = { {RTAUDIO_SINT16, PA_SAMPLE_S16LE}, {RTAUDIO_SINT32, PA_SAMPLE_S32LE}, {RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE}, {0, PA_SAMPLE_INVALID}}; struct PulseAudioHandle { pa_simple *s_play; pa_simple *s_rec; pthread_t thread; pthread_cond_t runnable_cv; bool runnable; PulseAudioHandle() : s_play(0), s_rec(0), runnable(false) { } }; RtApiPulse::~RtApiPulse() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiPulse::getDeviceCount( void ) { return 1; } RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; info.probed = true; info.name = "PulseAudio"; info.outputChannels = 2; info.inputChannels = 2; info.duplexChannels = 2; info.isDefaultOutput = true; info.isDefaultInput = true; for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) info.sampleRates.push_back( *sr ); info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32; return info; } static void *pulseaudio_callback( void * user ) { CallbackInfo *cbi = static_cast( user ); RtApiPulse *context = static_cast( cbi->object ); volatile bool *isRunning = &cbi->isRunning; while ( *isRunning ) { pthread_testcancel(); context->callbackEvent(); } pthread_exit( NULL ); } void RtApiPulse::closeStream( void ) { PulseAudioHandle *pah = static_cast( stream_.apiHandle ); stream_.callbackInfo.isRunning = false; if ( pah ) { MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) { pah->runnable = true; pthread_cond_signal( &pah->runnable_cv ); } MUTEX_UNLOCK( &stream_.mutex ); pthread_join( pah->thread, 0 ); if ( pah->s_play ) { pa_simple_flush( pah->s_play, NULL ); pa_simple_free( pah->s_play ); } if ( pah->s_rec ) pa_simple_free( pah->s_rec ); pthread_cond_destroy( &pah->runnable_cv ); delete pah; stream_.apiHandle = 0; } if ( stream_.userBuffer[0] ) { free( stream_.userBuffer[0] ); stream_.userBuffer[0] = 0; } if ( stream_.userBuffer[1] ) { free( stream_.userBuffer[1] ); stream_.userBuffer[1] = 0; } stream_.state = STREAM_CLOSED; stream_.mode = UNINITIALIZED; } void RtApiPulse::callbackEvent( void ) { PulseAudioHandle *pah = static_cast( stream_.apiHandle ); if ( stream_.state == STREAM_STOPPED ) { MUTEX_LOCK( &stream_.mutex ); while ( !pah->runnable ) pthread_cond_wait( &pah->runnable_cv, &stream_.mutex ); if ( stream_.state != STREAM_RUNNING ) { MUTEX_UNLOCK( &stream_.mutex ); return; } MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... " "this shouldn't happen!"; error( RtAudioError::WARNING ); return; } RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); if ( doStopStream == 2 ) { abortStream(); return; } MUTEX_LOCK( &stream_.mutex ); void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT]; void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT]; if ( stream_.state != STREAM_RUNNING ) goto unlock; int pa_error; size_t bytes; if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( stream_.doConvertBuffer[OUTPUT] ) { convertBuffer( stream_.deviceBuffer, stream_.userBuffer[OUTPUT], stream_.convertInfo[OUTPUT] ); bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize * formatBytes( stream_.deviceFormat[OUTPUT] ); } else bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize * formatBytes( stream_.userFormat ); if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) { errorStream_ << "RtApiPulse::callbackEvent: audio write error, " << pa_strerror( pa_error ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX) { if ( stream_.doConvertBuffer[INPUT] ) bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize * formatBytes( stream_.deviceFormat[INPUT] ); else bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize * formatBytes( stream_.userFormat ); if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) { errorStream_ << "RtApiPulse::callbackEvent: audio read error, " << pa_strerror( pa_error ) << "."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); } if ( stream_.doConvertBuffer[INPUT] ) { convertBuffer( stream_.userBuffer[INPUT], stream_.deviceBuffer, stream_.convertInfo[INPUT] ); } } unlock: MUTEX_UNLOCK( &stream_.mutex ); RtApi::tickStreamTime(); if ( doStopStream == 1 ) stopStream(); } void RtApiPulse::startStream( void ) { PulseAudioHandle *pah = static_cast( stream_.apiHandle ); if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiPulse::startStream(): the stream is not open!"; error( RtAudioError::INVALID_USE ); return; } if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiPulse::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); stream_.state = STREAM_RUNNING; pah->runnable = true; pthread_cond_signal( &pah->runnable_cv ); MUTEX_UNLOCK( &stream_.mutex ); } void RtApiPulse::stopStream( void ) { PulseAudioHandle *pah = static_cast( stream_.apiHandle ); if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiPulse::stopStream(): the stream is not open!"; error( RtAudioError::INVALID_USE ); return; } if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); if ( pah && pah->s_play ) { int pa_error; if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) { errorStream_ << "RtApiPulse::stopStream: error draining output device, " << pa_strerror( pa_error ) << "."; errorText_ = errorStream_.str(); MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } } stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); } void RtApiPulse::abortStream( void ) { PulseAudioHandle *pah = static_cast( stream_.apiHandle ); if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiPulse::abortStream(): the stream is not open!"; error( RtAudioError::INVALID_USE ); return; } if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); if ( pah && pah->s_play ) { int pa_error; if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) { errorStream_ << "RtApiPulse::abortStream: error flushing output device, " << pa_strerror( pa_error ) << "."; errorText_ = errorStream_.str(); MUTEX_UNLOCK( &stream_.mutex ); error( RtAudioError::SYSTEM_ERROR ); return; } } stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); } bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) { PulseAudioHandle *pah = 0; unsigned long bufferBytes = 0; pa_sample_spec ss; if ( device != 0 ) return false; if ( mode != INPUT && mode != OUTPUT ) return false; if ( channels != 1 && channels != 2 ) { errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels."; return false; } ss.channels = channels; if ( firstChannel != 0 ) return false; bool sr_found = false; for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) { if ( sampleRate == *sr ) { sr_found = true; stream_.sampleRate = sampleRate; ss.rate = sampleRate; break; } } if ( !sr_found ) { errorText_ = "RtApiPulse::probeDeviceOpen: unsupported sample rate."; return false; } bool sf_found = 0; for ( const rtaudio_pa_format_mapping_t *sf = supported_sampleformats; sf->rtaudio_format && sf->pa_format != PA_SAMPLE_INVALID; ++sf ) { if ( format == sf->rtaudio_format ) { sf_found = true; stream_.userFormat = sf->rtaudio_format; stream_.deviceFormat[mode] = stream_.userFormat; ss.format = sf->pa_format; break; } } if ( !sf_found ) { // Use internal data format conversion. stream_.userFormat = format; stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; ss.format = PA_SAMPLE_FLOAT32LE; } // Set other stream parameters. if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; else stream_.userInterleaved = true; stream_.deviceInterleaved[mode] = true; stream_.nBuffers = 1; stream_.doByteSwap[mode] = false; stream_.nUserChannels[mode] = channels; stream_.nDeviceChannels[mode] = channels + firstChannel; stream_.channelOffset[mode] = 0; std::string streamName = "RtAudio"; // Set flags for buffer conversion. stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; // Allocate necessary internal buffers. bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiPulse::probeDeviceOpen: error allocating user buffer memory."; goto error; } stream_.bufferSize = *bufferSize; if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.device[mode] = device; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); if ( !stream_.apiHandle ) { PulseAudioHandle *pah = new PulseAudioHandle; if ( !pah ) { errorText_ = "RtApiPulse::probeDeviceOpen: error allocating memory for handle."; goto error; } stream_.apiHandle = pah; if ( pthread_cond_init( &pah->runnable_cv, NULL ) != 0 ) { errorText_ = "RtApiPulse::probeDeviceOpen: error creating condition variable."; goto error; } } pah = static_cast( stream_.apiHandle ); int error; if ( !options->streamName.empty() ) streamName = options->streamName; switch ( mode ) { case INPUT: pa_buffer_attr buffer_attr; buffer_attr.fragsize = bufferBytes; buffer_attr.maxlength = -1; pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error ); if ( !pah->s_rec ) { errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server."; goto error; } break; case OUTPUT: pah->s_play = pa_simple_new( NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error ); if ( !pah->s_play ) { errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server."; goto error; } break; default: goto error; } if ( stream_.mode == UNINITIALIZED ) stream_.mode = mode; else if ( stream_.mode == mode ) goto error; else stream_.mode = DUPLEX; if ( !stream_.callbackInfo.isRunning ) { stream_.callbackInfo.object = this; stream_.callbackInfo.isRunning = true; if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) { errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread."; goto error; } } stream_.state = STREAM_STOPPED; return true; error: if ( pah && stream_.callbackInfo.isRunning ) { pthread_cond_destroy( &pah->runnable_cv ); delete pah; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } //******************** End of __LINUX_PULSE__ *********************// #endif #if defined(__LINUX_OSS__) #include #include #include #include #include #include #include static void *ossCallbackHandler(void * ptr); // A structure to hold various information related to the OSS API // implementation. struct OssHandle { int id[2]; // device ids bool xrun[2]; bool triggered; pthread_cond_t runnable; OssHandle() :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; } }; RtApiOss :: RtApiOss() { // Nothing to do here. } RtApiOss :: ~RtApiOss() { if ( stream_.state != STREAM_CLOSED ) closeStream(); } unsigned int RtApiOss :: getDeviceCount( void ) { int mixerfd = open( "/dev/mixer", O_RDWR, 0 ); if ( mixerfd == -1 ) { errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'."; error( RtAudioError::WARNING ); return 0; } oss_sysinfo sysinfo; if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required."; error( RtAudioError::WARNING ); return 0; } close( mixerfd ); return sysinfo.numaudios; } RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; info.probed = false; int mixerfd = open( "/dev/mixer", O_RDWR, 0 ); if ( mixerfd == -1 ) { errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'."; error( RtAudioError::WARNING ); return info; } oss_sysinfo sysinfo; int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ); if ( result == -1 ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required."; error( RtAudioError::WARNING ); return info; } unsigned nDevices = sysinfo.numaudios; if ( nDevices == 0 ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: no devices found!"; error( RtAudioError::INVALID_USE ); return info; } if ( device >= nDevices ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!"; error( RtAudioError::INVALID_USE ); return info; } oss_audioinfo ainfo; ainfo.dev = device; result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo ); close( mixerfd ); if ( result == -1 ) { errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Probe channels if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels; if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels; if ( ainfo.caps & PCM_CAP_DUPLEX ) { if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX ) info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; } // Probe data formats ... do for input unsigned long mask = ainfo.iformats; if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE ) info.nativeFormats |= RTAUDIO_SINT16; if ( mask & AFMT_S8 ) info.nativeFormats |= RTAUDIO_SINT8; if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE ) info.nativeFormats |= RTAUDIO_SINT32; if ( mask & AFMT_FLOAT ) info.nativeFormats |= RTAUDIO_FLOAT32; if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE ) info.nativeFormats |= RTAUDIO_SINT24; // Check that we have at least one supported format if ( info.nativeFormats == 0 ) { errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); return info; } // Probe the supported sample rates. info.sampleRates.clear(); if ( ainfo.nrates ) { for ( unsigned int i=0; i= (int) SAMPLE_RATES[k] ) info.sampleRates.push_back( SAMPLE_RATES[k] ); } } if ( info.sampleRates.size() == 0 ) { errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); error( RtAudioError::WARNING ); } else { info.probed = true; info.name = ainfo.name; } return info; } bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) { int mixerfd = open( "/dev/mixer", O_RDWR, 0 ); if ( mixerfd == -1 ) { errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'."; return FAILURE; } oss_sysinfo sysinfo; int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ); if ( result == -1 ) { close( mixerfd ); errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required."; return FAILURE; } unsigned nDevices = sysinfo.numaudios; if ( nDevices == 0 ) { // This should not happen because a check is made before this function is called. close( mixerfd ); errorText_ = "RtApiOss::probeDeviceOpen: no devices found!"; return FAILURE; } if ( device >= nDevices ) { // This should not happen because a check is made before this function is called. close( mixerfd ); errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!"; return FAILURE; } oss_audioinfo ainfo; ainfo.dev = device; result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo ); close( mixerfd ); if ( result == -1 ) { errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info."; errorText_ = errorStream_.str(); return FAILURE; } // Check if device supports input or output if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) || ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) { if ( mode == OUTPUT ) errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output."; else errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input."; errorText_ = errorStream_.str(); return FAILURE; } int flags = 0; OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( mode == OUTPUT ) flags |= O_WRONLY; else { // mode == INPUT if (stream_.mode == OUTPUT && stream_.device[0] == device) { // We just set the same device for playback ... close and reopen for duplex (OSS only). close( handle->id[0] ); handle->id[0] = 0; if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) { errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode."; errorText_ = errorStream_.str(); return FAILURE; } // Check that the number previously set channels is the same. if ( stream_.nUserChannels[0] != channels ) { errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } flags |= O_RDWR; } else flags |= O_RDONLY; } // Set exclusive access if specified. if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL; // Try to open the device. int fd; fd = open( ainfo.devnode, flags, 0 ); if ( fd == -1 ) { if ( errno == EBUSY ) errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy."; else errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } // For duplex operation, specifically set this mode (this doesn't seem to work). /* if ( flags | O_RDWR ) { result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL ); if ( result == -1) { errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } } */ // Check the device channel support. stream_.nUserChannels[mode] = channels; if ( ainfo.max_channels < (int)(channels + firstChannel) ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters."; errorText_ = errorStream_.str(); return FAILURE; } // Set the number of channels. int deviceChannels = channels + firstChannel; result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels ); if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.nDeviceChannels[mode] = deviceChannels; // Get the data format mask int mask; result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask ); if ( result == -1 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats."; errorText_ = errorStream_.str(); return FAILURE; } // Determine how to set the device format. stream_.userFormat = format; int deviceFormat = -1; stream_.doByteSwap[mode] = false; if ( format == RTAUDIO_SINT8 ) { if ( mask & AFMT_S8 ) { deviceFormat = AFMT_S8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } } else if ( format == RTAUDIO_SINT16 ) { if ( mask & AFMT_S16_NE ) { deviceFormat = AFMT_S16_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } else if ( mask & AFMT_S16_OE ) { deviceFormat = AFMT_S16_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; stream_.doByteSwap[mode] = true; } } else if ( format == RTAUDIO_SINT24 ) { if ( mask & AFMT_S24_NE ) { deviceFormat = AFMT_S24_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; } else if ( mask & AFMT_S24_OE ) { deviceFormat = AFMT_S24_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; stream_.doByteSwap[mode] = true; } } else if ( format == RTAUDIO_SINT32 ) { if ( mask & AFMT_S32_NE ) { deviceFormat = AFMT_S32_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; } else if ( mask & AFMT_S32_OE ) { deviceFormat = AFMT_S32_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; stream_.doByteSwap[mode] = true; } } if ( deviceFormat == -1 ) { // The user requested format is not natively supported by the device. if ( mask & AFMT_S16_NE ) { deviceFormat = AFMT_S16_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; } else if ( mask & AFMT_S32_NE ) { deviceFormat = AFMT_S32_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; } else if ( mask & AFMT_S24_NE ) { deviceFormat = AFMT_S24_NE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; } else if ( mask & AFMT_S16_OE ) { deviceFormat = AFMT_S16_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT16; stream_.doByteSwap[mode] = true; } else if ( mask & AFMT_S32_OE ) { deviceFormat = AFMT_S32_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT32; stream_.doByteSwap[mode] = true; } else if ( mask & AFMT_S24_OE ) { deviceFormat = AFMT_S24_OE; stream_.deviceFormat[mode] = RTAUDIO_SINT24; stream_.doByteSwap[mode] = true; } else if ( mask & AFMT_S8) { deviceFormat = AFMT_S8; stream_.deviceFormat[mode] = RTAUDIO_SINT8; } } if ( stream_.deviceFormat[mode] == 0 ) { // This really shouldn't happen ... close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; } // Set the data format. int temp = deviceFormat; result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat ); if ( result == -1 || deviceFormat != temp ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Attempt to set the buffer size. According to OSS, the minimum // number of buffers is two. The supposed minimum buffer size is 16 // bytes, so that will be our lower bound. The argument to this // call is in the form 0xMMMMSSSS (hex), where the buffer size (in // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM. // We'll check the actual value used near the end of the setup // procedure. int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels; if ( ossBufferBytes < 16 ) ossBufferBytes = 16; int buffers = 0; if ( options ) buffers = options->numberOfBuffers; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2; if ( buffers < 2 ) buffers = 3; temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) ); result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp ); if ( result == -1 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.nBuffers = buffers; // Save buffer size (in sample frames). *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels ); stream_.bufferSize = *bufferSize; // Set the sample rate. int srate = sampleRate; result = ioctl( fd, SNDCTL_DSP_SPEED, &srate ); if ( result == -1 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ")."; errorText_ = errorStream_.str(); return FAILURE; } // Verify the sample rate setup worked. if ( abs( srate - sampleRate ) > 100 ) { close( fd ); errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ")."; errorText_ = errorStream_.str(); return FAILURE; } stream_.sampleRate = sampleRate; if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) { // We're doing duplex setup here. stream_.deviceFormat[0] = stream_.deviceFormat[1]; stream_.nDeviceChannels[0] = deviceChannels; } // Set interleaving parameters. stream_.userInterleaved = true; stream_.deviceInterleaved[mode] = true; if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false; // Set flags for buffer conversion stream_.doConvertBuffer[mode] = false; if ( stream_.userFormat != stream_.deviceFormat[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) stream_.doConvertBuffer[mode] = true; if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && stream_.nUserChannels[mode] > 1 ) stream_.doConvertBuffer[mode] = true; // Allocate the stream handles if necessary and then save. if ( stream_.apiHandle == 0 ) { try { handle = new OssHandle; } catch ( std::bad_alloc& ) { errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory."; goto error; } if ( pthread_cond_init( &handle->runnable, NULL ) ) { errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable."; goto error; } stream_.apiHandle = (void *) handle; } else { handle = (OssHandle *) stream_.apiHandle; } handle->id[mode] = fd; // Allocate necessary internal buffers. unsigned long bufferBytes; bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory."; goto error; } if ( stream_.doConvertBuffer[mode] ) { bool makeBuffer = true; bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] ); if ( mode == INPUT ) { if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] ); if ( bufferBytes <= bytesOut ) makeBuffer = false; } } if ( makeBuffer ) { bufferBytes *= *bufferSize; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory."; goto error; } } } stream_.device[mode] = device; stream_.state = STREAM_STOPPED; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); // Setup thread if necessary. if ( stream_.mode == OUTPUT && mode == INPUT ) { // We had already set up an output stream. stream_.mode = DUPLEX; if ( stream_.device[0] == device ) handle->id[0] = fd; } else { stream_.mode = mode; // Setup callback thread. stream_.callbackInfo.object = (void *) this; // Set the thread attributes for joinable and realtime scheduling // priority. The higher priority will only take affect if the // program is run as root or suid. pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) { struct sched_param param; int priority = options->priority; int min = sched_get_priority_min( SCHED_RR ); int max = sched_get_priority_max( SCHED_RR ); if ( priority < min ) priority = min; else if ( priority > max ) priority = max; param.sched_priority = priority; pthread_attr_setschedparam( &attr, ¶m ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); } else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #endif stream_.callbackInfo.isRunning = true; result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo ); pthread_attr_destroy( &attr ); if ( result ) { stream_.callbackInfo.isRunning = false; errorText_ = "RtApiOss::error creating callback thread!"; goto error; } } return SUCCESS; error: if ( handle ) { pthread_cond_destroy( &handle->runnable ); if ( handle->id[0] ) close( handle->id[0] ); if ( handle->id[1] ) close( handle->id[1] ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } return FAILURE; } void RtApiOss :: closeStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiOss::closeStream(): no open stream to close!"; error( RtAudioError::WARNING ); return; } OssHandle *handle = (OssHandle *) stream_.apiHandle; stream_.callbackInfo.isRunning = false; MUTEX_LOCK( &stream_.mutex ); if ( stream_.state == STREAM_STOPPED ) pthread_cond_signal( &handle->runnable ); MUTEX_UNLOCK( &stream_.mutex ); pthread_join( stream_.callbackInfo.thread, NULL ); if ( stream_.state == STREAM_RUNNING ) { if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); else ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 ); stream_.state = STREAM_STOPPED; } if ( handle ) { pthread_cond_destroy( &handle->runnable ); if ( handle->id[0] ) close( handle->id[0] ); if ( handle->id[1] ) close( handle->id[1] ); delete handle; stream_.apiHandle = 0; } for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); stream_.userBuffer[i] = 0; } } if ( stream_.deviceBuffer ) { free( stream_.deviceBuffer ); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; } void RtApiOss :: startStream() { verifyStream(); if ( stream_.state == STREAM_RUNNING ) { errorText_ = "RtApiOss::startStream(): the stream is already running!"; error( RtAudioError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); stream_.state = STREAM_RUNNING; // No need to do anything else here ... OSS automatically starts // when fed samples. MUTEX_UNLOCK( &stream_.mutex ); OssHandle *handle = (OssHandle *) stream_.apiHandle; pthread_cond_signal( &handle->runnable ); } void RtApiOss :: stopStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiOss::stopStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } int result = 0; OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Flush the output with zeros a few times. char *buffer; int samples; RtAudioFormat format; if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; samples = stream_.bufferSize * stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer[0]; samples = stream_.bufferSize * stream_.nUserChannels[0]; format = stream_.userFormat; } memset( buffer, 0, samples * formatBytes(format) ); for ( unsigned int i=0; iid[0], buffer, samples * formatBytes(format) ); if ( result == -1 ) { errorText_ = "RtApiOss::stopStream: audio write error."; error( RtAudioError::WARNING ); } } result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } handle->triggered = false; } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) { result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } unlock: stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); if ( result != -1 ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiOss :: abortStream() { verifyStream(); if ( stream_.state == STREAM_STOPPED ) { errorText_ = "RtApiOss::abortStream(): the stream is already stopped!"; error( RtAudioError::WARNING ); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) { MUTEX_UNLOCK( &stream_.mutex ); return; } int result = 0; OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } handle->triggered = false; } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) { result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 ); if ( result == -1 ) { errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ")."; errorText_ = errorStream_.str(); goto unlock; } } unlock: stream_.state = STREAM_STOPPED; MUTEX_UNLOCK( &stream_.mutex ); if ( result != -1 ) return; error( RtAudioError::SYSTEM_ERROR ); } void RtApiOss :: callbackEvent() { OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.state == STREAM_STOPPED ) { MUTEX_LOCK( &stream_.mutex ); pthread_cond_wait( &handle->runnable, &stream_.mutex ); if ( stream_.state != STREAM_RUNNING ) { MUTEX_UNLOCK( &stream_.mutex ); return; } MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!"; error( RtAudioError::WARNING ); return; } // Invoke user callback to get fresh output data. int doStopStream = 0; RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; } if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) { status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); if ( doStopStream == 2 ) { this->abortStream(); return; } MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. if ( stream_.state == STREAM_STOPPED ) goto unlock; int result; char *buffer; int samples; RtAudioFormat format; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Setup parameters and do buffer conversion if necessary. if ( stream_.doConvertBuffer[0] ) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); samples = stream_.bufferSize * stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer[0]; samples = stream_.bufferSize * stream_.nUserChannels[0]; format = stream_.userFormat; } // Do byte swapping if necessary. if ( stream_.doByteSwap[0] ) byteSwapBuffer( buffer, samples, format ); if ( stream_.mode == DUPLEX && handle->triggered == false ) { int trig = 0; ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig ); result = write( handle->id[0], buffer, samples * formatBytes(format) ); trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT; ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig ); handle->triggered = true; } else // Write samples to device. result = write( handle->id[0], buffer, samples * formatBytes(format) ); if ( result == -1 ) { // We'll assume this is an underrun, though there isn't a // specific means for determining that. handle->xrun[0] = true; errorText_ = "RtApiOss::callbackEvent: audio write error."; error( RtAudioError::WARNING ); // Continue on to input section. } } if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { // Setup parameters. if ( stream_.doConvertBuffer[1] ) { buffer = stream_.deviceBuffer; samples = stream_.bufferSize * stream_.nDeviceChannels[1]; format = stream_.deviceFormat[1]; } else { buffer = stream_.userBuffer[1]; samples = stream_.bufferSize * stream_.nUserChannels[1]; format = stream_.userFormat; } // Read samples from device. result = read( handle->id[1], buffer, samples * formatBytes(format) ); if ( result == -1 ) { // We'll assume this is an overrun, though there isn't a // specific means for determining that. handle->xrun[1] = true; errorText_ = "RtApiOss::callbackEvent: audio read error."; error( RtAudioError::WARNING ); goto unlock; } // Do byte swapping if necessary. if ( stream_.doByteSwap[1] ) byteSwapBuffer( buffer, samples, format ); // Do buffer conversion if necessary. if ( stream_.doConvertBuffer[1] ) convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } unlock: MUTEX_UNLOCK( &stream_.mutex ); RtApi::tickStreamTime(); if ( doStopStream == 1 ) this->stopStream(); } static void *ossCallbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiOss *object = (RtApiOss *) info->object; bool *isRunning = &info->isRunning; while ( *isRunning == true ) { pthread_testcancel(); object->callbackEvent(); } pthread_exit( NULL ); } //******************** End of __LINUX_OSS__ *********************// #endif // *************************************************** // // // Protected common (OS-independent) RtAudio methods. // // *************************************************** // // This method can be modified to control the behavior of error // message printing. void RtApi :: error( RtAudioError::Type type ) { errorStream_.str(""); // clear the ostringstream RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback; if ( errorCallback ) { // abortStream() can generate new error messages. Ignore them. Just keep original one. if ( firstErrorOccurred_ ) return; firstErrorOccurred_ = true; const std::string errorMessage = errorText_; if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) { stream_.callbackInfo.isRunning = false; // exit from the thread abortStream(); } errorCallback( type, errorMessage ); firstErrorOccurred_ = false; return; } if ( type == RtAudioError::WARNING && showWarnings_ == true ) std::cerr << '\n' << errorText_ << "\n\n"; else if ( type != RtAudioError::WARNING ) throw( RtAudioError( errorText_, type ) ); } void RtApi :: verifyStream() { if ( stream_.state == STREAM_CLOSED ) { errorText_ = "RtApi:: a stream is not open!"; error( RtAudioError::INVALID_USE ); } } void RtApi :: clearStreamInfo() { stream_.mode = UNINITIALIZED; stream_.state = STREAM_CLOSED; stream_.sampleRate = 0; stream_.bufferSize = 0; stream_.nBuffers = 0; stream_.userFormat = 0; stream_.userInterleaved = true; stream_.streamTime = 0.0; stream_.apiHandle = 0; stream_.deviceBuffer = 0; stream_.callbackInfo.callback = 0; stream_.callbackInfo.userData = 0; stream_.callbackInfo.isRunning = false; stream_.callbackInfo.errorCallback = 0; for ( int i=0; i<2; i++ ) { stream_.device[i] = 11111; stream_.doConvertBuffer[i] = false; stream_.deviceInterleaved[i] = true; stream_.doByteSwap[i] = false; stream_.nUserChannels[i] = 0; stream_.nDeviceChannels[i] = 0; stream_.channelOffset[i] = 0; stream_.deviceFormat[i] = 0; stream_.latency[i] = 0; stream_.userBuffer[i] = 0; stream_.convertInfo[i].channels = 0; stream_.convertInfo[i].inJump = 0; stream_.convertInfo[i].outJump = 0; stream_.convertInfo[i].inFormat = 0; stream_.convertInfo[i].outFormat = 0; stream_.convertInfo[i].inOffset.clear(); stream_.convertInfo[i].outOffset.clear(); } } unsigned int RtApi :: formatBytes( RtAudioFormat format ) { if ( format == RTAUDIO_SINT16 ) return 2; else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 ) return 4; else if ( format == RTAUDIO_FLOAT64 ) return 8; else if ( format == RTAUDIO_SINT24 ) return 3; else if ( format == RTAUDIO_SINT8 ) return 1; errorText_ = "RtApi::formatBytes: undefined format."; error( RtAudioError::WARNING ); return 0; } void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel ) { if ( mode == INPUT ) { // convert device to user buffer stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1]; stream_.convertInfo[mode].outJump = stream_.nUserChannels[1]; stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1]; stream_.convertInfo[mode].outFormat = stream_.userFormat; } else { // convert user to device buffer stream_.convertInfo[mode].inJump = stream_.nUserChannels[0]; stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0]; stream_.convertInfo[mode].inFormat = stream_.userFormat; stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0]; } if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump ) stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump; else stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump; // Set up the interleave/deinterleave offsets. if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) { if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) || ( mode == INPUT && stream_.userInterleaved ) ) { for ( int k=0; k 0 ) { if ( stream_.deviceInterleaved[mode] ) { if ( mode == OUTPUT ) { for ( int k=0; k> 8); //out[info.outOffset[j]] >>= 8; } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_FLOAT32) { Float32 *in = (Float32 *)inBuffer; for (unsigned int i=0; i> 8); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_SINT32) { Int32 *in = (Int32 *)inBuffer; for (unsigned int i=0; i> 16) & 0x0000ffff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_FLOAT32) { Float32 *in = (Float32 *)inBuffer; for (unsigned int i=0; i> 8) & 0x00ff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_SINT24) { Int24 *in = (Int24 *)inBuffer; for (unsigned int i=0; i> 16); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_SINT32) { Int32 *in = (Int32 *)inBuffer; for (unsigned int i=0; i> 24) & 0x000000ff); } in += info.inJump; out += info.outJump; } } else if (info.inFormat == RTAUDIO_FLOAT32) { Float32 *in = (Float32 *)inBuffer; for (unsigned int i=0; i>8) | (x<<8); } //static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); } //static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); } void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format ) { register char val; register char *ptr; ptr = buffer; if ( format == RTAUDIO_SINT16 ) { for ( unsigned int i=0; i #include /* --- Monocasual hack ---------------------------------------------- */ #if defined(__linux__) #include #endif /* ------------------------------------------------------------------ */ #include #include /*! \typedef typedef unsigned long RtAudioFormat; \brief RtAudio data format type. Support for signed integers and floats. Audio data fed to/from an RtAudio stream is assumed to ALWAYS be in host byte order. The internal routines will automatically take care of any necessary byte-swapping between the host format and the soundcard. Thus, endian-ness is not a concern in the following format definitions. - \e RTAUDIO_SINT8: 8-bit signed integer. - \e RTAUDIO_SINT16: 16-bit signed integer. - \e RTAUDIO_SINT24: 24-bit signed integer. - \e RTAUDIO_SINT32: 32-bit signed integer. - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0. - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0. */ typedef unsigned long RtAudioFormat; static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer. static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer. static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // 24-bit signed integer. static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer. static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0. static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0. /*! \typedef typedef unsigned long RtAudioStreamFlags; \brief RtAudio stream option flags. The following flags can be OR'ed together to allow a client to make changes to the default stream behavior: - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). By default, RtAudio streams pass and receive audio data from the client in an interleaved format. By passing the RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio data will instead be presented in non-interleaved buffers. In this case, each buffer argument in the RtAudioCallback function will point to a single array of data, with \c nFrames samples for each channel concatenated back-to-back. For example, the first sample of data for the second channel would be located at index \c nFrames (assuming the \c buffer pointer was recast to the correct data type for the stream). Certain audio APIs offer a number of parameters that influence the I/O latency of a stream. By default, RtAudio will attempt to set these parameters internally for robust (glitch-free) performance (though some APIs, like Windows Direct Sound, make this difficult). By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream() function, internal stream settings will be influenced in an attempt to minimize stream latency, though possibly at the expense of stream performance. If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to open the input and/or output stream device(s) for exclusive use. Note that this is not possible with all supported audio APIs. If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt to select realtime scheduling (round-robin) for the callback thread. If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to open the "default" PCM device when using the ALSA API. Note that this will override any specified input or output device id. */ typedef unsigned int RtAudioStreamFlags; static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved). static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to set stream parameters for lowest possible latency. static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others. static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread. static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only). /*! \typedef typedef unsigned long RtAudioStreamStatus; \brief RtAudio stream status (over- or underflow) flags. Notification of a stream over- or underflow is indicated by a non-zero stream \c status argument in the RtAudioCallback function. The stream status can be one of the following two options, depending on whether the stream is open for output and/or input: - \e RTAUDIO_INPUT_OVERFLOW: Input data was discarded because of an overflow condition at the driver. - \e RTAUDIO_OUTPUT_UNDERFLOW: The output buffer ran low, likely producing a break in the output sound. */ typedef unsigned int RtAudioStreamStatus; static const RtAudioStreamStatus RTAUDIO_INPUT_OVERFLOW = 0x1; // Input data was discarded because of an overflow condition at the driver. static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2; // The output buffer ran low, likely causing a gap in the output sound. //! RtAudio callback function prototype. /*! All RtAudio clients must create a function of type RtAudioCallback to read and/or write data from/to the audio stream. When the underlying audio system is ready for new input or output data, this function will be invoked. \param outputBuffer For output (or duplex) streams, the client should write \c nFrames of audio sample frames into this buffer. This argument should be recast to the datatype specified when the stream was opened. For input-only streams, this argument will be NULL. \param inputBuffer For input (or duplex) streams, this buffer will hold \c nFrames of input audio sample frames. This argument should be recast to the datatype specified when the stream was opened. For output-only streams, this argument will be NULL. \param nFrames The number of sample frames of input or output data in the buffers. The actual buffer size in bytes is dependent on the data type and number of channels in use. \param streamTime The number of seconds that have elapsed since the stream was started. \param status If non-zero, this argument indicates a data overflow or underflow condition for the stream. The particular condition can be determined by comparison with the RtAudioStreamStatus flags. \param userData A pointer to optional data provided by the client when opening the stream (default = NULL). To continue normal stream operation, the RtAudioCallback function should return a value of zero. To stop the stream and drain the output buffer, the function should return a value of one. To abort the stream immediately, the client should return a value of two. */ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData ); /************************************************************************/ /*! \class RtAudioError \brief Exception handling class for RtAudio. The RtAudioError class is quite simple but it does allow errors to be "caught" by RtAudioError::Type. See the RtAudio documentation to know which methods can throw an RtAudioError. */ /************************************************************************/ class RtAudioError : public std::exception { public: //! Defined RtAudioError types. enum Type { WARNING, /*!< A non-critical error. */ DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */ UNSPECIFIED, /*!< The default, unspecified error type. */ NO_DEVICES_FOUND, /*!< No devices found on system. */ INVALID_DEVICE, /*!< An invalid device ID was specified. */ MEMORY_ERROR, /*!< An error occured during memory allocation. */ INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */ INVALID_USE, /*!< The function was called incorrectly. */ DRIVER_ERROR, /*!< A system driver error occured. */ SYSTEM_ERROR, /*!< A system error occured. */ THREAD_ERROR /*!< A thread error occured. */ }; //! The constructor. RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {} //! The destructor. virtual ~RtAudioError( void ) throw() {} //! Prints thrown error message to stderr. virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; } //! Returns the thrown error message type. virtual const Type& getType(void) const throw() { return type_; } //! Returns the thrown error message string. virtual const std::string& getMessage(void) const throw() { return message_; } //! Returns the thrown error message as a c-style string. virtual const char* what( void ) const throw() { return message_.c_str(); } protected: std::string message_; Type type_; }; //! RtAudio error callback function prototype. /*! \param type Type of error. \param errorText Error description. */ typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText ); // **************************************************************** // // // RtAudio class declaration. // // RtAudio is a "controller" used to select an available audio i/o // interface. It presents a common API for the user to call but all // functionality is implemented by the class RtApi and its // subclasses. RtAudio creates an instance of an RtApi subclass // based on the user's API choice. If no choice is made, RtAudio // attempts to make a "logical" API selection. // // **************************************************************** // class RtApi; class RtAudio { public: //! Audio API specifier arguments. enum Api { UNSPECIFIED, /*!< Search for a working compiled API. */ LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */ LINUX_PULSE, /*!< The Linux PulseAudio API. */ LINUX_OSS, /*!< The Linux Open Sound System API. */ UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */ MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */ WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */ WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */ WINDOWS_DS, /*!< The Microsoft Direct Sound API. */ RTAUDIO_DUMMY /*!< A compilable but non-functional API. */ }; //! The public device information structure for returning queried values. struct DeviceInfo { bool probed; /*!< true if the device capabilities were successfully probed. */ std::string name; /*!< Character string device identifier. */ unsigned int outputChannels; /*!< Maximum output channels supported by device. */ unsigned int inputChannels; /*!< Maximum input channels supported by device. */ unsigned int duplexChannels; /*!< Maximum simultaneous input/output channels supported by device. */ bool isDefaultOutput; /*!< true if this is the default output device. */ bool isDefaultInput; /*!< true if this is the default input device. */ std::vector sampleRates; /*!< Supported sample rates (queried from list of standard rates). */ RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */ // Default constructor. DeviceInfo() :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0), isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {} }; //! The structure for specifying input or ouput stream parameters. struct StreamParameters { unsigned int deviceId; /*!< Device index (0 to getDeviceCount() - 1). */ unsigned int nChannels; /*!< Number of channels. */ unsigned int firstChannel; /*!< First channel index on device (default = 0). */ // Default constructor. StreamParameters() : deviceId(0), nChannels(0), firstChannel(0) {} }; //! The structure for specifying stream options. /*! The following flags can be OR'ed together to allow a client to make changes to the default stream behavior: - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. - \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread. - \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only). By default, RtAudio streams pass and receive audio data from the client in an interleaved format. By passing the RTAUDIO_NONINTERLEAVED flag to the openStream() function, audio data will instead be presented in non-interleaved buffers. In this case, each buffer argument in the RtAudioCallback function will point to a single array of data, with \c nFrames samples for each channel concatenated back-to-back. For example, the first sample of data for the second channel would be located at index \c nFrames (assuming the \c buffer pointer was recast to the correct data type for the stream). Certain audio APIs offer a number of parameters that influence the I/O latency of a stream. By default, RtAudio will attempt to set these parameters internally for robust (glitch-free) performance (though some APIs, like Windows Direct Sound, make this difficult). By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream() function, internal stream settings will be influenced in an attempt to minimize stream latency, though possibly at the expense of stream performance. If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to open the input and/or output stream device(s) for exclusive use. Note that this is not possible with all supported audio APIs. If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt to select realtime scheduling (round-robin) for the callback thread. The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME flag is set. It defines the thread's realtime priority. If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to open the "default" PCM device when using the ALSA API. Note that this will override any specified input or output device id. The \c numberOfBuffers parameter can be used to control stream latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs only. A value of two is usually the smallest allowed. Larger numbers can potentially result in more robust stream performance, though likely at the cost of stream latency. The value set by the user is replaced during execution of the RtAudio::openStream() function by the value actually used by the system. The \c streamName parameter can be used to set the client name when using the Jack API. By default, the client name is set to RtApiJack. However, if you wish to create multiple instances of RtAudio with Jack, each instance must have a unique client name. */ struct StreamOptions { RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE, RTAUDIO_ALSA_USE_DEFAULT). */ unsigned int numberOfBuffers; /*!< Number of stream buffers. */ std::string streamName; /*!< A stream name (currently used only in Jack). */ int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ // Default constructor. StreamOptions() : flags(0), numberOfBuffers(0), priority(0) {} }; //! A static function to determine the current RtAudio version. static std::string getVersion( void ) throw(); //! A static function to determine the available compiled audio APIs. /*! The values returned in the std::vector can be compared against the enumerated list values. Note that there can be more than one API compiled for certain operating systems. */ static void getCompiledApi( std::vector &apis ) throw(); //! The class constructor. /*! The constructor performs minor initialization tasks. An exception can be thrown if no API support is compiled. If no API argument is specified and multiple API support has been compiled, the default order of use is JACK, ALSA, OSS (Linux systems) and ASIO, DS (Windows systems). */ RtAudio( RtAudio::Api api=UNSPECIFIED ); //! The destructor. /*! If a stream is running or open, it will be stopped and closed automatically. */ ~RtAudio() throw(); //! Returns the audio API specifier for the current instance of RtAudio. RtAudio::Api getCurrentApi( void ) throw(); //! A public function that queries for the number of audio devices available. /*! This function performs a system query of available devices each time it is called, thus supporting devices connected \e after instantiation. If a system error occurs during processing, a warning will be issued. */ unsigned int getDeviceCount( void ) throw(); //! Return an RtAudio::DeviceInfo structure for a specified device number. /*! Any device integer between 0 and getDeviceCount() - 1 is valid. If an invalid argument is provided, an RtAudioError (type = INVALID_USE) will be thrown. If a device is busy or otherwise unavailable, the structure member "probed" will have a value of "false" and all other members are undefined. If the specified device is the current default input or output device, the corresponding "isDefault" member will have a value of "true". */ RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); //! A function that returns the index of the default output device. /*! If the underlying audio API does not provide a "default device", or if no devices are available, the return value will be 0. Note that this is a valid device identifier and it is the client's responsibility to verify that a device is available before attempting to open a stream. */ unsigned int getDefaultOutputDevice( void ) throw(); //! A function that returns the index of the default input device. /*! If the underlying audio API does not provide a "default device", or if no devices are available, the return value will be 0. Note that this is a valid device identifier and it is the client's responsibility to verify that a device is available before attempting to open a stream. */ unsigned int getDefaultInputDevice( void ) throw(); //! A public function for opening a stream with the specified parameters. /*! An RtAudioError (type = SYSTEM_ERROR) is thrown if a stream cannot be opened with the specified parameters or an error occurs during processing. An RtAudioError (type = INVALID_USE) is thrown if any invalid device ID or channel number parameters are specified. \param outputParameters Specifies output stream parameters to use when opening a stream, including a device ID, number of channels, and starting channel number. For input-only streams, this argument should be NULL. The device ID is an index value between 0 and getDeviceCount() - 1. \param inputParameters Specifies input stream parameters to use when opening a stream, including a device ID, number of channels, and starting channel number. For output-only streams, this argument should be NULL. The device ID is an index value between 0 and getDeviceCount() - 1. \param format An RtAudioFormat specifying the desired sample data format. \param sampleRate The desired sample rate (sample frames per second). \param *bufferFrames A pointer to a value indicating the desired internal buffer size in sample frames. The actual value used by the device is returned via the same pointer. A value of zero can be specified, in which case the lowest allowable value is determined. \param callback A client-defined function that will be invoked when input data is available and/or output data is needed. \param userData An optional pointer to data that can be accessed from within the callback function. \param options An optional pointer to a structure containing various global stream options, including a list of OR'ed RtAudioStreamFlags and a suggested number of stream buffers that can be used to control stream latency. More buffers typically result in more robust performance, though at a cost of greater latency. If a value of zero is specified, a system-specific median value is chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the lowest allowable value is used. The actual value used is returned via the structure argument. The parameter is API dependent. \param errorCallback A client-defined function that will be invoked when an error has occured. */ void openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL ); //! A function that closes a stream and frees any associated stream memory. /*! If a stream is not open, this function issues a warning and returns (no exception is thrown). */ void closeStream( void ) throw(); //! A function that starts a stream. /*! An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs during processing. An RtAudioError (type = INVALID_USE) is thrown if a stream is not open. A warning is issued if the stream is already running. */ void startStream( void ); //! Stop a stream, allowing any samples remaining in the output queue to be played. /*! An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs during processing. An RtAudioError (type = INVALID_USE) is thrown if a stream is not open. A warning is issued if the stream is already stopped. */ void stopStream( void ); //! Stop a stream, discarding any samples remaining in the input/output queue. /*! An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs during processing. An RtAudioError (type = INVALID_USE) is thrown if a stream is not open. A warning is issued if the stream is already stopped. */ void abortStream( void ); //! Returns true if a stream is open and false if not. bool isStreamOpen( void ) const throw(); //! Returns true if the stream is running and false if it is stopped or not open. bool isStreamRunning( void ) const throw(); //! Returns the number of elapsed seconds since the stream was started. /*! If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown. */ double getStreamTime( void ); //! Set the stream time to a time in seconds greater than or equal to 0.0. /*! If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown. */ void setStreamTime( double time ); //! Returns the internal stream latency in sample frames. /*! The stream latency refers to delay in audio input and/or output caused by internal buffering by the audio system and/or hardware. For duplex streams, the returned value will represent the sum of the input and output latencies. If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown. If the API does not report latency, the return value will be zero. */ long getStreamLatency( void ); //! Returns actual sample rate in use by the stream. /*! On some systems, the sample rate used may be slightly different than that specified in the stream parameters. If a stream is not open, an RtAudioError (type = INVALID_USE) will be thrown. */ unsigned int getStreamSampleRate( void ); //! Specify whether warning messages should be printed to stderr. void showWarnings( bool value = true ) throw(); /* --- Monocasual hack ---------------------------------------------- */ //protected: /* ------------------------------------------------------------------ */ void openRtApi( RtAudio::Api api ); RtApi *rtapi_; }; // Operating system dependent thread functionality. #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__) #ifndef NOMINMAX #define NOMINMAX #endif #include #include typedef uintptr_t ThreadHandle; typedef CRITICAL_SECTION StreamMutex; #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) // Using pthread library for various flavors of unix. #include typedef pthread_t ThreadHandle; typedef pthread_mutex_t StreamMutex; #else // Setup for "dummy" behavior #define __RTAUDIO_DUMMY__ typedef int ThreadHandle; typedef int StreamMutex; #endif // This global structure type is used to pass callback information // between the private RtAudio stream structure and global callback // handling functions. struct CallbackInfo { void *object; // Used as a "this" pointer. ThreadHandle thread; void *callback; void *userData; void *errorCallback; void *apiInfo; // void pointer for API specific callback information bool isRunning; bool doRealtime; int priority; // Default constructor. CallbackInfo() :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {} }; // **************************************************************** // // // RtApi class declaration. // // Subclasses of RtApi contain all API- and OS-specific code necessary // to fully implement the RtAudio API. // // Note that RtApi is an abstract base class and cannot be // explicitly instantiated. The class RtAudio will create an // instance of an RtApi subclass (RtApiOss, RtApiAlsa, // RtApiJack, RtApiCore, RtApiDs, or RtApiAsio). // // **************************************************************** // #pragma pack(push, 1) class S24 { protected: unsigned char c3[3]; public: S24() {} S24& operator = ( const int& i ) { c3[0] = (i & 0x000000ff); c3[1] = (i & 0x0000ff00) >> 8; c3[2] = (i & 0x00ff0000) >> 16; return *this; } S24( const S24& v ) { *this = v; } S24( const double& d ) { *this = (int) d; } S24( const float& f ) { *this = (int) f; } S24( const signed short& s ) { *this = (int) s; } S24( const char& c ) { *this = (int) c; } int asInt() { int i = c3[0] | (c3[1] << 8) | (c3[2] << 16); if (i & 0x800000) i |= ~0xffffff; return i; } }; #pragma pack(pop) #if defined( HAVE_GETTIMEOFDAY ) #include #endif #include class RtApi { public: /* --- Monocasual hack ---------------------------------------------- */ #ifdef __linux__ void *__HACK__getJackClient(); #endif /* ------------------------------------------------------------------ */ RtApi(); virtual ~RtApi(); virtual RtAudio::Api getCurrentApi( void ) = 0; virtual unsigned int getDeviceCount( void ) = 0; virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0; virtual unsigned int getDefaultInputDevice( void ); virtual unsigned int getDefaultOutputDevice( void ); void openStream( RtAudio::StreamParameters *outputParameters, RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options, RtAudioErrorCallback errorCallback ); virtual void closeStream( void ); virtual void startStream( void ) = 0; virtual void stopStream( void ) = 0; virtual void abortStream( void ) = 0; long getStreamLatency( void ); unsigned int getStreamSampleRate( void ); virtual double getStreamTime( void ); virtual void setStreamTime( double time ); bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; } bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; } void showWarnings( bool value ) { showWarnings_ = value; } protected: static const unsigned int MAX_SAMPLE_RATES; static const unsigned int SAMPLE_RATES[]; enum { FAILURE, SUCCESS }; enum StreamState { STREAM_STOPPED, STREAM_STOPPING, STREAM_RUNNING, STREAM_CLOSED = -50 }; enum StreamMode { OUTPUT, INPUT, DUPLEX, UNINITIALIZED = -75 }; // A protected structure used for buffer conversion. struct ConvertInfo { int channels; int inJump, outJump; RtAudioFormat inFormat, outFormat; std::vector inOffset; std::vector outOffset; }; // A protected structure for audio streams. struct RtApiStream { unsigned int device[2]; // Playback and record, respectively. void *apiHandle; // void pointer for API specific stream handle information StreamMode mode; // OUTPUT, INPUT, or DUPLEX. StreamState state; // STOPPED, RUNNING, or CLOSED char *userBuffer[2]; // Playback and record, respectively. char *deviceBuffer; bool doConvertBuffer[2]; // Playback and record, respectively. bool userInterleaved; bool deviceInterleaved[2]; // Playback and record, respectively. bool doByteSwap[2]; // Playback and record, respectively. unsigned int sampleRate; unsigned int bufferSize; unsigned int nBuffers; unsigned int nUserChannels[2]; // Playback and record, respectively. unsigned int nDeviceChannels[2]; // Playback and record channels, respectively. unsigned int channelOffset[2]; // Playback and record, respectively. unsigned long latency[2]; // Playback and record, respectively. RtAudioFormat userFormat; RtAudioFormat deviceFormat[2]; // Playback and record, respectively. StreamMutex mutex; CallbackInfo callbackInfo; ConvertInfo convertInfo[2]; double streamTime; // Number of elapsed seconds since the stream started. #if defined(HAVE_GETTIMEOFDAY) struct timeval lastTickTimestamp; #endif RtApiStream() :apiHandle(0), deviceBuffer(0) { device[0] = 11111; device[1] = 11111; } }; typedef S24 Int24; typedef signed short Int16; typedef signed int Int32; typedef float Float32; typedef double Float64; std::ostringstream errorStream_; std::string errorText_; bool showWarnings_; RtApiStream stream_; bool firstErrorOccurred_; /*! Protected, api-specific method that attempts to open a device with the given parameters. This function MUST be implemented by all subclasses. If an error is encountered during the probe, a "warning" message is reported and FAILURE is returned. A successful probe is indicated by a return value of SUCCESS. */ virtual bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); //! A protected function used to increment the stream time. void tickStreamTime( void ); //! Protected common method to clear an RtApiStream structure. void clearStreamInfo(); /*! Protected common method that throws an RtAudioError (type = INVALID_USE) if a stream is not open. */ void verifyStream( void ); //! Protected common error method to allow global control over error handling. void error( RtAudioError::Type type ); /*! Protected method used to perform format, channel number, and/or interleaving conversions between the user and device buffers. */ void convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info ); //! Protected common method used to perform byte-swapping on buffers. void byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format ); //! Protected common method that returns the number of bytes for a given format. unsigned int formatBytes( RtAudioFormat format ); //! Protected common method that sets up the parameters for buffer conversion. void setConvertInfo( StreamMode mode, unsigned int firstChannel ); }; // **************************************************************** // // // Inline RtAudio definitions. // // **************************************************************** // inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); } inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); } inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); } inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); } inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); } inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); } inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); } inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); } inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); } inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); } inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); } inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); } inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); } inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); } inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); } // RtApi Subclass prototypes. #if defined(__MACOSX_CORE__) #include class RtApiCore: public RtApi { public: RtApiCore(); ~RtApiCore(); RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! bool callbackEvent( AudioDeviceID deviceId, const AudioBufferList *inBufferList, const AudioBufferList *outBufferList ); private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); static const char* getErrorCode( OSStatus code ); }; #endif #if defined(__UNIX_JACK__) class RtApiJack: public RtApi { public: RtApiJack(); ~RtApiJack(); RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! bool callbackEvent( unsigned long nframes ); private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); }; #endif #if defined(__WINDOWS_ASIO__) class RtApiAsio: public RtApi { public: RtApiAsio(); ~RtApiAsio(); RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! bool callbackEvent( long bufferIndex ); private: std::vector devices_; void saveDeviceInfo( void ); bool coInitialized_; bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); }; #endif #if defined(__WINDOWS_DS__) class RtApiDs: public RtApi { public: RtApiDs(); ~RtApiDs(); RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; } unsigned int getDeviceCount( void ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); long getStreamLatency( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: bool coInitialized_; bool buffersRolling; long duplexPrerollBytes; std::vector dsDevices; bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); }; #endif #if defined(__WINDOWS_WASAPI__) struct IMMDeviceEnumerator; class RtApiWasapi : public RtApi { public: RtApiWasapi(); ~RtApiWasapi(); RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); private: bool coInitialized_; IMMDeviceEnumerator* deviceEnumerator_; bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int* bufferSize, RtAudio::StreamOptions* options ); static DWORD WINAPI runWasapiThread( void* wasapiPtr ); static DWORD WINAPI stopWasapiThread( void* wasapiPtr ); static DWORD WINAPI abortWasapiThread( void* wasapiPtr ); void wasapiThread(); }; #endif #if defined(__LINUX_ALSA__) class RtApiAlsa: public RtApi { public: RtApiAlsa(); ~RtApiAlsa(); RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: std::vector devices_; void saveDeviceInfo( void ); bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); }; #endif #if defined(__LINUX_PULSE__) class RtApiPulse: public RtApi { public: ~RtApiPulse(); RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: std::vector devices_; void saveDeviceInfo( void ); bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); }; #endif #if defined(__LINUX_OSS__) class RtApiOss: public RtApi { public: RtApiOss(); ~RtApiOss(); RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); void startStream( void ); void stopStream( void ); void abortStream( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, // which is not a member of RtAudio. External use of this function // will most likely produce highly undesireable results! void callbackEvent( void ); private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, unsigned int firstChannel, unsigned int sampleRate, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ); }; #endif #if defined(__RTAUDIO_DUMMY__) class RtApiDummy: public RtApi { public: RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtAudioError::WARNING ); } RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; } unsigned int getDeviceCount( void ) { return 0; } RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; } void closeStream( void ) {} void startStream( void ) {} void stopStream( void ) {} void abortStream( void ) {} private: bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, unsigned int /*firstChannel*/, unsigned int /*sampleRate*/, RtAudioFormat /*format*/, unsigned int * /*bufferSize*/, RtAudio::StreamOptions * /*options*/ ) { return false; } }; #endif #endif // Indentation settings for Vim and Emacs // // Local Variables: // c-basic-offset: 2 // indent-tabs-mode: nil // End: // // vim: et sts=2 sw=2 giada-0.11.2/src/deps/rtaudio-mod/config/000077500000000000000000000000001264622563000200615ustar00rootroot00000000000000giada-0.11.2/src/deps/rtaudio-mod/config/config.guess000066400000000000000000001146171264622563000224100ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2004-02-26' # This file 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Written by Per Bothner . # Please send patches to . # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi dummy=dummy-$$ trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int dummy(){}" > $dummy.c for c in cc gcc c89 ; do ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 if test $? = 0 ; then CC_FOR_BUILD="$c"; break fi done rm -f $dummy.c $dummy.o $dummy.rel if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 8/24/94.) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # Netbsd (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # Determine the machine/vendor (is the vendor relevant). case "${UNAME_MACHINE}" in amiga) machine=m68k-unknown ;; arm32) machine=arm-unknown ;; atari*) machine=m68k-atari ;; sun3*) machine=m68k-sun ;; mac68k) machine=m68k-apple ;; macppc) machine=powerpc-apple ;; hp3[0-9][05]) machine=m68k-hp ;; ibmrt|romp-ibm) machine=romp-ibm ;; *) machine=${UNAME_MACHINE}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE}" in i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k) if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `./$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; esac fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; arc64:OpenBSD:*:*) echo mips64el-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hkmips:OpenBSD:*:*) echo mips-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mips-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; atari*:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; sun3*:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) case "${HPUX_REV}" in 11.[0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; esac ;; esac fi ;; esac if [ "${HP_ARCH}" = "" ]; then sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi rm -f $dummy.c $dummy fi ;; esac echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; hppa*:OpenBSD:*:*) echo hppa-unknown-openbsd exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*X-MP:*:*:*) echo xmp-cray-unicos exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3D:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY-2:*:*:*) echo cray2-cray-unicos exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) cat >$dummy.c < /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #ifdef __MIPSEB__ printf ("%s-unknown-linux-gnu\n", argv[1]); #endif #ifdef __MIPSEL__ printf ("%sel-unknown-linux-gnu\n", argv[1]); #endif return 0; } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy ;; ppc:Linux:*:*) # Determine Lib Version cat >$dummy.c < #if defined(__GLIBC__) extern char __libc_version[]; extern char __libc_release[]; #endif main(argc, argv) int argc; char *argv[]; { #if defined(__GLIBC__) printf("%s %s\n", __libc_version, __libc_release); #else printf("unknown\n"); #endif return 0; } EOF LIBC="" $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null if test "$?" = 0 ; then ./$dummy | grep 1\.99 > /dev/null if test "$?" = 0 ; then LIBC="libc1" ; fi fi rm -f $dummy.c $dummy echo powerpc-unknown-linux-gnu${LIBC} exit 0 ;; alpha:Linux:*:*) cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF LIBC="" $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `./$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; esac objdump --private-headers $dummy | \ grep ld.so.1 > /dev/null if test "$?" = 0 ; then LIBC="libc1" fi fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. ld_supported_emulations=`cd /; ld --help 2>&1 \ | sed -ne '/supported emulations:/!d s/[ ][ ]*/ /g s/.*supported emulations: *// s/ .*// p'` case "$ld_supported_emulations" in i*86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; elf_i*86) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; i*86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; esac # Either a pre-BFD a.out linker (linux-gnuoldld) # or one that does not give us useful --help. # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. # If ld does not provide *any* "supported emulations:" # that means it is gnuoldld. test -z "$ld_supported_emulations" && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 case "${UNAME_MACHINE}" in i*86) VENDOR=pc; ;; *) VENDOR=unknown; ;; esac # Determine whether the default compiler is a.out or elf cat >$dummy.c < #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); # else printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); # endif # else printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); # endif #else printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); #endif return 0; } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions # are messed up and put the nodename in both sysname and nodename. i*86:DYNIX/ptx:4*:*) echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:7*) # Fixed at (any) Pentium or better UNAME_MACHINE=i586 if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} fi exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) echo `uname -p`-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) if test "${UNAME_MACHINE}" = "x86pc"; then UNAME_MACHINE=pc fi echo `uname -p`-${UNAME_MACHINE}-nto-qnx exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[KW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: giada-0.11.2/src/deps/rtaudio-mod/config/config.sub000077500000000000000000000661511264622563000220550ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2012-11-19' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \ | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \ | pyramid | mn10200 | mn10300 | tron | a29k \ | 580 | i960 | h8300 \ | x86 | ppcbe | mipsbe | mipsle | shbe | shle \ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ | hppa64 \ | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ | alphaev6[78] \ | we32k | ns16k | clipper | i370 | sh | sh[34] \ | powerpc | powerpc64 | powerpcle \ | 1750a | dsp16xx | pdp10 | pdp11 \ | mips16 | mips64 | mipsel | mips64el \ | mips64orion | mips64orionel | mipstx39 | mipstx39el \ | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ | mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \ | sparc | sparclet | sparclite | sparc64 | sparcv9 | sparcv9b \ | v850 | c4x \ | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \ | pj | pjl | h8500) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | w65) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. # FIXME: clean up the formatting here. vax-* | tahoe-* | i*86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \ | arm-* | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ | xmp-* | ymp-* \ | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \ | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ | hppa2.0n-* | hppa64-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ | alphaev6[78]-* \ | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ | clipper-* | orion-* \ | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpc64-* | powerpcle-* \ | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \ | mips16-* | mips64-* | mipsel-* \ | mips64el-* | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ | mipstx39-* | mipstx39el-* | mcore-* \ | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \ | [cjt]90-* \ | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \ | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | ymp) basic_machine=ymp-cray os=-unicos ;; cray2) basic_machine=cray2-cray os=-unicos ;; [cjt]90) basic_machine=${basic_machine}-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsel*-linux*) basic_machine=mipsel-unknown os=-linux-gnu ;; mips*-linux*) basic_machine=mips-unknown os=-linux-gnu ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=t3e-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xmp) basic_machine=xmp-cray os=-unicos ;; xps | xps100) basic_machine=xps100-honeywell ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; mips) if [ x$os = x-linux-gnu ]; then basic_machine=mips-unknown else basic_machine=mips-mips fi ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4) basic_machine=sh-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: giada-0.11.2/src/deps/rtaudio-mod/config/install.sh000077500000000000000000000000001264622563000220540ustar00rootroot00000000000000giada-0.11.2/src/deps/rtaudio-mod/configure000077500000000000000000005126431264622563000205360ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for RtAudio 4.1. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: gary@music.mcgill.ca about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='RtAudio' PACKAGE_TARNAME='rtaudio' PACKAGE_VERSION='4.1' PACKAGE_STRING='RtAudio 4.1' PACKAGE_BUGREPORT='gary@music.mcgill.ca' PACKAGE_URL='' ac_unique_file="RtAudio.cpp" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS objects PULSE_LIBS PULSE_CFLAGS req api libflags sharedname sharedlib host_os host_vendor host_cpu host build_os build_vendor build_cpu build object_path cxxflag cppflag EGREP GREP CPP ac_ct_CC CFLAGS CC AR RANLIB OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG GXX target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_debug with_jack with_alsa with_pulse with_oss with_core with_asio with_ds with_wasapi ' ac_precious_vars='build_alias host_alias target_alias PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CC CFLAGS CPP PULSE_CFLAGS PULSE_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures RtAudio 4.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/rtaudio] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of RtAudio 4.1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug = enable various debug output Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-jack = choose JACK server support (mac and linux only) --with-alsa = choose native ALSA API support (linux only) --with-pulse = choose PulseAudio API support (linux only) --with-oss = choose OSS API support (linux only) --with-jack = choose JACK server support (unix only) --with-core = choose CoreAudio API support (mac only) --with-asio = choose ASIO API support (windoze only) --with-ds = choose DirectSound API support (windoze only) --with-wasapi = choose Windows Audio Session API support (windoze only) Some influential environment variables: PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CC C compiler command CFLAGS C compiler flags CPP C preprocessor PULSE_CFLAGS C compiler flags for PULSE, overriding pkg-config PULSE_LIBS linker flags for PULSE, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF RtAudio configure 4.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ----------------------------------- ## ## Report this to gary@music.mcgill.ca ## ## ----------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by RtAudio $as_me 4.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in config "$srcdir"/config; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ac_config_files="$ac_config_files rtaudio-config librtaudio.pc Makefile tests/Makefile" # Fill GXX with something before test. GXX="no" if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi # Checks for programs. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ CC c++ cxx do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ CC c++ cxx do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 $as_echo_n "checking whether the C++ compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 $as_echo_n "checking for C++ compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_AR+:} false; then : $as_echo_n "(cached) " >&6 else case $AR in [\\/]* | ?:[\\/]*) ac_cv_path_AR="$AR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_AR" && ac_cv_path_AR="no" ;; esac fi AR=$ac_cv_path_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if [ $AR = "no" ] ; then as_fn_error $? "\"Could not find ar - needed to create a library\"" "$LINENO" 5; fi # Checks for header files. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/ioctl.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Check for debug { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile debug version" >&5 $as_echo_n "checking whether to compile debug version... " >&6; } # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; cppflag=-D__RTAUDIO_DEBUG__ cxxflag=-g object_path=Debug { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else cppflag= cxxflag=-O2 object_path=Release { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Checks for functions ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes; then : cppflag="$cppflag -DHAVE_GETTIMEOFDAY" fi # Set paths if prefix is defined if test "x$prefix" != "x" && test "x$prefix" != "xNONE"; then LIBS="$LIBS -L$prefix/lib" CPPFLAGS="$CPPFLAGS -I$prefix/include" fi # For -I and -D flags CPPFLAGS="$CPPFLAGS $cppflag" # For debugging and optimization ... overwrite default because it has both -g and -O2 #CXXFLAGS="$CXXFLAGS $cxxflag" CXXFLAGS="$cxxflag" # Check compiler and use -Wall if gnu. if test $GXX = "yes" ; then cxxflag="-Wall -Wextra" fi CXXFLAGS="$CXXFLAGS $cxxflag" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac sharedlib="librtaudio.so" sharedname="librtaudio.so.\$(RELEASE)" libflags="-shared -Wl,-soname,\$(SHARED).\$(MAJOR) -o \$(SHARED).\$(RELEASE)" case $host in *-apple*) sharedlib="librtaudio.dylib" sharedname="librtaudio.\$(RELEASE).dylib" libflags="-dynamiclib -o librtaudio.\$(RELEASE).dylib" esac # Checks for package options and external software api="" req="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for audio API" >&5 $as_echo_n "checking for audio API... " >&6; } case $host in *-*-netbsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: using OSS" >&5 $as_echo "using OSS" >&6; } api="$api -D__LINUX_OSS__" LIBS="$LIBS -lossaudio" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5 fi ;; *-*-linux*) # Check whether --with-jack was given. if test "${with_jack+set}" = set; then : withval=$with_jack; api="$api -D__UNIX_JACK__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using JACK" >&5 $as_echo "using JACK" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5 $as_echo_n "checking for jack_client_open in -ljack... " >&6; } if ${ac_cv_lib_jack_jack_client_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ljack $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char jack_client_open (); int main () { return jack_client_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_jack_jack_client_open=yes else ac_cv_lib_jack_jack_client_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5 $as_echo "$ac_cv_lib_jack_jack_client_open" >&6; } if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBJACK 1 _ACEOF LIBS="-ljack $LIBS" else as_fn_error $? "JACK support requires the jack library!" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5 $as_echo_n "checking for snd_pcm_open in -lasound... " >&6; } if ${ac_cv_lib_asound_snd_pcm_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lasound $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char snd_pcm_open (); int main () { return snd_pcm_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_asound_snd_pcm_open=yes else ac_cv_lib_asound_snd_pcm_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5 $as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; } if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBASOUND 1 _ACEOF LIBS="-lasound $LIBS" else as_fn_error $? "Jack support also requires the asound library!" "$LINENO" 5 fi fi # Look for ALSA flag # Check whether --with-alsa was given. if test "${with_alsa+set}" = set; then : withval=$with_alsa; api="$api -D__LINUX_ALSA__" req="$req alsa" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ALSA" >&5 $as_echo "using ALSA" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5 $as_echo_n "checking for snd_pcm_open in -lasound... " >&6; } if ${ac_cv_lib_asound_snd_pcm_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lasound $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char snd_pcm_open (); int main () { return snd_pcm_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_asound_snd_pcm_open=yes else ac_cv_lib_asound_snd_pcm_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5 $as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; } if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBASOUND 1 _ACEOF LIBS="-lasound $LIBS" else as_fn_error $? "ALSA support requires the asound library!" "$LINENO" 5 fi fi # Look for PULSE flag # Check whether --with-pulse was given. if test "${with_pulse+set}" = set; then : withval=$with_pulse; api="$api -D__LINUX_PULSE__" req="$req libpulse-simple" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using PulseAudio" >&5 $as_echo "using PulseAudio" >&6; } pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PULSE" >&5 $as_echo_n "checking for PULSE... " >&6; } if test -n "$PULSE_CFLAGS"; then pkg_cv_PULSE_CFLAGS="$PULSE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse-simple\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpulse-simple") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PULSE_CFLAGS=`$PKG_CONFIG --cflags "libpulse-simple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$PULSE_LIBS"; then pkg_cv_PULSE_LIBS="$PULSE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse-simple\""; } >&5 ($PKG_CONFIG --exists --print-errors "libpulse-simple") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_PULSE_LIBS=`$PKG_CONFIG --libs "libpulse-simple" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then PULSE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse-simple" 2>&1` else PULSE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse-simple" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$PULSE_PKG_ERRORS" >&5 as_fn_error $? "PulseAudio support requires the pulse-simple library!" "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "PulseAudio support requires the pulse-simple library!" "$LINENO" 5 else PULSE_CFLAGS=$pkg_cv_PULSE_CFLAGS PULSE_LIBS=$pkg_cv_PULSE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi LIBS="$LIBS `pkg-config --libs libpulse-simple`" fi # Look for OSS flag # Check whether --with-oss was given. if test "${with_oss+set}" = set; then : withval=$with_oss; api="$api -D__LINUX_OSS__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using OSS" >&5 $as_echo "using OSS" >&6; } fi # If no audio api flags specified, use ALSA if test "$api" == ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ALSA" >&5 $as_echo "using ALSA" >&6; } api=-D__LINUX_ALSA__ req="$req alsa" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5 $as_echo_n "checking for snd_pcm_open in -lasound... " >&6; } if ${ac_cv_lib_asound_snd_pcm_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lasound $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char snd_pcm_open (); int main () { return snd_pcm_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_asound_snd_pcm_open=yes else ac_cv_lib_asound_snd_pcm_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5 $as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; } if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBASOUND 1 _ACEOF LIBS="-lasound $LIBS" else as_fn_error $? "ALSA support requires the asound library!" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5 fi ;; *-apple*) # Check whether --with-jack was given. if test "${with_jack+set}" = set; then : withval=$with_jack; api="$api -D__UNIX_JACK__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using JACK" >&5 $as_echo "using JACK" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5 $as_echo_n "checking for jack_client_open in -ljack... " >&6; } if ${ac_cv_lib_jack_jack_client_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ljack $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char jack_client_open (); int main () { return jack_client_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_jack_jack_client_open=yes else ac_cv_lib_jack_jack_client_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5 $as_echo "$ac_cv_lib_jack_jack_client_open" >&6; } if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBJACK 1 _ACEOF LIBS="-ljack $LIBS" else as_fn_error $? "JACK support requires the jack library!" "$LINENO" 5 fi fi # AC_CHECK_HEADER(jack/jack.h, [], [AC_MSG_ERROR(Jack header file not found!)] ) # LIBS="$LIBS -framework jackmp" ], ) # Look for Core flag # Check whether --with-core was given. if test "${with_core+set}" = set; then : withval=$with_core; api="$api -D__MACOSX_CORE__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using CoreAudio" >&5 $as_echo "using CoreAudio" >&6; } ac_fn_c_check_header_mongrel "$LINENO" "CoreAudio/CoreAudio.h" "ac_cv_header_CoreAudio_CoreAudio_h" "$ac_includes_default" if test "x$ac_cv_header_CoreAudio_CoreAudio_h" = xyes; then : else as_fn_error $? "CoreAudio header files not found!" "$LINENO" 5 fi LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" fi # If no audio api flags specified, use CoreAudio if test "$api" == ""; then api=-D__MACOSX_CORE__ { $as_echo "$as_me:${as_lineno-$LINENO}: result: using CoreAudio" >&5 $as_echo "using CoreAudio" >&6; } ac_fn_c_check_header_mongrel "$LINENO" "CoreAudio/CoreAudio.h" "ac_cv_header_CoreAudio_CoreAudio_h" "$ac_includes_default" if test "x$ac_cv_header_CoreAudio_CoreAudio_h" = xyes; then : else as_fn_error $? "CoreAudio header files not found!" "$LINENO" 5 fi LIBS="-framework CoreAudio -framework CoreFoundation" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else as_fn_error $? "RtAudio requires the pthread library!" "$LINENO" 5 fi ;; *-mingw32*) # Check whether --with-asio was given. if test "${with_asio+set}" = set; then : withval=$with_asio; api="$api -D__WINDOWS_ASIO__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using ASIO" >&5 $as_echo "using ASIO" >&6; } objects="asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o" fi # Look for DirectSound flag # Check whether --with-ds was given. if test "${with_ds+set}" = set; then : withval=$with_ds; api="$api -D__WINDOWS_DS__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using DirectSound" >&5 $as_echo "using DirectSound" >&6; } LIBS="-ldsound -lwinmm $LIBS" fi # Look for WASAPI flag # Check whether --with-wasapi was given. if test "${with_wasapi+set}" = set; then : withval=$with_wasapi; api="$api -D__WINDOWS_WASAPI__" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using WASAPI" >&5 $as_echo "using WASAPI" >&6; } LIBS="-lwinmm -luuid -lksuser $LIBS" fi # If no audio api flags specified, use DS if test "$api" == ""; then api=-D__WINDOWS_DS__ { $as_echo "$as_me:${as_lineno-$LINENO}: result: using DirectSound" >&5 $as_echo "using DirectSound" >&6; } LIBS="-ldsound -lwinmm $LIBS" fi LIBS="-lole32 $LIBS" ;; *) # Default case for unknown realtime systems. as_fn_error $? "Unknown system type for realtime support!" "$LINENO" 5 ;; esac CPPFLAGS="$CPPFLAGS $api" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by RtAudio $as_me 4.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ RtAudio config.status 4.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "rtaudio-config") CONFIG_FILES="$CONFIG_FILES rtaudio-config" ;; "librtaudio.pc") CONFIG_FILES="$CONFIG_FILES librtaudio.pc" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi chmod oug+x rtaudio-config giada-0.11.2/src/deps/rtaudio-mod/configure.ac000066400000000000000000000147221264622563000211100ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. AC_INIT(RtAudio, 4.1, gary@music.mcgill.ca, rtaudio) AC_CONFIG_AUX_DIR(config) AC_CONFIG_SRCDIR(RtAudio.cpp) AC_CONFIG_FILES([rtaudio-config librtaudio.pc Makefile tests/Makefile]) # Fill GXX with something before test. AC_SUBST( GXX, ["no"] ) dnl Check for pkg-config program, used for configuring some libraries. m4_define_default([PKG_PROG_PKG_CONFIG], [AC_MSG_CHECKING([pkg-config]) AC_MSG_RESULT([no])]) PKG_PROG_PKG_CONFIG dnl If the pkg-config autoconf support isn't installed, define its dnl autoconf macro to disable any packages depending on it. m4_define_default([PKG_CHECK_MODULES], [AC_MSG_CHECKING([$1]) AC_MSG_RESULT([no]) $4]) # Checks for programs. AC_PROG_CXX(g++ CC c++ cxx) AC_PROG_RANLIB AC_PATH_PROG(AR, ar, no) if [[ $AR = "no" ]] ; then AC_MSG_ERROR("Could not find ar - needed to create a library"); fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(sys/ioctl.h unistd.h) # Check for debug AC_MSG_CHECKING(whether to compile debug version) AC_ARG_ENABLE(debug, [ --enable-debug = enable various debug output], [AC_SUBST( cppflag, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cxxflag, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)], [AC_SUBST( cppflag, [] ) AC_SUBST( cxxflag, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)]) # Checks for functions AC_CHECK_FUNC(gettimeofday, [cppflag="$cppflag -DHAVE_GETTIMEOFDAY"], ) # Set paths if prefix is defined if test "x$prefix" != "x" && test "x$prefix" != "xNONE"; then LIBS="$LIBS -L$prefix/lib" CPPFLAGS="$CPPFLAGS -I$prefix/include" fi # For -I and -D flags CPPFLAGS="$CPPFLAGS $cppflag" # For debugging and optimization ... overwrite default because it has both -g and -O2 #CXXFLAGS="$CXXFLAGS $cxxflag" CXXFLAGS="$cxxflag" # Check compiler and use -Wall if gnu. if [test $GXX = "yes" ;] then AC_SUBST( cxxflag, ["-Wall -Wextra"] ) fi CXXFLAGS="$CXXFLAGS $cxxflag" AC_CANONICAL_HOST AC_SUBST( sharedlib, ["librtaudio.so"] ) AC_SUBST( sharedname, ["librtaudio.so.\$(RELEASE)"] ) AC_SUBST( libflags, ["-shared -Wl,-soname,\$(SHARED).\$(MAJOR) -o \$(SHARED).\$(RELEASE)"] ) case $host in *-apple*) AC_SUBST( sharedlib, ["librtaudio.dylib"] ) AC_SUBST( sharedname, ["librtaudio.\$(RELEASE).dylib"] ) AC_SUBST( libflags, ["-dynamiclib -o librtaudio.\$(RELEASE).dylib"] ) esac # Checks for package options and external software AC_SUBST( api, [""] ) AC_SUBST( req, [""] ) AC_MSG_CHECKING(for audio API) case $host in *-*-netbsd*) AC_MSG_RESULT(using OSS) api="$api -D__LINUX_OSS__" LIBS="$LIBS -lossaudio" AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!)) ;; *-*-linux*) AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (mac and linux only)], [ api="$api -D__UNIX_JACK__" AC_MSG_RESULT(using JACK) AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!)) AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))], ) # Look for ALSA flag AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [ api="$api -D__LINUX_ALSA__" req="$req alsa" AC_MSG_RESULT(using ALSA) AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], ) # Look for PULSE flag AC_ARG_WITH(pulse, [ --with-pulse = choose PulseAudio API support (linux only)], [ api="$api -D__LINUX_PULSE__" req="$req libpulse-simple" AC_MSG_RESULT(using PulseAudio) PKG_CHECK_MODULES([PULSE], [libpulse-simple], , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!)) LIBS="$LIBS `pkg-config --libs libpulse-simple`" ], ) # Look for OSS flag AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [ api="$api -D__LINUX_OSS__" AC_MSG_RESULT(using OSS)], ) # If no audio api flags specified, use ALSA if [test "$api" == "";] then AC_MSG_RESULT(using ALSA) AC_SUBST( api, [-D__LINUX_ALSA__] ) req="$req alsa" AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!)) fi AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!)) ;; *-apple*) AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (unix only)], [ api="$api -D__UNIX_JACK__" AC_MSG_RESULT(using JACK) AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))], ) # AC_CHECK_HEADER(jack/jack.h, [], [AC_MSG_ERROR(Jack header file not found!)] ) # LIBS="$LIBS -framework jackmp" ], ) # Look for Core flag AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [ api="$api -D__MACOSX_CORE__" AC_MSG_RESULT(using CoreAudio) AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] ) LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" ], ) # If no audio api flags specified, use CoreAudio if [test "$api" == ""; ] then AC_SUBST( api, [-D__MACOSX_CORE__] ) AC_MSG_RESULT(using CoreAudio) AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] ) AC_SUBST( LIBS, ["-framework CoreAudio -framework CoreFoundation"] ) fi AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!)) ;; *-mingw32*) AC_ARG_WITH(asio, [ --with-asio = choose ASIO API support (windoze only)], [ api="$api -D__WINDOWS_ASIO__" AC_MSG_RESULT(using ASIO) AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) ], ) # Look for DirectSound flag AC_ARG_WITH(ds, [ --with-ds = choose DirectSound API support (windoze only)], [ api="$api -D__WINDOWS_DS__" AC_MSG_RESULT(using DirectSound) LIBS="-ldsound -lwinmm $LIBS" ], ) # Look for WASAPI flag AC_ARG_WITH(wasapi, [ --with-wasapi = choose Windows Audio Session API support (windoze only)], [ api="$api -D__WINDOWS_WASAPI__" AC_MSG_RESULT(using WASAPI) LIBS="-lwinmm -luuid -lksuser $LIBS" ], ) # If no audio api flags specified, use DS if [test "$api" == "";] then AC_SUBST( api, [-D__WINDOWS_DS__] ) AC_MSG_RESULT(using DirectSound) LIBS="-ldsound -lwinmm $LIBS" fi LIBS="-lole32 $LIBS" ;; *) # Default case for unknown realtime systems. AC_MSG_ERROR(Unknown system type for realtime support!) ;; esac CPPFLAGS="$CPPFLAGS $api" AC_OUTPUT chmod oug+x rtaudio-config giada-0.11.2/src/deps/rtaudio-mod/include/000077500000000000000000000000001264622563000202375ustar00rootroot00000000000000giada-0.11.2/src/deps/rtaudio-mod/include/FunctionDiscoveryKeys_devpkey.h000066400000000000000000000443621264622563000264610ustar00rootroot00000000000000#pragma once /*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: devpkey.h Abstract: Defines property keys for the Plug and Play Device Property API. Author: Jim Cavalaris (jamesca) 10-14-2003 Environment: User-mode only. Revision History: 14-October-2003 jamesca Creation and initial implementation. 20-June-2006 dougb Copied Jim's version replaced "DEFINE_DEVPROPKEY(DEVPKEY_" with "DEFINE_PROPERTYKEY(PKEY_" --*/ //#include // // _NAME // DEFINE_PROPERTYKEY(PKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING // // Device properties // These PKEYs correspond to the old setupapi SPDRP_XXX properties // DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_Service, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_Class, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10); // DEVPROP_TYPE_GUID DEFINE_PROPERTYKEY(PKEY_Device_Driver, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_PDOName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_Capabilities, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17); // DEVPROP_TYPE_UNINT32 DEFINE_PROPERTYKEY(PKEY_Device_UINumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21); // DEVPROP_TYPE_GUID DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_Security, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING DEFINE_PROPERTYKEY(PKEY_Device_DevType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_Exclusive, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_Characteristics, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_Address, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_PowerData, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32); // DEVPROP_TYPE_BINARY DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_InstallState, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_BaseContainerId, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38); // DEVPROP_TYPE_GUID // // Device properties // These PKEYs correspond to a device's status and problem code // DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3); // DEVPROP_TYPE_UINT32 // // Device properties // These PKEYs correspond to device relations // DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_BusRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_Children, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_Siblings, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_TransportRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11); // DEVPROP_TYPE_STRING_LIST // // Other Device properties // DEFINE_PROPERTYKEY(PKEY_Device_Reported, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_Device_Legacy, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID DEFINE_PROPERTYKEY(PKEY_Device_ModelId, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2); // DEVPROP_TYPE_GUID DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_ManufacturerAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_PresenceNotForDevice, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_DHP_Rebalance_Policy, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_InstallInProgress, 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9); // DEVPROP_TYPE_BOOLEAN // // Device driver properties // DEFINE_PROPERTYKEY(PKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2); // DEVPROP_TYPE_FILETIME DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_Device_DriverRank, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_Device_AdditionalSoftwareRequested, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19);// DEVPROP_TYPE_BOOLEAN // // Device safe-removal properties // DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequired, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequiredOverride, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3);// DEVPROP_TYPE_BOOLEAN // // Device properties that were set by the driver package that was installed // on the device. // DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7); // DEVPROP_TYPE_STRING_LIST // // Device setup class properties // These PKEYs correspond to the old setupapi SPCRP_XXX properties // DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20); // DEVPROP_TYPE_STRING_LIST DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28); // DEVPROP_TYPE_UINT32 DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29); // DEVPROP_TYPE_UINT32 // // Device setup class properties // These PKEYs correspond to registry values under the device class GUID key // DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST // // Other Device setup class properties // DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST // // Device interface properties // DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID // // Device interface class properties // DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface, 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING giada-0.11.2/src/deps/rtaudio-mod/include/asio.cpp000066400000000000000000000127111264622563000217000ustar00rootroot00000000000000/* Steinberg Audio Stream I/O API (c) 1996, Steinberg Soft- und Hardware GmbH asio.cpp asio functions entries which translate the asio interface to the asiodrvr class methods */ #include #include "asiosys.h" // platform definition #include "asio.h" #if MAC #include "asiodrvr.h" #pragma export on AsioDriver *theAsioDriver = 0; extern "C" { long main() { return 'ASIO'; } #elif WINDOWS #include "windows.h" #include "iasiodrv.h" #include "asiodrivers.h" IASIO *theAsioDriver = 0; extern AsioDrivers *asioDrivers; #elif SGI || SUN || BEOS || LINUX #include "asiodrvr.h" static AsioDriver *theAsioDriver = 0; #endif //----------------------------------------------------------------------------------------------------- ASIOError ASIOInit(ASIODriverInfo *info) { #if MAC || SGI || SUN || BEOS || LINUX if(theAsioDriver) { delete theAsioDriver; theAsioDriver = 0; } info->driverVersion = 0; strcpy(info->name, "No ASIO Driver"); theAsioDriver = getDriver(); if(!theAsioDriver) { strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); return ASE_NotPresent; } if(!theAsioDriver->init(info->sysRef)) { theAsioDriver->getErrorMessage(info->errorMessage); delete theAsioDriver; theAsioDriver = 0; return ASE_NotPresent; } strcpy(info->errorMessage, "No ASIO Driver Error"); theAsioDriver->getDriverName(info->name); info->driverVersion = theAsioDriver->getDriverVersion(); return ASE_OK; #else info->driverVersion = 0; strcpy(info->name, "No ASIO Driver"); if(theAsioDriver) // must be loaded! { if(!theAsioDriver->init(info->sysRef)) { theAsioDriver->getErrorMessage(info->errorMessage); theAsioDriver = 0; return ASE_NotPresent; } strcpy(info->errorMessage, "No ASIO Driver Error"); theAsioDriver->getDriverName(info->name); info->driverVersion = theAsioDriver->getDriverVersion(); return ASE_OK; } return ASE_NotPresent; #endif // !MAC } ASIOError ASIOExit(void) { if(theAsioDriver) { #if WINDOWS asioDrivers->removeCurrentDriver(); #else delete theAsioDriver; #endif } theAsioDriver = 0; return ASE_OK; } ASIOError ASIOStart(void) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->start(); } ASIOError ASIOStop(void) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->stop(); } ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels) { if(!theAsioDriver) { *numInputChannels = *numOutputChannels = 0; return ASE_NotPresent; } return theAsioDriver->getChannels(numInputChannels, numOutputChannels); } ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency) { if(!theAsioDriver) { *inputLatency = *outputLatency = 0; return ASE_NotPresent; } return theAsioDriver->getLatencies(inputLatency, outputLatency); } ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) { if(!theAsioDriver) { *minSize = *maxSize = *preferredSize = *granularity = 0; return ASE_NotPresent; } return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity); } ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->canSampleRate(sampleRate); } ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->getSampleRate(currentRate); } ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->setSampleRate(sampleRate); } ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources) { if(!theAsioDriver) { *numSources = 0; return ASE_NotPresent; } return theAsioDriver->getClockSources(clocks, numSources); } ASIOError ASIOSetClockSource(long reference) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->setClockSource(reference); } ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->getSamplePosition(sPos, tStamp); } ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info) { if(!theAsioDriver) { info->channelGroup = -1; info->type = ASIOSTInt16MSB; strcpy(info->name, "None"); return ASE_NotPresent; } return theAsioDriver->getChannelInfo(info); } ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) { if(!theAsioDriver) { ASIOBufferInfo *info = bufferInfos; for(long i = 0; i < numChannels; i++, info++) info->buffers[0] = info->buffers[1] = 0; return ASE_NotPresent; } return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks); } ASIOError ASIODisposeBuffers(void) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->disposeBuffers(); } ASIOError ASIOControlPanel(void) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->controlPanel(); } ASIOError ASIOFuture(long selector, void *opt) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->future(selector, opt); } ASIOError ASIOOutputReady(void) { if(!theAsioDriver) return ASE_NotPresent; return theAsioDriver->outputReady(); } #if MAC } // extern "C" #pragma export off #endif giada-0.11.2/src/deps/rtaudio-mod/include/asio.h000066400000000000000000001236111264622563000213470ustar00rootroot00000000000000//--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- /* Steinberg Audio Stream I/O API (c) 1997 - 2005, Steinberg Media Technologies GmbH ASIO Interface Specification v 2.1 2005 - Added support for DSD sample data (in cooperation with Sony) basic concept is an i/o synchronous double-buffer scheme: on bufferSwitch(index == 0), host will read/write: after ASIOStart(), the read first input buffer A (index 0) | will be invalid (empty) * ------------------------ |------------------------|-----------------------| | | | | Input Buffer A (0) | Input Buffer B (1) | | | | |------------------------|-----------------------| | | | | Output Buffer A (0) | Output Buffer B (1) | | | | |------------------------|-----------------------| * ------------------------- | before calling ASIOStart(), write host will have filled output buffer B (index 1) already *please* take special care of proper statement of input and output latencies (see ASIOGetLatencies()), these control sequencer sync accuracy */ //--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- /* prototypes summary: ASIOError ASIOInit(ASIODriverInfo *info); ASIOError ASIOExit(void); ASIOError ASIOStart(void); ASIOError ASIOStop(void); ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); ASIOError ASIOSetClockSource(long reference); ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); ASIOError ASIODisposeBuffers(void); ASIOError ASIOControlPanel(void); void *ASIOFuture(long selector, void *params); ASIOError ASIOOutputReady(void); */ //--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- #ifndef __ASIO_H #define __ASIO_H // force 4 byte alignment #if defined(_MSC_VER) && !defined(__MWERKS__) #pragma pack(push,4) #elif PRAGMA_ALIGN_SUPPORTED #pragma options align = native #endif //- - - - - - - - - - - - - - - - - - - - - - - - - // Type definitions //- - - - - - - - - - - - - - - - - - - - - - - - - // number of samples data type is 64 bit integer #if NATIVE_INT64 typedef long long int ASIOSamples; #else typedef struct ASIOSamples { unsigned long hi; unsigned long lo; } ASIOSamples; #endif // Timestamp data type is 64 bit integer, // Time format is Nanoseconds. #if NATIVE_INT64 typedef long long int ASIOTimeStamp ; #else typedef struct ASIOTimeStamp { unsigned long hi; unsigned long lo; } ASIOTimeStamp; #endif // Samplerates are expressed in IEEE 754 64 bit double float, // native format as host computer #if IEEE754_64FLOAT typedef double ASIOSampleRate; #else typedef struct ASIOSampleRate { char ieee[8]; } ASIOSampleRate; #endif // Boolean values are expressed as long typedef long ASIOBool; enum { ASIOFalse = 0, ASIOTrue = 1 }; // Sample Types are expressed as long typedef long ASIOSampleType; enum { ASIOSTInt16MSB = 0, ASIOSTInt24MSB = 1, // used for 20 bits as well ASIOSTInt32MSB = 2, ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can be more easily used with these ASIOSTInt32MSB16 = 8, // 32 bit data with 16 bit alignment ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment ASIOSTInt16LSB = 16, ASIOSTInt24LSB = 17, // used for 20 bits as well ASIOSTInt32LSB = 18, ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment // ASIO DSD format. ASIOSTDSDInt8LSB1 = 32, // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit. ASIOSTDSDInt8MSB1 = 33, // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit. ASIOSTDSDInt8NER8 = 40, // DSD 8 bit data, 1 sample per byte. No Endianness required. ASIOSTLastEntry }; /*----------------------------------------------------------------------------- // DSD operation and buffer layout // Definition by Steinberg/Sony Oxford. // // We have tried to treat DSD as PCM and so keep a consistant structure across // the ASIO interface. // // DSD's sample rate is normally referenced as a multiple of 44.1Khz, so // the standard sample rate is refered to as 64Fs (or 2.8224Mhz). We looked // at making a special case for DSD and adding a field to the ASIOFuture that // would allow the user to select the Over Sampleing Rate (OSR) as a seperate // entity but decided in the end just to treat it as a simple value of // 2.8224Mhz and use the standard interface to set it. // // The second problem was the "word" size, in PCM the word size is always a // greater than or equal to 8 bits (a byte). This makes life easy as we can // then pack the samples into the "natural" size for the machine. // In DSD the "word" size is 1 bit. This is not a major problem and can easily // be dealt with if we ensure that we always deal with a multiple of 8 samples. // // DSD brings with it another twist to the Endianness religion. How are the // samples packed into the byte. It would be nice to just say the most significant // bit is always the first sample, however there would then be a performance hit // on little endian machines. Looking at how some of the processing goes... // Little endian machines like the first sample to be in the Least Significant Bit, // this is because when you write it to memory the data is in the correct format // to be shifted in and out of the words. // Big endian machine prefer the first sample to be in the Most Significant Bit, // again for the same reasion. // // And just when things were looking really muddy there is a proposed extension to // DSD that uses 8 bit word sizes. It does not care what endianness you use. // // Switching the driver between DSD and PCM mode // ASIOFuture allows for extending the ASIO API quite transparently. // See kAsioSetIoFormat, kAsioGetIoFormat, kAsioCanDoIoFormat // //-----------------------------------------------------------------------------*/ //- - - - - - - - - - - - - - - - - - - - - - - - - // Error codes //- - - - - - - - - - - - - - - - - - - - - - - - - typedef long ASIOError; enum { ASE_OK = 0, // This value will be returned whenever the call succeeded ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls ASE_NotPresent = -1000, // hardware input or output is not present or available ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) ASE_InvalidParameter, // input parameter invalid ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode ASE_SPNotAdvancing, // hardware is not running when sample position is inquired ASE_NoClock, // sample clock or rate cannot be determined or is not present ASE_NoMemory // not enough memory for completing the request }; //--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- //- - - - - - - - - - - - - - - - - - - - - - - - - // Time Info support //- - - - - - - - - - - - - - - - - - - - - - - - - typedef struct ASIOTimeCode { double speed; // speed relation (fraction of nominal speed) // optional; set to 0. or 1. if not supported ASIOSamples timeCodeSamples; // time in samples unsigned long flags; // some information flags (see below) char future[64]; } ASIOTimeCode; typedef enum ASIOTimeCodeFlags { kTcValid = 1, kTcRunning = 1 << 1, kTcReverse = 1 << 2, kTcOnspeed = 1 << 3, kTcStill = 1 << 4, kTcSpeedValid = 1 << 8 } ASIOTimeCodeFlags; typedef struct AsioTimeInfo { double speed; // absolute speed (1. = nominal) ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds // on mac, must be derived from Microseconds() (not UpTime()!) // on windows, must be derived from timeGetTime() ASIOSamples samplePosition; ASIOSampleRate sampleRate; // current rate unsigned long flags; // (see below) char reserved[12]; } AsioTimeInfo; typedef enum AsioTimeInfoFlags { kSystemTimeValid = 1, // must always be valid kSamplePositionValid = 1 << 1, // must always be valid kSampleRateValid = 1 << 2, kSpeedValid = 1 << 3, kSampleRateChanged = 1 << 4, kClockSourceChanged = 1 << 5 } AsioTimeInfoFlags; typedef struct ASIOTime // both input/output { long reserved[4]; // must be 0 struct AsioTimeInfo timeInfo; // required struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) } ASIOTime; /* using time info: it is recommended to use the new method with time info even if the asio device does not support timecode; continuous calls to ASIOGetSamplePosition and ASIOGetSampleRate are avoided, and there is a more defined relationship between callback time and the time info. see the example below. to initiate time info mode, after you have received the callbacks pointer in ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo as the argument. if this returns 1, host has accepted time info mode. now host expects the new callback bufferSwitchTimeInfo to be used instead of the old bufferSwitch method. the ASIOTime structure is assumed to be valid and accessible until the callback returns. using time code: if the device supports reading time code, it will call host's asioMessage callback with kAsioSupportsTimeCode as the selector. it may then fill the according fields and set the kTcValid flag. host will call the future method with the kAsioEnableTimeCodeRead selector when it wants to enable or disable tc reading by the device. you should also support the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). note: the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. as a matter of convention, the relationship between the sample position counter and the time code at buffer switch time is (ignoring offset between tc and sample pos when tc is running): on input: sample 0 -> input buffer sample 0 -> time code 0 on output: sample 0 -> output buffer sample 0 -> time code 0 this means that for 'real' calculations, one has to take into account the according latencies. example: ASIOTime asioTime; in createBuffers() { memset(&asioTime, 0, sizeof(ASIOTime)); AsioTimeInfo* ti = &asioTime.timeInfo; ti->sampleRate = theSampleRate; ASIOTimeCode* tc = &asioTime.timeCode; tc->speed = 1.; timeInfoMode = false; canTimeCode = false; if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) { timeInfoMode = true; #if kCanTimeCode if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) canTimeCode = true; #endif } } void switchBuffers(long doubleBufferIndex, bool processNow) { if(timeInfoMode) { AsioTimeInfo* ti = &asioTime.timeInfo; ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; ti->systemTime = theNanoSeconds; ti->samplePosition = theSamplePosition; if(ti->sampleRate != theSampleRate) ti->flags |= kSampleRateChanged; ti->sampleRate = theSampleRate; #if kCanTimeCode if(canTimeCode && timeCodeEnabled) { ASIOTimeCode* tc = &asioTime.timeCode; tc->timeCodeSamples = tcSamples; // tc in samples tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... } ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); #else callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); #endif } else callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); } ASIOError ASIOFuture(long selector, void *params) { switch(selector) { case kAsioEnableTimeCodeRead: timeCodeEnabled = true; return ASE_SUCCESS; case kAsioDisableTimeCodeRead: timeCodeEnabled = false; return ASE_SUCCESS; case kAsioCanTimeInfo: return ASE_SUCCESS; #if kCanTimeCode case kAsioCanTimeCode: return ASE_SUCCESS; #endif } return ASE_NotPresent; }; */ //- - - - - - - - - - - - - - - - - - - - - - - - - // application's audio stream handler callbacks //- - - - - - - - - - - - - - - - - - - - - - - - - typedef struct ASIOCallbacks { void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess); // bufferSwitch indicates that both input and output are to be processed. // the current buffer half index (0 for A, 1 for B) determines // - the output buffer that the host should start to fill. the other buffer // will be passed to output hardware regardless of whether it got filled // in time or not. // - the input buffer that is now filled with incoming data. Note that // because of the synchronicity of i/o, the input always has at // least one buffer latency in relation to the output. // directProcess suggests to the host whether it should immedeately // start processing (directProcess == ASIOTrue), or whether its process // should be deferred because the call comes from a very low level // (for instance, a high level priority interrupt), and direct processing // would cause timing instabilities for the rest of the system. If in doubt, // directProcess should be set to ASIOFalse. // Note: bufferSwitch may be called at interrupt time for highest efficiency. void (*sampleRateDidChange) (ASIOSampleRate sRate); // gets called when the AudioStreamIO detects a sample rate change // If sample rate is unknown, 0 is passed (for instance, clock loss // when externally synchronized). long (*asioMessage) (long selector, long value, void* message, double* opt); // generic callback for various purposes, see selectors below. // note this is only present if the asio version is 2 or higher ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess); // new callback with time info. makes ASIOGetSamplePosition() and various // calls to ASIOGetSampleRate obsolete, // and allows for timecode sync etc. to be preferred; will be used if // the driver calls asioMessage with selector kAsioSupportsTimeInfo. } ASIOCallbacks; // asioMessage selectors enum { kAsioSelectorSupported = 1, // selector in , returns 1L if supported, // 0 otherwise kAsioEngineVersion, // returns engine (host) asio implementation version, // 2 or higher kAsioResetRequest, // request driver reset. if accepted, this // will close the driver (ASIO_Exit() ) and // re-open it again (ASIO_Init() etc). some // drivers need to reconfigure for instance // when the sample rate changes, or some basic // changes have been made in ASIO_ControlPanel(). // returns 1L; note the request is merely passed // to the application, there is no way to determine // if it gets accepted at this time (but it usually // will be). kAsioBufferSizeChange, // not yet supported, will currently always return 0L. // for now, use kAsioResetRequest instead. // once implemented, the new buffer size is expected // in , and on success returns 1L kAsioResyncRequest, // the driver went out of sync, such that // the timestamp is no longer valid. this // is a request to re-start the engine and // slave devices (sequencer). returns 1 for ok, // 0 if not supported. kAsioLatenciesChanged, // the drivers latencies have changed. The engine // will refetch the latencies. kAsioSupportsTimeInfo, // if host returns true here, it will expect the // callback bufferSwitchTimeInfo to be called instead // of bufferSwitch kAsioSupportsTimeCode, // kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this kAsioSupportsInputGain, // unused and undefined kAsioSupportsInputMeter, // unused and undefined kAsioSupportsOutputGain, // unused and undefined kAsioSupportsOutputMeter, // unused and undefined kAsioOverload, // driver detected an overload kAsioNumMessageSelectors }; //--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- //- - - - - - - - - - - - - - - - - - - - - - - - - // (De-)Construction //- - - - - - - - - - - - - - - - - - - - - - - - - typedef struct ASIODriverInfo { long asioVersion; // currently, 2 long driverVersion; // driver specific char name[32]; char errorMessage[124]; void *sysRef; // on input: system reference // (Windows: application main window handle, Mac & SGI: 0) } ASIODriverInfo; ASIOError ASIOInit(ASIODriverInfo *info); /* Purpose: Initialize the AudioStreamIO. Parameter: info: pointer to an ASIODriver structure: - asioVersion: - on input, the host version. *** Note *** this is 0 for earlier asio implementations, and the asioMessage callback is implemeted only if asioVersion is 2 or greater. sorry but due to a design fault the driver doesn't have access to the host version in ASIOInit :-( added selector for host (engine) version in the asioMessage callback so we're ok from now on. - on return, asio implementation version. older versions are 1 if you support this version (namely, ASIO_outputReady() ) this should be 2 or higher. also see the note in ASIO_getTimeStamp() ! - version: on return, the driver version (format is driver specific) - name: on return, a null-terminated string containing the driver's name - error message: on return, should contain a user message describing the type of error that occured during ASIOInit(), if any. - sysRef: platform specific Returns: If neither input nor output is present ASE_NotPresent will be returned. ASE_NoMemory, ASE_HWMalfunction are other possible error conditions */ ASIOError ASIOExit(void); /* Purpose: Terminates the AudioStreamIO. Parameter: None. Returns: If neither input nor output is present ASE_NotPresent will be returned. Notes: this implies ASIOStop() and ASIODisposeBuffers(), meaning that no host callbacks must be accessed after ASIOExit(). */ //- - - - - - - - - - - - - - - - - - - - - - - - - // Start/Stop //- - - - - - - - - - - - - - - - - - - - - - - - - ASIOError ASIOStart(void); /* Purpose: Start input and output processing synchronously. This will - reset the sample counter to zero - start the hardware (both input and output) The first call to the hosts' bufferSwitch(index == 0) then tells the host to read from input buffer A (index 0), and start processing to output buffer A while output buffer B (which has been filled by the host prior to calling ASIOStart()) is possibly sounding (see also ASIOGetLatencies()) Parameter: None. Returns: If neither input nor output is present, ASE_NotPresent will be returned. If the hardware fails to start, ASE_HWMalfunction will be returned. Notes: There is no restriction on the time that ASIOStart() takes to perform (that is, it is not considered a realtime trigger). */ ASIOError ASIOStop(void); /* Purpose: Stops input and output processing altogether. Parameter: None. Returns: If neither input nor output is present ASE_NotPresent will be returned. Notes: On return from ASIOStop(), the driver must in no case call the hosts' bufferSwitch() routine. */ //- - - - - - - - - - - - - - - - - - - - - - - - - // Inquiry methods and sample rate //- - - - - - - - - - - - - - - - - - - - - - - - - ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); /* Purpose: Returns number of individual input/output channels. Parameter: numInputChannels will hold the number of available input channels numOutputChannels will hold the number of available output channels Returns: If no input/output is present ASE_NotPresent will be returned. If only inputs, or only outputs are available, the according other parameter will be zero, and ASE_OK is returned. */ ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); /* Purpose: Returns the input and output latencies. This includes device specific delays, like FIFOs etc. Parameter: inputLatency will hold the 'age' of the first sample frame in the input buffer when the hosts reads it in bufferSwitch() (this is theoretical, meaning it does not include the overhead and delay between the actual physical switch, and the time when bufferSitch() enters). This will usually be the size of one block in sample frames, plus device specific latencies. outputLatency will specify the time between the buffer switch, and the time when the next play buffer will start to sound. The next play buffer is defined as the one the host starts processing after (or at) bufferSwitch(), indicated by the index parameter (0 for buffer A, 1 for buffer B). It will usually be either one block, if the host writes directly to a dma buffer, or two or more blocks if the buffer is 'latched' by the driver. As an example, on ASIOStart(), the host will have filled the play buffer at index 1 already; when it gets the callback (with the parameter index == 0), this tells it to read from the input buffer 0, and start to fill the play buffer 0 (assuming that now play buffer 1 is already sounding). In this case, the output latency is one block. If the driver decides to copy buffer 1 at that time, and pass it to the hardware at the next slot (which is most commonly done, but should be avoided), the output latency becomes two blocks instead, resulting in a total i/o latency of at least 3 blocks. As memory access is the main bottleneck in native dsp processing, and to acheive less latency, it is highly recommended to try to avoid copying (this is also why the driver is the owner of the buffers). To summarize, the minimum i/o latency can be acheived if the input buffer is processed by the host into the output buffer which will physically start to sound on the next time slice. Also note that the host expects the bufferSwitch() callback to be accessed for each time slice in order to retain sync, possibly recursively; if it fails to process a block in time, it will suspend its operation for some time in order to recover. Returns: If no input/output is present ASE_NotPresent will be returned. */ ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); /* Purpose: Returns min, max, and preferred buffer sizes for input/output Parameter: minSize will hold the minimum buffer size maxSize will hold the maxium possible buffer size preferredSize will hold the preferred buffer size (a size which best fits performance and hardware requirements) granularity will hold the granularity at which buffer sizes may differ. Usually, the buffer size will be a power of 2; in this case, granularity will hold -1 on return, signalling possible buffer sizes starting from minSize, increased in powers of 2 up to maxSize. Returns: If no input/output is present ASE_NotPresent will be returned. Notes: When minimum and maximum buffer size are equal, the preferred buffer size has to be the same value as well; granularity should be 0 in this case. */ ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); /* Purpose: Inquires the hardware for the available sample rates. Parameter: sampleRate is the rate in question. Returns: If the inquired sample rate is not supported, ASE_NoClock will be returned. If no input/output is present ASE_NotPresent will be returned. */ ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); /* Purpose: Get the current sample Rate. Parameter: currentRate will hold the current sample rate on return. Returns: If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. If no input/output is present ASE_NotPresent will be returned. Notes: */ ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); /* Purpose: Set the hardware to the requested sample Rate. If sampleRate == 0, enable external sync. Parameter: sampleRate: on input, the requested rate Returns: If sampleRate is unknown ASE_NoClock will be returned. If the current clock is external, and sampleRate is != 0, ASE_InvalidMode will be returned If no input/output is present ASE_NotPresent will be returned. Notes: */ typedef struct ASIOClockSource { long index; // as used for ASIOSetClockSource() long associatedChannel; // for instance, S/PDIF or AES/EBU long associatedGroup; // see channel groups (ASIOGetChannelInfo()) ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source char name[32]; // for user selection } ASIOClockSource; ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); /* Purpose: Get the available external audio clock sources Parameter: clocks points to an array of ASIOClockSource structures: - index: this is used to identify the clock source when ASIOSetClockSource() is accessed, should be an index counting from zero - associatedInputChannel: the first channel of an associated input group, if any. - associatedGroup: the group index of that channel. groups of channels are defined to seperate for instance analog, S/PDIF, AES/EBU, ADAT connectors etc, when present simultaniously. Note that associated channel is enumerated according to numInputs/numOutputs, means it is independant from a group (see also ASIOGetChannelInfo()) inputs are associated to a clock if the physical connection transfers both data and clock (like S/PDIF, AES/EBU, or ADAT inputs). if there is no input channel associated with the clock source (like Word Clock, or internal oscillator), both associatedChannel and associatedGroup should be set to -1. - isCurrentSource: on exit, ASIOTrue if this is the current clock source, ASIOFalse else - name: a null-terminated string for user selection of the available sources. numSources: on input: the number of allocated array members on output: the number of available clock sources, at least 1 (internal clock generator). Returns: If no input/output is present ASE_NotPresent will be returned. Notes: */ ASIOError ASIOSetClockSource(long index); /* Purpose: Set the audio clock source Parameter: index as obtained from an inquiry to ASIOGetClockSources() Returns: If no input/output is present ASE_NotPresent will be returned. If the clock can not be selected because an input channel which carries the current clock source is active, ASE_InvalidMode *may* be returned (this depends on the properties of the driver and/or hardware). Notes: Should *not* return ASE_NoClock if there is no clock signal present at the selected source; this will be inquired via ASIOGetSampleRate(). It should call the host callback procedure sampleRateHasChanged(), if the switch causes a sample rate change, or if no external clock is present at the selected source. */ ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); /* Purpose: Inquires the sample position/time stamp pair. Parameter: sPos will hold the sample position on return. The sample position is reset to zero when ASIOStart() gets called. tStamp will hold the system time when the sample position was latched. Returns: If no input/output is present, ASE_NotPresent will be returned. If there is no clock, ASE_SPNotAdvancing will be returned. Notes: in order to be able to synchronise properly, the sample position / time stamp pair must refer to the current block, that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() callback and expect the time for the current block. thus, when requested in the very first bufferSwitch after ASIO_Start(), the sample position should be zero, and the time stamp should refer to the very time where the stream was started. it also means that the sample position must be block aligned. the driver must ensure proper interpolation if the system time can not be determined for the block position. the driver is responsible for precise time stamps as it usually has most direct access to lower level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() are essential for precise media synchronization! */ typedef struct ASIOChannelInfo { long channel; // on input, channel index ASIOBool isInput; // on input ASIOBool isActive; // on exit long channelGroup; // dto ASIOSampleType type; // dto char name[32]; // dto } ASIOChannelInfo; ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); /* Purpose: retreive information about the nature of a channel Parameter: info: pointer to a ASIOChannelInfo structure with - channel: on input, the channel index of the channel in question. - isInput: on input, ASIOTrue if info for an input channel is requested, else output - channelGroup: on return, the channel group that the channel belongs to. For drivers which support different types of channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, there should be a reasonable grouping of these types. Groups are always independant form a channel index, that is, a channel index always counts from 0 to numInputs/numOutputs regardless of the group it may belong to. There will always be at least one group (group 0). Please also note that by default, the host may decide to activate channels 0 and 1; thus, these should belong to the most useful type (analog i/o, if present). - type: on return, contains the sample type of the channel - isActive: on return, ASIOTrue if channel is active as it was installed by ASIOCreateBuffers(), ASIOFalse else - name: describing the type of channel in question. Used to allow for user selection, and enabling of specific channels. examples: "Analog In", "SPDIF Out" etc Returns: If no input/output is present ASE_NotPresent will be returned. Notes: If possible, the string should be organised such that the first characters are most significantly describing the nature of the port, to allow for identification even if the view showing the port name is too small to display more than 8 characters, for instance. */ //- - - - - - - - - - - - - - - - - - - - - - - - - // Buffer preparation //- - - - - - - - - - - - - - - - - - - - - - - - - typedef struct ASIOBufferInfo { ASIOBool isInput; // on input: ASIOTrue: input, else output long channelNum; // on input: channel index void *buffers[2]; // on output: double buffer addresses } ASIOBufferInfo; ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); /* Purpose: Allocates input/output buffers for all input and output channels to be activated. Parameter: bufferInfos is a pointer to an array of ASIOBufferInfo structures: - isInput: on input, ASIOTrue if the buffer is to be allocated for an input, output buffer else - channelNum: on input, the index of the channel in question (counting from 0) - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. the size of the buffer(s) of course depend on both the ASIOSampleType as obtained from ASIOGetChannelInfo(), and bufferSize numChannels is the sum of all input and output channels to be created; thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo structures. bufferSize selects one of the possible buffer sizes as obtained from ASIOGetBufferSizes(). callbacks is a pointer to an ASIOCallbacks structure. Returns: If not enough memory is available ASE_NoMemory will be returned. If no input/output is present ASE_NotPresent will be returned. If bufferSize is not supported, or one or more of the bufferInfos elements contain invalid settings, ASE_InvalidMode will be returned. Notes: If individual channel selection is not possible but requested, the driver has to handle this. namely, bufferSwitch() will only have filled buffers of enabled outputs. If possible, processing and buss activities overhead should be avoided for channels which were not enabled here. */ ASIOError ASIODisposeBuffers(void); /* Purpose: Releases all buffers for the device. Parameter: None. Returns: If no buffer were ever prepared, ASE_InvalidMode will be returned. If no input/output is present ASE_NotPresent will be returned. Notes: This implies ASIOStop(). */ ASIOError ASIOControlPanel(void); /* Purpose: request the driver to start a control panel component for device specific user settings. This will not be accessed on some platforms (where the component is accessed instead). Parameter: None. Returns: If no panel is available ASE_NotPresent will be returned. Actually, the return code is ignored. Notes: if the user applied settings which require a re-configuration of parts or all of the enigine and/or driver (such as a change of the block size), the asioMessage callback can be used (see ASIO_Callbacks). */ ASIOError ASIOFuture(long selector, void *params); /* Purpose: various Parameter: selector: operation Code as to be defined. zero is reserved for testing purposes. params: depends on the selector; usually pointer to a structure for passing and retreiving any type and amount of parameters. Returns: the return value is also selector dependant. if the selector is unknown, ASE_InvalidParameter should be returned to prevent further calls with this selector. on success, ASE_SUCCESS must be returned (note: ASE_OK is *not* sufficient!) Notes: see selectors defined below. */ enum { kAsioEnableTimeCodeRead = 1, // no arguments kAsioDisableTimeCodeRead, // no arguments kAsioSetInputMonitor, // ASIOInputMonitor* in params kAsioTransport, // ASIOTransportParameters* in params kAsioSetInputGain, // ASIOChannelControls* in params, apply gain kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors kAsioCanTimeInfo, kAsioCanTimeCode, kAsioCanTransport, kAsioCanInputGain, kAsioCanInputMeter, kAsioCanOutputGain, kAsioCanOutputMeter, // DSD support // The following extensions are required to allow switching // and control of the DSD subsystem. kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */ kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */ kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */ }; typedef struct ASIOInputMonitor { long input; // this input was set to monitor (or off), -1: all long output; // suggested output for monitoring the input (if so) long gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) ASIOBool state; // ASIOTrue => on, ASIOFalse => off long pan; // suggested pan, 0 => all left, 0x7fffffff => right } ASIOInputMonitor; typedef struct ASIOChannelControls { long channel; // on input, channel index ASIOBool isInput; // on input long gain; // on input, ranges 0 thru 0x7fffffff long meter; // on return, ranges 0 thru 0x7fffffff char future[32]; } ASIOChannelControls; typedef struct ASIOTransportParameters { long command; // see enum below ASIOSamples samplePosition; long track; long trackSwitches[16]; // 512 tracks on/off char future[64]; } ASIOTransportParameters; enum { kTransStart = 1, kTransStop, kTransLocate, // to samplePosition kTransPunchIn, kTransPunchOut, kTransArmOn, // track kTransArmOff, // track kTransMonitorOn, // track kTransMonitorOff, // track kTransArm, // trackSwitches kTransMonitor // trackSwitches }; /* // DSD support // Some notes on how to use ASIOIoFormatType. // // The caller will fill the format with the request types. // If the board can do the request then it will leave the // values unchanged. If the board does not support the // request then it will change that entry to Invalid (-1) // // So to request DSD then // // ASIOIoFormat NeedThis={kASIODSDFormat}; // // if(ASE_SUCCESS != ASIOFuture(kAsioSetIoFormat,&NeedThis) ){ // // If the board did not accept one of the parameters then the // // whole call will fail and the failing parameter will // // have had its value changes to -1. // } // // Note: Switching between the formats need to be done before the "prepared" // state (see ASIO 2 documentation) is entered. */ typedef long int ASIOIoFormatType; enum ASIOIoFormatType_e { kASIOFormatInvalid = -1, kASIOPCMFormat = 0, kASIODSDFormat = 1, }; typedef struct ASIOIoFormat_s { ASIOIoFormatType FormatType; char future[512-sizeof(ASIOIoFormatType)]; } ASIOIoFormat; ASIOError ASIOOutputReady(void); /* Purpose: this tells the driver that the host has completed processing the output buffers. if the data format required by the hardware differs from the supported asio formats, but the hardware buffers are DMA buffers, the driver will have to convert the audio stream data; as the bufferSwitch callback is usually issued at dma block switch time, the driver will have to convert the *previous* host buffer, which increases the output latency by one block. when the host finds out that ASIOOutputReady() returns true, it will issue this call whenever it completed output processing. then the driver can convert the host data directly to the dma buffer to be played next, reducing output latency by one block. another way to look at it is, that the buffer switch is called in order to pass the *input* stream to the host, so that it can process the input into the output, and the output stream is passed to the driver when the host has completed its process. Parameter: None Returns: only if the above mentioned scenario is given, and a reduction of output latency can be acheived by this mechanism, should ASE_OK be returned. otherwise (and usually), ASE_NotPresent should be returned in order to prevent further calls to this function. note that the host may want to determine if it is to use this when the system is not yet fully initialized, so ASE_OK should always be returned if the mechanism makes sense. Notes: please remeber to adjust ASIOGetLatencies() according to whether ASIOOutputReady() was ever called or not, if your driver supports this scenario. also note that the engine may fail to call ASIO_OutputReady() in time in overload cases. as already mentioned, bufferSwitch should be called for every block regardless of whether a block could be processed in time. */ // restore old alignment #if defined(_MSC_VER) && !defined(__MWERKS__) #pragma pack(pop) #elif PRAGMA_ALIGN_SUPPORTED #pragma options align = reset #endif #endif giada-0.11.2/src/deps/rtaudio-mod/include/asiodrivers.cpp000066400000000000000000000065421264622563000233040ustar00rootroot00000000000000#include #include "asiodrivers.h" AsioDrivers* asioDrivers = 0; bool loadAsioDriver(char *name); bool loadAsioDriver(char *name) { if(!asioDrivers) asioDrivers = new AsioDrivers(); if(asioDrivers) return asioDrivers->loadDriver(name); return false; } //------------------------------------------------------------------------------------ #if MAC bool resolveASIO(unsigned long aconnID); AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio') { connID = -1; curIndex = -1; } AsioDrivers::~AsioDrivers() { removeCurrentDriver(); } bool AsioDrivers::getCurrentDriverName(char *name) { if(curIndex >= 0) return getName(curIndex, name); return false; } long AsioDrivers::getDriverNames(char **names, long maxDrivers) { for(long i = 0; i < getNumFragments() && i < maxDrivers; i++) getName(i, names[i]); return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers; } bool AsioDrivers::loadDriver(char *name) { char dname[64]; unsigned long newID; for(long i = 0; i < getNumFragments(); i++) { if(getName(i, dname) && !strcmp(name, dname)) { if(newInstance(i, &newID)) { if(resolveASIO(newID)) { if(connID != -1) removeInstance(curIndex, connID); curIndex = i; connID = newID; return true; } } break; } } return false; } void AsioDrivers::removeCurrentDriver() { if(connID != -1) removeInstance(curIndex, connID); connID = -1; curIndex = -1; } //------------------------------------------------------------------------------------ #elif WINDOWS #include "iasiodrv.h" extern IASIO* theAsioDriver; AsioDrivers::AsioDrivers() : AsioDriverList() { curIndex = -1; } AsioDrivers::~AsioDrivers() { } bool AsioDrivers::getCurrentDriverName(char *name) { if(curIndex >= 0) return asioGetDriverName(curIndex, name, 32) == 0 ? true : false; name[0] = 0; return false; } long AsioDrivers::getDriverNames(char **names, long maxDrivers) { for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++) asioGetDriverName(i, names[i], 32); return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers; } bool AsioDrivers::loadDriver(char *name) { char dname[64]; char curName[64]; for(long i = 0; i < asioGetNumDev(); i++) { if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname)) { curName[0] = 0; getCurrentDriverName(curName); // in case we fail... removeCurrentDriver(); if(!asioOpenDriver(i, (void **)&theAsioDriver)) { curIndex = i; return true; } else { theAsioDriver = 0; if(curName[0] && strcmp(dname, curName)) loadDriver(curName); // try restore } break; } } return false; } void AsioDrivers::removeCurrentDriver() { if(curIndex != -1) asioCloseDriver(curIndex); curIndex = -1; } #elif SGI || BEOS #include "asiolist.h" AsioDrivers::AsioDrivers() : AsioDriverList() { curIndex = -1; } AsioDrivers::~AsioDrivers() { } bool AsioDrivers::getCurrentDriverName(char *name) { return false; } long AsioDrivers::getDriverNames(char **names, long maxDrivers) { return 0; } bool AsioDrivers::loadDriver(char *name) { return false; } void AsioDrivers::removeCurrentDriver() { } #else #error implement me #endif giada-0.11.2/src/deps/rtaudio-mod/include/asiodrivers.h000066400000000000000000000013171264622563000227440ustar00rootroot00000000000000#ifndef __AsioDrivers__ #define __AsioDrivers__ #include "ginclude.h" #if MAC #include "CodeFragments.hpp" class AsioDrivers : public CodeFragments #elif WINDOWS #include #include "asiolist.h" class AsioDrivers : public AsioDriverList #elif SGI || BEOS #include "asiolist.h" class AsioDrivers : public AsioDriverList #else #error implement me #endif { public: AsioDrivers(); ~AsioDrivers(); bool getCurrentDriverName(char *name); long getDriverNames(char **names, long maxDrivers); bool loadDriver(char *name); void removeCurrentDriver(); long getCurrentDriverIndex() {return curIndex;} protected: unsigned long connID; long curIndex; }; #endif giada-0.11.2/src/deps/rtaudio-mod/include/asiodrvr.h000066400000000000000000000043321264622563000222430ustar00rootroot00000000000000/* Steinberg Audio Stream I/O API (c) 1996, Steinberg Soft- und Hardware GmbH charlie (May 1996) asiodrvr.h c++ superclass to implement asio functionality. from this, you can derive whatever required */ #ifndef _asiodrvr_ #define _asiodrvr_ // cpu and os system we are running on #include "asiosys.h" // basic "C" interface #include "asio.h" class AsioDriver; extern AsioDriver *getDriver(); // for generic constructor #if WINDOWS #include #include "combase.h" #include "iasiodrv.h" class AsioDriver : public IASIO ,public CUnknown { public: AsioDriver(LPUNKNOWN pUnk, HRESULT *phr); DECLARE_IUNKNOWN // Factory method static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); // IUnknown virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); #else class AsioDriver { public: AsioDriver(); #endif virtual ~AsioDriver(); virtual ASIOBool init(void* sysRef); virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero virtual long getDriverVersion(); virtual void getErrorMessage(char *string); // max 124 bytes incl. virtual ASIOError start(); virtual ASIOError stop(); virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); virtual ASIOError setClockSource(long reference); virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); virtual ASIOError getChannelInfo(ASIOChannelInfo *info); virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); virtual ASIOError disposeBuffers(); virtual ASIOError controlPanel(); virtual ASIOError future(long selector, void *opt); virtual ASIOError outputReady(); }; #endif giada-0.11.2/src/deps/rtaudio-mod/include/asiolist.cpp000066400000000000000000000167741264622563000226110ustar00rootroot00000000000000#include #include "iasiodrv.h" #include "asiolist.h" #define ASIODRV_DESC "description" #define INPROC_SERVER "InprocServer32" #define ASIO_PATH "software\\asio" #define COM_CLSID "clsid" // ****************************************************************** // Local Functions // ****************************************************************** static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize) { HKEY hkEnum,hksub,hkpath; char databuf[512]; LONG cr,rc = -1; DWORD datatype,datasize; DWORD index; OFSTRUCT ofs; HFILE hfile; BOOL found = FALSE; #ifdef UNICODE CharLowerBuffA(clsidstr,strlen(clsidstr)); if ((cr = RegOpenKeyA(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { index = 0; while (cr == ERROR_SUCCESS && !found) { cr = RegEnumKeyA(hkEnum,index++,databuf,512); if (cr == ERROR_SUCCESS) { CharLowerBuffA(databuf,strlen(databuf)); if (!(strcmp(databuf,clsidstr))) { if ((cr = RegOpenKeyExA(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { if ((cr = RegOpenKeyExA(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { datatype = REG_SZ; datasize = (DWORD)dllpathsize; cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); if (cr == ERROR_SUCCESS) { memset(&ofs,0,sizeof(OFSTRUCT)); ofs.cBytes = sizeof(OFSTRUCT); hfile = OpenFile(dllpath,&ofs,OF_EXIST); if (hfile) rc = 0; } RegCloseKey(hkpath); } RegCloseKey(hksub); } found = TRUE; // break out } } } RegCloseKey(hkEnum); } #else CharLowerBuff(clsidstr,strlen(clsidstr)); if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { index = 0; while (cr == ERROR_SUCCESS && !found) { cr = RegEnumKey(hkEnum,index++,databuf,512); if (cr == ERROR_SUCCESS) { CharLowerBuff(databuf,strlen(databuf)); if (!(strcmp(databuf,clsidstr))) { if ((cr = RegOpenKeyEx(hkEnum,databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { if ((cr = RegOpenKeyEx(hksub,INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { datatype = REG_SZ; datasize = (DWORD)dllpathsize; cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); if (cr == ERROR_SUCCESS) { memset(&ofs,0,sizeof(OFSTRUCT)); ofs.cBytes = sizeof(OFSTRUCT); hfile = OpenFile(dllpath,&ofs,OF_EXIST); if (hfile) rc = 0; } RegCloseKey(hkpath); } RegCloseKey(hksub); } found = TRUE; // break out } } } RegCloseKey(hkEnum); } #endif return rc; } static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv) { HKEY hksub; char databuf[256]; char dllpath[MAXPATHLEN]; WORD wData[100]; CLSID clsid; DWORD datatype,datasize; LONG cr,rc; if (!lpdrv) { if ((cr = RegOpenKeyExA(hkey,keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { datatype = REG_SZ; datasize = 256; cr = RegQueryValueExA(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize); if (cr == ERROR_SUCCESS) { rc = findDrvPath (databuf,dllpath,MAXPATHLEN); if (rc == 0) { lpdrv = new ASIODRVSTRUCT[1]; if (lpdrv) { memset(lpdrv,0,sizeof(ASIODRVSTRUCT)); lpdrv->drvID = drvID; MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100); if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) { memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID)); } datatype = REG_SZ; datasize = 256; cr = RegQueryValueExA(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize); if (cr == ERROR_SUCCESS) { strcpy(lpdrv->drvname,databuf); } else strcpy(lpdrv->drvname,keyname); } } } RegCloseKey(hksub); } } else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next); return lpdrv; } static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv) { IASIO *iasio; if (lpdrv != 0) { deleteDrvStruct(lpdrv->next); if (lpdrv->asiodrv) { iasio = (IASIO *)lpdrv->asiodrv; iasio->Release(); } delete lpdrv; } } static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv) { while (lpdrv) { if (lpdrv->drvID == drvID) return lpdrv; lpdrv = lpdrv->next; } return 0; } // ****************************************************************** // ****************************************************************** // AsioDriverList // ****************************************************************** AsioDriverList::AsioDriverList () { HKEY hkEnum = 0; char keyname[MAXDRVNAMELEN]; LPASIODRVSTRUCT pdl; LONG cr; DWORD index = 0; BOOL fin = FALSE; numdrv = 0; lpdrvlist = 0; #ifdef UNICODE cr = RegOpenKeyA(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); #else cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); #endif while (cr == ERROR_SUCCESS) { #ifdef UNICODE if ((cr = RegEnumKeyA(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { #else if ((cr = RegEnumKey(hkEnum,index++,keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { #endif lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist); } else fin = TRUE; } if (hkEnum) RegCloseKey(hkEnum); pdl = lpdrvlist; while (pdl) { numdrv++; pdl = pdl->next; } if (numdrv) CoInitialize(0); // initialize COM } AsioDriverList::~AsioDriverList () { if (numdrv) { deleteDrvStruct(lpdrvlist); CoUninitialize(); } } LONG AsioDriverList::asioGetNumDev (VOID) { return (LONG)numdrv; } LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv) { LPASIODRVSTRUCT lpdrv = 0; long rc; if (!asiodrv) return DRVERR_INVALID_PARAM; if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { if (!lpdrv->asiodrv) { rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv); if (rc == S_OK) { lpdrv->asiodrv = *asiodrv; return 0; } // else if (rc == REGDB_E_CLASSNOTREG) // strcpy (info->messageText, "Driver not registered in the Registration Database!"); } else rc = DRVERR_DEVICE_ALREADY_OPEN; } else rc = DRVERR_DEVICE_NOT_FOUND; return rc; } LONG AsioDriverList::asioCloseDriver (int drvID) { LPASIODRVSTRUCT lpdrv = 0; IASIO *iasio; if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { if (lpdrv->asiodrv) { iasio = (IASIO *)lpdrv->asiodrv; iasio->Release(); lpdrv->asiodrv = 0; } } return 0; } LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize) { LPASIODRVSTRUCT lpdrv = 0; if (!drvname) return DRVERR_INVALID_PARAM; if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) { strcpy(drvname,lpdrv->drvname); } else { memcpy(drvname,lpdrv->drvname,drvnamesize-4); drvname[drvnamesize-4] = '.'; drvname[drvnamesize-3] = '.'; drvname[drvnamesize-2] = '.'; drvname[drvnamesize-1] = 0; } return 0; } return DRVERR_DEVICE_NOT_FOUND; } LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize) { LPASIODRVSTRUCT lpdrv = 0; if (!dllpath) return DRVERR_INVALID_PARAM; if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) { strcpy(dllpath,lpdrv->dllpath); return 0; } dllpath[0] = 0; return DRVERR_INVALID_PARAM; } return DRVERR_DEVICE_NOT_FOUND; } LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid) { LPASIODRVSTRUCT lpdrv = 0; if (!clsid) return DRVERR_INVALID_PARAM; if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { memcpy(clsid,&lpdrv->clsid,sizeof(CLSID)); return 0; } return DRVERR_DEVICE_NOT_FOUND; } giada-0.11.2/src/deps/rtaudio-mod/include/asiolist.h000066400000000000000000000017421264622563000222430ustar00rootroot00000000000000#ifndef __asiolist__ #define __asiolist__ #define DRVERR -5000 #define DRVERR_INVALID_PARAM DRVERR-1 #define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2 #define DRVERR_DEVICE_NOT_FOUND DRVERR-3 #define MAXPATHLEN 512 #define MAXDRVNAMELEN 128 struct asiodrvstruct { int drvID; CLSID clsid; char dllpath[MAXPATHLEN]; char drvname[MAXDRVNAMELEN]; LPVOID asiodrv; struct asiodrvstruct *next; }; typedef struct asiodrvstruct ASIODRVSTRUCT; typedef ASIODRVSTRUCT *LPASIODRVSTRUCT; class AsioDriverList { public: AsioDriverList(); ~AsioDriverList(); LONG asioOpenDriver (int,VOID **); LONG asioCloseDriver (int); // nice to have LONG asioGetNumDev (VOID); LONG asioGetDriverName (int,char *,int); LONG asioGetDriverPath (int,char *,int); LONG asioGetDriverCLSID (int,CLSID *); // or use directly access LPASIODRVSTRUCT lpdrvlist; int numdrv; }; typedef class AsioDriverList *LPASIODRIVERLIST; #endif giada-0.11.2/src/deps/rtaudio-mod/include/asiosys.h000066400000000000000000000025201264622563000221010ustar00rootroot00000000000000#ifndef __asiosys__ #define __asiosys__ #ifdef WIN32 #undef MAC #define PPC 0 #define WINDOWS 1 #define SGI 0 #define SUN 0 #define LINUX 0 #define BEOS 0 #define NATIVE_INT64 0 #define IEEE754_64FLOAT 1 #elif BEOS #define MAC 0 #define PPC 0 #define WINDOWS 0 #define PC 0 #define SGI 0 #define SUN 0 #define LINUX 0 #define NATIVE_INT64 0 #define IEEE754_64FLOAT 1 #ifndef DEBUG #define DEBUG 0 #if DEBUG void DEBUGGERMESSAGE(char *string); #else #define DEBUGGERMESSAGE(a) #endif #endif #elif SGI #define MAC 0 #define PPC 0 #define WINDOWS 0 #define PC 0 #define SUN 0 #define LINUX 0 #define BEOS 0 #define NATIVE_INT64 0 #define IEEE754_64FLOAT 1 #ifndef DEBUG #define DEBUG 0 #if DEBUG void DEBUGGERMESSAGE(char *string); #else #define DEBUGGERMESSAGE(a) #endif #endif #else // MAC #define MAC 1 #define PPC 1 #define WINDOWS 0 #define PC 0 #define SGI 0 #define SUN 0 #define LINUX 0 #define BEOS 0 #define NATIVE_INT64 0 #define IEEE754_64FLOAT 1 #ifndef DEBUG #define DEBUG 0 #if DEBUG void DEBUGGERMESSAGE(char *string); #else #define DEBUGGERMESSAGE(a) #endif #endif #endif #endif giada-0.11.2/src/deps/rtaudio-mod/include/dsound.h000066400000000000000000003235431264622563000217160ustar00rootroot00000000000000/*==========================================================================; * * Copyright (c) Microsoft Corporation. All rights reserved. * * File: dsound.h * Content: DirectSound include file * **************************************************************************/ #define COM_NO_WINDOWS_H #include #include #ifndef DIRECTSOUND_VERSION #define DIRECTSOUND_VERSION 0x0900 /* Version 9.0 */ #endif #ifdef __cplusplus extern "C" { #endif // __cplusplus #ifndef __DSOUND_INCLUDED__ #define __DSOUND_INCLUDED__ /* Type definitions shared with Direct3D */ #ifndef DX_SHARED_DEFINES typedef float D3DVALUE, *LPD3DVALUE; #ifndef D3DCOLOR_DEFINED typedef DWORD D3DCOLOR; #define D3DCOLOR_DEFINED #endif #ifndef LPD3DCOLOR_DEFINED typedef DWORD *LPD3DCOLOR; #define LPD3DCOLOR_DEFINED #endif #ifndef D3DVECTOR_DEFINED typedef struct _D3DVECTOR { float x; float y; float z; } D3DVECTOR; #define D3DVECTOR_DEFINED #endif #ifndef LPD3DVECTOR_DEFINED typedef D3DVECTOR *LPD3DVECTOR; #define LPD3DVECTOR_DEFINED #endif #define DX_SHARED_DEFINES #endif // DX_SHARED_DEFINES #define _FACDS 0x878 /* DirectSound's facility code */ #define MAKE_DSHRESULT(code) MAKE_HRESULT(1, _FACDS, code) // DirectSound Component GUID {47D4D946-62E8-11CF-93BC-444553540000} DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); // DirectSound 8.0 Component GUID {3901CC3F-84B5-4FA4-BA35-AA8172B8A09B} DEFINE_GUID(CLSID_DirectSound8, 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b); // DirectSound Capture Component GUID {B0210780-89CD-11D0-AF08-00A0C925CD16} DEFINE_GUID(CLSID_DirectSoundCapture, 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); // DirectSound 8.0 Capture Component GUID {E4BCAC13-7F99-4908-9A8E-74E3BF24B6E1} DEFINE_GUID(CLSID_DirectSoundCapture8, 0xe4bcac13, 0x7f99, 0x4908, 0x9a, 0x8e, 0x74, 0xe3, 0xbf, 0x24, 0xb6, 0xe1); // DirectSound Full Duplex Component GUID {FEA4300C-7959-4147-B26A-2377B9E7A91D} DEFINE_GUID(CLSID_DirectSoundFullDuplex, 0xfea4300c, 0x7959, 0x4147, 0xb2, 0x6a, 0x23, 0x77, 0xb9, 0xe7, 0xa9, 0x1d); // DirectSound default playback device GUID {DEF00000-9C6D-47ED-AAF1-4DDA8F2B5C03} DEFINE_GUID(DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); // DirectSound default capture device GUID {DEF00001-9C6D-47ED-AAF1-4DDA8F2B5C03} DEFINE_GUID(DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); // DirectSound default device for voice playback {DEF00002-9C6D-47ED-AAF1-4DDA8F2B5C03} DEFINE_GUID(DSDEVID_DefaultVoicePlayback, 0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); // DirectSound default device for voice capture {DEF00003-9C6D-47ED-AAF1-4DDA8F2B5C03} DEFINE_GUID(DSDEVID_DefaultVoiceCapture, 0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); // // Forward declarations for interfaces. // 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined // #ifdef __cplusplus struct IDirectSound; struct IDirectSoundBuffer; struct IDirectSound3DListener; struct IDirectSound3DBuffer; struct IDirectSoundCapture; struct IDirectSoundCaptureBuffer; struct IDirectSoundNotify; #endif // __cplusplus // // DirectSound 8.0 interfaces. // #if DIRECTSOUND_VERSION >= 0x0800 #ifdef __cplusplus struct IDirectSound8; struct IDirectSoundBuffer8; struct IDirectSoundCaptureBuffer8; struct IDirectSoundFXGargle; struct IDirectSoundFXChorus; struct IDirectSoundFXFlanger; struct IDirectSoundFXEcho; struct IDirectSoundFXDistortion; struct IDirectSoundFXCompressor; struct IDirectSoundFXParamEq; struct IDirectSoundFXWavesReverb; struct IDirectSoundFXI3DL2Reverb; struct IDirectSoundCaptureFXAec; struct IDirectSoundCaptureFXNoiseSuppress; struct IDirectSoundFullDuplex; #endif // __cplusplus // IDirectSound8, IDirectSoundBuffer8 and IDirectSoundCaptureBuffer8 are the // only DirectSound 7.0 interfaces with changed functionality in version 8.0. // The other level 8 interfaces as equivalent to their level 7 counterparts: #define IDirectSoundCapture8 IDirectSoundCapture #define IDirectSound3DListener8 IDirectSound3DListener #define IDirectSound3DBuffer8 IDirectSound3DBuffer #define IDirectSoundNotify8 IDirectSoundNotify #define IDirectSoundFXGargle8 IDirectSoundFXGargle #define IDirectSoundFXChorus8 IDirectSoundFXChorus #define IDirectSoundFXFlanger8 IDirectSoundFXFlanger #define IDirectSoundFXEcho8 IDirectSoundFXEcho #define IDirectSoundFXDistortion8 IDirectSoundFXDistortion #define IDirectSoundFXCompressor8 IDirectSoundFXCompressor #define IDirectSoundFXParamEq8 IDirectSoundFXParamEq #define IDirectSoundFXWavesReverb8 IDirectSoundFXWavesReverb #define IDirectSoundFXI3DL2Reverb8 IDirectSoundFXI3DL2Reverb #define IDirectSoundCaptureFXAec8 IDirectSoundCaptureFXAec #define IDirectSoundCaptureFXNoiseSuppress8 IDirectSoundCaptureFXNoiseSuppress #define IDirectSoundFullDuplex8 IDirectSoundFullDuplex #endif // DIRECTSOUND_VERSION >= 0x0800 typedef struct IDirectSound *LPDIRECTSOUND; typedef struct IDirectSoundBuffer *LPDIRECTSOUNDBUFFER; typedef struct IDirectSound3DListener *LPDIRECTSOUND3DLISTENER; typedef struct IDirectSound3DBuffer *LPDIRECTSOUND3DBUFFER; typedef struct IDirectSoundCapture *LPDIRECTSOUNDCAPTURE; typedef struct IDirectSoundCaptureBuffer *LPDIRECTSOUNDCAPTUREBUFFER; typedef struct IDirectSoundNotify *LPDIRECTSOUNDNOTIFY; #if DIRECTSOUND_VERSION >= 0x0800 typedef struct IDirectSoundFXGargle *LPDIRECTSOUNDFXGARGLE; typedef struct IDirectSoundFXChorus *LPDIRECTSOUNDFXCHORUS; typedef struct IDirectSoundFXFlanger *LPDIRECTSOUNDFXFLANGER; typedef struct IDirectSoundFXEcho *LPDIRECTSOUNDFXECHO; typedef struct IDirectSoundFXDistortion *LPDIRECTSOUNDFXDISTORTION; typedef struct IDirectSoundFXCompressor *LPDIRECTSOUNDFXCOMPRESSOR; typedef struct IDirectSoundFXParamEq *LPDIRECTSOUNDFXPARAMEQ; typedef struct IDirectSoundFXWavesReverb *LPDIRECTSOUNDFXWAVESREVERB; typedef struct IDirectSoundFXI3DL2Reverb *LPDIRECTSOUNDFXI3DL2REVERB; typedef struct IDirectSoundCaptureFXAec *LPDIRECTSOUNDCAPTUREFXAEC; typedef struct IDirectSoundCaptureFXNoiseSuppress *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS; typedef struct IDirectSoundFullDuplex *LPDIRECTSOUNDFULLDUPLEX; typedef struct IDirectSound8 *LPDIRECTSOUND8; typedef struct IDirectSoundBuffer8 *LPDIRECTSOUNDBUFFER8; typedef struct IDirectSound3DListener8 *LPDIRECTSOUND3DLISTENER8; typedef struct IDirectSound3DBuffer8 *LPDIRECTSOUND3DBUFFER8; typedef struct IDirectSoundCapture8 *LPDIRECTSOUNDCAPTURE8; typedef struct IDirectSoundCaptureBuffer8 *LPDIRECTSOUNDCAPTUREBUFFER8; typedef struct IDirectSoundNotify8 *LPDIRECTSOUNDNOTIFY8; typedef struct IDirectSoundFXGargle8 *LPDIRECTSOUNDFXGARGLE8; typedef struct IDirectSoundFXChorus8 *LPDIRECTSOUNDFXCHORUS8; typedef struct IDirectSoundFXFlanger8 *LPDIRECTSOUNDFXFLANGER8; typedef struct IDirectSoundFXEcho8 *LPDIRECTSOUNDFXECHO8; typedef struct IDirectSoundFXDistortion8 *LPDIRECTSOUNDFXDISTORTION8; typedef struct IDirectSoundFXCompressor8 *LPDIRECTSOUNDFXCOMPRESSOR8; typedef struct IDirectSoundFXParamEq8 *LPDIRECTSOUNDFXPARAMEQ8; typedef struct IDirectSoundFXWavesReverb8 *LPDIRECTSOUNDFXWAVESREVERB8; typedef struct IDirectSoundFXI3DL2Reverb8 *LPDIRECTSOUNDFXI3DL2REVERB8; typedef struct IDirectSoundCaptureFXAec8 *LPDIRECTSOUNDCAPTUREFXAEC8; typedef struct IDirectSoundCaptureFXNoiseSuppress8 *LPDIRECTSOUNDCAPTUREFXNOISESUPPRESS8; typedef struct IDirectSoundFullDuplex8 *LPDIRECTSOUNDFULLDUPLEX8; #endif // DIRECTSOUND_VERSION >= 0x0800 // // IID definitions for the unchanged DirectSound 8.0 interfaces // #if DIRECTSOUND_VERSION >= 0x0800 #define IID_IDirectSoundCapture8 IID_IDirectSoundCapture #define IID_IDirectSound3DListener8 IID_IDirectSound3DListener #define IID_IDirectSound3DBuffer8 IID_IDirectSound3DBuffer #define IID_IDirectSoundNotify8 IID_IDirectSoundNotify #define IID_IDirectSoundFXGargle8 IID_IDirectSoundFXGargle #define IID_IDirectSoundFXChorus8 IID_IDirectSoundFXChorus #define IID_IDirectSoundFXFlanger8 IID_IDirectSoundFXFlanger #define IID_IDirectSoundFXEcho8 IID_IDirectSoundFXEcho #define IID_IDirectSoundFXDistortion8 IID_IDirectSoundFXDistortion #define IID_IDirectSoundFXCompressor8 IID_IDirectSoundFXCompressor #define IID_IDirectSoundFXParamEq8 IID_IDirectSoundFXParamEq #define IID_IDirectSoundFXWavesReverb8 IID_IDirectSoundFXWavesReverb #define IID_IDirectSoundFXI3DL2Reverb8 IID_IDirectSoundFXI3DL2Reverb #define IID_IDirectSoundCaptureFXAec8 IID_IDirectSoundCaptureFXAec #define IID_IDirectSoundCaptureFXNoiseSuppress8 IID_IDirectSoundCaptureFXNoiseSuppress #define IID_IDirectSoundFullDuplex8 IID_IDirectSoundFullDuplex #endif // DIRECTSOUND_VERSION >= 0x0800 // // Compatibility typedefs // #ifndef _LPCWAVEFORMATEX_DEFINED #define _LPCWAVEFORMATEX_DEFINED typedef const WAVEFORMATEX *LPCWAVEFORMATEX; #endif // _LPCWAVEFORMATEX_DEFINED #ifndef __LPCGUID_DEFINED__ #define __LPCGUID_DEFINED__ typedef const GUID *LPCGUID; #endif // __LPCGUID_DEFINED__ typedef LPDIRECTSOUND *LPLPDIRECTSOUND; typedef LPDIRECTSOUNDBUFFER *LPLPDIRECTSOUNDBUFFER; typedef LPDIRECTSOUND3DLISTENER *LPLPDIRECTSOUND3DLISTENER; typedef LPDIRECTSOUND3DBUFFER *LPLPDIRECTSOUND3DBUFFER; typedef LPDIRECTSOUNDCAPTURE *LPLPDIRECTSOUNDCAPTURE; typedef LPDIRECTSOUNDCAPTUREBUFFER *LPLPDIRECTSOUNDCAPTUREBUFFER; typedef LPDIRECTSOUNDNOTIFY *LPLPDIRECTSOUNDNOTIFY; #if DIRECTSOUND_VERSION >= 0x0800 typedef LPDIRECTSOUND8 *LPLPDIRECTSOUND8; typedef LPDIRECTSOUNDBUFFER8 *LPLPDIRECTSOUNDBUFFER8; typedef LPDIRECTSOUNDCAPTURE8 *LPLPDIRECTSOUNDCAPTURE8; typedef LPDIRECTSOUNDCAPTUREBUFFER8 *LPLPDIRECTSOUNDCAPTUREBUFFER8; #endif // DIRECTSOUND_VERSION >= 0x0800 // // Structures // typedef struct _DSCAPS { DWORD dwSize; DWORD dwFlags; DWORD dwMinSecondarySampleRate; DWORD dwMaxSecondarySampleRate; DWORD dwPrimaryBuffers; DWORD dwMaxHwMixingAllBuffers; DWORD dwMaxHwMixingStaticBuffers; DWORD dwMaxHwMixingStreamingBuffers; DWORD dwFreeHwMixingAllBuffers; DWORD dwFreeHwMixingStaticBuffers; DWORD dwFreeHwMixingStreamingBuffers; DWORD dwMaxHw3DAllBuffers; DWORD dwMaxHw3DStaticBuffers; DWORD dwMaxHw3DStreamingBuffers; DWORD dwFreeHw3DAllBuffers; DWORD dwFreeHw3DStaticBuffers; DWORD dwFreeHw3DStreamingBuffers; DWORD dwTotalHwMemBytes; DWORD dwFreeHwMemBytes; DWORD dwMaxContigFreeHwMemBytes; DWORD dwUnlockTransferRateHwBuffers; DWORD dwPlayCpuOverheadSwBuffers; DWORD dwReserved1; DWORD dwReserved2; } DSCAPS, *LPDSCAPS; typedef const DSCAPS *LPCDSCAPS; typedef struct _DSBCAPS { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwUnlockTransferRate; DWORD dwPlayCpuOverhead; } DSBCAPS, *LPDSBCAPS; typedef const DSBCAPS *LPCDSBCAPS; #if DIRECTSOUND_VERSION >= 0x0800 typedef struct _DSEFFECTDESC { DWORD dwSize; DWORD dwFlags; GUID guidDSFXClass; DWORD_PTR dwReserved1; DWORD_PTR dwReserved2; } DSEFFECTDESC, *LPDSEFFECTDESC; typedef const DSEFFECTDESC *LPCDSEFFECTDESC; #define DSFX_LOCHARDWARE 0x00000001 #define DSFX_LOCSOFTWARE 0x00000002 enum { DSFXR_PRESENT, // 0 DSFXR_LOCHARDWARE, // 1 DSFXR_LOCSOFTWARE, // 2 DSFXR_UNALLOCATED, // 3 DSFXR_FAILED, // 4 DSFXR_UNKNOWN, // 5 DSFXR_SENDLOOP // 6 }; typedef struct _DSCEFFECTDESC { DWORD dwSize; DWORD dwFlags; GUID guidDSCFXClass; GUID guidDSCFXInstance; DWORD dwReserved1; DWORD dwReserved2; } DSCEFFECTDESC, *LPDSCEFFECTDESC; typedef const DSCEFFECTDESC *LPCDSCEFFECTDESC; #define DSCFX_LOCHARDWARE 0x00000001 #define DSCFX_LOCSOFTWARE 0x00000002 #define DSCFXR_LOCHARDWARE 0x00000010 #define DSCFXR_LOCSOFTWARE 0x00000020 #endif // DIRECTSOUND_VERSION >= 0x0800 typedef struct _DSBUFFERDESC { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; LPWAVEFORMATEX lpwfxFormat; #if DIRECTSOUND_VERSION >= 0x0700 GUID guid3DAlgorithm; #endif } DSBUFFERDESC, *LPDSBUFFERDESC; typedef const DSBUFFERDESC *LPCDSBUFFERDESC; // Older version of this structure: typedef struct _DSBUFFERDESC1 { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; LPWAVEFORMATEX lpwfxFormat; } DSBUFFERDESC1, *LPDSBUFFERDESC1; typedef const DSBUFFERDESC1 *LPCDSBUFFERDESC1; typedef struct _DS3DBUFFER { DWORD dwSize; D3DVECTOR vPosition; D3DVECTOR vVelocity; DWORD dwInsideConeAngle; DWORD dwOutsideConeAngle; D3DVECTOR vConeOrientation; LONG lConeOutsideVolume; D3DVALUE flMinDistance; D3DVALUE flMaxDistance; DWORD dwMode; } DS3DBUFFER, *LPDS3DBUFFER; typedef const DS3DBUFFER *LPCDS3DBUFFER; typedef struct _DS3DLISTENER { DWORD dwSize; D3DVECTOR vPosition; D3DVECTOR vVelocity; D3DVECTOR vOrientFront; D3DVECTOR vOrientTop; D3DVALUE flDistanceFactor; D3DVALUE flRolloffFactor; D3DVALUE flDopplerFactor; } DS3DLISTENER, *LPDS3DLISTENER; typedef const DS3DLISTENER *LPCDS3DLISTENER; typedef struct _DSCCAPS { DWORD dwSize; DWORD dwFlags; DWORD dwFormats; DWORD dwChannels; } DSCCAPS, *LPDSCCAPS; typedef const DSCCAPS *LPCDSCCAPS; typedef struct _DSCBUFFERDESC1 { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; LPWAVEFORMATEX lpwfxFormat; } DSCBUFFERDESC1, *LPDSCBUFFERDESC1; typedef struct _DSCBUFFERDESC { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; LPWAVEFORMATEX lpwfxFormat; #if DIRECTSOUND_VERSION >= 0x0800 DWORD dwFXCount; LPDSCEFFECTDESC lpDSCFXDesc; #endif } DSCBUFFERDESC, *LPDSCBUFFERDESC; typedef const DSCBUFFERDESC *LPCDSCBUFFERDESC; typedef struct _DSCBCAPS { DWORD dwSize; DWORD dwFlags; DWORD dwBufferBytes; DWORD dwReserved; } DSCBCAPS, *LPDSCBCAPS; typedef const DSCBCAPS *LPCDSCBCAPS; typedef struct _DSBPOSITIONNOTIFY { DWORD dwOffset; HANDLE hEventNotify; } DSBPOSITIONNOTIFY, *LPDSBPOSITIONNOTIFY; typedef const DSBPOSITIONNOTIFY *LPCDSBPOSITIONNOTIFY; // // DirectSound API // typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID); typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID); extern HRESULT WINAPI DirectSoundCreate(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter); extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); extern HRESULT WINAPI DirectSoundEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); extern HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE *ppDSC, LPUNKNOWN pUnkOuter); extern HRESULT WINAPI DirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); extern HRESULT WINAPI DirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext); #if DIRECTSOUND_VERSION >= 0x0800 extern HRESULT WINAPI DirectSoundCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter); extern HRESULT WINAPI DirectSoundCaptureCreate8(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter); extern HRESULT WINAPI DirectSoundFullDuplexCreate(LPCGUID pcGuidCaptureDevice, LPCGUID pcGuidRenderDevice, LPCDSCBUFFERDESC pcDSCBufferDesc, LPCDSBUFFERDESC pcDSBufferDesc, HWND hWnd, DWORD dwLevel, LPDIRECTSOUNDFULLDUPLEX* ppDSFD, LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, LPUNKNOWN pUnkOuter); #define DirectSoundFullDuplexCreate8 DirectSoundFullDuplexCreate extern HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest); #endif // DIRECTSOUND_VERSION >= 0x0800 #ifdef UNICODE #define LPDSENUMCALLBACK LPDSENUMCALLBACKW #define DirectSoundEnumerate DirectSoundEnumerateW #define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateW #else // UNICODE #define LPDSENUMCALLBACK LPDSENUMCALLBACKA #define DirectSoundEnumerate DirectSoundEnumerateA #define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateA #endif // UNICODE // // IUnknown // #if !defined(__cplusplus) || defined(CINTERFACE) #ifndef IUnknown_QueryInterface #define IUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) #endif // IUnknown_QueryInterface #ifndef IUnknown_AddRef #define IUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) #endif // IUnknown_AddRef #ifndef IUnknown_Release #define IUnknown_Release(p) (p)->lpVtbl->Release(p) #endif // IUnknown_Release #else // !defined(__cplusplus) || defined(CINTERFACE) #ifndef IUnknown_QueryInterface #define IUnknown_QueryInterface(p,a,b) (p)->QueryInterface(a,b) #endif // IUnknown_QueryInterface #ifndef IUnknown_AddRef #define IUnknown_AddRef(p) (p)->AddRef() #endif // IUnknown_AddRef #ifndef IUnknown_Release #define IUnknown_Release(p) (p)->Release() #endif // IUnknown_Release #endif // !defined(__cplusplus) || defined(CINTERFACE) #ifndef __IReferenceClock_INTERFACE_DEFINED__ #define __IReferenceClock_INTERFACE_DEFINED__ typedef LONGLONG REFERENCE_TIME; typedef REFERENCE_TIME *LPREFERENCE_TIME; DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); #undef INTERFACE #define INTERFACE IReferenceClock DECLARE_INTERFACE_(IReferenceClock, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IReferenceClock methods STDMETHOD(GetTime) (THIS_ REFERENCE_TIME *pTime) PURE; STDMETHOD(AdviseTime) (THIS_ REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HANDLE hEvent, LPDWORD pdwAdviseCookie) PURE; STDMETHOD(AdvisePeriodic) (THIS_ REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HANDLE hSemaphore, LPDWORD pdwAdviseCookie) PURE; STDMETHOD(Unadvise) (THIS_ DWORD dwAdviseCookie) PURE; }; #endif // __IReferenceClock_INTERFACE_DEFINED__ #ifndef IReferenceClock_QueryInterface #define IReferenceClock_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IReferenceClock_AddRef(p) IUnknown_AddRef(p) #define IReferenceClock_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IReferenceClock_GetTime(p,a) (p)->lpVtbl->GetTime(p,a) #define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->lpVtbl->AdviseTime(p,a,b,c,d) #define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->lpVtbl->AdvisePeriodic(p,a,b,c,d) #define IReferenceClock_Unadvise(p,a) (p)->lpVtbl->Unadvise(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IReferenceClock_GetTime(p,a) (p)->GetTime(a) #define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->AdviseTime(a,b,c,d) #define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->AdvisePeriodic(a,b,c,d) #define IReferenceClock_Unadvise(p,a) (p)->Unadvise(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) #endif // IReferenceClock_QueryInterface // // IDirectSound // DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); #undef INTERFACE #define INTERFACE IDirectSound DECLARE_INTERFACE_(IDirectSound, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSound methods STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; STDMETHOD(Compact) (THIS) PURE; STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; }; #define IDirectSound_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSound_AddRef(p) IUnknown_AddRef(p) #define IDirectSound_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->lpVtbl->CreateSoundBuffer(p,a,b,c) #define IDirectSound_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) #define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->lpVtbl->DuplicateSoundBuffer(p,a,b) #define IDirectSound_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) #define IDirectSound_Compact(p) (p)->lpVtbl->Compact(p) #define IDirectSound_GetSpeakerConfig(p,a) (p)->lpVtbl->GetSpeakerConfig(p,a) #define IDirectSound_SetSpeakerConfig(p,b) (p)->lpVtbl->SetSpeakerConfig(p,b) #define IDirectSound_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->CreateSoundBuffer(a,b,c) #define IDirectSound_GetCaps(p,a) (p)->GetCaps(a) #define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->DuplicateSoundBuffer(a,b) #define IDirectSound_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) #define IDirectSound_Compact(p) (p)->Compact() #define IDirectSound_GetSpeakerConfig(p,a) (p)->GetSpeakerConfig(a) #define IDirectSound_SetSpeakerConfig(p,b) (p)->SetSpeakerConfig(b) #define IDirectSound_Initialize(p,a) (p)->Initialize(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) #if DIRECTSOUND_VERSION >= 0x0800 // // IDirectSound8 // DEFINE_GUID(IID_IDirectSound8, 0xC50A7E93, 0xF395, 0x4834, 0x9E, 0xF6, 0x7F, 0xA9, 0x9D, 0xE5, 0x09, 0x66); #undef INTERFACE #define INTERFACE IDirectSound8 DECLARE_INTERFACE_(IDirectSound8, IDirectSound) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSound methods STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(GetCaps) (THIS_ LPDSCAPS pDSCaps) PURE; STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate) PURE; STDMETHOD(SetCooperativeLevel) (THIS_ HWND hwnd, DWORD dwLevel) PURE; STDMETHOD(Compact) (THIS) PURE; STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD pdwSpeakerConfig) PURE; STDMETHOD(SetSpeakerConfig) (THIS_ DWORD dwSpeakerConfig) PURE; STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; // IDirectSound8 methods STDMETHOD(VerifyCertification) (THIS_ LPDWORD pdwCertified) PURE; }; #define IDirectSound8_QueryInterface(p,a,b) IDirectSound_QueryInterface(p,a,b) #define IDirectSound8_AddRef(p) IDirectSound_AddRef(p) #define IDirectSound8_Release(p) IDirectSound_Release(p) #define IDirectSound8_CreateSoundBuffer(p,a,b,c) IDirectSound_CreateSoundBuffer(p,a,b,c) #define IDirectSound8_GetCaps(p,a) IDirectSound_GetCaps(p,a) #define IDirectSound8_DuplicateSoundBuffer(p,a,b) IDirectSound_DuplicateSoundBuffer(p,a,b) #define IDirectSound8_SetCooperativeLevel(p,a,b) IDirectSound_SetCooperativeLevel(p,a,b) #define IDirectSound8_Compact(p) IDirectSound_Compact(p) #define IDirectSound8_GetSpeakerConfig(p,a) IDirectSound_GetSpeakerConfig(p,a) #define IDirectSound8_SetSpeakerConfig(p,a) IDirectSound_SetSpeakerConfig(p,a) #define IDirectSound8_Initialize(p,a) IDirectSound_Initialize(p,a) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound8_VerifyCertification(p,a) (p)->lpVtbl->VerifyCertification(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound8_VerifyCertification(p,a) (p)->VerifyCertification(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) #endif // DIRECTSOUND_VERSION >= 0x0800 // // IDirectSoundBuffer // DEFINE_GUID(IID_IDirectSoundBuffer, 0x279AFA85, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); #undef INTERFACE #define INTERFACE IDirectSoundBuffer DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundBuffer methods STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; STDMETHOD(Stop) (THIS) PURE; STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; STDMETHOD(Restore) (THIS) PURE; }; #define IDirectSoundBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundBuffer_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundBuffer_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) #define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) #define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) #define IDirectSoundBuffer_GetVolume(p,a) (p)->lpVtbl->GetVolume(p,a) #define IDirectSoundBuffer_GetPan(p,a) (p)->lpVtbl->GetPan(p,a) #define IDirectSoundBuffer_GetFrequency(p,a) (p)->lpVtbl->GetFrequency(p,a) #define IDirectSoundBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) #define IDirectSoundBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) #define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) #define IDirectSoundBuffer_Play(p,a,b,c) (p)->lpVtbl->Play(p,a,b,c) #define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->lpVtbl->SetCurrentPosition(p,a) #define IDirectSoundBuffer_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a) #define IDirectSoundBuffer_SetVolume(p,a) (p)->lpVtbl->SetVolume(p,a) #define IDirectSoundBuffer_SetPan(p,a) (p)->lpVtbl->SetPan(p,a) #define IDirectSoundBuffer_SetFrequency(p,a) (p)->lpVtbl->SetFrequency(p,a) #define IDirectSoundBuffer_Stop(p) (p)->lpVtbl->Stop(p) #define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) #define IDirectSoundBuffer_Restore(p) (p)->lpVtbl->Restore(p) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundBuffer_GetCaps(p,a) (p)->GetCaps(a) #define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) #define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) #define IDirectSoundBuffer_GetVolume(p,a) (p)->GetVolume(a) #define IDirectSoundBuffer_GetPan(p,a) (p)->GetPan(a) #define IDirectSoundBuffer_GetFrequency(p,a) (p)->GetFrequency(a) #define IDirectSoundBuffer_GetStatus(p,a) (p)->GetStatus(a) #define IDirectSoundBuffer_Initialize(p,a,b) (p)->Initialize(a,b) #define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) #define IDirectSoundBuffer_Play(p,a,b,c) (p)->Play(a,b,c) #define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->SetCurrentPosition(a) #define IDirectSoundBuffer_SetFormat(p,a) (p)->SetFormat(a) #define IDirectSoundBuffer_SetVolume(p,a) (p)->SetVolume(a) #define IDirectSoundBuffer_SetPan(p,a) (p)->SetPan(a) #define IDirectSoundBuffer_SetFrequency(p,a) (p)->SetFrequency(a) #define IDirectSoundBuffer_Stop(p) (p)->Stop() #define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) #define IDirectSoundBuffer_Restore(p) (p)->Restore() #endif // !defined(__cplusplus) || defined(CINTERFACE) #if DIRECTSOUND_VERSION >= 0x0800 // // IDirectSoundBuffer8 // DEFINE_GUID(IID_IDirectSoundBuffer8, 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e); #undef INTERFACE #define INTERFACE IDirectSoundBuffer8 DECLARE_INTERFACE_(IDirectSoundBuffer8, IDirectSoundBuffer) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundBuffer methods STDMETHOD(GetCaps) (THIS_ LPDSBCAPS pDSBufferCaps) PURE; STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor) PURE; STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; STDMETHOD(GetVolume) (THIS_ LPLONG plVolume) PURE; STDMETHOD(GetPan) (THIS_ LPLONG plPan) PURE; STDMETHOD(GetFrequency) (THIS_ LPDWORD pdwFrequency) PURE; STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc) PURE; STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; STDMETHOD(Play) (THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) PURE; STDMETHOD(SetCurrentPosition) (THIS_ DWORD dwNewPosition) PURE; STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX pcfxFormat) PURE; STDMETHOD(SetVolume) (THIS_ LONG lVolume) PURE; STDMETHOD(SetPan) (THIS_ LONG lPan) PURE; STDMETHOD(SetFrequency) (THIS_ DWORD dwFrequency) PURE; STDMETHOD(Stop) (THIS) PURE; STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; STDMETHOD(Restore) (THIS) PURE; // IDirectSoundBuffer8 methods STDMETHOD(SetFX) (THIS_ DWORD dwEffectsCount, LPDSEFFECTDESC pDSFXDesc, LPDWORD pdwResultCodes) PURE; STDMETHOD(AcquireResources) (THIS_ DWORD dwFlags, DWORD dwEffectsCount, LPDWORD pdwResultCodes) PURE; STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; }; // Special GUID meaning "select all objects" for use in GetObjectInPath() DEFINE_GUID(GUID_All_Objects, 0xaa114de5, 0xc262, 0x4169, 0xa1, 0xc8, 0x23, 0xd6, 0x98, 0xcc, 0x73, 0xb5); #define IDirectSoundBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundBuffer8_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundBuffer8_Release(p) IUnknown_Release(p) #define IDirectSoundBuffer8_GetCaps(p,a) IDirectSoundBuffer_GetCaps(p,a) #define IDirectSoundBuffer8_GetCurrentPosition(p,a,b) IDirectSoundBuffer_GetCurrentPosition(p,a,b) #define IDirectSoundBuffer8_GetFormat(p,a,b,c) IDirectSoundBuffer_GetFormat(p,a,b,c) #define IDirectSoundBuffer8_GetVolume(p,a) IDirectSoundBuffer_GetVolume(p,a) #define IDirectSoundBuffer8_GetPan(p,a) IDirectSoundBuffer_GetPan(p,a) #define IDirectSoundBuffer8_GetFrequency(p,a) IDirectSoundBuffer_GetFrequency(p,a) #define IDirectSoundBuffer8_GetStatus(p,a) IDirectSoundBuffer_GetStatus(p,a) #define IDirectSoundBuffer8_Initialize(p,a,b) IDirectSoundBuffer_Initialize(p,a,b) #define IDirectSoundBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) #define IDirectSoundBuffer8_Play(p,a,b,c) IDirectSoundBuffer_Play(p,a,b,c) #define IDirectSoundBuffer8_SetCurrentPosition(p,a) IDirectSoundBuffer_SetCurrentPosition(p,a) #define IDirectSoundBuffer8_SetFormat(p,a) IDirectSoundBuffer_SetFormat(p,a) #define IDirectSoundBuffer8_SetVolume(p,a) IDirectSoundBuffer_SetVolume(p,a) #define IDirectSoundBuffer8_SetPan(p,a) IDirectSoundBuffer_SetPan(p,a) #define IDirectSoundBuffer8_SetFrequency(p,a) IDirectSoundBuffer_SetFrequency(p,a) #define IDirectSoundBuffer8_Stop(p) IDirectSoundBuffer_Stop(p) #define IDirectSoundBuffer8_Unlock(p,a,b,c,d) IDirectSoundBuffer_Unlock(p,a,b,c,d) #define IDirectSoundBuffer8_Restore(p) IDirectSoundBuffer_Restore(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->lpVtbl->SetFX(p,a,b,c) #define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->lpVtbl->AcquireResources(p,a,b,c) #define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundBuffer8_SetFX(p,a,b,c) (p)->SetFX(a,b,c) #define IDirectSoundBuffer8_AcquireResources(p,a,b,c) (p)->AcquireResources(a,b,c) #define IDirectSoundBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) #endif // !defined(__cplusplus) || defined(CINTERFACE) #endif // DIRECTSOUND_VERSION >= 0x0800 // // IDirectSound3DListener // DEFINE_GUID(IID_IDirectSound3DListener, 0x279AFA84, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); #undef INTERFACE #define INTERFACE IDirectSound3DListener DECLARE_INTERFACE_(IDirectSound3DListener, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSound3DListener methods STDMETHOD(GetAllParameters) (THIS_ LPDS3DLISTENER pListener) PURE; STDMETHOD(GetDistanceFactor) (THIS_ D3DVALUE* pflDistanceFactor) PURE; STDMETHOD(GetDopplerFactor) (THIS_ D3DVALUE* pflDopplerFactor) PURE; STDMETHOD(GetOrientation) (THIS_ D3DVECTOR* pvOrientFront, D3DVECTOR* pvOrientTop) PURE; STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; STDMETHOD(GetRolloffFactor) (THIS_ D3DVALUE* pflRolloffFactor) PURE; STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; STDMETHOD(SetAllParameters) (THIS_ LPCDS3DLISTENER pcListener, DWORD dwApply) PURE; STDMETHOD(SetDistanceFactor) (THIS_ D3DVALUE flDistanceFactor, DWORD dwApply) PURE; STDMETHOD(SetDopplerFactor) (THIS_ D3DVALUE flDopplerFactor, DWORD dwApply) PURE; STDMETHOD(SetOrientation) (THIS_ D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD dwApply) PURE; STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; STDMETHOD(SetRolloffFactor) (THIS_ D3DVALUE flRolloffFactor, DWORD dwApply) PURE; STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; STDMETHOD(CommitDeferredSettings) (THIS) PURE; }; #define IDirectSound3DListener_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSound3DListener_AddRef(p) IUnknown_AddRef(p) #define IDirectSound3DListener_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound3DListener_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->lpVtbl->GetDistanceFactor(p,a) #define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->lpVtbl->GetDopplerFactor(p,a) #define IDirectSound3DListener_GetOrientation(p,a,b) (p)->lpVtbl->GetOrientation(p,a,b) #define IDirectSound3DListener_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) #define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->lpVtbl->GetRolloffFactor(p,a) #define IDirectSound3DListener_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) #define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) #define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->lpVtbl->SetDistanceFactor(p,a,b) #define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->lpVtbl->SetDopplerFactor(p,a,b) #define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->lpVtbl->SetOrientation(p,a,b,c,d,e,f,g) #define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) #define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->lpVtbl->SetRolloffFactor(p,a,b) #define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) #define IDirectSound3DListener_CommitDeferredSettings(p) (p)->lpVtbl->CommitDeferredSettings(p) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound3DListener_GetAllParameters(p,a) (p)->GetAllParameters(a) #define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->GetDistanceFactor(a) #define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->GetDopplerFactor(a) #define IDirectSound3DListener_GetOrientation(p,a,b) (p)->GetOrientation(a,b) #define IDirectSound3DListener_GetPosition(p,a) (p)->GetPosition(a) #define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->GetRolloffFactor(a) #define IDirectSound3DListener_GetVelocity(p,a) (p)->GetVelocity(a) #define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) #define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->SetDistanceFactor(a,b) #define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->SetDopplerFactor(a,b) #define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->SetOrientation(a,b,c,d,e,f,g) #define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) #define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->SetRolloffFactor(a,b) #define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) #define IDirectSound3DListener_CommitDeferredSettings(p) (p)->CommitDeferredSettings() #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSound3DBuffer // DEFINE_GUID(IID_IDirectSound3DBuffer, 0x279AFA86, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); #undef INTERFACE #define INTERFACE IDirectSound3DBuffer DECLARE_INTERFACE_(IDirectSound3DBuffer, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSound3DBuffer methods STDMETHOD(GetAllParameters) (THIS_ LPDS3DBUFFER pDs3dBuffer) PURE; STDMETHOD(GetConeAngles) (THIS_ LPDWORD pdwInsideConeAngle, LPDWORD pdwOutsideConeAngle) PURE; STDMETHOD(GetConeOrientation) (THIS_ D3DVECTOR* pvOrientation) PURE; STDMETHOD(GetConeOutsideVolume) (THIS_ LPLONG plConeOutsideVolume) PURE; STDMETHOD(GetMaxDistance) (THIS_ D3DVALUE* pflMaxDistance) PURE; STDMETHOD(GetMinDistance) (THIS_ D3DVALUE* pflMinDistance) PURE; STDMETHOD(GetMode) (THIS_ LPDWORD pdwMode) PURE; STDMETHOD(GetPosition) (THIS_ D3DVECTOR* pvPosition) PURE; STDMETHOD(GetVelocity) (THIS_ D3DVECTOR* pvVelocity) PURE; STDMETHOD(SetAllParameters) (THIS_ LPCDS3DBUFFER pcDs3dBuffer, DWORD dwApply) PURE; STDMETHOD(SetConeAngles) (THIS_ DWORD dwInsideConeAngle, DWORD dwOutsideConeAngle, DWORD dwApply) PURE; STDMETHOD(SetConeOrientation) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; STDMETHOD(SetConeOutsideVolume) (THIS_ LONG lConeOutsideVolume, DWORD dwApply) PURE; STDMETHOD(SetMaxDistance) (THIS_ D3DVALUE flMaxDistance, DWORD dwApply) PURE; STDMETHOD(SetMinDistance) (THIS_ D3DVALUE flMinDistance, DWORD dwApply) PURE; STDMETHOD(SetMode) (THIS_ DWORD dwMode, DWORD dwApply) PURE; STDMETHOD(SetPosition) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; STDMETHOD(SetVelocity) (THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD dwApply) PURE; }; #define IDirectSound3DBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSound3DBuffer_AddRef(p) IUnknown_AddRef(p) #define IDirectSound3DBuffer_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->lpVtbl->GetConeAngles(p,a,b) #define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->lpVtbl->GetConeOrientation(p,a) #define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->lpVtbl->GetConeOutsideVolume(p,a) #define IDirectSound3DBuffer_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) #define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->lpVtbl->GetMinDistance(p,a) #define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->lpVtbl->GetMaxDistance(p,a) #define IDirectSound3DBuffer_GetMode(p,a) (p)->lpVtbl->GetMode(p,a) #define IDirectSound3DBuffer_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) #define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) #define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->lpVtbl->SetConeAngles(p,a,b,c) #define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->lpVtbl->SetConeOrientation(p,a,b,c,d) #define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->lpVtbl->SetConeOutsideVolume(p,a,b) #define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) #define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->lpVtbl->SetMinDistance(p,a,b) #define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->lpVtbl->SetMaxDistance(p,a,b) #define IDirectSound3DBuffer_SetMode(p,a,b) (p)->lpVtbl->SetMode(p,a,b) #define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->GetAllParameters(a) #define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->GetConeAngles(a,b) #define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->GetConeOrientation(a) #define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->GetConeOutsideVolume(a) #define IDirectSound3DBuffer_GetPosition(p,a) (p)->GetPosition(a) #define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->GetMinDistance(a) #define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->GetMaxDistance(a) #define IDirectSound3DBuffer_GetMode(p,a) (p)->GetMode(a) #define IDirectSound3DBuffer_GetVelocity(p,a) (p)->GetVelocity(a) #define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) #define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->SetConeAngles(a,b,c) #define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->SetConeOrientation(a,b,c,d) #define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b) (p)->SetConeOutsideVolume(a,b) #define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) #define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->SetMinDistance(a,b) #define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->SetMaxDistance(a,b) #define IDirectSound3DBuffer_SetMode(p,a,b) (p)->SetMode(a,b) #define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundCapture // DEFINE_GUID(IID_IDirectSoundCapture, 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); #undef INTERFACE #define INTERFACE IDirectSoundCapture DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundCapture methods STDMETHOD(CreateCaptureBuffer) (THIS_ LPCDSCBUFFERDESC pcDSCBufferDesc, LPDIRECTSOUNDCAPTUREBUFFER *ppDSCBuffer, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(GetCaps) (THIS_ LPDSCCAPS pDSCCaps) PURE; STDMETHOD(Initialize) (THIS_ LPCGUID pcGuidDevice) PURE; }; #define IDirectSoundCapture_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundCapture_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundCapture_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->lpVtbl->CreateCaptureBuffer(p,a,b,c) #define IDirectSoundCapture_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) #define IDirectSoundCapture_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->CreateCaptureBuffer(a,b,c) #define IDirectSoundCapture_GetCaps(p,a) (p)->GetCaps(a) #define IDirectSoundCapture_Initialize(p,a) (p)->Initialize(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundCaptureBuffer // DEFINE_GUID(IID_IDirectSoundCaptureBuffer, 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); #undef INTERFACE #define INTERFACE IDirectSoundCaptureBuffer DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundCaptureBuffer methods STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; STDMETHOD(Stop) (THIS) PURE; STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; }; #define IDirectSoundCaptureBuffer_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundCaptureBuffer_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundCaptureBuffer_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) #define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) #define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) #define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) #define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) #define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) #define IDirectSoundCaptureBuffer_Start(p,a) (p)->lpVtbl->Start(p,a) #define IDirectSoundCaptureBuffer_Stop(p) (p)->lpVtbl->Stop(p) #define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->GetCaps(a) #define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) #define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) #define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->GetStatus(a) #define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->Initialize(a,b) #define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) #define IDirectSoundCaptureBuffer_Start(p,a) (p)->Start(a) #define IDirectSoundCaptureBuffer_Stop(p) (p)->Stop() #define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) #endif // !defined(__cplusplus) || defined(CINTERFACE) #if DIRECTSOUND_VERSION >= 0x0800 // // IDirectSoundCaptureBuffer8 // DEFINE_GUID(IID_IDirectSoundCaptureBuffer8, 0x990df4, 0xdbb, 0x4872, 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6); #undef INTERFACE #define INTERFACE IDirectSoundCaptureBuffer8 DECLARE_INTERFACE_(IDirectSoundCaptureBuffer8, IDirectSoundCaptureBuffer) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundCaptureBuffer methods STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS pDSCBCaps) PURE; STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD pdwCapturePosition, LPDWORD pdwReadPosition) PURE; STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten) PURE; STDMETHOD(GetStatus) (THIS_ LPDWORD pdwStatus) PURE; STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE pDirectSoundCapture, LPCDSCBUFFERDESC pcDSCBufferDesc) PURE; STDMETHOD(Lock) (THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1, LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags) PURE; STDMETHOD(Start) (THIS_ DWORD dwFlags) PURE; STDMETHOD(Stop) (THIS) PURE; STDMETHOD(Unlock) (THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2) PURE; // IDirectSoundCaptureBuffer8 methods STDMETHOD(GetObjectInPath) (THIS_ REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, LPVOID *ppObject) PURE; STDMETHOD(GetFXStatus) (DWORD dwFXCount, LPDWORD pdwFXStatus) PURE; }; #define IDirectSoundCaptureBuffer8_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundCaptureBuffer8_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundCaptureBuffer8_Release(p) IUnknown_Release(p) #define IDirectSoundCaptureBuffer8_GetCaps(p,a) IDirectSoundCaptureBuffer_GetCaps(p,a) #define IDirectSoundCaptureBuffer8_GetCurrentPosition(p,a,b) IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) #define IDirectSoundCaptureBuffer8_GetFormat(p,a,b,c) IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) #define IDirectSoundCaptureBuffer8_GetStatus(p,a) IDirectSoundCaptureBuffer_GetStatus(p,a) #define IDirectSoundCaptureBuffer8_Initialize(p,a,b) IDirectSoundCaptureBuffer_Initialize(p,a,b) #define IDirectSoundCaptureBuffer8_Lock(p,a,b,c,d,e,f,g) IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) #define IDirectSoundCaptureBuffer8_Start(p,a) IDirectSoundCaptureBuffer_Start(p,a) #define IDirectSoundCaptureBuffer8_Stop(p) IDirectSoundCaptureBuffer_Stop(p)) #define IDirectSoundCaptureBuffer8_Unlock(p,a,b,c,d) IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->lpVtbl->GetObjectInPath(p,a,b,c,d) #define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->lpVtbl->GetFXStatus(p,a,b) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureBuffer8_GetObjectInPath(p,a,b,c,d) (p)->GetObjectInPath(a,b,c,d) #define IDirectSoundCaptureBuffer8_GetFXStatus(p,a,b) (p)->GetFXStatus(a,b) #endif // !defined(__cplusplus) || defined(CINTERFACE) #endif // DIRECTSOUND_VERSION >= 0x0800 // // IDirectSoundNotify // DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); #undef INTERFACE #define INTERFACE IDirectSoundNotify DECLARE_INTERFACE_(IDirectSoundNotify, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundNotify methods STDMETHOD(SetNotificationPositions) (THIS_ DWORD dwPositionNotifies, LPCDSBPOSITIONNOTIFY pcPositionNotifies) PURE; }; #define IDirectSoundNotify_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundNotify_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundNotify_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->lpVtbl->SetNotificationPositions(p,a,b) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->SetNotificationPositions(a,b) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IKsPropertySet // #ifndef _IKsPropertySet_ #define _IKsPropertySet_ #ifdef __cplusplus // 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined struct IKsPropertySet; #endif // __cplusplus typedef struct IKsPropertySet *LPKSPROPERTYSET; #define KSPROPERTY_SUPPORT_GET 0x00000001 #define KSPROPERTY_SUPPORT_SET 0x00000002 DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); #undef INTERFACE #define INTERFACE IKsPropertySet DECLARE_INTERFACE_(IKsPropertySet, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IKsPropertySet methods STDMETHOD(Get) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, LPVOID pPropertyData, ULONG ulDataLength, PULONG pulBytesReturned) PURE; STDMETHOD(Set) (THIS_ REFGUID rguidPropSet, ULONG ulId, LPVOID pInstanceData, ULONG ulInstanceLength, LPVOID pPropertyData, ULONG ulDataLength) PURE; STDMETHOD(QuerySupport) (THIS_ REFGUID rguidPropSet, ULONG ulId, PULONG pulTypeSupport) PURE; }; #define IKsPropertySet_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IKsPropertySet_AddRef(p) IUnknown_AddRef(p) #define IKsPropertySet_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->lpVtbl->Get(p,a,b,c,d,e,f,g) #define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->lpVtbl->Set(p,a,b,c,d,e,f) #define IKsPropertySet_QuerySupport(p,a,b,c) (p)->lpVtbl->QuerySupport(p,a,b,c) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->Get(a,b,c,d,e,f,g) #define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->Set(a,b,c,d,e,f) #define IKsPropertySet_QuerySupport(p,a,b,c) (p)->QuerySupport(a,b,c) #endif // !defined(__cplusplus) || defined(CINTERFACE) #endif // _IKsPropertySet_ #if DIRECTSOUND_VERSION >= 0x0800 // // IDirectSoundFXGargle // DEFINE_GUID(IID_IDirectSoundFXGargle, 0xd616f352, 0xd622, 0x11ce, 0xaa, 0xc5, 0x00, 0x20, 0xaf, 0x0b, 0x99, 0xa3); typedef struct _DSFXGargle { DWORD dwRateHz; // Rate of modulation in hz DWORD dwWaveShape; // DSFXGARGLE_WAVE_xxx } DSFXGargle, *LPDSFXGargle; #define DSFXGARGLE_WAVE_TRIANGLE 0 #define DSFXGARGLE_WAVE_SQUARE 1 typedef const DSFXGargle *LPCDSFXGargle; #define DSFXGARGLE_RATEHZ_MIN 1 #define DSFXGARGLE_RATEHZ_MAX 1000 #undef INTERFACE #define INTERFACE IDirectSoundFXGargle DECLARE_INTERFACE_(IDirectSoundFXGargle, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXGargle methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXGargle pcDsFxGargle) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXGargle pDsFxGargle) PURE; }; #define IDirectSoundFXGargle_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXGargle_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXGargle_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXGargle_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXGargle_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXChorus // DEFINE_GUID(IID_IDirectSoundFXChorus, 0x880842e3, 0x145f, 0x43e6, 0xa9, 0x34, 0xa7, 0x18, 0x06, 0xe5, 0x05, 0x47); typedef struct _DSFXChorus { FLOAT fWetDryMix; FLOAT fDepth; FLOAT fFeedback; FLOAT fFrequency; LONG lWaveform; // LFO shape; DSFXCHORUS_WAVE_xxx FLOAT fDelay; LONG lPhase; } DSFXChorus, *LPDSFXChorus; typedef const DSFXChorus *LPCDSFXChorus; #define DSFXCHORUS_WAVE_TRIANGLE 0 #define DSFXCHORUS_WAVE_SIN 1 #define DSFXCHORUS_WETDRYMIX_MIN 0.0f #define DSFXCHORUS_WETDRYMIX_MAX 100.0f #define DSFXCHORUS_DEPTH_MIN 0.0f #define DSFXCHORUS_DEPTH_MAX 100.0f #define DSFXCHORUS_FEEDBACK_MIN -99.0f #define DSFXCHORUS_FEEDBACK_MAX 99.0f #define DSFXCHORUS_FREQUENCY_MIN 0.0f #define DSFXCHORUS_FREQUENCY_MAX 10.0f #define DSFXCHORUS_DELAY_MIN 0.0f #define DSFXCHORUS_DELAY_MAX 20.0f #define DSFXCHORUS_PHASE_MIN 0 #define DSFXCHORUS_PHASE_MAX 4 #define DSFXCHORUS_PHASE_NEG_180 0 #define DSFXCHORUS_PHASE_NEG_90 1 #define DSFXCHORUS_PHASE_ZERO 2 #define DSFXCHORUS_PHASE_90 3 #define DSFXCHORUS_PHASE_180 4 #undef INTERFACE #define INTERFACE IDirectSoundFXChorus DECLARE_INTERFACE_(IDirectSoundFXChorus, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXChorus methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXChorus pcDsFxChorus) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXChorus pDsFxChorus) PURE; }; #define IDirectSoundFXChorus_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXChorus_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXChorus_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXChorus_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXChorus_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXFlanger // DEFINE_GUID(IID_IDirectSoundFXFlanger, 0x903e9878, 0x2c92, 0x4072, 0x9b, 0x2c, 0xea, 0x68, 0xf5, 0x39, 0x67, 0x83); typedef struct _DSFXFlanger { FLOAT fWetDryMix; FLOAT fDepth; FLOAT fFeedback; FLOAT fFrequency; LONG lWaveform; FLOAT fDelay; LONG lPhase; } DSFXFlanger, *LPDSFXFlanger; typedef const DSFXFlanger *LPCDSFXFlanger; #define DSFXFLANGER_WAVE_TRIANGLE 0 #define DSFXFLANGER_WAVE_SIN 1 #define DSFXFLANGER_WETDRYMIX_MIN 0.0f #define DSFXFLANGER_WETDRYMIX_MAX 100.0f #define DSFXFLANGER_FREQUENCY_MIN 0.0f #define DSFXFLANGER_FREQUENCY_MAX 10.0f #define DSFXFLANGER_DEPTH_MIN 0.0f #define DSFXFLANGER_DEPTH_MAX 100.0f #define DSFXFLANGER_PHASE_MIN 0 #define DSFXFLANGER_PHASE_MAX 4 #define DSFXFLANGER_FEEDBACK_MIN -99.0f #define DSFXFLANGER_FEEDBACK_MAX 99.0f #define DSFXFLANGER_DELAY_MIN 0.0f #define DSFXFLANGER_DELAY_MAX 4.0f #define DSFXFLANGER_PHASE_NEG_180 0 #define DSFXFLANGER_PHASE_NEG_90 1 #define DSFXFLANGER_PHASE_ZERO 2 #define DSFXFLANGER_PHASE_90 3 #define DSFXFLANGER_PHASE_180 4 #undef INTERFACE #define INTERFACE IDirectSoundFXFlanger DECLARE_INTERFACE_(IDirectSoundFXFlanger, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXFlanger methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXFlanger pcDsFxFlanger) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXFlanger pDsFxFlanger) PURE; }; #define IDirectSoundFXFlanger_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXFlanger_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXFlanger_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXFlanger_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXFlanger_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXEcho // DEFINE_GUID(IID_IDirectSoundFXEcho, 0x8bd28edf, 0x50db, 0x4e92, 0xa2, 0xbd, 0x44, 0x54, 0x88, 0xd1, 0xed, 0x42); typedef struct _DSFXEcho { FLOAT fWetDryMix; FLOAT fFeedback; FLOAT fLeftDelay; FLOAT fRightDelay; LONG lPanDelay; } DSFXEcho, *LPDSFXEcho; typedef const DSFXEcho *LPCDSFXEcho; #define DSFXECHO_WETDRYMIX_MIN 0.0f #define DSFXECHO_WETDRYMIX_MAX 100.0f #define DSFXECHO_FEEDBACK_MIN 0.0f #define DSFXECHO_FEEDBACK_MAX 100.0f #define DSFXECHO_LEFTDELAY_MIN 1.0f #define DSFXECHO_LEFTDELAY_MAX 2000.0f #define DSFXECHO_RIGHTDELAY_MIN 1.0f #define DSFXECHO_RIGHTDELAY_MAX 2000.0f #define DSFXECHO_PANDELAY_MIN 0 #define DSFXECHO_PANDELAY_MAX 1 #undef INTERFACE #define INTERFACE IDirectSoundFXEcho DECLARE_INTERFACE_(IDirectSoundFXEcho, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXEcho methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXEcho pcDsFxEcho) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXEcho pDsFxEcho) PURE; }; #define IDirectSoundFXEcho_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXEcho_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXEcho_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXEcho_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXEcho_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXDistortion // DEFINE_GUID(IID_IDirectSoundFXDistortion, 0x8ecf4326, 0x455f, 0x4d8b, 0xbd, 0xa9, 0x8d, 0x5d, 0x3e, 0x9e, 0x3e, 0x0b); typedef struct _DSFXDistortion { FLOAT fGain; FLOAT fEdge; FLOAT fPostEQCenterFrequency; FLOAT fPostEQBandwidth; FLOAT fPreLowpassCutoff; } DSFXDistortion, *LPDSFXDistortion; typedef const DSFXDistortion *LPCDSFXDistortion; #define DSFXDISTORTION_GAIN_MIN -60.0f #define DSFXDISTORTION_GAIN_MAX 0.0f #define DSFXDISTORTION_EDGE_MIN 0.0f #define DSFXDISTORTION_EDGE_MAX 100.0f #define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MIN 100.0f #define DSFXDISTORTION_POSTEQCENTERFREQUENCY_MAX 8000.0f #define DSFXDISTORTION_POSTEQBANDWIDTH_MIN 100.0f #define DSFXDISTORTION_POSTEQBANDWIDTH_MAX 8000.0f #define DSFXDISTORTION_PRELOWPASSCUTOFF_MIN 100.0f #define DSFXDISTORTION_PRELOWPASSCUTOFF_MAX 8000.0f #undef INTERFACE #define INTERFACE IDirectSoundFXDistortion DECLARE_INTERFACE_(IDirectSoundFXDistortion, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXDistortion methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXDistortion pcDsFxDistortion) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXDistortion pDsFxDistortion) PURE; }; #define IDirectSoundFXDistortion_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXDistortion_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXDistortion_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXDistortion_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXDistortion_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXCompressor // DEFINE_GUID(IID_IDirectSoundFXCompressor, 0x4bbd1154, 0x62f6, 0x4e2c, 0xa1, 0x5c, 0xd3, 0xb6, 0xc4, 0x17, 0xf7, 0xa0); typedef struct _DSFXCompressor { FLOAT fGain; FLOAT fAttack; FLOAT fRelease; FLOAT fThreshold; FLOAT fRatio; FLOAT fPredelay; } DSFXCompressor, *LPDSFXCompressor; typedef const DSFXCompressor *LPCDSFXCompressor; #define DSFXCOMPRESSOR_GAIN_MIN -60.0f #define DSFXCOMPRESSOR_GAIN_MAX 60.0f #define DSFXCOMPRESSOR_ATTACK_MIN 0.01f #define DSFXCOMPRESSOR_ATTACK_MAX 500.0f #define DSFXCOMPRESSOR_RELEASE_MIN 50.0f #define DSFXCOMPRESSOR_RELEASE_MAX 3000.0f #define DSFXCOMPRESSOR_THRESHOLD_MIN -60.0f #define DSFXCOMPRESSOR_THRESHOLD_MAX 0.0f #define DSFXCOMPRESSOR_RATIO_MIN 1.0f #define DSFXCOMPRESSOR_RATIO_MAX 100.0f #define DSFXCOMPRESSOR_PREDELAY_MIN 0.0f #define DSFXCOMPRESSOR_PREDELAY_MAX 4.0f #undef INTERFACE #define INTERFACE IDirectSoundFXCompressor DECLARE_INTERFACE_(IDirectSoundFXCompressor, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXCompressor methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXCompressor pcDsFxCompressor) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXCompressor pDsFxCompressor) PURE; }; #define IDirectSoundFXCompressor_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXCompressor_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXCompressor_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXCompressor_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXCompressor_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXParamEq // DEFINE_GUID(IID_IDirectSoundFXParamEq, 0xc03ca9fe, 0xfe90, 0x4204, 0x80, 0x78, 0x82, 0x33, 0x4c, 0xd1, 0x77, 0xda); typedef struct _DSFXParamEq { FLOAT fCenter; FLOAT fBandwidth; FLOAT fGain; } DSFXParamEq, *LPDSFXParamEq; typedef const DSFXParamEq *LPCDSFXParamEq; #define DSFXPARAMEQ_CENTER_MIN 80.0f #define DSFXPARAMEQ_CENTER_MAX 16000.0f #define DSFXPARAMEQ_BANDWIDTH_MIN 1.0f #define DSFXPARAMEQ_BANDWIDTH_MAX 36.0f #define DSFXPARAMEQ_GAIN_MIN -15.0f #define DSFXPARAMEQ_GAIN_MAX 15.0f #undef INTERFACE #define INTERFACE IDirectSoundFXParamEq DECLARE_INTERFACE_(IDirectSoundFXParamEq, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXParamEq methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXParamEq pcDsFxParamEq) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXParamEq pDsFxParamEq) PURE; }; #define IDirectSoundFXParamEq_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXParamEq_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXParamEq_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXParamEq_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXParamEq_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXI3DL2Reverb // DEFINE_GUID(IID_IDirectSoundFXI3DL2Reverb, 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4); typedef struct _DSFXI3DL2Reverb { LONG lRoom; // [-10000, 0] default: -1000 mB LONG lRoomHF; // [-10000, 0] default: 0 mB FLOAT flRoomRolloffFactor; // [0.0, 10.0] default: 0.0 FLOAT flDecayTime; // [0.1, 20.0] default: 1.49s FLOAT flDecayHFRatio; // [0.1, 2.0] default: 0.83 LONG lReflections; // [-10000, 1000] default: -2602 mB FLOAT flReflectionsDelay; // [0.0, 0.3] default: 0.007 s LONG lReverb; // [-10000, 2000] default: 200 mB FLOAT flReverbDelay; // [0.0, 0.1] default: 0.011 s FLOAT flDiffusion; // [0.0, 100.0] default: 100.0 % FLOAT flDensity; // [0.0, 100.0] default: 100.0 % FLOAT flHFReference; // [20.0, 20000.0] default: 5000.0 Hz } DSFXI3DL2Reverb, *LPDSFXI3DL2Reverb; typedef const DSFXI3DL2Reverb *LPCDSFXI3DL2Reverb; #define DSFX_I3DL2REVERB_ROOM_MIN (-10000) #define DSFX_I3DL2REVERB_ROOM_MAX 0 #define DSFX_I3DL2REVERB_ROOM_DEFAULT (-1000) #define DSFX_I3DL2REVERB_ROOMHF_MIN (-10000) #define DSFX_I3DL2REVERB_ROOMHF_MAX 0 #define DSFX_I3DL2REVERB_ROOMHF_DEFAULT (-100) #define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MIN 0.0f #define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MAX 10.0f #define DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_DEFAULT 0.0f #define DSFX_I3DL2REVERB_DECAYTIME_MIN 0.1f #define DSFX_I3DL2REVERB_DECAYTIME_MAX 20.0f #define DSFX_I3DL2REVERB_DECAYTIME_DEFAULT 1.49f #define DSFX_I3DL2REVERB_DECAYHFRATIO_MIN 0.1f #define DSFX_I3DL2REVERB_DECAYHFRATIO_MAX 2.0f #define DSFX_I3DL2REVERB_DECAYHFRATIO_DEFAULT 0.83f #define DSFX_I3DL2REVERB_REFLECTIONS_MIN (-10000) #define DSFX_I3DL2REVERB_REFLECTIONS_MAX 1000 #define DSFX_I3DL2REVERB_REFLECTIONS_DEFAULT (-2602) #define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MIN 0.0f #define DSFX_I3DL2REVERB_REFLECTIONSDELAY_MAX 0.3f #define DSFX_I3DL2REVERB_REFLECTIONSDELAY_DEFAULT 0.007f #define DSFX_I3DL2REVERB_REVERB_MIN (-10000) #define DSFX_I3DL2REVERB_REVERB_MAX 2000 #define DSFX_I3DL2REVERB_REVERB_DEFAULT (200) #define DSFX_I3DL2REVERB_REVERBDELAY_MIN 0.0f #define DSFX_I3DL2REVERB_REVERBDELAY_MAX 0.1f #define DSFX_I3DL2REVERB_REVERBDELAY_DEFAULT 0.011f #define DSFX_I3DL2REVERB_DIFFUSION_MIN 0.0f #define DSFX_I3DL2REVERB_DIFFUSION_MAX 100.0f #define DSFX_I3DL2REVERB_DIFFUSION_DEFAULT 100.0f #define DSFX_I3DL2REVERB_DENSITY_MIN 0.0f #define DSFX_I3DL2REVERB_DENSITY_MAX 100.0f #define DSFX_I3DL2REVERB_DENSITY_DEFAULT 100.0f #define DSFX_I3DL2REVERB_HFREFERENCE_MIN 20.0f #define DSFX_I3DL2REVERB_HFREFERENCE_MAX 20000.0f #define DSFX_I3DL2REVERB_HFREFERENCE_DEFAULT 5000.0f #define DSFX_I3DL2REVERB_QUALITY_MIN 0 #define DSFX_I3DL2REVERB_QUALITY_MAX 3 #define DSFX_I3DL2REVERB_QUALITY_DEFAULT 2 #undef INTERFACE #define INTERFACE IDirectSoundFXI3DL2Reverb DECLARE_INTERFACE_(IDirectSoundFXI3DL2Reverb, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXI3DL2Reverb methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXI3DL2Reverb pcDsFxI3DL2Reverb) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXI3DL2Reverb pDsFxI3DL2Reverb) PURE; STDMETHOD(SetPreset) (THIS_ DWORD dwPreset) PURE; STDMETHOD(GetPreset) (THIS_ LPDWORD pdwPreset) PURE; STDMETHOD(SetQuality) (THIS_ LONG lQuality) PURE; STDMETHOD(GetQuality) (THIS_ LONG *plQuality) PURE; }; #define IDirectSoundFXI3DL2Reverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXI3DL2Reverb_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXI3DL2Reverb_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->lpVtbl->SetPreset(p,a) #define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->lpVtbl->GetPreset(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXI3DL2Reverb_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXI3DL2Reverb_GetAllParameters(p,a) (p)->GetAllParameters(a) #define IDirectSoundFXI3DL2Reverb_SetPreset(p,a) (p)->SetPreset(a) #define IDirectSoundFXI3DL2Reverb_GetPreset(p,a) (p)->GetPreset(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFXWavesReverb // DEFINE_GUID(IID_IDirectSoundFXWavesReverb,0x46858c3a,0x0dc6,0x45e3,0xb7,0x60,0xd4,0xee,0xf1,0x6c,0xb3,0x25); typedef struct _DSFXWavesReverb { FLOAT fInGain; // [-96.0,0.0] default: 0.0 dB FLOAT fReverbMix; // [-96.0,0.0] default: 0.0 db FLOAT fReverbTime; // [0.001,3000.0] default: 1000.0 ms FLOAT fHighFreqRTRatio; // [0.001,0.999] default: 0.001 } DSFXWavesReverb, *LPDSFXWavesReverb; typedef const DSFXWavesReverb *LPCDSFXWavesReverb; #define DSFX_WAVESREVERB_INGAIN_MIN -96.0f #define DSFX_WAVESREVERB_INGAIN_MAX 0.0f #define DSFX_WAVESREVERB_INGAIN_DEFAULT 0.0f #define DSFX_WAVESREVERB_REVERBMIX_MIN -96.0f #define DSFX_WAVESREVERB_REVERBMIX_MAX 0.0f #define DSFX_WAVESREVERB_REVERBMIX_DEFAULT 0.0f #define DSFX_WAVESREVERB_REVERBTIME_MIN 0.001f #define DSFX_WAVESREVERB_REVERBTIME_MAX 3000.0f #define DSFX_WAVESREVERB_REVERBTIME_DEFAULT 1000.0f #define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MIN 0.001f #define DSFX_WAVESREVERB_HIGHFREQRTRATIO_MAX 0.999f #define DSFX_WAVESREVERB_HIGHFREQRTRATIO_DEFAULT 0.001f #undef INTERFACE #define INTERFACE IDirectSoundFXWavesReverb DECLARE_INTERFACE_(IDirectSoundFXWavesReverb, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFXWavesReverb methods STDMETHOD(SetAllParameters) (THIS_ LPCDSFXWavesReverb pcDsFxWavesReverb) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSFXWavesReverb pDsFxWavesReverb) PURE; }; #define IDirectSoundFXWavesReverb_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFXWavesReverb_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFXWavesReverb_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFXWavesReverb_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundFXWavesReverb_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundCaptureFXAec // DEFINE_GUID(IID_IDirectSoundCaptureFXAec, 0xad74143d, 0x903d, 0x4ab7, 0x80, 0x66, 0x28, 0xd3, 0x63, 0x03, 0x6d, 0x65); typedef struct _DSCFXAec { BOOL fEnable; BOOL fNoiseFill; DWORD dwMode; } DSCFXAec, *LPDSCFXAec; typedef const DSCFXAec *LPCDSCFXAec; // These match the AEC_MODE_* constants in the DDK's ksmedia.h file #define DSCFX_AEC_MODE_PASS_THROUGH 0x0 #define DSCFX_AEC_MODE_HALF_DUPLEX 0x1 #define DSCFX_AEC_MODE_FULL_DUPLEX 0x2 // These match the AEC_STATUS_* constants in ksmedia.h #define DSCFX_AEC_STATUS_HISTORY_UNINITIALIZED 0x0 #define DSCFX_AEC_STATUS_HISTORY_CONTINUOUSLY_CONVERGED 0x1 #define DSCFX_AEC_STATUS_HISTORY_PREVIOUSLY_DIVERGED 0x2 #define DSCFX_AEC_STATUS_CURRENTLY_CONVERGED 0x8 #undef INTERFACE #define INTERFACE IDirectSoundCaptureFXAec DECLARE_INTERFACE_(IDirectSoundCaptureFXAec, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundCaptureFXAec methods STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXAec pDscFxAec) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSCFXAec pDscFxAec) PURE; STDMETHOD(GetStatus) (THIS_ PDWORD pdwStatus) PURE; STDMETHOD(Reset) (THIS) PURE; }; #define IDirectSoundCaptureFXAec_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundCaptureFXAec_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundCaptureFXAec_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureFXAec_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundCaptureFXAec_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundCaptureFXNoiseSuppress // DEFINE_GUID(IID_IDirectSoundCaptureFXNoiseSuppress, 0xed311e41, 0xfbae, 0x4175, 0x96, 0x25, 0xcd, 0x8, 0x54, 0xf6, 0x93, 0xca); typedef struct _DSCFXNoiseSuppress { BOOL fEnable; } DSCFXNoiseSuppress, *LPDSCFXNoiseSuppress; typedef const DSCFXNoiseSuppress *LPCDSCFXNoiseSuppress; #undef INTERFACE #define INTERFACE IDirectSoundCaptureFXNoiseSuppress DECLARE_INTERFACE_(IDirectSoundCaptureFXNoiseSuppress, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundCaptureFXNoiseSuppress methods STDMETHOD(SetAllParameters) (THIS_ LPCDSCFXNoiseSuppress pcDscFxNoiseSuppress) PURE; STDMETHOD(GetAllParameters) (THIS_ LPDSCFXNoiseSuppress pDscFxNoiseSuppress) PURE; STDMETHOD(Reset) (THIS) PURE; }; #define IDirectSoundCaptureFXNoiseSuppress_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundCaptureFXNoiseSuppress_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundCaptureFXNoiseSuppress_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->lpVtbl->SetAllParameters(p,a) #define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundCaptureFXNoiseSuppress_SetAllParameters(p,a) (p)->SetAllParameters(a) #define IDirectSoundCaptureFXNoiseSuppress_GetAllParameters(p,a) (p)->GetAllParameters(a) #endif // !defined(__cplusplus) || defined(CINTERFACE) // // IDirectSoundFullDuplex // #ifndef _IDirectSoundFullDuplex_ #define _IDirectSoundFullDuplex_ #ifdef __cplusplus // 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined struct IDirectSoundFullDuplex; #endif // __cplusplus typedef struct IDirectSoundFullDuplex *LPDIRECTSOUNDFULLDUPLEX; DEFINE_GUID(IID_IDirectSoundFullDuplex, 0xedcb4c7a, 0xdaab, 0x4216, 0xa4, 0x2e, 0x6c, 0x50, 0x59, 0x6d, 0xdc, 0x1d); #undef INTERFACE #define INTERFACE IDirectSoundFullDuplex DECLARE_INTERFACE_(IDirectSoundFullDuplex, IUnknown) { // IUnknown methods STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; STDMETHOD_(ULONG,AddRef) (THIS) PURE; STDMETHOD_(ULONG,Release) (THIS) PURE; // IDirectSoundFullDuplex methods STDMETHOD(Initialize) (THIS_ LPCGUID pCaptureGuid, LPCGUID pRenderGuid, LPCDSCBUFFERDESC lpDscBufferDesc, LPCDSBUFFERDESC lpDsBufferDesc, HWND hWnd, DWORD dwLevel, LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8) PURE; }; #define IDirectSoundFullDuplex_QueryInterface(p,a,b) IUnknown_QueryInterface(p,a,b) #define IDirectSoundFullDuplex_AddRef(p) IUnknown_AddRef(p) #define IDirectSoundFullDuplex_Release(p) IUnknown_Release(p) #if !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->Initialize(p,a,b,c,d,e,f,g,h) #else // !defined(__cplusplus) || defined(CINTERFACE) #define IDirectSoundFullDuplex_Initialize(p,a,b,c,d,e,f,g,h) (p)->Initialize(a,b,c,d,e,f,g,h) #endif // !defined(__cplusplus) || defined(CINTERFACE) #endif // _IDirectSoundFullDuplex_ #endif // DIRECTSOUND_VERSION >= 0x0800 // // Return Codes // // The function completed successfully #define DS_OK S_OK // The call succeeded, but we had to substitute the 3D algorithm #define DS_NO_VIRTUALIZATION MAKE_HRESULT(0, _FACDS, 10) // The call failed because resources (such as a priority level) // were already being used by another caller #define DSERR_ALLOCATED MAKE_DSHRESULT(10) // The control (vol, pan, etc.) requested by the caller is not available #define DSERR_CONTROLUNAVAIL MAKE_DSHRESULT(30) // An invalid parameter was passed to the returning function #define DSERR_INVALIDPARAM E_INVALIDARG // This call is not valid for the current state of this object #define DSERR_INVALIDCALL MAKE_DSHRESULT(50) // An undetermined error occurred inside the DirectSound subsystem #define DSERR_GENERIC E_FAIL // The caller does not have the priority level required for the function to // succeed #define DSERR_PRIOLEVELNEEDED MAKE_DSHRESULT(70) // Not enough free memory is available to complete the operation #define DSERR_OUTOFMEMORY E_OUTOFMEMORY // The specified WAVE format is not supported #define DSERR_BADFORMAT MAKE_DSHRESULT(100) // The function called is not supported at this time #define DSERR_UNSUPPORTED E_NOTIMPL // No sound driver is available for use #define DSERR_NODRIVER MAKE_DSHRESULT(120) // This object is already initialized #define DSERR_ALREADYINITIALIZED MAKE_DSHRESULT(130) // This object does not support aggregation #define DSERR_NOAGGREGATION CLASS_E_NOAGGREGATION // The buffer memory has been lost, and must be restored #define DSERR_BUFFERLOST MAKE_DSHRESULT(150) // Another app has a higher priority level, preventing this call from // succeeding #define DSERR_OTHERAPPHASPRIO MAKE_DSHRESULT(160) // This object has not been initialized #define DSERR_UNINITIALIZED MAKE_DSHRESULT(170) // The requested COM interface is not available #define DSERR_NOINTERFACE E_NOINTERFACE // Access is denied #define DSERR_ACCESSDENIED E_ACCESSDENIED // Tried to create a DSBCAPS_CTRLFX buffer shorter than DSBSIZE_FX_MIN milliseconds #define DSERR_BUFFERTOOSMALL MAKE_DSHRESULT(180) // Attempt to use DirectSound 8 functionality on an older DirectSound object #define DSERR_DS8_REQUIRED MAKE_DSHRESULT(190) // A circular loop of send effects was detected #define DSERR_SENDLOOP MAKE_DSHRESULT(200) // The GUID specified in an audiopath file does not match a valid MIXIN buffer #define DSERR_BADSENDBUFFERGUID MAKE_DSHRESULT(210) // The object requested was not found (numerically equal to DMUS_E_NOT_FOUND) #define DSERR_OBJECTNOTFOUND MAKE_DSHRESULT(4449) // The effects requested could not be found on the system, or they were found // but in the wrong order, or in the wrong hardware/software locations. #define DSERR_FXUNAVAILABLE MAKE_DSHRESULT(220) // // Flags // #define DSCAPS_PRIMARYMONO 0x00000001 #define DSCAPS_PRIMARYSTEREO 0x00000002 #define DSCAPS_PRIMARY8BIT 0x00000004 #define DSCAPS_PRIMARY16BIT 0x00000008 #define DSCAPS_CONTINUOUSRATE 0x00000010 #define DSCAPS_EMULDRIVER 0x00000020 #define DSCAPS_CERTIFIED 0x00000040 #define DSCAPS_SECONDARYMONO 0x00000100 #define DSCAPS_SECONDARYSTEREO 0x00000200 #define DSCAPS_SECONDARY8BIT 0x00000400 #define DSCAPS_SECONDARY16BIT 0x00000800 #define DSSCL_NORMAL 0x00000001 #define DSSCL_PRIORITY 0x00000002 #define DSSCL_EXCLUSIVE 0x00000003 #define DSSCL_WRITEPRIMARY 0x00000004 #define DSSPEAKER_DIRECTOUT 0x00000000 #define DSSPEAKER_HEADPHONE 0x00000001 #define DSSPEAKER_MONO 0x00000002 #define DSSPEAKER_QUAD 0x00000003 #define DSSPEAKER_STEREO 0x00000004 #define DSSPEAKER_SURROUND 0x00000005 #define DSSPEAKER_5POINT1 0x00000006 // obsolete 5.1 setting #define DSSPEAKER_7POINT1 0x00000007 // obsolete 7.1 setting #define DSSPEAKER_7POINT1_SURROUND 0x00000008 // correct 7.1 Home Theater setting #define DSSPEAKER_7POINT1_WIDE DSSPEAKER_7POINT1 #if (DIRECTSOUND_VERSION >= 0x1000) #define DSSPEAKER_5POINT1_SURROUND 0x00000009 // correct 5.1 setting #define DSSPEAKER_5POINT1_BACK DSSPEAKER_5POINT1 #endif #define DSSPEAKER_GEOMETRY_MIN 0x00000005 // 5 degrees #define DSSPEAKER_GEOMETRY_NARROW 0x0000000A // 10 degrees #define DSSPEAKER_GEOMETRY_WIDE 0x00000014 // 20 degrees #define DSSPEAKER_GEOMETRY_MAX 0x000000B4 // 180 degrees #define DSSPEAKER_COMBINED(c, g) ((DWORD)(((BYTE)(c)) | ((DWORD)((BYTE)(g))) << 16)) #define DSSPEAKER_CONFIG(a) ((BYTE)(a)) #define DSSPEAKER_GEOMETRY(a) ((BYTE)(((DWORD)(a) >> 16) & 0x00FF)) #define DSBCAPS_PRIMARYBUFFER 0x00000001 #define DSBCAPS_STATIC 0x00000002 #define DSBCAPS_LOCHARDWARE 0x00000004 #define DSBCAPS_LOCSOFTWARE 0x00000008 #define DSBCAPS_CTRL3D 0x00000010 #define DSBCAPS_CTRLFREQUENCY 0x00000020 #define DSBCAPS_CTRLPAN 0x00000040 #define DSBCAPS_CTRLVOLUME 0x00000080 #define DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 #define DSBCAPS_CTRLFX 0x00000200 #define DSBCAPS_STICKYFOCUS 0x00004000 #define DSBCAPS_GLOBALFOCUS 0x00008000 #define DSBCAPS_GETCURRENTPOSITION2 0x00010000 #define DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 #define DSBCAPS_LOCDEFER 0x00040000 #if (DIRECTSOUND_VERSION >= 0x1000) // Force GetCurrentPosition() to return a buffer's true play position; // unmodified by aids to enhance backward compatibility. #define DSBCAPS_TRUEPLAYPOSITION 0x00080000 #endif #define DSBPLAY_LOOPING 0x00000001 #define DSBPLAY_LOCHARDWARE 0x00000002 #define DSBPLAY_LOCSOFTWARE 0x00000004 #define DSBPLAY_TERMINATEBY_TIME 0x00000008 #define DSBPLAY_TERMINATEBY_DISTANCE 0x000000010 #define DSBPLAY_TERMINATEBY_PRIORITY 0x000000020 #define DSBSTATUS_PLAYING 0x00000001 #define DSBSTATUS_BUFFERLOST 0x00000002 #define DSBSTATUS_LOOPING 0x00000004 #define DSBSTATUS_LOCHARDWARE 0x00000008 #define DSBSTATUS_LOCSOFTWARE 0x00000010 #define DSBSTATUS_TERMINATED 0x00000020 #define DSBLOCK_FROMWRITECURSOR 0x00000001 #define DSBLOCK_ENTIREBUFFER 0x00000002 #define DSBFREQUENCY_ORIGINAL 0 #define DSBFREQUENCY_MIN 100 #if DIRECTSOUND_VERSION >= 0x0900 #define DSBFREQUENCY_MAX 200000 #else #define DSBFREQUENCY_MAX 100000 #endif #define DSBPAN_LEFT -10000 #define DSBPAN_CENTER 0 #define DSBPAN_RIGHT 10000 #define DSBVOLUME_MIN -10000 #define DSBVOLUME_MAX 0 #define DSBSIZE_MIN 4 #define DSBSIZE_MAX 0x0FFFFFFF #define DSBSIZE_FX_MIN 150 // NOTE: Milliseconds, not bytes #define DSBNOTIFICATIONS_MAX 100000UL #define DS3DMODE_NORMAL 0x00000000 #define DS3DMODE_HEADRELATIVE 0x00000001 #define DS3DMODE_DISABLE 0x00000002 #define DS3D_IMMEDIATE 0x00000000 #define DS3D_DEFERRED 0x00000001 #define DS3D_MINDISTANCEFACTOR FLT_MIN #define DS3D_MAXDISTANCEFACTOR FLT_MAX #define DS3D_DEFAULTDISTANCEFACTOR 1.0f #define DS3D_MINROLLOFFFACTOR 0.0f #define DS3D_MAXROLLOFFFACTOR 10.0f #define DS3D_DEFAULTROLLOFFFACTOR 1.0f #define DS3D_MINDOPPLERFACTOR 0.0f #define DS3D_MAXDOPPLERFACTOR 10.0f #define DS3D_DEFAULTDOPPLERFACTOR 1.0f #define DS3D_DEFAULTMINDISTANCE 1.0f #define DS3D_DEFAULTMAXDISTANCE 1000000000.0f #define DS3D_MINCONEANGLE 0 #define DS3D_MAXCONEANGLE 360 #define DS3D_DEFAULTCONEANGLE 360 #define DS3D_DEFAULTCONEOUTSIDEVOLUME DSBVOLUME_MAX // IDirectSoundCapture attributes #define DSCCAPS_EMULDRIVER DSCAPS_EMULDRIVER #define DSCCAPS_CERTIFIED DSCAPS_CERTIFIED #define DSCCAPS_MULTIPLECAPTURE 0x00000001 // IDirectSoundCaptureBuffer attributes #define DSCBCAPS_WAVEMAPPED 0x80000000 #if DIRECTSOUND_VERSION >= 0x0800 #define DSCBCAPS_CTRLFX 0x00000200 #endif #define DSCBLOCK_ENTIREBUFFER 0x00000001 #define DSCBSTATUS_CAPTURING 0x00000001 #define DSCBSTATUS_LOOPING 0x00000002 #define DSCBSTART_LOOPING 0x00000001 #define DSBPN_OFFSETSTOP 0xFFFFFFFF #define DS_CERTIFIED 0x00000000 #define DS_UNCERTIFIED 0x00000001 // // Flags for the I3DL2 effects // // // I3DL2 Material Presets // enum { DSFX_I3DL2_MATERIAL_PRESET_SINGLEWINDOW, DSFX_I3DL2_MATERIAL_PRESET_DOUBLEWINDOW, DSFX_I3DL2_MATERIAL_PRESET_THINDOOR, DSFX_I3DL2_MATERIAL_PRESET_THICKDOOR, DSFX_I3DL2_MATERIAL_PRESET_WOODWALL, DSFX_I3DL2_MATERIAL_PRESET_BRICKWALL, DSFX_I3DL2_MATERIAL_PRESET_STONEWALL, DSFX_I3DL2_MATERIAL_PRESET_CURTAIN }; #define I3DL2_MATERIAL_PRESET_SINGLEWINDOW -2800,0.71f #define I3DL2_MATERIAL_PRESET_DOUBLEWINDOW -5000,0.40f #define I3DL2_MATERIAL_PRESET_THINDOOR -1800,0.66f #define I3DL2_MATERIAL_PRESET_THICKDOOR -4400,0.64f #define I3DL2_MATERIAL_PRESET_WOODWALL -4000,0.50f #define I3DL2_MATERIAL_PRESET_BRICKWALL -5000,0.60f #define I3DL2_MATERIAL_PRESET_STONEWALL -6000,0.68f #define I3DL2_MATERIAL_PRESET_CURTAIN -1200,0.15f enum { DSFX_I3DL2_ENVIRONMENT_PRESET_DEFAULT, DSFX_I3DL2_ENVIRONMENT_PRESET_GENERIC, DSFX_I3DL2_ENVIRONMENT_PRESET_PADDEDCELL, DSFX_I3DL2_ENVIRONMENT_PRESET_ROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_BATHROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_LIVINGROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_STONEROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_AUDITORIUM, DSFX_I3DL2_ENVIRONMENT_PRESET_CONCERTHALL, DSFX_I3DL2_ENVIRONMENT_PRESET_CAVE, DSFX_I3DL2_ENVIRONMENT_PRESET_ARENA, DSFX_I3DL2_ENVIRONMENT_PRESET_HANGAR, DSFX_I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY, DSFX_I3DL2_ENVIRONMENT_PRESET_HALLWAY, DSFX_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR, DSFX_I3DL2_ENVIRONMENT_PRESET_ALLEY, DSFX_I3DL2_ENVIRONMENT_PRESET_FOREST, DSFX_I3DL2_ENVIRONMENT_PRESET_CITY, DSFX_I3DL2_ENVIRONMENT_PRESET_MOUNTAINS, DSFX_I3DL2_ENVIRONMENT_PRESET_QUARRY, DSFX_I3DL2_ENVIRONMENT_PRESET_PLAIN, DSFX_I3DL2_ENVIRONMENT_PRESET_PARKINGLOT, DSFX_I3DL2_ENVIRONMENT_PRESET_SEWERPIPE, DSFX_I3DL2_ENVIRONMENT_PRESET_UNDERWATER, DSFX_I3DL2_ENVIRONMENT_PRESET_SMALLROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEROOM, DSFX_I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL, DSFX_I3DL2_ENVIRONMENT_PRESET_LARGEHALL, DSFX_I3DL2_ENVIRONMENT_PRESET_PLATE }; // // I3DL2 Reverberation Presets Values // #define I3DL2_ENVIRONMENT_PRESET_DEFAULT -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_GENERIC -1000, -100, 0.0f, 1.49f, 0.83f, -2602, 0.007f, 200, 0.011f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_PADDEDCELL -1000,-6000, 0.0f, 0.17f, 0.10f, -1204, 0.001f, 207, 0.002f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_ROOM -1000, -454, 0.0f, 0.40f, 0.83f, -1646, 0.002f, 53, 0.003f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_BATHROOM -1000,-1200, 0.0f, 1.49f, 0.54f, -370, 0.007f, 1030, 0.011f, 100.0f, 60.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_LIVINGROOM -1000,-6000, 0.0f, 0.50f, 0.10f, -1376, 0.003f, -1104, 0.004f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_STONEROOM -1000, -300, 0.0f, 2.31f, 0.64f, -711, 0.012f, 83, 0.017f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_AUDITORIUM -1000, -476, 0.0f, 4.32f, 0.59f, -789, 0.020f, -289, 0.030f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_CONCERTHALL -1000, -500, 0.0f, 3.92f, 0.70f, -1230, 0.020f, -2, 0.029f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_CAVE -1000, 0, 0.0f, 2.91f, 1.30f, -602, 0.015f, -302, 0.022f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_ARENA -1000, -698, 0.0f, 7.24f, 0.33f, -1166, 0.020f, 16, 0.030f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_HANGAR -1000,-1000, 0.0f,10.05f, 0.23f, -602, 0.020f, 198, 0.030f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_CARPETEDHALLWAY -1000,-4000, 0.0f, 0.30f, 0.10f, -1831, 0.002f, -1630, 0.030f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_HALLWAY -1000, -300, 0.0f, 1.49f, 0.59f, -1219, 0.007f, 441, 0.011f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR -1000, -237, 0.0f, 2.70f, 0.79f, -1214, 0.013f, 395, 0.020f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_ALLEY -1000, -270, 0.0f, 1.49f, 0.86f, -1204, 0.007f, -4, 0.011f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_FOREST -1000,-3300, 0.0f, 1.49f, 0.54f, -2560, 0.162f, -613, 0.088f, 79.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_CITY -1000, -800, 0.0f, 1.49f, 0.67f, -2273, 0.007f, -2217, 0.011f, 50.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_MOUNTAINS -1000,-2500, 0.0f, 1.49f, 0.21f, -2780, 0.300f, -2014, 0.100f, 27.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_QUARRY -1000,-1000, 0.0f, 1.49f, 0.83f,-10000, 0.061f, 500, 0.025f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_PLAIN -1000,-2000, 0.0f, 1.49f, 0.50f, -2466, 0.179f, -2514, 0.100f, 21.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_PARKINGLOT -1000, 0, 0.0f, 1.65f, 1.50f, -1363, 0.008f, -1153, 0.012f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_SEWERPIPE -1000,-1000, 0.0f, 2.81f, 0.14f, 429, 0.014f, 648, 0.021f, 80.0f, 60.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_UNDERWATER -1000,-4000, 0.0f, 1.49f, 0.10f, -449, 0.007f, 1700, 0.011f, 100.0f, 100.0f, 5000.0f // // Examples simulating 'musical' reverb presets // // Name Decay time Description // Small Room 1.1s A small size room with a length of 5m or so. // Medium Room 1.3s A medium size room with a length of 10m or so. // Large Room 1.5s A large size room suitable for live performances. // Medium Hall 1.8s A medium size concert hall. // Large Hall 1.8s A large size concert hall suitable for a full orchestra. // Plate 1.3s A plate reverb simulation. // #define I3DL2_ENVIRONMENT_PRESET_SMALLROOM -1000, -600, 0.0f, 1.10f, 0.83f, -400, 0.005f, 500, 0.010f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_MEDIUMROOM -1000, -600, 0.0f, 1.30f, 0.83f, -1000, 0.010f, -200, 0.020f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_LARGEROOM -1000, -600, 0.0f, 1.50f, 0.83f, -1600, 0.020f, -1000, 0.040f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_MEDIUMHALL -1000, -600, 0.0f, 1.80f, 0.70f, -1300, 0.015f, -800, 0.030f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_LARGEHALL -1000, -600, 0.0f, 1.80f, 0.70f, -2000, 0.030f, -1400, 0.060f, 100.0f, 100.0f, 5000.0f #define I3DL2_ENVIRONMENT_PRESET_PLATE -1000, -200, 0.0f, 1.30f, 0.90f, 0, 0.002f, 0, 0.010f, 100.0f, 75.0f, 5000.0f // // DirectSound3D Algorithms // // Default DirectSound3D algorithm {00000000-0000-0000-0000-000000000000} #define DS3DALG_DEFAULT GUID_NULL // No virtualization (Pan3D) {C241333F-1C1B-11d2-94F5-00C04FC28ACA} DEFINE_GUID(DS3DALG_NO_VIRTUALIZATION, 0xc241333f, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); // High-quality HRTF algorithm {C2413340-1C1B-11d2-94F5-00C04FC28ACA} DEFINE_GUID(DS3DALG_HRTF_FULL, 0xc2413340, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); // Lower-quality HRTF algorithm {C2413342-1C1B-11d2-94F5-00C04FC28ACA} DEFINE_GUID(DS3DALG_HRTF_LIGHT, 0xc2413342, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x0, 0xc0, 0x4f, 0xc2, 0x8a, 0xca); #if DIRECTSOUND_VERSION >= 0x0800 // // DirectSound Internal Effect Algorithms // // Gargle {DAFD8210-5711-4B91-9FE3-F75B7AE279BF} DEFINE_GUID(GUID_DSFX_STANDARD_GARGLE, 0xdafd8210, 0x5711, 0x4b91, 0x9f, 0xe3, 0xf7, 0x5b, 0x7a, 0xe2, 0x79, 0xbf); // Chorus {EFE6629C-81F7-4281-BD91-C9D604A95AF6} DEFINE_GUID(GUID_DSFX_STANDARD_CHORUS, 0xefe6629c, 0x81f7, 0x4281, 0xbd, 0x91, 0xc9, 0xd6, 0x04, 0xa9, 0x5a, 0xf6); // Flanger {EFCA3D92-DFD8-4672-A603-7420894BAD98} DEFINE_GUID(GUID_DSFX_STANDARD_FLANGER, 0xefca3d92, 0xdfd8, 0x4672, 0xa6, 0x03, 0x74, 0x20, 0x89, 0x4b, 0xad, 0x98); // Echo/Delay {EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D} DEFINE_GUID(GUID_DSFX_STANDARD_ECHO, 0xef3e932c, 0xd40b, 0x4f51, 0x8c, 0xcf, 0x3f, 0x98, 0xf1, 0xb2, 0x9d, 0x5d); // Distortion {EF114C90-CD1D-484E-96E5-09CFAF912A21} DEFINE_GUID(GUID_DSFX_STANDARD_DISTORTION, 0xef114c90, 0xcd1d, 0x484e, 0x96, 0xe5, 0x09, 0xcf, 0xaf, 0x91, 0x2a, 0x21); // Compressor/Limiter {EF011F79-4000-406D-87AF-BFFB3FC39D57} DEFINE_GUID(GUID_DSFX_STANDARD_COMPRESSOR, 0xef011f79, 0x4000, 0x406d, 0x87, 0xaf, 0xbf, 0xfb, 0x3f, 0xc3, 0x9d, 0x57); // Parametric Equalization {120CED89-3BF4-4173-A132-3CB406CF3231} DEFINE_GUID(GUID_DSFX_STANDARD_PARAMEQ, 0x120ced89, 0x3bf4, 0x4173, 0xa1, 0x32, 0x3c, 0xb4, 0x06, 0xcf, 0x32, 0x31); // I3DL2 Environmental Reverberation: Reverb (Listener) Effect {EF985E71-D5C7-42D4-BA4D-2D073E2E96F4} DEFINE_GUID(GUID_DSFX_STANDARD_I3DL2REVERB, 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4); // Waves Reverberation {87FC0268-9A55-4360-95AA-004A1D9DE26C} DEFINE_GUID(GUID_DSFX_WAVES_REVERB, 0x87fc0268, 0x9a55, 0x4360, 0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c); // // DirectSound Capture Effect Algorithms // // Acoustic Echo Canceller {BF963D80-C559-11D0-8A2B-00A0C9255AC1} // Matches KSNODETYPE_ACOUSTIC_ECHO_CANCEL in ksmedia.h DEFINE_GUID(GUID_DSCFX_CLASS_AEC, 0xBF963D80L, 0xC559, 0x11D0, 0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1); // Microsoft AEC {CDEBB919-379A-488a-8765-F53CFD36DE40} DEFINE_GUID(GUID_DSCFX_MS_AEC, 0xcdebb919, 0x379a, 0x488a, 0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40); // System AEC {1C22C56D-9879-4f5b-A389-27996DDC2810} DEFINE_GUID(GUID_DSCFX_SYSTEM_AEC, 0x1c22c56d, 0x9879, 0x4f5b, 0xa3, 0x89, 0x27, 0x99, 0x6d, 0xdc, 0x28, 0x10); // Noise Supression {E07F903F-62FD-4e60-8CDD-DEA7236665B5} // Matches KSNODETYPE_NOISE_SUPPRESS in post Windows ME DDK's ksmedia.h DEFINE_GUID(GUID_DSCFX_CLASS_NS, 0xe07f903f, 0x62fd, 0x4e60, 0x8c, 0xdd, 0xde, 0xa7, 0x23, 0x66, 0x65, 0xb5); // Microsoft Noise Suppresion {11C5C73B-66E9-4ba1-A0BA-E814C6EED92D} DEFINE_GUID(GUID_DSCFX_MS_NS, 0x11c5c73b, 0x66e9, 0x4ba1, 0xa0, 0xba, 0xe8, 0x14, 0xc6, 0xee, 0xd9, 0x2d); // System Noise Suppresion {5AB0882E-7274-4516-877D-4EEE99BA4FD0} DEFINE_GUID(GUID_DSCFX_SYSTEM_NS, 0x5ab0882e, 0x7274, 0x4516, 0x87, 0x7d, 0x4e, 0xee, 0x99, 0xba, 0x4f, 0xd0); #endif // DIRECTSOUND_VERSION >= 0x0800 #endif // __DSOUND_INCLUDED__ #ifdef __cplusplus }; #endif // __cplusplus giada-0.11.2/src/deps/rtaudio-mod/include/ginclude.h000066400000000000000000000011741264622563000222050ustar00rootroot00000000000000#ifndef __gInclude__ #define __gInclude__ #if SGI #undef BEOS #undef MAC #undef WINDOWS // #define ASIO_BIG_ENDIAN 1 #define ASIO_CPU_MIPS 1 #elif defined WIN32 #undef BEOS #undef MAC #undef SGI #define WINDOWS 1 #define ASIO_LITTLE_ENDIAN 1 #define ASIO_CPU_X86 1 #elif BEOS #undef MAC #undef SGI #undef WINDOWS #define ASIO_LITTLE_ENDIAN 1 #define ASIO_CPU_X86 1 // #else #define MAC 1 #undef BEOS #undef WINDOWS #undef SGI #define ASIO_BIG_ENDIAN 1 #define ASIO_CPU_PPC 1 #endif // always #define NATIVE_INT64 0 #define IEEE754_64FLOAT 1 #endif // __gInclude__ giada-0.11.2/src/deps/rtaudio-mod/include/iasiodrv.h000066400000000000000000000030641264622563000222330ustar00rootroot00000000000000#include "asiosys.h" #include "asio.h" /* Forward Declarations */ #ifndef __ASIODRIVER_FWD_DEFINED__ #define __ASIODRIVER_FWD_DEFINED__ typedef interface IASIO IASIO; #endif /* __ASIODRIVER_FWD_DEFINED__ */ interface IASIO : public IUnknown { virtual ASIOBool init(void *sysHandle) = 0; virtual void getDriverName(char *name) = 0; virtual long getDriverVersion() = 0; virtual void getErrorMessage(char *string) = 0; virtual ASIOError start() = 0; virtual ASIOError stop() = 0; virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0; virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0; virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) = 0; virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0; virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0; virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0; virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0; virtual ASIOError setClockSource(long reference) = 0; virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0; virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) = 0; virtual ASIOError disposeBuffers() = 0; virtual ASIOError controlPanel() = 0; virtual ASIOError future(long selector,void *opt) = 0; virtual ASIOError outputReady() = 0; }; giada-0.11.2/src/deps/rtaudio-mod/include/iasiothiscallresolver.cpp000066400000000000000000000566631264622563000253750ustar00rootroot00000000000000/* IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for the top level description - this comment describes the technical details of the implementation. The latest version of this file is available from: http://www.audiomulch.com/~rossb/code/calliasio please email comments to Ross Bencina BACKGROUND The IASIO interface declared in the Steinberg ASIO 2 SDK declares functions with no explicit calling convention. This causes MSVC++ to default to using the thiscall convention, which is a proprietary convention not implemented by some non-microsoft compilers - notably borland BCC, C++Builder, and gcc. MSVC++ is the defacto standard compiler used by Steinberg. As a result of this situation, the ASIO sdk will compile with any compiler, however attempting to execute the compiled code will cause a crash due to different default calling conventions on non-Microsoft compilers. IASIOThiscallResolver solves the problem by providing an adapter class that delegates to the IASIO interface using the correct calling convention (thiscall). Due to the lack of support for thiscall in the Borland and GCC compilers, the calls have been implemented in assembly language. A number of macros are defined for thiscall function calls with different numbers of parameters, with and without return values - it may be possible to modify the format of these macros to make them work with other inline assemblers. THISCALL DEFINITION A number of definitions of the thiscall calling convention are floating around the internet. The following definition has been validated against output from the MSVC++ compiler: For non-vararg functions, thiscall works as follows: the object (this) pointer is passed in ECX. All arguments are passed on the stack in right to left order. The return value is placed in EAX. The callee clears the passed arguments from the stack. FINDING FUNCTION POINTERS FROM AN IASIO POINTER The first field of a COM object is a pointer to its vtble. Thus a pointer to an object implementing the IASIO interface also points to a pointer to that object's vtbl. The vtble is a table of function pointers for all of the virtual functions exposed by the implemented interfaces. If we consider a variable declared as a pointer to IASO: IASIO *theAsioDriver theAsioDriver points to: object implementing IASIO { IASIOvtbl *vtbl other data } in other words, theAsioDriver points to a pointer to an IASIOvtbl vtbl points to a table of function pointers: IASIOvtbl ( interface IASIO : public IUnknown ) { (IUnknown functions) 0 virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0; 4 virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0; 8 virtual ULONG STDMETHODCALLTYPE (*Release)() = 0; (IASIO functions) 12 virtual ASIOBool (*init)(void *sysHandle) = 0; 16 virtual void (*getDriverName)(char *name) = 0; 20 virtual long (*getDriverVersion)() = 0; 24 virtual void (*getErrorMessage)(char *string) = 0; 28 virtual ASIOError (*start)() = 0; 32 virtual ASIOError (*stop)() = 0; 36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0; 40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0; 44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize, long *preferredSize, long *granularity) = 0; 48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0; 52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0; 56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0; 60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0; 64 virtual ASIOError (*setClockSource)(long reference) = 0; 68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; 72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0; 76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) = 0; 80 virtual ASIOError (*disposeBuffers)() = 0; 84 virtual ASIOError (*controlPanel)() = 0; 88 virtual ASIOError (*future)(long selector,void *opt) = 0; 92 virtual ASIOError (*outputReady)() = 0; }; The numbers in the left column show the byte offset of each function ptr from the beginning of the vtbl. These numbers are used in the code below to select different functions. In order to find the address of a particular function, theAsioDriver must first be dereferenced to find the value of the vtbl pointer: mov eax, theAsioDriver mov edx, [theAsioDriver] // edx now points to vtbl[0] Then an offset must be added to the vtbl pointer to select a particular function, for example vtbl+44 points to the slot containing a pointer to the getBufferSize function. Finally vtbl+x must be dereferenced to obtain the value of the function pointer stored in that address: call [edx+44] // call the function pointed to by // the value in the getBufferSize field of the vtbl SEE ALSO Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same problem by providing a new COM interface which wraps IASIO with an interface that uses portable calling conventions. OpenASIO must be compiled with MSVC, and requires that you ship the OpenASIO DLL with your application. ACKNOWLEDGEMENTS Ross Bencina: worked out the thiscall details above, wrote the original Borland asm macros, and a patch for asio.cpp (which is no longer needed). Thanks to Martin Fay for introducing me to the issues discussed here, and to Rene G. Ceballos for assisting with asm dumps from MSVC++. Antti Silvast: converted the original calliasio to work with gcc and NASM by implementing the asm code in a separate file. Fraser Adams: modified the original calliasio containing the Borland inline asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax for gcc. This seems a neater approach for gcc than to have a separate .asm file and it means that we only need one version of the thiscall patch. Fraser Adams: rewrote the original calliasio patch in the form of the IASIOThiscallResolver class in order to avoid modifications to files from the Steinberg SDK, which may have had potential licence issues. Andrew Baldwin: contributed fixes for compatibility problems with more recent versions of the gcc assembler. */ // We only need IASIOThiscallResolver at all if we are on Win32. For other // platforms we simply bypass the IASIOThiscallResolver definition to allow us // to be safely #include'd whatever the platform to keep client code portable #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver // is not used. #if !defined(_MSC_VER) #include #include // We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is // #include'd before it in client code, we do NOT want to do this test here. #define iasiothiscallresolver_sourcefile 1 #include "iasiothiscallresolver.h" #undef iasiothiscallresolver_sourcefile // iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want // this macro defined in this translation unit. #undef ASIOInit // theAsioDriver is a global pointer to the current IASIO instance which the // ASIO SDK uses to perform all actions on the IASIO interface. We substitute // our own forwarding interface into this pointer. extern IASIO* theAsioDriver; // The following macros define the inline assembler for BORLAND first then gcc #if defined(__BCPLUSPLUS__) || defined(__BORLANDC__) #define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\ void *this_ = (thisPtr); \ __asm { \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ } #define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\ void *this_ = (thisPtr); \ void *doubleParamPtr_ (¶m1); \ __asm { \ mov eax, doubleParamPtr_ ; \ push [eax+4] ; \ push [eax] ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param2 ; \ push eax ; \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param4 ; \ push eax ; \ mov eax, param3 ; \ push eax ; \ mov eax, param2 ; \ push eax ; \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #elif defined(__GNUC__) #define CALL_THISCALL_0( resultName, thisPtr, funcOffset ) \ __asm__ __volatile__ ("movl (%1), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"c"(thisPtr) /* Input Operands */ \ : "%edx" /* Clobbered Registers */ \ ); \ #define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 ) \ __asm__ __volatile__ ("pushl %0\n\t" \ "movl (%1), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ : /* Output Operands */ \ :"r"(param1), /* Input Operands */ \ "c"(thisPtr) \ : "%edx" /* Clobbered Registers */ \ ); \ #define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 ) \ __asm__ __volatile__ ("pushl %1\n\t" \ "movl (%2), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"r"(param1), /* Input Operands */ \ "c"(thisPtr) \ : "%edx" /* Clobbered Registers */ \ ); \ #define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \ do { \ double param1f64 = param1; /* Cast explicitly to double */ \ double *param1f64Ptr = ¶m1f64; /* Make pointer to address */ \ __asm__ __volatile__ ("pushl 4(%1)\n\t" \ "pushl (%1)\n\t" \ "movl (%2), %%edx\n\t" \ "call *"#funcOffset"(%%edx);\n\t" \ : "=a"(resultName) /* Output Operands */ \ : "r"(param1f64Ptr), /* Input Operands */ \ "c"(thisPtr), \ "m"(*param1f64Ptr) /* Using address */ \ : "%edx" /* Clobbered Registers */ \ ); \ } while (0); \ #define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 ) \ __asm__ __volatile__ ("pushl %1\n\t" \ "pushl %2\n\t" \ "movl (%3), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"r"(param2), /* Input Operands */ \ "r"(param1), \ "c"(thisPtr) \ : "%edx" /* Clobbered Registers */ \ ); \ #define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ __asm__ __volatile__ ("pushl %1\n\t" \ "pushl %2\n\t" \ "pushl %3\n\t" \ "pushl %4\n\t" \ "movl (%5), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"r"(param4), /* Input Operands */ \ "r"(param3), \ "r"(param2), \ "r"(param1), \ "c"(thisPtr) \ : "%edx" /* Clobbered Registers */ \ ); \ #endif // Our static singleton instance. IASIOThiscallResolver IASIOThiscallResolver::instance; // Constructor called to initialize static Singleton instance above. Note that // it is important not to clear that_ incase it has already been set by the call // to placement new in ASIOInit(). IASIOThiscallResolver::IASIOThiscallResolver() { } // Constructor called from ASIOInit() below IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that) : that_( that ) { } // Implement IUnknown methods as assert(false). IASIOThiscallResolver is not // really a COM object, just a wrapper which will work with the ASIO SDK. // If you wanted to use ASIO without the SDK you might want to implement COM // aggregation in these methods. HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv) { (void)riid; // suppress unused variable warning assert( false ); // this function should never be called by the ASIO SDK. *ppv = NULL; return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef() { assert( false ); // this function should never be called by the ASIO SDK. return 1; } ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release() { assert( false ); // this function should never be called by the ASIO SDK. return 1; } // Implement the IASIO interface methods by performing the vptr manipulation // described above then delegating to the real implementation. ASIOBool IASIOThiscallResolver::init(void *sysHandle) { ASIOBool result; CALL_THISCALL_1( result, that_, 12, sysHandle ); return result; } void IASIOThiscallResolver::getDriverName(char *name) { CALL_VOID_THISCALL_1( that_, 16, name ); } long IASIOThiscallResolver::getDriverVersion() { ASIOBool result; CALL_THISCALL_0( result, that_, 20 ); return result; } void IASIOThiscallResolver::getErrorMessage(char *string) { CALL_VOID_THISCALL_1( that_, 24, string ); } ASIOError IASIOThiscallResolver::start() { ASIOBool result; CALL_THISCALL_0( result, that_, 28 ); return result; } ASIOError IASIOThiscallResolver::stop() { ASIOBool result; CALL_THISCALL_0( result, that_, 32 ); return result; } ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels) { ASIOBool result; CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels ); return result; } ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency) { ASIOBool result; CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency ); return result; } ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) { ASIOBool result; CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity ); return result; } ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate) { ASIOBool result; CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate ); return result; } ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate) { ASIOBool result; CALL_THISCALL_1( result, that_, 52, sampleRate ); return result; } ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate) { ASIOBool result; CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate ); return result; } ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources) { ASIOBool result; CALL_THISCALL_2( result, that_, 60, clocks, numSources ); return result; } ASIOError IASIOThiscallResolver::setClockSource(long reference) { ASIOBool result; CALL_THISCALL_1( result, that_, 64, reference ); return result; } ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) { ASIOBool result; CALL_THISCALL_2( result, that_, 68, sPos, tStamp ); return result; } ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info) { ASIOBool result; CALL_THISCALL_1( result, that_, 72, info ); return result; } ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) { ASIOBool result; CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks ); return result; } ASIOError IASIOThiscallResolver::disposeBuffers() { ASIOBool result; CALL_THISCALL_0( result, that_, 80 ); return result; } ASIOError IASIOThiscallResolver::controlPanel() { ASIOBool result; CALL_THISCALL_0( result, that_, 84 ); return result; } ASIOError IASIOThiscallResolver::future(long selector,void *opt) { ASIOBool result; CALL_THISCALL_2( result, that_, 88, selector, opt ); return result; } ASIOError IASIOThiscallResolver::outputReady() { ASIOBool result; CALL_THISCALL_0( result, that_, 92 ); return result; } // Implement our substitute ASIOInit() method ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info) { // To ensure that our instance's vptr is correctly constructed, even if // ASIOInit is called prior to main(), we explicitly call its constructor // (potentially over the top of an existing instance). Note that this is // pretty ugly, and is only safe because IASIOThiscallResolver has no // destructor and contains no objects with destructors. new((void*)&instance) IASIOThiscallResolver( theAsioDriver ); // Interpose between ASIO client code and the real driver. theAsioDriver = &instance; // Note that we never need to switch theAsioDriver back to point to the // real driver because theAsioDriver is reset to zero in ASIOExit(). // Delegate to the real ASIOInit return ::ASIOInit(info); } #endif /* !defined(_MSC_VER) */ #endif /* Win32 */ giada-0.11.2/src/deps/rtaudio-mod/include/iasiothiscallresolver.h000066400000000000000000000232101264622563000250200ustar00rootroot00000000000000// **************************************************************************** // // Changed: I have modified this file slightly (includes) to work with // RtAudio. RtAudio.cpp must include this file after asio.h. // // File: IASIOThiscallResolver.h // Description: The IASIOThiscallResolver class implements the IASIO // interface and acts as a proxy to the real IASIO interface by // calling through its vptr table using the thiscall calling // convention. To put it another way, we interpose // IASIOThiscallResolver between ASIO SDK code and the driver. // This is necessary because most non-Microsoft compilers don't // implement the thiscall calling convention used by IASIO. // // iasiothiscallresolver.cpp contains the background of this // problem plus a technical description of the vptr // manipulations. // // In order to use this mechanism one simply has to add // iasiothiscallresolver.cpp to the list of files to compile // and #include // // Note that this #include must come after the other ASIO SDK // #includes, for example: // // #include // #include // #include // #include // #include // // Actually the important thing is to #include // after . We have // incorporated a test to enforce this ordering. // // The code transparently takes care of the interposition by // using macro substitution to intercept calls to ASIOInit() // and ASIOExit(). We save the original ASIO global // "theAsioDriver" in our "that" variable, and then set // "theAsioDriver" to equal our IASIOThiscallResolver instance. // // Whilst this method of resolving the thiscall problem requires // the addition of #include to client // code it has the advantage that it does not break the terms // of the ASIO licence by publishing it. We are NOT modifying // any Steinberg code here, we are merely implementing the IASIO // interface in the same way that we would need to do if we // wished to provide an open source ASIO driver. // // For compilation with MinGW -lole32 needs to be added to the // linker options. For BORLAND, linking with Import32.lib is // sufficient. // // The dependencies are with: CoInitialize, CoUninitialize, // CoCreateInstance, CLSIDFromString - used by asiolist.cpp // and are required on Windows whether ThiscallResolver is used // or not. // // Searching for the above strings in the root library path // of your compiler should enable the correct libraries to be // identified if they aren't immediately obvious. // // Note that the current implementation of IASIOThiscallResolver // is not COM compliant - it does not correctly implement the // IUnknown interface. Implementing it is not necessary because // it is not called by parts of the ASIO SDK which call through // theAsioDriver ptr. The IUnknown methods are implemented as // assert(false) to ensure that the code fails if they are // ever called. // Restrictions: None. Public Domain & Open Source distribute freely // You may use IASIOThiscallResolver commercially as well as // privately. // You the user assume the responsibility for the use of the // files, binary or text, and there is no guarantee or warranty, // expressed or implied, including but not limited to the // implied warranties of merchantability and fitness for a // particular purpose. You assume all responsibility and agree // to hold no entity, copyright holder or distributors liable // for any loss of data or inaccurate representations of data // as a result of using IASIOThiscallResolver. // Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from // Andrew Baldwin, and volatile for whole gcc asm blocks, // both for compatibility with newer gcc versions. Cleaned up // Borland asm to use one less register. // 1.3 Switched to including assert.h for better compatibility. // Wrapped entire .h and .cpp contents with a check for // _MSC_VER to provide better compatibility with MS compilers. // Changed Singleton implementation to use static instance // instead of freestore allocated instance. Removed ASIOExit // macro as it is no longer needed. // 1.2 Removed semicolons from ASIOInit and ASIOExit macros to // allow them to be embedded in expressions (if statements). // Cleaned up some comments. Removed combase.c dependency (it // doesn't compile with BCB anyway) by stubbing IUnknown. // 1.1 Incorporated comments from Ross Bencina including things // such as changing name from ThiscallResolver to // IASIOThiscallResolver, tidying up the constructor, fixing // a bug in IASIOThiscallResolver::ASIOExit() and improving // portability through the use of conditional compilation // 1.0 Initial working version. // Created: 6/09/2003 // Authors: Fraser Adams // Ross Bencina // Rene G. Ceballos // Martin Fay // Antti Silvast // Andrew Baldwin // // **************************************************************************** #ifndef included_iasiothiscallresolver_h #define included_iasiothiscallresolver_h // We only need IASIOThiscallResolver at all if we are on Win32. For other // platforms we simply bypass the IASIOThiscallResolver definition to allow us // to be safely #include'd whatever the platform to keep client code portable //#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver // is not used. #if !defined(_MSC_VER) // The following is in order to ensure that this header is only included after // the other ASIO headers (except for the case of iasiothiscallresolver.cpp). // We need to do this because IASIOThiscallResolver works by eclipsing the // original definition of ASIOInit() with a macro (see below). #if !defined(iasiothiscallresolver_sourcefile) #if !defined(__ASIO_H) #error iasiothiscallresolver.h must be included AFTER asio.h #endif #endif #include #include "iasiodrv.h" /* From ASIO SDK */ class IASIOThiscallResolver : public IASIO { private: IASIO* that_; // Points to the real IASIO static IASIOThiscallResolver instance; // Singleton instance // Constructors - declared private so construction is limited to // our Singleton instance IASIOThiscallResolver(); IASIOThiscallResolver(IASIO* that); public: // Methods from the IUnknown interface. We don't fully implement IUnknown // because the ASIO SDK never calls these methods through theAsioDriver ptr. // These methods are implemented as assert(false). virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); // Methods from the IASIO interface, implemented as forwarning calls to that. virtual ASIOBool init(void *sysHandle); virtual void getDriverName(char *name); virtual long getDriverVersion(); virtual void getErrorMessage(char *string); virtual ASIOError start(); virtual ASIOError stop(); virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); virtual ASIOError setClockSource(long reference); virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); virtual ASIOError getChannelInfo(ASIOChannelInfo *info); virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); virtual ASIOError disposeBuffers(); virtual ASIOError controlPanel(); virtual ASIOError future(long selector,void *opt); virtual ASIOError outputReady(); // Class method, see ASIOInit() macro below. static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit }; // Replace calls to ASIOInit with our interposing version. // This macro enables us to perform thiscall resolution simply by #including // after the asio #includes (this file _must_ be // included _after_ the asio #includes) #define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) #endif /* !defined(_MSC_VER) */ #endif /* Win32 */ #endif /* included_iasiothiscallresolver_h */ giada-0.11.2/src/deps/rtaudio-mod/include/soundcard.h000066400000000000000000002011011264622563000223650ustar00rootroot00000000000000/* * soundcard.h */ /*- * Copyright by Hannu Savolainen 1993 / 4Front Technologies 1993-2006 * Modified for the new FreeBSD sound driver by Luigi Rizzo, 1997 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/sys/soundcard.h,v 1.48 2006/11/26 11:55:48 netchild Exp $ */ /* * Unless coordinating changes with 4Front Technologies, do NOT make any * modifications to ioctl commands, types, etc. that would break * compatibility with the OSS API. */ #ifndef _SYS_SOUNDCARD_H_ #define _SYS_SOUNDCARD_H_ /* * If you make modifications to this file, please contact me before * distributing the modified version. There is already enough * diversity in the world. * * Regards, * Hannu Savolainen * hannu@voxware.pp.fi * ********************************************************************** * PS. The Hacker's Guide to VoxWare available from * nic.funet.fi:pub/Linux/ALPHA/sound. The file is * snd-sdk-doc-0.1.ps.gz (gzipped postscript). It contains * some useful information about programming with VoxWare. * (NOTE! The pub/Linux/ALPHA/ directories are hidden. You have * to cd inside them before the files are accessible.) ********************************************************************** */ /* * SOUND_VERSION is only used by the voxware driver. Hopefully apps * should not depend on it, but rather look at the capabilities * of the driver in the kernel! */ #define SOUND_VERSION 301 #define VOXWARE /* does this have any use ? */ /* * Supported card ID numbers (Should be somewhere else? We keep * them here just for compativility with the old driver, but these * constants are of little or no use). */ #define SNDCARD_ADLIB 1 #define SNDCARD_SB 2 #define SNDCARD_PAS 3 #define SNDCARD_GUS 4 #define SNDCARD_MPU401 5 #define SNDCARD_SB16 6 #define SNDCARD_SB16MIDI 7 #define SNDCARD_UART6850 8 #define SNDCARD_GUS16 9 #define SNDCARD_MSS 10 #define SNDCARD_PSS 11 #define SNDCARD_SSCAPE 12 #define SNDCARD_PSS_MPU 13 #define SNDCARD_PSS_MSS 14 #define SNDCARD_SSCAPE_MSS 15 #define SNDCARD_TRXPRO 16 #define SNDCARD_TRXPRO_SB 17 #define SNDCARD_TRXPRO_MPU 18 #define SNDCARD_MAD16 19 #define SNDCARD_MAD16_MPU 20 #define SNDCARD_CS4232 21 #define SNDCARD_CS4232_MPU 22 #define SNDCARD_MAUI 23 #define SNDCARD_PSEUDO_MSS 24 #define SNDCARD_AWE32 25 #define SNDCARD_NSS 26 #define SNDCARD_UART16550 27 #define SNDCARD_OPL 28 #include #include #ifndef _IOWR #include #endif /* !_IOWR */ /* * The first part of this file contains the new FreeBSD sound ioctl * interface. Tries to minimize the number of different ioctls, and * to be reasonably general. * * 970821: some of the new calls have not been implemented yet. */ /* * the following three calls extend the generic file descriptor * interface. AIONWRITE is the dual of FIONREAD, i.e. returns the max * number of bytes for a write operation to be non-blocking. * * AIOGSIZE/AIOSSIZE are used to change the behaviour of the device, * from a character device (default) to a block device. In block mode, * (not to be confused with blocking mode) the main difference for the * application is that select() will return only when a complete * block can be read/written to the device, whereas in character mode * select will return true when one byte can be exchanged. For audio * devices, character mode makes select almost useless since one byte * will always be ready by the next sample time (which is often only a * handful of microseconds away). * Use a size of 0 or 1 to return to character mode. */ #define AIONWRITE _IOR('A', 10, int) /* get # bytes to write */ struct snd_size { int play_size; int rec_size; }; #define AIOGSIZE _IOR('A', 11, struct snd_size)/* read current blocksize */ #define AIOSSIZE _IOWR('A', 11, struct snd_size) /* sets blocksize */ /* * The following constants define supported audio formats. The * encoding follows voxware conventions, i.e. 1 bit for each supported * format. We extend it by using bit 31 (RO) to indicate full-duplex * capability, and bit 29 (RO) to indicate that the card supports/ * needs different formats on capture & playback channels. * Bit 29 (RW) is used to indicate/ask stereo. * * The number of bits required to store the sample is: * o 4 bits for the IDA ADPCM format, * o 8 bits for 8-bit formats, mu-law and A-law, * o 16 bits for the 16-bit formats, and * o 32 bits for the 24/32-bit formats. * o undefined for the MPEG audio format. */ #define AFMT_QUERY 0x00000000 /* Return current format */ #define AFMT_MU_LAW 0x00000001 /* Logarithmic mu-law */ #define AFMT_A_LAW 0x00000002 /* Logarithmic A-law */ #define AFMT_IMA_ADPCM 0x00000004 /* A 4:1 compressed format where 16-bit * squence represented using the * the average 4 bits per sample */ #define AFMT_U8 0x00000008 /* Unsigned 8-bit */ #define AFMT_S16_LE 0x00000010 /* Little endian signed 16-bit */ #define AFMT_S16_BE 0x00000020 /* Big endian signed 16-bit */ #define AFMT_S8 0x00000040 /* Signed 8-bit */ #define AFMT_U16_LE 0x00000080 /* Little endian unsigned 16-bit */ #define AFMT_U16_BE 0x00000100 /* Big endian unsigned 16-bit */ #define AFMT_MPEG 0x00000200 /* MPEG MP2/MP3 audio */ #define AFMT_AC3 0x00000400 /* Dolby Digital AC3 */ #if _BYTE_ORDER == _LITTLE_ENDIAN #define AFMT_S16_NE AFMT_S16_LE /* native endian signed 16 */ #else #define AFMT_S16_NE AFMT_S16_BE #endif /* * 32-bit formats below used for 24-bit audio data where the data is stored * in the 24 most significant bits and the least significant bits are not used * (should be set to 0). */ #define AFMT_S32_LE 0x00001000 /* Little endian signed 32-bit */ #define AFMT_S32_BE 0x00002000 /* Big endian signed 32-bit */ #define AFMT_U32_LE 0x00004000 /* Little endian unsigned 32-bit */ #define AFMT_U32_BE 0x00008000 /* Big endian unsigned 32-bit */ #define AFMT_S24_LE 0x00010000 /* Little endian signed 24-bit */ #define AFMT_S24_BE 0x00020000 /* Big endian signed 24-bit */ #define AFMT_U24_LE 0x00040000 /* Little endian unsigned 24-bit */ #define AFMT_U24_BE 0x00080000 /* Big endian unsigned 24-bit */ #define AFMT_STEREO 0x10000000 /* can do/want stereo */ /* * the following are really capabilities */ #define AFMT_WEIRD 0x20000000 /* weird hardware... */ /* * AFMT_WEIRD reports that the hardware might need to operate * with different formats in the playback and capture * channels when operating in full duplex. * As an example, SoundBlaster16 cards only support U8 in one * direction and S16 in the other one, and applications should * be aware of this limitation. */ #define AFMT_FULLDUPLEX 0x80000000 /* can do full duplex */ /* * The following structure is used to get/set format and sampling rate. * While it would be better to have things such as stereo, bits per * sample, endiannes, etc split in different variables, it turns out * that formats are not that many, and not all combinations are possible. * So we followed the Voxware approach of associating one bit to each * format. */ typedef struct _snd_chan_param { u_long play_rate; /* sampling rate */ u_long rec_rate; /* sampling rate */ u_long play_format; /* everything describing the format */ u_long rec_format; /* everything describing the format */ } snd_chan_param; #define AIOGFMT _IOR('f', 12, snd_chan_param) /* get format */ #define AIOSFMT _IOWR('f', 12, snd_chan_param) /* sets format */ /* * The following structure is used to get/set the mixer setting. * Up to 32 mixers are supported, each one with up to 32 channels. */ typedef struct _snd_mix_param { u_char subdev; /* which output */ u_char line; /* which input */ u_char left,right; /* volumes, 0..255, 0 = mute */ } snd_mix_param ; /* XXX AIOGMIX, AIOSMIX not implemented yet */ #define AIOGMIX _IOWR('A', 13, snd_mix_param) /* return mixer status */ #define AIOSMIX _IOWR('A', 14, snd_mix_param) /* sets mixer status */ /* * channel specifiers used in AIOSTOP and AIOSYNC */ #define AIOSYNC_PLAY 0x1 /* play chan */ #define AIOSYNC_CAPTURE 0x2 /* capture chan */ /* AIOSTOP stop & flush a channel, returns the residual count */ #define AIOSTOP _IOWR ('A', 15, int) /* alternate method used to notify the sync condition */ #define AIOSYNC_SIGNAL 0x100 #define AIOSYNC_SELECT 0x200 /* what the 'pos' field refers to */ #define AIOSYNC_READY 0x400 #define AIOSYNC_FREE 0x800 typedef struct _snd_sync_parm { long chan ; /* play or capture channel, plus modifier */ long pos; } snd_sync_parm; #define AIOSYNC _IOWR ('A', 15, snd_sync_parm) /* misc. synchronization */ /* * The following is used to return device capabilities. If the structure * passed to the ioctl is zeroed, default values are returned for rate * and formats, a bitmap of available mixers is returned, and values * (inputs, different levels) for the first one are returned. * * If formats, mixers, inputs are instantiated, then detailed info * are returned depending on the call. */ typedef struct _snd_capabilities { u_long rate_min, rate_max; /* min-max sampling rate */ u_long formats; u_long bufsize; /* DMA buffer size */ u_long mixers; /* bitmap of available mixers */ u_long inputs; /* bitmap of available inputs (per mixer) */ u_short left, right; /* how many levels are supported */ } snd_capabilities; #define AIOGCAP _IOWR('A', 15, snd_capabilities) /* get capabilities */ /* * here is the old (Voxware) ioctl interface */ /* * IOCTL Commands for /dev/sequencer */ #define SNDCTL_SEQ_RESET _IO ('Q', 0) #define SNDCTL_SEQ_SYNC _IO ('Q', 1) #define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info) #define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer res.(hz) */ #define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int) #define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int) #define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int) #define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */ #define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int) #define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int) #define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int) #define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int) #define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info) #define SNDCTL_SEQ_THRESHOLD _IOW ('Q',13, int) #define SNDCTL_SEQ_TRESHOLD SNDCTL_SEQ_THRESHOLD /* there was once a typo */ #define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */ #define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */ #define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info) #define SNDCTL_SEQ_PANIC _IO ('Q',17) #define SNDCTL_SEQ_OUTOFBAND _IOW ('Q',18, struct seq_event_rec) #define SNDCTL_SEQ_GETTIME _IOR ('Q',19, int) struct seq_event_rec { u_char arr[8]; }; #define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int) #define SNDCTL_TMR_START _IO ('T', 2) #define SNDCTL_TMR_STOP _IO ('T', 3) #define SNDCTL_TMR_CONTINUE _IO ('T', 4) #define SNDCTL_TMR_TEMPO _IOWR('T', 5, int) #define SNDCTL_TMR_SOURCE _IOWR('T', 6, int) # define TMR_INTERNAL 0x00000001 # define TMR_EXTERNAL 0x00000002 # define TMR_MODE_MIDI 0x00000010 # define TMR_MODE_FSK 0x00000020 # define TMR_MODE_CLS 0x00000040 # define TMR_MODE_SMPTE 0x00000080 #define SNDCTL_TMR_METRONOME _IOW ('T', 7, int) #define SNDCTL_TMR_SELECT _IOW ('T', 8, int) /* * Endian aware patch key generation algorithm. */ #if defined(_AIX) || defined(AIX) # define _PATCHKEY(id) (0xfd00|id) #else # define _PATCHKEY(id) ((id<<8)|0xfd) #endif /* * Sample loading mechanism for internal synthesizers (/dev/sequencer) * The following patch_info structure has been designed to support * Gravis UltraSound. It tries to be universal format for uploading * sample based patches but is probably too limited. */ struct patch_info { /* u_short key; Use GUS_PATCH here */ short key; /* Use GUS_PATCH here */ #define GUS_PATCH _PATCHKEY(0x04) #define OBSOLETE_GUS_PATCH _PATCHKEY(0x02) short device_no; /* Synthesizer number */ short instr_no; /* Midi pgm# */ u_long mode; /* * The least significant byte has the same format than the GUS .PAT * files */ #define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */ #define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */ #define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */ #define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */ #define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */ #define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/ #define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */ /* (use the env_rate/env_offs fields). */ /* Linux specific bits */ #define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ #define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ #define WAVE_SCALE 0x00040000 /* The scaling info is valid */ /* Other bits must be zeroed */ long len; /* Size of the wave data in bytes */ long loop_start, loop_end; /* Byte offsets from the beginning */ /* * The base_freq and base_note fields are used when computing the * playback speed for a note. The base_note defines the tone frequency * which is heard if the sample is played using the base_freq as the * playback speed. * * The low_note and high_note fields define the minimum and maximum note * frequencies for which this sample is valid. It is possible to define * more than one samples for an instrument number at the same time. The * low_note and high_note fields are used to select the most suitable one. * * The fields base_note, high_note and low_note should contain * the note frequency multiplied by 1000. For example value for the * middle A is 440*1000. */ u_int base_freq; u_long base_note; u_long high_note; u_long low_note; int panning; /* -128=left, 127=right */ int detuning; /* New fields introduced in version 1.99.5 */ /* Envelope. Enabled by mode bit WAVE_ENVELOPES */ u_char env_rate[ 6 ]; /* GUS HW ramping rate */ u_char env_offset[ 6 ]; /* 255 == 100% */ /* * The tremolo, vibrato and scale info are not supported yet. * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or * WAVE_SCALE */ u_char tremolo_sweep; u_char tremolo_rate; u_char tremolo_depth; u_char vibrato_sweep; u_char vibrato_rate; u_char vibrato_depth; int scale_frequency; u_int scale_factor; /* from 0 to 2048 or 0 to 2 */ int volume; int spare[4]; char data[1]; /* The waveform data starts here */ }; struct sysex_info { short key; /* Use GUS_PATCH here */ #define SYSEX_PATCH _PATCHKEY(0x05) #define MAUI_PATCH _PATCHKEY(0x06) short device_no; /* Synthesizer number */ long len; /* Size of the sysex data in bytes */ u_char data[1]; /* Sysex data starts here */ }; /* * Patch management interface (/dev/sequencer, /dev/patmgr#) * Don't use these calls if you want to maintain compatibility with * the future versions of the driver. */ #define PS_NO_PATCHES 0 /* No patch support on device */ #define PS_MGR_NOT_OK 1 /* Plain patch support (no mgr) */ #define PS_MGR_OK 2 /* Patch manager supported */ #define PS_MANAGED 3 /* Patch manager running */ #define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info) /* * The patmgr_info is a fixed size structure which is used for two * different purposes. The intended use is for communication between * the application using /dev/sequencer and the patch manager daemon * associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)). * * This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows * a patch manager daemon to read and write device parameters. This * ioctl available through /dev/sequencer also. Avoid using it since it's * extremely hardware dependent. In addition access trough /dev/sequencer * may confuse the patch manager daemon. */ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */ u_long key; /* Don't worry. Reserved for communication between the patch manager and the driver. */ #define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */ #define PM_K_COMMAND 2 /* Request from an application */ #define PM_K_RESPONSE 3 /* From patmgr to application */ #define PM_ERROR 4 /* Error returned by the patmgr */ int device; int command; /* * Commands 0x000 to 0xfff reserved for patch manager programs */ #define PM_GET_DEVTYPE 1 /* Returns type of the patch mgr interface of dev */ #define PMTYPE_FM2 1 /* 2 OP fm */ #define PMTYPE_FM4 2 /* Mixed 4 or 2 op FM (OPL-3) */ #define PMTYPE_WAVE 3 /* Wave table synthesizer (GUS) */ #define PM_GET_NRPGM 2 /* Returns max # of midi programs in parm1 */ #define PM_GET_PGMMAP 3 /* Returns map of loaded midi programs in data8 */ #define PM_GET_PGM_PATCHES 4 /* Return list of patches of a program (parm1) */ #define PM_GET_PATCH 5 /* Return patch header of patch parm1 */ #define PM_SET_PATCH 6 /* Set patch header of patch parm1 */ #define PM_READ_PATCH 7 /* Read patch (wave) data */ #define PM_WRITE_PATCH 8 /* Write patch (wave) data */ /* * Commands 0x1000 to 0xffff are for communication between the patch manager * and the client */ #define _PM_LOAD_PATCH 0x100 /* * Commands above 0xffff reserved for device specific use */ long parm1; long parm2; long parm3; union { u_char data8[4000]; u_short data16[2000]; u_long data32[1000]; struct patch_info patch; } data; }; /* * When a patch manager daemon is present, it will be informed by the * driver when something important happens. For example when the * /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is * returned. The command field contains the event type: */ #define PM_E_OPENED 1 /* /dev/sequencer opened */ #define PM_E_CLOSED 2 /* /dev/sequencer closed */ #define PM_E_PATCH_RESET 3 /* SNDCTL_RESETSAMPLES called */ #define PM_E_PATCH_LOADED 4 /* A patch has been loaded by appl */ /* * /dev/sequencer input events. * * The data written to the /dev/sequencer is a stream of events. Events * are records of 4 or 8 bytes. The first byte defines the size. * Any number of events can be written with a write call. There * is a set of macros for sending these events. Use these macros if you * want to maximize portability of your program. * * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events. * (All input events are currently 4 bytes long. Be prepared to support * 8 byte events also. If you receive any event having first byte >= 128, * it's a 8 byte event. * * The events are documented at the end of this file. * * Normal events (4 bytes) * There is also a 8 byte version of most of the 4 byte events. The * 8 byte one is recommended. */ #define SEQ_NOTEOFF 0 #define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */ #define SEQ_NOTEON 1 #define SEQ_FMNOTEON SEQ_NOTEON #define SEQ_WAIT TMR_WAIT_ABS #define SEQ_PGMCHANGE 3 #define SEQ_FMPGMCHANGE SEQ_PGMCHANGE #define SEQ_SYNCTIMER TMR_START #define SEQ_MIDIPUTC 5 #define SEQ_DRUMON 6 /*** OBSOLETE ***/ #define SEQ_DRUMOFF 7 /*** OBSOLETE ***/ #define SEQ_ECHO TMR_ECHO /* For synching programs with output */ #define SEQ_AFTERTOUCH 9 #define SEQ_CONTROLLER 10 /* * Midi controller numbers * * Controllers 0 to 31 (0x00 to 0x1f) and 32 to 63 (0x20 to 0x3f) * are continuous controllers. * In the MIDI 1.0 these controllers are sent using two messages. * Controller numbers 0 to 31 are used to send the MSB and the * controller numbers 32 to 63 are for the LSB. Note that just 7 bits * are used in MIDI bytes. */ #define CTL_BANK_SELECT 0x00 #define CTL_MODWHEEL 0x01 #define CTL_BREATH 0x02 /* undefined 0x03 */ #define CTL_FOOT 0x04 #define CTL_PORTAMENTO_TIME 0x05 #define CTL_DATA_ENTRY 0x06 #define CTL_MAIN_VOLUME 0x07 #define CTL_BALANCE 0x08 /* undefined 0x09 */ #define CTL_PAN 0x0a #define CTL_EXPRESSION 0x0b /* undefined 0x0c - 0x0f */ #define CTL_GENERAL_PURPOSE1 0x10 #define CTL_GENERAL_PURPOSE2 0x11 #define CTL_GENERAL_PURPOSE3 0x12 #define CTL_GENERAL_PURPOSE4 0x13 /* undefined 0x14 - 0x1f */ /* undefined 0x20 */ /* * The controller numbers 0x21 to 0x3f are reserved for the * least significant bytes of the controllers 0x00 to 0x1f. * These controllers are not recognised by the driver. * * Controllers 64 to 69 (0x40 to 0x45) are on/off switches. * 0=OFF and 127=ON (intermediate values are possible) */ #define CTL_DAMPER_PEDAL 0x40 #define CTL_SUSTAIN CTL_DAMPER_PEDAL /* Alias */ #define CTL_HOLD CTL_DAMPER_PEDAL /* Alias */ #define CTL_PORTAMENTO 0x41 #define CTL_SOSTENUTO 0x42 #define CTL_SOFT_PEDAL 0x43 /* undefined 0x44 */ #define CTL_HOLD2 0x45 /* undefined 0x46 - 0x4f */ #define CTL_GENERAL_PURPOSE5 0x50 #define CTL_GENERAL_PURPOSE6 0x51 #define CTL_GENERAL_PURPOSE7 0x52 #define CTL_GENERAL_PURPOSE8 0x53 /* undefined 0x54 - 0x5a */ #define CTL_EXT_EFF_DEPTH 0x5b #define CTL_TREMOLO_DEPTH 0x5c #define CTL_CHORUS_DEPTH 0x5d #define CTL_DETUNE_DEPTH 0x5e #define CTL_CELESTE_DEPTH CTL_DETUNE_DEPTH /* Alias for the above one */ #define CTL_PHASER_DEPTH 0x5f #define CTL_DATA_INCREMENT 0x60 #define CTL_DATA_DECREMENT 0x61 #define CTL_NONREG_PARM_NUM_LSB 0x62 #define CTL_NONREG_PARM_NUM_MSB 0x63 #define CTL_REGIST_PARM_NUM_LSB 0x64 #define CTL_REGIST_PARM_NUM_MSB 0x65 /* undefined 0x66 - 0x78 */ /* reserved 0x79 - 0x7f */ /* Pseudo controllers (not midi compatible) */ #define CTRL_PITCH_BENDER 255 #define CTRL_PITCH_BENDER_RANGE 254 #define CTRL_EXPRESSION 253 /* Obsolete */ #define CTRL_MAIN_VOLUME 252 /* Obsolete */ #define SEQ_BALANCE 11 #define SEQ_VOLMODE 12 /* * Volume mode decides how volumes are used */ #define VOL_METHOD_ADAGIO 1 #define VOL_METHOD_LINEAR 2 /* * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as * input events. */ /* * Event codes 0xf0 to 0xfc are reserved for future extensions. */ #define SEQ_FULLSIZE 0xfd /* Long events */ /* * SEQ_FULLSIZE events are used for loading patches/samples to the * synthesizer devices. These events are passed directly to the driver * of the associated synthesizer device. There is no limit to the size * of the extended events. These events are not queued but executed * immediately when the write() is called (execution can take several * seconds of time). * * When a SEQ_FULLSIZE message is written to the device, it must * be written using exactly one write() call. Other events cannot * be mixed to the same write. * * For FM synths (YM3812/OPL3) use struct sbi_instrument and write * it to the /dev/sequencer. Don't write other data together with * the instrument structure Set the key field of the structure to * FM_PATCH. The device field is used to route the patch to the * corresponding device. * * For Gravis UltraSound use struct patch_info. Initialize the key field * to GUS_PATCH. */ #define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */ #define SEQ_EXTENDED 0xff /* Extended events (8 bytes) OBSOLETE */ /* * Record for FM patches */ typedef u_char sbi_instr_data[32]; struct sbi_instrument { u_short key; /* FM_PATCH or OPL3_PATCH */ #define FM_PATCH _PATCHKEY(0x01) #define OPL3_PATCH _PATCHKEY(0x03) short device; /* Synth# (0-4) */ int channel; /* Program# to be initialized */ sbi_instr_data operators; /* Reg. settings for operator cells * (.SBI format) */ }; struct synth_info { /* Read only */ char name[30]; int device; /* 0-N. INITIALIZE BEFORE CALLING */ int synth_type; #define SYNTH_TYPE_FM 0 #define SYNTH_TYPE_SAMPLE 1 #define SYNTH_TYPE_MIDI 2 /* Midi interface */ int synth_subtype; #define FM_TYPE_ADLIB 0x00 #define FM_TYPE_OPL3 0x01 #define MIDI_TYPE_MPU401 0x401 #define SAMPLE_TYPE_BASIC 0x10 #define SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC #define SAMPLE_TYPE_AWE32 0x20 int perc_mode; /* No longer supported */ int nr_voices; int nr_drums; /* Obsolete field */ int instr_bank_size; u_long capabilities; #define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */ #define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */ #define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */ int dummies[19]; /* Reserve space */ }; struct sound_timer_info { char name[32]; int caps; }; struct midi_info { char name[30]; int device; /* 0-N. INITIALIZE BEFORE CALLING */ u_long capabilities; /* To be defined later */ int dev_type; int dummies[18]; /* Reserve space */ }; /* * ioctl commands for the /dev/midi## */ typedef struct { u_char cmd; char nr_args, nr_returns; u_char data[30]; } mpu_command_rec; #define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int) #define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int) #define SNDCTL_MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec) #define MIOSPASSTHRU _IOWR('m', 3, int) #define MIOGPASSTHRU _IOWR('m', 4, int) /* * IOCTL commands for /dev/dsp and /dev/audio */ #define SNDCTL_DSP_RESET _IO ('P', 0) #define SNDCTL_DSP_SYNC _IO ('P', 1) #define SNDCTL_DSP_SPEED _IOWR('P', 2, int) #define SNDCTL_DSP_STEREO _IOWR('P', 3, int) #define SNDCTL_DSP_GETBLKSIZE _IOR('P', 4, int) #define SNDCTL_DSP_SETBLKSIZE _IOW('P', 4, int) #define SNDCTL_DSP_SETFMT _IOWR('P',5, int) /* Selects ONE fmt*/ /* * SOUND_PCM_WRITE_CHANNELS is not that different * from SNDCTL_DSP_STEREO */ #define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int) #define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS #define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int) #define SNDCTL_DSP_POST _IO ('P', 8) /* * SNDCTL_DSP_SETBLKSIZE and the following two calls mostly do * the same thing, i.e. set the block size used in DMA transfers. */ #define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int) #define SNDCTL_DSP_SETFRAGMENT _IOWR('P',10, int) #define SNDCTL_DSP_GETFMTS _IOR ('P',11, int) /* Returns a mask */ /* * Buffer status queries. */ typedef struct audio_buf_info { int fragments; /* # of avail. frags (partly used ones not counted) */ int fragstotal; /* Total # of fragments allocated */ int fragsize; /* Size of a fragment in bytes */ int bytes; /* Avail. space in bytes (includes partly used fragments) */ /* Note! 'bytes' could be more than fragments*fragsize */ } audio_buf_info; #define SNDCTL_DSP_GETOSPACE _IOR ('P',12, audio_buf_info) #define SNDCTL_DSP_GETISPACE _IOR ('P',13, audio_buf_info) /* * SNDCTL_DSP_NONBLOCK is the same (but less powerful, since the * action cannot be undone) of FIONBIO. The same can be achieved * by opening the device with O_NDELAY */ #define SNDCTL_DSP_NONBLOCK _IO ('P',14) #define SNDCTL_DSP_GETCAPS _IOR ('P',15, int) #define DSP_CAP_REVISION 0x000000ff /* revision level (0 to 255) */ #define DSP_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */ #define DSP_CAP_REALTIME 0x00000200 /* Real time capability */ #define DSP_CAP_BATCH 0x00000400 /* * Device has some kind of internal buffers which may * cause some delays and decrease precision of timing */ #define DSP_CAP_COPROC 0x00000800 /* Has a coprocessor, sometimes it's a DSP but usually not */ #define DSP_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */ #define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */ /* * What do these function do ? */ #define SNDCTL_DSP_GETTRIGGER _IOR ('P',16, int) #define SNDCTL_DSP_SETTRIGGER _IOW ('P',16, int) #define PCM_ENABLE_INPUT 0x00000001 #define PCM_ENABLE_OUTPUT 0x00000002 typedef struct count_info { int bytes; /* Total # of bytes processed */ int blocks; /* # of fragment transitions since last time */ int ptr; /* Current DMA pointer value */ } count_info; /* * GETIPTR and GETISPACE are not that different... same for out. */ #define SNDCTL_DSP_GETIPTR _IOR ('P',17, count_info) #define SNDCTL_DSP_GETOPTR _IOR ('P',18, count_info) typedef struct buffmem_desc { caddr_t buffer; int size; } buffmem_desc; #define SNDCTL_DSP_MAPINBUF _IOR ('P', 19, buffmem_desc) #define SNDCTL_DSP_MAPOUTBUF _IOR ('P', 20, buffmem_desc) #define SNDCTL_DSP_SETSYNCRO _IO ('P', 21) #define SNDCTL_DSP_SETDUPLEX _IO ('P', 22) #define SNDCTL_DSP_GETODELAY _IOR ('P', 23, int) /* * I guess these are the readonly version of the same * functions that exist above as SNDCTL_DSP_... */ #define SOUND_PCM_READ_RATE _IOR ('P', 2, int) #define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int) #define SOUND_PCM_READ_BITS _IOR ('P', 5, int) #define SOUND_PCM_READ_FILTER _IOR ('P', 7, int) /* * ioctl calls to be used in communication with coprocessors and * DSP chips. */ typedef struct copr_buffer { int command; /* Set to 0 if not used */ int flags; #define CPF_NONE 0x0000 #define CPF_FIRST 0x0001 /* First block */ #define CPF_LAST 0x0002 /* Last block */ int len; int offs; /* If required by the device (0 if not used) */ u_char data[4000]; /* NOTE! 4000 is not 4k */ } copr_buffer; typedef struct copr_debug_buf { int command; /* Used internally. Set to 0 */ int parm1; int parm2; int flags; int len; /* Length of data in bytes */ } copr_debug_buf; typedef struct copr_msg { int len; u_char data[4000]; } copr_msg; #define SNDCTL_COPR_RESET _IO ('C', 0) #define SNDCTL_COPR_LOAD _IOWR('C', 1, copr_buffer) #define SNDCTL_COPR_RDATA _IOWR('C', 2, copr_debug_buf) #define SNDCTL_COPR_RCODE _IOWR('C', 3, copr_debug_buf) #define SNDCTL_COPR_WDATA _IOW ('C', 4, copr_debug_buf) #define SNDCTL_COPR_WCODE _IOW ('C', 5, copr_debug_buf) #define SNDCTL_COPR_RUN _IOWR('C', 6, copr_debug_buf) #define SNDCTL_COPR_HALT _IOWR('C', 7, copr_debug_buf) #define SNDCTL_COPR_SENDMSG _IOW ('C', 8, copr_msg) #define SNDCTL_COPR_RCVMSG _IOR ('C', 9, copr_msg) /* * IOCTL commands for /dev/mixer */ /* * Mixer devices * * There can be up to 20 different analog mixer channels. The * SOUND_MIXER_NRDEVICES gives the currently supported maximum. * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells * the devices supported by the particular mixer. */ #define SOUND_MIXER_NRDEVICES 25 #define SOUND_MIXER_VOLUME 0 /* Master output level */ #define SOUND_MIXER_BASS 1 /* Treble level of all output channels */ #define SOUND_MIXER_TREBLE 2 /* Bass level of all output channels */ #define SOUND_MIXER_SYNTH 3 /* Volume of synthesier input */ #define SOUND_MIXER_PCM 4 /* Output level for the audio device */ #define SOUND_MIXER_SPEAKER 5 /* Output level for the PC speaker * signals */ #define SOUND_MIXER_LINE 6 /* Volume level for the line in jack */ #define SOUND_MIXER_MIC 7 /* Volume for the signal coming from * the microphone jack */ #define SOUND_MIXER_CD 8 /* Volume level for the input signal * connected to the CD audio input */ #define SOUND_MIXER_IMIX 9 /* Recording monitor. It controls the * output volume of the selected * recording sources while recording */ #define SOUND_MIXER_ALTPCM 10 /* Volume of the alternative codec * device */ #define SOUND_MIXER_RECLEV 11 /* Global recording level */ #define SOUND_MIXER_IGAIN 12 /* Input gain */ #define SOUND_MIXER_OGAIN 13 /* Output gain */ /* * The AD1848 codec and compatibles have three line level inputs * (line, aux1 and aux2). Since each card manufacturer have assigned * different meanings to these inputs, it's inpractical to assign * specific meanings (line, cd, synth etc.) to them. */ #define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ #define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */ #define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */ #define SOUND_MIXER_DIGITAL1 17 /* Digital (input) 1 */ #define SOUND_MIXER_DIGITAL2 18 /* Digital (input) 2 */ #define SOUND_MIXER_DIGITAL3 19 /* Digital (input) 3 */ #define SOUND_MIXER_PHONEIN 20 /* Phone input */ #define SOUND_MIXER_PHONEOUT 21 /* Phone output */ #define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */ #define SOUND_MIXER_RADIO 23 /* Radio in */ #define SOUND_MIXER_MONITOR 24 /* Monitor (usually mic) volume */ /* * Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) * Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */ #define SOUND_ONOFF_MIN 28 #define SOUND_ONOFF_MAX 30 #define SOUND_MIXER_MUTE 28 /* 0 or 1 */ #define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ #define SOUND_MIXER_LOUD 30 /* 0 or 1 */ /* Note! Number 31 cannot be used since the sign bit is reserved */ #define SOUND_MIXER_NONE 31 #define SOUND_DEVICE_LABELS { \ "Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \ "Line1", "Line2", "Line3", "Digital1", "Digital2", "Digital3", \ "PhoneIn", "PhoneOut", "Video", "Radio", "Monitor"} #define SOUND_DEVICE_NAMES { \ "vol", "bass", "treble", "synth", "pcm", "speaker", "line", \ "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \ "line1", "line2", "line3", "dig1", "dig2", "dig3", \ "phin", "phout", "video", "radio", "monitor"} /* Device bitmask identifiers */ #define SOUND_MIXER_RECSRC 0xff /* 1 bit per recording source */ #define SOUND_MIXER_DEVMASK 0xfe /* 1 bit per supported device */ #define SOUND_MIXER_RECMASK 0xfd /* 1 bit per supp. recording source */ #define SOUND_MIXER_CAPS 0xfc #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only 1 rec. src at a time */ #define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */ /* Device mask bits */ #define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME) #define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS) #define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE) #define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH) #define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM) #define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER) #define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE) #define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC) #define SOUND_MASK_CD (1 << SOUND_MIXER_CD) #define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX) #define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM) #define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV) #define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN) #define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN) #define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1) #define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) #define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) #define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1) #define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2) #define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3) #define SOUND_MASK_PHONEIN (1 << SOUND_MIXER_PHONEIN) #define SOUND_MASK_PHONEOUT (1 << SOUND_MIXER_PHONEOUT) #define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO) #define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO) #define SOUND_MASK_MONITOR (1 << SOUND_MIXER_MONITOR) /* Obsolete macros */ #define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) #define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) #define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) #define MIXER_READ(dev) _IOR('M', dev, int) #define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) #define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS) #define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE) #define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH) #define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM) #define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER) #define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE) #define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC) #define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD) #define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX) #define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM) #define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV) #define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN) #define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN) #define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) #define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) #define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) #define SOUND_MIXER_READ_DIGITAL1 MIXER_READ(SOUND_MIXER_DIGITAL1) #define SOUND_MIXER_READ_DIGITAL2 MIXER_READ(SOUND_MIXER_DIGITAL2) #define SOUND_MIXER_READ_DIGITAL3 MIXER_READ(SOUND_MIXER_DIGITAL3) #define SOUND_MIXER_READ_PHONEIN MIXER_READ(SOUND_MIXER_PHONEIN) #define SOUND_MIXER_READ_PHONEOUT MIXER_READ(SOUND_MIXER_PHONEOUT) #define SOUND_MIXER_READ_RADIO MIXER_READ(SOUND_MIXER_RADIO) #define SOUND_MIXER_READ_VIDEO MIXER_READ(SOUND_MIXER_VIDEO) #define SOUND_MIXER_READ_MONITOR MIXER_READ(SOUND_MIXER_MONITOR) /* Obsolete macros */ #define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) #define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) #define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) #define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) #define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK) #define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS) #define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS) #define MIXER_WRITE(dev) _IOWR('M', dev, int) #define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME) #define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS) #define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE) #define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH) #define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM) #define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER) #define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE) #define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC) #define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD) #define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX) #define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM) #define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV) #define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN) #define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN) #define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) #define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) #define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) #define SOUND_MIXER_WRITE_DIGITAL1 MIXER_WRITE(SOUND_MIXER_DIGITAL1) #define SOUND_MIXER_WRITE_DIGITAL2 MIXER_WRITE(SOUND_MIXER_DIGITAL2) #define SOUND_MIXER_WRITE_DIGITAL3 MIXER_WRITE(SOUND_MIXER_DIGITAL3) #define SOUND_MIXER_WRITE_PHONEIN MIXER_WRITE(SOUND_MIXER_PHONEIN) #define SOUND_MIXER_WRITE_PHONEOUT MIXER_WRITE(SOUND_MIXER_PHONEOUT) #define SOUND_MIXER_WRITE_RADIO MIXER_WRITE(SOUND_MIXER_RADIO) #define SOUND_MIXER_WRITE_VIDEO MIXER_WRITE(SOUND_MIXER_VIDEO) #define SOUND_MIXER_WRITE_MONITOR MIXER_WRITE(SOUND_MIXER_MONITOR) #define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) #define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) typedef struct mixer_info { char id[16]; char name[32]; int modify_counter; int fillers[10]; } mixer_info; #define SOUND_MIXER_INFO _IOR('M', 101, mixer_info) #define LEFT_CHN 0 #define RIGHT_CHN 1 /* * Level 2 event types for /dev/sequencer */ /* * The 4 most significant bits of byte 0 specify the class of * the event: * * 0x8X = system level events, * 0x9X = device/port specific events, event[1] = device/port, * The last 4 bits give the subtype: * 0x02 = Channel event (event[3] = chn). * 0x01 = note event (event[4] = note). * (0x01 is not used alone but always with bit 0x02). * event[2] = MIDI message code (0x80=note off etc.) * */ #define EV_SEQ_LOCAL 0x80 #define EV_TIMING 0x81 #define EV_CHN_COMMON 0x92 #define EV_CHN_VOICE 0x93 #define EV_SYSEX 0x94 /* * Event types 200 to 220 are reserved for application use. * These numbers will not be used by the driver. */ /* * Events for event type EV_CHN_VOICE */ #define MIDI_NOTEOFF 0x80 #define MIDI_NOTEON 0x90 #define MIDI_KEY_PRESSURE 0xA0 /* * Events for event type EV_CHN_COMMON */ #define MIDI_CTL_CHANGE 0xB0 #define MIDI_PGM_CHANGE 0xC0 #define MIDI_CHN_PRESSURE 0xD0 #define MIDI_PITCH_BEND 0xE0 #define MIDI_SYSTEM_PREFIX 0xF0 /* * Timer event types */ #define TMR_WAIT_REL 1 /* Time relative to the prev time */ #define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */ #define TMR_STOP 3 #define TMR_START 4 #define TMR_CONTINUE 5 #define TMR_TEMPO 6 #define TMR_ECHO 8 #define TMR_CLOCK 9 /* MIDI clock */ #define TMR_SPP 10 /* Song position pointer */ #define TMR_TIMESIG 11 /* Time signature */ /* * Local event types */ #define LOCL_STARTAUDIO 1 #if (!defined(_KERNEL) && !defined(INKERNEL)) || defined(USE_SEQ_MACROS) /* * Some convenience macros to simplify programming of the * /dev/sequencer interface * * These macros define the API which should be used when possible. */ #ifndef USE_SIMPLE_MACROS void seqbuf_dump(void); /* This function must be provided by programs */ /* Sample seqbuf_dump() implementation: * * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes * * int seqfd; -- The file descriptor for /dev/sequencer. * * void * seqbuf_dump () * { * if (_seqbufptr) * if (write (seqfd, _seqbuf, _seqbufptr) == -1) * { * perror ("write /dev/sequencer"); * exit (-1); * } * _seqbufptr = 0; * } */ #define SEQ_DEFINEBUF(len) \ u_char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0 #define SEQ_USE_EXTBUF() \ extern u_char _seqbuf[]; \ extern int _seqbuflen;extern int _seqbufptr #define SEQ_DECLAREBUF() SEQ_USE_EXTBUF() #define SEQ_PM_DEFINES struct patmgr_info _pm_info #define _SEQ_NEEDBUF(len) \ if ((_seqbufptr+(len)) > _seqbuflen) \ seqbuf_dump() #define _SEQ_ADVBUF(len) _seqbufptr += len #define SEQ_DUMPBUF seqbuf_dump #else /* * This variation of the sequencer macros is used just to format one event * using fixed buffer. * * The program using the macro library must define the following macros before * using this library. * * #define _seqbuf name of the buffer (u_char[]) * #define _SEQ_ADVBUF(len) If the applic needs to know the exact * size of the event, this macro can be used. * Otherwise this must be defined as empty. * #define _seqbufptr Define the name of index variable or 0 if * not required. */ #define _SEQ_NEEDBUF(len) /* empty */ #endif #define PM_LOAD_PATCH(dev, bank, pgm) \ (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \ _pm_info.parm1 = bank, _pm_info.parm2 = 1, \ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info)) #define PM_LOAD_PATCHES(dev, bank, pgm) \ (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ _pm_info.device=dev, bcopy( pgm, _pm_info.data.data8, 128), \ _pm_info.parm1 = bank, _pm_info.parm2 = 128, \ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info)) #define SEQ_VOLUME_MODE(dev, mode) { \ _SEQ_NEEDBUF(8);\ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\ _seqbuf[_seqbufptr+2] = (dev);\ _seqbuf[_seqbufptr+3] = (mode);\ _seqbuf[_seqbufptr+4] = 0;\ _seqbuf[_seqbufptr+5] = 0;\ _seqbuf[_seqbufptr+6] = 0;\ _seqbuf[_seqbufptr+7] = 0;\ _SEQ_ADVBUF(8);} /* * Midi voice messages */ #define _CHN_VOICE(dev, event, chn, note, parm) { \ _SEQ_NEEDBUF(8);\ _seqbuf[_seqbufptr] = EV_CHN_VOICE;\ _seqbuf[_seqbufptr+1] = (dev);\ _seqbuf[_seqbufptr+2] = (event);\ _seqbuf[_seqbufptr+3] = (chn);\ _seqbuf[_seqbufptr+4] = (note);\ _seqbuf[_seqbufptr+5] = (parm);\ _seqbuf[_seqbufptr+6] = (0);\ _seqbuf[_seqbufptr+7] = 0;\ _SEQ_ADVBUF(8);} #define SEQ_START_NOTE(dev, chn, note, vol) \ _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol) #define SEQ_STOP_NOTE(dev, chn, note, vol) \ _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol) #define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \ _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure) /* * Midi channel messages */ #define _CHN_COMMON(dev, event, chn, p1, p2, w14) { \ _SEQ_NEEDBUF(8);\ _seqbuf[_seqbufptr] = EV_CHN_COMMON;\ _seqbuf[_seqbufptr+1] = (dev);\ _seqbuf[_seqbufptr+2] = (event);\ _seqbuf[_seqbufptr+3] = (chn);\ _seqbuf[_seqbufptr+4] = (p1);\ _seqbuf[_seqbufptr+5] = (p2);\ *(short *)&_seqbuf[_seqbufptr+6] = (w14);\ _SEQ_ADVBUF(8);} /* * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits * sending any MIDI bytes but it's absolutely not possible. Trying to do * so _will_ cause problems with MPU401 intelligent mode). * * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be * sent by calling SEQ_SYSEX() several times (there must be no other events * between them). First sysex fragment must have 0xf0 in the first byte * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte * between these sysex start and end markers cannot be larger than 0x7f. Also * lengths of each fragments (except the last one) must be 6. * * Breaking the above rules may work with some MIDI ports but is likely to * cause fatal problems with some other devices (such as MPU401). */ #define SEQ_SYSEX(dev, buf, len) { \ int i, l=(len); if (l>6)l=6;\ _SEQ_NEEDBUF(8);\ _seqbuf[_seqbufptr] = EV_SYSEX;\ for(i=0;i:50+%   <„ÈìýÿÿÿÿÿñË£zXWUROKFA<70+%  HÍÿÿÿÿÿÿÿþüÿÿÿÿÿåœWJGC?;61+&! •ýÿÿÿÿÿôœP69d‘¼÷ÿÿÿ÷•60-*&# fÿÿÿÿÿÿÑ,AÒÿÿÿÿÓE ÿÿÿÿÿÿÒÿÿÿÿÿù+ ‹üÿÿÿöT ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³ ÿ ÿ ÿ ÿ ÿŠ_ ÿ ÿ ÿ ÿ û]ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!Ï ÿ ÿ ÿ¸¤ ÿ ÿ ÿ ÿ ù,ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ*m>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ àÿÿÿÿ Éÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=ÿÿÿÿÿUÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÍÿÿÿÿ ³ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{ÿÿÿÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ)ÿÿÿÿÿ^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ| ®´ Žh0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×ÿÿÿÿ —ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿ ÿ ÿ ÿ ÿÿ»Aÿÿÿÿÿÿÿÿÿÿÿÿ Š ÿ ÿ!!!ÿ!!!ÿÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ1Ø"""ÿ"""ÿ"""ÿ"""ÿ"""ÿ"""ÿ!!!þ###ÿ###ÿ###ÿ"""ÿ¼ÿÿÿÿÿÿX###ÿ###ÿ###ÿ###ÿ"""ü ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ3"""ù%%%ÿ%%%ÿ%%%ÿ%%%ÿÍT 8mÝ%%%ÿ%%%ÿÞ+ÿÿÿ)&&&ÿ&&&ÿ&&&ÿ&&&ÿ&&&ÿ<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÃ'''ÿ'''ÿ'''ÿ(((ÿ« ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿj"""î(((ÿ###ñ?&&&÷)))ÿ)))ÿ)))ÿ)))ÿkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿV***ÿ***ÿ***ÿ***ÿ%%%ðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ)!!!á+++ÿ###èÍ+++ÿ+++ÿ,,,ÿ,,,ÿšÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ###à---ÿ---ÿ---ÿ---ÿ „ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Ö...ÿ¸ ...ÿ...ÿ...ÿ...ÿÉÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"...ÿ000ÿ000ÿ000ÿ///ÿCÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(,,,õ111ÿ&&&Þ111ÿ111ÿ111ÿ111ÿ---õÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿK111ÿ222ÿ222ÿ222ÿ111ÿ#ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ i333ÿ444ÿ444ÿ444ÿ444ÿ444ÿ333ÿ&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ u555ÿ555ÿ555ÿ555ÿ444ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿666ÿ666ÿ666ÿ666ÿ777ÿ777ÿUÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿž888ÿ888ÿ888ÿ888ÿ777ÿ%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿI888ÿ999ÿ999ÿ999ÿ999ÿ999ÿ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®:::ÿ:::ÿ:::ÿ;;;ÿ;;;ÿNÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+++Ø<<<ÿ<<<ÿ<<<ÿ<<<ÿ<<<ÿ²ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—===ÿ===ÿ===ÿ===ÿ===ÿ wÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ j???ÿ???ÿ???ÿ???ÿ???ÿ111áÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ???ÿ@@@ÿ@@@ÿ@@@ÿ@@@ÿ¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 777ïAAAÿAAAÿBBBÿBBBÿAAAÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ fBBBÿCCCÿCCCÿCCCÿCCCÿ***Êÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‘CCCÿDDDÿDDDÿDDDÿCCCÿ>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ/DDDÿEEEÿEEEÿFFFÿFFFÿ>>>òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRFFFÿGGGÿGGGÿGGGÿFFFÿmÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ;;;çHHHÿHHHÿHHHÿHHHÿGGGÿ5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIIIÿJJJÿJJJÿJJJÿJJJÿœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡KKKÿKKKÿKKKÿKKKÿKKKÿ!!!©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ<<<ãLLLÿLLLÿLLLÿMMMÿ000ËÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMMMMÿNNNÿNNNÿNNNÿNNNÿKKKü!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$$$¬OOOÿOOOÿOOOÿOOOÿHHHöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333ÐPPPÿPPPÿPPPÿQQQÿPPPÿ’ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿtQQQÿRRRÿRRRÿRRRÿQQQÿ(ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ RRRRÿSSSÿSSSÿSSSÿSSSÿJJJôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=SSSÿUUUÿUUUÿUUUÿTTTÿ Wÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ555ÊVVVÿVVVÿVVVÿVVVÿUUUÿ|ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ SSSûWWWÿWWWÿWWWÿWWWÿ…ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%PPPôYYYÿYYYÿYYYÿYYYÿLLLí ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ:::ÎYYYÿYYYÿYYYÿYYYÿ,,,´ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ bXXXÿYYYÿYYYÿYYYÿYYYÿ<<<Ó ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(((«YYYÿYYYÿYYYÿYYYÿEEEãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿXXXÿYYYÿYYYÿYYYÿXXXÿ111Àÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ†XXXþYYYÿYYYÿYYYÿYYYÿXXXÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿXXXÿYYYÿYYYÿYYYÿYYYÿDDDá<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ---¹XXXÿXXXÿYYYÿYYYÿYYYÿYYYÿXXXÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿkQQQöYYYÿYYYÿYYYÿYYYÿXXXÿ222À V%) `–FFFäYYYÿVVVýsNNNðYYYÿYYYÿYYYÿXXXÿoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ#///ºXXXÿYYYÿYYYÿYYYÿYYYÿXXXÿXXXÿXXXþXXXÿXXXÿXXXÿXXXÿNNNò WÿÿÿŽXXXÿYYYÿYYYÿYYYÿ"""žÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ O+++±TTTúXXXÿXXXÿYYYÿYYYÿYYYÿXXXÿXXXÿPPPó"""Ÿÿÿÿÿÿÿ#WWWþXXXÿXXXÿXXXÿ777Ìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ c‡$$$¤000¾!!!› d-ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ7@@@:ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÀÿÿÿxÿÿÿÿÿÿþÿÿÿþÿàÿÿÿÿàÿÿÿÿð?ÿÿÿÿø?ÿÿÿÿøÿÿÿÿüÿÿÿÿüÿÿÿãüÿÿþ|ÿÿüÿÿøÿÿð?ÆÿÿðâÿÿàðÿÿàÿøÿÿàÿüÿÿàÿüÿÿÀÿþÿÿÀÿþÿÿÀÿÿÿÿàÿÿÿàÿÿÿàÿƒÿÿàÿÿÿà?ÿÿÿð?ÿÿÿðÿÁÿÿøÿÁÿÿøÿÀÿÿüÿÀÿÿþÿÀÿÿþÿ€ÿÿÿÿÿÿÿÀ| ÿÿÿà`ÿÿøðÿÿÿÿÿÿÿÿÿÿÿgiada-0.11.2/src/ext/resource.h000066400000000000000000000000251264622563000162320ustar00rootroot00000000000000#define IDI_ICON1 101giada-0.11.2/src/ext/resource.rc000066400000000000000000000000741264622563000164130ustar00rootroot00000000000000#include "resource.h" IDI_ICON1 ICON DISCARDABLE "giada.ico"giada-0.11.2/src/glue/000077500000000000000000000000001264622563000143715ustar00rootroot00000000000000giada-0.11.2/src/glue/channel.cpp000066400000000000000000000062371264622563000165150ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * glue * Intermediate layer GUI <-> CORE. * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/elems/ge_keyboard.h" #include "../gui/elems/ge_channel.h" #include "../utils/gui_utils.h" #include "../core/mixerHandler.h" #include "../core/mixer.h" #include "../core/conf.h" #include "../core/channel.h" #include "../core/sampleChannel.h" #include "../core/midiChannel.h" #include "glue.h" #include "channel.h" extern gdMainWindow *mainWin; extern Conf G_Conf; extern Mixer G_Mixer; using std::string; int glue_loadChannel(SampleChannel *ch, const char *fname) { /* save the patch and take the last browser's dir in order to re-use it * the next time */ G_Conf.samplePath = gDirname(fname); int result = ch->load(fname); if (result == SAMPLE_LOADED_OK) mainWin->keyboard->updateChannel(ch->guiChannel); return result; } /* -------------------------------------------------------------------------- */ Channel *glue_addChannel(int column, int type) { Channel *ch = G_Mixer.addChannel(type); gChannel *gch = mainWin->keyboard->addChannel(column, ch); ch->guiChannel = gch; glue_setChanVol(ch, 1.0, false); // false = not from gui click return ch; } /* -------------------------------------------------------------------------- */ void glue_deleteChannel(Channel *ch) { int index = ch->index; recorder::clearChan(index); Fl::lock(); mainWin->keyboard->deleteChannel(ch->guiChannel); Fl::unlock(); G_Mixer.deleteChannel(ch); gu_closeAllSubwindows(); } /* -------------------------------------------------------------------------- */ void glue_freeChannel(Channel *ch) { mainWin->keyboard->freeChannel(ch->guiChannel); recorder::clearChan(ch->index); ch->empty(); } /* -------------------------------------------------------------------------- */ int glue_cloneChannel(Channel *src) { Channel *ch = G_Mixer.addChannel(src->type); gChannel *gch = mainWin->keyboard->addChannel(src->guiChannel->getColumnIndex(), ch); ch->guiChannel = gch; ch->copy(src); mainWin->keyboard->updateChannel(ch->guiChannel); return true; } giada-0.11.2/src/glue/channel.h000066400000000000000000000034771264622563000161650ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * glue * Intermediate layer GUI <-> CORE. * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GLUE_CHANNEL_H #define GLUE_CHANNEL_H #include "../core/patch.h" using std::string; /* addChannel * add an empty new channel to the stack. Returns the new channel. */ class Channel *glue_addChannel(int column, int type); /* loadChannel * fill an existing channel with a wave. */ int glue_loadChannel(class SampleChannel *ch, const char *fname); /* deleteChannel * Remove a channel from Mixer. */ void glue_deleteChannel(class Channel *ch); /* freeChannel * Unload the sample from a sample channel. */ void glue_freeChannel(class Channel *ch); /* cloneChannel * Make an exact copy of Channel *ch. */ int glue_cloneChannel(class Channel *ch); #endif giada-0.11.2/src/glue/glue.cpp000066400000000000000000000522021264622563000160320ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * glue * Intermediate layer GUI <-> CORE. * * How to know if you need another glue_ function? Ask yourself if the * new action will ever be called via MIDI or keyboard/mouse. If yes, * put it here. * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../gui/elems/ge_waveform.h" #include "../gui/elems/ge_mixed.h" #include "../gui/elems/ge_channel.h" #include "../gui/elems/ge_sampleChannel.h" #include "../gui/elems/ge_waveTools.h" #include "../gui/elems/ge_keyboard.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_editor.h" #include "../gui/dialogs/gd_warnings.h" #include "../utils/gui_utils.h" #include "../utils/utils.h" #include "../utils/log.h" #include "../core/mixerHandler.h" #include "../core/mixer.h" #include "../core/recorder.h" #include "../core/wave.h" #include "../core/pluginHost.h" #include "../core/channel.h" #include "../core/sampleChannel.h" #include "../core/midiChannel.h" #include "../core/kernelMidi.h" #include "../core/patch_DEPR_.h" #include "../core/conf.h" #include "glue.h" extern gdMainWindow *mainWin; extern Mixer G_Mixer; extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; extern bool G_audio_status; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif static bool __soloSession__ = false; void glue_setBpm(const char *v1, const char *v2) { char buf[6]; float value = atof(v1) + (atof(v2)/10); if (value < 20.0f) { value = 20.0f; sprintf(buf, "20.0"); } else sprintf(buf, "%s.%s", v1, !strcmp(v2, "") ? "0" : v2); /* a value such as atof("120.1") will never be 120.1 but 120.0999999, * because of the rounding error. So we pass the real "wrong" value to * G_Mixer and we show the nice looking (but fake) one to the GUI. */ float old_bpm = G_Mixer.bpm; G_Mixer.bpm = value; G_Mixer.updateFrameBars(); /* inform recorder and actionEditor of the change */ recorder::updateBpm(old_bpm, value, G_Mixer.quanto); gu_refreshActionEditor(); mainWin->timing->setBpm(buf); gLog("[glue] Bpm changed to %s (real=%f)\n", buf, G_Mixer.bpm); } /* -------------------------------------------------------------------------- */ void glue_setBeats(int beats, int bars, bool expand) { /* temp vars to store old data (they are necessary) */ int oldvalue = G_Mixer.beats; unsigned oldfpb = G_Mixer.totalFrames; if (beats > MAX_BEATS) G_Mixer.beats = MAX_BEATS; else if (beats < 1) G_Mixer.beats = 1; else G_Mixer.beats = beats; /* update bars - bars cannot be greate than beats and must be a sub * multiple of beats. If not, approximation to the nearest (and greater) * value available. */ if (bars > G_Mixer.beats) G_Mixer.bars = G_Mixer.beats; else if (bars <= 0) G_Mixer.bars = 1; else if (beats % bars != 0) { G_Mixer.bars = bars + (beats % bars); if (beats % G_Mixer.bars != 0) // it could be an odd value, let's check it (and avoid it) G_Mixer.bars = G_Mixer.bars - (beats % G_Mixer.bars); } else G_Mixer.bars = bars; G_Mixer.updateFrameBars(); /* update recorded actions */ if (expand) { if (G_Mixer.beats > oldvalue) recorder::expand(oldfpb, G_Mixer.totalFrames); //else if (G_Mixer.beats < oldvalue) // recorder::shrink(G_Mixer.totalFrames); } mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); gu_refreshActionEditor(); // in case the action editor is open } /* -------------------------------------------------------------------------- */ void glue_startStopSeq(bool gui) { G_Mixer.running ? glue_stopSeq(gui) : glue_startSeq(gui); } /* -------------------------------------------------------------------------- */ void glue_startSeq(bool gui) { G_Mixer.running = true; if (gui) { #ifdef __linux__ kernelAudio::jackStart(); #endif } if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) { kernelMidi::send(MIDI_START, -1, -1); kernelMidi::send(MIDI_POSITION_PTR, 0, 0); } if (gui) Fl::lock(); mainWin->controller->updatePlay(1); if (gui) Fl::unlock(); } /* -------------------------------------------------------------------------- */ void glue_stopSeq(bool gui) { mh_stopSequencer(); if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) kernelMidi::send(MIDI_STOP, -1, -1); #ifdef __linux__ if (gui) kernelAudio::jackStop(); #endif /* what to do if we stop the sequencer and some action recs are active? * Deactivate the button and delete any 'rec on' status */ if (recorder::active) { recorder::active = false; if (gui) Fl::lock(); mainWin->controller->updateRecAction(0); if (gui) Fl::unlock(); } /* if input recs are active (who knows why) we must deactivate them. * One might stop the sequencer while an input rec is running. */ if (G_Mixer.chanInput != NULL) { mh_stopInputRec(); if (gui) Fl::lock(); mainWin->controller->updateRecInput(0); if (gui) Fl::unlock(); } if (gui) Fl::lock(); mainWin->controller->updatePlay(0); if (gui) Fl::unlock(); } /* -------------------------------------------------------------------------- */ void glue_rewindSeq() { mh_rewindSequencer(); if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) kernelMidi::send(MIDI_POSITION_PTR, 0, 0); } /* -------------------------------------------------------------------------- */ void glue_startStopActionRec() { recorder::active ? glue_stopActionRec() : glue_startActionRec(); } /* -------------------------------------------------------------------------- */ void glue_startActionRec() { if (G_audio_status == false) return; if (!G_Mixer.running) glue_startSeq(); // start the sequencer for convenience recorder::active = true; Fl::lock(); mainWin->controller->updateRecAction(1); Fl::unlock(); } /* -------------------------------------------------------------------------- */ void glue_stopActionRec() { /* stop the recorder and sort new actions */ recorder::active = false; recorder::sortActions(); for (unsigned i=0; itype == CHANNEL_SAMPLE) { SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); if (ch->hasActions) ch->readActions = true; else ch->readActions = false; mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); } Fl::lock(); mainWin->controller->updateRecAction(0); Fl::unlock(); /* in case acton editor is on, refresh it */ gu_refreshActionEditor(); } /* -------------------------------------------------------------------------- */ void glue_startStopReadingRecs(SampleChannel *ch, bool gui) { if (ch->readActions) glue_stopReadingRecs(ch, gui); else glue_startReadingRecs(ch, gui); } /* -------------------------------------------------------------------------- */ void glue_startReadingRecs(SampleChannel *ch, bool gui) { if (G_Conf.treatRecsAsLoops) ch->recStatus = REC_WAITING; else ch->setReadActions(true); if (!gui) { gSampleChannel *gch = (gSampleChannel*)ch->guiChannel; if (gch->readActions) { // if button exists Fl::lock(); gch->readActions->value(1); Fl::unlock(); } } } /* -------------------------------------------------------------------------- */ void glue_stopReadingRecs(SampleChannel *ch, bool gui) { /* if "treatRecsAsLoop" wait until the sequencer reaches beat 0, so put * the channel in REC_ENDING status */ if (G_Conf.treatRecsAsLoops) ch->recStatus = REC_ENDING; else ch->setReadActions(false); if (!gui) { gSampleChannel *gch = (gSampleChannel*)ch->guiChannel; if (gch->readActions) { // if button exists Fl::lock(); gch->readActions->value(0); Fl::unlock(); } } } /* -------------------------------------------------------------------------- */ void glue_quantize(int val) { G_Mixer.quantize = val; G_Mixer.updateQuanto(); } /* -------------------------------------------------------------------------- */ void glue_setChanVol(Channel *ch, float v, bool gui) { ch->volume = v; /* also update wave editor if it's shown */ gdEditor *editor = (gdEditor*) gu_getSubwindow(mainWin, WID_SAMPLE_EDITOR); if (editor) { glue_setVolEditor(editor, (SampleChannel*) ch, v, false); Fl::lock(); editor->volume->value(v); Fl::unlock(); } if (!gui) { Fl::lock(); ch->guiChannel->vol->value(v); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_setOutVol(float v, bool gui) { G_Mixer.outVol = v; if (!gui) { Fl::lock(); mainWin->inOut->setOutVol(v); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_setInVol(float v, bool gui) { G_Mixer.inVol = v; if (!gui) { Fl::lock(); mainWin->inOut->setInVol(v); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_clearAllSamples() { G_Mixer.running = false; for (unsigned i=0; iempty(); G_Mixer.channels.at(i)->guiChannel->reset(); } recorder::init(); return; } /* -------------------------------------------------------------------------- */ void glue_clearAllRecs() { recorder::init(); gu_updateControls(); } /* -------------------------------------------------------------------------- */ void glue_resetToInitState(bool resetGui, bool createColumns) { G_Patch_DEPR_.setDefault(); G_Mixer.close(); G_Mixer.init(); recorder::init(); #ifdef WITH_VST G_PluginHost.freeAllStacks(); #endif mainWin->keyboard->clear(); if (createColumns) mainWin->keyboard->init(); if (resetGui) gu_updateControls(); } /* -------------------------------------------------------------------------- */ void glue_startStopMetronome(bool gui) { G_Mixer.metronome = !G_Mixer.metronome; if (!gui) { Fl::lock(); mainWin->controller->updateMetronome(G_Mixer.metronome); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_setBeginEndChannel(gdEditor *win, SampleChannel *ch, int b, int e, bool recalc, bool check) { if (check) { if (e > ch->wave->size) e = ch->wave->size; if (b < 0) b = 0; if (b > ch->wave->size) b = ch->wave->size-2; if (b >= ch->end) b = ch->begin; if (e <= ch->begin) e = ch->end; } /* continue only if new values != old values */ if (b == ch->begin && e == ch->end) return; /* print mono values */ char tmp[16]; sprintf(tmp, "%d", b/2); win->chanStart->value(tmp); tmp[0] = '\0'; sprintf(tmp, "%d", e/2); win->chanEnd->value(tmp); ch->setBegin(b); ch->setEnd(e); /* recalc is not needed when the user drags the bars directly over the waveform */ if (recalc) { win->waveTools->waveform->recalcPoints(); // importante, altrimenti non si vedono win->waveTools->waveform->redraw(); } } /* -------------------------------------------------------------------------- */ void glue_setBoost(gdEditor *win, SampleChannel *ch, float val, bool numeric) { if (numeric) { if (val > 20.0f) val = 20.0f; else if (val < 0.0f) val = 0.0f; float linear = pow(10, (val / 20)); // linear = 10^(dB/20) ch->boost = linear; char buf[10]; sprintf(buf, "%.2f", val); win->boostNum->value(buf); win->boostNum->redraw(); win->boost->value(linear); win->boost->redraw(); /// inutile } else { ch->boost = val; char buf[10]; sprintf(buf, "%.2f", 20*log10(val)); win->boostNum->value(buf); win->boostNum->redraw(); } } /* -------------------------------------------------------------------------- */ void glue_setVolEditor(class gdEditor *win, SampleChannel *ch, float val, bool numeric) { if (numeric) { if (val > 0.0f) val = 0.0f; else if (val < -60.0f) val = -INFINITY; float linear = pow(10, (val / 20)); // linear = 10^(dB/20) ch->volume = linear; win->volume->value(linear); win->volume->redraw(); char buf[10]; if (val > -INFINITY) sprintf(buf, "%.2f", val); else sprintf(buf, "-inf"); win->volumeNum->value(buf); win->volumeNum->redraw(); ch->guiChannel->vol->value(linear); ch->guiChannel->vol->redraw(); } else { ch->volume = val; float dbVal = 20 * log10(val); char buf[10]; if (dbVal > -INFINITY) sprintf(buf, "%.2f", dbVal); else sprintf(buf, "-inf"); win->volumeNum->value(buf); win->volumeNum->redraw(); ch->guiChannel->vol->value(val); ch->guiChannel->vol->redraw(); } } /* -------------------------------------------------------------------------- */ void glue_setMute(Channel *ch, bool gui) { if (recorder::active && recorder::canRec(ch)) { if (!ch->mute) recorder::startOverdub(ch->index, ACTION_MUTES, G_Mixer.actualFrame); else recorder::stopOverdub(G_Mixer.actualFrame); } ch->mute ? ch->unsetMute(false) : ch->setMute(false); if (!gui) { Fl::lock(); ch->guiChannel->mute->value(ch->mute); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_setSoloOn(Channel *ch, bool gui) { /* if there's no solo session, store mute configuration of all chans * and start the session */ if (!__soloSession__) { for (unsigned i=0; imute_s = och->mute; } __soloSession__ = true; } ch->solo = !ch->solo; ch->sendMidiLsolo(); /* mute all other channels and unmute this (if muted) */ for (unsigned i=0; isolo && !och->mute) { och->setMute(false); Fl::lock(); och->guiChannel->mute->value(true); Fl::unlock(); } } if (ch->mute) { ch->unsetMute(false); Fl::lock(); ch->guiChannel->mute->value(false); Fl::unlock(); } if (!gui) { Fl::lock(); ch->guiChannel->solo->value(1); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_setSoloOff(Channel *ch, bool gui) { /* if this is uniqueSolo, stop solo session and restore mute status, * else mute this */ if (mh_uniqueSolo(ch)) { __soloSession__ = false; for (unsigned i=0; imute_s) { och->setMute(false); Fl::lock(); och->guiChannel->mute->value(true); Fl::unlock(); } else { och->unsetMute(false); Fl::lock(); och->guiChannel->mute->value(false); Fl::unlock(); } och->mute_s = false; } } else { ch->setMute(false); Fl::lock(); ch->guiChannel->mute->value(true); Fl::unlock(); } ch->solo = !ch->solo; ch->sendMidiLsolo(); if (!gui) { Fl::lock(); ch->guiChannel->solo->value(0); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ void glue_setPanning(class gdEditor *win, SampleChannel *ch, float val) { if (val < 1.0f) { ch->panLeft = 1.0f; ch->panRight= 0.0f + val; char buf[8]; sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100)); win->panNum->value(buf); } else if (val == 1.0f) { ch->panLeft = 1.0f; ch->panRight= 1.0f; win->panNum->value("C"); } else { ch->panLeft = 2.0f - val; ch->panRight= 1.0f; char buf[8]; sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100)); win->panNum->value(buf); } win->panNum->redraw(); } /* -------------------------------------------------------------------------- */ void glue_startStopInputRec(bool gui, bool alert) { if (G_Mixer.chanInput == NULL) { if (!glue_startInputRec(gui)) { if (alert) gdAlert("No channels available for recording."); else gLog("[glue] no channels available for recording\n"); } } else glue_stopInputRec(gui); } /* -------------------------------------------------------------------------- */ int glue_startInputRec(bool gui) { if (G_audio_status == false) return -1; SampleChannel *ch = mh_startInputRec(); if (ch == NULL) { // no chans available Fl::lock(); mainWin->controller->updateRecInput(0); Fl::unlock(); return 0; } if (!G_Mixer.running) { glue_startSeq(); Fl::lock(); mainWin->controller->updatePlay(1); Fl::unlock(); } glue_setChanVol(ch, 1.0f, false); // false = not from gui click ch->guiChannel->mainButton->label(ch->wave->name.c_str()); if (!gui) { Fl::lock(); mainWin->controller->updateRecInput(1); Fl::unlock(); } return 1; } /* -------------------------------------------------------------------------- */ int glue_stopInputRec(bool gui) { SampleChannel *ch = mh_stopInputRec(); if (ch->mode & (LOOP_BASIC | LOOP_ONCE | LOOP_REPEAT)) ch->start(0, true); // on frame 0: user-generated event if (!gui) { Fl::lock(); mainWin->controller->updateRecInput(0); Fl::unlock(); } return 1; } /* -------------------------------------------------------------------------- */ void glue_keyPress(Channel *ch, bool ctrl, bool shift) { if (ch->type == CHANNEL_SAMPLE) glue_keyPress((SampleChannel*)ch, ctrl, shift); else glue_keyPress((MidiChannel*)ch, ctrl, shift); } /* -------------------------------------------------------------------------- */ void glue_keyRelease(Channel *ch, bool ctrl, bool shift) { if (ch->type == CHANNEL_SAMPLE) glue_keyRelease((SampleChannel*)ch, ctrl, shift); } /* -------------------------------------------------------------------------- */ void glue_keyPress(MidiChannel *ch, bool ctrl, bool shift) { if (ctrl) glue_setMute(ch); else if (shift) ch->kill(0); // on frame 0: user-generated event else ch->start(0, true); // on frame 0: user-generated event } /* -------------------------------------------------------------------------- */ void glue_keyPress(SampleChannel *ch, bool ctrl, bool shift) { /* case CTRL */ if (ctrl) glue_setMute(ch); /* case SHIFT * * action recording on: * if seq is playing, rec a killchan * action recording off: * if chan has recorded events: * | if seq is playing OR channel 'c' is stopped, de/activate recs * | else kill chan * else kill chan */ else if (shift) { if (recorder::active) { if (G_Mixer.running) { ch->kill(0); // on frame 0: user-generated event if (recorder::canRec(ch) && !(ch->mode & LOOP_ANY)) // don't record killChan actions for LOOP channels recorder::rec(ch->index, ACTION_KILLCHAN, G_Mixer.actualFrame); } } else { if (ch->hasActions) { if (G_Mixer.running || ch->status == STATUS_OFF) ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch); else ch->kill(0); // on frame 0: user-generated event } else ch->kill(0); // on frame 0: user-generated event } } /* case no modifier */ else { /* record now if the quantizer is off, otherwise let mixer to handle it * when a quantoWait has passed. Moreover, KEYPRESS and KEYREL are * meaningless for loop modes */ if (G_Mixer.quantize == 0 && recorder::canRec(ch) && !(ch->mode & LOOP_ANY)) { if (ch->mode == SINGLE_PRESS) recorder::startOverdub(ch->index, ACTION_KEYS, G_Mixer.actualFrame); else recorder::rec(ch->index, ACTION_KEYPRESS, G_Mixer.actualFrame); } ch->start(0, true); // on frame 0: user-generated event } /* the GUI update is done by gui_refresh() */ } /* -------------------------------------------------------------------------- */ void glue_keyRelease(SampleChannel *ch, bool ctrl, bool shift) { if (!ctrl && !shift) { ch->stop(); /* record a key release only if channel is single_press. For any * other mode the KEY REL is meaningless. */ if (ch->mode == SINGLE_PRESS && recorder::canRec(ch)) recorder::stopOverdub(G_Mixer.actualFrame); } /* the GUI update is done by gui_refresh() */ } /* -------------------------------------------------------------------------- */ void glue_setPitch(class gdEditor *win, SampleChannel *ch, float val, bool numeric) { if (numeric) { if (val <= 0.0f) val = 0.1000f; if (val > 4.0f) val = 4.0000f; if (win) win->pitch->value(val); } ch->setPitch(val); if (win) { char buf[16]; sprintf(buf, "%.4f", val); Fl::lock(); win->pitchNum->value(buf); win->pitchNum->redraw(); Fl::unlock(); } } /* -------------------------------------------------------------------------- */ /* never expand or shrink recordings (last param of setBeats = false): * this is live manipulation */ void glue_beatsMultiply() { glue_setBeats(G_Mixer.beats*2, G_Mixer.bars, false); } void glue_beatsDivide() { glue_setBeats(G_Mixer.beats/2, G_Mixer.bars, false); } giada-0.11.2/src/glue/glue.h000066400000000000000000000125361264622563000155050ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * glue * Intermediate layer GUI <-> CORE. * * How to know if you need another glue_ function? Ask yourself if the * new action will ever be called via MIDI or keyboard/mouse. If yes, * put it here. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GLUE_H #define GLUE_H /* keyPress / keyRelease * handle the key pressure, either via mouse/keyboard or MIDI. If gui * is true it means that the event comes from the main window (mouse, * keyb or MIDI), otherwise the event comes from the action recorder. */ void glue_keyPress (class Channel *ch, bool ctrl=0, bool shift=0); void glue_keyPress (class SampleChannel *ch, bool ctrl=0, bool shift=0); void glue_keyPress (class MidiChannel *ch, bool ctrl=0, bool shift=0); void glue_keyRelease(class Channel *ch, bool ctrl=0, bool shift=0); void glue_keyRelease(class SampleChannel *ch, bool ctrl=0, bool shift=0); void glue_setBpm(const char *v1, const char *v2); void glue_setBeats(int beats, int bars, bool expand); /* start, stop, rewind sequencer * if gui == true the signal comes from an internal interaction on the * GUI, otherwise it's a MIDI/Jack/external signal. */ void glue_startStopSeq(bool gui=true); void glue_startSeq (bool gui=true); void glue_stopSeq (bool gui=true); void glue_rewindSeq (); /* start/stopActionRec * handle the action recording. */ void glue_startStopActionRec(); void glue_startActionRec(); void glue_stopActionRec(); /* start/stopInputRec * handle the input recording (take). If gui == true the signal comes * from an internal interaction on the GUI, otherwise it's a * MIDI/Jack/external signal. Alert displays or not the popup message * if there are no available channels. */ void glue_startStopInputRec(bool gui=true, bool alert=true); int glue_startInputRec (bool gui=true); int glue_stopInputRec (bool gui=true); /* start/stopReadingRecs * handle the 'R' button. If gui == true the signal comes from an * internal interaction on the GUI, otherwise it's a MIDI/Jack/external * signal. */ void glue_startStopReadingRecs(class SampleChannel *ch, bool gui=true); void glue_startReadingRecs (class SampleChannel *ch, bool gui=true); void glue_stopReadingRecs (class SampleChannel *ch, bool gui=true); void glue_quantize(int val); void glue_setChanVol(class Channel *ch, float v, bool gui=true); void glue_setOutVol (float v, bool gui=true); void glue_setInVol (float v, bool gui=true); void glue_setPanning(class gdEditor *win, class SampleChannel *ch, float val); void glue_clearAllSamples(); void glue_clearAllRecs(); /* resetToInitState * reset Giada to init state. If resetGui also refresh all widgets. If * createColumns also build initial empty columns. */ void glue_resetToInitState(bool resetGui=true, bool createColumns=true); void glue_startStopMetronome(bool gui=true); /* setBeginEndChannel * sets start/end points in the sample editor. * Recalc=false: don't recalc internal position * check=true: check the points' consistency */ /** FIXME - nobody will call this via MIDI/keyb/mouse! */ void glue_setBeginEndChannel(class gdEditor *win, class SampleChannel *ch, int b, int e, bool recalc=false, bool check=true); /** FIXME - nobody will call this via MIDI/keyb/mouse! */ void glue_setBoost(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); void glue_setPitch(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); /* setVolEditor * handles the volume inside the SAMPLE EDITOR (not the main gui). The * numeric flag tells if we want to handle the dial or the numeric input * field. */ /** FIXME - nobody will call this via MIDI/keyb/mouse! */ void glue_setVolEditor(class gdEditor *win, class SampleChannel *ch, float val, bool numeric); /* mute * set mute on or off. If gui == true the signal comes from an internal * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */ void glue_setMute(class Channel *ch, bool gui=true); /* solo on/off * set solo on and off. If gui == true the signal comes from an internal * interaction on the GUI, otherwise it's a MIDI/Jack/external signal. */ void glue_setSoloOn (class Channel *ch, bool gui=true); void glue_setSoloOff(class Channel *ch, bool gui=true); /* beatsDivide/Multiply * shrinks or enlarges the number of beats by 2. */ void glue_beatsMultiply(); void glue_beatsDivide(); #endif giada-0.11.2/src/glue/storage.cpp000066400000000000000000000245001264622563000165420ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * glue * Intermediate layer GUI <-> CORE. * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../gui/elems/ge_column.h" #include "../gui/elems/ge_keyboard.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_warnings.h" #include "../core/mixer.h" #include "../core/mixerHandler.h" #include "../core/channel.h" #include "../core/pluginHost.h" #include "../core/conf.h" #include "../core/patch.h" #include "../core/patch_DEPR_.h" // TODO - remove, used only for DEPR calls #include "../core/sampleChannel.h" #include "../core/midiChannel.h" #include "../core/wave.h" #include "../utils/gui_utils.h" #include "glue.h" // TODO - remove, used only for DEPR calls #include "channel.h" #include "storage.h" using std::string; extern gdMainWindow *mainWin; extern Mixer G_Mixer; extern Patch G_Patch; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; // TODO - remove, used only for DEPR calls #ifdef WITH_VST extern PluginHost G_PluginHost; #endif static void __glue_setProgressBar__(class gProgress *status, float v) { status->value(status->value() + v); //Fl::check(); Fl::wait(0); } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST static void __glue_fillPatchGlobalsPlugins__(vector *host, vector *patch) { for (unsigned i=0; isize(); i++) { Plugin *pl = host->at(i); Patch::plugin_t ppl; ppl.path = pl->pathfile; ppl.bypass = pl->bypass; int numParams = pl->getNumParams(); for (int k=0; kgetParam(k)); patch->push_back(ppl); } } #endif /* -------------------------------------------------------------------------- */ static void __glue_fillPatchColumns__() { for (unsigned i=0; ikeyboard->getTotalColumns(); i++) { gColumn *gCol = mainWin->keyboard->getColumn(i); Patch::column_t pCol; pCol.index = gCol->getIndex(); pCol.width = gCol->w(); for (int k=0; kcountChannels(); k++) { Channel *colChannel = gCol->getChannel(k); for (unsigned j=0; jindex); break; } } } G_Patch.columns.push_back(pCol); } } /* -------------------------------------------------------------------------- */ static void __glue_fillPatchChannels__(bool isProject) { for (unsigned i=0; iwritePatch(i, isProject); } } /* -------------------------------------------------------------------------- */ static void __glue_fillPatchGlobals__(const string &name) { G_Patch.version = G_VERSION_STR; G_Patch.versionMajor = G_VERSION_MAJOR; G_Patch.versionMinor = G_VERSION_MINOR; G_Patch.versionPatch = G_VERSION_PATCH; G_Patch.name = name; G_Patch.bpm = G_Mixer.bpm; G_Patch.bars = G_Mixer.bars; G_Patch.beats = G_Mixer.beats; G_Patch.quantize = G_Mixer.quantize; G_Patch.masterVolIn = G_Mixer.inVol; G_Patch.masterVolOut = G_Mixer.outVol; G_Patch.metronome = G_Mixer.metronome; #ifdef WITH_VST __glue_fillPatchGlobalsPlugins__(&G_PluginHost.masterIn, &G_Patch.masterInPlugins); __glue_fillPatchGlobalsPlugins__(&G_PluginHost.masterOut, &G_Patch.masterOutPlugins); #endif } /* -------------------------------------------------------------------------- */ int glue_savePatch(const string &fullPath, const string &name, bool isProject) { G_Patch.init(); __glue_fillPatchGlobals__(name); __glue_fillPatchChannels__(isProject); __glue_fillPatchColumns__(); if (G_Patch.write(fullPath)) { gu_update_win_label(name.c_str()); gLog("[glue] patch saved as %s\n", fullPath.c_str()); return 1; } return 0; } /* -------------------------------------------------------------------------- */ int glue_loadPatch(const string &fullPath, class gProgress *status, bool isProject) { /* try to load the new JSON-based patch. If it fails, fall back to deprecated * one. */ gLog("[glue] loading %s...\n", fullPath.c_str()); string fileToLoad = fullPath; // patch file to read from string basePath = ""; // base path, in case of reading from a project if (isProject) { fileToLoad = fullPath + gGetSlash() + gStripExt(gBasename(fullPath)) + ".gptc"; basePath = fullPath.c_str() + gGetSlash(); } int res = G_Patch.read(fileToLoad); if (res == PATCH_UNREADABLE) { gLog("[glue] failed reading JSON-based patch. Trying with the deprecated method\n"); return glue_loadPatch__DEPR__(gBasename(fileToLoad).c_str(), fileToLoad.c_str(), status, isProject); } if (res != PATCH_READ_OK) return res; /* close all other windows. This prevents segfault if plugin * windows GUIs are on. */ gu_closeAllSubwindows(); /* reset the system. False(1): don't update the gui right now. False(2): do * not create empty columns. */ glue_resetToInitState(false, false); __glue_setProgressBar__(status, 0.1f); /* Add common stuff, columns and channels. Also increment the progress bar * by 0.8 / total_channels steps. */ float steps = 0.8 / G_Patch.channels.size(); for (unsigned i=0; ikeyboard->addColumn(col->width); for (unsigned k=0; kindex) { Channel *ch = glue_addChannel(G_Patch.channels.at(k).column, G_Patch.channels.at(k).type); ch->readPatch(basePath, k); } __glue_setProgressBar__(status, steps); } } /* fill Mixer */ mh_readPatch(); /* let recorder recompute the actions' positions if the current * samplerate != patch samplerate */ recorder::updateSamplerate(G_Conf.samplerate, G_Patch.samplerate); /* save patchPath by taking the last dir of the broswer, in order to * reuse it the next time */ G_Conf.patchPath = gDirname(fullPath.c_str()); /* refresh GUI */ gu_updateControls(); gu_update_win_label(G_Patch.name.c_str()); __glue_setProgressBar__(status, 1.0f); gLog("[glue] patch loaded successfully\n"); return res; } /* -------------------------------------------------------------------------- */ int glue_loadPatch__DEPR__(const char *fname, const char *fpath, gProgress *status, bool isProject) { /* update browser's status bar with % 0.1 */ status->show(); status->value(0.1f); //Fl::check(); Fl::wait(0); /* is it a valid patch? */ int res = G_Patch_DEPR_.open(fpath); if (res != PATCH_READ_OK) return res; /* close all other windows. This prevents segfault if plugin windows * GUI are on. */ if (res) gu_closeAllSubwindows(); /* reset the system. False(1): don't update the gui right now. False(2): do * not create empty columns. */ glue_resetToInitState(false, false); status->value(0.2f); // progress status: % 0.2 //Fl::check(); Fl::wait(0); /* mixerHandler will update the samples inside Mixer */ mh_loadPatch_DEPR_(isProject, gDirname(fpath).c_str()); /* take the patch name and update the main window's title */ G_Patch_DEPR_.getName(); gu_update_win_label(G_Patch_DEPR_.name); status->value(0.4f); // progress status: 0.4 //Fl::check(); Fl::wait(0); G_Patch_DEPR_.readRecs(); status->value(0.6f); // progress status: 0.6 //Fl::check(); Fl::wait(0); #ifdef WITH_VST int resPlugins = G_Patch_DEPR_.readPlugins(); status->value(0.8f); // progress status: 0.8 //Fl::check(); Fl::wait(0); #endif /* this one is vital: let recorder recompute the actions' positions if * the current samplerate != patch samplerate */ recorder::updateSamplerate(G_Conf.samplerate, G_Patch_DEPR_.samplerate); /* update gui */ gu_updateControls(); status->value(1.0f); // progress status: 1.0 (done) //Fl::check(); Fl::wait(0); /* save patchPath by taking the last dir of the broswer, in order to * reuse it the next time */ G_Conf.patchPath = gDirname(fpath).c_str(); gLog("[glue] patch %s loaded\n", fname); #ifdef WITH_VST if (resPlugins != 1) gdAlert("Some VST plugins were not loaded successfully."); #endif gdAlert("This patch is using a deprecated format.\nPlease save it again to store it properly."); return res; } /* -------------------------------------------------------------------------- */ int glue_saveProject(const string &folderPath, const string &projName) { if (!gDirExists(folderPath.c_str()) && !gMkdir(folderPath.c_str())) { gLog("[glue] unable to make project directory!\n"); return 0; } /* copy all samples inside the folder. Takes and logical ones are saved * via glue_saveSample() */ for (unsigned i=0; itype == CHANNEL_MIDI) continue; SampleChannel *ch = (SampleChannel*) G_Mixer.channels.at(i); if (ch->wave == NULL) continue; /* update the new samplePath: everything now comes from the project * folder (folderPath). Also remove any existing file. */ string samplePath = folderPath + gGetSlash() + ch->wave->basename() + "." + ch->wave->extension(); if (gFileExists(samplePath.c_str())) remove(samplePath.c_str()); if (ch->save(samplePath.c_str())) ch->wave->pathfile = samplePath; } string gptcPath = folderPath + gGetSlash() + gStripExt(projName.c_str()) + ".gptc"; glue_savePatch(gptcPath, projName, true); // true == it's a project return 1; } giada-0.11.2/src/glue/storage.h000066400000000000000000000032031264622563000162040ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * glue * Intermediate layer GUI <-> CORE. * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GLUE_STORAGE_H #define GLUE_STORAGE_H #include #include "../core/patch.h" using std::string; using std::vector; int glue_loadPatch (const string &fullPath, class gProgress *status, bool isProject); int glue_loadPatch__DEPR__(const char *fname, const char *fpath, class gProgress *status, bool isProject); int glue_savePatch (const string &fullPath, const string &name, bool isProject); int glue_saveProject(const string &folderPath, const string &projName); #endif giada-0.11.2/src/gui/000077500000000000000000000000001264622563000142215ustar00rootroot00000000000000giada-0.11.2/src/gui/dialogs/000077500000000000000000000000001264622563000156435ustar00rootroot00000000000000giada-0.11.2/src/gui/dialogs/gd_about.cpp000066400000000000000000000066701264622563000201440ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_about * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../../core/conf.h" #include "../../core/const.h" #include "../../core/kernelAudio.h" #include "../../core/kernelMidi.h" #include "../../core/graphics.h" #include "../../utils/gui_utils.h" #include "../elems/ge_mixed.h" #include "gd_about.h" extern Conf G_Conf; gdAbout::gdAbout() #ifdef WITH_VST : gWindow(340, 405, "About Giada") { #else : gWindow(340, 320, "About Giada") { #endif if (G_Conf.aboutX) resize(G_Conf.aboutX, G_Conf.aboutY, w(), h()); set_modal(); logo = new gBox(8, 10, 324, 86); text = new gBox(8, 120, 324, 145); close = new gClick(252, h()-28, 80, 20, "Close"); #ifdef WITH_VST vstLogo = new gBox(8, 265, 324, 50); vstText = new gBox(8, 315, 324, 46); #endif end(); logo->image(new Fl_Pixmap(giada_logo_xpm)); text->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_TOP); char message[512]; sprintf( message, "Version " G_VERSION_STR " (" __DATE__ ")\n\n" "Developed by Monocasual\n" "Based on FLTK (%d.%d.%d), RtAudio (%s),\n" "RtMidi (%s), libsamplerate, Jansson (%s) \n" "and libsndfile\n\n" "Released under the terms of the GNU General\n" "Public License (GPL v3)\n\n" "News, infos, contacts and documentation:\n" "www.giadamusic.com", FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION, kernelAudio::getRtAudioVersion().c_str(), kernelMidi::getRtMidiVersion().c_str(), JANSSON_VERSION); int tw = 0; int th = 0; fl_measure(message, tw, th); text->copy_label(message); text->size(text->w(), th); #ifdef WITH_VST vstLogo->image(new Fl_Pixmap(vstLogo_xpm)); vstLogo->position(vstLogo->x(), text->y()+text->h()+8); vstText->label( "VST Plug-In Technology by Steinberg\n" "VST is a trademark of Steinberg\nMedia Technologies GmbH" ); vstText->position(vstText->x(), vstLogo->y()+vstLogo->h()); #endif close->callback(cb_close, (void*)this); gu_setFavicon(this); setId(WID_ABOUT); show(); } /* -------------------------------------------------------------------------- */ gdAbout::~gdAbout() { G_Conf.aboutX = x(); G_Conf.aboutY = y(); } /* -------------------------------------------------------------------------- */ void gdAbout::cb_close(Fl_Widget *w, void *p) { ((gdAbout*)p)->__cb_close(); } /* -------------------------------------------------------------------------- */ void gdAbout::__cb_close() { do_callback(); } giada-0.11.2/src/gui/dialogs/gd_about.h000066400000000000000000000027761264622563000176140ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_about * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_ABOUT_H #define GD_ABOUT_H #include #include #include "../elems/ge_window.h" class gdAbout : public gWindow { private: class gBox *logo; class gBox *text; class gClick *close; #ifdef WITH_VST class gBox *vstText; class gBox *vstLogo; #endif public: gdAbout(); ~gdAbout(); static void cb_close(Fl_Widget *w, void *p); inline void __cb_close(); }; #endif giada-0.11.2/src/gui/dialogs/gd_actionEditor.cpp000066400000000000000000000264071264622563000214560ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_actionEditor * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../../utils/gui_utils.h" #include "../../core/graphics.h" #include "../../core/mixer.h" #include "../../core/recorder.h" #include "../../core/conf.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../elems/ge_actionChannel.h" #include "../elems/ge_muteChannel.h" #include "../elems/ge_envelopeChannel.h" #include "../elems/ge_pianoRoll.h" #include "../elems/ge_mixed.h" #include "gd_actionEditor.h" extern Mixer G_Mixer; extern Conf G_Conf; gdActionEditor::gdActionEditor(Channel *chan) : gWindow(640, 284), chan (chan), zoom (100), coverX (0) { if (G_Conf.actionEditorW) { resize(G_Conf.actionEditorX, G_Conf.actionEditorY, G_Conf.actionEditorW, G_Conf.actionEditorH); zoom = G_Conf.actionEditorZoom; } totalWidth = (int) ceilf(G_Mixer.framesInSequencer / (float) zoom); /* container with zoom buttons and the action type selector. Scheme of * the resizable boxes: |[--b1--][actionType][--b2--][+][-]| */ Fl_Group *upperArea = new Fl_Group(8, 8, w()-16, 20); upperArea->begin(); if (chan->type == CHANNEL_SAMPLE) { actionType = new gChoice(8, 8, 80, 20); gridTool = new gGridTool(actionType->x()+actionType->w()+4, 8, this); actionType->add("key press"); actionType->add("key release"); actionType->add("kill chan"); actionType->value(0); SampleChannel *ch = (SampleChannel*) chan; if (ch->mode == SINGLE_PRESS || ch->mode & LOOP_ANY) actionType->deactivate(); } else { gridTool = new gGridTool(8, 8, this); } gBox *b1 = new gBox(gridTool->x()+gridTool->w()+4, 8, 300, 20); // padding actionType - zoomButtons zoomIn = new gClick(w()-8-40-4, 8, 20, 20, "", zoomInOff_xpm, zoomInOn_xpm); zoomOut = new gClick(w()-8-20, 8, 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm); upperArea->end(); upperArea->resizable(b1); zoomIn->callback(cb_zoomIn, (void*)this); zoomOut->callback(cb_zoomOut, (void*)this); /* main scroller: contains all widgets */ scroller = new gScroll(8, 36, w()-16, h()-44); if (chan->type == CHANNEL_SAMPLE) { SampleChannel *ch = (SampleChannel*) chan; ac = new gActionChannel (scroller->x(), upperArea->y()+upperArea->h()+8, this, ch); mc = new gMuteChannel (scroller->x(), ac->y()+ac->h()+8, this); vc = new gEnvelopeChannel (scroller->x(), mc->y()+mc->h()+8, this, ACTION_VOLUME, RANGE_FLOAT, "volume"); scroller->add(ac); //scroller->add(new gResizerBar(ac->x(), ac->y()+ac->h(), scroller->w(), 8)); scroller->add(mc); //scroller->add(new gResizerBar(mc->x(), mc->y()+mc->h(), scroller->w(), 8)); scroller->add(vc); //scroller->add(new gResizerBar(vc->x(), vc->y()+vc->h(), scroller->w(), 8)); /* fill volume envelope with actions from recorder */ vc->fill(); /* if channel is LOOP_ANY, deactivate it: a loop mode channel cannot * hold keypress/keyrelease actions */ if (ch->mode & LOOP_ANY) ac->deactivate(); } else { pr = new gPianoRollContainer(scroller->x(), upperArea->y()+upperArea->h()+8, this); scroller->add(pr); scroller->add(new gResizerBar(pr->x(), pr->y()+pr->h(), scroller->w(), 8)); } end(); /* compute values */ update(); gridTool->calc(); gu_setFavicon(this); char buf[256]; sprintf(buf, "Edit Actions in Channel %d", chan->index+1); label(buf); set_non_modal(); size_range(640, 284); resizable(scroller); show(); } /* ------------------------------------------------------------------ */ gdActionEditor::~gdActionEditor() { G_Conf.actionEditorX = x(); G_Conf.actionEditorY = y(); G_Conf.actionEditorW = w(); G_Conf.actionEditorH = h(); G_Conf.actionEditorZoom = zoom; /** CHECKME - missing clear() ? */ } /* ------------------------------------------------------------------ */ void gdActionEditor::cb_zoomIn(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomIn(); } void gdActionEditor::cb_zoomOut(Fl_Widget *w, void *p) { ((gdActionEditor*)p)->__cb_zoomOut(); } /* ------------------------------------------------------------------ */ void gdActionEditor::__cb_zoomIn() { /* zoom 50: empirical value, to avoid a totalWidth > 16 bit signed * (32767 max), unsupported by FLTK 1.3.x */ if (zoom <= 50) return; zoom /= 2; update(); if (chan->type == CHANNEL_SAMPLE) { ac->size(totalWidth, ac->h()); mc->size(totalWidth, mc->h()); vc->size(totalWidth, vc->h()); ac->updateActions(); mc->updateActions(); vc->updateActions(); } else { pr->size(totalWidth, pr->h()); pr->updateActions(); } /* scroll to pointer */ int shift = Fl::event_x() + scroller->xposition(); scroller->scroll_to(scroller->xposition() + shift, scroller->yposition()); /* update all underlying widgets */ gridTool->calc(); scroller->redraw(); } /* ------------------------------------------------------------------ */ void gdActionEditor::__cb_zoomOut() { zoom *= 2; update(); if (chan->type == CHANNEL_SAMPLE) { ac->size(totalWidth, ac->h()); mc->size(totalWidth, mc->h()); vc->size(totalWidth, vc->h()); ac->updateActions(); mc->updateActions(); vc->updateActions(); } else { pr->size(totalWidth, pr->h()); pr->updateActions(); } /* scroll to pointer */ int shift = (Fl::event_x() + scroller->xposition()) / -2; if (scroller->xposition() + shift < 0) shift = 0; scroller->scroll_to(scroller->xposition() + shift, scroller->yposition()); /* update all underlying widgets */ gridTool->calc(); scroller->redraw(); } /* ------------------------------------------------------------------ */ void gdActionEditor::update() { totalWidth = (int) ceilf(G_Mixer.framesInSequencer / (float) zoom); if (totalWidth < scroller->w()) { totalWidth = scroller->w(); zoom = (int) ceilf(G_Mixer.framesInSequencer / (float) totalWidth); scroller->scroll_to(0, scroller->yposition()); } } /* ------------------------------------------------------------------ */ int gdActionEditor::handle(int e) { int ret = Fl_Group::handle(e); switch (e) { case FL_MOUSEWHEEL: { Fl::event_dy() == -1 ? __cb_zoomIn() : __cb_zoomOut(); ret = 1; break; } } return ret; } /* ------------------------------------------------------------------ */ int gdActionEditor::getActionType() { if (actionType->value() == 0) return ACTION_KEYPRESS; else if (actionType->value() == 1) return ACTION_KEYREL; else if (actionType->value() == 2) return ACTION_KILLCHAN; else return -1; } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ gGridTool::gGridTool(int x, int y, gdActionEditor *parent) : Fl_Group(x, y, 80, 20), parent(parent) { gridType = new gChoice(x, y, 40, 20); gridType->add("1"); gridType->add("2"); gridType->add("3"); gridType->add("4"); gridType->add("6"); gridType->add("8"); gridType->add("16"); gridType->add("32"); gridType->value(0); gridType->callback(cb_changeType, (void*)this); active = new gCheck (x+44, y+4, 12, 12); gridType->value(G_Conf.actionEditorGridVal); active->value(G_Conf.actionEditorGridOn); end(); } /* ------------------------------------------------------------------ */ gGridTool::~gGridTool() { G_Conf.actionEditorGridVal = gridType->value(); G_Conf.actionEditorGridOn = active->value(); } /* ------------------------------------------------------------------ */ void gGridTool::cb_changeType(Fl_Widget *w, void *p) { ((gGridTool*)p)->__cb_changeType(); } /* ------------------------------------------------------------------ */ void gGridTool::__cb_changeType() { calc(); parent->redraw(); } /* ------------------------------------------------------------------ */ bool gGridTool::isOn() { return active->value(); } /* ------------------------------------------------------------------ */ int gGridTool::getValue() { switch (gridType->value()) { case 0: return 1; case 1: return 2; case 2: return 3; case 3: return 4; case 4: return 6; case 5: return 8; case 6: return 16; case 7: return 32; } return 0; } /* ------------------------------------------------------------------ */ void gGridTool::calc() { points.clear(); frames.clear(); bars.clear(); beats.clear(); /* find beats, bars and grid. The method is the same of the waveform in sample * editor. Take totalwidth (the width in pixel of the area to draw), knowing * that totalWidth = totalFrames / zoom. Then, for each pixel of totalwidth, * put a concentrate of each block (which is totalFrames / zoom) */ int j = 0; int fpgc = floor(G_Mixer.framesPerBeat / getValue()); // frames per grid cell for (int i=1; itotalWidth; i++) { // if i=0, step=0 -> useless cycle int step = parent->zoom*i; while (j < step && j < G_Mixer.totalFrames) { if (j % fpgc == 0) { points.push_back(i); frames.push_back(j); } if (j % G_Mixer.framesPerBeat == 0) beats.push_back(i); if (j % G_Mixer.framesPerBar == 0 && i != 1) bars.push_back(i); if (j == G_Mixer.totalFrames-1) parent->coverX = i; j++; } j = step; } /* fix coverX if == 0, which means G_Mixer.beats == 32 */ if (G_Mixer.beats == 32) parent->coverX = parent->totalWidth; } /* ------------------------------------------------------------------ */ int gGridTool::getSnapPoint(int v) { if (v == 0) return 0; for (int i=0; i<(int)points.size(); i++) { if (i == (int) points.size()-1) return points.at(i); int gp = points.at(i); int gpn = points.at(i+1); if (v >= gp && v < gpn) return gp; } return v; // default value } /* ------------------------------------------------------------------ */ int gGridTool::getSnapFrame(int v) { v *= parent->zoom; // transformation pixel -> frame for (int i=0; i<(int)frames.size(); i++) { if (i == (int) frames.size()-1) return frames.at(i); int gf = frames.at(i); // grid frame int gfn = frames.at(i+1); // grid frame next if (v >= gf && v < gfn) { /* which one is the closest? gf < v < gfn */ if ((gfn - v) < (v - gf)) return gfn; else return gf; } } return v; // default value } /* ------------------------------------------------------------------ */ int gGridTool::getCellSize() { return (parent->coverX - parent->ac->x()) / G_Mixer.beats / getValue(); } giada-0.11.2/src/gui/dialogs/gd_actionEditor.h000066400000000000000000000063531264622563000211210ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_actionEditor * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_ACTIONEDITOR_H #define GD_ACTIONEDITOR_H #include #include #include #include #include "../elems/ge_window.h" using std::vector; /* gActionEditor * main window which contains the tools for dealing with actions. * This class calculates chan, zoom, frames per beat, and so on. Each * sub-widget contains a pointer to this window to query those data. */ class gdActionEditor : public gWindow { private: /* update * compute total width, in pixel. */ void update(); public: gdActionEditor(class Channel *chan); ~gdActionEditor(); int handle(int e); int getActionType(); static void cb_zoomIn(Fl_Widget *w, void *p); static void cb_zoomOut(Fl_Widget *w, void *p); inline void __cb_zoomIn(); inline void __cb_zoomOut(); class gChoice *actionType; class gGridTool *gridTool; class gClick *zoomIn; class gClick *zoomOut; class gScroll *scroller; // widget container class gActionChannel *ac; class gMuteChannel *mc; class gEnvelopeChannel *vc; class gPianoRollContainer *pr; vector widgets; class Channel *chan; int zoom; int totalWidth; // total width of the widget, in pixel (zoom affected) int coverX; // x1 of the unused area (x2 = totalWidth) }; /* ------------------------------------------------------------------ */ class gGridTool : public Fl_Group { private: class gChoice *gridType; class gCheck *active; class gdActionEditor *parent; static void cb_changeType(Fl_Widget *w, void *p); inline void __cb_changeType(); public: gGridTool(int x, int y, gdActionEditor *parent); ~gGridTool(); int getValue(); bool isOn(); void calc(); /* getSnapPoint * given a cursor position in input, return the x coordinates of the * nearest snap point (in pixel, clean, ie. not x()-shifted) */ int getSnapPoint(int v); int getSnapFrame(int v); /* getCellSize * return the size in pixel of a single cell of the grid. */ int getCellSize(); vector points; // points of the grid vector frames; // frames of the grid vector bars; vector beats; }; #endif giada-0.11.2/src/gui/dialogs/gd_beatsInput.cpp000066400000000000000000000054411264622563000211430ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_beatsInput * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "../../utils/gui_utils.h" #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../glue/glue.h" #include "gd_beatsInput.h" #include "gd_mainWindow.h" extern Mixer G_Mixer; extern Conf G_Conf; extern gdMainWindow *mainWin; gdBeatsInput::gdBeatsInput() : gWindow(164, 60, "Beats") { if (G_Conf.beatsX) resize(G_Conf.beatsX, G_Conf.beatsY, w(), h()); set_modal(); beats = new gInput(8, 8, 35, 20); bars = new gInput(47, 8, 35, 20); ok = new gClick(86, 8, 70, 20, "Ok"); resizeRec = new gCheck(8, 40, 12, 12, "resize recorded actions"); end(); char buf_bars[3]; sprintf(buf_bars, "%d", G_Mixer.bars); char buf_beats[3]; sprintf(buf_beats, "%d", G_Mixer.beats); beats->maximum_size(2); beats->value(buf_beats); beats->type(FL_INT_INPUT); bars->maximum_size(2); bars->value(buf_bars); bars->type(FL_INT_INPUT); ok->shortcut(FL_Enter); ok->callback(cb_update_batt, (void*)this); resizeRec->value(G_Conf.resizeRecordings); gu_setFavicon(this); setId(WID_BEATS); show(); } /* ------------------------------------------------------------------ */ gdBeatsInput::~gdBeatsInput() { G_Conf.beatsX = x(); G_Conf.beatsY = y(); G_Conf.resizeRecordings = resizeRec->value(); } /* ------------------------------------------------------------------ */ void gdBeatsInput::cb_update_batt(Fl_Widget *w, void *p) { ((gdBeatsInput*)p)->__cb_update_batt(); } /* ------------------------------------------------------------------ */ void gdBeatsInput::__cb_update_batt() { if (!strcmp(beats->value(), "") || !strcmp(bars->value(), "")) return; glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value()); do_callback(); } giada-0.11.2/src/gui/dialogs/gd_beatsInput.h000066400000000000000000000027731264622563000206150ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_beatsInput * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_BEATSINPUT_H #define GD_BEATSINPUT_H #include #include #include "../elems/ge_window.h" class gdBeatsInput : public gWindow { private: static void cb_update_batt(Fl_Widget *w, void *p); inline void __cb_update_batt(); class gInput *beats; class gInput *bars; class gClick *ok; class gCheck *resizeRec; public: gdBeatsInput(); ~gdBeatsInput(); }; #endif giada-0.11.2/src/gui/dialogs/gd_bpmInput.cpp000066400000000000000000000052611264622563000206230ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_bpmInput * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "../../core/conf.h" #include "../../core/mixer.h" #include "../../glue/glue.h" #include "../../utils/gui_utils.h" #include "../elems/ge_mixed.h" #include "gd_bpmInput.h" #include "gd_mainWindow.h" extern Mixer G_Mixer; extern Conf G_Conf; extern gdMainWindow *mainWin; gdBpmInput::gdBpmInput(const char *label) : gWindow(144, 36, "Bpm") { if (G_Conf.bpmX) resize(G_Conf.bpmX, G_Conf.bpmY, w(), h()); set_modal(); input_a = new gInput(8, 8, 30, 20); input_b = new gInput(42, 8, 20, 20); ok = new gClick(66, 8, 70, 20, "Ok"); end(); char a[4]; snprintf(a, 4, "%d", (int) G_Mixer.bpm); char b[2]; for (unsigned i=0; imaximum_size(3); input_a->type(FL_INT_INPUT); input_a->value(a); input_b->maximum_size(1); input_b->type(FL_INT_INPUT); input_b->value(b); ok->shortcut(FL_Enter); ok->callback(cb_update_bpm, (void*)this); gu_setFavicon(this); setId(WID_BPM); show(); } /* ------------------------------------------------------------------ */ gdBpmInput::~gdBpmInput() { G_Conf.bpmX = x(); G_Conf.bpmY = y(); } /* ------------------------------------------------------------------ */ void gdBpmInput::cb_update_bpm(Fl_Widget *w, void *p) { ((gdBpmInput*)p)->__cb_update_bpm(); } /* ------------------------------------------------------------------ */ void gdBpmInput::__cb_update_bpm() { if (strcmp(input_a->value(), "") == 0) return; glue_setBpm(input_a->value(), input_b->value()); do_callback(); } giada-0.11.2/src/gui/dialogs/gd_bpmInput.h000066400000000000000000000030221264622563000202610ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_bpmInput * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_BPMINPUT_H #define GD_BPMINPUT_H #include #include #include "../elems/ge_window.h" class gdBpmInput : public gWindow { private: static void cb_update_bpm(Fl_Widget *w, void *p); inline void __cb_update_bpm(); class gInput *input_a; class gInput *input_b; class gClick *ok; public: gdBpmInput(const char *label); // pointer to mainWin->timing->bpm->label() ~gdBpmInput(); }; #endif giada-0.11.2/src/gui/dialogs/gd_browser.cpp000066400000000000000000000235601264622563000205120ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_browser * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmacghine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/mixer.h" #include "../../core/graphics.h" #include "../../core/wave.h" #include "../../core/pluginHost.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/patch_DEPR_.h" #include "../../core/patch.h" #include "../../core/conf.h" #include "../../glue/glue.h" #include "../../glue/channel.h" #include "../../glue/storage.h" #include "../elems/ge_browser.h" #include "../elems/ge_channel.h" #include "../elems/ge_keyboard.h" #include "gd_browser.h" #include "gd_pluginList.h" #include "gd_mainWindow.h" #include "gd_warnings.h" using std::string; extern Patch_DEPR_ G_Patch_DEPR_; extern Patch G_Patch; extern Conf G_Conf; extern Mixer G_Mixer; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif extern gdMainWindow *mainWin; gdBrowser::gdBrowser(const char *title, const char *initPath, Channel *ch, int type, int stackType) : gWindow (396, 302, title), ch (ch), type (type), stackType(stackType) { set_non_modal(); browser = new gBrowser(8, 36, 380, 230); Fl_Group *group_btn = new Fl_Group(8, 274, 380, 20); gBox *b = new gBox(8, 274, 204, 20); // spacer window border <-> buttons ok = new gClick(308, 274, 80, 20); cancel = new gClick(220, 274, 80, 20, "Cancel"); status = new gProgress(8, 274, 204, 20); status->minimum(0); status->maximum(1); status->hide(); // show the bar only if necessary group_btn->resizable(b); group_btn->end(); Fl_Group *group_upd = new Fl_Group(8, 8, 380, 25); if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) /// bitmask please! name = new gInput(208, 8, 152, 20); if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) /// bitmask please! where = new gInput(8, 8, 192, 20); else where = new gInput(8, 8, 352, 20); updir = new gClick(368, 8, 20, 20, "", updirOff_xpm, updirOn_xpm); group_upd->resizable(where); group_upd->end(); end(); resizable(browser); size_range(w(), h(), 0, 0); where->readonly(true); where->cursor_color(COLOR_BG_DARK); if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) /// bitmask please! ok->label("Save"); else ok->label("Load"); if (type == BROWSER_LOAD_PATCH) ok->callback(cb_load_patch, (void*)this); else if (type == BROWSER_LOAD_SAMPLE) ok->callback(cb_load_sample, (void*)this); else if (type == BROWSER_SAVE_PATCH) { ok->callback(cb_save_patch, (void*)this); name->value(G_Patch.name == "" ? "my_patch.gptc" : G_Patch.name.c_str()); name->maximum_size(MAX_PATCHNAME_LEN+5); // +5 for ".gptc" } else if (type == BROWSER_SAVE_SAMPLE) { ok->callback(cb_save_sample, (void*)this); name->value(((SampleChannel*)ch)->wave->name.c_str()); } else if (type == BROWSER_SAVE_PROJECT) { ok->callback(cb_save_project, (void*)this); name->value(gStripExt(G_Patch.name).c_str()); } #ifdef WITH_VST else if (type == BROWSER_LOAD_PLUGIN) { ok->callback(cb_loadPlugin, (void*)this); } #endif ok->shortcut(FL_Enter); updir->callback(cb_up, (void*)this); cancel->callback(cb_close, (void*)this); browser->callback(cb_down, this); browser->path_obj = where; browser->init(initPath); if (G_Conf.browserW) resize(G_Conf.browserX, G_Conf.browserY, G_Conf.browserW, G_Conf.browserH); gu_setFavicon(this); show(); } /* -------------------------------------------------------------------------- */ gdBrowser::~gdBrowser() { G_Conf.browserX = x(); G_Conf.browserY = y(); G_Conf.browserW = w(); G_Conf.browserH = h(); } /* -------------------------------------------------------------------------- */ void gdBrowser::cb_load_patch (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_load_patch(); } void gdBrowser::cb_load_sample (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_load_sample(); } void gdBrowser::cb_save_sample (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_save_sample(); } void gdBrowser::cb_save_patch (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_save_patch(); } void gdBrowser::cb_save_project(Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_save_project(); } void gdBrowser::cb_down (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_down(); } void gdBrowser::cb_up (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_up(); } void gdBrowser::cb_close (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_close(); } #ifdef WITH_VST void gdBrowser::cb_loadPlugin (Fl_Widget *v, void *p) { ((gdBrowser*)p)->__cb_loadPlugin(); } #endif /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_load_patch() { if (browser->text(browser->value()) == NULL) return; bool isProject = gIsProject(browser->get_selected_item()); int res = glue_loadPatch(browser->get_selected_item(), status, isProject); if (res == PATCH_UNREADABLE) { status->hide(); if (isProject) gdAlert("This project is unreadable."); else gdAlert("This patch is unreadable."); } else if (res == PATCH_INVALID) { status->hide(); if (isProject) gdAlert("This project is not valid."); else gdAlert("This patch is not valid."); } else do_callback(); } /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_save_sample() { if (strcmp(name->value(), "") == 0) { /// FIXME glue business gdAlert("Please choose a file name."); return; } /* bruteforce check extension. */ string filename = gStripExt(name->value()); char fullpath[PATH_MAX]; sprintf(fullpath, "%s/%s.wav", where->value(), filename.c_str()); if (gFileExists(fullpath)) if (!gdConfirmWin("Warning", "File exists: overwrite?")) return; if (((SampleChannel*)ch)->save(fullpath)) do_callback(); else gdAlert("Unable to save this sample!"); } /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_load_sample() { if (browser->text(browser->value()) == NULL) return; int res = glue_loadChannel((SampleChannel*) ch, browser->get_selected_item()); if (res == SAMPLE_LOADED_OK) { do_callback(); mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open } else mainWin->keyboard->printChannelMessage(res); } /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_down() { const char *path = browser->get_selected_item(); if (!path) // when click on an empty area return; if (!gIsDir(path)) { /* set the name of the patch/sample/project as the selected item */ if (type == BROWSER_SAVE_PATCH || type == BROWSER_SAVE_SAMPLE || type == BROWSER_SAVE_PROJECT) { if (gIsProject(path)) { string tmp = browser->text(browser->value()); tmp.erase(0, 4); name->value(tmp.c_str()); } else name->value(browser->text(browser->value())); } return; } browser->clear(); browser->down_dir(path); browser->sort(); } /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_up() { browser->clear(); browser->up_dir(); browser->sort(); } /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_save_patch() { if (strcmp(name->value(), "") == 0) { /// FIXME glue business gdAlert("Please choose a file name."); return; } string fullpath = where->value() + gGetSlash() + gStripExt(name->value()) + ".gptc"; if (gFileExists(fullpath.c_str())) if (!gdConfirmWin("Warning", "File exists: overwrite?")) return; if (glue_savePatch(fullpath, name->value(), false)) // false == not a project do_callback(); else gdAlert("Unable to save the patch!"); } /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_save_project() { if (strcmp(name->value(), "") == 0) { /// FIXME glue business gdAlert("Please choose a project name."); return; } string fullpath = where->value() + gGetSlash() + gStripExt(name->value()) + ".gprj"; if (gIsProject(fullpath.c_str()) && !gdConfirmWin("Warning", "Project exists: overwrite?")) return; if (glue_saveProject(fullpath, name->value())) do_callback(); else gdAlert("Unable to save the project!"); } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void gdBrowser::__cb_loadPlugin() { if (browser->text(browser->value()) == NULL) return; Plugin *p = G_PluginHost.addPlugin(browser->get_selected_item(), stackType, ch); /* store the folder path inside G_Conf, in order to reuse it the * next time. */ G_Conf.pluginPath = where->value(); if (p != NULL) do_callback(); else gdAlert("Unable to load the selected plugin!"); } #endif /* -------------------------------------------------------------------------- */ void gdBrowser::__cb_close() { do_callback(); } giada-0.11.2/src/gui/dialogs/gd_browser.h000066400000000000000000000053761264622563000201640ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_browser * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_BROWSER_H #define GD_BROWSER_H #include #include #include "../elems/ge_window.h" /* TODO - this class must be subclassed into gdPluginBrowser, gdFileBrowser, * and so on. It's a real mess right now. */ class gdBrowser : public gWindow { private: static void cb_down(Fl_Widget *v, void *p); static void cb_up (Fl_Widget *v, void *p); static void cb_load_sample (Fl_Widget *v, void *p); static void cb_save_sample (Fl_Widget *v, void *p); static void cb_load_patch (Fl_Widget *v, void *p); static void cb_save_patch (Fl_Widget *v, void *p); static void cb_save_project(Fl_Widget *v, void *p); static void cb_close (Fl_Widget *w, void *p); #ifdef WITH_VST static void cb_loadPlugin (Fl_Widget *v, void *p); #endif inline void __cb_down(); inline void __cb_up(); inline void __cb_load_sample(); inline void __cb_save_sample(); inline void __cb_save_project(); inline void __cb_load_patch(); inline void __cb_save_patch(); inline void __cb_close(); #ifdef WITH_VST inline void __cb_loadPlugin(); #endif class gBrowser *browser; class gClick *ok; class gClick *cancel; class gInput *where; class gInput *name; class gClick *updir; class gProgress *status; class Channel *ch; /* browser type: see const.h */ /** FIXME internal enum: * enum browserType { * TYPE_A, * TYPE_B, * .... * }; */ int type; /* PluginHost stack type. Used only when loading plugins */ int stackType; char selectedFile[FILENAME_MAX]; public: gdBrowser(const char *title, const char *initPath, class Channel *ch, int type, int stackType=0); ~gdBrowser(); char* SelectedFile(); }; #endif giada-0.11.2/src/gui/dialogs/gd_config.cpp000066400000000000000000000605451264622563000203000ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_config * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/conf.h" #include "../../core/midiMapConf.h" #include "../../core/patch_DEPR_.h" #include "../../core/kernelAudio.h" #include "../../core/kernelMidi.h" #include "../../utils/gui_utils.h" #include "../../utils/log.h" #include "../elems/ge_mixed.h" #include "gd_config.h" #include "gd_keyGrabber.h" #include "gd_devInfo.h" #include "gd_browser.h" extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; extern bool G_audio_status; extern MidiMapConf G_MidiMap; using std::string; gTabMisc::gTabMisc(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, "Misc") { begin(); debugMsg = new gChoice(x()+92, y()+9, 253, 20, "Debug messages"); end(); debugMsg->add("(disabled)"); debugMsg->add("To standard output"); debugMsg->add("To file"); labelsize(11); switch (G_Conf.logMode) { case LOG_MODE_MUTE: debugMsg->value(0); break; case LOG_MODE_STDOUT: debugMsg->value(1); break; case LOG_MODE_FILE: debugMsg->value(2); break; } } /* -------------------------------------------------------------------------- */ void gTabMisc::save() { switch(debugMsg->value()) { case 0: G_Conf.logMode = LOG_MODE_MUTE; break; case 1: G_Conf.logMode = LOG_MODE_STDOUT; break; case 2: G_Conf.logMode = LOG_MODE_FILE; break; } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gTabAudio::gTabAudio(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, "Sound System") { begin(); soundsys = new gChoice(x()+92, y()+9, 253, 20, "System"); buffersize = new gChoice(x()+92, y()+37, 55, 20, "Buffer size"); samplerate = new gChoice(x()+290, y()+37, 55, 20, "Sample rate"); sounddevOut = new gChoice(x()+92, y()+65, 225, 20, "Output device"); devOutInfo = new gClick (x()+325, y()+65, 20, 20, "?"); channelsOut = new gChoice(x()+92, y()+93, 55, 20, "Output channels"); limitOutput = new gCheck (x()+155, y()+97, 55, 20, "Limit output"); sounddevIn = new gChoice(x()+92, y()+121, 225, 20, "Input device"); devInInfo = new gClick (x()+325, y()+121, 20, 20, "?"); channelsIn = new gChoice(x()+92, y()+149, 55, 20, "Input channels"); delayComp = new gInput (x()+290, y()+149, 55, 20, "Rec delay comp."); rsmpQuality = new gChoice(x()+92, y()+177, 253, 20, "Resampling"); new gBox(x(), rsmpQuality->y()+rsmpQuality->h()+8, w(), 92, "Restart Giada for the changes to take effect."); end(); labelsize(11); soundsys->add("(none)"); #if defined(__linux__) if (kernelAudio::hasAPI(RtAudio::LINUX_ALSA)) soundsys->add("ALSA"); if (kernelAudio::hasAPI(RtAudio::UNIX_JACK)) soundsys->add("Jack"); if (kernelAudio::hasAPI(RtAudio::LINUX_PULSE)) soundsys->add("PulseAudio"); switch (G_Conf.soundSystem) { case SYS_API_NONE: soundsys->showItem("(none)"); break; case SYS_API_ALSA: soundsys->showItem("ALSA"); break; case SYS_API_JACK: soundsys->showItem("Jack"); buffersize->deactivate(); samplerate->deactivate(); break; case SYS_API_PULSE: soundsys->showItem("PulseAudio"); break; } #elif defined(_WIN32) if (kernelAudio::hasAPI(RtAudio::WINDOWS_DS)) soundsys->add("DirectSound"); if (kernelAudio::hasAPI(RtAudio::WINDOWS_ASIO)) soundsys->add("ASIO"); switch (G_Conf.soundSystem) { case SYS_API_NONE: soundsys->showItem("(none)"); break; case SYS_API_DS: soundsys->showItem("DirectSound"); break; case SYS_API_ASIO: soundsys->showItem("ASIO"); break; } #elif defined (__APPLE__) if (kernelAudio::hasAPI(RtAudio::MACOSX_CORE)) soundsys->add("CoreAudio"); switch (G_Conf.soundSystem) { case SYS_API_NONE: soundsys->showItem("(none)"); break; case SYS_API_CORE: soundsys->showItem("CoreAudio"); break; } #endif soundsysInitValue = soundsys->value(); soundsys->callback(cb_deactivate_sounddev, (void*)this); sounddevIn->callback(cb_fetchInChans, this); sounddevOut->callback(cb_fetchOutChans, this); devOutInfo->callback(cb_showOutputInfo, this); devInInfo->callback(cb_showInputInfo, this); if (G_Conf.soundSystem != SYS_API_NONE) { fetchSoundDevs(); fetchOutChans(sounddevOut->value()); fetchInChans(sounddevIn->value()); /* fill frequency dropdown menu */ /* TODO - add fetchFrequencies() */ int nfreq = kernelAudio::getTotalFreqs(sounddevOut->value()); for (int i=0; ivalue(), i); samplerate->add(gItoa(freq).c_str()); if (freq == G_Conf.samplerate) samplerate->value(i); } } else { sounddevIn->deactivate(); sounddevOut->deactivate(); channelsIn->deactivate(); channelsOut->deactivate(); devOutInfo->deactivate(); devInInfo->deactivate(); samplerate->deactivate(); } buffersize->add("8"); buffersize->add("16"); buffersize->add("32"); buffersize->add("64"); buffersize->add("128"); buffersize->add("256"); buffersize->add("512"); buffersize->add("1024"); buffersize->add("2048"); buffersize->add("4096"); buffersize->showItem(gItoa(G_Conf.buffersize).c_str()); rsmpQuality->add("Sinc best quality (very slow)"); rsmpQuality->add("Sinc medium quality (slow)"); rsmpQuality->add("Sinc basic quality (medium)"); rsmpQuality->add("Zero Order Hold (fast)"); rsmpQuality->add("Linear (very fast)"); rsmpQuality->value(G_Conf.rsmpQuality); delayComp->value(gItoa(G_Conf.delayComp).c_str()); delayComp->type(FL_INT_INPUT); delayComp->maximum_size(5); limitOutput->value(G_Conf.limitOutput); } /* -------------------------------------------------------------------------- */ void gTabAudio::cb_deactivate_sounddev(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_deactivate_sounddev(); } void gTabAudio::cb_fetchInChans(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_fetchInChans(); } void gTabAudio::cb_fetchOutChans(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_fetchOutChans(); } void gTabAudio::cb_showInputInfo(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_showInputInfo(); } void gTabAudio::cb_showOutputInfo(Fl_Widget *w, void *p) { ((gTabAudio*)p)->__cb_showOutputInfo(); } /* -------------------------------------------------------------------------- */ void gTabAudio::__cb_fetchInChans() { fetchInChans(sounddevIn->value()); channelsIn->value(0); } /* -------------------------------------------------------------------------- */ void gTabAudio::__cb_fetchOutChans() { fetchOutChans(sounddevOut->value()); channelsOut->value(0); } /* -------------------------------------------------------------------------- */ void gTabAudio::__cb_showInputInfo() { unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value())); new gdDevInfo(dev); } /* -------------------------------------------------------------------------- */ void gTabAudio::__cb_showOutputInfo() { unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value())); new gdDevInfo(dev); } /* -------------------------------------------------------------------------- */ void gTabAudio::__cb_deactivate_sounddev() { /* if the user changes sound system (eg ALSA->JACK) device menu deactivates. * If it returns to the original sound system, we re-fill the list by * querying kernelAudio. Watch out if soundsysInitValue == 0: you don't want * to query kernelAudio for '(none)' soundsystem! */ if (soundsysInitValue == soundsys->value() && soundsysInitValue != 0) { sounddevOut->clear(); sounddevIn->clear(); fetchSoundDevs(); /* the '?' button is added by fetchSoundDevs */ fetchOutChans(sounddevOut->value()); sounddevOut->activate(); channelsOut->activate(); /* chan menus and '?' button are activated by fetchInChans(...) */ fetchInChans(sounddevIn->value()); sounddevIn->activate(); samplerate->activate(); } else { sounddevOut->deactivate(); sounddevOut->clear(); sounddevOut->add("-- restart to fetch device(s) --"); sounddevOut->value(0); channelsOut->deactivate(); devOutInfo->deactivate(); samplerate->deactivate(); sounddevIn->deactivate(); sounddevIn->clear(); sounddevIn->add("-- restart to fetch device(s) --"); sounddevIn->value(0); channelsIn->deactivate(); devInInfo->deactivate(); } } /* -------------------------------------------------------------------------- */ void gTabAudio::fetchInChans(int menuItem) { /* if menuItem==0 device in input is disabled. */ if (menuItem == 0) { devInInfo ->deactivate(); channelsIn->deactivate(); delayComp ->deactivate(); return; } devInInfo ->activate(); channelsIn->activate(); delayComp ->activate(); channelsIn->clear(); unsigned dev = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value())); unsigned chs = kernelAudio::getMaxInChans(dev); if (chs == 0) { channelsIn->add("none"); channelsIn->value(0); return; } for (unsigned i=0; iadd(str); } channelsIn->value(G_Conf.channelsIn); } /* -------------------------------------------------------------------------- */ void gTabAudio::fetchOutChans(int menuItem) { channelsOut->clear(); unsigned dev = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value())); unsigned chs = kernelAudio::getMaxOutChans(dev); if (chs == 0) { channelsOut->add("none"); channelsOut->value(0); return; } for (unsigned i=0; iadd(str); } channelsOut->value(G_Conf.channelsOut); } /* -------------------------------------------------------------------------- */ int gTabAudio::findMenuDevice(gChoice *m, int device) { if (device == -1) return 0; if (G_audio_status == false) return 0; for (int i=0; isize(); i++) { if (kernelAudio::getDeviceName(device) == "") continue; if (m->text(i) == NULL) continue; if (m->text(i) == kernelAudio::getDeviceName(device)) return i; } return 0; } /* -------------------------------------------------------------------------- */ void gTabAudio::fetchSoundDevs() { if (kernelAudio::numDevs == 0) { sounddevOut->add("-- no devices found --"); sounddevOut->value(0); sounddevIn->add("-- no devices found --"); sounddevIn->value(0); devInInfo ->deactivate(); devOutInfo->deactivate(); } else { devInInfo ->activate(); devOutInfo->activate(); /* input device may be disabled: now device number -1 is the disabled * one. KernelAudio knows how to handle it. */ sounddevIn->add("(disabled)"); for (unsigned i=0; i 0) sounddevOut->add(tmp.c_str()); if (kernelAudio::getMaxInChans(i) > 0) sounddevIn->add(tmp.c_str()); } /* we show the device saved in the configuration file. */ if (sounddevOut->size() == 0) { sounddevOut->add("-- no devices found --"); sounddevOut->value(0); devOutInfo->deactivate(); } else { int outMenuValue = findMenuDevice(sounddevOut, G_Conf.soundDeviceOut); sounddevOut->value(outMenuValue); } if (sounddevIn->size() == 0) { sounddevIn->add("-- no devices found --"); sounddevIn->value(0); devInInfo->deactivate(); } else { int inMenuValue = findMenuDevice(sounddevIn, G_Conf.soundDeviceIn); sounddevIn->value(inMenuValue); } } } /* -------------------------------------------------------------------------- */ void gTabAudio::save() { string text = soundsys->text(soundsys->value()); if (text == "(none)") { G_Conf.soundSystem = SYS_API_NONE; return; } #if defined(__linux__) else if (text == "ALSA") G_Conf.soundSystem = SYS_API_ALSA; else if (text == "Jack") G_Conf.soundSystem = SYS_API_JACK; else if (text == "PulseAudio") G_Conf.soundSystem = SYS_API_PULSE; #elif defined(_WIN32) else if (text == "DirectSound") G_Conf.soundSystem = SYS_API_DS; else if (text == "ASIO") G_Conf.soundSystem = SYS_API_ASIO; #elif defined (__APPLE__) else if (text == "CoreAudio") G_Conf.soundSystem = SYS_API_CORE; #endif /* use the device name to search into the drop down menu's */ G_Conf.soundDeviceOut = kernelAudio::getDeviceByName(sounddevOut->text(sounddevOut->value())); G_Conf.soundDeviceIn = kernelAudio::getDeviceByName(sounddevIn->text(sounddevIn->value())); G_Conf.channelsOut = channelsOut->value(); G_Conf.channelsIn = channelsIn->value(); G_Conf.limitOutput = limitOutput->value(); G_Conf.rsmpQuality = rsmpQuality->value(); /* if sounddevOut is disabled (because of system change e.g. alsa -> * jack) its value is equal to -1. Change it! */ if (G_Conf.soundDeviceOut == -1) G_Conf.soundDeviceOut = 0; int bufsize = atoi(buffersize->text()); if (bufsize % 2 != 0) bufsize++; if (bufsize < 8) bufsize = 8; if (bufsize > 8192) bufsize = 8192; G_Conf.buffersize = bufsize; const Fl_Menu_Item *i = NULL; i = samplerate->mvalue(); // mvalue() returns a pointer to the last menu item that was picked if (i) G_Conf.samplerate = atoi(i->label()); G_Conf.delayComp = atoi(delayComp->value()); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gTabMidi::gTabMidi(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, "MIDI") { begin(); system = new gChoice(x()+92, y()+9, 253, 20, "System"); portOut = new gChoice(x()+92, system->y()+system->h()+8, 253, 20, "Output port"); portIn = new gChoice(x()+92, portOut->y()+portOut->h()+8, 253, 20, "Input port"); noNoteOff = new gCheck (x()+92, portIn->y()+portIn->h()+8, 253, 20, "Device does not send NoteOff"); midiMap = new gChoice(x()+92, noNoteOff->y()+noNoteOff->h(), 253, 20, "Output Midi Map"); sync = new gChoice(x()+92, midiMap->y()+midiMap->h()+8, 253, 20, "Sync"); new gBox(x(), sync->y()+sync->h()+8, w(), h()-125, "Restart Giada for the changes to take effect."); end(); labelsize(11); system->callback(cb_changeSystem, (void*)this); fetchSystems(); fetchOutPorts(); fetchInPorts(); fetchMidiMaps(); noNoteOff->value(G_Conf.noNoteOff); sync->add("(disabled)"); sync->add("MIDI Clock (master)"); sync->add("MTC (master)"); if (G_Conf.midiSync == MIDI_SYNC_NONE) sync->value(0); else if (G_Conf.midiSync == MIDI_SYNC_CLOCK_M) sync->value(1); else if (G_Conf.midiSync == MIDI_SYNC_MTC_M) sync->value(2); systemInitValue = system->value(); } /* -------------------------------------------------------------------------- */ void gTabMidi::fetchOutPorts() { if (kernelMidi::numOutPorts == 0) { portOut->add("-- no ports found --"); portOut->value(0); portOut->deactivate(); } else { portOut->add("(disabled)"); for (unsigned i=0; iadd(gu_removeFltkChars(kernelMidi::getOutPortName(i)).c_str()); portOut->value(G_Conf.midiPortOut+1); // +1 because midiPortOut=-1 is '(disabled)' } } /* -------------------------------------------------------------------------- */ void gTabMidi::fetchInPorts() { if (kernelMidi::numInPorts == 0) { portIn->add("-- no ports found --"); portIn->value(0); portIn->deactivate(); } else { portIn->add("(disabled)"); for (unsigned i=0; iadd(gu_removeFltkChars(kernelMidi::getInPortName(i)).c_str()); portIn->value(G_Conf.midiPortIn+1); // +1 because midiPortIn=-1 is '(disabled)' } } /* -------------------------------------------------------------------------- */ void gTabMidi::fetchMidiMaps() { if (G_MidiMap.maps.size() == 0) { midiMap->add("(no MIDI maps available)"); midiMap->value(0); midiMap->deactivate(); return; } for (unsigned i=0; iadd(imap); if (G_Conf.midiMapPath == imap) midiMap->value(i); } } /* -------------------------------------------------------------------------- */ void gTabMidi::save() { string text = system->text(system->value()); if (text == "ALSA") G_Conf.midiSystem = RtMidi::LINUX_ALSA; else if (text == "Jack") G_Conf.midiSystem = RtMidi::UNIX_JACK; else if (text == "Multimedia MIDI") G_Conf.midiSystem = RtMidi::WINDOWS_MM; else if (text == "OSX Core MIDI") G_Conf.midiSystem = RtMidi::MACOSX_CORE; G_Conf.midiPortOut = portOut->value()-1; // -1 because midiPortOut=-1 is '(disabled)' G_Conf.midiPortIn = portIn->value()-1; // -1 because midiPortIn=-1 is '(disabled)' G_Conf.noNoteOff = noNoteOff->value(); G_Conf.midiMapPath = G_MidiMap.maps.size() == 0 ? "" : midiMap->text(midiMap->value()); if (sync->value() == 0) G_Conf.midiSync = MIDI_SYNC_NONE; else if (sync->value() == 1) G_Conf.midiSync = MIDI_SYNC_CLOCK_M; else if (sync->value() == 2) G_Conf.midiSync = MIDI_SYNC_MTC_M; } /* -------------------------------------------------------------------------- */ void gTabMidi::fetchSystems() { #if defined(__linux__) if (kernelMidi::hasAPI(RtMidi::LINUX_ALSA)) system->add("ALSA"); if (kernelMidi::hasAPI(RtMidi::UNIX_JACK)) system->add("Jack"); #elif defined(_WIN32) if (kernelMidi::hasAPI(RtMidi::WINDOWS_MM)) system->add("Multimedia MIDI"); #elif defined (__APPLE__) system->add("OSX Core MIDI"); #endif switch (G_Conf.midiSystem) { case RtMidi::LINUX_ALSA: system->showItem("ALSA"); break; case RtMidi::UNIX_JACK: system->showItem("Jack"); break; case RtMidi::WINDOWS_MM: system->showItem("Multimedia MIDI"); break; case RtMidi::MACOSX_CORE: system->showItem("OSX Core MIDI"); break; default: system->value(0); break; } } /* -------------------------------------------------------------------------- */ void gTabMidi::cb_changeSystem(Fl_Widget *w, void *p) { ((gTabMidi*)p)->__cb_changeSystem(); } /* -------------------------------------------------------------------------- */ void gTabMidi::__cb_changeSystem() { /* if the user changes MIDI device (eg ALSA->JACK) device menu deactivates. * If it returns to the original system, we re-fill the list by * querying kernelMidi. */ if (systemInitValue == system->value()) { portOut->clear(); fetchOutPorts(); portOut->activate(); portIn->clear(); fetchInPorts(); portIn->activate(); noNoteOff->activate(); sync->activate(); } else { portOut->deactivate(); portOut->clear(); portOut->add("-- restart to fetch device(s) --"); portOut->value(0); portIn->deactivate(); portIn->clear(); portIn->add("-- restart to fetch device(s) --"); portIn->value(0); noNoteOff->deactivate(); sync->deactivate(); } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gTabBehaviors::gTabBehaviors(int X, int Y, int W, int H) : Fl_Group(X, Y, W, H, "Behaviors") { begin(); Fl_Group *radioGrp_1 = new Fl_Group(x(), y()+10, w(), 70); // radio group for the mutex new gBox(x(), y()+10, 70, 25, "When a channel with recorded actions is halted:", FL_ALIGN_LEFT); recsStopOnChanHalt_1 = new gRadio(x()+25, y()+35, 280, 20, "stop it immediately"); recsStopOnChanHalt_0 = new gRadio(x()+25, y()+55, 280, 20, "play it until finished"); radioGrp_1->end(); Fl_Group *radioGrp_2 = new Fl_Group(x(), y()+70, w(), 70); // radio group for the mutex new gBox(x(), y()+80, 70, 25, "When the sequencer is halted:", FL_ALIGN_LEFT); chansStopOnSeqHalt_1 = new gRadio(x()+25, y()+105, 280, 20, "stop immediately all dynamic channels"); chansStopOnSeqHalt_0 = new gRadio(x()+25, y()+125, 280, 20, "play all dynamic channels until finished"); radioGrp_2->end(); treatRecsAsLoops = new gCheck(x(), y()+155, 280, 20, "Treat one shot channels with actions as loops"); end(); labelsize(11); G_Conf.recsStopOnChanHalt == 1 ? recsStopOnChanHalt_1->value(1) : recsStopOnChanHalt_0->value(1); G_Conf.chansStopOnSeqHalt == 1 ? chansStopOnSeqHalt_1->value(1) : chansStopOnSeqHalt_0->value(1); G_Conf.treatRecsAsLoops == 1 ? treatRecsAsLoops->value(1) : treatRecsAsLoops->value(0); recsStopOnChanHalt_1->callback(cb_radio_mutex, (void*)this); recsStopOnChanHalt_0->callback(cb_radio_mutex, (void*)this); chansStopOnSeqHalt_1->callback(cb_radio_mutex, (void*)this); chansStopOnSeqHalt_0->callback(cb_radio_mutex, (void*)this); } /* -------------------------------------------------------------------------- */ void gTabBehaviors::cb_radio_mutex(Fl_Widget *w, void *p) { ((gTabBehaviors*)p)->__cb_radio_mutex(w); } /* -------------------------------------------------------------------------- */ void gTabBehaviors::__cb_radio_mutex(Fl_Widget *w) { ((Fl_Button *)w)->type(FL_RADIO_BUTTON); } /* -------------------------------------------------------------------------- */ void gTabBehaviors::save() { G_Conf.recsStopOnChanHalt = recsStopOnChanHalt_1->value() == 1 ? 1 : 0; G_Conf.chansStopOnSeqHalt = chansStopOnSeqHalt_1->value() == 1 ? 1 : 0; G_Conf.treatRecsAsLoops = treatRecsAsLoops->value() == 1 ? 1 : 0; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gdConfig::gdConfig(int w, int h) : gWindow(w, h, "Configuration") { set_modal(); if (G_Conf.configX) resize(G_Conf.configX, G_Conf.configY, this->w(), this->h()); Fl_Tabs *tabs = new Fl_Tabs(8, 8, w-16, h-44); tabAudio = new gTabAudio(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); tabMidi = new gTabMidi(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); tabBehaviors = new gTabBehaviors(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); tabMisc = new gTabMisc(tabs->x()+10, tabs->y()+20, tabs->w()-20, tabs->h()-40); tabs->end(); save = new gClick (w-88, h-28, 80, 20, "Save"); cancel = new gClick (w-176, h-28, 80, 20, "Cancel"); end(); tabs->box(FL_FLAT_BOX); // TODO - G_BOX crashes FLTK 1.3.3 tabs->labelcolor(COLOR_TEXT_0); save->callback(cb_save_config, (void*)this); cancel->callback(cb_cancel, (void*)this); gu_setFavicon(this); setId(WID_CONFIG); show(); } /* -------------------------------------------------------------------------- */ gdConfig::~gdConfig() { G_Conf.configX = x(); G_Conf.configY = y(); } /* -------------------------------------------------------------------------- */ void gdConfig::cb_save_config(Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_save_config(); } void gdConfig::cb_cancel (Fl_Widget *w, void *p) { ((gdConfig*)p)->__cb_cancel(); } /* -------------------------------------------------------------------------- */ void gdConfig::__cb_save_config() { tabAudio->save(); tabBehaviors->save(); tabMidi->save(); tabMisc->save(); do_callback(); } /* -------------------------------------------------------------------------- */ void gdConfig::__cb_cancel() { do_callback(); } giada-0.11.2/src/gui/dialogs/gd_config.h000066400000000000000000000101051264622563000177300ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_config * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_CONFIG_H #define GD_CONFIG_H #include #include #include #include "../elems/ge_window.h" using std::string; class gdConfig : public gWindow { private: static void cb_save_config (Fl_Widget *w, void *p); static void cb_cancel (Fl_Widget *w, void *p); inline void __cb_save_config(); inline void __cb_cancel(); public: gdConfig(int w, int h); ~gdConfig(); class gTabAudio *tabAudio; class gTabBehaviors *tabBehaviors; class gTabMidi *tabMidi; class gTabMisc *tabMisc; class gClick *save; class gClick *cancel; }; /* ------------------------------------------------------------------ */ class gTabMidi : public Fl_Group { private: void fetchSystems(); void fetchOutPorts(); void fetchInPorts(); void fetchMidiMaps(); static void cb_changeSystem (Fl_Widget *w, void *p); inline void __cb_changeSystem(); int systemInitValue; public: class gChoice *system; class gChoice *portOut; class gChoice *portIn; class gCheck *noNoteOff; class gChoice *midiMap; class gChoice *sync; gTabMidi(int x, int y, int w, int h); void save(); }; /* ------------------------------------------------------------------ */ class gTabAudio : public Fl_Group { private: static void cb_deactivate_sounddev(Fl_Widget *w, void *p); static void cb_fetchInChans (Fl_Widget *w, void *p); static void cb_fetchOutChans (Fl_Widget *w, void *p); static void cb_showInputInfo (Fl_Widget *w, void *p); static void cb_showOutputInfo (Fl_Widget *w, void *p); inline void __cb_deactivate_sounddev(); inline void __cb_fetchInChans(); inline void __cb_fetchOutChans(); inline void __cb_showInputInfo(); inline void __cb_showOutputInfo(); void fetchSoundDevs(); void fetchInChans(int menuItem); void fetchOutChans(int menuItem); int findMenuDevice(class gChoice *m, int device); int soundsysInitValue; public: class gChoice *soundsys; class gChoice *samplerate; class gChoice *rsmpQuality; class gChoice *sounddevIn; class gClick *devInInfo; class gChoice *channelsIn; class gChoice *sounddevOut; class gClick *devOutInfo; class gChoice *channelsOut; class gCheck *limitOutput; class gChoice *buffersize; class gInput *delayComp; gTabAudio(int x, int y, int w, int h); void save(); }; /* ------------------------------------------------------------------ */ class gTabBehaviors : public Fl_Group { private: static void cb_radio_mutex (Fl_Widget *w, void *p); inline void __cb_radio_mutex(Fl_Widget *w); public: class gRadio *recsStopOnChanHalt_1; class gRadio *recsStopOnChanHalt_0; class gRadio *chansStopOnSeqHalt_1; class gRadio *chansStopOnSeqHalt_0; class gCheck *treatRecsAsLoops; gTabBehaviors(int x, int y, int w, int h); void save(); }; /* ------------------------------------------------------------------ */ class gTabMisc : public Fl_Group { public: class gChoice *debugMsg; gTabMisc(int x, int y, int w, int h); void save(); }; #endif giada-0.11.2/src/gui/dialogs/gd_devInfo.cpp000066400000000000000000000053751264622563000204250ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_devInfo * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "../../core/kernelAudio.h" #include "../../utils/gui_utils.h" #include "../../utils/utils.h" #include "../elems/ge_mixed.h" #include "gd_devInfo.h" using std::string; gdDevInfo::gdDevInfo(unsigned dev) : Fl_Window(340, 300, "Device information") { set_modal(); text = new gBox(8, 8, 320, 200, "", (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP)); close = new gClick(252, h()-28, 80, 20, "Close"); end(); string body = ""; int lines = 7; body = "Device name: " + kernelAudio::getDeviceName(dev) + "\n"; body += "Total output(s): " + gItoa(kernelAudio::getMaxOutChans(dev)) + "\n"; body += "Total intput(s): " + gItoa(kernelAudio::getMaxInChans(dev)) + "\n"; body += "Duplex channel(s): " + gItoa(kernelAudio::getDuplexChans(dev)) + "\n"; body += "Default output: " + string(kernelAudio::isDefaultOut(dev) ? "yes" : "no") + "\n"; body += "Default input: " + string(kernelAudio::isDefaultIn(dev) ? "yes" : "no") + "\n"; int totalFreq = kernelAudio::getTotalFreqs(dev); body += "Supported frequencies: " + gItoa(totalFreq); for (int i=0; icopy_label(body.c_str()); /* resize the window to fit the content. fl_height() returns the height * of a line. fl_height() * total lines + margins + button size */ resize(x(), y(), w(), (lines * fl_height()) + 8 + 8 + 8 + 20); close->position(close->x(), (lines * fl_height()) + 8 + 8); close->callback(__cb_window_closer, (void*)this); gu_setFavicon(this); show(); } gdDevInfo::~gdDevInfo() {} giada-0.11.2/src/gui/dialogs/gd_devInfo.h000066400000000000000000000025241264622563000200630ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_devInfo * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_DEV_INFO_H #define GD_DEV_INFO_H #include #include class gdDevInfo : public Fl_Window { private: class gBox *text; class gClick *close; public: gdDevInfo(unsigned dev); ~gdDevInfo(); }; #endif giada-0.11.2/src/gui/dialogs/gd_editor.cpp000066400000000000000000000351631264622563000203170ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_editor * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "../../utils/gui_utils.h" #include "../../glue/glue.h" #include "../../core/waveFx.h" #include "../../core/conf.h" #include "../../core/graphics.h" #include "../../core/mixerHandler.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/mixer.h" #include "../../core/wave.h" #include "../elems/ge_waveform.h" #include "../elems/ge_mixed.h" #include "../elems/ge_channel.h" #include "../elems/ge_waveTools.h" #include "../elems/ge_keyboard.h" #include "gd_editor.h" #include "gd_mainWindow.h" #include "gd_warnings.h" extern Mixer G_Mixer; extern gdMainWindow *mainWin; extern Conf G_Conf; gdEditor::gdEditor(SampleChannel *ch) : gWindow(640, 480), ch(ch) { set_non_modal(); if (G_Conf.sampleEditorX) resize(G_Conf.sampleEditorX, G_Conf.sampleEditorY, G_Conf.sampleEditorW, G_Conf.sampleEditorH); /* top bar: grid and zoom tools */ Fl_Group *bar = new Fl_Group(8, 8, w()-16, 20); bar->begin(); grid = new gChoice(bar->x(), bar->y(), 50, 20); snap = new gCheck(grid->x()+grid->w()+4, bar->y()+4, 12, 12); zoomOut = new gClick(bar->x()+bar->w()-20, bar->y(), 20, 20, "", zoomOutOff_xpm, zoomOutOn_xpm); zoomIn = new gClick(zoomOut->x()-24, bar->y(), 20, 20, "", zoomInOff_xpm, zoomInOn_xpm); bar->end(); bar->resizable(new gBox(grid->x()+grid->w()+4, bar->y(), 80, bar->h())); /* waveform */ waveTools = new gWaveTools(8, 36, w()-16, h()-120, ch); waveTools->end(); /* other tools */ Fl_Group *tools = new Fl_Group(8, waveTools->y()+waveTools->h()+8, w()-16, 130); tools->begin(); volume = new gDial (tools->x()+42, tools->y(), 20, 20, "Volume"); volumeNum = new gInput(volume->x()+volume->w()+4, tools->y(), 46, 20, "dB"); boost = new gDial (volumeNum->x()+volumeNum->w()+80, tools->y(), 20, 20, "Boost"); boostNum = new gInput(boost->x()+boost->w()+4, tools->y(), 46, 20, "dB"); normalize = new gClick(boostNum->x()+boostNum->w()+54, tools->y(), 70, 20, "Normalize"); pan = new gDial (normalize->x()+normalize->w()+40, tools->y(), 20, 20, "Pan"); panNum = new gInput(pan->x()+pan->w()+4, tools->y(), 45, 20, "%"); pitch = new gDial (tools->x()+42, volume->y()+volume->h()+4, 20, 20, "Pitch"); pitchNum = new gInput(pitch->x()+pitch->w()+4, volume->y()+volume->h()+4, 46, 20); pitchToBar = new gClick(pitchNum->x()+pitchNum->w()+4, volume->y()+volume->h()+4, 46, 20, "To bar"); pitchToSong = new gClick(pitchToBar->x()+pitchToBar->w()+4, volume->y()+volume->h()+4, 46, 20, "To song"); pitchHalf = new gClick(pitchToSong->x()+pitchToSong->w()+4, volume->y()+volume->h()+4, 21, 20, "÷"); pitchDouble = new gClick(pitchHalf->x()+pitchHalf->w()+4, volume->y()+volume->h()+4, 21, 20, "×"); pitchReset = new gClick(pitchDouble->x()+pitchDouble->w()+4, volume->y()+volume->h()+4, 46, 20, "Reset"); reload = new gClick(pitchReset->x()+pitchReset->w()+4, volume->y()+volume->h()+4, 70, 20, "Reload"); chanStart = new gInput(tools->x()+52, pitch->y()+pitch->h()+4, 60, 20, "Start"); chanEnd = new gInput(chanStart->x()+chanStart->w()+40, pitch->y()+pitch->h()+4, 60, 20, "End"); resetStartEnd = new gClick(chanEnd->x()+chanEnd->w()+4, pitch->y()+pitch->h()+4, 46, 20, "Reset"); tools->end(); tools->resizable(new gBox(panNum->x()+panNum->w()+4, tools->y(), 80, tools->h())); /* grid tool setup */ grid->add("(off)"); grid->add("2"); grid->add("3"); grid->add("4"); grid->add("6"); grid->add("8"); grid->add("16"); grid->add("32"); grid->add("64"); grid->value(G_Conf.sampleEditorGridVal); grid->callback(cb_changeGrid, (void*)this); snap->value(G_Conf.sampleEditorGridOn); snap->callback(cb_enableSnap, (void*)this); /* TODO - redraw grid if != (off) */ char buf[16]; sprintf(buf, "%d", ch->begin / 2); // divided by 2 because stereo chanStart->value(buf); chanStart->type(FL_INT_INPUT); chanStart->callback(cb_setChanPos, this); /* inputs callback: fire when they lose focus or Enter is pressed. */ chanStart->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); chanEnd ->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); sprintf(buf, "%d", ch->end / 2); // divided by 2 because stereo chanEnd->value(buf); chanEnd->type(FL_INT_INPUT); chanEnd->callback(cb_setChanPos, this); resetStartEnd->callback(cb_resetStartEnd, this); volume->callback(cb_setVolume, (void*)this); volume->value(ch->guiChannel->vol->value()); float dB = 20*log10(ch->volume); // dB = 20*log_10(linear value) if (dB > -INFINITY) sprintf(buf, "%.2f", dB); else sprintf(buf, "-inf"); volumeNum->value(buf); volumeNum->align(FL_ALIGN_RIGHT); volumeNum->callback(cb_setVolumeNum, (void*)this); boost->range(1.0f, 10.0f); boost->callback(cb_setBoost, (void*)this); if (ch->boost > 10.f) boost->value(10.0f); else boost->value(ch->boost); boost->when(FL_WHEN_CHANGED | FL_WHEN_RELEASE); float boost = 20*log10(ch->boost); // dB = 20*log_10(linear value) sprintf(buf, "%.2f", boost); boostNum->value(buf); boostNum->align(FL_ALIGN_RIGHT); boostNum->callback(cb_setBoostNum, (void*)this); normalize->callback(cb_normalize, (void*)this); pan->range(0.0f, 2.0f); pan->callback(cb_panning, (void*)this); pitch->range(0.01f, 4.0f); pitch->value(ch->pitch); pitch->callback(cb_setPitch, (void*)this); pitch->when(FL_WHEN_RELEASE); sprintf(buf, "%.4f", ch->pitch); // 4 digits pitchNum->value(buf); pitchNum->align(FL_ALIGN_RIGHT); pitchNum->callback(cb_setPitchNum, (void*)this); pitchNum->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY); pitchToBar->callback(cb_setPitchToBar, (void*)this); pitchToSong->callback(cb_setPitchToSong, (void*)this); pitchHalf->callback(cb_setPitchHalf, (void*)this); pitchDouble->callback(cb_setPitchDouble, (void*)this); pitchReset->callback(cb_resetPitch, (void*)this); reload->callback(cb_reload, (void*)this); zoomOut->callback(cb_zoomOut, (void*)this); zoomIn->callback(cb_zoomIn, (void*)this); /* logical samples (aka takes) cannot be reloaded. So far. */ if (ch->wave->isLogical) reload->deactivate(); if (ch->panRight < 1.0f) { char buf[8]; sprintf(buf, "%d L", abs((ch->panRight * 100.0f) - 100)); pan->value(ch->panRight); panNum->value(buf); } else if (ch->panRight == 1.0f && ch->panLeft == 1.0f) { pan->value(1.0f); panNum->value("C"); } else { char buf[8]; sprintf(buf, "%d R", abs((ch->panLeft * 100.0f) - 100)); pan->value(2.0f - ch->panLeft); panNum->value(buf); } panNum->align(FL_ALIGN_RIGHT); panNum->readonly(1); panNum->cursor_color(FL_WHITE); gu_setFavicon(this); size_range(640, 480); resizable(waveTools); label(ch->wave->name.c_str()); show(); } /* ------------------------------------------------------------------ */ gdEditor::~gdEditor() { G_Conf.sampleEditorX = x(); G_Conf.sampleEditorY = y(); G_Conf.sampleEditorW = w(); G_Conf.sampleEditorH = h(); G_Conf.sampleEditorGridVal = grid->value(); G_Conf.sampleEditorGridOn = snap->value(); } /* ------------------------------------------------------------------ */ void gdEditor::cb_setChanPos (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setChanPos(); } void gdEditor::cb_resetStartEnd (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_resetStartEnd(); } void gdEditor::cb_setVolume (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setVolume(); } void gdEditor::cb_setVolumeNum (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setVolumeNum(); } void gdEditor::cb_setBoost (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setBoost(); } void gdEditor::cb_setBoostNum (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setBoostNum(); } void gdEditor::cb_normalize (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_normalize(); } void gdEditor::cb_panning (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_panning(); } void gdEditor::cb_reload (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_reload(); } void gdEditor::cb_setPitch (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitch(); } void gdEditor::cb_setPitchToBar (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchToBar(); } void gdEditor::cb_setPitchToSong (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchToSong(); } void gdEditor::cb_setPitchHalf (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchHalf(); } void gdEditor::cb_setPitchDouble (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchDouble(); } void gdEditor::cb_resetPitch (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_resetPitch(); } void gdEditor::cb_setPitchNum (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_setPitchNum(); } void gdEditor::cb_zoomIn (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_zoomIn(); } void gdEditor::cb_zoomOut (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_zoomOut(); } void gdEditor::cb_changeGrid (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_changeGrid(); } void gdEditor::cb_enableSnap (Fl_Widget *w, void *p) { ((gdEditor*)p)->__cb_enableSnap(); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_enableSnap() { waveTools->waveform->setSnap(!waveTools->waveform->getSnap()); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setPitchToBar() { glue_setPitch(this, ch, ch->end/(float)G_Mixer.framesPerBar, true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setPitchToSong() { glue_setPitch(this, ch, ch->end/(float)G_Mixer.totalFrames, true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_resetPitch() { glue_setPitch(this, ch, 1.0f, true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setChanPos() { glue_setBeginEndChannel( this, ch, atoi(chanStart->value())*2, // glue halves printed values atoi(chanEnd->value())*2, true ); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_resetStartEnd() { glue_setBeginEndChannel(this, ch, 0, ch->wave->size, true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setVolume() { glue_setVolEditor(this, ch, volume->value(), false); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setVolumeNum() { glue_setVolEditor(this, ch, atof(volumeNum->value()), true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setBoost() { if (Fl::event() == FL_DRAG) glue_setBoost(this, ch, boost->value(), false); else if (Fl::event() == FL_RELEASE) { glue_setBoost(this, ch, boost->value(), false); waveTools->updateWaveform(); } } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setBoostNum() { glue_setBoost(this, ch, atof(boostNum->value()), true); waveTools->updateWaveform(); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_normalize() { float val = wfx_normalizeSoft(ch->wave); glue_setBoost(this, ch, val, false); // we pretend that a fake user turns the dial (numeric=false) if (val < 0.0f) boost->value(0.0f); else if (val > 20.0f) // a dial > than it's max value goes crazy boost->value(10.0f); else boost->value(val); waveTools->updateWaveform(); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_panning() { glue_setPanning(this, ch, pan->value()); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_reload() { if (!gdConfirmWin("Warning", "Reload sample: are you sure?")) return; /* no need for glue_loadChan, there's no gui to refresh */ ch->load(ch->wave->pathfile.c_str()); glue_setBoost(this, ch, DEFAULT_BOOST, true); glue_setPitch(this, ch, gDEFAULT_PITCH, true); glue_setPanning(this, ch, 1.0f); pan->value(1.0f); // glue_setPanning doesn't do it pan->redraw(); // glue_setPanning doesn't do it waveTools->waveform->stretchToWindow(); waveTools->updateWaveform(); glue_setBeginEndChannel(this, ch, 0, ch->wave->size, true); redraw(); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setPitch() { glue_setPitch(this, ch, pitch->value(), false); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setPitchNum() { glue_setPitch(this, ch, atof(pitchNum->value()), true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setPitchHalf() { glue_setPitch(this, ch, pitch->value()/2, true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_setPitchDouble() { glue_setPitch(this, ch, pitch->value()*2, true); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_zoomIn() { waveTools->waveform->setZoom(-1); waveTools->redraw(); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_zoomOut() { waveTools->waveform->setZoom(0); waveTools->redraw(); } /* ------------------------------------------------------------------ */ void gdEditor::__cb_changeGrid() { waveTools->waveform->setGridLevel(atoi(grid->text())); } giada-0.11.2/src/gui/dialogs/gd_editor.h000066400000000000000000000073561264622563000177670ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_editor * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_EDITOR_H #define GD_EDITOR_H #include #include #include #include "../elems/ge_window.h" class gdEditor : public gWindow { private: static void cb_setChanPos (Fl_Widget *w, void *p); static void cb_resetStartEnd (Fl_Widget *w, void *p); static void cb_setVolume (Fl_Widget *w, void *p); static void cb_setVolumeNum (Fl_Widget *w, void *p); static void cb_setBoost (Fl_Widget *w, void *p); static void cb_setBoostNum (Fl_Widget *w, void *p); static void cb_normalize (Fl_Widget *w, void *p); static void cb_panning (Fl_Widget *w, void *p); static void cb_reload (Fl_Widget *w, void *p); static void cb_setPitch (Fl_Widget *w, void *p); static void cb_setPitchToBar (Fl_Widget *w, void *p); static void cb_setPitchToSong(Fl_Widget *w, void *p); static void cb_setPitchHalf (Fl_Widget *w, void *p); static void cb_setPitchDouble(Fl_Widget *w, void *p); static void cb_resetPitch (Fl_Widget *w, void *p); static void cb_setPitchNum (Fl_Widget *w, void *p); static void cb_zoomIn (Fl_Widget *w, void *p); static void cb_zoomOut (Fl_Widget *w, void *p); static void cb_changeGrid (Fl_Widget *w, void *p); static void cb_enableSnap (Fl_Widget *w, void *p); inline void __cb_setChanPos(); inline void __cb_resetStartEnd(); inline void __cb_setVolume(); inline void __cb_setVolumeNum(); inline void __cb_setBoost(); inline void __cb_setBoostNum(); inline void __cb_normalize(); inline void __cb_panning(); inline void __cb_reload(); inline void __cb_setPitch(); inline void __cb_setPitchToBar(); inline void __cb_setPitchToSong(); inline void __cb_setPitchHalf(); inline void __cb_setPitchDouble(); inline void __cb_resetPitch(); inline void __cb_setPitchNum(); inline void __cb_zoomIn(); inline void __cb_zoomOut(); inline void __cb_changeGrid(); inline void __cb_enableSnap(); public: gdEditor(class SampleChannel *ch); ~gdEditor(); class gClick *zoomIn; class gClick *zoomOut; class gWaveTools *waveTools; class gInput *chanStart; class gInput *chanEnd; class gClick *resetStartEnd; class gDial *volume; class gInput *volumeNum; class gDial *boost; class gInput *boostNum; class gClick *normalize; class gDial *pan; class gInput *panNum; class gClick *reload; class gDial *pitch; class gInput *pitchNum; class gClick *pitchToBar; class gClick *pitchToSong; class gClick *pitchHalf; class gClick *pitchDouble; class gClick *pitchReset; class gClick *close; class gChoice *grid; class gCheck *snap; class SampleChannel *ch; }; #endif giada-0.11.2/src/gui/dialogs/gd_keyGrabber.cpp000066400000000000000000000072231264622563000211020ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_keyGrabber * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../utils/gui_utils.h" #include "../../core/conf.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../utils/log.h" #include "../elems/ge_keyboard.h" #include "../elems/ge_mixed.h" #include "../elems/ge_channel.h" #include "../elems/ge_channelButton.h" #include "gd_keyGrabber.h" #include "gd_config.h" #include "gd_mainWindow.h" extern Conf G_Conf; extern gdMainWindow *mainWin; gdKeyGrabber::gdKeyGrabber(Channel *ch) : gWindow(300, 126, "Key configuration"), ch(ch) { set_modal(); text = new gBox(8, 8, 284, 80, ""); clear = new gClick(w()-88, text->y()+text->h()+8, 80, 20, "Clear"); cancel = new gClick(clear->x()-88, clear->y(), 80, 20, "Close"); end(); clear->callback(cb_clear, (void*)this); cancel->callback(cb_cancel, (void*)this); updateText(ch->key); gu_setFavicon(this); show(); } /* -------------------------------------------------------------------------- */ void gdKeyGrabber::cb_clear (Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_clear(); } void gdKeyGrabber::cb_cancel(Fl_Widget *w, void *p) { ((gdKeyGrabber*)p)->__cb_cancel(); } /* -------------------------------------------------------------------------- */ void gdKeyGrabber::__cb_cancel() { do_callback(); } /* -------------------------------------------------------------------------- */ void gdKeyGrabber::__cb_clear() { updateText(0); setButtonLabel(0); } /* -------------------------------------------------------------------------- */ void gdKeyGrabber::setButtonLabel(int key) { char tmp[2]; sprintf(tmp, "%c", key); ch->guiChannel->mainButton->setKey(tmp); ch->key = key; } /* -------------------------------------------------------------------------- */ void gdKeyGrabber::updateText(int key) { char tmp2[64]; if (key != 0) sprintf(tmp2, "Press a key.\n\nCurrent binding: %c", key); else sprintf(tmp2, "Press a key.\n\nCurrent binding: [none]"); text->copy_label(tmp2); } /* -------------------------------------------------------------------------- */ int gdKeyGrabber::handle(int e) { int ret = Fl_Group::handle(e); switch(e) { case FL_KEYUP: { int x = Fl::event_key(); if (strlen(Fl::event_text()) != 0 && x != FL_BackSpace && x != FL_Enter && x != FL_Delete && x != FL_Tab && x != FL_End && x != ' ') { gLog("set key '%c' (%d) for channel %d\n", x, x, ch->index); setButtonLabel(x); updateText(x); break; } else gLog("invalid key\n"); } } return(ret); } giada-0.11.2/src/gui/dialogs/gd_keyGrabber.h000066400000000000000000000032111264622563000205400ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_keyGrabber * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GD_KEYGRABBER_H #define GD_KEYGRABBER_H #include #include "../elems/ge_window.h" class gdKeyGrabber : public gWindow { private: class Channel *ch; class gBox *text; class gClick *clear; class gClick *cancel; static void cb_clear (Fl_Widget *w, void *p); static void cb_cancel(Fl_Widget *w, void *p); inline void __cb_clear (); inline void __cb_cancel(); void setButtonLabel(int key); void updateText(int key); public: gdKeyGrabber(class Channel *ch); int handle(int e); }; #endif giada-0.11.2/src/gui/dialogs/gd_mainWindow.cpp000066400000000000000000000346511264622563000211460ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_mainWindow * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifdef __linux__ #include // for mkdir #endif #include "../../core/graphics.h" #include "../../core/mixer.h" #include "../../core/recorder.h" #include "../../core/mixerHandler.h" #include "../../core/pluginHost.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/init.h" #include "../../core/patch_DEPR_.h" #include "../../core/conf.h" #include "../../glue/glue.h" #include "../elems/ge_keyboard.h" #include "gd_warnings.h" #include "gd_bpmInput.h" #include "gd_beatsInput.h" #include "gd_midiInput.h" #include "gd_about.h" #include "gd_config.h" #include "gd_browser.h" #include "gd_mainWindow.h" #ifdef WITH_VST #include "gd_pluginList.h" #endif extern Mixer G_Mixer; extern Patch_DEPR_ G_Patch_DEPR_; extern Conf G_Conf; extern gdMainWindow *mainWin; extern bool G_quit; extern bool G_audio_status; #if defined(WITH_VST) extern PluginHost G_PluginHost; #endif gdMainWindow::gdMainWindow(int W, int H, const char *title, int argc, char **argv) : gWindow(W, H, title) { Fl::visible_focus(0); Fl::background(25, 25, 25); Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2); // custom box G_BOX size_range(GUI_WIDTH, GUI_HEIGHT); menu = new gMenu(8, -1); inOut = new gInOut(408, 8); controller = new gController(8, 39); timing = new gTiming(632, 39); beatMeter = new gBeatMeter(100, 83, 609, 20); keyboard = new gKeyboard(8, 122, w()-16, 380); /* zone 1 - menus, and I/O tools */ Fl_Group *zone1 = new Fl_Group(8, 8, W-16, 20); zone1->add(menu); zone1->resizable(new Fl_Box(300, 8, 80, 20)); zone1->add(inOut); /* zone 2 - controller and timing tools */ Fl_Group *zone2 = new Fl_Group(8, controller->y(), W-16, controller->h()); zone2->add(controller); zone2->resizable(new Fl_Box(controller->x()+controller->w()+4, zone2->y(), 80, 20)); zone2->add(timing); /* zone 3 - beat meter */ Fl_Group *zone3 = new Fl_Group(8, beatMeter->y(), W-16, beatMeter->h()); zone3->add(beatMeter); /* zone 4 - the keyboard (Fl_Group is unnecessary here, keyboard is * a group by itself) */ resizable(keyboard); add(zone1); add(zone2); add(zone3); add(keyboard); callback(cb_endprogram); gu_setFavicon(this); show(argc, argv); } /* ------------------------------------------------------------------ */ void gdMainWindow::cb_endprogram(Fl_Widget *v, void *p) { mainWin->__cb_endprogram(); } /* ------------------------------------------------------------------ */ void gdMainWindow::__cb_endprogram() { if (!gdConfirmWin("Warning", "Quit Giada: are you sure?")) return; init_shutdown(); hide(); delete this; } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ gInOut::gInOut(int x, int y) : Fl_Group(x, y, 394, 20) { begin(); #if defined(WITH_VST) masterFxIn = new gFxButton (x, y, 20, 20, fxOff_xpm, fxOn_xpm); inVol = new gDial (masterFxIn->x()+masterFxIn->w()+4, y, 20, 20); inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10); inToOut = new gClick (inMeter->x()+inMeter->w()+4, y+5, 10, 10, ""); outMeter = new gSoundMeter(inToOut->x()+inToOut->w()+4, y+5, 140, 10); outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); masterFxOut = new gFxButton (outVol->x()+outVol->w()+4, y, 20, 20, fxOff_xpm, fxOn_xpm); #else inVol = new gDial (x+62, y, 20, 20); inMeter = new gSoundMeter(inVol->x()+inVol->w()+4, y+5, 140, 10); outMeter = new gSoundMeter(inMeter->x()+inMeter->w()+4, y+5, 140, 10); outVol = new gDial (outMeter->x()+outMeter->w()+4, y, 20, 20); #endif end(); resizable(NULL); // don't resize any widget outVol->callback(cb_outVol, (void*)this); outVol->value(G_Mixer.outVol); inVol->callback(cb_inVol, (void*)this); inVol->value(G_Mixer.inVol); #ifdef WITH_VST masterFxOut->callback(cb_masterFxOut, (void*)this); masterFxIn->callback(cb_masterFxIn, (void*)this); inToOut->callback(cb_inToOut, (void*)this); inToOut->type(FL_TOGGLE_BUTTON); #endif } /* ------------------------------------------------------------------ */ void gInOut::cb_outVol (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_outVol(); } void gInOut::cb_inVol (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_inVol(); } #ifdef WITH_VST void gInOut::cb_masterFxOut(Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_masterFxOut(); } void gInOut::cb_masterFxIn (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_masterFxIn(); } void gInOut::cb_inToOut (Fl_Widget *v, void *p) { ((gInOut*)p)->__cb_inToOut(); } #endif /* ------------------------------------------------------------------ */ void gInOut::__cb_outVol() { glue_setOutVol(outVol->value()); } /* ------------------------------------------------------------------ */ void gInOut::__cb_inVol() { glue_setInVol(inVol->value()); } /* ------------------------------------------------------------------ */ #ifdef WITH_VST void gInOut::__cb_masterFxOut() { gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_OUT), WID_FX_LIST); } void gInOut::__cb_masterFxIn() { gu_openSubWindow(mainWin, new gdPluginList(PluginHost::MASTER_IN), WID_FX_LIST); } void gInOut::__cb_inToOut() { G_Mixer.inToOut = inToOut->value(); } #endif /* ------------------------------------------------------------------ */ void gInOut::refresh() { outMeter->mixerPeak = G_Mixer.peakOut; inMeter->mixerPeak = G_Mixer.peakIn; outMeter->redraw(); inMeter->redraw(); } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ gMenu::gMenu(int x, int y) : Fl_Group(x, y, 300, 20) { begin(); file = new gClick(x, y, 70, 21, "file"); edit = new gClick(file->x()+file->w()+4, y, 70, 21, "edit"); config = new gClick(edit->x()+edit->w()+4, y, 70, 21, "config"); about = new gClick(config->x()+config->w()+4, y, 70, 21, "about"); end(); resizable(NULL); // don't resize any widget about->callback(cb_about, (void*)this); file->callback(cb_file, (void*)this); edit->callback(cb_edit, (void*)this); config->callback(cb_config, (void*)this); } /* ------------------------------------------------------------------ */ void gMenu::cb_about (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_about(); } void gMenu::cb_config(Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_config(); } void gMenu::cb_file (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_file(); } void gMenu::cb_edit (Fl_Widget *v, void *p) { ((gMenu*)p)->__cb_edit(); } /* ------------------------------------------------------------------ */ void gMenu::__cb_about() { gu_openSubWindow(mainWin, new gdAbout(), WID_ABOUT); } /* ------------------------------------------------------------------ */ void gMenu::__cb_config() { gu_openSubWindow(mainWin, new gdConfig(380, 370), WID_CONFIG); } /* ------------------------------------------------------------------ */ void gMenu::__cb_file() { /* An Fl_Menu_Button is made of many Fl_Menu_Item */ Fl_Menu_Item menu[] = { {"Open patch or project..."}, {"Save patch..."}, {"Save project..."}, {"Quit Giada"}, {0} }; Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); b->box(G_BOX); b->textsize(11); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); if (!m) return; if (strcmp(m->label(), "Open patch or project...") == 0) { gWindow *childWin = new gdBrowser("Load Patch", G_Conf.patchPath.c_str(), 0, BROWSER_LOAD_PATCH); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Save patch...") == 0) { if (G_Mixer.hasLogicalSamples() || G_Mixer.hasEditedSamples()) if (!gdConfirmWin("Warning", "You should save a project in order to store\nyour takes and/or processed samples.")) return; gWindow *childWin = new gdBrowser("Save Patch", G_Conf.patchPath.c_str(), 0, BROWSER_SAVE_PATCH); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Save project...") == 0) { gWindow *childWin = new gdBrowser("Save Project", G_Conf.patchPath.c_str(), 0, BROWSER_SAVE_PROJECT); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); return; } if (strcmp(m->label(), "Quit Giada") == 0) { mainWin->do_callback(); return; } } /* ------------------------------------------------------------------ */ void gMenu::__cb_edit() { Fl_Menu_Item menu[] = { {"Clear all samples"}, {"Clear all actions"}, {"Remove empty columns"}, {"Reset to init state"}, {"Setup global MIDI input..."}, {0} }; /* clear all actions disabled if no recs, clear all samples disabled * if no samples. */ menu[1].deactivate(); for (unsigned i=0; ihasActions) { menu[1].activate(); break; } for (unsigned i=0; itype == CHANNEL_SAMPLE) if (((SampleChannel*)G_Mixer.channels.at(i))->wave != NULL) { menu[0].activate(); break; } Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); b->box(G_BOX); b->textsize(11); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); if (!m) return; if (strcmp(m->label(), "Clear all samples") == 0) { if (!gdConfirmWin("Warning", "Clear all samples: are you sure?")) return; mainWin->delSubWindow(WID_SAMPLE_EDITOR); glue_clearAllSamples(); return; } if (strcmp(m->label(), "Clear all actions") == 0) { if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) return; mainWin->delSubWindow(WID_ACTION_EDITOR); glue_clearAllRecs(); return; } if (strcmp(m->label(), "Reset to init state") == 0) { if (!gdConfirmWin("Warning", "Reset to init state: are you sure?")) return; gu_closeAllSubwindows(); glue_resetToInitState(); return; } if (strcmp(m->label(), "Remove empty columns") == 0) { mainWin->keyboard->organizeColumns(); return; } if (strcmp(m->label(), "Setup global MIDI input...") == 0) { gu_openSubWindow(mainWin, new gdMidiInputMaster(), 0); return; } } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ gTiming::gTiming(int x, int y) : Fl_Group(x, y, 170, 15) { begin(); quantizer = new gChoice(x, y, 40, 15, "", false); bpm = new gClick (quantizer->x()+quantizer->w()+4, y, 40, 15); meter = new gClick (bpm->x()+bpm->w()+8, y, 40, 15, "4/1"); multiplier = new gClick (meter->x()+meter->w()+4, y, 15, 15, "", beatsMultiplyOff_xpm, beatsMultiplyOn_xpm); divider = new gClick (multiplier->x()+multiplier->w()+4, y, 15, 15, "÷", beatsDivideOff_xpm, beatsDivideOn_xpm); end(); resizable(NULL); // don't resize any widget char buf[6]; snprintf(buf, 6, "%f", G_Mixer.bpm); bpm->copy_label(buf); bpm->callback(cb_bpm, (void*)this); meter->callback(cb_meter, (void*)this); multiplier->callback(cb_multiplier, (void*)this); divider->callback(cb_divider, (void*)this); quantizer->add("off", 0, cb_quantizer, (void*)this); quantizer->add("1b", 0, cb_quantizer, (void*)this); quantizer->add("2b", 0, cb_quantizer, (void*)this); quantizer->add("3b", 0, cb_quantizer, (void*)this); quantizer->add("4b", 0, cb_quantizer, (void*)this); quantizer->add("6b", 0, cb_quantizer, (void*)this); quantizer->add("8b", 0, cb_quantizer, (void*)this); quantizer->value(0); // "off" by default } /* ------------------------------------------------------------------ */ void gTiming::cb_bpm (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_bpm(); } void gTiming::cb_meter (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_meter(); } void gTiming::cb_quantizer (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_quantizer(); } void gTiming::cb_multiplier(Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_multiplier(); } void gTiming::cb_divider (Fl_Widget *v, void *p) { ((gTiming*)p)->__cb_divider(); } /* ------------------------------------------------------------------ */ void gTiming::__cb_bpm() { gu_openSubWindow(mainWin, new gdBpmInput(bpm->label()), WID_BPM); } /* ------------------------------------------------------------------ */ void gTiming::__cb_meter() { gu_openSubWindow(mainWin, new gdBeatsInput(), WID_BEATS); } /* ------------------------------------------------------------------ */ void gTiming::__cb_quantizer() { glue_quantize(quantizer->value()); } /* ------------------------------------------------------------------ */ void gTiming::__cb_multiplier() { glue_beatsMultiply(); } /* ------------------------------------------------------------------ */ void gTiming::__cb_divider() { glue_beatsDivide(); } /* ------------------------------------------------------------------ */ void gTiming::setBpm(const char *v) { bpm->copy_label(v); } void gTiming::setBpm(float v) { char buf[6]; sprintf(buf, "%.01f", v); // only 1 decimal place (e.g. 120.0) bpm->copy_label(buf); } /* ------------------------------------------------------------------ */ void gTiming::setMeter(int beats, int bars) { char buf[8]; sprintf(buf, "%d/%d", beats, bars); meter->copy_label(buf); } giada-0.11.2/src/gui/dialogs/gd_mainWindow.h000066400000000000000000000102761264622563000206100ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * gd_mainWindow * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_MAINWINDOW_H #define GD_MAINWINDOW_H #include #include #include "../elems/ge_mixed.h" #include "../elems/ge_window.h" #include "../elems/ge_controller.h" /* ------------------------------------------------------------------ */ class gdMainWindow : public gWindow { private: static void cb_endprogram (Fl_Widget *v, void *p); inline void __cb_endprogram(); public: class gKeyboard *keyboard; class gBeatMeter *beatMeter; class gMenu *menu; class gInOut *inOut; class gController *controller; class gTiming *timing; gdMainWindow(int w, int h, const char *title, int argc, char **argv); }; /* ------------------------------------------------------------------ */ class gInOut : public Fl_Group { private: class gSoundMeter *outMeter; class gSoundMeter *inMeter; class gDial *outVol; class gDial *inVol; #ifdef WITH_VST class gFxButton *masterFxOut; class gFxButton *masterFxIn; class gClick *inToOut; #endif static void cb_outVol (Fl_Widget *v, void *p); static void cb_inVol (Fl_Widget *v, void *p); #ifdef WITH_VST static void cb_masterFxOut(Fl_Widget *v, void *p); static void cb_masterFxIn (Fl_Widget *v, void *p); static void cb_inToOut (Fl_Widget *v, void *p); #endif inline void __cb_outVol (); inline void __cb_inVol (); #ifdef WITH_VST inline void __cb_masterFxOut(); inline void __cb_masterFxIn (); inline void __cb_inToOut (); #endif public: gInOut(int x, int y); void refresh(); inline void setOutVol(float v) { outVol->value(v); } inline void setInVol (float v) { inVol->value(v); } #ifdef WITH_VST inline void setMasterFxOutFull(bool v) { masterFxOut->full = v; masterFxOut->redraw(); } inline void setMasterFxInFull(bool v) { masterFxIn->full = v; masterFxIn->redraw(); } #endif }; /* ------------------------------------------------------------------ */ class gMenu : public Fl_Group { private: class gClick *file; class gClick *edit; class gClick *config; class gClick *about; static void cb_about (Fl_Widget *v, void *p); static void cb_config(Fl_Widget *v, void *p); static void cb_file (Fl_Widget *v, void *p); static void cb_edit (Fl_Widget *v, void *p); inline void __cb_about (); inline void __cb_config(); inline void __cb_file (); inline void __cb_edit (); public: gMenu(int x, int y); }; /* ------------------------------------------------------------------ */ class gTiming : public Fl_Group { private: class gClick *bpm; class gClick *meter; class gChoice *quantizer; class gClick *multiplier; class gClick *divider; static void cb_bpm (Fl_Widget *v, void *p); static void cb_meter (Fl_Widget *v, void *p); static void cb_quantizer (Fl_Widget *v, void *p); static void cb_multiplier(Fl_Widget *v, void *p); static void cb_divider (Fl_Widget *v, void *p); inline void __cb_bpm(); inline void __cb_meter(); inline void __cb_quantizer(); inline void __cb_multiplier(); inline void __cb_divider(); public: gTiming(int x, int y); void setBpm(const char *v); void setBpm(float v); void setMeter(int beats, int bars); }; #endif giada-0.11.2/src/gui/dialogs/gd_midiInput.cpp000066400000000000000000000133101264622563000207610ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_midiInput * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../utils/gui_utils.h" #include "../../core/kernelMidi.h" #include "../../core/conf.h" #include "../../core/sampleChannel.h" #include "../../utils/log.h" #include "../elems/ge_mixed.h" #include "../elems/ge_midiIoTools.h" #include "gd_midiInput.h" extern Conf G_Conf; gdMidiInput::gdMidiInput(int w, int h, const char *title) : gWindow(w, h, title) { } /* -------------------------------------------------------------------------- */ gdMidiInput::~gdMidiInput() { kernelMidi::stopMidiLearn(); } /* -------------------------------------------------------------------------- */ void gdMidiInput::stopMidiLearn(gLearner *learner) { kernelMidi::stopMidiLearn(); learner->updateValue(); } /* -------------------------------------------------------------------------- */ void gdMidiInput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { *param = msg; stopMidiLearn(l); gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); } /* -------------------------------------------------------------------------- */ void gdMidiInput::cb_learn(uint32_t msg, void *d) { cbData *data = (cbData*) d; gdMidiInput *window = (gdMidiInput*) data->window; gLearner *learner = data->learner; uint32_t *param = learner->param; window->__cb_learn(param, msg, learner); free(data); } /* -------------------------------------------------------------------------- */ void gdMidiInput::cb_close(Fl_Widget *w, void *p) { ((gdMidiInput*)p)->__cb_close(); } /* -------------------------------------------------------------------------- */ void gdMidiInput::__cb_close() { do_callback(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gdMidiInputChannel::gdMidiInputChannel(Channel *ch) : gdMidiInput(300, 206, "MIDI Input Setup"), ch(ch) { char title[64]; sprintf(title, "MIDI Input Setup (channel %d)", ch->index+1); label(title); set_modal(); enable = new gCheck(8, 8, 120, 20, "enable MIDI input"); new gLearner(8, 30, w()-16, "key press", cb_learn, &ch->midiInKeyPress); new gLearner(8, 54, w()-16, "key release", cb_learn, &ch->midiInKeyRel); new gLearner(8, 78, w()-16, "key kill", cb_learn, &ch->midiInKill); new gLearner(8, 102, w()-16, "mute", cb_learn, &ch->midiInMute); new gLearner(8, 126, w()-16, "solo", cb_learn, &ch->midiInSolo); new gLearner(8, 150, w()-16, "volume", cb_learn, &ch->midiInVolume); int yy = 178; if (ch->type == CHANNEL_SAMPLE) { size(300, 254); new gLearner(8, 174, w()-16, "pitch", cb_learn, &((SampleChannel*)ch)->midiInPitch); new gLearner(8, 198, w()-16, "read actions", cb_learn, &((SampleChannel*)ch)->midiInReadActions); yy = 226; } ok = new gButton(w()-88, yy, 80, 20, "Close"); ok->callback(cb_close, (void*)this); enable->value(ch->midiIn); enable->callback(cb_enable, (void*)this); gu_setFavicon(this); show(); } /* -------------------------------------------------------------------------- */ void gdMidiInputChannel::cb_enable(Fl_Widget *w, void *p) { ((gdMidiInputChannel*)p)->__cb_enable(); } /* -------------------------------------------------------------------------- */ void gdMidiInputChannel::__cb_enable() { ch->midiIn = enable->value(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gdMidiInputMaster::gdMidiInputMaster() : gdMidiInput(300, 256, "MIDI Input Setup (global)") { set_modal(); new gLearner(8, 8, w()-16, "rewind", &cb_learn, &G_Conf.midiInRewind); new gLearner(8, 32, w()-16, "play/stop", &cb_learn, &G_Conf.midiInStartStop); new gLearner(8, 56, w()-16, "action recording", &cb_learn, &G_Conf.midiInActionRec); new gLearner(8, 80, w()-16, "input recording", &cb_learn, &G_Conf.midiInInputRec); new gLearner(8, 104, w()-16, "metronome", &cb_learn, &G_Conf.midiInMetronome); new gLearner(8, 128, w()-16, "input volume", &cb_learn, &G_Conf.midiInVolumeIn); new gLearner(8, 152, w()-16, "output volume", &cb_learn, &G_Conf.midiInVolumeOut); new gLearner(8, 176, w()-16, "sequencer ×2", &cb_learn, &G_Conf.midiInBeatDouble); new gLearner(8, 200, w()-16, "sequencer ÷2", &cb_learn, &G_Conf.midiInBeatHalf); ok = new gButton(w()-88, 228, 80, 20, "Close"); ok->callback(cb_close, (void*)this); gu_setFavicon(this); show(); } giada-0.11.2/src/gui/dialogs/gd_midiInput.h000066400000000000000000000044451264622563000204370ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_midiInput * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GD_MIDI_INPUT_H #define GD_MIDI_INPUT_H #include "../../core/kernelMidi.h" #include "../../utils/utils.h" #include "../elems/ge_window.h" #include "../elems/ge_mixed.h" class gdMidiInput : public gWindow { protected: gClick *ok; void stopMidiLearn(class gLearner *l); /* cb_learn * callback attached to kernelMidi to learn various actions. */ static void cb_learn (uint32_t msg, void *data); inline void __cb_learn(uint32_t *param, uint32_t msg, gLearner *l); static void cb_close (Fl_Widget *w, void *p); inline void __cb_close(); public: gdMidiInput(int w, int h, const char *title); ~gdMidiInput(); }; /* -------------------------------------------------------------------------- */ class gdMidiInputChannel : public gdMidiInput { private: class Channel *ch; gCheck *enable; //gVector items; for future use, with vst parameters static void cb_enable (Fl_Widget *w, void *p); inline void __cb_enable(); public: gdMidiInputChannel(class Channel *ch); }; /* -------------------------------------------------------------------------- */ class gdMidiInputMaster : public gdMidiInput { public: gdMidiInputMaster(); }; #endif giada-0.11.2/src/gui/dialogs/gd_midiOutput.cpp000066400000000000000000000165261264622563000211760ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_midiOutput * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/conf.h" #include "../../core/midiChannel.h" #include "../../utils/gui_utils.h" #include "../elems/ge_mixed.h" #include "../elems/ge_channel.h" #include "../elems/ge_midiIoTools.h" #include "../elems/ge_keyboard.h" #include "gd_midiOutput.h" extern Conf G_Conf; gdMidiOutput::gdMidiOutput(int w, int h) //: gWindow(300, 64, "Midi Output Setup") : gWindow(w, h, "Midi Output Setup") { } /* -------------------------------------------------------------------------- */ void gdMidiOutput::stopMidiLearn(gLearner *learner) { kernelMidi::stopMidiLearn(); learner->updateValue(); } /* -------------------------------------------------------------------------- */ void gdMidiOutput::__cb_learn(uint32_t *param, uint32_t msg, gLearner *l) { *param = msg; stopMidiLearn(l); gLog("[gdMidiGrabber] MIDI learn done - message=0x%X\n", msg); } /* -------------------------------------------------------------------------- */ void gdMidiOutput::cb_learn(uint32_t msg, void *d) { cbData *data = (cbData*) d; gdMidiOutput *window = (gdMidiOutput*) data->window; gLearner *learner = data->learner; uint32_t *param = learner->param; window->__cb_learn(param, msg, learner); free(data); } /* -------------------------------------------------------------------------- */ void gdMidiOutput::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutput*)p)->__cb_close(); } /* -------------------------------------------------------------------------- */ void gdMidiOutput::__cb_close() { do_callback(); } /* -------------------------------------------------------------------------- */ void gdMidiOutput::cb_enableLightning(Fl_Widget *w, void *p) { ((gdMidiOutput*)p)->__cb_enableLightning(); } /* -------------------------------------------------------------------------- */ void gdMidiOutput::__cb_enableLightning() {} /* -------------------------------------------------------------------------- */ void gdMidiOutput::setTitle(int chanNum) { char title[64]; sprintf(title, "MIDI Output Setup (channel %d)", chanNum); copy_label(title); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gdMidiOutputMidiCh::gdMidiOutputMidiCh(MidiChannel *ch) : gdMidiOutput(300, 168), ch(ch) { setTitle(ch->index+1); begin(); enableOut = new gCheck(x()+8, y()+8, 150, 20, "Enable MIDI output"); chanListOut = new gChoice(w()-108, y()+8, 100, 20); enableLightning = new gCheck(x()+8, chanListOut->y()+chanListOut->h()+8, 120, 20, "Enable MIDI lightning output"); new gLearner(x()+8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); new gLearner(x()+8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); new gLearner(x()+8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); end(); chanListOut->add("Channel 1"); chanListOut->add("Channel 2"); chanListOut->add("Channel 3"); chanListOut->add("Channel 4"); chanListOut->add("Channel 5"); chanListOut->add("Channel 6"); chanListOut->add("Channel 7"); chanListOut->add("Channel 8"); chanListOut->add("Channel 9"); chanListOut->add("Channel 10"); chanListOut->add("Channel 11"); chanListOut->add("Channel 12"); chanListOut->add("Channel 13"); chanListOut->add("Channel 14"); chanListOut->add("Channel 15"); chanListOut->add("Channel 16"); chanListOut->value(0); if (ch->midiOut) enableOut->value(1); else chanListOut->deactivate(); if (ch->midiOutL) enableLightning->value(1); chanListOut->value(ch->midiOutChan); enableOut->callback(cb_enableChanList, (void*)this); close->callback(cb_close, (void*)this); set_modal(); gu_setFavicon(this); show(); } /* -------------------------------------------------------------------------- */ void gdMidiOutputMidiCh::cb_close (Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_close(); } void gdMidiOutputMidiCh::cb_enableChanList(Fl_Widget *w, void *p) { ((gdMidiOutputMidiCh*)p)->__cb_enableChanList(); } /* -------------------------------------------------------------------------- */ void gdMidiOutputMidiCh::__cb_enableChanList() { enableOut->value() ? chanListOut->activate() : chanListOut->deactivate(); } /* -------------------------------------------------------------------------- */ void gdMidiOutputMidiCh::__cb_close() { ch->midiOut = enableOut->value(); ch->midiOutChan = chanListOut->value(); ch->midiOutL = enableLightning->value(); ch->guiChannel->update(); do_callback(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gdMidiOutputSampleCh::gdMidiOutputSampleCh(SampleChannel *ch) : gdMidiOutput(300, 140), ch(ch) { setTitle(ch->index+1); enableLightning = new gCheck(8, 8, 120, 20, "Enable MIDI lightning output"); new gLearner(8, enableLightning->y()+enableLightning->h()+8, w()-16, "playing", cb_learn, &ch->midiOutLplaying); new gLearner(8, enableLightning->y()+enableLightning->h()+32, w()-16, "mute", cb_learn, &ch->midiOutLmute); new gLearner(8, enableLightning->y()+enableLightning->h()+56, w()-16, "solo", cb_learn, &ch->midiOutLsolo); close = new gButton(w()-88, enableLightning->y()+enableLightning->h()+84, 80, 20, "Close"); close->callback(cb_close, (void*)this); enableLightning->value(ch->midiOutL); enableLightning->callback(cb_enableLightning, (void*)this); set_modal(); gu_setFavicon(this); show(); } /* -------------------------------------------------------------------------- */ void gdMidiOutputSampleCh::cb_close(Fl_Widget *w, void *p) { ((gdMidiOutputSampleCh*)p)->__cb_close(); } /* -------------------------------------------------------------------------- */ void gdMidiOutputSampleCh::__cb_close() { ch->midiOutL = enableLightning->value(); do_callback(); } giada-0.11.2/src/gui/dialogs/gd_midiOutput.h000066400000000000000000000064331264622563000206370ustar00rootroot00000000000000/* ---------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_midiOutput * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_MIDI_OUTPUT_H #define GD_MIDI_OUTPUT_H #include #include #include "../elems/ge_window.h" /* There's no such thing as a gdMidiOutputMaster vs gdMidiOutputChannel. MIDI output master is managed by the configuration window, hence gdMidiOutput deals only with channels. Both MidiOutputMidiCh and MidiOutputSampleCh have the MIDI lighting widget set. In addition MidiOutputMidiCh has the MIDI message output box. */ /* TODO - gdMidiOutput is almost the same thing of gdMidiInput. Create another parent class gdMidiIO to inherit from */ class gdMidiOutput : public gWindow { protected: class gClick *close; class gCheck *enableLightning; void stopMidiLearn(class gLearner *l); /* cb_learn * callback attached to kernelMidi to learn various actions. */ static void cb_learn (uint32_t msg, void *data); inline void __cb_learn(uint32_t *param, uint32_t msg, class gLearner *l); /* cb_close close current window. */ static void cb_close (Fl_Widget *w, void *p); inline void __cb_close(); /* cb_enableLightning enable MIDI lightning output. */ static void cb_enableLightning (Fl_Widget *w, void *p); inline void __cb_enableLightning(); /* setTitle * set window title. */ void setTitle(int chanNum); public: gdMidiOutput(int w, int h); }; /* -------------------------------------------------------------------------- */ class gdMidiOutputMidiCh : public gdMidiOutput { private: static void cb_enableChanList (Fl_Widget *w, void *p); inline void __cb_enableChanList(); /* __cb_close override parent method, we need to do more stuff on close. */ static void cb_close (Fl_Widget *w, void *p); inline void __cb_close(); class gCheck *enableOut; class gChoice *chanListOut; class MidiChannel *ch; public: gdMidiOutputMidiCh(class MidiChannel *ch); }; /* -------------------------------------------------------------------------- */ class gdMidiOutputSampleCh : public gdMidiOutput { private: class SampleChannel *ch; /* __cb_close override parent method, we need to do more stuff on close. */ static void cb_close (Fl_Widget *w, void *p); inline void __cb_close(); public: gdMidiOutputSampleCh(class SampleChannel *ch); }; #endif giada-0.11.2/src/gui/dialogs/gd_pluginList.cpp000066400000000000000000000264721264622563000211660ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_pluginList * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifdef WITH_VST #include "../../utils/gui_utils.h" #include "../../utils/utils.h" #include "../../core/conf.h" #include "../../core/graphics.h" #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/channel.h" #include "../elems/ge_mixed.h" #include "../elems/ge_channel.h" #include "gd_pluginList.h" #include "gd_pluginWindow.h" #include "gd_pluginWindowGUI.h" #include "gd_browser.h" #include "gd_mainWindow.h" extern Conf G_Conf; extern PluginHost G_PluginHost; extern gdMainWindow *mainWin; gdPluginList::gdPluginList(int stackType, Channel *ch) : gWindow(468, 204), ch(ch), stackType(stackType) { if (G_Conf.pluginListX) resize(G_Conf.pluginListX, G_Conf.pluginListY, w(), h()); list = new Fl_Scroll(8, 8, 476, 188); list->type(Fl_Scroll::VERTICAL); list->scrollbar.color(COLOR_BG_0); list->scrollbar.selection_color(COLOR_BG_1); list->scrollbar.labelcolor(COLOR_BD_1); list->scrollbar.slider(G_BOX); list->begin(); refreshList(); list->end(); end(); set_non_modal(); /* TODO - awful stuff... we should subclass into gdPluginListChannel and gdPluginListMaster */ if (stackType == PluginHost::MASTER_OUT) label("Master Out Plugins"); else if (stackType == PluginHost::MASTER_IN) label("Master In Plugins"); else { char tmp[32]; sprintf(tmp, "Channel %d Plugins", ch->index+1); copy_label(tmp); } gu_setFavicon(this); show(); } /* -------------------------------------------------------------------------- */ gdPluginList::~gdPluginList() { G_Conf.pluginListX = x(); G_Conf.pluginListY = y(); } /* -------------------------------------------------------------------------- */ void gdPluginList::cb_addPlugin(Fl_Widget *v, void *p) { ((gdPluginList*)p)->__cb_addPlugin(); } /* -------------------------------------------------------------------------- */ void gdPluginList::cb_refreshList(Fl_Widget *v, void *p) { /* note: this callback is fired by gdBrowser. Close its window first, * by calling the parent (pluginList) and telling it to delete its * subwindow (i.e. gdBrowser). */ gWindow *child = (gWindow*) v; if (child->getParent() != NULL) (child->getParent())->delSubWindow(child); /* finally refresh plugin list: void *p is a pointer to gdPluginList. * This callback works even when you click 'x' to close the window... * well, who cares */ ((gdPluginList*)p)->refreshList(); ((gdPluginList*)p)->redraw(); } /* -------------------------------------------------------------------------- */ void gdPluginList::__cb_addPlugin() { /* the usual callback that gWindow adds to each subwindow in this case * is not enough, because when we close the browser the plugin list * must be redrawn. We have a special callback, cb_refreshList, which * we add to gdBrowser. It does exactly what we need. */ gdBrowser *b = new gdBrowser("Browse Plugin", G_Conf.pluginPath.c_str(), ch, BROWSER_LOAD_PLUGIN, stackType); addSubWindow(b); b->callback(cb_refreshList, (void*)this); // 'this' refers to gdPluginList } /* -------------------------------------------------------------------------- */ void gdPluginList::refreshList() { /* delete the previous list */ list->clear(); list->scroll_to(0, 0); /* add new buttons, as many as the plugin in pluginHost::stack + 1, * the 'add new' button. Warning: if ch == NULL we are working with * master in/master out stacks. */ int numPlugins = G_PluginHost.countPlugins(stackType, ch); int i = 0; while (ix(), list->y()-list->yposition()+(i*24), 800); list->add(gdp); i++; } int addPlugY = numPlugins == 0 ? 90 : list->y()-list->yposition()+(i*24); addPlugin = new gClick(8, addPlugY, 452, 20, "-- add new plugin --"); addPlugin->callback(cb_addPlugin, (void*)this); list->add(addPlugin); /* if num(plugins) > 7 make room for the side scrollbar. * Scrollbar.width = 20 + 4(margin) */ if (i>7) size(492, h()); else size(468, h()); redraw(); /* set 'full' flag to FX button */ /* TODO - awful stuff... we should subclass into gdPluginListChannel and gdPluginListMaster */ if (stackType == PluginHost::MASTER_OUT) { mainWin->inOut->setMasterFxOutFull(G_PluginHost.countPlugins(stackType, ch) > 0); } else if (stackType == PluginHost::MASTER_IN) { mainWin->inOut->setMasterFxInFull(G_PluginHost.countPlugins(stackType, ch) > 0); } else { ch->guiChannel->fx->full = G_PluginHost.countPlugins(stackType, ch) > 0; ch->guiChannel->fx->redraw(); } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gdPlugin::gdPlugin(gdPluginList *gdp, Plugin *p, int X, int Y, int W) : Fl_Group(X, Y, W, 20), pParent(gdp), pPlugin (p) { begin(); button = new gButton(8, y(), 220, 20); program = new gChoice(button->x()+button->w()+4, y(), 132, 20); bypass = new gButton(program->x()+program->w()+4, y(), 20, 20); shiftUp = new gButton(bypass->x()+bypass->w()+4, y(), 20, 20, "", fxShiftUpOff_xpm, fxShiftUpOn_xpm); shiftDown = new gButton(shiftUp->x()+shiftUp->w()+4, y(), 20, 20, "", fxShiftDownOff_xpm, fxShiftDownOn_xpm); remove = new gButton(shiftDown->x()+shiftDown->w()+4, y(), 20, 20, "", fxRemoveOff_xpm, fxRemoveOn_xpm); end(); if (pPlugin->status != 1) { // bad state char name[256]; sprintf(name, "* %s *", gBasename(pPlugin->pathfile).c_str()); button->copy_label(name); } else { char name[256]; pPlugin->getProduct(name); if (strcmp(name, " ")==0) pPlugin->getName(name); button->copy_label(name); button->callback(cb_openPluginWindow, (void*)this); program->callback(cb_setProgram, (void*)this); /* loading vst programs */ /* FIXME - max programs = 128 (unknown source) */ for (int i=0; i<64; i++) { char out[kVstMaxProgNameLen]; pPlugin->getProgramName(i, out); for (int j=0; j 0) program->add(out); } if (program->size() == 0) { program->add("-- no programs --\0"); program->deactivate(); } if (pPlugin->getProgram() == -1) program->value(0); else program->value(pPlugin->getProgram()); bypass->callback(cb_setBypass, (void*)this); bypass->type(FL_TOGGLE_BUTTON); bypass->value(pPlugin->bypass ? 0 : 1); } shiftUp->callback(cb_shiftUp, (void*)this); shiftDown->callback(cb_shiftDown, (void*)this); remove->callback(cb_removePlugin, (void*)this); } /* -------------------------------------------------------------------------- */ void gdPlugin::cb_removePlugin (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_removePlugin(); } void gdPlugin::cb_openPluginWindow(Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_openPluginWindow(); } void gdPlugin::cb_setBypass (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_setBypass(); } void gdPlugin::cb_shiftUp (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_shiftUp(); } void gdPlugin::cb_shiftDown (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_shiftDown(); } void gdPlugin::cb_setProgram (Fl_Widget *v, void *p) { ((gdPlugin*)p)->__cb_setProgram(); } /* -------------------------------------------------------------------------- */ void gdPlugin::__cb_shiftUp() { /*nothing to do if there's only one plugin */ if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1) return; int pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch); if (pluginIndex == 0) // first of the stack, do nothing return; G_PluginHost.swapPlugin(pluginIndex, pluginIndex-1, pParent->stackType, pParent->ch); pParent->refreshList(); } /* -------------------------------------------------------------------------- */ void gdPlugin::__cb_shiftDown() { /*nothing to do if there's only one plugin */ if (G_PluginHost.countPlugins(pParent->stackType, pParent->ch) == 1) return; unsigned pluginIndex = G_PluginHost.getPluginIndex(pPlugin->getId(), pParent->stackType, pParent->ch); unsigned stackSize = (G_PluginHost.getStack(pParent->stackType, pParent->ch))->size(); if (pluginIndex == stackSize-1) // last one in the stack, do nothing return; G_PluginHost.swapPlugin(pluginIndex, pluginIndex+1, pParent->stackType, pParent->ch); pParent->refreshList(); } /* -------------------------------------------------------------------------- */ void gdPlugin::__cb_removePlugin() { /* os x hack: show window before deleting it */ #ifdef __APPLE__ gdPluginWindowGUImac* w = (gdPluginWindowGUImac*) pParent->getChild(pPlugin->getId()+1); if (w) w->show(); #endif /* any subwindow linked to the plugin must be destroyed */ pParent->delSubWindow(pPlugin->getId()+1); G_PluginHost.freePlugin(pPlugin->getId(), pParent->stackType, pParent->ch); pParent->refreshList(); } /* -------------------------------------------------------------------------- */ void gdPlugin::__cb_openPluginWindow() { /* the new pluginWindow has id = id_plugin + 1, because id=0 is reserved * for the window 'add plugin'. */ /* TODO - at the moment you can open a window for each plugin in the stack. * This is not consistent with the rest of the gui. You can avoid this by * calling * * gu_openSubWindow(this, new gdPluginWindow(pPlugin), WID_FX); * * instead of the following code. * * EDIT 2 - having only 1 plugin window would be very uncomfortable */ if (!pParent->hasWindow(pPlugin->getId()+1)) { gWindow *w; if (pPlugin->hasGui()) #ifdef __APPLE__ w = new gdPluginWindowGUImac(pPlugin); #else w = new gdPluginWindowGUI(pPlugin); #endif else w = new gdPluginWindow(pPlugin); w->setId(pPlugin->getId()+1); pParent->addSubWindow(w); } } /* -------------------------------------------------------------------------- */ void gdPlugin::__cb_setBypass() { pPlugin->bypass = !pPlugin->bypass; } /* -------------------------------------------------------------------------- */ void gdPlugin::__cb_setProgram() { pPlugin->setProgram(program->value()); } #endif // #ifdef WITH_VST giada-0.11.2/src/gui/dialogs/gd_pluginList.h000066400000000000000000000056241264622563000206270ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_pluginList * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifdef WITH_VST #ifndef __GD_PLUGINLIST_H__ #define __GD_PLUGINLIST_H__ #include #include #include "../elems/ge_window.h" class gdPluginList : public gWindow { private: class gClick *addPlugin; Fl_Scroll *list; //gVector subWindows; static void cb_addPlugin (Fl_Widget *v, void *p); inline void __cb_addPlugin (); public: class Channel *ch; // ch == NULL ? masterOut int stackType; gdPluginList(int stackType, class Channel *ch=NULL); ~gdPluginList(); /* special callback, passed to browser. When closed (i.e. plugin * has been selected) the same browser will refresh this window. */ static void cb_refreshList(Fl_Widget*, void*); void refreshList(); }; /* -------------------------------------------------------------------------- */ class gdPlugin : public Fl_Group { private: class gdPluginList *pParent; class Plugin *pPlugin; static void cb_removePlugin (Fl_Widget *v, void *p); static void cb_openPluginWindow (Fl_Widget *v, void *p); static void cb_setBypass (Fl_Widget *v, void *p); static void cb_shiftUp (Fl_Widget *v, void *p); static void cb_shiftDown (Fl_Widget *v, void *p); static void cb_setProgram (Fl_Widget *v, void *p); inline void __cb_removePlugin (); inline void __cb_openPluginWindow (); inline void __cb_setBypass (); inline void __cb_shiftUp (); inline void __cb_shiftDown (); inline void __cb_setProgram (); public: class gButton *button; class gChoice *program; class gButton *bypass; class gButton *shiftUp; class gButton *shiftDown; class gButton *remove; gdPlugin(gdPluginList *gdp, class Plugin *p, int x, int y, int w); }; #endif #endif // #ifdef WITH_VST giada-0.11.2/src/gui/dialogs/gd_pluginWindow.cpp000066400000000000000000000065711264622563000215200ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_pluginWindow * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifdef WITH_VST #include #include "../../utils/gui_utils.h" #include "../../core/pluginHost.h" #include "../elems/ge_mixed.h" #include "gd_pluginWindow.h" extern PluginHost G_PluginHost; Parameter::Parameter(int id, Plugin *p, int X, int Y, int W) : Fl_Group(X,Y,W-24,20), id(id), pPlugin(p) { begin(); label = new gBox(x(), y(), 60, 20); char name[kVstMaxParamStrLen]; pPlugin->getParamName(id, name); label->copy_label(name); label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); slider = new gSlider(label->x()+label->w()+8, y(), W-200, 20); slider->value(pPlugin->getParam(id)); slider->callback(cb_setValue, (void *)this); value = new gBox(slider->x()+slider->w()+8, y(), 100, 20); char disp[kVstMaxParamStrLen]; char labl[kVstMaxParamStrLen]; char str [256]; pPlugin->getParamDisplay(id, disp); pPlugin->getParamLabel(id, labl); sprintf(str, "%s %s", disp, labl); value->copy_label(str); value->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); value->box(G_BOX); resizable(slider); end(); } /* ------------------------------------------------------------------ */ void Parameter::cb_setValue(Fl_Widget *v, void *p) { ((Parameter*)p)->__cb_setValue(); } /* ------------------------------------------------------------------ */ void Parameter::__cb_setValue() { pPlugin->setParam(id, slider->value()); char disp[256]; char labl[256]; char str [256]; pPlugin->getParamDisplay(id, disp); pPlugin->getParamLabel(id, labl); sprintf(str, "%s %s", disp, labl); value->copy_label(str); value->redraw(); } /* ------------------------------------------------------------------ */ gdPluginWindow::gdPluginWindow(Plugin *pPlugin) : gWindow(400, 156), pPlugin(pPlugin) // 350 { set_non_modal(); gLiquidScroll *list = new gLiquidScroll(8, 8, w()-16, h()-16); list->type(Fl_Scroll::VERTICAL_ALWAYS); list->begin(); int numParams = pPlugin->getNumParams(); for (int i=0; ix(), list->y()+(i*24), list->w()); list->end(); end(); char name[256]; pPlugin->getProduct(name); if (strcmp(name, " ")==0) pPlugin->getName(name); label(name); size_range(400, (24*1)+12); resizable(list); gu_setFavicon(this); show(); } gdPluginWindow::~gdPluginWindow() {} #endif // #ifdef WITH_VST giada-0.11.2/src/gui/dialogs/gd_pluginWindow.h000066400000000000000000000034711264622563000211610ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_pluginWindow * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifdef WITH_VST #ifndef __GD_PLUGINWINDOW_H__ #define __GD_PLUGINWINDOW_H__ #include #include #include "../elems/ge_window.h" class gdPluginWindow : public gWindow { private: class Plugin *pPlugin; public: int id; gdPluginWindow(Plugin *pPlugin); ~gdPluginWindow(); }; /* ------------------------------------------------------------------ */ class Parameter : public Fl_Group { private: int id; class Plugin *pPlugin; static void cb_setValue(Fl_Widget *v, void *p); inline void __cb_setValue(); public: class gBox *label; class gSlider *slider; class gBox *value; Parameter(int id, class Plugin *p, int x, int y, int w); }; #endif #endif // #ifdef WITH_VST giada-0.11.2/src/gui/dialogs/gd_pluginWindowGUI.cpp000066400000000000000000000126431264622563000220620ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_pluginWindowGUI * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifdef WITH_VST #include "../../utils/log.h" #include "../../utils/gui_utils.h" #include "../../core/pluginHost.h" #include "../elems/ge_mixed.h" #include "gd_pluginWindowGUI.h" extern PluginHost G_PluginHost; gdPluginWindowGUI::gdPluginWindowGUI(Plugin *pPlugin) : gWindow(450, 300), pPlugin(pPlugin) { /* some effects like to have us get their rect before opening them */ ERect *rect; pPlugin->getRect(&rect); gu_setFavicon(this); set_non_modal(); resize(x(), y(), pPlugin->getGuiWidth(), pPlugin->getGuiWidth()); show(); gLog("[gdPluginWindowGUI] open window, w=%d h=%d\n", pPlugin->getGuiWidth(), pPlugin->getGuiWidth()); /* Fl::check(): Waits until "something happens" and then returns. It's * mandatory on linux, otherwise X can't find 'this' window. */ #ifndef __APPLE__ Fl::check(); #endif pPlugin->openGui((void*)fl_xid(this)); char name[256]; pPlugin->getProduct(name); copy_label(name); /* add a pointer to this window to plugin */ pPlugin->window = this; pPlugin->idle(); } /* ------------------------------------------------------------------ */ gdPluginWindowGUI::~gdPluginWindowGUI() { pPlugin->closeGui(); } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ #if defined(__APPLE__) pascal OSStatus gdPluginWindowGUImac::windowHandler(EventHandlerCallRef ehc, EventRef e, void *data) { return ((gdPluginWindowGUImac*)data)->__wh(ehc, e); } /* ------------------------------------------------------------------ */ pascal OSStatus gdPluginWindowGUImac::__wh(EventHandlerCallRef inHandlerCallRef, EventRef inEvent) { OSStatus result = eventNotHandledErr; // let the Carbon Event Manager close the window UInt32 eventClass = GetEventClass(inEvent); UInt32 eventKind = GetEventKind(inEvent); switch (eventClass) { case kEventClassWindow: { switch (eventKind) { case kEventWindowClose: { gLog("[pluginWindowMac] <<< CALLBACK >>> kEventWindowClose for gWindow=%p, window=%p\n", (void*)this, (void*)carbonWindow); show(); break; } case kEventWindowClosed: { gLog("[pluginWindowMac] <<< CALLBACK >>> kEventWindowClosed for gWindow=%p, window=%p\n", (void*)this, (void*)carbonWindow); open = false; result = noErr; break; } } break; } } return result; } /* ------------------------------------------------------------------ */ gdPluginWindowGUImac::gdPluginWindowGUImac(Plugin *pPlugin) : gWindow(450, 300), pPlugin(pPlugin), carbonWindow(NULL) { /* some effects like to have us get their rect before opening them */ ERect *rect; pPlugin->getRect(&rect); /* window initialization */ Rect wRect; wRect.top = rect->top; wRect.left = rect->left; wRect.bottom = rect->bottom; wRect.right = rect->right; int winclass = kDocumentWindowClass; int winattr = kWindowStandardHandlerAttribute | kWindowCloseBoxAttribute | kWindowCompositingAttribute | kWindowAsyncDragAttribute; // winattr &= GetAvailableWindowAttributes(winclass); // make sure that the window will open OSStatus status = CreateNewWindow(winclass, winattr, &wRect, &carbonWindow); if (status != noErr) { gLog("[pluginWindowMac] Unable to create window! Status=%d\n", (int) status); return; } else gLog("[pluginWindowMac] created window=%p\n", (void*)carbonWindow); /* install event handler, called when window is closed */ static EventTypeSpec eventTypes[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowClosed } }; InstallWindowEventHandler(carbonWindow, windowHandler, GetEventTypeCount(eventTypes), eventTypes, this, NULL); /* open window, center it, show it and start the handler */ pPlugin->openGui((void*)carbonWindow); RepositionWindow(carbonWindow, NULL, kWindowCenterOnMainScreen); ShowWindow(carbonWindow); open = true; } /* ------------------------------------------------------------------ */ gdPluginWindowGUImac::~gdPluginWindowGUImac() { gLog("[pluginWindowMac] [[[ destructor ]]] gWindow=%p deleted, window=%p deleted\n", (void*)this, (void*)carbonWindow); pPlugin->closeGui(); if (open) DisposeWindow(carbonWindow); } #endif #endif // #ifdef WITH_VST giada-0.11.2/src/gui/dialogs/gd_pluginWindowGUI.h000066400000000000000000000037441264622563000215310ustar00rootroot00000000000000 /* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_pluginWindowGUI * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifdef WITH_VST #ifndef __GD_PLUGINWINDOW_GUI_H__ #define __GD_PLUGINWINDOW_GUI_H__ #include #include #include "../elems/ge_window.h" #if defined(__APPLE__) #include #endif class gdPluginWindowGUI : public gWindow { private: class Plugin *pPlugin; public: gdPluginWindowGUI(Plugin *pPlugin); ~gdPluginWindowGUI(); }; /* ------------------------------------------------------------------ */ #if defined(__APPLE__) class gdPluginWindowGUImac : public gWindow { private: static pascal OSStatus windowHandler(EventHandlerCallRef ehc, EventRef e, void *data); inline pascal OSStatus __wh(EventHandlerCallRef ehc, EventRef e); class Plugin *pPlugin; WindowRef carbonWindow; bool open; public: gdPluginWindowGUImac(Plugin *pPlugin); ~gdPluginWindowGUImac(); }; #endif #endif // include guard #endif // #ifdef WITH_VST giada-0.11.2/src/gui/dialogs/gd_warnings.cpp000066400000000000000000000042721264622563000206560ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_warnings * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "gd_warnings.h" void gdAlert(const char *c) { Fl_Window *modal = new Fl_Window( (Fl::w() / 2) - 150, (Fl::h() / 2) - 47, 300, 90, "Alert"); modal->set_modal(); modal->begin(); gBox *box = new gBox(10, 10, 280, 40, c); gClick *b = new gClick(210, 60, 80, 20, "Close"); modal->end(); box->labelsize(11); b->callback(__cb_window_closer, (void *)modal); b->shortcut(FL_Enter); gu_setFavicon(modal); modal->show(); } int gdConfirmWin(const char *title, const char *msg) { Fl_Window *win = new Fl_Window( (Fl::w() / 2) - 150, (Fl::h() / 2) - 47, 300, 90, title); win->set_modal(); win->begin(); new gBox(10, 10, 280, 40, msg); gClick *ok = new gClick(212, 62, 80, 20, "Ok"); gClick *ko = new gClick(124, 62, 80, 20, "Cancel"); win->end(); ok->shortcut(FL_Enter); gu_setFavicon(win); win->show(); /* no callbacks here. readqueue() check the event stack. */ int r = 0; while (true) { Fl_Widget *o = Fl::readqueue(); if (!o) Fl::wait(); else if (o == ok) {r = 1; break;} else if (o == ko) {r = 0; break;} } //delete win; win->hide(); return r; } giada-0.11.2/src/gui/dialogs/gd_warnings.h000066400000000000000000000025641264622563000203250ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_warnings * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GD_WARNINGS_H #define GD_WARNINGS_H #include #include #include #include "../elems/ge_mixed.h" #include "../../utils/gui_utils.h" void gdAlert(const char *c); int gdConfirmWin(const char *title, const char *msg); #endif giada-0.11.2/src/gui/elems/000077500000000000000000000000001264622563000153265ustar00rootroot00000000000000giada-0.11.2/src/gui/elems/ge_actionChannel.cpp000066400000000000000000000435341264622563000212640ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionChannel * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../../core/conf.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../glue/glue.h" #include "../../utils/log.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_actionEditor.h" #include "ge_keyboard.h" #include "ge_actionChannel.h" extern gdMainWindow *mainWin; extern Mixer G_Mixer; extern Conf G_Conf; /* ------------------------------------------------------------------ */ gActionChannel::gActionChannel(int x, int y, gdActionEditor *pParent, SampleChannel *ch) : gActionWidget(x, y, 200, 40, pParent), ch(ch), selected(NULL) { size(pParent->totalWidth, h()); /* add actions when the window opens. Their position is zoom-based; * each frame is / 2 because we don't care about stereo infos. */ for (unsigned i=0; ichan == pParent->chan->index) { /* don't show actions > than the grey area */ if (recorder::frames.at(i) > G_Mixer.totalFrames) continue; /* skip the killchan actions in a singlepress channel. They cannot be recorded * in such mode, but they can exist if you change from another mode to singlepress */ if (ra->type == ACTION_KILLCHAN && ch->mode == SINGLE_PRESS) continue; /* also filter out ACTION_KEYREL: it's up to gAction to find the other piece * (namely frame_b) */ if (ra->type & (ACTION_KEYPRESS | ACTION_KILLCHAN)) { int ax = x+(ra->frame/pParent->zoom); gAction *a = new gAction( ax, // x y+4, // y h()-8, // h ra->frame, // frame_a i, // n. of recordings pParent, // pointer to the pParent window ch, // pointer to SampleChannel false, // record = false: don't record it, we are just displaying it! ra->type); // type of action add(a); } } } } end(); // mandatory when you add widgets to a fl_group, otherwise mega malfunctions } /* ------------------------------------------------------------------ */ gAction *gActionChannel::getSelectedAction() { for (int i=0; ix(); int action_w = ((gAction*)child(i))->w(); if (Fl::event_x() >= action_x && Fl::event_x() <= action_x + action_w) return (gAction*)child(i); } return NULL; } /* ------------------------------------------------------------------ */ void gActionChannel::updateActions() { /* when zooming, don't delete and re-add actions, just MOVE them. This * function shifts the action by a zoom factor. Those singlepress are * stretched, as well */ gAction *a; for (int i=0; iframe_a / pParent->zoom); if (ch->mode == SINGLE_PRESS) { int newW = ((a->frame_b - a->frame_a) / pParent->zoom); if (newW < gAction::MIN_WIDTH) newW = gAction::MIN_WIDTH; a->resize(newX, a->y(), newW, a->h()); } else a->resize(newX, a->y(), gAction::MIN_WIDTH, a->h()); } } /* ------------------------------------------------------------------ */ void gActionChannel::draw() { /* draw basic boundaries (+ beat bars) and hide the unused area. Then * draw the children (the actions) */ baseDraw(); /* print label */ fl_color(COLOR_BG_1); fl_font(FL_HELVETICA, 12); if (active()) fl_draw("start/stop", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER)); /// FIXME h() is too much! else fl_draw("start/stop (disabled)", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER)); /// FIXME h() is too much! draw_children(); } /* ------------------------------------------------------------------ */ int gActionChannel::handle(int e) { int ret = Fl_Group::handle(e); /* do nothing if the widget is deactivated. It could happen for loopmode * channels */ if (!active()) return 1; switch (e) { case FL_DRAG: { if (selected != NULL) { // if you don't drag an empty area /* if onLeftEdge o onRightEdge are true it means that you're resizing * an action. Otherwise move the widget. */ if (selected->onLeftEdge || selected->onRightEdge) { /* some checks: a) cannot resize an action < N pixels, b) no beyond zero, * c) no beyond bar maxwidth. Checks for overlap are done in FL_RELEASE */ if (selected->onRightEdge) { int aw = Fl::event_x()-selected->x(); int ah = selected->h(); if (Fl::event_x() < selected->x()+gAction::MIN_WIDTH) aw = gAction::MIN_WIDTH; else if (Fl::event_x() > pParent->coverX) aw = pParent->coverX-selected->x(); selected->size(aw, ah); } else { int ax = Fl::event_x(); int ay = selected->y(); int aw = selected->x()-Fl::event_x()+selected->w(); int ah = selected->h(); if (Fl::event_x() < x()) { ax = x(); aw = selected->w()+selected->x()-x(); } else if (Fl::event_x() > selected->x()+selected->w()-gAction::MIN_WIDTH) { ax = selected->x()+selected->w()-gAction::MIN_WIDTH; aw = gAction::MIN_WIDTH; } selected->resize(ax, ay, aw, ah); } } /* move the widget around */ else { int real_x = Fl::event_x() - actionPickPoint; if (real_x < x()) // don't go beyond the left border selected->position(x(), selected->y()); else if (real_x+selected->w() > pParent->coverX+x()) // don't go beyond the right border selected->position(pParent->coverX+x()-selected->w(), selected->y()); else { if (pParent->gridTool->isOn()) { int snpx = pParent->gridTool->getSnapPoint(real_x-x()) + x() -1; selected->position(snpx, selected->y()); } else selected->position(real_x, selected->y()); } } redraw(); } ret = 1; break; } case FL_PUSH: { if (Fl::event_button1()) { /* avoid at all costs two overlapping actions. We use 'selected' because * the selected action can be reused in FL_DRAG, in case you want to move * it. */ selected = getSelectedAction(); if (selected == NULL) { /* avoid click on grey area */ if (Fl::event_x() >= pParent->coverX) { ret = 1; break; } /* snap function, if enabled */ int ax = Fl::event_x(); int fx = (ax - x()) * pParent->zoom; if (pParent->gridTool->isOn()) { ax = pParent->gridTool->getSnapPoint(ax-x()) + x() -1; fx = pParent->gridTool->getSnapFrame(ax-x()); /* with snap=on an action can fall onto another */ if (actionCollides(fx)) { ret = 1; break; } } gAction *a = new gAction( ax, // x y()+4, // y h()-8, // h fx, // frame_a recorder::frames.size()-1, // n. of actions recorded pParent, // pParent window pointer ch, // pointer to SampleChannel true, // record = true: record it! pParent->getActionType()); // type of action add(a); mainWin->keyboard->setChannelWithActions((gSampleChannel*)ch->guiChannel); // mainWindow update redraw(); ret = 1; } else { actionOriginalX = selected->x(); actionOriginalW = selected->w(); actionPickPoint = Fl::event_x() - selected->x(); ret = 1; // for dragging } } else if (Fl::event_button3()) { gAction *a = getSelectedAction(); if (a != NULL) { a->delAction(); remove(a); delete a; mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); redraw(); ret = 1; } } break; } case FL_RELEASE: { if (selected == NULL) { ret = 1; break; } /* noChanges = true when you click on an action without doing anything * (dragging or moving it). */ bool noChanges = false; if (actionOriginalX == selected->x()) noChanges = true; if (ch->mode == SINGLE_PRESS && actionOriginalX+actionOriginalW != selected->x()+selected->w()) noChanges = false; if (noChanges) { ret = 1; selected = NULL; break; } /* step 1: check if the action doesn't overlap with another one. * In case of overlap the moved action returns to the original X * value ("actionOriginalX"). */ bool overlap = false; for (int i=0; ix(); int action_w = ((gAction*)child(i))->w(); if (ch->mode == SINGLE_PRESS) { /* when 2 segments overlap? * start = the highest value between the two starting points * end = the lowest value between the two ending points * if start < end then there's an overlap of end-start pixels. */ int start = action_x >= selected->x() ? action_x : selected->x(); int end = action_x+action_w < selected->x()+selected->w() ? action_x+action_w : selected->x()+selected->w(); if (start < end) { selected->resize(actionOriginalX, selected->y(), actionOriginalW, selected->h()); redraw(); overlap = true; // one overlap: stop checking } } else { if (selected->x() == action_x) { selected->position(actionOriginalX, selected->y()); redraw(); overlap = true; // one overlap: stop checking } } } /* step 2: no overlap? then update the coordinates of the action, ie * delete the previous rec and create a new one. * Anyway the selected action becomes NULL, because when you release * the mouse button the dragging process ends. */ if (!overlap) { if (pParent->gridTool->isOn()) { int f = pParent->gridTool->getSnapFrame(selected->absx()); selected->moveAction(f); } else selected->moveAction(); } selected = NULL; ret = 1; break; } } return ret; } /* ------------------------------------------------------------------ */ bool gActionChannel::actionCollides(int frame) { /* if SINGLE_PRESS we check that the tail (frame_b) of the action doesn't * overlap the head (frame) of the new one. First the general case, yet. */ bool collision = false; for (int i=0; iframe_a == frame) collision = true; if (ch->mode == SINGLE_PRESS) { for (int i=0; iframe_b && frame >= c->frame_a) collision = true; } } return collision; } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ const int gAction::MIN_WIDTH = 8; /* ------------------------------------------------------------------ */ /** TODO - index is useless? * TODO - pass a record::action pointer and let gAction compute values */ gAction::gAction(int X, int Y, int H, int frame_a, unsigned index, gdActionEditor *parent, SampleChannel *ch, bool record, char type) : Fl_Box (X, Y, MIN_WIDTH, H), selected (false), index (index), parent (parent), ch (ch), type (type), frame_a (frame_a), onRightEdge(false), onLeftEdge (false) { /* bool 'record' defines how to understand the action. * record = false: don't record it, just show it. It happens when you * open the editor with some actions to be shown. * * record = true: record it AND show it. It happens when you click on * an empty area in order to add a new actions. First you record it * (addAction()) then you show it (FLTK::Draw()) */ if (record) addAction(); /* in order to show a singlepress action we must compute the frame_b. We * do that after the possible recording, otherwise we don't know which * key_release is associated. */ if (ch->mode == SINGLE_PRESS && type == ACTION_KEYPRESS) { recorder::action *a2 = NULL; recorder::getNextAction(ch->index, ACTION_KEYREL, frame_a, &a2); if (a2) { frame_b = a2->frame; w((frame_b - frame_a)/parent->zoom); } else gLog("[gActionChannel] frame_b not found! [%d:???]\n", frame_a); /* a singlepress action narrower than 8 pixel is useless. So check it. * Warning: if an action is 8 px narrow, it has no body space to drag * it. It's up to the user to zoom in and drag it. */ if (w() < MIN_WIDTH) size(MIN_WIDTH, h()); } } /* ------------------------------------------------------------------ */ void gAction::draw() { int color; if (selected) /// && gActionChannel !disabled color = COLOR_BD_1; else color = COLOR_BG_2; if (ch->mode == SINGLE_PRESS) { fl_rectf(x(), y(), w(), h(), (Fl_Color) color); } else { if (type == ACTION_KILLCHAN) fl_rect(x(), y(), MIN_WIDTH, h(), (Fl_Color) color); else { fl_rectf(x(), y(), MIN_WIDTH, h(), (Fl_Color) color); if (type == ACTION_KEYPRESS) fl_rectf(x()+3, y()+h()-11, 2, 8, COLOR_BD_0); else if (type == ACTION_KEYREL) fl_rectf(x()+3, y()+3, 2, 8, COLOR_BD_0); } } } /* ------------------------------------------------------------------ */ int gAction::handle(int e) { /* ret = 0 sends the event to the parent window. */ int ret = 0; switch (e) { case FL_ENTER: { selected = true; ret = 1; redraw(); break; } case FL_LEAVE: { fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); selected = false; ret = 1; redraw(); break; } case FL_MOVE: { /* handling of the two margins, left & right. 4 pixels are good enough */ if (ch->mode == SINGLE_PRESS) { onLeftEdge = false; onRightEdge = false; if (Fl::event_x() >= x() && Fl::event_x() < x()+4) { onLeftEdge = true; fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); } else if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) { onRightEdge = true; fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); } else fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); } } } return ret; } /* ------------------------------------------------------------------ */ void gAction::addAction() { /* always check frame parity */ if (frame_a % 2 != 0) frame_a++; /* anatomy of an action * ____[#######]_____ (a) is the left margin, ACTION_KEYPRESS. (b) is * a b the right margin, the ACTION_KEYREL. This is the * theory behind the singleshot.press actions; for any other kind the * (b) is just a graphical and meaningless point. */ if (ch->mode == SINGLE_PRESS) { recorder::rec(parent->chan->index, ACTION_KEYPRESS, frame_a); recorder::rec(parent->chan->index, ACTION_KEYREL, frame_a+4096); //gLog("action added, [%d, %d]\n", frame_a, frame_a+4096); } else { recorder::rec(parent->chan->index, parent->getActionType(), frame_a); //gLog("action added, [%d]\n", frame_a); } recorder::sortActions(); index++; // important! } /* ------------------------------------------------------------------ */ void gAction::delAction() { /* if SINGLE_PRESS you must delete both the keypress and the keyrelease * actions. */ if (ch->mode == SINGLE_PRESS) { recorder::deleteAction(parent->chan->index, frame_a, ACTION_KEYPRESS, false); recorder::deleteAction(parent->chan->index, frame_b, ACTION_KEYREL, false); } else recorder::deleteAction(parent->chan->index, frame_a, type, false); /* restore the initial cursor shape, in case you delete an action and * the double arrow (for resizing) is displayed */ fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); } /* ------------------------------------------------------------------ */ void gAction::moveAction(int frame_a) { /* easy one: delete previous action and record the new ones. As usual, * SINGLE_PRESS requires two jobs. If frame_a is valid, use that frame * value. */ delAction(); if (frame_a != -1) this->frame_a = frame_a; else this->frame_a = xToFrame_a(); /* always check frame parity */ if (this->frame_a % 2 != 0) this->frame_a++; recorder::rec(parent->chan->index, type, this->frame_a); if (ch->mode == SINGLE_PRESS) { frame_b = xToFrame_b(); recorder::rec(parent->chan->index, ACTION_KEYREL, frame_b); } recorder::sortActions(); } /* ------------------------------------------------------------------ */ int gAction::absx() { return x() - parent->ac->x(); } /* ------------------------------------------------------------------ */ int gAction::xToFrame_a() { return (absx()) * parent->zoom; } /* ------------------------------------------------------------------ */ int gAction::xToFrame_b() { return (absx() + w()) * parent->zoom; } giada-0.11.2/src/gui/elems/ge_actionChannel.h000066400000000000000000000070371264622563000207270ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionChannel * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GE_ACTIONCHANNEL_H #define GE_ACTIONCHANNEL_H #include #include #include "../../utils/gui_utils.h" #include "../../core/mixer.h" #include "../../core/recorder.h" #include "ge_actionWidget.h" class gAction : public Fl_Box { private: bool selected; unsigned index; class gdActionEditor *parent; // pointer to parent (gActionEditor) class SampleChannel *ch; char type; // type of action public: gAction(int x, int y, int h, int frame_a, unsigned index, gdActionEditor *parent, class SampleChannel *ch, bool record, char type); void draw(); int handle(int e); void addAction(); void delAction(); /* moveAction * shift the action on the x-axis and update Recorder. If frame_a != -1 * use the new frame in input (used while snapping) */ void moveAction(int frame_a=-1); /* absx * x() is relative to scrolling position. absx() returns the absolute * x value of the action, from the leftmost edge. */ int absx(); /* xToFrame_a,b * return the real frames of x() position */ int xToFrame_a(); int xToFrame_b(); int frame_a; // initial frame (KEYPRESS for singlemode.press) int frame_b; // terminal frame (KEYREL for singlemode.press, null for others) bool onRightEdge; bool onLeftEdge; static const int MIN_WIDTH; }; /* ------------------------------------------------------------------ */ class gActionChannel : public gActionWidget { private: class SampleChannel *ch; /* getSelectedAction * get the action under the mouse. NULL if nothing found. */ gAction *getSelectedAction(); /* selected * pointer to the selected action. Useful when dragging around. */ gAction *selected; /* actionOriginalX, actionOriginalW * x and w of the action, when moved. Useful for checking if the action * overlaps another one: in that case the moved action returns to * actionOriginalX (and to actionOriginalW if resized). */ int actionOriginalX; int actionOriginalW; /* actionPickPoint * the precise x point in which the action has been picked with the mouse, * before a dragging action. */ int actionPickPoint; /* actionCollides * true if an action collides with another. Used while adding new points * with snap active.*/ bool actionCollides(int frame); public: gActionChannel(int x, int y, gdActionEditor *pParent, class SampleChannel *ch); void draw(); int handle(int e); void updateActions(); }; #endif giada-0.11.2/src/gui/elems/ge_actionWidget.cpp000066400000000000000000000054141264622563000211320ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionWidget * * pParent class of any widget inside the action editor. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../../core/mixer.h" #include "../dialogs/gd_actionEditor.h" #include "ge_actionWidget.h" #include "ge_mixed.h" extern Mixer G_Mixer; gActionWidget::gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent) : Fl_Group(x, y, w, h), pParent(pParent) {} /* ------------------------------------------------------------------ */ gActionWidget::~gActionWidget() {} /* ------------------------------------------------------------------ */ void gActionWidget::baseDraw(bool clear) { /* clear the screen */ if (clear) fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN); /* draw the container */ fl_color(COLOR_BD_0); fl_rect(x(), y(), w(), h()); /* grid drawing, if > 1 */ if (pParent->gridTool->getValue() > 1) { fl_color(fl_rgb_color(54, 54, 54)); fl_line_style(FL_DASH, 0, NULL); for (int i=0; i<(int) pParent->gridTool->points.size(); i++) { int px = pParent->gridTool->points.at(i)+x()-1; fl_line(px, y()+1, px, y()+h()-2); } fl_line_style(0); } /* bars and beats drawing */ fl_color(COLOR_BD_0); for (int i=0; i<(int) pParent->gridTool->beats.size(); i++) { int px = pParent->gridTool->beats.at(i)+x()-1; fl_line(px, y()+1, px, y()+h()-2); } fl_color(COLOR_BG_2); for (int i=0; i<(int) pParent->gridTool->bars.size(); i++) { int px = pParent->gridTool->bars.at(i)+x()-1; fl_line(px, y()+1, px, y()+h()-2); } /* cover unused area. Avoid drawing cover if width == 0 (i.e. beats * are 32) */ int coverWidth = pParent->totalWidth-pParent->coverX; if (coverWidth != 0) fl_rectf(pParent->coverX+x(), y()+1, coverWidth, h()-2, COLOR_BG_1); } giada-0.11.2/src/gui/elems/ge_actionWidget.h000066400000000000000000000030611264622563000205730ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_actionWidget * * parent class of any widget inside the action editor. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef __GE_ACTIONWIDGET_H__ #define __GE_ACTIONWIDGET_H__ #include #include #include "../../core/const.h" class gActionWidget : public Fl_Group { protected: class gdActionEditor *pParent; void baseDraw(bool clear=true); public: virtual void updateActions() = 0; gActionWidget(int x, int y, int w, int h, gdActionEditor *pParent); ~gActionWidget(); }; #endif giada-0.11.2/src/gui/elems/ge_browser.cpp000066400000000000000000000161411264622563000201730ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gd_browser * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../../core/const.h" #include "../../utils/utils.h" #include "../../utils/log.h" #include "ge_browser.h" gBrowser::gBrowser(int x, int y, int w, int h, const char *L) : Fl_Hold_Browser(x, y, w, h, L) { box(G_BOX); textsize(11); textcolor(COLOR_TEXT_0); selection_color(COLOR_BG_1); color(COLOR_BG_0); this->scrollbar.color(COLOR_BG_0); this->scrollbar.selection_color(COLOR_BG_1); this->scrollbar.labelcolor(COLOR_BD_1); this->scrollbar.slider(G_BOX); this->hscrollbar.color(COLOR_BG_0); this->hscrollbar.selection_color(COLOR_BG_1); this->hscrollbar.labelcolor(COLOR_BD_1); this->hscrollbar.slider(G_BOX); } /* ------------------------------------------------------------------ */ gBrowser::~gBrowser() {} /* ------------------------------------------------------------------ */ void gBrowser::init(const char *init_path) { gLog("[gBrowser] init path = '%s'\n", init_path); if (init_path == NULL || !gIsDir(init_path)) { #if defined(__linux__) || defined(__APPLE__) path_obj->value("/home"); #elif defined(_WIN32) /* SHGetFolderPath is deprecated. We should use SHGetKnownFolderPath * but that would break compatibility with XP. On Vista, GetFolderPath * is a wrapper of GetKnownFolderPath, so no problem. */ char winRoot[1024]; SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, winRoot); // si parte dal Desktop path_obj->value(winRoot); #endif gLog("[gBrowser] init_path null or invalid, using default\n"); } else path_obj->value(init_path); refresh(); sort(); } /* ------------------------------------------------------------------ */ void gBrowser::refresh() { DIR *dp; struct dirent *ep; dp = opendir(path_obj->value()); if (dp != NULL) { while ((ep = readdir(dp))) { /* skip: * - "." e ".." * - hidden files */ if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) { if (ep->d_name[0] != '.') { /* is it a folder? add square brackets. Is it a file? Append * a '/' (on Windows seems useless, though) */ std::string file = path_obj->value(); file.insert(file.size(), gGetSlash()); file += ep->d_name; if (gIsDir(file.c_str())) { char name[PATH_MAX]; sprintf(name, "@b[%s]", ep->d_name); add(name); } else if (gIsProject(file.c_str())) { char name[PATH_MAX]; sprintf(name, "@i@b%s", ep->d_name); add(name); } else add(ep->d_name); } } } closedir(dp); } else gLog("[gBrowser] Couldn't open the directory '%s'\n", path_obj->value()); } /* ------------------------------------------------------------------ */ void gBrowser::sort() { for (int t=1; t<=size(); t++) for (int r=t+1; r<=size(); r++) if (strcmp(text(t), text(r)) > 0) swap(t,r); } /* ------------------------------------------------------------------ */ void gBrowser::up_dir() { /* updir = remove last folder from the path. Start from strlen(-1) to * skip the trailing slash */ int i = strlen(path_obj->value())-1; /* on Windows an updir from the path "X:\" (3 chars long) must redirect * to the list of available devices. */ #if defined(_WIN32) if (i <= 3 || !strcmp(path_obj->value(), "All drives")) { path_obj->value("All drives"); showDrives(); return; } else { while (i >= 0) { if (path_obj->value()[i] == '\\') break; i--; } /* delete the last part of the string, from i to len-i, ie everything * after the "/" */ std::string tmp = path_obj->value(); tmp.erase(i, tmp.size()-i); /* if tmp.size == 2 we have something like 'C:'. Add a trailing * slash */ if (tmp.size() == 2) tmp += "\\"; path_obj->value(tmp.c_str()); refresh(); } #elif defined(__linux__) || defined (__APPLE__) while (i >= 0) { if (path_obj->value()[i] == '/') break; i--; } /* i == 0 means '/', the root dir. It's meaningless to go updir */ if (i==0) path_obj->value("/"); else { /* delete the last part of the string, from i to len-i, ie everything * after the "/" */ std::string tmp = path_obj->value(); tmp.erase(i, tmp.size()-i); path_obj->value(tmp.c_str()); } refresh(); #endif } /* ------------------------------------------------------------------ */ void gBrowser::down_dir(const char *path) { path_obj->value(path); refresh(); } /* ------------------------------------------------------------------ */ const char *gBrowser::get_selected_item() { /* click on an empty line */ if (text(value()) == NULL) return NULL; selected_item = text(value()); /* @ = formatting marks. * @b = bold, i.e. a directory. Erease '@b[' and ']' */ if (selected_item[0] == '@') { if (selected_item[1] == 'b') { selected_item.erase(0, 3); selected_item.erase(selected_item.size()-1, 1); } else if (selected_item[1] == 'i') selected_item.erase(0, 4); } #if defined(__linux__) || defined(__APPLE__) /* add path to file name, to get an absolute path. Avoid double * slashes like '//' */ if (strcmp("/", path_obj->value())) selected_item.insert(0, "/"); selected_item.insert(0, path_obj->value()); return selected_item.c_str(); #elif defined(_WIN32) /* if path is 'All drives' we are in the devices list and the user * has clicked on a device such as 'X:\' */ if (strcmp(path_obj->value(), "All drives") == 0) return selected_item.c_str(); else { /* add '\' if the path is like 'X:\' */ if (strlen(path_obj->value()) > 3) /// shouln't it be == 3? selected_item.insert(0, "\\"); selected_item.insert(0, path_obj->value()); return selected_item.c_str(); } #endif } /* ------------------------------------------------------------------ */ #ifdef _WIN32 void gBrowser::showDrives() { /* GetLogicalDriveStrings fills drives like that: * * a:\[null]b:\[null]c:\[null]...[null][null] * * where [null] stands for \0. */ char drives[64]; char *i = drives; // pointer to 0th element in drives GetLogicalDriveStrings(64, drives); /* code stolen from the web, still unknown. (Jan 09, 2012). */ while (*i) { add(i); i = &i[strlen(i) + 1]; } } #endif giada-0.11.2/src/gui/elems/ge_browser.h000066400000000000000000000034001264622563000176320ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_browser * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GE_BROWSER_H #define GE_BROWSER_H #include #include #include #include "ge_mixed.h" class gBrowser : public Fl_Hold_Browser { public: gBrowser(int x, int y, int w, int h, const char *L=0); ~gBrowser(); void init(const char *init_path=NULL); void refresh(); void sort(); void up_dir(); void down_dir(const char *path); const char *get_selected_item(); /* path_obj * the actual path*/ class gInput *path_obj; /* selected_item * choosen item */ std::string selected_item; #ifdef _WIN32 private: /* showDrives [WIN32 only] * lists all the available drivers */ void showDrives(); #endif }; #endif giada-0.11.2/src/gui/elems/ge_channel.cpp000066400000000000000000000100241264622563000201120ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_channel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" #include "../../core/wave.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../glue/glue.h" #include "../../utils/gui_utils.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_keyGrabber.h" #include "../dialogs/gd_midiInput.h" #include "../dialogs/gd_editor.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_warnings.h" #include "../dialogs/gd_browser.h" #include "../dialogs/gd_midiOutput.h" #include "ge_keyboard.h" #include "ge_channel.h" #include "ge_sampleChannel.h" #ifdef WITH_VST #include "../dialogs/gd_pluginList.h" #endif extern Mixer G_Mixer; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; gChannel::gChannel(int X, int Y, int W, int H, int type) : Fl_Group(X, Y, W, H, NULL), type(type) {} /* -------------------------------------------------------------------------- */ int gChannel::getColumnIndex() { return ((gColumn*)parent())->getIndex(); } /* -------------------------------------------------------------------------- */ void gChannel::blink() { if (gu_getBlinker() > 6) mainButton->setPlayMode(); else mainButton->setDefaultMode(); } /* -------------------------------------------------------------------------- */ void gChannel::setColorsByStatus(int playStatus, int recStatus) { switch (playStatus) { case STATUS_OFF: mainButton->setDefaultMode(); button->imgOn = channelPlay_xpm; button->imgOff = channelStop_xpm; button->redraw(); break; case STATUS_PLAY: mainButton->setPlayMode(); button->imgOn = channelStop_xpm; button->imgOff = channelPlay_xpm; button->redraw(); break; case STATUS_WAIT: blink(); break; case STATUS_ENDING: mainButton->setEndingMode(); break; } switch (recStatus) { case REC_WAITING: blink(); break; case REC_ENDING: mainButton->setEndingMode(); break; } } /* -------------------------------------------------------------------------- */ int gChannel::handleKey(int e, int key) { int ret; if (e == FL_KEYDOWN && button->value()) // key already pressed! skip it ret = 1; else if (Fl::event_key() == key && !button->value()) { button->take_focus(); // move focus to this button button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state button->do_callback(); // invoke the button's callback ret = 1; } else ret = 0; if (Fl::event_key() == key) button->value((e == FL_KEYDOWN || e == FL_SHORTCUT) ? 1 : 0); // change the button's state return ret; } giada-0.11.2/src/gui/elems/ge_channel.h000066400000000000000000000056701264622563000175720ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_channel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_CHANNEL_H #define GE_CHANNEL_H #include #include #include #include "ge_mixed.h" class gChannel : public Fl_Group { protected: /* define some breakpoints for dynamic resize */ #ifdef WITH_VST static const int BREAK_READ_ACTIONS = 212; static const int BREAK_MODE_BOX = 188; static const int BREAK_FX = 164; static const int BREAK_DELTA = 120; #else static const int BREAK_READ_ACTIONS = 188; static const int BREAK_MODE_BOX = 164; static const int BREAK_FX = 140; static const int BREAK_DELTA = 96; #endif static const int BREAK_UNIT = 24; /* blink * blink button when channel is in wait/ending status. */ void blink(); /* setColorByStatus * update colors depending on channel status. */ void setColorsByStatus(int playStatus, int recStatus); /* handleKey * method wrapped by virtual handle(int e). */ int handleKey(int e, int key); public: gChannel(int x, int y, int w, int h, int type); /* reset * reset channel to initial status. */ virtual void reset() = 0; /* update * update the label of sample button and everything else such as 'R' * button, key box and so on, according to global values. */ virtual void update() = 0; /* refresh * update graphics. */ virtual void refresh() = 0; /* keypress * what to do when the corresponding key is pressed. */ virtual int keyPress(int event) = 0; /* getColumnIndex * return the numeric index of the column in which this channel is * located. */ int getColumnIndex(); class gButton *button; class gStatus *status; class gChannelButton *mainButton; class gDial *vol; class gClick *mute; class gClick *solo; #ifdef WITH_VST class gFxButton *fx; #endif int type; }; #endif giada-0.11.2/src/gui/elems/ge_channelButton.cpp000066400000000000000000000060111264622563000213070ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_channelButton * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/const.h" #include "../../utils/utils.h" #include "ge_channelButton.h" using std::string; gChannelButton::gChannelButton(int x, int y, int w, int h, const char *l) : gClick(x, y, w, h, l), key("") {} /* -------------------------------------------------------------------------- */ void gChannelButton::setKey(const string &k) { key = k; } /* -------------------------------------------------------------------------- */ void gChannelButton::setKey(int k) { if (k == 0) key = ""; else { // FIXME - this crap won't work with unicode/utf-8 char c = (char) k; key = c; } } /* -------------------------------------------------------------------------- */ void gChannelButton::draw() { gClick::draw(); if (key == "") return; /* draw background */ fl_rectf(x()+1, y()+1, 18, h()-2, bgColor0); /* draw key */ fl_color(COLOR_TEXT_0); fl_font(FL_HELVETICA, 11); fl_draw(key.c_str(), x(), y(), 18, h(), FL_ALIGN_CENTER); } /* -------------------------------------------------------------------------- */ void gChannelButton::setInputRecordMode() { bgColor0 = COLOR_BG_3; } /* -------------------------------------------------------------------------- */ void gChannelButton::setActionRecordMode() { bgColor0 = COLOR_BG_4; txtColor = COLOR_TEXT_0; } /* -------------------------------------------------------------------------- */ void gChannelButton::setDefaultMode(const char *l) { bgColor0 = COLOR_BG_0; bdColor = COLOR_BD_0; txtColor = COLOR_TEXT_0; if (l) label(l); } /* -------------------------------------------------------------------------- */ void gChannelButton::setPlayMode() { bgColor0 = COLOR_BG_2; bdColor = COLOR_BD_1; txtColor = COLOR_TEXT_1; } /* -------------------------------------------------------------------------- */ void gChannelButton::setEndingMode() { bgColor0 = COLOR_BD_0; } giada-0.11.2/src/gui/elems/ge_channelButton.h000066400000000000000000000031511264622563000207560ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_channelButton * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_CHANNEL_BUTTON_H #define GE_CHANNEL_BUTTON_H #include "ge_mixed.h" using std::string; class gChannelButton : public gClick { private: string key; public: gChannelButton(int x, int y, int w, int h, const char *l=0); virtual int handle(int e) = 0; void draw(); void setKey(const string &k); void setKey(int k); void setPlayMode(); void setEndingMode(); void setDefaultMode(const char *l=0); void setInputRecordMode(); void setActionRecordMode(); }; #endif giada-0.11.2/src/gui/elems/ge_column.cpp000066400000000000000000000176431264622563000200150ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_column * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/patch_DEPR_.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../glue/glue.h" #include "../../glue/channel.h" #include "../../utils/log.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_warnings.h" #include "../elems/ge_keyboard.h" #include "ge_column.h" #include "ge_channel.h" #include "ge_sampleChannel.h" #include "ge_midiChannel.h" #ifdef WITH_VST #include "../dialogs/gd_pluginList.h" #endif extern Mixer G_Mixer; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; gColumn::gColumn(int X, int Y, int W, int H, int index, gKeyboard *parent) : Fl_Group(X, Y, W, H), parent(parent), index(index) { /* gColumn does a bit of a mess: we pass a pointer to its parent (gKeyboard) and the gColumn itself deals with the creation of another widget, outside gColumn and inside gKeyboard, which handles the vertical resize bar (gResizerBar). The resizer cannot stay inside gColumn: it needs a broader view on the other side widgets. The view can be obtained from gKeyboard only (the upper level). Unfortunately, parent() can be NULL: at this point (i.e the constructor) gColumn is still detached from any parent. We use a custom gKeyboard *parent instead. */ begin(); addChannelBtn = new gClick(x(), y(), w(), 20, "Add new channel"); end(); resizer = new gResizerBar(x()+w(), y(), 16, h(), false); resizer->setMinSize(MIN_COLUMN_WIDTH); parent->add(resizer); addChannelBtn->callback(cb_addChannel, (void*)this); } /* -------------------------------------------------------------------------- */ gColumn::~gColumn() { /* FIXME - this could actually cause a memory leak. resizer is just removed, not deleted. But we cannot delete it right now. */ parent->remove(resizer); } /* -------------------------------------------------------------------------- */ int gColumn::handle(int e) { switch (e) { case FL_RELEASE: { if (Fl::event_button() == FL_RIGHT_MOUSE) { __cb_addChannel(); return 1; } } case FL_DND_ENTER: // return(1) for these events to 'accept' dnd case FL_DND_DRAG: case FL_DND_RELEASE: { return 1; } case FL_PASTE: { // handle actual drop (paste) operation vector paths; gSplit(Fl::event_text(), "\n", &paths); bool fails = false; int result = 0; for (unsigned i=0; iguiChannel); fails = true; } } if (fails) { if (paths.size() > 1) gdAlert("Some files were not loaded successfully."); else parent->printChannelMessage(result); } return 1; } } /* we return fl_Group::handle only if none of the cases above are fired. That is because we don't want to propagate a dnd drop to all the sub widgets. */ return Fl_Group::handle(e); } /* -------------------------------------------------------------------------- */ void gColumn::resize(int X, int Y, int W, int H) { /* resize all children */ int ch = children(); for (int i=0; iresize(X, Y + (i * (c->h() + 4)), W, c->h()); } /* resize group itself */ x(X); y(Y); w(W); h(H); /* resize resizerBar */ resizer->size(16, H); } /* -------------------------------------------------------------------------- */ void gColumn::refreshChannels() { for (int i=1; irefresh(); } /* -------------------------------------------------------------------------- */ void gColumn::draw() { fl_color(fl_rgb_color(27, 27, 27)); fl_rectf(x(), y(), w(), h()); /* call draw and then redraw in order to avoid channel corruption when scrolling horizontally */ for (int i=0; idraw(); child(i)->redraw(); } } /* -------------------------------------------------------------------------- */ void gColumn::cb_addChannel(Fl_Widget *v, void *p) { ((gColumn*)p)->__cb_addChannel(); } /* -------------------------------------------------------------------------- */ gChannel *gColumn::addChannel(class Channel *ch) { int currentY = y() + children() * 24; gChannel *gch = NULL; if (ch->type == CHANNEL_SAMPLE) gch = (gSampleChannel*) new gSampleChannel(x(), currentY, w(), 20, (SampleChannel*) ch); else gch = (gMidiChannel*) new gMidiChannel(x(), currentY, w(), 20, (MidiChannel*) ch); add(gch); resize(x(), y(), w(), (children() * 24) + 66); // evil space for drag n drop gch->redraw(); // avoid corruption parent->redraw(); // redraw Keyboard return gch; } /* -------------------------------------------------------------------------- */ void gColumn::deleteChannel(gChannel *gch) { gch->hide(); remove(gch); delete gch; /* reposition all other channels and resize this group */ /** TODO * reposition is useless when called by gColumn::clear(). Add a new * parameter to skip the operation */ for (int i=0; iposition(gch->x(), y()+(i*24)); } size(w(), children() * 24 + 66); // evil space for drag n drop redraw(); } /* -------------------------------------------------------------------------- */ void gColumn::__cb_addChannel() { gLog("[gColumn::__cb_addChannel] index = %d\n", index); int type = openTypeMenu(); if (type) glue_addChannel(index, type); } /* -------------------------------------------------------------------------- */ int gColumn::openTypeMenu() { Fl_Menu_Item rclick_menu[] = { {"Sample channel"}, {"MIDI channel"}, {0} }; Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); b->box(G_BOX); b->textsize(11); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); if (!m) return 0; if (strcmp(m->label(), "Sample channel") == 0) return CHANNEL_SAMPLE; if (strcmp(m->label(), "MIDI channel") == 0) return CHANNEL_MIDI; return 0; } /* -------------------------------------------------------------------------- */ void gColumn::clear(bool full) { if (full) Fl_Group::clear(); else { while (children() >= 2) { // skip "add new channel" btn int i = children()-1; deleteChannel((gChannel*)child(i)); } } } /* -------------------------------------------------------------------------- */ Channel *gColumn::getChannel(int i) { gChannel *gch = (gChannel*) child(i); if (gch->type == CHANNEL_SAMPLE) return ((gSampleChannel*) child(i))->ch; else return ((gMidiChannel*) child(i))->ch; } giada-0.11.2/src/gui/elems/ge_column.h000066400000000000000000000050231264622563000174470ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_column * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_COLUMN_H #define GE_COLUMN_H #include #include class gColumn : public Fl_Group { private: static void cb_addChannel (Fl_Widget *v, void *p); inline void __cb_addChannel(); int openTypeMenu(); class gClick *addChannelBtn; class gResizerBar *resizer; class gKeyboard *parent; int index; public: gColumn(int x, int y, int w, int h, int index, class gKeyboard *parent); ~gColumn(); /* addChannel * add a new channel in this column and set the internal pointer * to channel to 'ch'. */ class gChannel *addChannel(class Channel *ch); /* handle */ int handle(int e); /* resize * custom resize behavior. */ void resize(int x, int y, int w, int h); /* deleteChannel * remove the channel 'gch' from this column. */ void deleteChannel(gChannel *gch); /* refreshChannels * update channels' graphical statues. Called on each GUI cycle. */ void refreshChannels(); /* getChannel */ Channel *getChannel(int i); /* clear * remove all channels from the column. If full==true, delete also the * "add new channel" button. This method ovverrides the inherited one * from Fl_Group. */ void clear(bool full=false); void draw(); inline int getIndex() { return index; } inline void setIndex(int i) { index = i; } inline bool isEmpty() { return children() == 1; } inline int countChannels() { return children(); } }; #endif giada-0.11.2/src/gui/elems/ge_controller.cpp000066400000000000000000000101071264622563000206670ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * ge_controller * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/graphics.h" #include "../../glue/glue.h" #include "ge_mixed.h" #include "ge_controller.h" gController::gController(int x, int y) : Fl_Group(x, y, 131, 25) { begin(); rewind = new gClick(x, y, 25, 25, "", rewindOff_xpm, rewindOn_xpm); play = new gClick(rewind->x()+rewind->w()+4, y, 25, 25, "", play_xpm, pause_xpm); recAction = new gClick(play->x()+play->w()+4, y, 25, 25, "", recOff_xpm, recOn_xpm); recInput = new gClick(recAction->x()+recAction->w()+4, y, 25, 25, "", inputRecOff_xpm, inputRecOn_xpm); metronome = new gClick(recInput->x()+recInput->w()+4, y+10, 15, 15, "", metronomeOff_xpm, metronomeOn_xpm); end(); resizable(NULL); // don't resize any widget rewind->callback(cb_rewind, (void*)this); play->callback(cb_play); play->type(FL_TOGGLE_BUTTON); recAction->callback(cb_recAction, (void*)this); recAction->type(FL_TOGGLE_BUTTON); recInput->callback(cb_recInput, (void*)this); recInput->type(FL_TOGGLE_BUTTON); metronome->callback(cb_metronome); metronome->type(FL_TOGGLE_BUTTON); } /* -------------------------------------------------------------------------- */ void gController::cb_rewind (Fl_Widget *v, void *p) { ((gController*)p)->__cb_rewind(); } void gController::cb_play (Fl_Widget *v, void *p) { ((gController*)p)->__cb_play(); } void gController::cb_recAction(Fl_Widget *v, void *p) { ((gController*)p)->__cb_recAction(); } void gController::cb_recInput (Fl_Widget *v, void *p) { ((gController*)p)->__cb_recInput(); } void gController::cb_metronome(Fl_Widget *v, void *p) { ((gController*)p)->__cb_metronome(); } /* -------------------------------------------------------------------------- */ void gController::__cb_rewind() { glue_rewindSeq(); } /* -------------------------------------------------------------------------- */ void gController::__cb_play() { glue_startStopSeq(); } /* -------------------------------------------------------------------------- */ void gController::__cb_recAction() { glue_startStopActionRec(); } /* -------------------------------------------------------------------------- */ void gController::__cb_recInput() { glue_startStopInputRec(); } /* -------------------------------------------------------------------------- */ void gController::__cb_metronome() { glue_startStopMetronome(); } /* -------------------------------------------------------------------------- */ void gController::updatePlay(int v) { play->value(v); play->redraw(); } /* -------------------------------------------------------------------------- */ void gController::updateMetronome(int v) { metronome->value(v); metronome->redraw(); } /* -------------------------------------------------------------------------- */ void gController::updateRecInput(int v) { recInput->value(v); recInput->redraw(); } /* -------------------------------------------------------------------------- */ void gController::updateRecAction(int v) { recAction->value(v); recAction->redraw(); } giada-0.11.2/src/gui/elems/ge_controller.h000066400000000000000000000036611264622563000203430ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * ge_controller * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_CONTROLLER_H #define GE_CONTROLLER_H #include class gController : public Fl_Group { private: class gClick *rewind; class gClick *play; class gClick *recAction; class gClick *recInput; class gClick *metronome; static void cb_rewind (Fl_Widget *v, void *p); static void cb_play (Fl_Widget *v, void *p); static void cb_recAction(Fl_Widget *v, void *p); static void cb_recInput (Fl_Widget *v, void *p); static void cb_metronome(Fl_Widget *v, void *p); inline void __cb_rewind (); inline void __cb_play (); inline void __cb_recAction(); inline void __cb_recInput (); inline void __cb_metronome(); public: gController(int x, int y); void updatePlay (int v); void updateMetronome(int v); void updateRecInput (int v); void updateRecAction(int v); }; #endif giada-0.11.2/src/gui/elems/ge_envelopeChannel.cpp000066400000000000000000000233041264622563000216150ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_envelopeWidget * * Parent class of any envelope controller, from volume to VST parameter * automations. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../../core/channel.h" #include "../../core/recorder.h" #include "../../core/mixer.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_mainWindow.h" #include "ge_keyboard.h" #include "ge_envelopeChannel.h" extern Mixer G_Mixer; extern gdMainWindow *mainWin; gEnvelopeChannel::gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l) : gActionWidget(x, y, 200, 80, pParent), l(l), type(type), range(range), selectedPoint(-1), draggedPoint(-1) { size(pParent->totalWidth, h()); } /* ------------------------------------------------------------------ */ gEnvelopeChannel::~gEnvelopeChannel() { clearPoints(); } /* ------------------------------------------------------------------ */ void gEnvelopeChannel::addPoint(int frame, int iValue, float fValue, int px, int py) { point p; p.frame = frame; p.iValue = iValue; p.fValue = fValue; p.x = px; p.y = py; points.push_back(p); } /* ------------------------------------------------------------------ */ void gEnvelopeChannel::updateActions() { for (unsigned i=0; izoom; } /* ------------------------------------------------------------------ */ void gEnvelopeChannel::draw() { baseDraw(); /* print label */ fl_color(COLOR_BG_1); fl_font(FL_HELVETICA, 12); fl_draw(l, x()+4, y(), 80, h(), (Fl_Align) (FL_ALIGN_LEFT)); int pxOld = x()-3; int pyOld = y()+1; int pxNew = 0; int pyNew = 0; fl_color(COLOR_BG_2); for (unsigned i=0; i 0) fl_line(pxOld+3, pyOld+3, pxNew+3, pyNew+3); pxOld = pxNew; pyOld = pyNew; } } /* ------------------------------------------------------------------ */ int gEnvelopeChannel::handle(int e) { /* Adding an action: no further checks required, just record it on frame * mx*pParent->zoom. Deleting action is trickier: find the active * point and derive from it the corresponding frame. */ int ret = 0; int mx = Fl::event_x()-x(); // mouse x int my = Fl::event_y()-y(); // mouse y switch (e) { case FL_ENTER: { ret = 1; break; } case FL_MOVE: { selectedPoint = getSelectedPoint(); redraw(); ret = 1; break; } case FL_LEAVE: { draggedPoint = -1; selectedPoint = -1; redraw(); ret = 1; break; } case FL_PUSH: { /* left click on point: drag * right click on point: delete * left click on void: add */ if (Fl::event_button1()) { if (selectedPoint != -1) { draggedPoint = selectedPoint; } else { /* top & border fix */ if (my > h()-8) my = h()-8; if (mx > pParent->coverX-x()) mx = pParent->coverX-x(); if (range == RANGE_FLOAT) { /* if this is the first point ever, add other two points at the beginning * and the end of the range */ if (points.size() == 0) { addPoint(0, 0, 1.0f, 0, 1); recorder::rec(pParent->chan->index, type, 0, 0, 1.0f); addPoint(G_Mixer.totalFrames, 0, 1.0f, pParent->coverX, 1); recorder::rec(pParent->chan->index, type, G_Mixer.totalFrames, 0, 1.0f); } /* line between 2 points y = (x-a) / (b-a); a = h() - 8; b = 1 */ int frame = mx * pParent->zoom; float value = (my - h() + 8) / (float) (1 - h() + 8); addPoint(frame, 0, value, mx, my); recorder::rec(pParent->chan->index, type, frame, 0, value); recorder::sortActions(); sortPoints(); } else { /// TODO } mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow redraw(); } } else { /* right click on point 0 or point size-1 deletes the entire envelope */ if (selectedPoint != -1) { if (selectedPoint == 0 || (unsigned) selectedPoint == points.size()-1) { recorder::clearAction(pParent->chan->index, type); points.clear(); } else { recorder::deleteAction(pParent->chan->index, points.at(selectedPoint).frame, type, false); recorder::sortActions(); points.erase(points.begin() + selectedPoint); } mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow redraw(); } } ret = 1; break; } case FL_RELEASE: { if (draggedPoint != -1) { if (points.at(draggedPoint).x == previousXPoint) { //gLog("nothing to do\n"); } else { int newFrame = points.at(draggedPoint).x * pParent->zoom; /* x edge correction */ if (newFrame < 0) newFrame = 0; else if (newFrame > G_Mixer.totalFrames) newFrame = G_Mixer.totalFrames; /* vertical line check */ int vp = verticalPoint(points.at(draggedPoint)); if (vp == 1) newFrame -= 256; else if (vp == -1) newFrame += 256; /* delete previous point and record a new one */ recorder::deleteAction(pParent->chan->index, points.at(draggedPoint).frame, type, false); if (range == RANGE_FLOAT) { float value = (points.at(draggedPoint).y - h() + 8) / (float) (1 - h() + 8); recorder::rec(pParent->chan->index, type, newFrame, 0, value); } else { /// TODO } recorder::sortActions(); points.at(draggedPoint).frame = newFrame; draggedPoint = -1; selectedPoint = -1; } } ret = 1; break; } case FL_DRAG: { if (draggedPoint != -1) { /* y constraint */ if (my > h()-8) points.at(draggedPoint).y = h()-8; else if (my < 1) points.at(draggedPoint).y = 1; else points.at(draggedPoint).y = my; /* x constraint * constrain the point between two ends (leftBorder-point, point-point, * point-rightBorder). First & last points cannot be shifted on x */ if (draggedPoint == 0) points.at(draggedPoint).x = x()-8; else if ((unsigned) draggedPoint == points.size()-1) points.at(draggedPoint).x = pParent->coverX; else { int prevPoint = points.at(draggedPoint-1).x; int nextPoint = points.at(draggedPoint+1).x; if (mx <= prevPoint) points.at(draggedPoint).x = prevPoint; else if (mx >= nextPoint) points.at(draggedPoint).x = nextPoint; //else // points.at(draggedPoint).x = mx; else { if (pParent->gridTool->isOn()) points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mx)-1; else points.at(draggedPoint).x = mx; } } redraw(); } ret = 1; break; } } return ret; } /* ------------------------------------------------------------------ */ int gEnvelopeChannel::verticalPoint(const point &p) { for (unsigned i=0; i points.at(i).x) std::swap(points.at(j), points.at(i)); } /* ------------------------------------------------------------------ */ int gEnvelopeChannel::getSelectedPoint() { /* point is a 7x7 dot */ for (unsigned i=0; i= points.at(i).x+x()-4 && Fl::event_x() <= points.at(i).x+x()+4 && Fl::event_y() >= points.at(i).y+y() && Fl::event_y() <= points.at(i).y+y()+7) return i; } return -1; } /* ------------------------------------------------------------------ */ void gEnvelopeChannel::fill() { points.clear(); for (unsigned i=0; itype == type && a->chan == pParent->chan->index) { if (range == RANGE_FLOAT) addPoint( a->frame, // frame 0, // int value (unused) a->fValue, // float value a->frame / pParent->zoom, // x ((1-h()+8)*a->fValue)+h()-8); // y = (b-a)x + a (line between two points) // else: TODO } } } giada-0.11.2/src/gui/elems/ge_envelopeChannel.h000066400000000000000000000060201264622563000212560ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_envelopeWidget * * parent class of any envelope controller, from volume to VST parameter * automations. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef __GE_ENVELOPECHANNEL_H__ #define __GE_ENVELOPECHANNEL_H__ #include #include #include #include "../../utils/utils.h" #include "ge_actionWidget.h" using std::vector; class gEnvelopeChannel : public gActionWidget { const char *l; // internal label int type; // type of action int range; /* point * a single dot in the graph. x = relative frame, y = relative value */ struct point { int frame; int iValue; float fValue; int x; int y; }; /* points * array of points, filled by fillPoints() */ vector points; /* selectedPoint * which point we are selecting? */ int selectedPoint; /* draggedPoint * which point we are dragging? */ int draggedPoint; /* previousXPoint * x coordinate of point at time t-1. Used to check effective shifts */ int previousXPoint; void draw(); int handle(int e); int getSelectedPoint(); void sortPoints(); /* verticalPoint * check if two points form a vertical line. In that case the frame value * would be the same and recorder would go crazy, so shift by a small value * of frames to create a minimal fadein/fadeout level. Return 0: no * vertical points; return 1: vertical with the next one, return -1: vertical * with the previous one. */ int verticalPoint(const point &p); public: gEnvelopeChannel(int x, int y, gdActionEditor *pParent, int type, int range, const char *l); ~gEnvelopeChannel(); /* addPoint * add a point made of frame+value to internal points[]. */ void addPoint(int frame, int iValue=0, float fValue=0.0f, int x=-1, int y=-1); void updateActions(); /* fill * parse recorder's stack and fill the widget with points. It's up to * the caller to call this method as initialization. */ void fill(); inline void clearPoints() { points.clear(); } }; #endif giada-0.11.2/src/gui/elems/ge_keyboard.cpp000066400000000000000000000234041264622563000203100ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gg_keyboard * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/const.h" #include "../../core/patch_DEPR_.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../glue/glue.h" #include "../../utils/log.h" #include "../dialogs/gd_browser.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_editor.h" #include "../dialogs/gd_warnings.h" #include "ge_channel.h" #include "ge_sampleChannel.h" #include "ge_keyboard.h" extern Mixer G_Mixer; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; int gKeyboard::indexColumn = 0; /* -------------------------------------------------------------------------- */ gKeyboard::gKeyboard(int X, int Y, int W, int H) : Fl_Scroll (X, Y, W, H), bckspcPressed(false), endPressed (false), spacePressed (false), addColumnBtn (NULL) { color(COLOR_BG_MAIN); type(Fl_Scroll::BOTH_ALWAYS); scrollbar.color(COLOR_BG_0); scrollbar.selection_color(COLOR_BG_1); scrollbar.labelcolor(COLOR_BD_1); scrollbar.slider(G_BOX); hscrollbar.color(COLOR_BG_0); hscrollbar.selection_color(COLOR_BG_1); hscrollbar.labelcolor(COLOR_BD_1); hscrollbar.slider(G_BOX); addColumnBtn = new gClick(8, y(), 200, 20, "Add new column"); addColumnBtn->callback(cb_addColumn, (void*) this); add(addColumnBtn); init(); } /* -------------------------------------------------------------------------- */ void gKeyboard::init() { /* add 6 empty columns as init layout */ __cb_addColumn(); __cb_addColumn(); __cb_addColumn(); __cb_addColumn(); __cb_addColumn(); __cb_addColumn(); } /* -------------------------------------------------------------------------- */ void gKeyboard::freeChannel(gChannel *gch) { gch->reset(); } /* -------------------------------------------------------------------------- */ void gKeyboard::deleteChannel(gChannel *gch) { for (unsigned i=0; ifind(gch); if (k != columns.at(i)->children()) { columns.at(i)->deleteChannel(gch); return; } } } /* -------------------------------------------------------------------------- */ void gKeyboard::updateChannel(gChannel *gch) { gch->update(); } /* -------------------------------------------------------------------------- */ void gKeyboard::organizeColumns() { /* if only one column exists don't cleanup: the initial column must * stay here. */ if (columns.size() == 1) return; /* otherwise delete all empty columns */ /** FIXME - this for loop might not work correctly! */ for (unsigned i=columns.size()-1; i>=1; i--) { if (columns.at(i)->isEmpty()) { //Fl::delete_widget(columns.at(i)); delete columns.at(i); columns.erase(columns.begin() + i); } } /* compact column, avoid empty spaces */ for (unsigned i=1; iposition(columns.at(i-1)->x() + columns.at(i-1)->w() + 16, y()); addColumnBtn->position(columns.back()->x() + columns.back()->w() + 16, y()); /* recompute col indexes */ refreshColIndexes(); redraw(); } /* -------------------------------------------------------------------------- */ void gKeyboard::cb_addColumn(Fl_Widget *v, void *p) { ((gKeyboard*)p)->__cb_addColumn(DEFAULT_COLUMN_WIDTH); } /* -------------------------------------------------------------------------- */ gChannel *gKeyboard::addChannel(int colIndex, Channel *ch, bool build) { gColumn *col = getColumnByIndex(colIndex); /* no column with index 'colIndex' found? Just create it and set its index to 'colIndex'. */ if (!col) { __cb_addColumn(); col = columns.back(); col->setIndex(colIndex); gLog("[gKeyboard::addChannel] created new column with index=%d\n", colIndex); } gLog("[gKeyboard::addChannel] add to column with index = %d\n", col->getIndex()); return col->addChannel(ch); } /* -------------------------------------------------------------------------- */ void gKeyboard::refreshColumns() { for (unsigned i=0; irefreshChannels(); } /* -------------------------------------------------------------------------- */ gColumn *gKeyboard::getColumnByIndex(int index) { for (unsigned i=0; igetIndex() == index) return columns.at(i); return NULL; } /* -------------------------------------------------------------------------- */ int gKeyboard::handle(int e) { int ret = Fl_Group::handle(e); // assume the buttons won't handle the Keyboard events switch (e) { case FL_FOCUS: case FL_UNFOCUS: { ret = 1; // enables receiving Keyboard events break; } case FL_SHORTCUT: // in case widget that isn't ours has focus case FL_KEYDOWN: // Keyboard key pushed case FL_KEYUP: { // Keyboard key released /* rewind session. Avoid retrigs */ if (e == FL_KEYDOWN) { if (Fl::event_key() == FL_BackSpace && !bckspcPressed) { bckspcPressed = true; glue_rewindSeq(); ret = 1; break; } else if (Fl::event_key() == FL_End && !endPressed) { endPressed = true; glue_startStopInputRec(false); // update gui ret = 1; break; } else if (Fl::event_key() == FL_Enter && !enterPressed) { enterPressed = true; glue_startStopActionRec(); ret = 1; break; } else if (Fl::event_key() == ' ' && !spacePressed) { spacePressed = true; G_Mixer.running ? glue_stopSeq() : glue_startSeq(); // TODO - glue_startStopSeq, no core logic here ret = 1; break; } } else if (e == FL_KEYUP) { if (Fl::event_key() == FL_BackSpace) bckspcPressed = false; else if (Fl::event_key() == FL_End) endPressed = false; else if (Fl::event_key() == ' ') spacePressed = false; else if (Fl::event_key() == FL_Enter) enterPressed = false; } /* Walk button arrays, trying to match button's label with the Keyboard event. * If found, set that button's value() based on up/down event, * and invoke that button's callback() */ for (unsigned i=0; ichildren(); k++) ret &= ((gChannel*)columns.at(i)->child(k))->keyPress(e); break; } } return ret; } /* -------------------------------------------------------------------------- */ void gKeyboard::clear() { for (unsigned i=0; iposition(8, y()); } /* -------------------------------------------------------------------------- */ void gKeyboard::setChannelWithActions(gSampleChannel *gch) { if (gch->ch->hasActions) gch->addActionButton(); else gch->delActionButton(); } /* -------------------------------------------------------------------------- */ void gKeyboard::printChannelMessage(int res) { if (res == SAMPLE_NOT_VALID) gdAlert("This is not a valid WAVE file."); else if (res == SAMPLE_MULTICHANNEL) gdAlert("Multichannel samples not supported."); else if (res == SAMPLE_WRONG_BIT) gdAlert("This sample has an\nunsupported bit-depth (> 32 bit)."); else if (res == SAMPLE_WRONG_ENDIAN) gdAlert("This sample has a wrong\nbyte order (not little-endian)."); else if (res == SAMPLE_WRONG_FORMAT) gdAlert("This sample is encoded in\nan unsupported audio format."); else if (res == SAMPLE_READ_ERROR) gdAlert("Unable to read this sample."); else if (res == SAMPLE_PATH_TOO_LONG) gdAlert("File path too long."); else gdAlert("Unknown error."); } /* -------------------------------------------------------------------------- */ void gKeyboard::__cb_addColumn(int width) { int colx; int colxw; int gap = 16; if (columns.size() == 0) { colx = x() - xposition(); // mind the offset with xposition() colxw = colx + width; } else { gColumn *prev = columns.back(); colx = prev->x()+prev->w() + gap; colxw = colx + width; } /* add gColumn to gKeyboard and to columns vector */ gColumn *gc = new gColumn(colx, y(), width, 2000, indexColumn, this); add(gc); columns.push_back(gc); indexColumn++; /* move addColumn button */ addColumnBtn->position(colxw + gap, y()); redraw(); gLog("[gKeyboard::__cb_addColumn] new column added (index=%d, w=%d), total count=%d, addColumn(x)=%d\n", gc->getIndex(), width, columns.size(), addColumnBtn->x()); /* recompute col indexes */ refreshColIndexes(); } /* -------------------------------------------------------------------------- */ void gKeyboard::addColumn(int width) { __cb_addColumn(width); } /* -------------------------------------------------------------------------- */ void gKeyboard::refreshColIndexes() { for (unsigned i=0; isetIndex(i); } giada-0.11.2/src/gui/elems/ge_keyboard.h000066400000000000000000000101601264622563000177500ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gg_keyboard * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_KEYBOARD_H #define GE_KEYBOARD_H #include #include #include #include #include #include #include "../elems/ge_column.h" #include "../../core/const.h" #include "../../utils/utils.h" using std::vector; class gKeyboard : public Fl_Scroll { private: /* refreshColIndexes * Recompute all column indexes in order to avoid any gaps between them. * Indexes must always be contiguous! */ void refreshColIndexes(); static void cb_addColumn (Fl_Widget *v, void *p); inline void __cb_addColumn(int width=DEFAULT_COLUMN_WIDTH); bool bckspcPressed; bool endPressed; bool spacePressed; bool enterPressed; /* indexColumn * the last index used for column. */ static int indexColumn; class gClick *addColumnBtn; /* columns * a vector of columns which in turn contain channels. */ vector columns; public: gKeyboard(int X, int Y, int W, int H); int handle(int e); /* init * build the initial setup of empty channels. */ void init(); /* addChannel * add a new channel to gChannels. Used by callbacks and during * patch loading. Requires Channel (and not gChannel). If build is * set to true, also generate the corresponding column if column (index) does * not exist yet. */ gChannel *addChannel(int column, class Channel *ch, bool build=false); /* addColumn * add a new column to the top of the stack. */ void addColumn(int width=380); /* deleteChannel * delete a channel from gChannels<> where gChannel->ch == ch and remove * it from the stack. */ void deleteChannel(gChannel *gch); /* freeChannel * free a channel from gChannels<> where gChannel->ch == ch. No channels * are deleted */ void freeChannel(gChannel *gch); /* updateChannel * wrapper function to call gch->update(). */ void updateChannel(gChannel *gch); /* organizeColumns * reorganize columns layout by removing empty gaps. */ void organizeColumns(); /* refreshColumns * refresh each column's channel, called on each GUI cycle. */ void refreshColumns(); /* getColumnByIndex * return the column with index 'index', or NULL if not found. */ gColumn *getColumnByIndex(int index); /* getColumn * return the column with from columns->at(i). */ inline gColumn *getColumn(int i) { return columns.at(i); } /* clear * delete all channels and groups. */ void clear(); /* setChannelWithActions * add 'R' button if channel has actions, and set recorder to active. */ void setChannelWithActions(class gSampleChannel *gch); /* printChannelMessage * given any output by glue_loadChannel, print the message on screen * on a gdAlert subwindow. */ void printChannelMessage(int res); /* getTotalColumns */ inline unsigned getTotalColumns() { return columns.size(); } /* getColumnWidth * return the width in pixel of i-th column. Warning: 'i' is the i-th column * in the column array, NOT the index. */ inline int getColumnWidth(int i) { return getColumnByIndex(i)->w(); } }; #endif giada-0.11.2/src/gui/elems/ge_midiChannel.cpp000066400000000000000000000223441264622563000207250ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_midiChannel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" #include "../../core/wave.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../glue/channel.h" #include "../../glue/glue.h" #include "../../utils/gui_utils.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_keyGrabber.h" #include "../dialogs/gd_midiInput.h" #include "../dialogs/gd_editor.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_warnings.h" #include "../dialogs/gd_browser.h" #include "../dialogs/gd_keyGrabber.h" #include "../dialogs/gd_midiOutput.h" #include "ge_keyboard.h" #include "ge_midiChannel.h" #include "ge_channel.h" #include "ge_sampleChannel.h" #ifdef WITH_VST #include "../dialogs/gd_pluginList.h" #endif extern Mixer G_Mixer; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; gMidiChannel::gMidiChannel(int X, int Y, int W, int H, class MidiChannel *ch) : gChannel(X, Y, W, H, CHANNEL_MIDI), ch(ch) { begin(); #if defined(WITH_VST) int delta = 120; // (5 widgets * 20) + (5 paddings * 4) #else int delta = 96; // (4 widgets * 20) + (4 paddings * 4) #endif button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); mainButton = new gMidiChannelButton(button->x()+button->w()+4, y(), w() - delta, 20, "-- MIDI --"); mute = new gClick(mainButton->x()+mainButton->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); #if defined(WITH_VST) fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); #else vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); #endif end(); resizable(mainButton); update(); button->callback(cb_button, (void*)this); button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease #ifdef WITH_VST fx->callback(cb_openFxWindow, (void*)this); #endif mute->type(FL_TOGGLE_BUTTON); mute->callback(cb_mute, (void*)this); solo->type(FL_TOGGLE_BUTTON); solo->callback(cb_solo, (void*)this); mainButton->callback(cb_openMenu, (void*)this); vol->callback(cb_changeVol, (void*)this); ch->guiChannel = this; } /* -------------------------------------------------------------------------- */ void gMidiChannel::cb_button (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_button(); } void gMidiChannel::cb_mute (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_mute(); } void gMidiChannel::cb_solo (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_solo(); } void gMidiChannel::cb_openMenu (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openMenu(); } void gMidiChannel::cb_changeVol (Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_changeVol(); } #ifdef WITH_VST void gMidiChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gMidiChannel*)p)->__cb_openFxWindow(); } #endif /* -------------------------------------------------------------------------- */ void gMidiChannel::__cb_mute() { glue_setMute(ch); } /* -------------------------------------------------------------------------- */ void gMidiChannel::__cb_solo() { solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); } /* -------------------------------------------------------------------------- */ void gMidiChannel::__cb_changeVol() { glue_setChanVol(ch, vol->value()); } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void gMidiChannel::__cb_openFxWindow() { gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); } #endif /* -------------------------------------------------------------------------- */ void gMidiChannel::__cb_button() { if (button->value()) glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); } /* -------------------------------------------------------------------------- */ void gMidiChannel::__cb_openMenu() { Fl_Menu_Item rclick_menu[] = { {"Edit actions..."}, // 0 {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 1 {"All"}, // 2 {0}, // 3 {"Setup keyboard input..."}, // 5 {"Setup MIDI input..."}, // 6 {"Setup MIDI output..."}, // 7 {"Clone channel"}, // 8 {"Delete channel"}, // 9 {0} }; /* no 'clear actions' if there are no actions */ if (!ch->hasActions) rclick_menu[1].deactivate(); Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); b->box(G_BOX); b->textsize(11); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); if (!m) return; if (strcmp(m->label(), "Delete channel") == 0) { if (!gdConfirmWin("Warning", "Delete channel: are you sure?")) return; glue_deleteChannel(ch); return; } if (strcmp(m->label(), "Clone channel") == 0) { glue_cloneChannel(ch); return; } if (strcmp(m->label(), "Setup keyboard input...") == 0) { gu_openSubWindow(mainWin, new gdKeyGrabber(ch), 0); //new gdKeyGrabber(ch); return; } if (strcmp(m->label(), "All") == 0) { if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) return; recorder::clearChan(ch->index); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "Edit actions...") == 0) { gu_openSubWindow(mainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); return; } if (strcmp(m->label(), "Setup MIDI input...") == 0) { gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0); return; } if (strcmp(m->label(), "Setup MIDI output...") == 0) { //gu_openSubWindow(mainWin, new gdMidiGrabberChannel(ch, GrabForOutput), 0); gu_openSubWindow(mainWin, new gdMidiOutputMidiCh(ch), 0); return; } } /* -------------------------------------------------------------------------- */ void gMidiChannel::refresh() { setColorsByStatus(ch->status, ch->recStatus); mainButton->redraw(); } /* -------------------------------------------------------------------------- */ void gMidiChannel::reset() { mainButton->setDefaultMode("-- MIDI --"); mainButton->redraw(); } /* -------------------------------------------------------------------------- */ void gMidiChannel::update() { if (ch->midiOut) { char tmp[32]; sprintf(tmp, "-- MIDI (channel %d) --", ch->midiOutChan+1); mainButton->copy_label(tmp); } else mainButton->label("-- MIDI --"); vol->value(ch->volume); mute->value(ch->mute); solo->value(ch->solo); mainButton->setKey(ch->key); #ifdef WITH_VST fx->full = ch->plugins.size() > 0; #endif } /* -------------------------------------------------------------------------- */ void gMidiChannel::resize(int X, int Y, int W, int H) { gChannel::resize(X, Y, W, H); /* this stuff makes sense only with FX button available. Do nothing * otherwise */ #ifdef WITH_VST if (w() < BREAK_FX) { fx->hide(); mainButton->size(w() - (BREAK_DELTA - BREAK_UNIT), mainButton->h()); } else { fx->show(); mainButton->size(w() - BREAK_DELTA, mainButton->h()); } mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); solo->resize(mute->x()+mute->w()+4, y(), 20, 20); gChannel::init_sizes(); #endif } /* -------------------------------------------------------------------------- */ int gMidiChannel::keyPress(int e) { return handleKey(e, ch->key); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gMidiChannelButton::gMidiChannelButton(int x, int y, int w, int h, const char *l) : gChannelButton(x, y, w, h, l) {} /* -------------------------------------------------------------------------- */ int gMidiChannelButton::handle(int e) { // MIDI drag-n-drop does nothing so far. return gClick::handle(e); } giada-0.11.2/src/gui/elems/ge_midiChannel.h000066400000000000000000000047031264622563000203710ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_midiChannel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_MIDI_CHANNEL_H #define GE_MIDI_CHANNEL_H #include #include #include #include "ge_channel.h" #include "ge_channelButton.h" #include "ge_mixed.h" class gMidiChannel : public gChannel { private: static void cb_button (Fl_Widget *v, void *p); static void cb_mute (Fl_Widget *v, void *p); static void cb_solo (Fl_Widget *v, void *p); static void cb_openMenu (Fl_Widget *v, void *p); static void cb_changeVol (Fl_Widget *v, void *p); #ifdef WITH_VST static void cb_openFxWindow (Fl_Widget *v, void *p); #endif inline void __cb_mute (); inline void __cb_solo (); inline void __cb_changeVol (); inline void __cb_button (); inline void __cb_openMenu (); inline void __cb_readActions (); #ifdef WITH_VST inline void __cb_openFxWindow(); #endif public: gMidiChannel(int x, int y, int w, int h, class MidiChannel *ch); void reset (); void update (); void refresh (); int keyPress(int event); void resize (int x, int y, int w, int h); class MidiChannel *ch; }; /* -------------------------------------------------------------------------- */ class gMidiChannelButton : public gChannelButton { public: gMidiChannelButton(int x, int y, int w, int h, const char *l=0); int handle(int e); }; #endif giada-0.11.2/src/gui/elems/ge_midiIoTools.cpp000066400000000000000000000057661264622563000207560ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_midiIoTools * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "ge_midiIoTools.h" #include "ge_mixed.h" gLearner::gLearner(int X, int Y, int W, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param) : Fl_Group(X, Y, W, 20), callback(cb), param (param) { begin(); text = new gBox(x(), y(), 156, 20, l); value = new gClick(text->x()+text->w()+4, y(), 80, 20, "(not set)"); button = new gButton(value->x()+value->w()+4, y(), 40, 20, "learn"); end(); text->box(G_BOX); text->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); value->box(G_BOX); value->callback(cb_value, (void*)this); value->when(FL_WHEN_RELEASE); updateValue(); button->type(FL_TOGGLE_BUTTON); button->callback(cb_button, (void*)this); } /* -------------------------------------------------------------------------- */ void gLearner::updateValue() { char buf[16]; if (*param != 0x0) snprintf(buf, 9, "0x%X", *param); else snprintf(buf, 16, "(not set)"); value->copy_label(buf); button->value(0); } /* -------------------------------------------------------------------------- */ void gLearner::cb_button(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_button(); } void gLearner::cb_value(Fl_Widget *v, void *p) { ((gLearner*)p)->__cb_value(); } /* -------------------------------------------------------------------------- */ void gLearner::__cb_value() { if (Fl::event_button() == FL_RIGHT_MOUSE) { *param = 0x0; updateValue(); } /// TODO - elif (LEFT_MOUSE) : insert values by hand } /* -------------------------------------------------------------------------- */ /* FIXME - do not malloc on each callback! do it on the constructor! */ void gLearner::__cb_button() { if (button->value() == 1) { cbData *data = (cbData*) malloc(sizeof(cbData)); data->window = (gdMidiInput*) parent(); // parent = gdMidiGrabberChannel data->learner = this; kernelMidi::startMidiLearn(callback, (void*)data); } else kernelMidi::stopMidiLearn(); } giada-0.11.2/src/gui/elems/ge_midiIoTools.h000066400000000000000000000046061264622563000204130ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_midiIoTools * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_LEARNER_H #define GE_LEARNER_H #include #include #include "../../core/kernelMidi.h" #include "../dialogs/gd_midiInput.h" class gLearner : public Fl_Group { private: /* callback * cb to pass to kernelMidi. Requires two parameters: * uint32_t msg - MIDI message * void *data - extra data */ kernelMidi::cb_midiLearn *callback; class gBox *text; class gClick *value; class gButton *button; static void cb_button(Fl_Widget *v, void *p); static void cb_value (Fl_Widget *v, void *p); inline void __cb_button(); inline void __cb_value(); public: /* param * pointer to ch->midiIn[value] */ uint32_t *param; gLearner(int x, int y, int w, const char *l, kernelMidi::cb_midiLearn *cb, uint32_t *param); void updateValue(); }; /* -------------------------------------------------------------------------- */ /* cbData * struct we pass to kernelMidi as extra parameter. Local scope made * with unnamed namespace. Infos: * http://stackoverflow.com/questions/4422507/superiority-of-unnamed-namespace-over-static */ /* TODO - instead of the unnamed namespace, why don't we make the struct as a (static) member of gLearner? */ namespace { struct cbData { gdMidiInput *window; gLearner *learner; }; } #endif giada-0.11.2/src/gui/elems/ge_mixed.cpp000066400000000000000000000413231264622563000176160ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_mixed * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #include "../../core/const.h" #include "../../core/mixer.h" #include "../../core/graphics.h" #include "../../core/recorder.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../utils/gui_utils.h" #include "../dialogs/gd_mainWindow.h" #include "ge_mixed.h" extern Mixer G_Mixer; extern unsigned G_beats; extern bool G_audio_status; extern gdMainWindow *mainWin; void __cb_window_closer(Fl_Widget *v, void *p) { delete (Fl_Window*)p; } /* -------------------------------------------------------------------------- */ gButton::gButton(int X, int Y, int W, int H, const char *L, const char **imgOff, const char **imgOn) : gClick(X, Y, W, H, L, imgOff, imgOn) {} /* -------------------------------------------------------------------------- */ gClick::gClick(int x, int y, int w, int h, const char *L, const char **imgOff, const char **imgOn) : gBaseButton(x, y, w, h, L), imgOff(imgOff), imgOn(imgOn), bgColor0(COLOR_BG_0), bgColor1(COLOR_BG_1), bdColor(COLOR_BD_0), txtColor(COLOR_TEXT_0) {} void gClick::draw() { if (!active()) txtColor = bdColor; else txtColor = COLOR_TEXT_0; fl_rect(x(), y(), w(), h(), bdColor); // borders if (value()) { // -- clicked if (imgOn != NULL) fl_draw_pixmap(imgOn, x()+1, y()+1); else fl_rectf(x(), y(), w(), h(), bgColor1); // covers the border } else { // -- not clicked fl_rectf(x()+1, y()+1, w()-2, h()-2, bgColor0); // bg inside the border if (imgOff != NULL) fl_draw_pixmap(imgOff, x()+1, y()+1); } if (!active()) fl_color(FL_INACTIVE_COLOR); fl_color(txtColor); fl_font(FL_HELVETICA, 11); fl_draw(label(), x()+2, y(), w()-2, h(), FL_ALIGN_CENTER); } /* -------------------------------------------------------------------------- */ gClickRepeat::gClickRepeat(int x, int y, int w, int h, const char *L, const char **imgOff, const char **imgOn) : Fl_Repeat_Button(x, y, w, h, L), imgOff(imgOff), imgOn(imgOn) {} void gClickRepeat::draw() { if (value()) { // -- clicked fl_rectf(x(), y(), w(), h(), COLOR_BG_1); // bg if (imgOn != NULL) fl_draw_pixmap(imgOn, x()+1, y()+1); } else { // -- not clicked fl_rectf(x(), y(), w(), h(), COLOR_BG_0); // bg fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border if (imgOff != NULL) fl_draw_pixmap(imgOff, x()+1, y()+1); } if (!active()) fl_color(FL_INACTIVE_COLOR); fl_color(COLOR_TEXT_0); fl_font(FL_HELVETICA, 11); fl_draw(label(), x(), y(), w(), h(), FL_ALIGN_CENTER); } /* -------------------------------------------------------------------------- */ gInput::gInput(int x, int y, int w, int h, const char *L) : Fl_Input(x, y, w, h, L) { //Fl::set_boxtype(G_BOX, gDrawBox, 1, 1, 2, 2); box(G_BOX); labelsize(11); labelcolor(COLOR_TEXT_0); color(COLOR_BG_DARK); textcolor(COLOR_TEXT_0); cursor_color(COLOR_TEXT_0); selection_color(COLOR_BD_0); textsize(11); } /* -------------------------------------------------------------------------- */ gDial::gDial(int x, int y, int w, int h, const char *L) : Fl_Dial(x, y, w, h, L) { labelsize(11); labelcolor(COLOR_TEXT_0); align(FL_ALIGN_LEFT); type(FL_FILL_DIAL); angles(0, 360); color(COLOR_BG_0); // background selection_color(COLOR_BG_1); // selection } void gDial::draw() { double angle = (angle2()-angle1())*(value()-minimum())/(maximum()-minimum()) + angle1(); fl_color(COLOR_BG_0); fl_pie(x(), y(), w(), h(), 270-angle1(), angle > angle1() ? 360+270-angle : 270-360-angle); fl_color(COLOR_BD_0); fl_arc(x(), y(), w(), h(), 0, 360); fl_pie(x(), y(), w(), h(), 270-angle, 270-angle1()); } /* -------------------------------------------------------------------------- */ gBox::gBox(int x, int y, int w, int h, const char *L, Fl_Align al) : Fl_Box(x, y, w, h, L) { labelsize(11); box(FL_NO_BOX); labelcolor(COLOR_TEXT_0); if (al != 0) align(al | FL_ALIGN_INSIDE); } /* -------------------------------------------------------------------------- */ gCheck::gCheck(int x, int y, int w, int h, const char *L) : Fl_Check_Button(x, y, w, h, L) {} void gCheck::draw() { int color = !active() ? FL_INACTIVE_COLOR : COLOR_BD_0; if (value()) { fl_rect(x(), y(), 12, 12, (Fl_Color) color); fl_rectf(x(), y(), 12, 12, (Fl_Color) color); } else { fl_rectf(x(), y(), 12, 12, FL_BACKGROUND_COLOR); fl_rect(x(), y(), 12, 12, (Fl_Color) color); } fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR); // clearer fl_font(FL_HELVETICA, 11); fl_color(!active() ? FL_INACTIVE_COLOR : COLOR_TEXT_0); fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP)); } /* -------------------------------------------------------------------------- */ gRadio::gRadio(int x, int y, int w, int h, const char *L) : Fl_Radio_Button(x, y, w, h, L) {} void gRadio::draw() { int color = !active() ? FL_INACTIVE_COLOR : COLOR_BD_0; if (value()) { fl_rect(x(), y(), 12, 12, (Fl_Color) color); fl_rectf(x(), y(), 12, 12, (Fl_Color) color); } else { fl_rectf(x(), y(), 12, 12, FL_BACKGROUND_COLOR); fl_rect(x(), y(), 12, 12, (Fl_Color) color); } fl_rectf(x()+20, y(), w(), h(), FL_BACKGROUND_COLOR); // clearer fl_font(FL_HELVETICA, 11); fl_color(COLOR_TEXT_0); fl_draw(label(), x()+20, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP)); } /* -------------------------------------------------------------------------- */ gProgress::gProgress(int x, int y, int w, int h, const char *L) : Fl_Progress(x, y, w, h, L) { color(COLOR_BG_0, COLOR_BD_0); box(G_BOX); } /* -------------------------------------------------------------------------- */ gSoundMeter::gSoundMeter(int x, int y, int w, int h, const char *L) : Fl_Box(x, y, w, h, L), clip(false), mixerPeak(0.0f), peak(0.0f), db_level(0.0f), db_level_old(0.0f) {} void gSoundMeter::draw() { fl_rect(x(), y(), w(), h(), COLOR_BD_0); /* peak = the highest value inside the frame */ peak = 0.0f; float tmp_peak = 0.0f; tmp_peak = fabs(mixerPeak); if (tmp_peak > peak) peak = tmp_peak; clip = peak >= 1.0f ? true : false; // 1.0f is considered clip /* dBFS (full scale) calculation, plus decay of -2dB per frame */ db_level = 20 * log10(peak); if (db_level < db_level_old) if (db_level_old > -DB_MIN_SCALE) db_level = db_level_old - 2.0f; db_level_old = db_level; /* graphical part */ float px_level = 0.0f; if (db_level < 0.0f) px_level = ((w()/DB_MIN_SCALE) * db_level) + w(); else px_level = w(); fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); fl_rectf(x()+1, y()+1, (int) px_level, h()-2, clip || !G_audio_status ? COLOR_ALERT : COLOR_BD_0); } /* -------------------------------------------------------------------------- */ gBeatMeter::gBeatMeter(int x, int y, int w, int h, const char *L) : Fl_Box(x, y, w, h, L) {} void gBeatMeter::draw() { int cursorW = w() / MAX_BEATS; int greyX = G_Mixer.beats * cursorW; fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border fl_rectf(x()+1, y()+1, w()-2, h()-2, FL_BACKGROUND_COLOR); // bg fl_rectf(x()+(G_Mixer.actualBeat*cursorW)+3, y()+3, cursorW-5, h()-6, COLOR_BG_2); // cursor /* beat cells */ fl_color(COLOR_BD_0); for (int i=1; i<=G_Mixer.beats; i++) fl_line(x()+cursorW*i, y()+1, x()+cursorW*i, y()+h()-2); /* bar line */ fl_color(COLOR_BG_2); int delta = G_Mixer.beats / G_Mixer.bars; for (int i=1; i= w()-16) { tmp.resize(size); size--; } tmp += "..."; fl_draw(tmp.c_str(), x(), y(), w(), h(), FL_ALIGN_CENTER); } } } /* -------------------------------------------------------------------------- */ void gDrawBox(int x, int y, int w, int h, Fl_Color c) { fl_color(c); fl_rectf(x, y, w, h); fl_color(COLOR_BD_0); fl_rect(x, y, w, h); } /* -------------------------------------------------------------------------- */ gLiquidScroll::gLiquidScroll(int x, int y, int w, int h, const char *l) : Fl_Scroll(x, y, w, h, l) { type(Fl_Scroll::VERTICAL); scrollbar.color(COLOR_BG_0); scrollbar.selection_color(COLOR_BG_1); scrollbar.labelcolor(COLOR_BD_1); scrollbar.slider(G_BOX); } void gLiquidScroll::resize(int X, int Y, int W, int H) { int nc = children()-2; // skip hscrollbar and vscrollbar for ( int t=0; tresize(c->x(), c->y(), W-24, c->h()); // W-24: leave room for scrollbar } init_sizes(); // tell scroll children changed in size Fl_Scroll::resize(X,Y,W,H); } /* -------------------------------------------------------------------------- */ gSlider::gSlider(int x, int y, int w, int h, const char *l) : Fl_Slider(x, y, w, h, l) { type(FL_HOR_FILL_SLIDER); labelsize(11); align(FL_ALIGN_LEFT); labelcolor(COLOR_TEXT_0); box(G_BOX); color(COLOR_BG_0); selection_color(COLOR_BD_0); } /* -------------------------------------------------------------------------- */ gResizerBar::gResizerBar(int X,int Y,int W,int H, bool vertical) : Fl_Box(X,Y,W,H), vertical(vertical) { last_y = 0; min_h = 30; if (vertical) { orig_h = H; labelsize(H); } else { orig_h = W; labelsize(W); } align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE); labelfont(FL_COURIER); visible_focus(0); } /* gResizerBar::~gResizerBar() { gLog("------ resizerbar %p destroyed\n", (void*)this); } */ void gResizerBar::HandleDrag(int diff) { Fl_Scroll *grp = (Fl_Scroll*)parent(); int top; int bot; if (vertical) { top = y(); bot = y()+h(); } else { top = x(); bot = x()+w(); } // First pass: find widget directly above us with common edge // Possibly clamp 'diff' if widget would get too small.. for (int t=0; tchildren(); t++) { Fl_Widget *wd = grp->child(t); if (vertical) { if ((wd->y()+wd->h()) == top) { // found widget directly above? if ((wd->h()+diff) < min_h) diff = wd->h() - min_h; // clamp wd->resize(wd->x(), wd->y(), wd->w(), wd->h()+diff); // change height break; // done with first pass } } else { if ((wd->x()+wd->w()) == top) { // found widget directly above? if ((wd->w()+diff) < min_h) diff = wd->w() - min_h; // clamp wd->resize(wd->x(), wd->y(), wd->w()+diff, wd->h()); // change height break; // done with first pass } } } // Second pass: find widgets below us, move based on clamped diff for (int t=0; tchildren(); t++) { Fl_Widget *wd = grp->child(t); if (vertical) { if (wd->y() >= bot) // found widget below us? wd->resize(wd->x(), wd->y()+diff, wd->w(), wd->h()); // change position } else { if (wd->x() >= bot) wd->resize(wd->x()+diff, wd->y(), wd->w(), wd->h()); } } // Change our position last if (vertical) resize(x(), y()+diff, w(), h()); else resize(x()+diff, y(), w(), h()); grp->init_sizes(); grp->redraw(); } int gResizerBar::handle(int e) { int ret = 0; int this_y; if (vertical) this_y = Fl::event_y_root(); else this_y = Fl::event_x_root(); switch (e) { case FL_FOCUS: ret = 1; break; case FL_ENTER: ret = 1; fl_cursor(vertical ? FL_CURSOR_NS : FL_CURSOR_WE); break; case FL_LEAVE: ret = 1; fl_cursor(FL_CURSOR_DEFAULT); break; case FL_PUSH: ret = 1; last_y = this_y; break; case FL_DRAG: HandleDrag(this_y-last_y); last_y = this_y; ret = 1; break; default: break; } return(Fl_Box::handle(e) | ret); } void gResizerBar::resize(int X,int Y,int W,int H) { if (vertical) Fl_Box::resize(X,Y,W,orig_h); // height of resizer stays constant size else Fl_Box::resize(X,Y,orig_h,H); } /* -------------------------------------------------------------------------- */ gScroll::gScroll(int x, int y, int w, int h, int t) : Fl_Scroll(x, y, w, h) { type(t); scrollbar.color(COLOR_BG_0); scrollbar.selection_color(COLOR_BG_1); scrollbar.labelcolor(COLOR_BD_1); scrollbar.slider(G_BOX); hscrollbar.color(COLOR_BG_0); hscrollbar.selection_color(COLOR_BG_1); hscrollbar.labelcolor(COLOR_BD_1); hscrollbar.slider(G_BOX); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gBaseButton::gBaseButton(int x, int y, int w, int h, const char *l) : Fl_Button(x, y, w, h, l) { initLabel = l ? l : ""; } /* -------------------------------------------------------------------------- */ void gBaseButton::trimLabel() { if (initLabel.empty()) return; std::string out; if (w() > 20) { out = initLabel; int len = initLabel.size(); while (fl_width(out.c_str(), out.size()) > w()) { out = initLabel.substr(0, len) + "..."; len--; } } else out = ""; copy_label(out.c_str()); } /* -------------------------------------------------------------------------- */ void gBaseButton::label(const char *l) { Fl_Button::label(l); initLabel = l; trimLabel(); } const char *gBaseButton::label() { return Fl_Button::label(); } /* -------------------------------------------------------------------------- */ void gBaseButton::resize(int X, int Y, int W, int H) { trimLabel(); Fl_Button::resize(X, Y, W, H); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gFxButton::gFxButton(int x, int y, int w, int h, const char **imgOff, const char **imgOn) : gClick(x, y, w, h, NULL, imgOff, imgOn), full(false) {} /* -------------------------------------------------------------------------- */ void gFxButton::draw() { gClick::draw(); if (full) fl_draw_pixmap(imgOn, x()+1, y()+1, COLOR_BD_0); } giada-0.11.2/src/gui/elems/ge_mixed.h000066400000000000000000000200431264622563000172570ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_mixed * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_MIXED_H #define GE_MIXED_H #include #include #include // for intptr_t #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include // for SHGetFolderPath #endif /* cb_window_closer * callback for when closing windows. Deletes the widget (delete). */ void __cb_window_closer(Fl_Widget *v, void *p); /* -------------------------------------------------------------------------- */ class gBaseButton : public Fl_Button { private: std::string initLabel; void trimLabel(); public: gBaseButton(int x, int y, int w, int h, const char *l=0); void resize(int x, int y, int w, int h); void label(const char *l); const char *label(); }; /* -------------------------------------------------------------------------- */ /* gClick * a normal button. */ class gClick : public gBaseButton { public: gClick(int x, int y, int w, int h, const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL); void draw(); const char **imgOff; const char **imgOn; Fl_Color bgColor0; // background not clicked Fl_Color bgColor1; // background clicked Fl_Color bdColor; // border Fl_Color txtColor; // testo }; /* -------------------------------------------------------------------------- */ class gClickRepeat : public Fl_Repeat_Button { public: gClickRepeat(int x, int y, int w, int h, const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL); void draw(); const char **imgOff; const char **imgOn; }; /* -------------------------------------------------------------------------- */ /* gButton * exactly as gClick but with a unique id inside of it. Used for the buttons in * channels and for FXs. */ class gButton : public gClick { public: gButton(int X,int Y,int W,int H,const char *L=0, const char **imgOff=NULL, const char **imgOn=NULL); int key; int id; }; /* -------------------------------------------------------------------------- */ class gInput : public Fl_Input { public: gInput(int x, int y, int w, int h, const char *L=0); }; /* -------------------------------------------------------------------------- */ class gDial : public Fl_Dial { public: gDial(int x, int y, int w, int h, const char *L=0); void draw(); }; /* -------------------------------------------------------------------------- */ class gBox : public Fl_Box { public: gBox(int x, int y, int w, int h, const char *L=0, Fl_Align al=FL_ALIGN_CENTER); }; /* -------------------------------------------------------------------------- */ class gCheck : public Fl_Check_Button { public: gCheck(int x, int y, int w, int h, const char *L=0); void draw(); }; /* -------------------------------------------------------------------------- */ class gRadio : public Fl_Radio_Button { public: gRadio(int x, int y, int w, int h, const char *L=0); void draw(); }; /* -------------------------------------------------------------------------- */ class gProgress : public Fl_Progress { public: gProgress(int x, int y, int w, int h, const char *L=0); }; /* -------------------------------------------------------------------------- */ class gSoundMeter : public Fl_Box { public: gSoundMeter(int X,int Y,int W,int H,const char *L=0); void draw(); bool clip; float mixerPeak; // peak from mixer private: float peak; float db_level; float db_level_old; }; /* -------------------------------------------------------------------------- */ class gBeatMeter : public Fl_Box { public: gBeatMeter(int X,int Y,int W,int H,const char *L=0); void draw(); }; /* -------------------------------------------------------------------------- */ class gChoice : public Fl_Choice { public: gChoice(int X,int Y,int W,int H,const char *L=0, bool angle=true); void draw(); inline void showItem(const char *c) {value(find_index(c)); } bool angle; int id; }; /* -------------------------------------------------------------------------- */ /* gDrawBox * custom boxes in FLTK. */ #define G_BOX FL_FREE_BOXTYPE void gDrawBox(int x, int y, int w, int h, Fl_Color c); /* -------------------------------------------------------------------------- */ /* gLiquidScroll * custom scroll that tells children to follow scroll's width when * resized. Thanks to Greg Ercolano from FLTK dev team. * http://seriss.com/people/erco/fltk/ */ class gLiquidScroll : public Fl_Scroll { public: gLiquidScroll(int x, int y, int w, int h, const char *l=0); void resize(int x, int y, int w, int h); }; /* -------------------------------------------------------------------------- */ /* gScroll * custom scroll with nice scrollbars and something else. */ class gScroll : public Fl_Scroll { public: gScroll(int x, int y, int w, int h, int type=Fl_Scroll::BOTH); }; /* -------------------------------------------------------------------------- */ /* gResizerBar * 'resizer bar' between widgets Fl_Scroll. Thanks to Greg Ercolano from * FLTK dev team. http://seriss.com/people/erco/fltk/ * * Shows a resize cursor when hovered over. * Assumes: * - Parent is an Fl_Scroll * - All children of Fl_Scroll are vertically arranged * - The widget above us has a bottom edge touching our top edge * ie. (w->y()+w->h() == this->y()) * * When this widget is dragged: * - The widget above us (with a common edge) will be /resized/ * vertically * - All children below us will be /moved/ vertically */ /* TODO - use more general variable names * (last_y -> last_?, min_h -> min_?, ...) */ class gResizerBar : public Fl_Box { private: bool vertical; int orig_h; int last_y; int min_h; // min height for widget above us void HandleDrag(int diff); public: /* 'vertical' defines the bar movement. Vertical=true: the bar moves * vertically (up and down). */ gResizerBar(int x, int y, int w, int h, bool vertical=true); //~gResizerBar(); inline void setMinSize(int val) { min_h = val; } inline int getMinSize() { return min_h; } int handle(int e); void resize(int x, int y, int w, int h); }; /* -------------------------------------------------------------------------- */ class gSlider : public Fl_Slider { public: gSlider(int x, int y, int w, int h, const char *l=0); int id; }; /* -------------------------------------------------------------------------- */ /* gFxButton * a simple gClick with 'full' parameter (i.e. has plugins). If 'full' is true, * draw something somewhere. */ class gFxButton : public gClick { public: gFxButton(int x, int y, int w, int h, const char **imgOff=NULL, const char **imgOn=NULL); void draw(); bool full; }; #endif giada-0.11.2/src/gui/elems/ge_modeBox.cpp000066400000000000000000000067061264622563000201130ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_modeBox * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../utils/gui_utils.h" #include "../../core/graphics.h" #include "../../core/sampleChannel.h" #include "../../core/const.h" #include "../dialogs/gd_mainWindow.h" #include "ge_modeBox.h" gModeBox::gModeBox(int x, int y, int w, int h, SampleChannel *ch, const char *L) : Fl_Menu_Button(x, y, w, h, L), ch(ch) { box(G_BOX); textsize(11); textcolor(COLOR_TEXT_0); color(COLOR_BG_0); add("Loop . basic", 0, cb_changeMode, (void *)LOOP_BASIC); add("Loop . once", 0, cb_changeMode, (void *)LOOP_ONCE); add("Loop . once . bar", 0, cb_changeMode, (void *)LOOP_ONCE_BAR); add("Loop . repeat", 0, cb_changeMode, (void *)LOOP_REPEAT); add("Oneshot . basic", 0, cb_changeMode, (void *)SINGLE_BASIC); add("Oneshot . press", 0, cb_changeMode, (void *)SINGLE_PRESS); add("Oneshot . retrig", 0, cb_changeMode, (void *)SINGLE_RETRIG); add("Oneshot . endless", 0, cb_changeMode, (void *)SINGLE_ENDLESS); } /* -------------------------------------------------------------------------- */ void gModeBox::draw() { fl_rect(x(), y(), w(), h(), COLOR_BD_0); // border switch (ch->mode) { case LOOP_BASIC: fl_draw_pixmap(loopBasic_xpm, x()+1, y()+1); break; case LOOP_ONCE: fl_draw_pixmap(loopOnce_xpm, x()+1, y()+1); break; case LOOP_ONCE_BAR: fl_draw_pixmap(loopOnceBar_xpm, x()+1, y()+1); break; case LOOP_REPEAT: fl_draw_pixmap(loopRepeat_xpm, x()+1, y()+1); break; case SINGLE_BASIC: fl_draw_pixmap(oneshotBasic_xpm, x()+1, y()+1); break; case SINGLE_PRESS: fl_draw_pixmap(oneshotPress_xpm, x()+1, y()+1); break; case SINGLE_RETRIG: fl_draw_pixmap(oneshotRetrig_xpm, x()+1, y()+1); break; case SINGLE_ENDLESS: fl_draw_pixmap(oneshotEndless_xpm, x()+1, y()+1); break; } } /* -------------------------------------------------------------------------- */ void gModeBox::cb_changeMode(Fl_Widget *v, void *p) { ((gModeBox*)v)->__cb_changeMode((intptr_t)p); } /* -------------------------------------------------------------------------- */ void gModeBox::__cb_changeMode(int mode) { ch->mode = mode; /* what to do when the channel is playing and you change the mode? * Nothing, since v0.5.3. Just refresh the action editor window, in * case it's open */ gu_refreshActionEditor(); } giada-0.11.2/src/gui/elems/ge_modeBox.h000066400000000000000000000027511264622563000175540ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_modeBox * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_MODEBOX_H #define GE_MODEBOX_H #include class gModeBox : public Fl_Menu_Button { private: static void cb_changeMode (Fl_Widget *v, void *p); inline void __cb_changeMode(int mode); class SampleChannel *ch; public: gModeBox(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0); void draw(); }; #endif giada-0.11.2/src/gui/elems/ge_muteChannel.cpp000066400000000000000000000236231264622563000207560ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_muteChannel * a widget that represents mute actions inside the action editor. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "../../core/recorder.h" #include "../../core/mixer.h" #include "../../core/channel.h" #include "../../glue/glue.h" #include "../../utils/log.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_mainWindow.h" #include "ge_keyboard.h" #include "ge_actionWidget.h" #include "ge_muteChannel.h" extern gdMainWindow *mainWin; extern Mixer G_Mixer; gMuteChannel::gMuteChannel(int x, int y, gdActionEditor *pParent) : gActionWidget(x, y, 200, 80, pParent), draggedPoint(-1), selectedPoint(-1) { size(pParent->totalWidth, h()); extractPoints(); } /* ------------------------------------------------------------------ */ void gMuteChannel::draw() { baseDraw(); /* print label */ fl_color(COLOR_BG_1); fl_font(FL_HELVETICA, 12); fl_draw("mute", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER)); /* draw "on" and "off" labels. Must stay in background */ fl_color(COLOR_BG_1); fl_font(FL_HELVETICA, 9); fl_draw("on", x()+4, y(), w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP)); fl_draw("off", x()+4, y()+h()-14, w(), h(), (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_TOP)); /* draw on-off points. On = higher rect, off = lower rect. It always * starts with a note_off */ fl_color(COLOR_BG_2); int pxOld = x()+1; int pxNew = 0; int py = y()+h()-5; int pyDot = py-6; for (unsigned i=0; icoverX+x()-1, py); } /* ------------------------------------------------------------------ */ void gMuteChannel::extractPoints() { points.clear(); /* actions are already sorted by recorder::sortActions() */ for (unsigned i=0; ichan == pParent->chan->index) { if (recorder::global.at(i).at(j)->type & (ACTION_MUTEON | ACTION_MUTEOFF)) { point p; p.frame = recorder::frames.at(i); p.type = recorder::global.at(i).at(j)->type; p.x = p.frame / pParent->zoom; points.push_back(p); //gLog("[gMuteChannel::extractPoints] point found, type=%d, frame=%d\n", p.type, p.frame); } } } } } /* ------------------------------------------------------------------ */ void gMuteChannel::updateActions() { for (unsigned i=0; izoom; } /* ------------------------------------------------------------------ */ int gMuteChannel::handle(int e) { int ret = 0; int mouseX = Fl::event_x()-x(); switch (e) { case FL_ENTER: { ret = 1; break; } case FL_MOVE: { selectedPoint = getSelectedPoint(); redraw(); ret = 1; break; } case FL_LEAVE: { draggedPoint = -1; selectedPoint = -1; redraw(); ret = 1; break; } case FL_PUSH: { /* left click on point: drag * right click on point: delete * left click on void: add */ if (Fl::event_button1()) { if (selectedPoint != -1) { draggedPoint = selectedPoint; previousXPoint = points.at(selectedPoint).x; } else { /* click on the grey area leads to nowhere */ if (mouseX > pParent->coverX) { ret = 1; break; } /* click in the middle of a long mute_on (between two points): new actions * must be added in reverse: first mute_off then mute_on. Let's find the * next point from here. */ unsigned nextPoint = points.size(); for (unsigned i=0; izoom; int frame_b = frame_a+2048; if (pParent->gridTool->isOn()) { frame_a = pParent->gridTool->getSnapFrame(mouseX); frame_b = pParent->gridTool->getSnapFrame(mouseX + pParent->gridTool->getCellSize()); /* with snap=on a point can fall onto another */ if (pointCollides(frame_a) || pointCollides(frame_b)) { ret = 1; break; } } /* ensure frame parity */ if (frame_a % 2 != 0) frame_a++; if (frame_b % 2 != 0) frame_b++; /* avoid overflow: frame_b must be within the sequencer range. In that * case shift the ON-OFF block */ if (frame_b >= G_Mixer.totalFrames) { frame_b = G_Mixer.totalFrames; frame_a = frame_b-2048; } if (nextPoint % 2 != 0) { recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_a); recorder::rec(pParent->chan->index, ACTION_MUTEON, frame_b); } else { recorder::rec(pParent->chan->index, ACTION_MUTEON, frame_a); recorder::rec(pParent->chan->index, ACTION_MUTEOFF, frame_b); } recorder::sortActions(); mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow extractPoints(); redraw(); } } else { /* delete points pair */ if (selectedPoint != -1) { unsigned a; unsigned b; if (points.at(selectedPoint).type == ACTION_MUTEOFF) { a = selectedPoint-1; b = selectedPoint; } else { a = selectedPoint; b = selectedPoint+1; } //gLog("selected: a=%d, b=%d >>> frame_a=%d, frame_b=%d\n", // a, b, points.at(a).frame, points.at(b).frame); recorder::deleteAction(pParent->chan->index, points.at(a).frame, points.at(a).type, false); // false = don't check vals recorder::deleteAction(pParent->chan->index, points.at(b).frame, points.at(b).type, false); // false = don't check vals recorder::sortActions(); mainWin->keyboard->setChannelWithActions((gSampleChannel*)pParent->chan->guiChannel); // update mainWindow extractPoints(); redraw(); } } ret = 1; break; } case FL_RELEASE: { if (draggedPoint != -1) { if (points.at(draggedPoint).x == previousXPoint) { //gLog("nothing to do\n"); } else { int newFrame = points.at(draggedPoint).x * pParent->zoom; recorder::deleteAction( pParent->chan->index, points.at(draggedPoint).frame, points.at(draggedPoint).type, false); // don't check values recorder::rec( pParent->chan->index, points.at(draggedPoint).type, newFrame); recorder::sortActions(); points.at(draggedPoint).frame = newFrame; } } draggedPoint = -1; selectedPoint = -1; ret = 1; break; } case FL_DRAG: { if (draggedPoint != -1) { /* constrain the point between two ends (leftBorder-point, * point-point, point-rightBorder) */ int prevPoint; int nextPoint; if (draggedPoint == 0) { prevPoint = 0; nextPoint = points.at(draggedPoint+1).x - 1; if (pParent->gridTool->isOn()) nextPoint -= pParent->gridTool->getCellSize(); } else if ((unsigned) draggedPoint == points.size()-1) { prevPoint = points.at(draggedPoint-1).x + 1; nextPoint = pParent->coverX-x(); if (pParent->gridTool->isOn()) prevPoint += pParent->gridTool->getCellSize(); } else { prevPoint = points.at(draggedPoint-1).x + 1; nextPoint = points.at(draggedPoint+1).x - 1; if (pParent->gridTool->isOn()) { prevPoint += pParent->gridTool->getCellSize(); nextPoint -= pParent->gridTool->getCellSize(); } } if (mouseX <= prevPoint) points.at(draggedPoint).x = prevPoint; else if (mouseX >= nextPoint) points.at(draggedPoint).x = nextPoint; else if (pParent->gridTool->isOn()) points.at(draggedPoint).x = pParent->gridTool->getSnapPoint(mouseX)-1; else points.at(draggedPoint).x = mouseX; redraw(); } ret = 1; break; } } return ret; } /* ------------------------------------------------------------------ */ bool gMuteChannel::pointCollides(int frame) { for (unsigned i=0; i= points.at(i).x+x()-3 && Fl::event_x() <= points.at(i).x+x()+3) return i; } return -1; } giada-0.11.2/src/gui/elems/ge_muteChannel.h000066400000000000000000000051611264622563000204200ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_muteChannel * a widget representing mute actions inside the action editor. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GE_MUTECHANNEL_H #define GE_MUTECHANNEL_H #include #include #include #include #include "../../utils/utils.h" #include "ge_actionWidget.h" using std::vector; class gMuteChannel : public gActionWidget { private: /* point * a single dot in the graph. */ struct point { int frame; char type; int x; }; /* points * array of on/off points, in frames */ vector points; /* draggedPoint * which point we are dragging? */ int draggedPoint; /* selectedPoint * which point we are selecting? */ int selectedPoint; /* previousXPoint * x coordinate of point at time t-1. Used to check effective shifts */ int previousXPoint; /* extractPoints * va a leggere l'array di azioni di Recorder ed estrae tutti i punti * interessanti mute_on o mute_off. Li mette poi nel vector points. */ void extractPoints(); /* getSelectedPoint * ritorna l'indice di points[] in base al punto selezionato (quello * con il mouse hover). Ritorna -1 se non trova niente. */ int getSelectedPoint(); /* pointCollides * true if a point collides with another. Used while adding new points * with snap active.*/ bool pointCollides(int frame); public: gMuteChannel(int x, int y, class gdActionEditor *pParent); void draw(); int handle(int e); /* updateActions * calculates new points affected by the zoom. Call this one after * each zoom update. */ void updateActions(); }; #endif giada-0.11.2/src/gui/elems/ge_pianoRoll.cpp000066400000000000000000000421561264622563000204540ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_pianoRoll * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include "../../core/channel.h" #include "../../core/midiChannel.h" #include "../../core/const.h" #include "../../core/kernelMidi.h" #include "../../core/conf.h" #include "../../utils/log.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_actionEditor.h" #include "ge_pianoRoll.h" extern gdMainWindow *mainWin; extern Mixer G_Mixer; extern Conf G_Conf; gPianoRollContainer::gPianoRollContainer(int x, int y, class gdActionEditor *pParent) : Fl_Scroll(x, y, 200, 422), pParent(pParent) { size(pParent->totalWidth, G_Conf.pianoRollH); pianoRoll = new gPianoRoll(x, y, pParent->totalWidth, pParent); } /* ------------------------------------------------------------------ */ gPianoRollContainer::~gPianoRollContainer() { clear(); G_Conf.pianoRollH = h(); G_Conf.pianoRollY = pianoRoll->y(); } /* ------------------------------------------------------------------ */ void gPianoRollContainer::updateActions() { pianoRoll->updateActions(); } /* ------------------------------------------------------------------ */ void gPianoRollContainer::draw() { pianoRoll->size(this->w(), pianoRoll->h()); /// <--- not optimal /* clear background */ fl_rectf(x(), y(), w(), h(), COLOR_BG_MAIN); /* clip pianoRoll to pianoRollContainer size */ fl_push_clip(x(), y(), w(), h()); draw_child(*pianoRoll); fl_pop_clip(); fl_color(COLOR_BD_0); fl_line_style(0); fl_rect(x(), y(), pParent->totalWidth, h()); } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ gPianoRoll::gPianoRoll(int X, int Y, int W, class gdActionEditor *pParent) : gActionWidget(X, Y, W, 40, pParent) { resizable(NULL); // don't resize children (i.e. pianoItem) size(W, (MAX_NOTES+1) * CELL_H); // 128 MIDI channels * 15 px height if (G_Conf.pianoRollY == -1) position(x(), y()-(h()/2)); // center else position(x(), G_Conf.pianoRollY); drawSurface1(); drawSurface2(); /* add actions when the window is opened. Position is zoom-based. MIDI * actions come always in pair: start + end. */ recorder::sortActions(); recorder::action *a2 = NULL; recorder::action *prev = NULL; for (unsigned i=0; i than the grey area */ /** FIXME - can we move this to the outer cycle? */ if (recorder::frames.at(i) > G_Mixer.totalFrames) continue; recorder::action *a1 = recorder::global.at(i).at(j); if (a1->chan != pParent->chan->index) continue; if (a1->type == ACTION_MIDI) { /* if this action is == to previous one: skip it, we have already * checked it */ if (a1 == prev) { //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was previous\n"); continue; } /* extract MIDI infos from a1: if is note off skip it, we are looking * for note on only */ int a1_type = kernelMidi::getB1(a1->iValue); int a1_note = kernelMidi::getB2(a1->iValue); int a1_velo = kernelMidi::getB3(a1->iValue); if (a1_type == 0x80) { //gLog("[gPianoRoll] ACTION_MIDI found, but skipping - was note off\n"); continue; } /* search for the next action. Must have: same channel, ACTION_MIDI, greater * than a1->frame and with MIDI properties of note_off (0x80), same note * of a1, same velocity of a1 */ recorder::getNextAction( a1->chan, ACTION_MIDI, a1->frame, &a2, kernelMidi::getIValue(0x80, a1_note, a1_velo)); /* next action note off found: add a new gPianoItem to piano roll */ if (a2) { //gLog("[gPianoRoll] ACTION_MIDI pair found, frame_a=%d frame_b=%d, note_a=%d, note_b=%d, type_a=%d, type_b=%d\n", // a1->frame, a2->frame, kernelMidi::getNoteValue(a1->iValue), kernelMidi::getNoteValue(a2->iValue), // kernelMidi::getNoteOnOff(a1->iValue), kernelMidi::getNoteOnOff(a2->iValue)); new gPianoItem(0, 0, x(), y()+3, a1, a2, pParent); prev = a2; a2 = NULL; } else gLog("[gPianoRoll] recorder didn't find action!\n"); } } } end(); } /* ------------------------------------------------------------------ */ void gPianoRoll::drawSurface1() { surface1 = fl_create_offscreen(40, h()); fl_begin_offscreen(surface1); /* warning: only w() and h() come from this widget, x and y coordinates * are absolute, since we are writing in a memory chunk */ fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN); fl_line_style(FL_DASH, 0, NULL); fl_font(FL_HELVETICA, 11); int octave = 9; for (int i=1; i<=MAX_NOTES+1; i++) { /* print key note label. C C# D D# E F F# G G# A A# B */ char note[6]; int step = i % 12; switch (step) { case 1: fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); sprintf(note, "%dG", octave); break; case 2: sprintf(note, "%dF#", octave); break; case 3: sprintf(note, "%dF", octave); break; case 4: fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); sprintf(note, "%dE", octave); break; case 5: sprintf(note, "%dD#", octave); break; case 6: fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); sprintf(note, "%dD", octave); break; case 7: sprintf(note, "%dC#", octave); break; case 8: sprintf(note, "%dC", octave); break; case 9: fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); sprintf(note, "%dB", octave); break; case 10: sprintf(note, "%dA#", octave); break; case 11: fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); sprintf(note, "%dA", octave); break; case 0: sprintf(note, "%dG#", octave); octave--; break; } fl_color(fl_rgb_color(54, 54, 54)); fl_draw(note, 4, ((i-1)*CELL_H)+1, 30, CELL_H, (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CENTER)); /* print horizontal line */ if (i < 128) fl_line(0, i*CELL_H, 40, +i*CELL_H); } fl_line_style(0); fl_end_offscreen(); } /* ------------------------------------------------------------------ */ void gPianoRoll::drawSurface2() { surface2 = fl_create_offscreen(40, h()); fl_begin_offscreen(surface2); fl_rectf(0, 0, 40, h(), COLOR_BG_MAIN); fl_color(fl_rgb_color(54, 54, 54)); fl_line_style(FL_DASH, 0, NULL); for (int i=1; i<=MAX_NOTES+1; i++) { int step = i % 12; switch (step) { case 1: case 4: case 6: case 9: case 11: fl_rectf(0, i*CELL_H, 40, CELL_H, 30, 30, 30); break; } if (i < 128) { fl_color(fl_rgb_color(54, 54, 54)); fl_line(0, i*CELL_H, 40, +i*CELL_H); } } fl_line_style(0); fl_end_offscreen(); } /* ------------------------------------------------------------------ */ void gPianoRoll::draw() { fl_copy_offscreen(x(), y(), 40, h(), surface1, 0, 0); #if defined(__APPLE__) for (int i=36; itotalWidth; i+=36) /// TODO: i < pParent->coverX is faster fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 1, 0); #else for (int i=40; itotalWidth; i+=40) /// TODO: i < pParent->coverX is faster fl_copy_offscreen(x()+i, y(), 40, h(), surface2, 0, 0); #endif baseDraw(false); draw_children(); } /* ------------------------------------------------------------------ */ int gPianoRoll::handle(int e) { int ret = Fl_Group::handle(e); switch (e) { case FL_PUSH: { /* avoid click on grey area */ if (Fl::event_x() >= pParent->coverX) { ret = 1; break; } push_y = Fl::event_y() - y(); if (Fl::event_button1()) { /* ax is driven by grid, ay by the height in px of each note */ int ax = Fl::event_x(); int ay = Fl::event_y(); /* vertical snap */ int edge = (ay-y()-3) % 15; if (edge != 0) ay -= edge; /* if no overlap, add new piano item. Also check that it doesn't * overflow on the grey area, by shifting it to the left if * necessary. */ if (!onItem(ax, ay-y()-3)) { int greyover = ax+20 - pParent->coverX-x(); if (greyover > 0) ax -= greyover; add(new gPianoItem(ax, ay, ax-x(), ay-y()-3, NULL, NULL, pParent)); redraw(); } } ret = 1; break; } case FL_DRAG: { if (Fl::event_button3()) { gPianoRollContainer *prc = (gPianoRollContainer*) parent(); position(x(), Fl::event_y() - push_y); if (y() > prc->y()) position(x(), prc->y()); else if (y() < prc->y()+prc->h()-h()) position(x(), prc->y()+prc->h()-h()); prc->redraw(); } ret = 1; break; } case FL_MOUSEWHEEL: { // nothing to do, just avoid small internal scroll ret = 1; break; } } return ret; } /* ------------------------------------------------------------------ */ void gPianoRoll::updateActions() { /* when zooming, don't delete and re-add actions, just MOVE them. This * function shifts the action by a zoom factor. Those singlepress are * stretched, as well */ gPianoItem *i; for (int k=0; kgetFrame_a(), i->getFrame_b(), i->x()); int newX = x() + (i->getFrame_a() / pParent->zoom); int newW = ((i->getFrame_b() - i->getFrame_a()) / pParent->zoom); if (newW < 8) newW = 8; i->resize(newX, i->y(), newW, i->h()); i->redraw(); //gLog("update point %p, frame_a=%d frame_b=%d, x()=%d\n", (void*) i, i->getFrame_a(), i->getFrame_b(), i->x()); } } /* ------------------------------------------------------------------ */ bool gPianoRoll::onItem(int rel_x, int rel_y) { if (!pParent->chan->hasActions) return false; int note = MAX_NOTES - (rel_y / CELL_H); int n = children(); for (int i=0; igetNote() != note) continue; /* when 2 segments overlap? * start = the highest value between the two starting points * end = the lowest value between the two ending points * if start < end then there's an overlap of end-start pixels. We * also add 1 px to the edges in order to gain some space: * [ ][ ] ---> no * [ ] [ ] ---> yes! */ int start = p->x() > rel_x ? p->x() : rel_x-1; int end = p->x()+p->w() < rel_x + 20 ? p->x()+p->w() : rel_x + 21; if (start < end) return true; } return false; } /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */ gPianoItem::gPianoItem(int X, int Y, int rel_x, int rel_y, recorder::action *_a, recorder::action *_b, gdActionEditor *pParent) : Fl_Box (X, Y, 20, gPianoRoll::CELL_H-5), a (_a), b (_b), pParent (pParent), selected(false), event_a (0x00), event_b (0x00), changed (false) { /* a is a pointer: action exists, needs to be displayed */ if (a) { note = kernelMidi::getB2(a->iValue); frame_a = a->frame; frame_b = b->frame; event_a = a->iValue; event_b = b->iValue; int newX = rel_x + (frame_a / pParent->zoom); int newY = rel_y + getY(note); int newW = (frame_b - frame_a) / pParent->zoom; resize(newX, newY, newW, h()); } /* a is null: action needs to be recorded from scratch */ else { note = getNote(rel_y); frame_a = rel_x * pParent->zoom; frame_b = (rel_x + 20) * pParent->zoom; record(); size((frame_b - frame_a) / pParent->zoom, h()); } } /* ------------------------------------------------------------------ */ bool gPianoItem::overlap() { /* when 2 segments overlap? * start = the highest value between the two starting points * end = the lowest value between the two ending points * if start < end then there's an overlap of end-start pixels. */ gPianoRoll *pPiano = (gPianoRoll*) parent(); for (int i=0; ichildren(); i++) { gPianoItem *pItem = (gPianoItem*) pPiano->child(i); /* don't check against itself and with different y positions */ if (pItem == this || pItem->y() != y()) continue; int start = pItem->x() >= x() ? pItem->x() : x(); int end = pItem->x()+pItem->w() < x()+w() ? pItem->x()+pItem->w() : x()+w(); if (start < end) return true; } return false; } /* ------------------------------------------------------------------ */ void gPianoItem::draw() { int _w = w() > 4 ? w() : 4; //gLog("[gPianoItem] draw me (%p) at x=%d\n", (void*)this, x()); fl_rectf(x(), y(), _w, h(), (Fl_Color) selected ? COLOR_BD_1 : COLOR_BG_2); } /* ------------------------------------------------------------------ */ void gPianoItem::record() { /* avoid frame overflow */ int overflow = frame_b - G_Mixer.totalFrames; if (overflow > 0) { frame_b -= overflow; frame_a -= overflow; } /* note off */ /** FIXME - use constants */ event_a |= (0x90 << 24); // note on event_a |= (note << 16); // note value event_a |= (0x3F << 8); // velocity event_a |= (0x00); event_b |= (0x80 << 24); // note off event_b |= (note << 16); // note value event_b |= (0x3F << 8); // velocity event_b |= (0x00); recorder::rec(pParent->chan->index, ACTION_MIDI, frame_a, event_a); recorder::rec(pParent->chan->index, ACTION_MIDI, frame_b, event_b); } /* ------------------------------------------------------------------ */ void gPianoItem::remove() { recorder::deleteAction(pParent->chan->index, frame_a, ACTION_MIDI, true, event_a, 0.0); recorder::deleteAction(pParent->chan->index, frame_b, ACTION_MIDI, true, event_b, 0.0); /* send a note-off in case we are deleting it in a middle of a key_on * key_off sequence. */ ((MidiChannel*) pParent->chan)->sendMidi(event_b); } /* ------------------------------------------------------------------ */ int gPianoItem::handle(int e) { int ret = 0; switch (e) { case FL_ENTER: { selected = true; ret = 1; redraw(); break; } case FL_LEAVE: { fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); selected = false; ret = 1; redraw(); break; } case FL_MOVE: { onLeftEdge = false; onRightEdge = false; if (Fl::event_x() >= x() && Fl::event_x() < x()+4) { onLeftEdge = true; fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); } else if (Fl::event_x() >= x()+w()-4 && Fl::event_x() <= x()+w()) { onRightEdge = true; fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); } else fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); ret = 1; break; } case FL_PUSH: { push_x = Fl::event_x() - x(); old_x = x(); old_w = w(); if (Fl::event_button3()) { fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); remove(); hide(); // for Windows Fl::delete_widget(this); ((gPianoRoll*)parent())->redraw(); } ret = 1; break; } case FL_DRAG: { changed = true; gPianoRoll *pr = (gPianoRoll*) parent(); int coverX = pParent->coverX + pr->x(); // relative coverX int nx, ny, nw; if (onLeftEdge) { nx = Fl::event_x(); ny = y(); nw = x()-Fl::event_x()+w(); if (nx < pr->x()) { nx = pr->x(); nw = w()+x()-pr->x(); } else if (nx > x()+w()-8) { nx = x()+w()-8; nw = 8; } resize(nx, ny, nw, h()); } else if (onRightEdge) { nw = Fl::event_x()-x(); if (Fl::event_x() < x()+8) nw = 8; else if (Fl::event_x() > coverX) nw = coverX-x(); size(nw, h()); } else { nx = Fl::event_x() - push_x; if (nx < pr->x()+1) nx = pr->x()+1; else if (nx+w() > coverX) nx = coverX-w(); /* snapping */ if (pParent->gridTool->isOn()) nx = pParent->gridTool->getSnapPoint(nx-pr->x()) + pr->x() - 1; position(nx, y()); } /* update screen */ redraw(); ((gPianoRoll*)parent())->redraw(); ret = 1; break; } case FL_RELEASE: { /* delete & record the action, only if it doesn't overlap with * another one */ if (overlap()) { resize(old_x, y(), old_w, h()); redraw(); } else if (changed) { remove(); note = getNote(getRelY()); frame_a = getRelX() * pParent->zoom; frame_b = (getRelX()+w()) * pParent->zoom; record(); changed = false; } ((gPianoRoll*)parent())->redraw(); ret = 1; break; } } return ret; } giada-0.11.2/src/gui/elems/ge_pianoRoll.h000066400000000000000000000104461264622563000201160ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_pianoRoll * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GE_PIANOROLL_H #define GE_PIANOROLL_H #include #include #include #include "../../core/recorder.h" #include "ge_actionWidget.h" class gPianoRollContainer : public Fl_Scroll { private: class gdActionEditor *pParent; class gPianoRoll *pianoRoll; public: gPianoRollContainer(int x, int y, class gdActionEditor *parent); ~gPianoRollContainer(); void draw(); void updateActions(); }; /* ------------------------------------------------------------------ */ class gPianoRoll : public gActionWidget { private: /* onItem * is curson on a gPianoItem? */ bool onItem(int rel_x, int rel_y); /* drawSurface* * generate a complex drawing in memory first and copy it to the * screen at a later point in time. Fl_Offscreen surface holds the * necessary data. */ /* drawSurface1 * draw first tile of note values. */ void drawSurface1(); /* drawSurface2 * draw the rest of the piano roll. */ void drawSurface2(); int push_y; Fl_Offscreen surface1; // notes, no repeat Fl_Offscreen surface2; // lines, x-repeat public: gPianoRoll(int x, int y, int w, class gdActionEditor *pParent); void draw(); int handle(int e); void updateActions(); enum { MAX_NOTES = 127, CELL_H = 15 }; }; /* ------------------------------------------------------------------ */ class gPianoItem : public Fl_Box { private: /* getRelX/Y * return x/y point of this item, relative to piano roll (and not to * entire screen) */ inline int getRelY() { return y() - parent()->y() - 3; }; inline int getRelX() { return x() - parent()->x(); }; /* getNote * from a relative_y return the real MIDI note, range 0-127. 15 is * the hardcoded value for note height in pixels */ inline int getNote(int rel_y) { return gPianoRoll::MAX_NOTES - (rel_y / gPianoRoll::CELL_H); }; /* getY * from a note, return the y position on piano roll */ inline int getY(int note) { return (gPianoRoll::MAX_NOTES * gPianoRoll::CELL_H) - (note * gPianoRoll::CELL_H); }; /* overlap * check if this item don't overlap with another one. */ bool overlap(); recorder::action *a; recorder::action *b; class gdActionEditor *pParent; bool selected; int push_x; /* MIDI note, start frame, end frame - Used only if it's a newly added * action */ /** FIXME - is it true? */ int note; int frame_a; int frame_b; /* event - bitmasked MIDI events, generated by record() or by ctor if * not newly added action */ int event_a; int event_b; /* changed - if Item has been moved or resized: re-recording needed */ bool changed; /* onLeft,RightEdge - if cursor is on a widget's edge */ bool onLeftEdge; bool onRightEdge; /* old_x, old_w - store previous width and position while dragging * and moving, in order to restore it if overlap */ int old_x, old_w; public: /* pianoItem ctor * if action *a == NULL, record a new action */ gPianoItem(int x, int y, int rel_x, int rel_y, recorder::action *a, recorder::action *b, class gdActionEditor *pParent); void draw(); int handle(int e); void record(); void remove(); inline int getFrame_a() { return frame_a; } inline int getFrame_b() { return frame_b; } inline int getNote() { return note; } }; #endif giada-0.11.2/src/gui/elems/ge_sampleChannel.cpp000066400000000000000000000406371264622563000212710ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_sampleChannel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/pluginHost.h" #include "../../core/mixer.h" #include "../../core/conf.h" #include "../../core/patch_DEPR_.h" #include "../../core/graphics.h" #include "../../core/channel.h" #include "../../core/wave.h" #include "../../core/sampleChannel.h" #include "../../core/midiChannel.h" #include "../../glue/glue.h" #include "../../glue/channel.h" #include "../../utils/gui_utils.h" #include "../dialogs/gd_mainWindow.h" #include "../dialogs/gd_keyGrabber.h" #include "../dialogs/gd_midiInput.h" #include "../dialogs/gd_editor.h" #include "../dialogs/gd_actionEditor.h" #include "../dialogs/gd_warnings.h" #include "../dialogs/gd_browser.h" #include "../dialogs/gd_midiOutput.h" #include "ge_keyboard.h" #include "ge_sampleChannel.h" #include "ge_status.h" #include "ge_modeBox.h" #ifdef WITH_VST #include "../dialogs/gd_pluginList.h" #endif extern Mixer G_Mixer; extern Conf G_Conf; extern Patch_DEPR_ G_Patch_DEPR_; extern gdMainWindow *mainWin; gSampleChannel::gSampleChannel(int X, int Y, int W, int H, class SampleChannel *ch) : gChannel(X, Y, W, H, CHANNEL_SAMPLE), ch(ch) { begin(); #if defined(WITH_VST) int delta = 168; // (7 widgets * 20) + (7 paddings * 4) #else int delta = 144; // (6 widgets * 20) + (6 paddings * 4) #endif button = new gButton(x(), y(), 20, 20, "", channelStop_xpm, channelPlay_xpm); status = new gStatus(button->x()+button->w()+4, y(), 20, 20, ch); mainButton = new gSampleChannelButton(status->x()+status->w()+4, y(), w() - delta, 20, "-- no sample --"); modeBox = new gModeBox(mainButton->x()+mainButton->w()+4, y(), 20, 20, ch); mute = new gClick(modeBox->x()+modeBox->w()+4, y(), 20, 20, "", muteOff_xpm, muteOn_xpm); solo = new gClick(mute->x()+mute->w()+4, y(), 20, 20, "", soloOff_xpm, soloOn_xpm); readActions = NULL; // no 'R' button #if defined(WITH_VST) fx = new gFxButton(solo->x()+solo->w()+4, y(), 20, 20, fxOff_xpm, fxOn_xpm); vol = new gDial(fx->x()+fx->w()+4, y(), 20, 20); #else vol = new gDial(solo->x()+solo->w()+4, y(), 20, 20); #endif end(); resizable(mainButton); update(); button->callback(cb_button, (void*)this); button->when(FL_WHEN_CHANGED); // do callback on keypress && on keyrelease #ifdef WITH_VST fx->callback(cb_openFxWindow, (void*)this); #endif mute->type(FL_TOGGLE_BUTTON); mute->callback(cb_mute, (void*)this); solo->type(FL_TOGGLE_BUTTON); solo->callback(cb_solo, (void*)this); mainButton->callback(cb_openMenu, (void*)this); vol->callback(cb_changeVol, (void*)this); ch->guiChannel = this; } /* -------------------------------------------------------------------------- */ void gSampleChannel::cb_button (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_button(); } void gSampleChannel::cb_mute (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_mute(); } void gSampleChannel::cb_solo (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_solo(); } void gSampleChannel::cb_openMenu (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openMenu(); } void gSampleChannel::cb_changeVol (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_changeVol(); } void gSampleChannel::cb_readActions (Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_readActions(); } #ifdef WITH_VST void gSampleChannel::cb_openFxWindow(Fl_Widget *v, void *p) { ((gSampleChannel*)p)->__cb_openFxWindow(); } #endif /* -------------------------------------------------------------------------- */ void gSampleChannel::__cb_mute() { glue_setMute(ch); } /* -------------------------------------------------------------------------- */ void gSampleChannel::__cb_solo() { solo->value() ? glue_setSoloOn(ch) : glue_setSoloOff(ch); } /* -------------------------------------------------------------------------- */ void gSampleChannel::__cb_changeVol() { glue_setChanVol(ch, vol->value()); } /* -------------------------------------------------------------------------- */ #ifdef WITH_VST void gSampleChannel::__cb_openFxWindow() { gu_openSubWindow(mainWin, new gdPluginList(PluginHost::CHANNEL, ch), WID_FX_LIST); } #endif /* -------------------------------------------------------------------------- */ void gSampleChannel::__cb_button() { if (button->value()) // pushed glue_keyPress(ch, Fl::event_ctrl(), Fl::event_shift()); else // released glue_keyRelease(ch, Fl::event_ctrl(), Fl::event_shift()); } /* -------------------------------------------------------------------------- */ void gSampleChannel::__cb_openMenu() { /* if you're recording (actions or input) no menu is allowed; you can't * do anything, especially deallocate the channel */ if (G_Mixer.chanInput == ch || recorder::active) return; /* the following is a trash workaround for a FLTK menu. We need a gMenu * widget asap */ Fl_Menu_Item rclick_menu[] = { {"Load new sample..."}, // 0 {"Export sample to file..."}, // 1 {"Setup keyboard input..."}, // 2 {"Setup MIDI input..."}, // 3 {"Setup MIDI output..."}, // 4 {"Edit sample..."}, // 5 {"Edit actions..."}, // 6 {"Clear actions", 0, 0, 0, FL_SUBMENU}, // 7 {"All"}, // 8 {"Mute"}, // 9 {"Volume"}, // 10 {"Start/Stop"}, // 11 {0}, // 12 {"Clone channel"}, // 13 {"Free channel"}, // 14 {"Delete channel"}, // 15 {0} }; if (ch->status & (STATUS_EMPTY | STATUS_MISSING)) { rclick_menu[1].deactivate(); rclick_menu[5].deactivate(); rclick_menu[14].deactivate(); } /* no 'clear actions' if there are no actions */ if (!ch->hasActions) rclick_menu[7].deactivate(); /* no 'clear start/stop actions' for those channels in loop mode: * they cannot have start/stop actions. */ if (ch->mode & LOOP_ANY) rclick_menu[11].deactivate(); Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); b->box(G_BOX); b->textsize(11); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); if (!m) return; if (strcmp(m->label(), "Load new sample...") == 0) { openBrowser(BROWSER_LOAD_SAMPLE); return; } if (strcmp(m->label(), "Setup keyboard input...") == 0) { new gdKeyGrabber(ch); /// FIXME - use gu_openSubWindow return; } if (strcmp(m->label(), "Setup MIDI input...") == 0) { gu_openSubWindow(mainWin, new gdMidiInputChannel(ch), 0); return; } if (strcmp(m->label(), "Setup MIDI output...") == 0) { gu_openSubWindow(mainWin, new gdMidiOutputSampleCh(ch), 0); return; } if (strcmp(m->label(), "Edit sample...") == 0) { gu_openSubWindow(mainWin, new gdEditor(ch), WID_SAMPLE_EDITOR); /// FIXME title it's up to gdEditor return; } if (strcmp(m->label(), "Export sample to file...") == 0) { openBrowser(BROWSER_SAVE_SAMPLE); return; } if (strcmp(m->label(), "Delete channel") == 0) { if (!gdConfirmWin("Warning", "Delete channel: are you sure?")) return; glue_deleteChannel(ch); return; } if (strcmp(m->label(), "Free channel") == 0) { if (ch->status == STATUS_PLAY) { if (!gdConfirmWin("Warning", "This action will stop the channel: are you sure?")) return; } else if (!gdConfirmWin("Warning", "Free channel: are you sure?")) return; glue_freeChannel(ch); /* delete any related subwindow */ /** FIXME - use gu_closeAllSubwindows() */ mainWin->delSubWindow(WID_FILE_BROWSER); mainWin->delSubWindow(WID_ACTION_EDITOR); mainWin->delSubWindow(WID_SAMPLE_EDITOR); mainWin->delSubWindow(WID_FX_LIST); return; } if (strcmp(m->label(), "Clone channel") == 0) { glue_cloneChannel(ch); return; } if (strcmp(m->label(), "Mute") == 0) { if (!gdConfirmWin("Warning", "Clear all mute actions: are you sure?")) return; recorder::clearAction(ch->index, ACTION_MUTEON | ACTION_MUTEOFF); if (!ch->hasActions) delActionButton(); /* TODO - set mute=false */ gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "Start/Stop") == 0) { if (!gdConfirmWin("Warning", "Clear all start/stop actions: are you sure?")) return; recorder::clearAction(ch->index, ACTION_KEYPRESS | ACTION_KEYREL | ACTION_KILLCHAN); if (!ch->hasActions) delActionButton(); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "Volume") == 0) { if (!gdConfirmWin("Warning", "Clear all volume actions: are you sure?")) return; recorder::clearAction(ch->index, ACTION_VOLUME); if (!ch->hasActions) delActionButton(); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "All") == 0) { if (!gdConfirmWin("Warning", "Clear all actions: are you sure?")) return; recorder::clearChan(ch->index); delActionButton(); gu_refreshActionEditor(); // refresh a.editor window, it could be open return; } if (strcmp(m->label(), "Edit actions...") == 0) { gu_openSubWindow(mainWin, new gdActionEditor(ch), WID_ACTION_EDITOR); return; } } /* -------------------------------------------------------------------------- */ void gSampleChannel::__cb_readActions() { ch->readActions ? glue_stopReadingRecs(ch) : glue_startReadingRecs(ch); } /* -------------------------------------------------------------------------- */ void gSampleChannel::openBrowser(int type) { const char *title = ""; switch (type) { case BROWSER_LOAD_SAMPLE: title = "Browse Sample"; break; case BROWSER_SAVE_SAMPLE: title = "Save Sample"; break; case -1: title = "Edit Sample"; break; } gWindow *childWin = new gdBrowser(title, G_Conf.samplePath.c_str(), ch, type); gu_openSubWindow(mainWin, childWin, WID_FILE_BROWSER); } /* -------------------------------------------------------------------------- */ void gSampleChannel::refresh() { if (!mainButton->visible()) // mainButton invisible? status too (see below) return; setColorsByStatus(ch->status, ch->recStatus); if (ch->wave != NULL) { if (G_Mixer.chanInput == ch) mainButton->setInputRecordMode(); if (recorder::active) { if (recorder::canRec(ch)) mainButton->setActionRecordMode(); } status->redraw(); // status invisible? sampleButton too (see below) } mainButton->redraw(); } /* -------------------------------------------------------------------------- */ void gSampleChannel::reset() { delActionButton(true); // force==true, don't check, just remove it mainButton->setDefaultMode("-- no sample --"); mainButton->redraw(); status->redraw(); } /* -------------------------------------------------------------------------- */ void gSampleChannel::update() { /* update sample button's label */ switch (ch->status) { case STATUS_EMPTY: mainButton->label("-- no sample --"); break; case STATUS_MISSING: case STATUS_WRONG: mainButton->label("* file not found! *"); break; default: mainButton->label(ch->wave->name.c_str()); break; } /* update channels. If you load a patch with recorded actions, the 'R' * button must be shown. Moreover if the actions are active, the 'R' * button must be activated accordingly. */ if (ch->hasActions) addActionButton(); else delActionButton(); /* updates modebox */ modeBox->value(ch->mode); modeBox->redraw(); /* update volumes+mute+solo */ vol->value(ch->volume); mute->value(ch->mute); solo->value(ch->solo); mainButton->setKey(ch->key); #ifdef WITH_VST fx->full = ch->plugins.size() > 0; fx->redraw(); #endif } /* -------------------------------------------------------------------------- */ int gSampleChannel::keyPress(int e) { return handleKey(e, ch->key); } /* -------------------------------------------------------------------------- */ void gSampleChannel::addActionButton() { /* quit if 'R' exists yet. */ if (readActions != NULL) return; mainButton->size(mainButton->w()-24, mainButton->h()); redraw(); readActions = new gClick(mainButton->x() + mainButton->w() + 4, mainButton->y(), 20, 20, "", readActionOff_xpm, readActionOn_xpm); readActions->type(FL_TOGGLE_BUTTON); readActions->value(ch->readActions); readActions->callback(cb_readActions, (void*)this); add(readActions); /* hard redraw: there's no other way to avoid glitches when moving * the 'R' button */ mainWin->keyboard->redraw(); } /* -------------------------------------------------------------------------- */ void gSampleChannel::delActionButton(bool force) { if (readActions == NULL) return; /* TODO - readActions check is useless here */ if (!force && (readActions == NULL || ch->hasActions)) return; remove(readActions); // delete from Keyboard group (FLTK) delete readActions; // delete (C++) readActions = NULL; mainButton->size(mainButton->w()+24, mainButton->h()); mainButton->redraw(); } /* -------------------------------------------------------------------------- */ void gSampleChannel::resize(int X, int Y, int W, int H) { gChannel::resize(X, Y, W, H); if (w() < BREAK_FX) { #ifdef WITH_VST fx->hide(); #endif mainButton->size(w() - BREAK_DELTA, mainButton->h()); mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); solo->resize(mute->x()+mute->w()+4, y(), 20, 20); /* The followings are useless on manual resizing, but useful when a channel * is added from a patch with a small width. */ modeBox->hide(); if (readActions) readActions->hide(); } else if (w() < BREAK_MODE_BOX) { #ifdef WITH_VST fx->show(); #endif mainButton->size(w() - (BREAK_DELTA + BREAK_UNIT), mainButton->h()); mute->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); solo->resize(mute->x()+mute->w()+4, y(), 20, 20); modeBox->hide(); } else if (w() < BREAK_READ_ACTIONS) { modeBox->show(); mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 2)), mainButton->h()); modeBox->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); if (readActions) readActions->hide(); } else { if (readActions) { mainButton->size(w() - (BREAK_DELTA + (BREAK_UNIT * 3)), mainButton->h()); readActions->resize(mainButton->x()+mainButton->w()+4, y(), 20, 20); readActions->show(); } } gChannel::init_sizes(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ gSampleChannelButton::gSampleChannelButton(int x, int y, int w, int h, const char *l) : gChannelButton(x, y, w, h, l) {} /* -------------------------------------------------------------------------- */ int gSampleChannelButton::handle(int e) { int ret = gClick::handle(e); switch (e) { case FL_DND_ENTER: case FL_DND_DRAG: case FL_DND_RELEASE: { ret = 1; break; } case FL_PASTE: { gSampleChannel *gch = (gSampleChannel*) parent(); // parent is gSampleChannel SampleChannel *ch = gch->ch; int result = glue_loadChannel(ch, gTrim(gStripFileUrl(Fl::event_text())).c_str()); if (result != SAMPLE_LOADED_OK) mainWin->keyboard->printChannelMessage(result); ret = 1; break; } } return ret; } giada-0.11.2/src/gui/elems/ge_sampleChannel.h000066400000000000000000000055651264622563000207370ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_sampleChannel * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_SAMPLE_CHANNEL_H #define GE_SAMPLE_CHANNEL_H #include #include #include #include "ge_channel.h" #include "ge_channelButton.h" #include "ge_mixed.h" class gSampleChannel : public gChannel { private: static void cb_button (Fl_Widget *v, void *p); static void cb_mute (Fl_Widget *v, void *p); static void cb_solo (Fl_Widget *v, void *p); static void cb_openMenu (Fl_Widget *v, void *p); static void cb_changeVol (Fl_Widget *v, void *p); static void cb_readActions (Fl_Widget *v, void *p); #ifdef WITH_VST static void cb_openFxWindow (Fl_Widget *v, void *p); #endif inline void __cb_mute (); inline void __cb_solo (); inline void __cb_changeVol (); inline void __cb_button (); inline void __cb_openMenu (); inline void __cb_readActions (); #ifdef WITH_VST inline void __cb_openFxWindow(); #endif void openBrowser(int type); public: gSampleChannel(int x, int y, int w, int h, class SampleChannel *ch); void reset (); void update (); void refresh (); int keyPress(int event); void resize (int x, int y, int w, int h); /* add/delActionButton * add or remove 'R' button when actions are available. 'Status' is * the initial status of the button: on or off. * If force==true remove the button with no further checks. */ void addActionButton(); void delActionButton(bool force=false); class gModeBox *modeBox; class gClick *readActions; class SampleChannel *ch; }; /* -------------------------------------------------------------------------- */ class gSampleChannelButton : public gChannelButton { public: gSampleChannelButton(int x, int y, int w, int h, const char *l=0); int handle(int e); }; #endif giada-0.11.2/src/gui/elems/ge_status.cpp000066400000000000000000000047471264622563000200440ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_status * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../../core/mixer.h" #include "ge_status.h" extern Mixer G_Mixer; gStatus::gStatus(int x, int y, int w, int h, SampleChannel *ch, const char *L) : Fl_Box(x, y, w, h, L), ch(ch) {} /* -------------------------------------------------------------------------- */ void gStatus::draw() { fl_rect(x(), y(), w(), h(), COLOR_BD_0); // reset border fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // reset background if (ch != NULL) { if (ch->status & (STATUS_WAIT | STATUS_ENDING | REC_ENDING | REC_WAITING) || ch->recStatus & (REC_WAITING | REC_ENDING)) { fl_rect(x(), y(), w(), h(), COLOR_BD_1); } else if (ch->status == STATUS_PLAY) fl_rect(x(), y(), w(), h(), COLOR_BD_1); else fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_0); // status empty if (G_Mixer.chanInput == ch) fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_3); // take in progress else if (recorder::active && recorder::canRec(ch)) fl_rectf(x()+1, y()+1, w()-2, h()-2, COLOR_BG_4); // action record /* equation for the progress bar: * ((chanTracker - chanStart) * w()) / (chanEnd - chanStart). */ int pos = ch->getPosition(); if (pos == -1) pos = 0; else pos = (pos * (w()-1)) / (ch->end - ch->begin); fl_rectf(x()+1, y()+1, pos, h()-2, COLOR_BG_2); } } giada-0.11.2/src/gui/elems/ge_status.h000066400000000000000000000026441264622563000175030ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_status * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef GE_STATUS_H #define GE_STATUS_H #include #include "../../core/sampleChannel.h" #include "ge_mixed.h" class gStatus : public Fl_Box { public: gStatus(int X, int Y, int W, int H, class SampleChannel *ch, const char *L=0); void draw(); class SampleChannel *ch; }; #endif giada-0.11.2/src/gui/elems/ge_waveTools.cpp000066400000000000000000000052541264622563000204760ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gg_waveTools * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "../../core/graphics.h" #include "../../core/mixer.h" #include "../elems/ge_mixed.h" #include "../elems/ge_waveform.h" #include "ge_waveTools.h" gWaveTools::gWaveTools(int x, int y, int w, int h, SampleChannel *ch, const char *l) : Fl_Scroll(x, y, w, h, l) { type(Fl_Scroll::HORIZONTAL_ALWAYS); hscrollbar.color(COLOR_BG_0); hscrollbar.selection_color(COLOR_BG_1); hscrollbar.labelcolor(COLOR_BD_1); hscrollbar.slider(G_BOX); waveform = new gWaveform(x, y, w, h-24, ch); //resizable(waveform); } /* ------------------------------------------------------------------ */ void gWaveTools::updateWaveform() { waveform->alloc(w()); waveform->redraw(); } /* ------------------------------------------------------------------ */ void gWaveTools::resize(int x, int y, int w, int h) { if (this->w() == w || (this->w() != w && this->h() != h)) { // vertical or both resize Fl_Widget::resize(x, y, w, h); waveform->resize(x, y, waveform->w(), h-24); updateWaveform(); } else { // horizontal resize Fl_Widget::resize(x, y, w, h); } if (this->w() > waveform->w()) waveform->stretchToWindow(); int offset = waveform->x() + waveform->w() - this->w() - this->x(); if (offset < 0) waveform->position(waveform->x()-offset, this->y()); } /* ------------------------------------------------------------------ */ int gWaveTools::handle(int e) { int ret = Fl_Group::handle(e); switch (e) { case FL_MOUSEWHEEL: { waveform->setZoom(Fl::event_dy()); redraw(); ret = 1; break; } } return ret; } giada-0.11.2/src/gui/elems/ge_waveTools.h000066400000000000000000000027321264622563000201410ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gg_waveTools * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GE_WAVETOOLS_H #define GE_WAVETOOLS_H #include #include #include class gWaveTools : public Fl_Scroll { public: class gWaveform *waveform; gWaveTools(int X,int Y,int W, int H, class SampleChannel *ch, const char *L=0); void resize(int x, int y, int w, int h); int handle(int e); void updateWaveform(); }; #endif giada-0.11.2/src/gui/elems/ge_waveform.cpp000066400000000000000000000441361264622563000203430ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_waveform * an element which represents a waveform. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include #include #include "../../core/wave.h" #include "../../core/conf.h" #include "../../core/mixer.h" #include "../../core/waveFx.h" #include "../../core/channel.h" #include "../../core/sampleChannel.h" #include "../../glue/glue.h" #include "../dialogs/gd_editor.h" #include "ge_waveTools.h" #include "ge_mixed.h" #include "ge_waveform.h" extern Mixer G_Mixer; extern Conf G_Conf; gWaveform::gWaveform(int x, int y, int w, int h, class SampleChannel *ch, const char *l) : Fl_Widget(x, y, w, h, l), chan(ch), menuOpen(false), chanStart(0), chanStartLit(false), chanEnd(0), chanEndLit(false), ratio(0.0f), selectionA(0), selectionB(0), selectionA_abs(0), selectionB_abs(0) { data.sup = NULL; data.inf = NULL; data.size = 0; grid.snap = G_Conf.sampleEditorGridOn; grid.level = G_Conf.sampleEditorGridVal; stretchToWindow(); } /* ------------------------------------------------------------------ */ gWaveform::~gWaveform() { freeData(); } /* ------------------------------------------------------------------ */ void gWaveform::freeData() { if (data.sup != NULL) { free(data.sup); free(data.inf); data.sup = NULL; data.inf = NULL; data.size = 0; } grid.points.clear(); } /* ------------------------------------------------------------------ */ int gWaveform::alloc(int datasize) { ratio = chan->wave->size / (float) datasize; if (ratio < 2) return 0; freeData(); data.size = datasize; data.sup = (int*) malloc(data.size * sizeof(int)); data.inf = (int*) malloc(data.size * sizeof(int)); int offset = h() / 2; int zero = y() + offset; // center, zero amplitude (-inf dB) /* grid frequency: store a grid point every 'gridFreq' pixel. Must be * even, as always */ int gridFreq = 0; if (grid.level != 0) { gridFreq = chan->wave->size / grid.level; if (gridFreq % 2 != 0) gridFreq--; } for (int i=0; iwave->size - 1) / (float) datasize); pn = (i+1) * ((chan->wave->size - 1) / (float) datasize); if (pp % 2 != 0) pp -= 1; if (pn % 2 != 0) pn -= 1; float peaksup = 0.0f; float peakinf = 0.0f; /* scan the original data in chunks */ int k = pp; while (k < pn) { if (chan->wave->data[k] > peaksup) peaksup = chan->wave->data[k]; // FIXME - Left data only else if (chan->wave->data[k] <= peakinf) peakinf = chan->wave->data[k]; // FIXME - Left data only /* print grid */ if (gridFreq != 0) if (k % gridFreq == 0 && k != 0) grid.points.push_back(i); k += 2; } data.sup[i] = zero - (peaksup * chan->boost * offset); data.inf[i] = zero - (peakinf * chan->boost * offset); // avoid window overflow if (data.sup[i] < y()) data.sup[i] = y(); if (data.inf[i] > y()+h()-1) data.inf[i] = y()+h()-1; } recalcPoints(); return 1; } /* ------------------------------------------------------------------ */ void gWaveform::recalcPoints() { selectionA = relativePoint(selectionA_abs); selectionB = relativePoint(selectionB_abs); chanStart = relativePoint(chan->begin / 2); /* fix the rounding error when chanEnd is set on the very end of the * sample */ if (chan->end == chan->wave->size) chanEnd = data.size - 2; // 2 px border else chanEnd = relativePoint(chan->end / 2); } /* ------------------------------------------------------------------ */ void gWaveform::draw() { /* blank canvas */ fl_rectf(x(), y(), w(), h(), COLOR_BG_0); /* draw selection (if any) */ if (selectionA != selectionB) { int a_x = selectionA + x() - BORDER; // - start; int b_x = selectionB + x() - BORDER; // - start; if (a_x < 0) a_x = 0; if (b_x >= w()-1) b_x = w()-1; if (selectionA < selectionB) fl_rectf(a_x+BORDER, y(), b_x-a_x, h(), COLOR_BD_0); else fl_rectf(b_x+BORDER, y(), a_x-b_x, h(), COLOR_BD_0); } /* draw waveform from x1 (offset driven by the scrollbar) to x2 * (width of parent window). We don't draw the entire waveform, * only the visibile part. */ int offset = h() / 2; int zero = y() + offset; // sample zero (-inf dB) int wx1 = abs(x() - ((gWaveTools*)parent())->x()); int wx2 = wx1 + ((gWaveTools*)parent())->w(); if (x()+w() < ((gWaveTools*)parent())->w()) wx2 = x() + w() - BORDER; fl_color(0, 0, 0); for (int i=wx1; i w()+x()-2) fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, w()-lineX+x()-1, FLAG_HEIGHT); else { fl_rectf(lineX, y()+h()-FLAG_HEIGHT-1, FLAG_WIDTH, FLAG_HEIGHT); fl_color(255, 255, 255); fl_draw("s", lineX+4, y()+h()-3); } /* print chanEnd */ lineX = x()+chanEnd; if (chanEndLit) fl_color(COLOR_BD_1); else fl_color(COLOR_BD_0); fl_line(lineX, y()+1, lineX, y()+h()-2); if (lineX-FLAG_WIDTH < x()) fl_rectf(x()+1, y()+1, lineX-x(), FLAG_HEIGHT); else { fl_rectf(lineX-FLAG_WIDTH, y()+1, FLAG_WIDTH, FLAG_HEIGHT); fl_color(255, 255, 255); fl_draw("e", lineX-10, y()+10); } } /* ------------------------------------------------------------------ */ int gWaveform::handle(int e) { int ret = 0; switch (e) { case FL_PUSH: { mouseX = Fl::event_x(); pushed = true; if (!mouseOnEnd() && !mouseOnStart()) { /* right button? show the menu. Don't set selectionA,B,etc */ if (Fl::event_button3()) { openEditMenu(); } else if (mouseOnSelectionA() || mouseOnSelectionB()) { resized = true; } else { dragged = true; selectionA = Fl::event_x() - x(); if (selectionA >= data.size) selectionA = data.size; selectionB = selectionA; selectionA_abs = absolutePoint(selectionA); selectionB_abs = selectionA_abs; } } ret = 1; break; } case FL_RELEASE: { /* don't recompute points if something is selected */ if (selectionA != selectionB) { pushed = false; dragged = false; ret = 1; break; } int realChanStart = chan->begin; int realChanEnd = chan->end; if (chanStartLit) realChanStart = absolutePoint(chanStart)*2; else if (chanEndLit) realChanEnd = absolutePoint(chanEnd)*2; glue_setBeginEndChannel((gdEditor *) window(), chan, realChanStart, realChanEnd, false); pushed = false; dragged = false; redraw(); ret = 1; break; } case FL_ENTER: { // enables FL_DRAG ret = 1; break; } case FL_LEAVE: { if (chanStartLit || chanEndLit) { chanStartLit = false; chanEndLit = false; redraw(); } ret = 1; break; } case FL_MOVE: { mouseX = Fl::event_x(); mouseY = Fl::event_y(); if (mouseOnStart()) { chanStartLit = true; redraw(); } else if (chanStartLit) { chanStartLit = false; redraw(); } if (mouseOnEnd()) { chanEndLit = true; redraw(); } else if (chanEndLit) { chanEndLit = false; redraw(); } if (mouseOnSelectionA()) fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); else if (mouseOnSelectionB()) fl_cursor(FL_CURSOR_WE, FL_WHITE, FL_BLACK); else fl_cursor(FL_CURSOR_DEFAULT, FL_WHITE, FL_BLACK); ret = 1; break; } case FL_DRAG: { /* here the mouse is on the chanStart tool */ if (chanStartLit && pushed) { chanStart = Fl::event_x() - x(); if (grid.snap) chanStart = applySnap(chanStart); if (chanStart < 0) chanStart = 0; else if (chanStart >= chanEnd) chanStart = chanEnd-2; redraw(); } else if (chanEndLit && pushed) { chanEnd = Fl::event_x() - x(); if (grid.snap) chanEnd = applySnap(chanEnd); if (chanEnd >= data.size - 2) chanEnd = data.size - 2; else if (chanEnd <= chanStart) chanEnd = chanStart + 2; redraw(); } /* here the mouse is on the waveform, i.e. a selection */ else if (dragged) { selectionB = Fl::event_x() - x(); if (selectionB >= data.size) selectionB = data.size; if (selectionB <= 0) selectionB = 0; if (grid.snap) selectionB = applySnap(selectionB); selectionB_abs = absolutePoint(selectionB); redraw(); } /* here the mouse is on a selection boundary i.e. resize */ else if (resized) { int pos = Fl::event_x() - x(); if (mouseOnSelectionA()) { selectionA = grid.snap ? applySnap(pos) : pos; selectionA_abs = absolutePoint(selectionA); } else if (mouseOnSelectionB()) { selectionB = grid.snap ? applySnap(pos) : pos; selectionB_abs = absolutePoint(selectionB); } redraw(); } mouseX = Fl::event_x(); ret = 1; break; } } return ret; } /* ------------------------------------------------------------------ */ /* pixel snap disances (10px) must be equal to those defined in * gWaveform::mouseOnSelectionA() and gWaverfrom::mouseOnSelectionB() */ /* TODO - use constant for 10px */ int gWaveform::applySnap(int pos) { for (unsigned i=0; i= grid.points.at(i) - 10 && pos <= grid.points.at(i) + 10) { return grid.points.at(i); } } return pos; } /* ------------------------------------------------------------------ */ bool gWaveform::mouseOnStart() { return mouseX-10 > chanStart + x() - BORDER && mouseX-10 <= chanStart + x() - BORDER + FLAG_WIDTH && mouseY > h() + y() - FLAG_HEIGHT; } /* ------------------------------------------------------------------ */ bool gWaveform::mouseOnEnd() { return mouseX-10 >= chanEnd + x() - BORDER - FLAG_WIDTH && mouseX-10 <= chanEnd + x() - BORDER && mouseY <= y() + FLAG_HEIGHT + 1; } /* ------------------------------------------------------------------ */ /* pixel boundaries (10px) must be equal to the snap factor distance * defined in gWaveform::applySnap() */ bool gWaveform::mouseOnSelectionA() { if (selectionA == selectionB) return false; return mouseX >= selectionA-10+x() && mouseX <= selectionA+10+x(); } bool gWaveform::mouseOnSelectionB() { if (selectionA == selectionB) return false; return mouseX >= selectionB-10+x() && mouseX <= selectionB+10+x(); } /* ------------------------------------------------------------------ */ int gWaveform::absolutePoint(int p) { if (p <= 0) return 0; if (p > data.size) return chan->wave->size / 2; return (p * ratio) / 2; } /* ------------------------------------------------------------------ */ int gWaveform::relativePoint(int p) { return (ceilf(p / ratio)) * 2; } /* ------------------------------------------------------------------ */ void gWaveform::openEditMenu() { if (selectionA == selectionB) return; menuOpen = true; Fl_Menu_Item menu[] = { {"Cut"}, {"Trim"}, {"Silence"}, {"Fade in"}, {"Fade out"}, {"Smooth edges"}, {"Set start/end here"}, {0} }; if (chan->status == STATUS_PLAY) { menu[0].deactivate(); menu[1].deactivate(); } Fl_Menu_Button *b = new Fl_Menu_Button(0, 0, 100, 50); b->box(G_BOX); b->textsize(11); b->textcolor(COLOR_TEXT_0); b->color(COLOR_BG_0); const Fl_Menu_Item *m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, b); if (!m) { menuOpen = false; return; } /* straightSel() to ensure that point A is always lower than B */ straightSel(); if (strcmp(m->label(), "Silence") == 0) { wfx_silence(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB)); selectionA = 0; selectionB = 0; stretchToWindow(); redraw(); menuOpen = false; return; } if (strcmp(m->label(), "Set start/end here") == 0) { glue_setBeginEndChannel( (gdEditor *) window(), // parent chan, absolutePoint(selectionA) * 2, // stereo! absolutePoint(selectionB) * 2, // stereo! false, // no recalc (we do it here) false // don't check ); selectionA = 0; selectionB = 0; selectionA_abs = 0; selectionB_abs = 0; recalcPoints(); redraw(); menuOpen = false; return; } if (strcmp(m->label(), "Cut") == 0) { wfx_cut(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB)); /* for convenience reset start/end points */ glue_setBeginEndChannel( (gdEditor *) window(), chan, 0, chan->wave->size, false); selectionA = 0; selectionB = 0; selectionA_abs = 0; selectionB_abs = 0; setZoom(0); menuOpen = false; return; } if (strcmp(m->label(), "Trim") == 0) { wfx_trim(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB)); glue_setBeginEndChannel( (gdEditor *) window(), chan, 0, chan->wave->size, false); selectionA = 0; selectionB = 0; selectionA_abs = 0; selectionB_abs = 0; stretchToWindow(); menuOpen = false; redraw(); return; } if (!strcmp(m->label(), "Fade in") || !strcmp(m->label(), "Fade out")) { int type = !strcmp(m->label(), "Fade in") ? 0 : 1; wfx_fade(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB), type); selectionA = 0; selectionB = 0; stretchToWindow(); redraw(); menuOpen = false; return; } if (!strcmp(m->label(), "Smooth edges")) { wfx_smooth(chan->wave, absolutePoint(selectionA), absolutePoint(selectionB)); selectionA = 0; selectionB = 0; stretchToWindow(); redraw(); menuOpen = false; return; } } /* ------------------------------------------------------------------ */ void gWaveform::straightSel() { if (selectionA > selectionB) { unsigned tmp = selectionB; selectionB = selectionA; selectionA = tmp; } } /* ------------------------------------------------------------------ */ void gWaveform::setZoom(int type) { int newSize; if (type == -1) newSize = data.size*2; // zoom in else newSize = data.size/2; // zoom out if (alloc(newSize)) { size(data.size, h()); /* zoom to pointer */ int shift; if (x() > 0) shift = Fl::event_x() - x(); else if (type == -1) shift = Fl::event_x() + abs(x()); else shift = (Fl::event_x() + abs(x())) / -2; if (x() - shift > BORDER) shift = 0; position(x() - shift, y()); /* avoid overflow when zooming out with scrollbar like that: * |----------[scrollbar]| * * offset vs smaller: * |[wave------------| offset > 0 smaller = false * |[wave----] | offset < 0, smaller = true * |-------------] | offset < 0, smaller = false */ int parentW = ((gWaveTools*)parent())->w(); int thisW = x() + w() - BORDER; // visible width, not full width if (thisW < parentW) position(x() + parentW - thisW, y()); if (smaller()) stretchToWindow(); redraw(); } } /* ------------------------------------------------------------------ */ void gWaveform::stretchToWindow() { int s = ((gWaveTools*)parent())->w(); alloc(s); position(BORDER, y()); size(s, h()); } /* ------------------------------------------------------------------ */ bool gWaveform::smaller() { return w() < ((gWaveTools*)parent())->w(); } /* ------------------------------------------------------------------ */ void gWaveform::setGridLevel(int l) { grid.points.clear(); grid.level = l; alloc(data.size); redraw(); } giada-0.11.2/src/gui/elems/ge_waveform.h000066400000000000000000000102751264622563000200050ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_waveform * an element which represents a waveform. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GE_WAVEFORM_H #define GE_WAVEFORM_H #include #include #include #include #include #include "../../utils/utils.h" using std::vector; #define FLAG_WIDTH 14 #define FLAG_HEIGHT 12 #define BORDER 8 // window border <-> widget border class gWaveform : public Fl_Widget { private: /* data * real graphic stuff from the underlying waveform */ struct data { int *sup; int *inf; int size; } data; /* grid */ struct grid { bool snap; int level; vector points; } grid; /* chan * chan in use. */ class SampleChannel *chan; /* menuOpen * is the menu open? */ bool menuOpen; /* mouseOnStart/end * is mouse on start or end flag? */ bool mouseOnStart(); bool mouseOnEnd(); /* mouseOnSelectionA/B * as above, for the selection */ bool mouseOnSelectionA(); bool mouseOnSelectionB(); /* absolutePoint * from a relative 'p' point (zoom affected) returns the same point * zoom 1:1 based */ int absolutePoint(int p); /* relativePoint * from an absolute 'p' point (1:1 zoom), returns the same point zoom * affected */ int relativePoint(int p); /* straightSel * helper function which flattens the selection if it was made from * right to left (inverse selection) */ void straightSel(); /* freeData * destroy any graphical buffer */ void freeData(); /* smaller * is the waveform smaller than the parent window? */ bool smaller(); /* applySnap * snap a point at 'pos' pixel */ int applySnap(int pos); public: gWaveform(int x, int y, int w, int h, class SampleChannel *ch, const char *l=0); ~gWaveform(); void draw(); int handle(int e); /* alloc * allocate memory for the picture */ int alloc(int datasize=0); /* recalcPoints * re-calc chanStart, chanEnd, ... */ void recalcPoints(); /* openEditMenu * show edit menu on right-click */ void openEditMenu(); /* displayRatio * how much of the waveform is being displayed on screen */ inline float displayRatio() { return 1.0f / (data.size / (float) w()); }; /* zoom * type == 1 : zoom out, type == -1: zoom in */ void setZoom(int type); /* strecthToWindow * shrink or enlarge the waveform to match parent's width (gWaveTools) */ void stretchToWindow(); /* setGridLevel * set a new frequency level for the grid. 0 means disabled. */ void setGridLevel(int l); inline void setSnap(bool v) { grid.snap = v; } inline bool getSnap() { return grid.snap; } inline int getSize() { return data.size; } int chanStart; bool chanStartLit; int chanEnd; bool chanEndLit; bool pushed; bool dragged; bool resized; float ratio; /* TODO - useless! use Fl::mouse_x() and Fl::mouse_y() instead */ int mouseX; // mouse pos for drag.n.drop int mouseY; /* selectionA/B = portion of the selected wave * " " "" " _abs = selectionA/B not affected by zoom */ /** TODO - change selectionA to selectionA_rel TODO - change selectionB to selectionB_rel */ int selectionA; int selectionB; int selectionA_abs; int selectionB_abs; }; #endif giada-0.11.2/src/gui/elems/ge_window.cpp000066400000000000000000000111551264622563000200170ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_window * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include "ge_window.h" #include "../../utils/log.h" gWindow::gWindow(int x, int y, int w, int h, const char *title, int id) : Fl_Double_Window(x, y, w, h, title), id(id), parent(NULL) { } /* ------------------------------------------------------------------ */ gWindow::gWindow(int w, int h, const char *title, int id) : Fl_Double_Window(w, h, title), id(id), parent(NULL) { } /* ------------------------------------------------------------------ */ gWindow::~gWindow() { /* delete all subwindows in order to empty the stack */ for (unsigned i=0; igetParent() != NULL) (child->getParent())->delSubWindow(child); } /* ------------------------------------------------------------------ */ void gWindow::addSubWindow(gWindow *w) { /** TODO - useless: delete ---------------------------------------- */ for (unsigned i=0; igetId() == subWindows.at(i)->getId()) { //gLog("[gWindow] window %p (id=%d) exists, not added (and deleted)\n", (void*)w, w->getId()); delete w; return; } /** --------------------------------------------------------------- */ w->setParent(this); w->callback(cb_closeChild); // you can pass params: w->callback(cb_closeChild, (void*)params) subWindows.push_back(w); //debug(); } /* ------------------------------------------------------------------ */ void gWindow::delSubWindow(gWindow *w) { for (unsigned i=0; igetId() == subWindows.at(i)->getId()) { delete subWindows.at(i); subWindows.erase(subWindows.begin() + i); //debug(); return; } //debug(); } /* ------------------------------------------------------------------ */ void gWindow::delSubWindow(int id) { for (unsigned i=0; igetId() == id) { delete subWindows.at(i); subWindows.erase(subWindows.begin() + i); //debug(); return; } //debug(); } /* ------------------------------------------------------------------ */ int gWindow::getId() { return id; } /* ------------------------------------------------------------------ */ void gWindow::setId(int id) { this->id = id; } /* ------------------------------------------------------------------ */ void gWindow::debug() { gLog("---- window stack (id=%d): ----\n", getId()); for (unsigned i=0; igetId()); gLog("----\n"); } /* ------------------------------------------------------------------ */ gWindow *gWindow::getParent() { return parent; } /* ------------------------------------------------------------------ */ void gWindow::setParent(gWindow *w) { parent = w; } /* ------------------------------------------------------------------ */ bool gWindow::hasWindow(int id) { for (unsigned i=0; igetId()) return true; return false; } /* ------------------------------------------------------------------ */ gWindow *gWindow::getChild(int id) { for (unsigned i=0; igetId()) return subWindows.at(i); return NULL; } giada-0.11.2/src/gui/elems/ge_window.h000066400000000000000000000036361264622563000174710ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ge_window * A custom window. * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef __GE_WINDOW_H__ #define __GE_WINDOW_H__ #include #include #include "../../utils/utils.h" using std::vector; class gWindow : public Fl_Double_Window { protected: vector subWindows; int id; gWindow *parent; public: gWindow(int x, int y, int w, int h, const char *title=0, int id=0); gWindow(int w, int h, const char *title=0, int id=0); ~gWindow(); static void cb_closeChild(Fl_Widget *v, void *p); void addSubWindow(gWindow *w); void delSubWindow(gWindow *w); void delSubWindow(int id); int getId(); void setId(int id); void debug(); void setParent(gWindow *); gWindow *getParent(); gWindow *getChild(int id); /* hasWindow * true if the window with id 'id' exists in the stack. */ bool hasWindow(int id); }; #endif giada-0.11.2/src/main.cpp000066400000000000000000000047461264622563000151000ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include #if defined(__linux__) || defined(__APPLE__) #include #endif #include "core/init.h" #include "core/const.h" #include "core/patch_DEPR_.h" #include "core/patch.h" #include "core/conf.h" #include "core/midiMapConf.h" #include "core/mixer.h" #include "core/mixerHandler.h" #include "core/kernelAudio.h" #include "core/recorder.h" #include "utils/gui_utils.h" #include "gui/dialogs/gd_mainWindow.h" #ifdef WITH_VST #include "core/pluginHost.h" #endif /* global variables. Yeah, we are nasty */ pthread_t t_video; Mixer G_Mixer; bool G_quit; bool G_audio_status; bool G_midiStatus; Patch_DEPR_ G_Patch_DEPR_; Patch G_Patch; Conf G_Conf; MidiMapConf G_MidiMap; gdMainWindow *mainWin; #ifdef WITH_VST PluginHost G_PluginHost; #endif void *thread_video(void *arg); int main(int argc, char **argv) { G_quit = false; init_prepareParser(); init_prepareMidiMap(); init_prepareKernelAudio(); init_prepareKernelMIDI(); init_startGUI(argc, argv); Fl::lock(); pthread_create(&t_video, NULL, thread_video, NULL); init_startKernelAudio(); int ret = Fl::run(); pthread_join(t_video, NULL); return ret; } void *thread_video(void *arg) { if (G_audio_status) while (!G_quit) { gu_refresh(); #ifdef _WIN32 Sleep(GUI_SLEEP); #else usleep(GUI_SLEEP); #endif } pthread_exit(NULL); return 0; } giada-0.11.2/src/utils/000077500000000000000000000000001264622563000145755ustar00rootroot00000000000000giada-0.11.2/src/utils/gui_utils.cpp000066400000000000000000000125211264622563000173060ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gui_utils * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "../core/mixer.h" #include "../core/patch_DEPR_.h" #include "../core/recorder.h" #include "../core/wave.h" #include "../core/pluginHost.h" #include "../core/channel.h" #include "../core/conf.h" #include "../core/graphics.h" #include "../gui/dialogs/gd_warnings.h" #include "../gui/dialogs/gd_mainWindow.h" #include "../gui/dialogs/gd_actionEditor.h" #include "../gui/elems/ge_keyboard.h" #include "../gui/elems/ge_window.h" #include "../gui/elems/ge_channel.h" #include "gui_utils.h" #include "log.h" extern Mixer G_Mixer; extern unsigned G_beats; extern bool G_audio_status; extern Patch_DEPR_ G_patch; extern Conf G_conf; extern uint32_t G_time; extern gdMainWindow *mainWin; #ifdef WITH_VST extern PluginHost G_PluginHost; #endif static int blinker = 0; void gu_refresh() { Fl::lock(); /* update dynamic elements: in and out meters, beat meter and * each channel */ mainWin->inOut->refresh(); mainWin->beatMeter->redraw(); mainWin->keyboard->refreshColumns(); /* compute timer for blinker */ blinker++; if (blinker > 12) blinker = 0; /* redraw GUI */ Fl::unlock(); Fl::awake(); } /* -------------------------------------------------------------------------- */ int gu_getBlinker() { return blinker; } /* -------------------------------------------------------------------------- */ void gu_updateControls() { for (unsigned i=0; iguiChannel->update(); } mainWin->inOut->setOutVol(G_Mixer.outVol); mainWin->inOut->setInVol(G_Mixer.inVol); #ifdef WITH_VST mainWin->inOut->setMasterFxOutFull(G_PluginHost.masterOut.size() > 0); mainWin->inOut->setMasterFxInFull(G_PluginHost.masterIn.size() > 0); #endif mainWin->timing->setMeter(G_Mixer.beats, G_Mixer.bars); mainWin->timing->setBpm(G_Mixer.bpm); /* if you reset to init state while the seq is in play: it's better to * update the button status */ mainWin->controller->updatePlay(G_Mixer.running); mainWin->controller->updateMetronome(0); } /* -------------------------------------------------------------------------- */ void gu_update_win_label(const char *c) { std::string out = G_APP_NAME; out += " - "; out += c; mainWin->copy_label(out.c_str()); } /* -------------------------------------------------------------------------- */ void gu_setFavicon(Fl_Window *w) { #if defined(__linux__) fl_open_display(); Pixmap p, mask; XpmCreatePixmapFromData( fl_display, DefaultRootWindow(fl_display), (char **)giada_icon, &p, &mask, NULL); w->icon((char *)p); #elif defined(_WIN32) w->icon((char *)LoadIcon(fl_display, MAKEINTRESOURCE(IDI_ICON1))); #endif } /* -------------------------------------------------------------------------- */ void gu_openSubWindow(gWindow *parent, gWindow *child, int id) { if (parent->hasWindow(id)) { gLog("[GU] parent has subwindow with id=%d, deleting\n", id); parent->delSubWindow(id); } child->setId(id); parent->addSubWindow(child); } /* -------------------------------------------------------------------------- */ void gu_refreshActionEditor() { /** TODO - why don't we simply call WID_ACTION_EDITOR->redraw()? */ gdActionEditor *aeditor = (gdActionEditor*) mainWin->getChild(WID_ACTION_EDITOR); if (aeditor) { Channel *chan = aeditor->chan; mainWin->delSubWindow(WID_ACTION_EDITOR); gu_openSubWindow(mainWin, new gdActionEditor(chan), WID_ACTION_EDITOR); } } /* -------------------------------------------------------------------------- */ gWindow *gu_getSubwindow(gWindow *parent, int id) { if (parent->hasWindow(id)) return parent->getChild(id); else return NULL; } /* -------------------------------------------------------------------------- */ void gu_closeAllSubwindows() { /* don't close WID_FILE_BROWSER, because it's the caller of this * function */ mainWin->delSubWindow(WID_ACTION_EDITOR); mainWin->delSubWindow(WID_SAMPLE_EDITOR); mainWin->delSubWindow(WID_FX_LIST); mainWin->delSubWindow(WID_FX); } /* -------------------------------------------------------------------------- */ string gu_removeFltkChars(const string &s) { string out = gReplace(s, "/", "-"); out = gReplace(out, "|", "-"); out = gReplace(out, "&", "-"); out = gReplace(out, "_", "-"); return out; } giada-0.11.2/src/utils/gui_utils.h000066400000000000000000000050721264622563000167560ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * gui_utils * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef GUI_UTILS_H #define GUI_UTILS_H #include #include #include #include #ifdef __APPLE__ #include // in osx, for basename() (but linux?) #endif /* including stuff for the favicon */ #if defined(_WIN32) #include "../ext/resource.h" #elif defined(__linux__) #include #endif using std::string; /* refresh * refresh all GUI elements. */ void gu_refresh(); /* getBlinker * return blinker value, used to make widgets blink. */ int gu_getBlinker(); /* updateControls * update attributes of control elements (sample names, volumes, ...). * Useful when loading a new patch. */ void gu_updateControls(); /* update_win_label * update the name of the main window */ void gu_update_win_label(const char *c); void gu_setFavicon(Fl_Window *w); void gu_openSubWindow(class gWindow *parent, gWindow *child, int id); /* refreshActionEditor * reload the action editor window by closing and reopening it. It's used * when you delete some actions from the mainWindow and the action editor * window is open. */ void gu_refreshActionEditor(); /* closeAllSubwindows * close all subwindows attached to mainWin. */ void gu_closeAllSubwindows(); /* getSubwindow * return a pointer to an open subwindow, otherwise NULL. */ gWindow *gu_getSubwindow(class gWindow *parent, int id); /* removeFltkChars * Strip special chars used by FLTK to split menus into sub-menus. */ string gu_removeFltkChars(const string &s); #endif giada-0.11.2/src/utils/log.cpp000066400000000000000000000037001264622563000160620ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * log * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #include #include #include #include "../utils/utils.h" #include "../core/const.h" #include "log.h" static FILE *f; static int mode; static bool stat; int gLog_init(int m) { mode = m; stat = true; if (mode == LOG_MODE_FILE) { std::string fpath = gGetHomePath() + "/giada.log"; f = fopen(fpath.c_str(), "a"); if (!f) { stat = false; return 0; } } return 1; } /* ------------------------------------------------------------------ */ void gLog_close() { if (mode == LOG_MODE_FILE) fclose(f); } /* ------------------------------------------------------------------ */ void gLog(const char *format, ...) { if (mode == LOG_MODE_MUTE) return; va_list args; va_start(args, format); if (mode == LOG_MODE_FILE && stat == true) vfprintf(f, format, args); else vprintf(format, args); va_end(args); } giada-0.11.2/src/utils/log.h000066400000000000000000000025301264622563000155270ustar00rootroot00000000000000/* --------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * log * * --------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * ------------------------------------------------------------------ */ #ifndef __LOG_H__ #define __LOG_H__ /* init * init logger. Mode defines where to write the output: LOG_MODE_STDOUT, * LOG_MODE_FILE and LOG_MODE_MUTE. */ int gLog_init (int mode); void gLog_close(); void gLog(const char *format, ...); #endif giada-0.11.2/src/utils/utils.cpp000066400000000000000000000173341264622563000164510ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * utils * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #include "utils.h" #if defined(_WIN32) // getcwd (unix) or __getcwd (win) #include #include #else #include #endif #include #include // stat (gDirExists) #include #include #include #include #include #include #include #if defined(__APPLE__) #include // basename unix #include // getpwuid #endif using std::string; using std::vector; bool gFileExists(const char *filename) { FILE *fh = fopen(filename, "rb"); if (!fh) { return 0; } else { fclose(fh); return 1; } } /* -------------------------------------------------------------------------- */ bool gIsDir(const char *path) { bool ret; #if defined(__linux__) struct stat s1; stat(path, &s1); ret = S_ISDIR(s1.st_mode); #elif defined(__APPLE__) if (strcmp(path, "")==0) ret = false; else { struct stat s1; stat(path, &s1); ret = S_ISDIR(s1.st_mode); /* check if ret is a bundle, a special OS X folder which must be * shown as a regular file (VST). * FIXME - consider native functions CFBundle... */ if (ret) { string tmp = path; tmp += "/Contents/Info.plist"; if (gFileExists(tmp.c_str())) ret = false; } } #elif defined(__WIN32) unsigned dwAttrib = GetFileAttributes(path); ret = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); #endif return ret & !gIsProject(path); } /* -------------------------------------------------------------------------- */ bool gDirExists(const char *path) { struct stat st; if (stat(path, &st) != 0 && errno == ENOENT) return false; return true; } bool gDirExists(const string &path) { return gDirExists(path.c_str()); } /* -------------------------------------------------------------------------- */ bool gMkdir(const char *path) { #if defined(__linux__) || defined(__APPLE__) if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) #else if (_mkdir(path) == 0) #endif return true; return false; } bool gMkdir(const string &path) { return gMkdir(path.c_str()); } /* -------------------------------------------------------------------------- */ /* TODO - avoid this shit, just wrap the other call */ string gBasename(const char *path) { string out = path; out.erase(0, out.find_last_of(gGetSlash().c_str())+1); return out; } string gBasename(const string &s) { string out = s; out.erase(0, out.find_last_of(gGetSlash().c_str())+1); return out; } /* -------------------------------------------------------------------------- */ string gDirname(const char *path) { string out = path; out.erase(out.find_last_of(gGetSlash().c_str())); return out; } /* -------------------------------------------------------------------------- */ string gGetCurrentPath() { char buf[PATH_MAX]; #if defined(__WIN32) if (_getcwd(buf, PATH_MAX) != NULL) #else if (getcwd(buf, PATH_MAX) != NULL) #endif return buf; else return ""; } /* -------------------------------------------------------------------------- */ string gGetExt(const char *file) { int len = strlen(file); int pos = len; while (pos>0) { if (file[pos] == '.') break; pos--; } if (pos==0) return ""; string out = file; return out.substr(pos+1, len); } /* -------------------------------------------------------------------------- */ string gStripExt(const char *file) { int len = strlen(file); int pos = -1; for (int i=0; i=0) { /// TODO - use gGetSlash() #if defined(__linux__) || defined(__APPLE__) if (out[i] == '/') #elif defined(_WIN32) if (out[i] == '\\') #endif break; i--; } out.erase(0, i+1); // includes the '/' (or '\' on windows) return out; } /* -------------------------------------------------------------------------- */ string gGetSlash() { #if defined(_WIN32) return "\\"; #else return "/"; #endif } /* -------------------------------------------------------------------------- */ string gItoa(int i) { std::stringstream out; out << i; return out.str(); } /* -------------------------------------------------------------------------- */ string gTrim(const char *f) { string out = f; return gTrim(out); } string gTrim(const string &s) { std::size_t first = s.find_first_not_of(" \n\t"); std::size_t last = s.find_last_not_of(" \n\t"); return s.substr(first, last-first+1); } /* -------------------------------------------------------------------------- */ string gReplace(string in, const string& search, const string& replace) { size_t pos = 0; while ((pos = in.find(search, pos)) != string::npos) { in.replace(pos, search.length(), replace); pos += replace.length(); } return in; } /* -------------------------------------------------------------------------- */ string gStripFileUrl(const char *f) { string out = f; out = gReplace(out, "file://", ""); out = gReplace(out, "%20", " "); return out; } /* -------------------------------------------------------------------------- */ string gGetHomePath() { char path[PATH_MAX]; #if defined(__linux__) snprintf(path, PATH_MAX, "%s/.giada", getenv("HOME")); #elif defined(_WIN32) snprintf(path, PATH_MAX, "."); #elif defined(__APPLE__) struct passwd *p = getpwuid(getuid()); if (p == NULL) { gLog("[gGetHomePath] unable to fetch user infos\n"); return ""; } else { const char *home = p->pw_dir; snprintf(path, PATH_MAX, "%s/Library/Application Support/Giada", home); } #endif return string(path); } /* -------------------------------------------------------------------------- */ void gSplit(string in, string sep, vector *v) { string full = in; string token = ""; size_t curr = 0; size_t next = -1; do { curr = next + 1; next = full.find_first_of(sep, curr); token = full.substr(curr, next - curr); if (token != "") v->push_back(token); } while (next != string::npos); } giada-0.11.2/src/utils/utils.h000066400000000000000000000042021264622563000161040ustar00rootroot00000000000000/* ----------------------------------------------------------------------------- * * Giada - Your Hardcore Loopmachine * * utils * * ----------------------------------------------------------------------------- * * Copyright (C) 2010-2016 Giovanni A. Zuliani | Monocasual * * This file is part of Giada - Your Hardcore Loopmachine. * * Giada - Your Hardcore Loopmachine 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. * * Giada - Your Hardcore Loopmachine 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 Giada - Your Hardcore Loopmachine. If not, see * . * * -------------------------------------------------------------------------- */ #ifndef UTILS_H #define UTILS_H #include #include #include #include "log.h" using std::string; using std::vector; bool gFileExists(const char *path); bool gDirExists(const char *path); bool gDirExists(const string &path); bool gIsDir(const char *path); bool gIsProject(const char *path); bool gIsPatch(const char *path); bool gMkdir(const char *path); bool gMkdir(const string &path); string gBasename(const char *path); string gBasename(const string &s); string gReplace(string in, const string& search, const string& replace); string gDirname(const char *path); string gTrim(const char *path); string gTrim(const string &s); string gGetCurrentPath(); string gGetHomePath(); string gStripFileUrl(const char *path); string gGetExt(const char *path); string gStripExt(const char *path); string gStripExt(const string &s); string gGetProjectName(const char *path); // TODO - useless! string gGetSlash(); string gItoa(int i); void gSplit(string in, string sep, vector *v); #endif giada-0.11.2/tests/000077500000000000000000000000001264622563000140105ustar00rootroot00000000000000giada-0.11.2/tests/catch.hpp000066400000000000000000012217571264622563000156220ustar00rootroot00000000000000/* * Catch v1.2.1 * Generated: 2015-06-30 18:23:27.961086 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // #included from: internal/catch_suppress_warnings.h #define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic ignored "-Wglobal-constructors" # pragma clang diagnostic ignored "-Wvariadic-macros" # pragma clang diagnostic ignored "-Wc99-extensions" # pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" # pragma clang diagnostic ignored "-Wswitch-enum" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // #included from: internal/catch_notimplemented_exception.h #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED // #included from: catch_common.h #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) #include #include #include // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED // Detect a number of compiler features - mostly C++11/14 conformance - by compiler // The following features are defined: // // CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? // CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 #ifdef __clang__ # if __has_feature(cxx_nullptr) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # if __has_feature(cxx_noexcept) # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Borland #ifdef __BORLANDC__ #endif // __BORLANDC__ //////////////////////////////////////////////////////////////////////////////// // EDG #ifdef __EDG_VERSION__ #endif // __EDG_VERSION__ //////////////////////////////////////////////////////////////////////////////// // Digital Mars #ifdef __DMC__ #endif // __DMC__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif #endif // __GNUC__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER #if (_MSC_VER >= 1600) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) #define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT #define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #endif // _MSC_VER // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __GNUC__ && __GNUC__ >= 3 ) || \ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) #define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS #endif //////////////////////////////////////////////////////////////////////////////// // C++ language feature support // catch all support for C++11 #if (__cplusplus >= 201103L) # define CATCH_CPP11_OR_GREATER # if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM # endif # ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE # define CATCH_INTERNAL_CONFIG_CPP11_TUPLE # endif # ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS # endif #endif // __cplusplus >= 201103L // Now set the actual defines based on the above + anything the user has configured #if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NULLPTR #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_NOEXCEPT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_GENERATED_METHODS #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_IS_ENUM #endif #if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) # define CATCH_CONFIG_CPP11_TUPLE #endif #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) #define CATCH_CONFIG_VARIADIC_MACROS #endif // noexcept support: #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) # define CATCH_NOEXCEPT noexcept # define CATCH_NOEXCEPT_IS(x) noexcept(x) #else # define CATCH_NOEXCEPT throw() # define CATCH_NOEXCEPT_IS(x) #endif namespace Catch { class NonCopyable { #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; #else NonCopyable( NonCopyable const& info ); NonCopyable& operator = ( NonCopyable const& ); #endif protected: NonCopyable() {} virtual ~NonCopyable(); }; class SafeBool { public: typedef void (SafeBool::*type)() const; static type makeSafe( bool value ) { return value ? &SafeBool::trueValue : 0; } private: void trueValue() const {} }; template inline void deleteAll( ContainerT& container ) { typename ContainerT::const_iterator it = container.begin(); typename ContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete *it; } template inline void deleteAllValues( AssociativeContainerT& container ) { typename AssociativeContainerT::const_iterator it = container.begin(); typename AssociativeContainerT::const_iterator itEnd = container.end(); for(; it != itEnd; ++it ) delete it->second; } bool startsWith( std::string const& s, std::string const& prefix ); bool endsWith( std::string const& s, std::string const& suffix ); bool contains( std::string const& s, std::string const& infix ); void toLowerInPlace( std::string& s ); std::string toLower( std::string const& s ); std::string trim( std::string const& str ); bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); struct pluralise { pluralise( std::size_t count, std::string const& label ); friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); std::size_t m_count; std::string m_label; }; struct SourceLineInfo { SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); SourceLineInfo( SourceLineInfo const& other ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; # endif bool empty() const; bool operator == ( SourceLineInfo const& other ) const; bool operator < ( SourceLineInfo const& other ) const; std::string file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // This is just here to avoid compiler warnings with macro constants and boolean literals inline bool isTrue( bool value ){ return value; } inline bool alwaysTrue() { return true; } inline bool alwaysFalse() { return false; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() { return std::string(); } }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); #include namespace Catch { class NotImplementedException : public std::exception { public: NotImplementedException( SourceLineInfo const& lineInfo ); NotImplementedException( NotImplementedException const& ) {} virtual ~NotImplementedException() CATCH_NOEXCEPT {} virtual const char* what() const CATCH_NOEXCEPT; private: std::string m_what; SourceLineInfo m_lineInfo; }; } // end namespace Catch /////////////////////////////////////////////////////////////////////////////// #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) // #included from: internal/catch_context.h #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED // #included from: catch_interfaces_generators.h #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED #include namespace Catch { struct IGeneratorInfo { virtual ~IGeneratorInfo(); virtual bool moveNext() = 0; virtual std::size_t getCurrentIndex() const = 0; }; struct IGeneratorsForTest { virtual ~IGeneratorsForTest(); virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; virtual bool moveNext() = 0; }; IGeneratorsForTest* createGeneratorsForTest(); } // end namespace Catch // #included from: catch_ptr.hpp #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { // An intrusive reference counting smart pointer. // T must implement addRef() and release() methods // typically implementing the IShared interface template class Ptr { public: Ptr() : m_p( NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); } Ptr( Ptr const& other ) : m_p( other.m_p ){ if( m_p ) m_p->addRef(); } ~Ptr(){ if( m_p ) m_p->release(); } void reset() { if( m_p ) m_p->release(); m_p = NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); swap( temp ); return *this; } Ptr& operator = ( Ptr const& other ){ Ptr temp( other ); swap( temp ); return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } T* get() { return m_p; } const T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } bool operator !() const { return m_p == NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } private: T* m_p; }; struct IShared : NonCopyable { virtual ~IShared(); virtual void addRef() const = 0; virtual void release() const = 0; }; template struct SharedImpl : T { SharedImpl() : m_rc( 0 ){} virtual void addRef() const { ++m_rc; } virtual void release() const { if( --m_rc == 0 ) delete this; } mutable unsigned int m_rc; }; } // end namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif #include #include #include namespace Catch { class TestCase; class Stream; struct IResultCapture; struct IRunner; struct IGeneratorsForTest; struct IConfig; struct IContext { virtual ~IContext(); virtual IResultCapture* getResultCapture() = 0; virtual IRunner* getRunner() = 0; virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; virtual bool advanceGeneratorsForCurrentTest() = 0; virtual Ptr getConfig() const = 0; }; struct IMutableContext : IContext { virtual ~IMutableContext(); virtual void setResultCapture( IResultCapture* resultCapture ) = 0; virtual void setRunner( IRunner* runner ) = 0; virtual void setConfig( Ptr const& config ) = 0; }; IContext& getCurrentContext(); IMutableContext& getCurrentMutableContext(); void cleanUpContext(); Stream createStream( std::string const& streamName ); } // #included from: internal/catch_test_registry.hpp #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED // #included from: catch_interfaces_testcase.h #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED #include namespace Catch { class TestSpec; struct ITestCase : IShared { virtual void invoke () const = 0; protected: virtual ~ITestCase(); }; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; }; } namespace Catch { template class MethodTestCase : public SharedImpl { public: MethodTestCase( void (C::*method)() ) : m_method( method ) {} virtual void invoke() const { C obj; (obj.*m_method)(); } private: virtual ~MethodTestCase() {} void (C::*m_method)(); }; typedef void(*TestFunction)(); struct NameAndDesc { NameAndDesc( const char* _name = "", const char* _description= "" ) : name( _name ), description( _description ) {} const char* name; const char* description; }; struct AutoReg { AutoReg( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ); template AutoReg( void (C::*method)(), char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { registerTestCase( new MethodTestCase( method ), className, nameAndDesc, lineInfo ); } void registerTestCase( ITestCase* testCase, char const* className, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ); ~AutoReg(); private: AutoReg( AutoReg const& ); void operator= ( AutoReg const& ); }; } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( ... ) \ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ namespace{ \ struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ namespace{ \ struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() #endif // #included from: internal/catch_capture.hpp #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED // #included from: catch_result_builder.h #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED // #included from: catch_result_type.h #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED namespace Catch { // ResultWas::OfType enum struct ResultWas { enum OfType { Unknown = -1, Ok = 0, Info = 1, Warning = 2, FailureBit = 0x10, ExpressionFailed = FailureBit | 1, ExplicitFailure = FailureBit | 2, Exception = 0x100 | FailureBit, ThrewException = Exception | 1, DidntThrowException = Exception | 2, FatalErrorCondition = 0x200 | FailureBit }; }; inline bool isOk( ResultWas::OfType resultType ) { return ( resultType & ResultWas::FailureBit ) == 0; } inline bool isJustInfo( int flags ) { return flags == ResultWas::Info; } // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { Normal = 0x01, ContinueOnFailure = 0x02, // Failures fail test, but execution continues FalseTest = 0x04, // Prefix expression with ! SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { return static_cast( static_cast( lhs ) | static_cast( rhs ) ); } inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // #included from: catch_assertionresult.h #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED #include namespace Catch { struct AssertionInfo { AssertionInfo() {} AssertionInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, std::string const& _capturedExpression, ResultDisposition::Flags _resultDisposition ); std::string macroName; SourceLineInfo lineInfo; std::string capturedExpression; ResultDisposition::Flags resultDisposition; }; struct AssertionResultData { AssertionResultData() : resultType( ResultWas::Unknown ) {} std::string reconstructedExpression; std::string message; ResultWas::OfType resultType; }; class AssertionResult { public: AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionResult( AssertionResult const& ) = default; AssertionResult( AssertionResult && ) = default; AssertionResult& operator = ( AssertionResult const& ) = default; AssertionResult& operator = ( AssertionResult && ) = default; # endif bool isOk() const; bool succeeded() const; ResultWas::OfType getResultType() const; bool hasExpression() const; bool hasMessage() const; std::string getExpression() const; std::string getExpressionInMacro() const; bool hasExpandedExpression() const; std::string getExpandedExpression() const; std::string getMessage() const; SourceLineInfo getSourceInfo() const; std::string getTestMacroName() const; protected: AssertionInfo m_info; AssertionResultData m_resultData; }; } // end namespace Catch namespace Catch { struct TestFailureException{}; template class ExpressionLhs; struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; struct CopyableStream { CopyableStream() {} CopyableStream( CopyableStream const& other ) { oss << other.oss.str(); } CopyableStream& operator=( CopyableStream const& other ) { oss.str(""); oss << other.oss.str(); return *this; } std::ostringstream oss; }; class ResultBuilder { public: ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition ); template ExpressionLhs operator <= ( T const& operand ); ExpressionLhs operator <= ( bool value ); template ResultBuilder& operator << ( T const& value ) { m_stream.oss << value; return *this; } template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); ResultBuilder& setResultType( ResultWas::OfType result ); ResultBuilder& setResultType( bool result ); ResultBuilder& setLhs( std::string const& lhs ); ResultBuilder& setRhs( std::string const& rhs ); ResultBuilder& setOp( std::string const& op ); void endExpression(); std::string reconstructExpression() const; AssertionResult build() const; void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); void react(); bool shouldDebugBreak() const; bool allowThrows() const; private: AssertionInfo m_assertionInfo; AssertionResultData m_data; struct ExprComponents { ExprComponents() : testFalse( false ) {} bool testFalse; std::string lhs, rhs, op; } m_exprComponents; CopyableStream m_stream; bool m_shouldDebugBreak; bool m_shouldThrow; }; } // namespace Catch // Include after due to circular dependency: // #included from: catch_expression_lhs.hpp #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED // #included from: catch_evaluate.hpp #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch #endif #include namespace Catch { namespace Internal { enum Operator { IsEqualTo, IsNotEqualTo, IsLessThan, IsGreaterThan, IsLessThanOrEqualTo, IsGreaterThanOrEqualTo }; template struct OperatorTraits { static const char* getName(){ return "*error*"; } }; template<> struct OperatorTraits { static const char* getName(){ return "=="; } }; template<> struct OperatorTraits { static const char* getName(){ return "!="; } }; template<> struct OperatorTraits { static const char* getName(){ return "<"; } }; template<> struct OperatorTraits { static const char* getName(){ return ">"; } }; template<> struct OperatorTraits { static const char* getName(){ return "<="; } }; template<> struct OperatorTraits{ static const char* getName(){ return ">="; } }; template inline T& opCast(T const& t) { return const_cast(t); } // nullptr_t support based on pull request #154 from Konstantin Baumann #ifdef CATCH_CONFIG_CPP11_NULLPTR inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } #endif // CATCH_CONFIG_CPP11_NULLPTR // So the compare overloads can be operator agnostic we convey the operator as a template // enum, which is used to specialise an Evaluator for doing the comparison. template class Evaluator{}; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs) { return opCast( lhs ) == opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) != opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) < opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) > opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) >= opCast( rhs ); } }; template struct Evaluator { static bool evaluate( T1 const& lhs, T2 const& rhs ) { return opCast( lhs ) <= opCast( rhs ); } }; template bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // This level of indirection allows us to specialise for integer types // to avoid signed/ unsigned warnings // "base" overload template bool compare( T1 const& lhs, T2 const& rhs ) { return Evaluator::evaluate( lhs, rhs ); } // unsigned X to int template bool compare( unsigned int lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, int rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // unsigned X to long template bool compare( unsigned int lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned long lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } template bool compare( unsigned char lhs, long rhs ) { return applyEvaluator( lhs, static_cast( rhs ) ); } // int to unsigned X template bool compare( int lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( int lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // long to unsigned X template bool compare( long lhs, unsigned int rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned long rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } template bool compare( long lhs, unsigned char rhs ) { return applyEvaluator( static_cast( lhs ), rhs ); } // pointer to long (when comparing against NULL) template bool compare( long lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, long rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } // pointer to int (when comparing against NULL) template bool compare( int lhs, T* rhs ) { return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); } template bool compare( T* lhs, int rhs ) { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { return Evaluator::evaluate( NULL, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { return Evaluator::evaluate( lhs, NULL ); } #endif // CATCH_CONFIG_CPP11_NULLPTR } // end of namespace Internal } // end of namespace Catch #ifdef _MSC_VER #pragma warning(pop) #endif // #included from: catch_tostring.h #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED #include #include #include #include #include #ifdef __OBJC__ // #included from: catch_objc_arc.hpp #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED #import #ifdef __has_feature #define CATCH_ARC_ENABLED __has_feature(objc_arc) #else #define CATCH_ARC_ENABLED 0 #endif void arcSafeRelease( NSObject* obj ); id performOptionalSelector( id obj, SEL sel ); #if !CATCH_ARC_ENABLED inline void arcSafeRelease( NSObject* obj ) { [obj release]; } inline id performOptionalSelector( id obj, SEL sel ) { if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG #else inline void arcSafeRelease( NSObject* ){} inline id performOptionalSelector( id obj, SEL sel ) { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif if( [obj respondsToSelector: sel] ) return [obj performSelector: sel]; #ifdef __clang__ #pragma clang diagnostic pop #endif return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong #endif #endif #ifdef CATCH_CONFIG_CPP11_TUPLE #include #endif #ifdef CATCH_CONFIG_CPP11_IS_ENUM #include #endif namespace Catch { // Why we're here. template std::string toString( T const& value ); // Built in overloads std::string toString( std::string const& value ); std::string toString( std::wstring const& value ); std::string toString( const char* const value ); std::string toString( char* const value ); std::string toString( const wchar_t* const value ); std::string toString( wchar_t* const value ); std::string toString( int value ); std::string toString( unsigned long value ); std::string toString( unsigned int value ); std::string toString( const double value ); std::string toString( const float value ); std::string toString( bool value ); std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ); std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); std::string toString( NSObject* const& nsObject ); #endif namespace Detail { extern std::string unprintableString; struct BorgType { template BorgType( T const& ); }; struct TrueType { char sizer[1]; }; struct FalseType { char sizer[2]; }; TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); FalseType operator<<( std::ostream const&, BorgType const& ); template struct IsStreamInsertable { static std::ostream &s; static T const&t; enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template::value > struct EnumStringMaker { static std::string convert( T const& ) { return unprintableString; } }; template struct EnumStringMaker { static std::string convert( T const& v ) { return ::Catch::toString( static_cast::type>(v) ); } }; #endif template struct StringMakerBase { #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template static std::string convert( T const& v ) { return EnumStringMaker::convert( v ); } #else template static std::string convert( T const& ) { return unprintableString; } #endif }; template<> struct StringMakerBase { template static std::string convert( T const& _value ) { std::ostringstream oss; oss << _value; return oss.str(); } }; std::string rawMemoryToString( const void *object, std::size_t size ); template inline std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } } // end namespace Detail template struct StringMaker : Detail::StringMakerBase::value> {}; template struct StringMaker { template static std::string convert( U* p ) { if( !p ) return INTERNAL_CATCH_STRINGIFY( NULL ); else return Detail::rawMemoryToString( p ); } }; template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) return INTERNAL_CATCH_STRINGIFY( NULL ); else return Detail::rawMemoryToString( p ); } }; namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ); } //template //struct StringMaker > { // static std::string convert( std::vector const& v ) { // return Detail::rangeToString( v.begin(), v.end() ); // } //}; template std::string toString( std::vector const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } #ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size::value) > struct ElementPrinter { static void print( const Tuple& tuple, std::ostream& os ) { os << ( N ? ", " : " " ) << Catch::toString(std::get(tuple)); ElementPrinter::print(tuple,os); } }; template< typename Tuple, std::size_t N > struct ElementPrinter { static void print( const Tuple&, std::ostream& ) {} }; } template struct StringMaker> { static std::string convert( const std::tuple& tuple ) { std::ostringstream os; os << '{'; TupleDetail::ElementPrinter>::print( tuple, os ); os << " }"; return os.str(); } }; #endif // CATCH_CONFIG_CPP11_TUPLE namespace Detail { template std::string makeString( T const& value ) { return StringMaker::convert( value ); } } // end namespace Detail /// \brief converts any type to a string /// /// The default template forwards on to ostringstream - except when an /// ostringstream overload does not exist - in which case it attempts to detect /// that and writes {?}. /// Overload (not specialise) this template for custom typs that you don't want /// to provide an ostream overload for. template std::string toString( T const& value ) { return StringMaker::convert( value ); } namespace Detail { template std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { oss << Catch::toString( *first ); for( ++first ; first != last ; ++first ) oss << ", " << Catch::toString( *first ); } oss << " }"; return oss.str(); } } } // end namespace Catch namespace Catch { // Wraps the LHS of an expression and captures the operator and RHS (if any) - // wrapping them all in a ResultBuilder object template class ExpressionLhs { ExpressionLhs& operator = ( ExpressionLhs const& ); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs& operator = ( ExpressionLhs && ) = delete; # endif public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs( ExpressionLhs const& ) = default; ExpressionLhs( ExpressionLhs && ) = default; # endif template ResultBuilder& operator == ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator != ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator < ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator > ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator <= ( RhsT const& rhs ) { return captureExpression( rhs ); } template ResultBuilder& operator >= ( RhsT const& rhs ) { return captureExpression( rhs ); } ResultBuilder& operator == ( bool rhs ) { return captureExpression( rhs ); } ResultBuilder& operator != ( bool rhs ) { return captureExpression( rhs ); } void endExpression() { bool value = m_lhs ? true : false; m_rb .setLhs( Catch::toString( value ) ) .setResultType( value ) .endExpression(); } // Only simple binary expressions are allowed on the LHS. // If more complex compositions are required then place the sub expression in parentheses template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); template STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); private: template ResultBuilder& captureExpression( RhsT const& rhs ) { return m_rb .setResultType( Internal::compare( m_lhs, rhs ) ) .setLhs( Catch::toString( m_lhs ) ) .setRhs( Catch::toString( rhs ) ) .setOp( Internal::OperatorTraits::getName() ); } private: ResultBuilder& m_rb; T m_lhs; }; } // end namespace Catch namespace Catch { template inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { return ExpressionLhs( *this, value ); } } // namespace Catch // #included from: catch_message.h #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED #include namespace Catch { struct MessageInfo { MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ); std::string macroName; SourceLineInfo lineInfo; ResultWas::OfType type; std::string message; unsigned int sequence; bool operator == ( MessageInfo const& other ) const { return sequence == other.sequence; } bool operator < ( MessageInfo const& other ) const { return sequence < other.sequence; } private: static unsigned int globalCount; }; struct MessageBuilder { MessageBuilder( std::string const& macroName, SourceLineInfo const& lineInfo, ResultWas::OfType type ) : m_info( macroName, lineInfo, type ) {} template MessageBuilder& operator << ( T const& value ) { m_stream << value; return *this; } MessageInfo m_info; std::ostringstream m_stream; }; class ScopedMessage { public: ScopedMessage( MessageBuilder const& builder ); ScopedMessage( ScopedMessage const& other ); ~ScopedMessage(); MessageInfo m_info; }; } // end namespace Catch // #included from: catch_interfaces_capture.h #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED #include namespace Catch { class TestCase; class AssertionResult; struct AssertionInfo; struct SectionInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; struct IResultCapture { virtual ~IResultCapture(); virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; virtual std::string getCurrentTestName() const = 0; virtual const AssertionResult* getLastResult() const = 0; virtual void handleFatalErrorCondition( std::string const& message ) = 0; }; IResultCapture& getResultCapture(); } // #included from: catch_debugger.h #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED // #included from: catch_platform.h #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) #define CATCH_PLATFORM_MAC #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) #define CATCH_PLATFORM_IPHONE #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) #define CATCH_PLATFORM_WINDOWS #endif #include namespace Catch{ bool isDebuggerActive(); void writeToDebugConsole( std::string const& text ); } #ifdef CATCH_PLATFORM_MAC // The following code snippet based on: // http://cocoawithlove.com/2008/03/break-into-debugger.html #ifdef DEBUG #if defined(__ppc64__) || defined(__ppc__) #define CATCH_BREAK_INTO_DEBUGGER() \ if( Catch::isDebuggerActive() ) { \ __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ : : : "memory","r0","r3","r4" ); \ } #else #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} #endif #endif #elif defined(_MSC_VER) #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) void __stdcall DebugBreak(); #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } #endif #ifndef CATCH_BREAK_INTO_DEBUGGER #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); #endif // #included from: catch_interfaces_runner.h #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED namespace Catch { class TestCase; struct IRunner { virtual ~IRunner(); virtual bool aborting() const = 0; }; } /////////////////////////////////////////////////////////////////////////////// // In the event of a failure works out if the debugger needs to be invoked // and/or an exception thrown and takes appropriate action. // This needs to be done as a macro so the debugger will stop in the user // source code rather than in Catch library code #define INTERNAL_CATCH_REACT( resultBuilder ) \ if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ resultBuilder.react(); /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ ( __catchResult <= expr ).endExpression(); \ } \ catch( ... ) { \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ if( Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ if( !Catch::getResultCapture().getLastResult()->succeeded() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( exceptionType ) { \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ } \ catch( ... ) { \ __catchResult.useActiveException( resultDisposition ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #else #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ __catchResult << log + ::Catch::StreamEndStop(); \ __catchResult.captureResult( messageType ); \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) #endif /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( log, macroName ) \ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ try { \ std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ } \ INTERNAL_CATCH_REACT( __catchResult ) \ } while( Catch::alwaysFalse() ) // #included from: internal/catch_section.h #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED namespace Catch { struct SectionInfo { SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description = std::string() ); std::string name; std::string description; SourceLineInfo lineInfo; }; } // end namespace Catch // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED #include namespace Catch { struct Counts { Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} Counts operator - ( Counts const& other ) const { Counts diff; diff.passed = passed - other.passed; diff.failed = failed - other.failed; diff.failedButOk = failedButOk - other.failedButOk; return diff; } Counts& operator += ( Counts const& other ) { passed += other.passed; failed += other.failed; failedButOk += other.failedButOk; return *this; } std::size_t total() const { return passed + failed + failedButOk; } bool allPassed() const { return failed == 0 && failedButOk == 0; } bool allOk() const { return failed == 0; } std::size_t passed; std::size_t failed; std::size_t failedButOk; }; struct Totals { Totals operator - ( Totals const& other ) const { Totals diff; diff.assertions = assertions - other.assertions; diff.testCases = testCases - other.testCases; return diff; } Totals delta( Totals const& prevTotals ) const { Totals diff = *this - prevTotals; if( diff.assertions.failed > 0 ) ++diff.testCases.failed; else if( diff.assertions.failedButOk > 0 ) ++diff.testCases.failedButOk; else ++diff.testCases.passed; return diff; } Totals& operator += ( Totals const& other ) { assertions += other.assertions; testCases += other.testCases; return *this; } Counts assertions; Counts testCases; }; } // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED #ifdef CATCH_PLATFORM_WINDOWS typedef unsigned long long uint64_t; #else #include #endif namespace Catch { class Timer { public: Timer() : m_ticks( 0 ) {} void start(); unsigned int getElapsedMicroseconds() const; unsigned int getElapsedMilliseconds() const; double getElapsedSeconds() const; private: uint64_t m_ticks; }; } // namespace Catch #include namespace Catch { class Section : NonCopyable { public: Section( SectionInfo const& info ); ~Section(); // This indicates whether the section should be executed or not operator bool() const; private: SectionInfo m_info; std::string m_name; Counts m_assertions; bool m_sectionIncluded; Timer m_timer; }; } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS #define INTERNAL_CATCH_SECTION( ... ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) #else #define INTERNAL_CATCH_SECTION( name, desc ) \ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) #endif // #included from: internal/catch_generators.hpp #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED #include #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator() {} virtual T getValue( std::size_t index ) const = 0; virtual std::size_t size () const = 0; }; template class BetweenGenerator : public IGenerator { public: BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} virtual T getValue( std::size_t index ) const { return m_from+static_cast( index ); } virtual std::size_t size() const { return static_cast( 1+m_to-m_from ); } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { public: ValuesGenerator(){} void add( T value ) { m_values.push_back( value ); } virtual T getValue( std::size_t index ) const { return m_values[index]; } virtual std::size_t size() const { return m_values.size(); } private: std::vector m_values; }; template class CompositeGenerator { public: CompositeGenerator() : m_totalSize( 0 ) {} // *** Move semantics, similar to auto_ptr *** CompositeGenerator( CompositeGenerator& other ) : m_fileInfo( other.m_fileInfo ), m_totalSize( 0 ) { move( other ); } CompositeGenerator& setFileInfo( const char* fileInfo ) { m_fileInfo = fileInfo; return *this; } ~CompositeGenerator() { deleteAll( m_composed ); } operator T () const { size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); typename std::vector*>::const_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for( size_t index = 0; it != itEnd; ++it ) { const IGenerator* generator = *it; if( overallIndex >= index && overallIndex < index + generator->size() ) { return generator->getValue( overallIndex-index ); } index += generator->size(); } CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so } void add( const IGenerator* generator ) { m_totalSize += generator->size(); m_composed.push_back( generator ); } CompositeGenerator& then( CompositeGenerator& other ) { move( other ); return *this; } CompositeGenerator& then( T value ) { ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( value ); add( valuesGen ); return *this; } private: void move( CompositeGenerator& other ) { std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); m_totalSize += other.m_totalSize; other.m_composed.clear(); } std::vector*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { template CompositeGenerator between( T from, T to ) { CompositeGenerator generators; generators.add( new BetweenGenerator( from, to ) ); return generators; } template CompositeGenerator values( T val1, T val2 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3 ){ CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); generators.add( valuesGen ); return generators; } template CompositeGenerator values( T val1, T val2, T val3, T val4 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); valuesGen->add( val4 ); generators.add( valuesGen ); return generators; } } // end namespace Generators using namespace Generators; } // end namespace Catch #define INTERNAL_CATCH_LINESTR2( line ) #line #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) // #included from: internal/catch_interfaces_exception.h #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED #include namespace Catch { class TestCase; struct ITestCaseRegistry; struct IExceptionTranslatorRegistry; struct IExceptionTranslator; struct IReporterRegistry; struct IReporterFactory; struct IRegistryHub { virtual ~IRegistryHub(); virtual IReporterRegistry const& getReporterRegistry() const = 0; virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; }; struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; IRegistryHub& getRegistryHub(); IMutableRegistryHub& getMutableRegistryHub(); void cleanUp(); std::string translateActiveException(); } namespace Catch { typedef std::string(*exceptionTranslateFunction)(); struct IExceptionTranslator { virtual ~IExceptionTranslator(); virtual std::string translate() const = 0; }; struct IExceptionTranslatorRegistry { virtual ~IExceptionTranslatorRegistry(); virtual std::string translateActiveException() const = 0; }; class ExceptionTranslatorRegistrar { template class ExceptionTranslator : public IExceptionTranslator { public: ExceptionTranslator( std::string(*translateFunction)( T& ) ) : m_translateFunction( translateFunction ) {} virtual std::string translate() const { try { throw; } catch( T& ex ) { return m_translateFunction( ex ); } } protected: std::string(*m_translateFunction)( T& ); }; public: template ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { getMutableRegistryHub().registerTranslator ( new ExceptionTranslator( translateFunction ) ); } }; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) // #included from: internal/catch_approx.hpp #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED #include #include namespace Catch { namespace Detail { class Approx { public: explicit Approx ( double value ) : m_epsilon( std::numeric_limits::epsilon()*100 ), m_scale( 1.0 ), m_value( value ) {} Approx( Approx const& other ) : m_epsilon( other.m_epsilon ), m_scale( other.m_scale ), m_value( other.m_value ) {} static Approx custom() { return Approx( 0 ); } Approx operator()( double value ) { Approx approx( value ); approx.epsilon( m_epsilon ); approx.scale( m_scale ); return approx; } friend bool operator == ( double lhs, Approx const& rhs ) { // Thanks to Richard Harris for his help refining this formula return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); } friend bool operator == ( Approx const& lhs, double rhs ) { return operator==( rhs, lhs ); } friend bool operator != ( double lhs, Approx const& rhs ) { return !operator==( lhs, rhs ); } friend bool operator != ( Approx const& lhs, double rhs ) { return !operator==( rhs, lhs ); } Approx& epsilon( double newEpsilon ) { m_epsilon = newEpsilon; return *this; } Approx& scale( double newScale ) { m_scale = newScale; return *this; } std::string toString() const { std::ostringstream oss; oss << "Approx( " << Catch::toString( m_value ) << " )"; return oss.str(); } private: double m_epsilon; double m_scale; double m_value; }; } template<> inline std::string toString( Detail::Approx const& value ) { return value.toString(); } } // end namespace Catch // #included from: internal/catch_matchers.hpp #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED namespace Catch { namespace Matchers { namespace Impl { template struct Matcher : SharedImpl { typedef ExpressionT ExpressionType; virtual ~Matcher() {} virtual Ptr clone() const = 0; virtual bool match( ExpressionT const& expr ) const = 0; virtual std::string toString() const = 0; }; template struct MatcherImpl : Matcher { virtual Ptr > clone() const { return Ptr >( new DerivedT( static_cast( *this ) ) ); } }; namespace Generic { template class AllOf : public MatcherImpl, ExpressionT> { public: AllOf() {} AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} AllOf& add( Matcher const& matcher ) { m_matchers.push_back( matcher.clone() ); return *this; } virtual bool match( ExpressionT const& expr ) const { for( std::size_t i = 0; i < m_matchers.size(); ++i ) if( !m_matchers[i]->match( expr ) ) return false; return true; } virtual std::string toString() const { std::ostringstream oss; oss << "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) oss << " and "; oss << m_matchers[i]->toString(); } oss << " )"; return oss.str(); } private: std::vector > > m_matchers; }; template class AnyOf : public MatcherImpl, ExpressionT> { public: AnyOf() {} AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} AnyOf& add( Matcher const& matcher ) { m_matchers.push_back( matcher.clone() ); return *this; } virtual bool match( ExpressionT const& expr ) const { for( std::size_t i = 0; i < m_matchers.size(); ++i ) if( m_matchers[i]->match( expr ) ) return true; return false; } virtual std::string toString() const { std::ostringstream oss; oss << "( "; for( std::size_t i = 0; i < m_matchers.size(); ++i ) { if( i != 0 ) oss << " or "; oss << m_matchers[i]->toString(); } oss << " )"; return oss.str(); } private: std::vector > > m_matchers; }; } namespace StdString { inline std::string makeString( std::string const& str ) { return str; } inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } struct Equals : MatcherImpl { Equals( std::string const& str ) : m_str( str ){} Equals( Equals const& other ) : m_str( other.m_str ){} virtual ~Equals(); virtual bool match( std::string const& expr ) const { return m_str == expr; } virtual std::string toString() const { return "equals: \"" + m_str + "\""; } std::string m_str; }; struct Contains : MatcherImpl { Contains( std::string const& substr ) : m_substr( substr ){} Contains( Contains const& other ) : m_substr( other.m_substr ){} virtual ~Contains(); virtual bool match( std::string const& expr ) const { return expr.find( m_substr ) != std::string::npos; } virtual std::string toString() const { return "contains: \"" + m_substr + "\""; } std::string m_substr; }; struct StartsWith : MatcherImpl { StartsWith( std::string const& substr ) : m_substr( substr ){} StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} virtual ~StartsWith(); virtual bool match( std::string const& expr ) const { return expr.find( m_substr ) == 0; } virtual std::string toString() const { return "starts with: \"" + m_substr + "\""; } std::string m_substr; }; struct EndsWith : MatcherImpl { EndsWith( std::string const& substr ) : m_substr( substr ){} EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} virtual ~EndsWith(); virtual bool match( std::string const& expr ) const { return expr.find( m_substr ) == expr.size() - m_substr.size(); } virtual std::string toString() const { return "ends with: \"" + m_substr + "\""; } std::string m_substr; }; } // namespace StdString } // namespace Impl // The following functions create the actual matcher objects. // This allows the types to be inferred template inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, Impl::Matcher const& m2 ) { return Impl::Generic::AllOf().add( m1 ).add( m2 ); } template inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, Impl::Matcher const& m2, Impl::Matcher const& m3 ) { return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); } template inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, Impl::Matcher const& m2 ) { return Impl::Generic::AnyOf().add( m1 ).add( m2 ); } template inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, Impl::Matcher const& m2, Impl::Matcher const& m3 ) { return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); } inline Impl::StdString::Equals Equals( std::string const& str ) { return Impl::StdString::Equals( str ); } inline Impl::StdString::Equals Equals( const char* str ) { return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); } inline Impl::StdString::Contains Contains( std::string const& substr ) { return Impl::StdString::Contains( substr ); } inline Impl::StdString::Contains Contains( const char* substr ) { return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); } inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { return Impl::StdString::StartsWith( substr ); } inline Impl::StdString::StartsWith StartsWith( const char* substr ) { return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); } inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { return Impl::StdString::EndsWith( substr ); } inline Impl::StdString::EndsWith EndsWith( const char* substr ) { return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); } } // namespace Matchers using namespace Matchers; } // namespace Catch // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED // #included from: catch_tag_alias.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED #include namespace Catch { struct TagAlias { TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} std::string tag; SourceLineInfo lineInfo; }; struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } // #included from: catch_option.hpp #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED namespace Catch { // An optional type template class Option { public: Option() : nullableValue( NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) {} ~Option() { reset(); } Option& operator= ( Option const& _other ) { if( &_other != this ) { reset(); if( _other ) nullableValue = new( storage ) T( *_other ); } return *this; } Option& operator = ( T const& _value ) { reset(); nullableValue = new( storage ) T( _value ); return *this; } void reset() { if( nullableValue ) nullableValue->~T(); nullableValue = NULL; } T& operator*() { return *nullableValue; } T const& operator*() const { return *nullableValue; } T* operator->() { return nullableValue; } const T* operator->() const { return nullableValue; } T valueOr( T const& defaultValue ) const { return nullableValue ? *nullableValue : defaultValue; } bool some() const { return nullableValue != NULL; } bool none() const { return nullableValue == NULL; } bool operator !() const { return nullableValue == NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } private: T* nullableValue; char storage[sizeof(T)]; }; } // end namespace Catch namespace Catch { struct ITagAliasRegistry { virtual ~ITagAliasRegistry(); virtual Option find( std::string const& alias ) const = 0; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; static ITagAliasRegistry const& get(); }; } // end namespace Catch // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections // #included from: internal/catch_test_case_info.h #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED #include #include #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { struct ITestCase; struct TestCaseInfo { enum SpecialProperties{ None = 0, IsHidden = 1 << 1, ShouldFail = 1 << 2, MayFail = 1 << 3, Throws = 1 << 4 }; TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ); TestCaseInfo( TestCaseInfo const& other ); bool isHidden() const; bool throws() const; bool okToFail() const; bool expectedToFail() const; std::string name; std::string className; std::string description; std::set tags; std::set lcaseTags; std::string tagsAsString; SourceLineInfo lineInfo; SpecialProperties properties; }; class TestCase : public TestCaseInfo { public: TestCase( ITestCase* testCase, TestCaseInfo const& info ); TestCase( TestCase const& other ); TestCase withName( std::string const& _newName ) const; void invoke() const; TestCaseInfo const& getTestCaseInfo() const; void swap( TestCase& other ); bool operator == ( TestCase const& other ) const; bool operator < ( TestCase const& other ) const; TestCase& operator = ( TestCase const& other ); private: Ptr test; }; TestCase makeTestCase( ITestCase* testCase, std::string const& className, std::string const& name, std::string const& description, SourceLineInfo const& lineInfo ); } #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef __OBJC__ // #included from: internal/catch_objc.hpp #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED #import #include // NB. Any general catch headers included here must be included // in catch.hpp first to make sure they are included by the single // header for non obj-usage /////////////////////////////////////////////////////////////////////////////// // This protocol is really only here for (self) documenting purposes, since // all its methods are optional. @protocol OcFixture @optional -(void) setUp; -(void) tearDown; @end namespace Catch { class OcMethod : public SharedImpl { public: OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} virtual void invoke() const { id obj = [[m_cls alloc] init]; performOptionalSelector( obj, @selector(setUp) ); performOptionalSelector( obj, m_sel ); performOptionalSelector( obj, @selector(tearDown) ); arcSafeRelease( obj ); } private: virtual ~OcMethod() {} Class m_cls; SEL m_sel; }; namespace Detail{ inline std::string getAnnotation( Class cls, std::string const& annotationName, std::string const& testCaseName ) { NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; SEL sel = NSSelectorFromString( selStr ); arcSafeRelease( selStr ); id value = performOptionalSelector( cls, sel ); if( value ) return [(NSString*)value UTF8String]; return ""; } } inline size_t registerTestMethods() { size_t noTestMethods = 0; int noClasses = objc_getClassList( NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); for( int c = 0; c < noClasses; c++ ) { Class cls = classes[c]; { u_int count; Method* methods = class_copyMethodList( cls, &count ); for( u_int m = 0; m < count ; m++ ) { SEL selector = method_getName(methods[m]); std::string methodName = sel_getName(selector); if( startsWith( methodName, "Catch_TestCase_" ) ) { std::string testCaseName = methodName.substr( 15 ); std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); noTestMethods++; } } free(methods); } } return noTestMethods; } namespace Matchers { namespace Impl { namespace NSStringMatchers { template struct StringHolder : MatcherImpl{ StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolder() { arcSafeRelease( m_substr ); } NSString* m_substr; }; struct Equals : StringHolder { Equals( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str isEqualToString:m_substr]; } virtual std::string toString() const { return "equals string: " + Catch::toString( m_substr ); } }; struct Contains : StringHolder { Contains( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location != NSNotFound; } virtual std::string toString() const { return "contains string: " + Catch::toString( m_substr ); } }; struct StartsWith : StringHolder { StartsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == 0; } virtual std::string toString() const { return "starts with: " + Catch::toString( m_substr ); } }; struct EndsWith : StringHolder { EndsWith( NSString* substr ) : StringHolder( substr ){} virtual bool match( ExpressionType const& str ) const { return (str != nil || m_substr == nil ) && [str rangeOfString:m_substr].location == [str length] - [m_substr length]; } virtual std::string toString() const { return "ends with: " + Catch::toString( m_substr ); } }; } // namespace NSStringMatchers } // namespace Impl inline Impl::NSStringMatchers::Equals Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } inline Impl::NSStringMatchers::Contains Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } inline Impl::NSStringMatchers::StartsWith StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } inline Impl::NSStringMatchers::EndsWith EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } } // namespace Matchers using namespace Matchers; } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define OC_TEST_CASE( name, desc )\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ {\ return @ name; \ }\ +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ { \ return @ desc; \ } \ -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) #endif #ifdef CATCH_IMPL // #included from: internal/catch_impl.hpp #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED // Collect all the implementation files together here // These are the equivalent of what would usually be cpp files #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wweak-vtables" #endif // #included from: ../catch_runner.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED // #included from: catch_config.hpp #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED // #included from: catch_test_spec_parser.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif // #included from: catch_test_spec.hpp #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpadded" #endif #include #include namespace Catch { class TestSpec { struct Pattern : SharedImpl<> { virtual ~Pattern(); virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { enum WildcardPosition { NoWildcard = 0, WildcardAtStart = 1, WildcardAtEnd = 2, WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd }; public: NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { if( startsWith( m_name, "*" ) ) { m_name = m_name.substr( 1 ); m_wildcard = WildcardAtStart; } if( endsWith( m_name, "*" ) ) { m_name = m_name.substr( 0, m_name.size()-1 ); m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); } } virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { switch( m_wildcard ) { case NoWildcard: return m_name == toLower( testCase.name ); case WildcardAtStart: return endsWith( toLower( testCase.name ), m_name ); case WildcardAtEnd: return startsWith( toLower( testCase.name ), m_name ); case WildcardAtBothEnds: return contains( toLower( testCase.name ), m_name ); } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif throw std::logic_error( "Unknown enum" ); #ifdef __clang__ #pragma clang diagnostic pop #endif } private: std::string m_name; WildcardPosition m_wildcard; }; class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} virtual ~TagPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); } private: std::string m_tag; }; class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} virtual ~ExcludedPattern(); virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } private: Ptr m_underlyingPattern; }; struct Filter { std::vector > m_patterns; bool matches( TestCaseInfo const& testCase ) const { // All patterns in a filter must match for the filter to be a match for( std::vector >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) if( !(*it)->matches( testCase ) ) return false; return true; } }; public: bool hasFilters() const { return !m_filters.empty(); } bool matches( TestCaseInfo const& testCase ) const { // A TestSpec matches if any filter matches for( std::vector::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) if( it->matches( testCase ) ) return true; return false; } private: std::vector m_filters; friend class TestSpecParser; }; } #ifdef __clang__ #pragma clang diagnostic pop #endif namespace Catch { class TestSpecParser { enum Mode{ None, Name, QuotedName, Tag }; Mode m_mode; bool m_exclusion; std::size_t m_start, m_pos; std::string m_arg; TestSpec::Filter m_currentFilter; TestSpec m_testSpec; ITagAliasRegistry const* m_tagAliases; public: TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} TestSpecParser& parse( std::string const& arg ) { m_mode = None; m_exclusion = false; m_start = std::string::npos; m_arg = m_tagAliases->expandAliases( arg ); for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) visitChar( m_arg[m_pos] ); if( m_mode == Name ) addPattern(); return *this; } TestSpec testSpec() { addFilter(); return m_testSpec; } private: void visitChar( char c ) { if( m_mode == None ) { switch( c ) { case ' ': return; case '~': m_exclusion = true; return; case '[': return startNewMode( Tag, ++m_pos ); case '"': return startNewMode( QuotedName, ++m_pos ); default: startNewMode( Name, m_pos ); break; } } if( m_mode == Name ) { if( c == ',' ) { addPattern(); addFilter(); } else if( c == '[' ) { if( subString() == "exclude:" ) m_exclusion = true; else addPattern(); startNewMode( Tag, ++m_pos ); } } else if( m_mode == QuotedName && c == '"' ) addPattern(); else if( m_mode == Tag && c == ']' ) addPattern(); } void startNewMode( Mode mode, std::size_t start ) { m_mode = mode; m_start = start; } std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } template void addPattern() { std::string token = subString(); if( startsWith( token, "exclude:" ) ) { m_exclusion = true; token = token.substr( 8 ); } if( !token.empty() ) { Ptr pattern = new T( token ); if( m_exclusion ) pattern = new TestSpec::ExcludedPattern( pattern ); m_currentFilter.m_patterns.push_back( pattern ); } m_exclusion = false; m_mode = None; } void addFilter() { if( !m_currentFilter.m_patterns.empty() ) { m_testSpec.m_filters.push_back( m_currentFilter ); m_currentFilter = TestSpec::Filter(); } } }; inline TestSpec parseTestSpec( std::string const& arg ) { return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_interfaces_config.h #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED #include #include #include namespace Catch { struct Verbosity { enum Level { NoOutput = 0, Quiet, Normal }; }; struct WarnAbout { enum What { Nothing = 0x00, NoAssertions = 0x01 }; }; struct ShowDurations { enum OrNot { DefaultForReporter, Always, Never }; }; struct RunTests { enum InWhatOrder { InDeclarationOrder, InLexicographicalOrder, InRandomOrder }; }; class TestSpec; struct IConfig : IShared { virtual ~IConfig(); virtual bool allowThrows() const = 0; virtual std::ostream& stream() const = 0; virtual std::string name() const = 0; virtual bool includeSuccessfulResults() const = 0; virtual bool shouldDebugBreak() const = 0; virtual bool warnAboutMissingAssertions() const = 0; virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; virtual TestSpec const& testSpec() const = 0; virtual RunTests::InWhatOrder runOrder() const = 0; virtual unsigned int rngSeed() const = 0; virtual bool forceColour() const = 0; }; } // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED #include #ifdef __clang__ #pragma clang diagnostic ignored "-Wpadded" #endif namespace Catch { class Stream { public: Stream(); Stream( std::streambuf* _streamBuf, bool _isOwned ); void release(); std::streambuf* streamBuf; private: bool isOwned; }; std::ostream& cout(); std::ostream& cerr(); } #include #include #include #include #include #ifndef CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CONFIG_CONSOLE_WIDTH 80 #endif namespace Catch { struct ConfigData { ConfigData() : listTests( false ), listTags( false ), listReporters( false ), listTestNamesOnly( false ), showSuccessfulTests( false ), shouldDebugBreak( false ), noThrow( false ), showHelp( false ), showInvisibles( false ), forceColour( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), warnings( WarnAbout::Nothing ), showDurations( ShowDurations::DefaultForReporter ), runOrder( RunTests::InDeclarationOrder ) {} bool listTests; bool listTags; bool listReporters; bool listTestNamesOnly; bool showSuccessfulTests; bool shouldDebugBreak; bool noThrow; bool showHelp; bool showInvisibles; bool forceColour; int abortAfter; unsigned int rngSeed; Verbosity::Level verbosity; WarnAbout::What warnings; ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; std::string reporterName; std::string outputFilename; std::string name; std::string processName; std::vector testsOrTags; }; class Config : public SharedImpl { private: Config( Config const& other ); Config& operator = ( Config const& other ); virtual void dummy(); public: Config() : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), m_os( Catch::cout().rdbuf() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) parser.parse( data.testsOrTags[i] ); m_testSpec = parser.testSpec(); } } virtual ~Config() { m_os.rdbuf( Catch::cout().rdbuf() ); m_stream.release(); } void setFilename( std::string const& filename ) { m_data.outputFilename = filename; } std::string const& getFilename() const { return m_data.outputFilename ; } bool listTests() const { return m_data.listTests; } bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } bool listTags() const { return m_data.listTags; } bool listReporters() const { return m_data.listReporters; } std::string getProcessName() const { return m_data.processName; } bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } void setStreamBuf( std::streambuf* buf ) { m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); } void useStream( std::string const& streamName ) { Stream stream = createStream( streamName ); setStreamBuf( stream.streamBuf ); m_stream.release(); m_stream = stream; } std::string getReporterName() const { return m_data.reporterName; } int abortAfter() const { return m_data.abortAfter; } TestSpec const& testSpec() const { return m_testSpec; } bool showHelp() const { return m_data.showHelp; } bool showInvisibles() const { return m_data.showInvisibles; } // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } virtual std::ostream& stream() const { return m_os; } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } virtual unsigned int rngSeed() const { return m_data.rngSeed; } virtual bool forceColour() const { return m_data.forceColour; } private: ConfigData m_data; Stream m_stream; mutable std::ostream m_os; TestSpec m_testSpec; }; } // end namespace Catch // #included from: catch_clara.h #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED // Use Catch's value for console width (store Clara's off to the side, if present) #ifdef CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH #undef CLARA_CONFIG_CONSOLE_WIDTH #endif #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH // Declare Clara inside the Catch namespace #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: ../external/clara.h // Only use header guard if we are not using an outer namespace #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) #ifndef STITCH_CLARA_OPEN_NAMESPACE #define TWOBLUECUBES_CLARA_H_INCLUDED #define STITCH_CLARA_OPEN_NAMESPACE #define STITCH_CLARA_CLOSE_NAMESPACE #else #define STITCH_CLARA_CLOSE_NAMESPACE } #endif #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE // ----------- #included from tbc_text_format.h ----------- // Only use header guard if we are not using an outer namespace #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE #define TBC_TEXT_FORMAT_H_INCLUDED #endif #include #include #include // Use optional outer namespace #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ), tabChar( '\t' ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { std::string wrappableChars = " [({.,/|\\-"; std::size_t indent = _attr.initialIndent != std::string::npos ? _attr.initialIndent : _attr.indent; std::string remainder = _str; while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::size_t tabPos = std::string::npos; std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); std::size_t pos = remainder.find_first_of( '\n' ); if( pos <= width ) { width = pos; } pos = remainder.find_last_of( _attr.tabChar, width ); if( pos != std::string::npos ) { tabPos = pos; if( remainder[width] == '\n' ) width--; remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); } if( width == remainder.size() ) { spliceLine( indent, remainder, width ); } else if( remainder[width] == '\n' ) { spliceLine( indent, remainder, width ); if( width <= 1 || remainder.size() != 1 ) remainder = remainder.substr( 1 ); indent = _attr.indent; } else { pos = remainder.find_last_of( wrappableChars, width ); if( pos != std::string::npos && pos > 0 ) { spliceLine( indent, remainder, pos ); if( remainder[0] == ' ' ) remainder = remainder.substr( 1 ); } else { spliceLine( indent, remainder, width-1 ); lines.back() += "-"; } if( lines.size() == 1 ) indent = _attr.indent; if( tabPos != std::string::npos ) indent += tabPos; } } } void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); _remainder = _remainder.substr( _pos ); } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TBC_TEXT_FORMAT_H_INCLUDED // ----------- end of #include from tbc_text_format.h ----------- // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE #include #include #include #include // Use optional outer namespace #ifdef STITCH_CLARA_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE #endif namespace Clara { struct UnpositionalTag {}; extern UnpositionalTag _; #ifdef CLARA_CONFIG_MAIN UnpositionalTag _; #endif namespace Detail { #ifdef CLARA_CONSOLE_WIDTH const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif using namespace Tbc; inline bool startsWith( std::string const& str, std::string const& prefix ) { return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; } template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct IsBool { static const bool value = false; }; template<> struct IsBool { static const bool value = true; }; template void convertInto( std::string const& _source, T& _dest ) { std::stringstream ss; ss << _source; ss >> _dest; if( ss.fail() ) throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); } inline void convertInto( std::string const& _source, std::string& _dest ) { _dest = _source; } inline void convertInto( std::string const& _source, bool& _dest ) { std::string sourceLC = _source; std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) _dest = true; else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) _dest = false; else throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); } inline void convertInto( bool _source, bool& _dest ) { _dest = _source; } template inline void convertInto( bool, T& ) { throw std::runtime_error( "Invalid conversion" ); } template struct IArgFunction { virtual ~IArgFunction() {} # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; # endif virtual void set( ConfigT& config, std::string const& value ) const = 0; virtual void setFlag( ConfigT& config ) const = 0; virtual bool takesArg() const = 0; virtual IArgFunction* clone() const = 0; }; template class BoundArgFunction { public: BoundArgFunction() : functionObj( NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; delete functionObj; functionObj = newFunctionObj; return *this; } ~BoundArgFunction() { delete functionObj; } void set( ConfigT& config, std::string const& value ) const { functionObj->set( config, value ); } void setFlag( ConfigT& config ) const { functionObj->setFlag( config ); } bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { return functionObj != NULL; } private: IArgFunction* functionObj; }; template struct NullBinder : IArgFunction{ virtual void set( C&, std::string const& ) const {} virtual void setFlag( C& ) const {} virtual bool takesArg() const { return true; } virtual IArgFunction* clone() const { return new NullBinder( *this ); } }; template struct BoundDataMember : IArgFunction{ BoundDataMember( M C::* _member ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { convertInto( stringValue, p.*member ); } virtual void setFlag( C& p ) const { convertInto( true, p.*member ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } M C::* member; }; template struct BoundUnaryMethod : IArgFunction{ BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); (p.*member)( value ); } virtual void setFlag( C& p ) const { typename RemoveConstRef::type value; convertInto( true, value ); (p.*member)( value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } void (C::*member)( M ); }; template struct BoundNullaryMethod : IArgFunction{ BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} virtual void set( C& p, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) (p.*member)(); } virtual void setFlag( C& p ) const { (p.*member)(); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } void (C::*member)(); }; template struct BoundUnaryFunction : IArgFunction{ BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { bool value; convertInto( stringValue, value ); if( value ) function( obj ); } virtual void setFlag( C& p ) const { function( p ); } virtual bool takesArg() const { return false; } virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } void (*function)( C& ); }; template struct BoundBinaryFunction : IArgFunction{ BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} virtual void set( C& obj, std::string const& stringValue ) const { typename RemoveConstRef::type value; convertInto( stringValue, value ); function( obj, value ); } virtual void setFlag( C& obj ) const { typename RemoveConstRef::type value; convertInto( true, value ); function( obj, value ); } virtual bool takesArg() const { return !IsBool::value; } virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } void (*function)( C&, T ); }; } // namespace Detail struct Parser { Parser() : separators( " \t=:" ) {} struct Token { enum Type { Positional, ShortOpt, LongOpt }; Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} Type type; std::string data; }; void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { const std::string doubleDash = "--"; for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) parseIntoTokens( argv[i] , tokens); } void parseIntoTokens( std::string arg, std::vector& tokens ) const { while( !arg.empty() ) { Parser::Token token( Parser::Token::Positional, arg ); arg = ""; if( token.data[0] == '-' ) { if( token.data.size() > 1 && token.data[1] == '-' ) { token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); } else { token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { arg = "-" + token.data.substr( 1 ); token.data = token.data.substr( 0, 1 ); } } } if( token.type != Parser::Token::Positional ) { std::size_t pos = token.data.find_first_of( separators ); if( pos != std::string::npos ) { arg = token.data.substr( pos+1 ); token.data = token.data.substr( 0, pos ); } } tokens.push_back( token ); } } std::string separators; }; template struct CommonArgProperties { CommonArgProperties() {} CommonArgProperties( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ) {} Detail::BoundArgFunction boundField; std::string description; std::string detail; std::string placeholder; // Only value if boundField takes an arg bool takesArg() const { return !placeholder.empty(); } void validate() const { if( !boundField.isSet() ) throw std::logic_error( "option not bound" ); } }; struct OptionArgProperties { std::vector shortNames; std::string longName; bool hasShortName( std::string const& shortName ) const { return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); } bool hasLongName( std::string const& _longName ) const { return _longName == longName; } }; struct PositionalArgProperties { PositionalArgProperties() : position( -1 ) {} int position; // -1 means non-positional (floating) bool isFixedPositional() const { return position != -1; } }; template class CommandLine { struct Arg : CommonArgProperties, OptionArgProperties, PositionalArgProperties { Arg() {} Arg( Detail::BoundArgFunction const& _boundField ) : CommonArgProperties( _boundField ) {} using CommonArgProperties::placeholder; // !TBD std::string dbgName() const { if( !longName.empty() ) return "--" + longName; if( !shortNames.empty() ) return "-" + shortNames[0]; return "positional args"; } std::string commands() const { std::ostringstream oss; bool first = true; std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); for(; it != itEnd; ++it ) { if( first ) first = false; else oss << ", "; oss << "-" << *it; } if( !longName.empty() ) { if( !first ) oss << ", "; oss << "--" << longName; } if( !placeholder.empty() ) oss << " <" << placeholder << ">"; return oss.str(); } }; // NOTE: std::auto_ptr is deprecated in c++11/c++0x #if defined(__cplusplus) && __cplusplus > 199711L typedef std::unique_ptr ArgAutoPtr; #else typedef std::auto_ptr ArgAutoPtr; #endif friend void addOptName( Arg& arg, std::string const& optName ) { if( optName.empty() ) return; if( Detail::startsWith( optName, "--" ) ) { if( !arg.longName.empty() ) throw std::logic_error( "Only one long opt may be specified. '" + arg.longName + "' already specified, now attempting to add '" + optName + "'" ); arg.longName = optName.substr( 2 ); } else if( Detail::startsWith( optName, "-" ) ) arg.shortNames.push_back( optName.substr( 1 ) ); else throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); } friend void setPositionalArg( Arg& arg, int position ) { arg.position = position; } class ArgBuilder { public: ArgBuilder( Arg* arg ) : m_arg( arg ) {} // Bind a non-boolean data member (requires placeholder string) template void bind( M C::* field, std::string const& placeholder ) { m_arg->boundField = new Detail::BoundDataMember( field ); m_arg->placeholder = placeholder; } // Bind a boolean data member (no placeholder required) template void bind( bool C::* field ) { m_arg->boundField = new Detail::BoundDataMember( field ); } // Bind a method taking a single, non-boolean argument (requires a placeholder string) template void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); m_arg->placeholder = placeholder; } // Bind a method taking a single, boolean argument (no placeholder string required) template void bind( void (C::* unaryMethod)( bool ) ) { m_arg->boundField = new Detail::BoundUnaryMethod( unaryMethod ); } // Bind a method that takes no arguments (will be called if opt is present) template void bind( void (C::* nullaryMethod)() ) { m_arg->boundField = new Detail::BoundNullaryMethod( nullaryMethod ); } // Bind a free function taking a single argument - the object to operate on (no placeholder string required) template void bind( void (* unaryFunction)( C& ) ) { m_arg->boundField = new Detail::BoundUnaryFunction( unaryFunction ); } // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) template void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { m_arg->boundField = new Detail::BoundBinaryFunction( binaryFunction ); m_arg->placeholder = placeholder; } ArgBuilder& describe( std::string const& description ) { m_arg->description = description; return *this; } ArgBuilder& detail( std::string const& detail ) { m_arg->detail = detail; return *this; } protected: Arg* m_arg; }; class OptBuilder : public ArgBuilder { public: OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} OptBuilder& operator[]( std::string const& optName ) { addOptName( *ArgBuilder::m_arg, optName ); return *this; } }; public: CommandLine() : m_boundProcessName( new Detail::NullBinder() ), m_highestSpecifiedArgPosition( 0 ), m_throwOnUnrecognisedTokens( false ) {} CommandLine( CommandLine const& other ) : m_boundProcessName( other.m_boundProcessName ), m_options ( other.m_options ), m_positionalArgs( other.m_positionalArgs ), m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) { if( other.m_floatingArg.get() ) m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); } CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { m_throwOnUnrecognisedTokens = shouldThrow; return *this; } OptBuilder operator[]( std::string const& optName ) { m_options.push_back( Arg() ); addOptName( m_options.back(), optName ); OptBuilder builder( &m_options.back() ); return builder; } ArgBuilder operator[]( int position ) { m_positionalArgs.insert( std::make_pair( position, Arg() ) ); if( position > m_highestSpecifiedArgPosition ) m_highestSpecifiedArgPosition = position; setPositionalArg( m_positionalArgs[position], position ); ArgBuilder builder( &m_positionalArgs[position] ); return builder; } // Invoke this with the _ instance ArgBuilder operator[]( UnpositionalTag ) { if( m_floatingArg.get() ) throw std::logic_error( "Only one unpositional argument can be added" ); m_floatingArg.reset( new Arg() ); ArgBuilder builder( m_floatingArg.get() ); return builder; } template void bindProcessName( M C::* field ) { m_boundProcessName = new Detail::BoundDataMember( field ); } template void bindProcessName( void (C::*_unaryMethod)( M ) ) { m_boundProcessName = new Detail::BoundUnaryMethod( _unaryMethod ); } void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; std::size_t maxWidth = 0; for( it = itBegin; it != itEnd; ++it ) maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { Detail::Text usage( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { std::string usageCol = i < usage.size() ? usage[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) << desc[i]; os << "\n"; } } } std::string optUsage() const { std::ostringstream oss; optUsage( oss ); return oss.str(); } void argSynopsis( std::ostream& os ) const { for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { if( i > 1 ) os << " "; typename std::map::const_iterator it = m_positionalArgs.find( i ); if( it != m_positionalArgs.end() ) os << "<" << it->second.placeholder << ">"; else if( m_floatingArg.get() ) os << "<" << m_floatingArg->placeholder << ">"; else throw std::logic_error( "non consecutive positional arguments with no floating args" ); } // !TBD No indication of mandatory args if( m_floatingArg.get() ) { if( m_highestSpecifiedArgPosition > 1 ) os << " "; os << "[<" << m_floatingArg->placeholder << "> ...]"; } } std::string argSynopsis() const { std::ostringstream oss; argSynopsis( oss ); return oss.str(); } void usage( std::ostream& os, std::string const& procName ) const { validate(); os << "usage:\n " << procName << " "; argSynopsis( os ); if( !m_options.empty() ) { os << " [options]\n\nwhere options are: \n"; optUsage( os, 2 ); } os << "\n"; } std::string usage( std::string const& procName ) const { std::ostringstream oss; usage( oss, procName ); return oss.str(); } ConfigT parse( int argc, char const * const * argv ) const { ConfigT config; parseInto( argc, argv, config ); return config; } std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { std::string processName = argv[0]; std::size_t lastSlash = processName.find_last_of( "/\\" ); if( lastSlash != std::string::npos ) processName = processName.substr( lastSlash+1 ); m_boundProcessName.set( config, processName ); std::vector tokens; Parser parser; parser.parseIntoTokens( argc, argv, tokens ); return populate( tokens, config ); } std::vector populate( std::vector const& tokens, ConfigT& config ) const { validate(); std::vector unusedTokens = populateOptions( tokens, config ); unusedTokens = populateFixedArgs( unusedTokens, config ); unusedTokens = populateFloatingArgs( unusedTokens, config ); return unusedTokens; } std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; std::vector errors; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); for(; it != itEnd; ++it ) { Arg const& arg = *it; try { if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { if( arg.takesArg() ) { if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) errors.push_back( "Expected argument to option: " + token.data ); else arg.boundField.set( config, tokens[++i].data ); } else { arg.boundField.setFlag( config ); } break; } } catch( std::exception& ex ) { errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); } } if( it == itEnd ) { if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) unusedTokens.push_back( token ); else if( errors.empty() && m_throwOnUnrecognisedTokens ) errors.push_back( "unrecognised option: " + token.data ); } } if( !errors.empty() ) { std::ostringstream oss; for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); it != itEnd; ++it ) { if( it != errors.begin() ) oss << "\n"; oss << *it; } throw std::runtime_error( oss.str() ); } return unusedTokens; } std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { std::vector unusedTokens; int position = 1; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; typename std::map::const_iterator it = m_positionalArgs.find( position ); if( it != m_positionalArgs.end() ) it->second.boundField.set( config, token.data ); else unusedTokens.push_back( token ); if( token.type == Parser::Token::Positional ) position++; } return unusedTokens; } std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { if( !m_floatingArg.get() ) return tokens; std::vector unusedTokens; for( std::size_t i = 0; i < tokens.size(); ++i ) { Parser::Token const& token = tokens[i]; if( token.type == Parser::Token::Positional ) m_floatingArg->boundField.set( config, token.data ); else unusedTokens.push_back( token ); } return unusedTokens; } void validate() const { if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) throw std::logic_error( "No options or arguments specified" ); for( typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); it != itEnd; ++it ) it->validate(); } private: Detail::BoundArgFunction m_boundProcessName; std::vector m_options; std::map m_positionalArgs; ArgAutoPtr m_floatingArg; int m_highestSpecifiedArgPosition; bool m_throwOnUnrecognisedTokens; }; } // end namespace Clara STITCH_CLARA_CLOSE_NAMESPACE #undef STITCH_CLARA_OPEN_NAMESPACE #undef STITCH_CLARA_CLOSE_NAMESPACE #endif // TWOBLUECUBES_CLARA_H_INCLUDED #undef STITCH_CLARA_OPEN_NAMESPACE // Restore Clara's value for console width, if present #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #endif #include namespace Catch { inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } inline void abortAfterX( ConfigData& config, int x ) { if( x < 1 ) throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); else throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); } inline void setOrder( ConfigData& config, std::string const& order ) { if( startsWith( "declared", order ) ) config.runOrder = RunTests::InDeclarationOrder; else if( startsWith( "lexical", order ) ) config.runOrder = RunTests::InLexicographicalOrder; else if( startsWith( "random", order ) ) config.runOrder = RunTests::InRandomOrder; else throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); } inline void setRngSeed( ConfigData& config, std::string const& seed ) { if( seed == "time" ) { config.rngSeed = static_cast( std::time(0) ); } else { std::stringstream ss; ss << seed; ss >> config.rngSeed; if( ss.fail() ) throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); } } inline void setVerbosity( ConfigData& config, int level ) { // !TBD: accept strings? config.verbosity = static_cast( level ); } inline void setShowDurations( ConfigData& config, bool _showDurations ) { config.showDurations = _showDurations ? ShowDurations::Always : ShowDurations::Never; } inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { std::ifstream f( _filename.c_str() ); if( !f.is_open() ) throw std::domain_error( "Unable to load input file: " + _filename ); std::string line; while( std::getline( f, line ) ) { line = trim(line); if( !line.empty() && !startsWith( line, "#" ) ) addTestOrTags( config, "\"" + line + "\"," ); } } inline Clara::CommandLine makeCommandLineParser() { using namespace Clara; CommandLine cli; cli.bindProcessName( &ConfigData::processName ); cli["-?"]["-h"]["--help"] .describe( "display usage information" ) .bind( &ConfigData::showHelp ); cli["-l"]["--list-tests"] .describe( "list all/matching test cases" ) .bind( &ConfigData::listTests ); cli["-t"]["--list-tags"] .describe( "list all/matching tags" ) .bind( &ConfigData::listTags ); cli["-s"]["--success"] .describe( "include successful tests in output" ) .bind( &ConfigData::showSuccessfulTests ); cli["-b"]["--break"] .describe( "break into debugger on failure" ) .bind( &ConfigData::shouldDebugBreak ); cli["-e"]["--nothrow"] .describe( "skip exception tests" ) .bind( &ConfigData::noThrow ); cli["-i"]["--invisibles"] .describe( "show invisibles (tabs, newlines)" ) .bind( &ConfigData::showInvisibles ); cli["-o"]["--out"] .describe( "output filename" ) .bind( &ConfigData::outputFilename, "filename" ); cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) .bind( &ConfigData::reporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) .bind( &ConfigData::name, "name" ); cli["-a"]["--abort"] .describe( "abort at first failure" ) .bind( &abortAfterFirst ); cli["-x"]["--abortx"] .describe( "abort after x failures" ) .bind( &abortAfterX, "no. failures" ); cli["-w"]["--warn"] .describe( "enable warnings" ) .bind( &addWarning, "warning name" ); // - needs updating if reinstated // cli.into( &setVerbosity ) // .describe( "level of verbosity (0=no output)" ) // .shortOpt( "v") // .longOpt( "verbosity" ) // .placeholder( "level" ); cli[_] .describe( "which test or tests to use" ) .bind( &addTestOrTags, "test name, pattern or tags" ); cli["-d"]["--durations"] .describe( "show test durations" ) .bind( &setShowDurations, "yes/no" ); cli["-f"]["--input-file"] .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) .bind( &ConfigData::listTestNamesOnly ); cli["--list-reporters"] .describe( "list all reporters" ) .bind( &ConfigData::listReporters ); cli["--order"] .describe( "test case order (defaults to decl)" ) .bind( &setOrder, "decl|lex|rand" ); cli["--rng-seed"] .describe( "set a specific seed for random numbers" ) .bind( &setRngSeed, "'time'|number" ); cli["--force-colour"] .describe( "force colourised output" ) .bind( &ConfigData::forceColour ); return cli; } } // end namespace Catch // #included from: internal/catch_list.hpp #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED // #included from: catch_text.h #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch // #included from: ../external/tbc_text_format.h // Only use header guard if we are not using an outer namespace #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED # endif # else # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED # endif #endif #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #include #include #include // Use optional outer namespace #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { #endif namespace Tbc { #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; #else const unsigned int consoleWidth = 80; #endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), width( consoleWidth-1 ), tabChar( '\t' ) {} TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } std::size_t initialIndent; // indent of first line, or npos std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos std::size_t width; // maximum width of text, including indent. Longer text will wrap char tabChar; // If this char is seen the indent is changed to current pos }; class Text { public: Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) : attr( _attr ) { std::string wrappableChars = " [({.,/|\\-"; std::size_t indent = _attr.initialIndent != std::string::npos ? _attr.initialIndent : _attr.indent; std::string remainder = _str; while( !remainder.empty() ) { if( lines.size() >= 1000 ) { lines.push_back( "... message truncated due to excessive size" ); return; } std::size_t tabPos = std::string::npos; std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); std::size_t pos = remainder.find_first_of( '\n' ); if( pos <= width ) { width = pos; } pos = remainder.find_last_of( _attr.tabChar, width ); if( pos != std::string::npos ) { tabPos = pos; if( remainder[width] == '\n' ) width--; remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); } if( width == remainder.size() ) { spliceLine( indent, remainder, width ); } else if( remainder[width] == '\n' ) { spliceLine( indent, remainder, width ); if( width <= 1 || remainder.size() != 1 ) remainder = remainder.substr( 1 ); indent = _attr.indent; } else { pos = remainder.find_last_of( wrappableChars, width ); if( pos != std::string::npos && pos > 0 ) { spliceLine( indent, remainder, pos ); if( remainder[0] == ' ' ) remainder = remainder.substr( 1 ); } else { spliceLine( indent, remainder, width-1 ); lines.back() += "-"; } if( lines.size() == 1 ) indent = _attr.indent; if( tabPos != std::string::npos ) indent += tabPos; } } } void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); _remainder = _remainder.substr( _pos ); } typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return lines.begin(); } const_iterator end() const { return lines.end(); } std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } std::string toString() const { std::ostringstream oss; oss << *this; return oss.str(); } inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); it != itEnd; ++it ) { if( it != _text.begin() ) _stream << "\n"; _stream << *it; } return _stream; } private: std::string str; TextAttributes attr; std::vector lines; }; } // end namespace Tbc #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE } // end outer namespace #endif #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace Catch { using Tbc::Text; using Tbc::TextAttributes; } // #included from: catch_console_colour.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED namespace Catch { struct Colour { enum Code { None = 0, White, Red, Green, Blue, Cyan, Yellow, Grey, Bright = 0x10, BrightRed = Bright | Red, BrightGreen = Bright | Green, LightGrey = Bright | Grey, BrightWhite = Bright | White, // By intention FileName = LightGrey, Warning = Yellow, ResultError = BrightRed, ResultSuccess = BrightGreen, ResultExpectedFailure = Warning, Error = BrightRed, Success = Green, OriginalExpression = Cyan, ReconstructedExpression = Yellow, SecondaryText = LightGrey, Headers = White }; // Use constructed object for RAII guard Colour( Code _colourCode ); Colour( Colour const& other ); ~Colour(); // Use static method for one-shot changes static void use( Code _colourCode ); private: bool m_moved; }; inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } } // end namespace Catch // #included from: catch_interfaces_reporter.h #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED #include #include #include #include namespace Catch { struct ReporterConfig { explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; Ptr m_fullConfig; }; struct ReporterPreferences { ReporterPreferences() : shouldRedirectStdOut( false ) {} bool shouldRedirectStdOut; }; template struct LazyStat : Option { LazyStat() : used( false ) {} LazyStat& operator=( T const& _value ) { Option::operator=( _value ); used = false; return *this; } void reset() { Option::reset(); used = false; } bool used; }; struct TestRunInfo { TestRunInfo( std::string const& _name ) : name( _name ) {} std::string name; }; struct GroupInfo { GroupInfo( std::string const& _name, std::size_t _groupIndex, std::size_t _groupsCount ) : name( _name ), groupIndex( _groupIndex ), groupsCounts( _groupsCount ) {} std::string name; std::size_t groupIndex; std::size_t groupsCounts; }; struct AssertionStats { AssertionStats( AssertionResult const& _assertionResult, std::vector const& _infoMessages, Totals const& _totals ) : assertionResult( _assertionResult ), infoMessages( _infoMessages ), totals( _totals ) { if( assertionResult.hasMessage() ) { // Copy message into messages list. // !TBD This should have been done earlier, somewhere MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); builder << assertionResult.getMessage(); builder.m_info.message = builder.m_stream.str(); infoMessages.push_back( builder.m_info ); } } virtual ~AssertionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; AssertionStats& operator = ( AssertionStats && ) = default; # endif AssertionResult assertionResult; std::vector infoMessages; Totals totals; }; struct SectionStats { SectionStats( SectionInfo const& _sectionInfo, Counts const& _assertions, double _durationInSeconds, bool _missingAssertions ) : sectionInfo( _sectionInfo ), assertions( _assertions ), durationInSeconds( _durationInSeconds ), missingAssertions( _missingAssertions ) {} virtual ~SectionStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; SectionStats& operator = ( SectionStats && ) = default; # endif SectionInfo sectionInfo; Counts assertions; double durationInSeconds; bool missingAssertions; }; struct TestCaseStats { TestCaseStats( TestCaseInfo const& _testInfo, Totals const& _totals, std::string const& _stdOut, std::string const& _stdErr, bool _aborting ) : testInfo( _testInfo ), totals( _totals ), stdOut( _stdOut ), stdErr( _stdErr ), aborting( _aborting ) {} virtual ~TestCaseStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; TestCaseStats& operator = ( TestCaseStats && ) = default; # endif TestCaseInfo testInfo; Totals totals; std::string stdOut; std::string stdErr; bool aborting; }; struct TestGroupStats { TestGroupStats( GroupInfo const& _groupInfo, Totals const& _totals, bool _aborting ) : groupInfo( _groupInfo ), totals( _totals ), aborting( _aborting ) {} TestGroupStats( GroupInfo const& _groupInfo ) : groupInfo( _groupInfo ), aborting( false ) {} virtual ~TestGroupStats(); # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; TestGroupStats& operator = ( TestGroupStats && ) = default; # endif GroupInfo groupInfo; Totals totals; bool aborting; }; struct TestRunStats { TestRunStats( TestRunInfo const& _runInfo, Totals const& _totals, bool _aborting ) : runInfo( _runInfo ), totals( _totals ), aborting( _aborting ) {} virtual ~TestRunStats(); # ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS TestRunStats( TestRunStats const& _other ) : runInfo( _other.runInfo ), totals( _other.totals ), aborting( _other.aborting ) {} # else TestRunStats( TestRunStats const& ) = default; TestRunStats( TestRunStats && ) = default; TestRunStats& operator = ( TestRunStats const& ) = default; TestRunStats& operator = ( TestRunStats && ) = default; # endif TestRunInfo runInfo; Totals totals; bool aborting; }; struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); // Implementing class must also provide the following static method: // static std::string getDescription(); virtual ReporterPreferences getPreferences() const = 0; virtual void noMatchingTestCases( std::string const& spec ) = 0; virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; struct IReporterFactory { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { typedef std::map FactoryMap; virtual ~IReporterRegistry(); virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; }; } #include #include namespace Catch { inline std::size_t listTests( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Matching test cases:\n"; else { Catch::cout() << "All available test cases:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::size_t matchedTests = 0; TextAttributes nameAttr, tagsAttr; nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); std::vector matchedTestCases; getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); Colour::Code colour = testCaseInfo.isHidden() ? Colour::SecondaryText : Colour::None; Colour colourGuard( colour ); Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; if( !testCaseInfo.tags.empty() ) Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; } if( !config.testSpec().hasFilters() ) Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; else Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; return matchedTests; } inline std::size_t listTestsNamesOnly( Config const& config ) { TestSpec testSpec = config.testSpec(); if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases; getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { matchedTests++; TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); Catch::cout() << testCaseInfo.name << std::endl; } return matchedTests; } struct TagInfo { TagInfo() : count ( 0 ) {} void add( std::string const& spelling ) { ++count; spellings.insert( spelling ); } std::string all() const { std::string out; for( std::set::const_iterator it = spellings.begin(), itEnd = spellings.end(); it != itEnd; ++it ) out += "[" + *it + "]"; return out; } std::set spellings; std::size_t count; }; inline std::size_t listTags( Config const& config ) { TestSpec testSpec = config.testSpec(); if( config.testSpec().hasFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { Catch::cout() << "All available tags:\n"; testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); } std::map tagCounts; std::vector matchedTestCases; getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { for( std::set::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), tagItEnd = it->getTestCaseInfo().tags.end(); tagIt != tagItEnd; ++tagIt ) { std::string tagName = *tagIt; std::string lcaseTagName = toLower( tagName ); std::map::iterator countIt = tagCounts.find( lcaseTagName ); if( countIt == tagCounts.end() ) countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; countIt->second.add( tagName ); } } for( std::map::const_iterator countIt = tagCounts.begin(), countItEnd = tagCounts.end(); countIt != countItEnd; ++countIt ) { std::ostringstream oss; oss << " " << std::setw(2) << countIt->second.count << " "; Text wrapper( countIt->second.all(), TextAttributes() .setInitialIndent( 0 ) .setIndent( oss.str().size() ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); Catch::cout() << oss.str() << wrapper << "\n"; } Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; return tagCounts.size(); } inline std::size_t listReporters( Config const& /*config*/ ) { Catch::cout() << "Available reporters:\n"; IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; std::size_t maxNameLen = 0; for(it = itBegin; it != itEnd; ++it ) maxNameLen = (std::max)( maxNameLen, it->first.size() ); for(it = itBegin; it != itEnd; ++it ) { Text wrapper( it->second->getDescription(), TextAttributes() .setInitialIndent( 0 ) .setIndent( 7+maxNameLen ) .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); Catch::cout() << " " << it->first << ":" << std::string( maxNameLen - it->first.size() + 2, ' ' ) << wrapper << "\n"; } Catch::cout() << std::endl; return factories.size(); } inline Option list( Config const& config ) { Option listedCount; if( config.listTests() ) listedCount = listedCount.valueOr(0) + listTests( config ); if( config.listTestNamesOnly() ) listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); if( config.listTags() ) listedCount = listedCount.valueOr(0) + listTags( config ); if( config.listReporters() ) listedCount = listedCount.valueOr(0) + listReporters( config ); return listedCount; } } // end namespace Catch // #included from: internal/catch_runner_impl.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED #include #include #include namespace Catch { namespace SectionTracking { class TrackedSection { typedef std::map TrackedSections; public: enum RunState { NotStarted, Executing, ExecutingChildren, Completed }; TrackedSection( std::string const& name, TrackedSection* parent ) : m_name( name ), m_runState( NotStarted ), m_parent( parent ) {} RunState runState() const { return m_runState; } TrackedSection* findChild( std::string const& childName ); TrackedSection* acquireChild( std::string const& childName ); void enter() { if( m_runState == NotStarted ) m_runState = Executing; } void leave(); TrackedSection* getParent() { return m_parent; } bool hasChildren() const { return !m_children.empty(); } private: std::string m_name; RunState m_runState; TrackedSections m_children; TrackedSection* m_parent; }; inline TrackedSection* TrackedSection::findChild( std::string const& childName ) { TrackedSections::iterator it = m_children.find( childName ); return it != m_children.end() ? &it->second : NULL; } inline TrackedSection* TrackedSection::acquireChild( std::string const& childName ) { if( TrackedSection* child = findChild( childName ) ) return child; m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); return findChild( childName ); } inline void TrackedSection::leave() { for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); it != itEnd; ++it ) if( it->second.runState() != Completed ) { m_runState = ExecutingChildren; return; } m_runState = Completed; } class TestCaseTracker { public: TestCaseTracker( std::string const& testCaseName ) : m_testCase( testCaseName, NULL ), m_currentSection( &m_testCase ), m_completedASectionThisRun( false ) {} bool enterSection( std::string const& name ) { TrackedSection* child = m_currentSection->acquireChild( name ); if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) return false; m_currentSection = child; m_currentSection->enter(); return true; } void leaveSection() { m_currentSection->leave(); m_currentSection = m_currentSection->getParent(); assert( m_currentSection != NULL ); m_completedASectionThisRun = true; } bool currentSectionHasChildren() const { return m_currentSection->hasChildren(); } bool isCompleted() const { return m_testCase.runState() == TrackedSection::Completed; } class Guard { public: Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { m_tracker.enterTestCase(); } ~Guard() { m_tracker.leaveTestCase(); } private: Guard( Guard const& ); void operator = ( Guard const& ); TestCaseTracker& m_tracker; }; private: void enterTestCase() { m_currentSection = &m_testCase; m_completedASectionThisRun = false; m_testCase.enter(); } void leaveTestCase() { m_testCase.leave(); } TrackedSection m_testCase; TrackedSection* m_currentSection; bool m_completedASectionThisRun; }; } // namespace SectionTracking using SectionTracking::TestCaseTracker; } // namespace Catch // #included from: catch_fatal_condition.hpp #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED namespace Catch { // Report the error condition then exit the process inline void fatal( std::string const& message, int exitCode ) { IContext& context = Catch::getCurrentContext(); IResultCapture* resultCapture = context.getResultCapture(); resultCapture->handleFatalErrorCondition( message ); if( Catch::alwaysTrue() ) // avoids "no return" warnings exit( exitCode ); } } // namespace Catch #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// namespace Catch { struct FatalConditionHandler { void reset() {} }; } // namespace Catch #else // Not Windows - assumed to be POSIX compatible ////////////////////////// #include namespace Catch { struct SignalDefs { int id; const char* name; }; extern SignalDefs signalDefs[]; SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, { SIGFPE, "SIGFPE - Floating point error signal" }, { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, { SIGTERM, "SIGTERM - Termination request signal" }, { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; struct FatalConditionHandler { static void handleSignal( int sig ) { for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) if( sig == signalDefs[i].id ) fatal( signalDefs[i].name, -sig ); fatal( "", -sig ); } FatalConditionHandler() : m_isSet( true ) { for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) signal( signalDefs[i].id, handleSignal ); } ~FatalConditionHandler() { reset(); } void reset() { if( m_isSet ) { for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) signal( signalDefs[i].id, SIG_DFL ); m_isSet = false; } } bool m_isSet; }; } // namespace Catch #endif // not Windows #include #include namespace Catch { class StreamRedirect { public: StreamRedirect( std::ostream& stream, std::string& targetString ) : m_stream( stream ), m_prevBuf( stream.rdbuf() ), m_targetString( targetString ) { stream.rdbuf( m_oss.rdbuf() ); } ~StreamRedirect() { m_targetString += m_oss.str(); m_stream.rdbuf( m_prevBuf ); } private: std::ostream& m_stream; std::streambuf* m_prevBuf; std::ostringstream m_oss; std::string& m_targetString; }; /////////////////////////////////////////////////////////////////////////// class RunContext : public IResultCapture, public IRunner { RunContext( RunContext const& ); void operator =( RunContext const& ); public: explicit RunContext( Ptr const& config, Ptr const& reporter ) : m_runInfo( config->name() ), m_context( getCurrentMutableContext() ), m_activeTestCase( NULL ), m_config( config ), m_reporter( reporter ), m_prevRunner( m_context.getRunner() ), m_prevResultCapture( m_context.getResultCapture() ), m_prevConfig( m_context.getConfig() ) { m_context.setRunner( this ); m_context.setConfig( m_config ); m_context.setResultCapture( this ); m_reporter->testRunStarting( m_runInfo ); } virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); m_context.setRunner( m_prevRunner ); m_context.setConfig( NULL ); m_context.setResultCapture( m_prevResultCapture ); m_context.setConfig( m_prevConfig ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); } void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); } Totals runTest( TestCase const& testCase ) { Totals prevTotals = m_totals; std::string redirectedCout; std::string redirectedCerr; TestCaseInfo testInfo = testCase.getTestCaseInfo(); m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; m_testCaseTracker = TestCaseTracker( testInfo.name ); do { do { runCurrentTest( redirectedCout, redirectedCerr ); } while( !m_testCaseTracker->isCompleted() && !aborting() ); } while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); m_totals.testCases += deltaTotals.testCases; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, redirectedCout, redirectedCerr, aborting() ) ); m_activeTestCase = NULL; m_testCaseTracker.reset(); return deltaTotals; } Ptr config() const { return m_config; } private: // IResultCapture virtual void assertionEnded( AssertionResult const& result ) { if( result.getResultType() == ResultWas::Ok ) { m_totals.assertions.passed++; } else if( !result.isOk() ) { m_totals.assertions.failed++; } if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) m_messages.clear(); // Reset working state m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); m_lastResult = result; } virtual bool sectionStarted ( SectionInfo const& sectionInfo, Counts& assertions ) { std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; if( !m_testCaseTracker->enterSection( oss.str() ) ) return false; m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; m_reporter->sectionStarting( sectionInfo ); assertions = m_totals.assertions; return true; } bool testForMissingAssertions( Counts& assertions ) { if( assertions.total() != 0 || !m_config->warnAboutMissingAssertions() || m_testCaseTracker->currentSectionHasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { if( std::uncaught_exception() ) { m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); return; } Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); m_testCaseTracker->leaveSection(); m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); m_messages.clear(); } virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } virtual void popScopedMessage( MessageInfo const& message ) { m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); } virtual std::string getCurrentTestName() const { return m_activeTestCase ? m_activeTestCase->getTestCaseInfo().name : ""; } virtual const AssertionResult* getLastResult() const { return &m_lastResult; } virtual void handleFatalErrorCondition( std::string const& message ) { ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); resultBuilder.setResultType( ResultWas::FatalErrorCondition ); resultBuilder << message; resultBuilder.captureExpression(); handleUnfinishedSections(); // Recreate section for test case (as we will lose the one that was in scope) TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); Counts assertions; assertions.failed = 1; SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); m_reporter->sectionEnded( testCaseSectionStats ); TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); Totals deltaTotals; deltaTotals.testCases.failed = 1; m_reporter->testCaseEnded( TestCaseStats( testInfo, deltaTotals, "", "", false ) ); m_totals.testCases.failed++; testGroupEnded( "", m_totals, 1, 1 ); m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); } public: // !TBD We need to do this another way! bool aborting() const { return m_totals.assertions.failed == static_cast( m_config->abortAfter() ); } private: void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); m_reporter->sectionStarting( testCaseSection ); Counts prevAssertions = m_totals.assertions; double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); TestCaseTracker::Guard guard( *m_testCaseTracker ); Timer timer; timer.start(); if( m_reporter->getPreferences().shouldRedirectStdOut ) { StreamRedirect coutRedir( Catch::cout(), redirectedCout ); StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); invokeActiveTestCase(); } else { invokeActiveTestCase(); } duration = timer.getElapsedSeconds(); } catch( TestFailureException& ) { // This just means the test was aborted due to failure } catch(...) { makeUnexpectedResultBuilder().useActiveException(); } handleUnfinishedSections(); m_messages.clear(); Counts assertions = m_totals.assertions - prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); if( testCaseInfo.okToFail() ) { std::swap( assertions.failedButOk, assertions.failed ); m_totals.assertions.failed -= assertions.failedButOk; m_totals.assertions.failedButOk += assertions.failedButOk; } SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); m_reporter->sectionEnded( testCaseSectionStats ); } void invokeActiveTestCase() { FatalConditionHandler fatalConditionHandler; // Handle signals m_activeTestCase->invoke(); fatalConditionHandler.reset(); } private: ResultBuilder makeUnexpectedResultBuilder() const { return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), m_lastAssertionInfo.lineInfo, m_lastAssertionInfo.capturedExpression.c_str(), m_lastAssertionInfo.resultDisposition ); } void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); m_unfinishedSections.clear(); } struct UnfinishedSections { UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) {} SectionInfo info; Counts prevAssertions; double durationInSeconds; }; TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; Option m_testCaseTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; IRunner* m_prevRunner; IResultCapture* m_prevResultCapture; Ptr m_prevConfig; AssertionInfo m_lastAssertionInfo; std::vector m_unfinishedSections; }; IResultCapture& getResultCapture() { if( IResultCapture* capture = getCurrentContext().getResultCapture() ) return *capture; else throw std::logic_error( "No result capture instance" ); } } // end namespace Catch // #included from: internal/catch_version.h #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED namespace Catch { // Versioning information struct Version { Version( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, std::string const& _branchName, unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; unsigned int const patchNumber; // buildNumber is only used if branchName is not null std::string const branchName; unsigned int const buildNumber; friend std::ostream& operator << ( std::ostream& os, Version const& version ); private: void operator=( Version const& ); }; extern Version libraryVersion; } #include #include #include namespace Catch { class Runner { public: Runner( Ptr const& config ) : m_config( config ) { openStream(); makeReporter(); } Totals runTests() { RunContext context( m_config.get(), m_reporter ); Totals totals; context.testGroupStarting( "all tests", 1, 1 ); // deprecated? TestSpec testSpec = m_config->testSpec(); if( !testSpec.hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests std::vector testCases; getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); int testsRunForGroup = 0; for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); it != itEnd; ++it ) { testsRunForGroup++; if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { if( context.aborting() ) break; totals += context.runTest( *it ); m_testsAlreadyRun.insert( *it ); } } std::vector skippedTestCases; getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); it != itEnd; ++it ) m_reporter->skipTest( *it ); context.testGroupEnded( "all tests", totals, 1, 1 ); return totals; } private: void openStream() { // Open output file, if specified if( !m_config->getFilename().empty() ) { m_ofs.open( m_config->getFilename().c_str() ); if( m_ofs.fail() ) { std::ostringstream oss; oss << "Unable to open file: '" << m_config->getFilename() << "'"; throw std::domain_error( oss.str() ); } m_config->setStreamBuf( m_ofs.rdbuf() ); } } void makeReporter() { std::string reporterName = m_config->getReporterName().empty() ? "console" : m_config->getReporterName(); m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); if( !m_reporter ) { std::ostringstream oss; oss << "No reporter registered with name: '" << reporterName << "'"; throw std::domain_error( oss.str() ); } } private: Ptr m_config; std::ofstream m_ofs; Ptr m_reporter; std::set m_testsAlreadyRun; }; class Session : NonCopyable { static bool alreadyInstantiated; public: struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; Session() : m_cli( makeCommandLineParser() ) { if( alreadyInstantiated ) { std::string msg = "Only one instance of Catch::Session can ever be used"; Catch::cerr() << msg << std::endl; throw std::logic_error( msg ); } alreadyInstantiated = true; } ~Session() { Catch::cleanUp(); } void showHelp( std::string const& processName ) { Catch::cout() << "\nCatch v" << libraryVersion << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); if( m_configData.showHelp ) showHelp( m_configData.processName ); m_config.reset(); } catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); Catch::cerr() << "\nError(s) in input:\n" << Text( ex.what(), TextAttributes().setIndent(2) ) << "\n\n"; } m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); } return 0; } void useConfigData( ConfigData const& _configData ) { m_configData = _configData; m_config.reset(); } int run( int argc, char* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) returnCode = run(); return returnCode; } int run() { if( m_configData.showHelp ) return 0; try { config(); // Force config to be constructed std::srand( m_configData.rngSeed ); Runner runner( m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); return static_cast( runner.runTests().assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; return (std::numeric_limits::max)(); } } Clara::CommandLine const& cli() const { return m_cli; } std::vector const& unusedTokens() const { return m_unusedTokens; } ConfigData& configData() { return m_configData; } Config& config() { if( !m_config ) m_config = new Config( m_configData ); return *m_config; } private: Clara::CommandLine m_cli; std::vector m_unusedTokens; ConfigData m_configData; Ptr m_config; }; bool Session::alreadyInstantiated = false; } // end namespace Catch // #included from: catch_registry_hub.hpp #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED // #included from: catch_test_case_registry_impl.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED #include #include #include #include #include namespace Catch { class TestRegistry : public ITestCaseRegistry { struct LexSort { bool operator() (TestCase i,TestCase j) const { return (i const& getAllTests() const { return m_functionsInOrder; } virtual std::vector const& getAllNonHiddenTests() const { return m_nonHiddenFunctions; } virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { for( std::vector::const_iterator it = m_functionsInOrder.begin(), itEnd = m_functionsInOrder.end(); it != itEnd; ++it ) { bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); if( includeTest != negated ) matchingTestCases.push_back( *it ); } sortTests( config, matchingTestCases ); } private: static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { switch( config.runOrder() ) { case RunTests::InLexicographicalOrder: std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); break; case RunTests::InRandomOrder: { RandomNumberGenerator rng; std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); } break; case RunTests::InDeclarationOrder: // already in declaration order break; } } std::set m_functions; std::vector m_functionsInOrder; std::vector m_nonHiddenFunctions; size_t m_unnamedCount; }; /////////////////////////////////////////////////////////////////////////// class FreeFunctionTestCase : public SharedImpl { public: FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} virtual void invoke() const { m_fun(); } private: virtual ~FreeFunctionTestCase(); TestFunction m_fun; }; inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { std::string className = classOrQualifiedMethodName; if( startsWith( className, "&" ) ) { std::size_t lastColons = className.rfind( "::" ); std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); if( penultimateColons == std::string::npos ) penultimateColons = 1; className = className.substr( penultimateColons, lastColons-penultimateColons ); } return className; } /////////////////////////////////////////////////////////////////////////// AutoReg::AutoReg( TestFunction function, SourceLineInfo const& lineInfo, NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } AutoReg::~AutoReg() {} void AutoReg::registerTestCase( ITestCase* testCase, char const* classOrQualifiedMethodName, NameAndDesc const& nameAndDesc, SourceLineInfo const& lineInfo ) { getMutableRegistryHub().registerTest ( makeTestCase( testCase, extractClassName( classOrQualifiedMethodName ), nameAndDesc.name, nameAndDesc.description, lineInfo ) ); } } // end namespace Catch // #included from: catch_reporter_registry.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED #include namespace Catch { class ReporterRegistry : public IReporterRegistry { public: virtual ~ReporterRegistry() { deleteAllValues( m_factories ); } virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) return NULL; return it->second->create( ReporterConfig( config ) ); } void registerReporter( std::string const& name, IReporterFactory* factory ) { m_factories.insert( std::make_pair( name, factory ) ); } FactoryMap const& getFactories() const { return m_factories; } private: FactoryMap m_factories; }; } // #included from: catch_exception_translator_registry.hpp #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED #ifdef __OBJC__ #import "Foundation/Foundation.h" #endif namespace Catch { class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { public: ~ExceptionTranslatorRegistry() { deleteAll( m_translators ); } virtual void registerTranslator( const IExceptionTranslator* translator ) { m_translators.push_back( translator ); } virtual std::string translateActiveException() const { try { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { throw; } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else throw; #endif } catch( TestFailureException& ) { throw; } catch( std::exception& ex ) { return ex.what(); } catch( std::string& msg ) { return msg; } catch( const char* msg ) { return msg; } catch(...) { return tryTranslators( m_translators.begin() ); } } std::string tryTranslators( std::vector::const_iterator it ) const { if( it == m_translators.end() ) return "Unknown exception"; try { return (*it)->translate(); } catch(...) { return tryTranslators( it+1 ); } } private: std::vector m_translators; }; } namespace Catch { namespace { class RegistryHub : public IRegistryHub, public IMutableRegistryHub { RegistryHub( RegistryHub const& ); void operator=( RegistryHub const& ); public: // IRegistryHub RegistryHub() { } virtual IReporterRegistry const& getReporterRegistry() const { return m_reporterRegistry; } virtual ITestCaseRegistry const& getTestCaseRegistry() const { return m_testCaseRegistry; } virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { m_reporterRegistry.registerReporter( name, factory ); } virtual void registerTest( TestCase const& testInfo ) { m_testCaseRegistry.registerTest( testInfo ); } virtual void registerTranslator( const IExceptionTranslator* translator ) { m_exceptionTranslatorRegistry.registerTranslator( translator ); } private: TestRegistry m_testCaseRegistry; ReporterRegistry m_reporterRegistry; ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; }; // Single, global, instance inline RegistryHub*& getTheRegistryHub() { static RegistryHub* theRegistryHub = NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; } } IRegistryHub& getRegistryHub() { return *getTheRegistryHub(); } IMutableRegistryHub& getMutableRegistryHub() { return *getTheRegistryHub(); } void cleanUp() { delete getTheRegistryHub(); getTheRegistryHub() = NULL; cleanUpContext(); } std::string translateActiveException() { return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); } } // end namespace Catch // #included from: catch_notimplemented_exception.hpp #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED #include namespace Catch { NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) : m_lineInfo( lineInfo ) { std::ostringstream oss; oss << lineInfo << ": function "; oss << "not implemented"; m_what = oss.str(); } const char* NotImplementedException::what() const CATCH_NOEXCEPT { return m_what.c_str(); } } // end namespace Catch // #included from: catch_context_impl.hpp #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED // #included from: catch_streambuf.h #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED #include namespace Catch { class StreamBufBase : public std::streambuf { public: virtual ~StreamBufBase() CATCH_NOEXCEPT; }; } #include #include #include namespace Catch { template class StreamBufImpl : public StreamBufBase { char data[bufferSize]; WriterF m_writer; public: StreamBufImpl() { setp( data, data + sizeof(data) ); } ~StreamBufImpl() CATCH_NOEXCEPT { sync(); } private: int overflow( int c ) { sync(); if( c != EOF ) { if( pbase() == epptr() ) m_writer( std::string( 1, static_cast( c ) ) ); else sputc( static_cast( c ) ); } return 0; } int sync() { if( pbase() != pptr() ) { m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); setp( pbase(), epptr() ); } return 0; } }; /////////////////////////////////////////////////////////////////////////// struct OutputDebugWriter { void operator()( std::string const&str ) { writeToDebugConsole( str ); } }; Stream::Stream() : streamBuf( NULL ), isOwned( false ) {} Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) : streamBuf( _streamBuf ), isOwned( _isOwned ) {} void Stream::release() { if( isOwned ) { delete streamBuf; streamBuf = NULL; isOwned = false; } } #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions std::ostream& cout() { return std::cout; } std::ostream& cerr() { return std::cerr; } #endif } namespace Catch { class Context : public IMutableContext { Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} Context( Context const& ); void operator=( Context const& ); public: // IContext virtual IResultCapture* getResultCapture() { return m_resultCapture; } virtual IRunner* getRunner() { return m_runner; } virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { return getGeneratorsForCurrentTest() .getGeneratorInfo( fileInfo, totalSize ) .getCurrentIndex(); } virtual bool advanceGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); return generators && generators->moveNext(); } virtual Ptr getConfig() const { return m_config; } public: // IMutableContext virtual void setResultCapture( IResultCapture* resultCapture ) { m_resultCapture = resultCapture; } virtual void setRunner( IRunner* runner ) { m_runner = runner; } virtual void setConfig( Ptr const& config ) { m_config = config; } friend IMutableContext& getCurrentMutableContext(); private: IGeneratorsForTest* findGeneratorsForCurrentTest() { std::string testName = getResultCapture()->getCurrentTestName(); std::map::const_iterator it = m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second : NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); if( !generators ) { std::string testName = getResultCapture()->getCurrentTestName(); generators = createGeneratorsForTest(); m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); } return *generators; } private: Ptr m_config; IRunner* m_runner; IResultCapture* m_resultCapture; std::map m_generatorsByTestName; }; namespace { Context* currentContext = NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) currentContext = new Context(); return *currentContext; } IContext& getCurrentContext() { return getCurrentMutableContext(); } Stream createStream( std::string const& streamName ) { if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); throw std::domain_error( "Unknown stream: " + streamName ); } void cleanUpContext() { delete currentContext; currentContext = NULL; } } // #included from: catch_console_colour_impl.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED namespace Catch { namespace { struct IColourImpl { virtual ~IColourImpl() {} virtual void use( Colour::Code _colourCode ) = 0; }; struct NoColourImpl : IColourImpl { void use( Colour::Code ) {} static IColourImpl* instance() { static NoColourImpl s_instance; return &s_instance; } }; } // anon namespace } // namespace Catch #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) # ifdef CATCH_PLATFORM_WINDOWS # define CATCH_CONFIG_COLOUR_WINDOWS # else # define CATCH_CONFIG_COLOUR_ANSI # endif #endif #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// #ifndef NOMINMAX #define NOMINMAX #endif #ifdef __AFXDLL #include #else #include #endif namespace Catch { namespace { class Win32ColourImpl : public IColourImpl { public: Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); originalAttributes = csbiInfo.wAttributes; } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); case Colour::Grey: return setTextAttribute( 0 ); case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } private: void setTextAttribute( WORD _textAttribute ) { SetConsoleTextAttribute( stdoutHandle, _textAttribute ); } HANDLE stdoutHandle; WORD originalAttributes; }; IColourImpl* platformColourInstance() { static Win32ColourImpl s_instance; return &s_instance; } } // end anon namespace } // end namespace Catch #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// #include namespace Catch { namespace { // use POSIX/ ANSI console terminal codes // Thanks to Adam Strzelecki for original contribution // (http://github.com/nanoant) // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); case Colour::Red: return setColour( "[0;31m" ); case Colour::Green: return setColour( "[0;32m" ); case Colour::Blue: return setColour( "[0:34m" ); case Colour::Cyan: return setColour( "[0;36m" ); case Colour::Yellow: return setColour( "[0;33m" ); case Colour::Grey: return setColour( "[1;30m" ); case Colour::LightGrey: return setColour( "[0;37m" ); case Colour::BrightRed: return setColour( "[1;31m" ); case Colour::BrightGreen: return setColour( "[1;32m" ); case Colour::BrightWhite: return setColour( "[1;37m" ); case Colour::Bright: throw std::logic_error( "not a colour" ); } } static IColourImpl* instance() { static PosixColourImpl s_instance; return &s_instance; } private: void setColour( const char* _escapeCode ) { Catch::cout() << '\033' << _escapeCode; } }; IColourImpl* platformColourInstance() { Ptr config = getCurrentContext().getConfig(); return (config && config->forceColour()) || isatty(STDOUT_FILENO) ? PosixColourImpl::instance() : NoColourImpl::instance(); } } // end anon namespace } // end namespace Catch #else // not Windows or ANSI /////////////////////////////////////////////// namespace Catch { static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch #endif // Windows/ ANSI/ None namespace Catch { Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast( _other ).m_moved = true; } Colour::~Colour(){ if( !m_moved ) use( None ); } void Colour::use( Code _colourCode ) { static IColourImpl* impl = isDebuggerActive() ? NoColourImpl::instance() : platformColourInstance(); impl->use( _colourCode ); } } // end namespace Catch // #included from: catch_generators_impl.hpp #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED #include #include #include namespace Catch { struct GeneratorInfo : IGeneratorInfo { GeneratorInfo( std::size_t size ) : m_size( size ), m_currentIndex( 0 ) {} bool moveNext() { if( ++m_currentIndex == m_size ) { m_currentIndex = 0; return false; } return true; } std::size_t getCurrentIndex() const { return m_currentIndex; } std::size_t m_size; std::size_t m_currentIndex; }; /////////////////////////////////////////////////////////////////////////// class GeneratorsForTest : public IGeneratorsForTest { public: ~GeneratorsForTest() { deleteAll( m_generatorsInOrder ); } IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { std::map::const_iterator it = m_generatorsByName.find( fileInfo ); if( it == m_generatorsByName.end() ) { IGeneratorInfo* info = new GeneratorInfo( size ); m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); m_generatorsInOrder.push_back( info ); return *info; } return *it->second; } bool moveNext() { std::vector::const_iterator it = m_generatorsInOrder.begin(); std::vector::const_iterator itEnd = m_generatorsInOrder.end(); for(; it != itEnd; ++it ) { if( (*it)->moveNext() ) return true; } return false; } private: std::map m_generatorsByName; std::vector m_generatorsInOrder; }; IGeneratorsForTest* createGeneratorsForTest() { return new GeneratorsForTest(); } } // end namespace Catch // #included from: catch_assertionresult.hpp #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED namespace Catch { AssertionInfo::AssertionInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, std::string const& _capturedExpression, ResultDisposition::Flags _resultDisposition ) : macroName( _macroName ), lineInfo( _lineInfo ), capturedExpression( _capturedExpression ), resultDisposition( _resultDisposition ) {} AssertionResult::AssertionResult() {} AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) : m_info( info ), m_resultData( data ) {} AssertionResult::~AssertionResult() {} // Result was a success bool AssertionResult::succeeded() const { return Catch::isOk( m_resultData.resultType ); } // Result was a success, or failure is suppressed bool AssertionResult::isOk() const { return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); } ResultWas::OfType AssertionResult::getResultType() const { return m_resultData.resultType; } bool AssertionResult::hasExpression() const { return !m_info.capturedExpression.empty(); } bool AssertionResult::hasMessage() const { return !m_resultData.message.empty(); } std::string AssertionResult::getExpression() const { if( isFalseTest( m_info.resultDisposition ) ) return "!" + m_info.capturedExpression; else return m_info.capturedExpression; } std::string AssertionResult::getExpressionInMacro() const { if( m_info.macroName.empty() ) return m_info.capturedExpression; else return m_info.macroName + "( " + m_info.capturedExpression + " )"; } bool AssertionResult::hasExpandedExpression() const { return hasExpression() && getExpandedExpression() != getExpression(); } std::string AssertionResult::getExpandedExpression() const { return m_resultData.reconstructedExpression; } std::string AssertionResult::getMessage() const { return m_resultData.message; } SourceLineInfo AssertionResult::getSourceInfo() const { return m_info.lineInfo; } std::string AssertionResult::getTestMacroName() const { return m_info.macroName; } } // end namespace Catch // #included from: catch_test_case_info.hpp #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED namespace Catch { inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { if( startsWith( tag, "." ) || tag == "hide" || tag == "!hide" ) return TestCaseInfo::IsHidden; else if( tag == "!throws" ) return TestCaseInfo::Throws; else if( tag == "!shouldfail" ) return TestCaseInfo::ShouldFail; else if( tag == "!mayfail" ) return TestCaseInfo::MayFail; else return TestCaseInfo::None; } inline bool isReservedTag( std::string const& tag ) { return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); } inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { if( isReservedTag( tag ) ) { { Colour colourGuard( Colour::Red ); Catch::cerr() << "Tag name [" << tag << "] not allowed.\n" << "Tag names starting with non alpha-numeric characters are reserved\n"; } { Colour colourGuard( Colour::FileName ); Catch::cerr() << _lineInfo << std::endl; } exit(1); } } TestCase makeTestCase( ITestCase* _testCase, std::string const& _className, std::string const& _name, std::string const& _descOrTags, SourceLineInfo const& _lineInfo ) { bool isHidden( startsWith( _name, "./" ) ); // Legacy support // Parse out tags std::set tags; std::string desc, tag; bool inTag = false; for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { char c = _descOrTags[i]; if( !inTag ) { if( c == '[' ) inTag = true; else desc += c; } else { if( c == ']' ) { TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); if( prop == TestCaseInfo::IsHidden ) isHidden = true; else if( prop == TestCaseInfo::None ) enforceNotReservedTag( tag, _lineInfo ); tags.insert( tag ); tag.clear(); inTag = false; } else tag += c; } } if( isHidden ) { tags.insert( "hide" ); tags.insert( "." ); } TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); return TestCase( _testCase, info ); } TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, std::set const& _tags, SourceLineInfo const& _lineInfo ) : name( _name ), className( _className ), description( _description ), tags( _tags ), lineInfo( _lineInfo ), properties( None ) { std::ostringstream oss; for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { oss << "[" << *it << "]"; std::string lcaseTag = toLower( *it ); properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); lcaseTags.insert( lcaseTag ); } tagsAsString = oss.str(); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) : name( other.name ), className( other.className ), description( other.description ), tags( other.tags ), lcaseTags( other.lcaseTags ), tagsAsString( other.tagsAsString ), lineInfo( other.lineInfo ), properties( other.properties ) {} bool TestCaseInfo::isHidden() const { return ( properties & IsHidden ) != 0; } bool TestCaseInfo::throws() const { return ( properties & Throws ) != 0; } bool TestCaseInfo::okToFail() const { return ( properties & (ShouldFail | MayFail ) ) != 0; } bool TestCaseInfo::expectedToFail() const { return ( properties & (ShouldFail ) ) != 0; } TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} TestCase::TestCase( TestCase const& other ) : TestCaseInfo( other ), test( other.test ) {} TestCase TestCase::withName( std::string const& _newName ) const { TestCase other( *this ); other.name = _newName; return other; } void TestCase::swap( TestCase& other ) { test.swap( other.test ); name.swap( other.name ); className.swap( other.className ); description.swap( other.description ); tags.swap( other.tags ); lcaseTags.swap( other.lcaseTags ); tagsAsString.swap( other.tagsAsString ); std::swap( TestCaseInfo::properties, static_cast( other ).properties ); std::swap( lineInfo, other.lineInfo ); } void TestCase::invoke() const { test->invoke(); } bool TestCase::operator == ( TestCase const& other ) const { return test.get() == other.test.get() && name == other.name && className == other.className; } bool TestCase::operator < ( TestCase const& other ) const { return name < other.name; } TestCase& TestCase::operator = ( TestCase const& other ) { TestCase temp( other ); swap( temp ); return *this; } TestCaseInfo const& TestCase::getTestCaseInfo() const { return *this; } } // end namespace Catch // #included from: catch_version.hpp #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED namespace Catch { Version::Version ( unsigned int _majorVersion, unsigned int _minorVersion, unsigned int _patchNumber, std::string const& _branchName, unsigned int _buildNumber ) : majorVersion( _majorVersion ), minorVersion( _minorVersion ), patchNumber( _patchNumber ), branchName( _branchName ), buildNumber( _buildNumber ) {} std::ostream& operator << ( std::ostream& os, Version const& version ) { os << version.majorVersion << "." << version.minorVersion << "." << version.patchNumber; if( !version.branchName.empty() ) { os << "-" << version.branchName << "." << version.buildNumber; } return os; } Version libraryVersion( 1, 2, 1, "", 0 ); } // #included from: catch_message.hpp #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED namespace Catch { MessageInfo::MessageInfo( std::string const& _macroName, SourceLineInfo const& _lineInfo, ResultWas::OfType _type ) : macroName( _macroName ), lineInfo( _lineInfo ), type( _type ), sequence( ++globalCount ) {} // This may need protecting if threading support is added unsigned int MessageInfo::globalCount = 0; //////////////////////////////////////////////////////////////////////////// ScopedMessage::ScopedMessage( MessageBuilder const& builder ) : m_info( builder.m_info ) { m_info.message = builder.m_stream.str(); getResultCapture().pushScopedMessage( m_info ); } ScopedMessage::ScopedMessage( ScopedMessage const& other ) : m_info( other.m_info ) {} ScopedMessage::~ScopedMessage() { getResultCapture().popScopedMessage( m_info ); } } // end namespace Catch // #included from: catch_legacy_reporter_adapter.hpp #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED // #included from: catch_legacy_reporter_adapter.h #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED namespace Catch { // Deprecated struct IReporter : IShared { virtual ~IReporter(); virtual bool shouldRedirectStdout() const = 0; virtual void StartTesting() = 0; virtual void EndTesting( Totals const& totals ) = 0; virtual void StartGroup( std::string const& groupName ) = 0; virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; virtual void Aborted() = 0; virtual void Result( AssertionResult const& result ) = 0; }; class LegacyReporterAdapter : public SharedImpl { public: LegacyReporterAdapter( Ptr const& legacyReporter ); virtual ~LegacyReporterAdapter(); virtual ReporterPreferences getPreferences() const; virtual void noMatchingTestCases( std::string const& ); virtual void testRunStarting( TestRunInfo const& ); virtual void testGroupStarting( GroupInfo const& groupInfo ); virtual void testCaseStarting( TestCaseInfo const& testInfo ); virtual void sectionStarting( SectionInfo const& sectionInfo ); virtual void assertionStarting( AssertionInfo const& ); virtual bool assertionEnded( AssertionStats const& assertionStats ); virtual void sectionEnded( SectionStats const& sectionStats ); virtual void testCaseEnded( TestCaseStats const& testCaseStats ); virtual void testGroupEnded( TestGroupStats const& testGroupStats ); virtual void testRunEnded( TestRunStats const& testRunStats ); virtual void skipTest( TestCaseInfo const& ); private: Ptr m_legacyReporter; }; } namespace Catch { LegacyReporterAdapter::LegacyReporterAdapter( Ptr const& legacyReporter ) : m_legacyReporter( legacyReporter ) {} LegacyReporterAdapter::~LegacyReporterAdapter() {} ReporterPreferences LegacyReporterAdapter::getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); return prefs; } void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { m_legacyReporter->StartTesting(); } void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { m_legacyReporter->StartGroup( groupInfo.name ); } void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { m_legacyReporter->StartTestCase( testInfo ); } void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); } void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { // Not on legacy interface } bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); rb << it->message; rb.setResultType( ResultWas::Info ); AssertionResult result = rb.build(); m_legacyReporter->Result( result ); } } } m_legacyReporter->Result( assertionStats.assertionResult ); return true; } void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { if( sectionStats.missingAssertions ) m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); } void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { m_legacyReporter->EndTestCase ( testCaseStats.testInfo, testCaseStats.totals, testCaseStats.stdOut, testCaseStats.stdErr ); } void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { if( testGroupStats.aborting ) m_legacyReporter->Aborted(); m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); } void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { m_legacyReporter->EndTesting( testRunStats.totals ); } void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { } } // #included from: catch_timer.hpp #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wc++11-long-long" #endif #ifdef CATCH_PLATFORM_WINDOWS #include #else #include #endif namespace Catch { namespace { #ifdef CATCH_PLATFORM_WINDOWS uint64_t getCurrentTicks() { static uint64_t hz=0, hzo=0; if (!hz) { QueryPerformanceFrequency( reinterpret_cast( &hz ) ); QueryPerformanceCounter( reinterpret_cast( &hzo ) ); } uint64_t t; QueryPerformanceCounter( reinterpret_cast( &t ) ); return ((t-hzo)*1000000)/hz; } #else uint64_t getCurrentTicks() { timeval t; gettimeofday(&t,NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif } void Timer::start() { m_ticks = getCurrentTicks(); } unsigned int Timer::getElapsedMicroseconds() const { return static_cast(getCurrentTicks() - m_ticks); } unsigned int Timer::getElapsedMilliseconds() const { return static_cast(getElapsedMicroseconds()/1000); } double Timer::getElapsedSeconds() const { return getElapsedMicroseconds()/1000000.0; } } // namespace Catch #ifdef __clang__ #pragma clang diagnostic pop #endif // #included from: catch_common.hpp #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED namespace Catch { bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; } bool endsWith( std::string const& s, std::string const& suffix ) { return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; } bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), ::tolower ); } std::string toLower( std::string const& s ) { std::string lc = s; toLowerInPlace( lc ); return lc; } std::string trim( std::string const& str ) { static char const* whitespaceChars = "\n\r\t "; std::string::size_type start = str.find_first_not_of( whitespaceChars ); std::string::size_type end = str.find_last_not_of( whitespaceChars ); return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; } bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { bool replaced = false; std::size_t i = str.find( replaceThis ); while( i != std::string::npos ) { replaced = true; str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); if( i < str.size()-withThis.size() ) i = str.find( replaceThis, i+withThis.size() ); else i = std::string::npos; } return replaced; } pluralise::pluralise( std::size_t count, std::string const& label ) : m_count( count ), m_label( label ) {} std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { os << pluraliser.m_count << " " << pluraliser.m_label; if( pluraliser.m_count != 1 ) os << "s"; return os; } SourceLineInfo::SourceLineInfo() : line( 0 ){} SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) : file( _file ), line( _line ) {} SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) : file( other.file ), line( other.line ) {} bool SourceLineInfo::empty() const { return file.empty(); } bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { return line == other.line && file == other.file; } bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { return line < other.line || ( line == other.line && file < other.file ); } std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; #else os << info.file << ":" << info.line; #endif return os; } void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { std::ostringstream oss; oss << locationInfo << ": Internal Catch error: '" << message << "'"; if( alwaysTrue() ) throw std::logic_error( oss.str() ); } } // #included from: catch_section.hpp #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, std::string const& _description ) : name( _name ), description( _description ), lineInfo( _lineInfo ) {} Section::Section( SectionInfo const& info ) : m_info( info ), m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) { m_timer.start(); } Section::~Section() { if( m_sectionIncluded ) getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); } // This indicates whether the section should be executed or not Section::operator bool() const { return m_sectionIncluded; } } // end namespace Catch // #included from: catch_debugger.hpp #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED #include #ifdef CATCH_PLATFORM_MAC #include #include #include #include #include namespace Catch{ // The following function is taken directly from the following technical note: // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ int mib[4]; struct kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } // We're being debugged if the P_TRACED flag is set. return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } } // namespace Catch #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #elif defined(__MINGW32__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace Catch { bool isDebuggerActive() { return IsDebuggerPresent() != 0; } } #else namespace Catch { inline bool isDebuggerActive() { return false; } } #endif // Platform #ifdef CATCH_PLATFORM_WINDOWS extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); namespace Catch { void writeToDebugConsole( std::string const& text ) { ::OutputDebugStringA( text.c_str() ); } } #else namespace Catch { void writeToDebugConsole( std::string const& text ) { // !TBD: Need a version for Mac/ XCode and other IDEs Catch::cout() << text; } } #endif // Platform // #included from: catch_tostring.hpp #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED namespace Catch { namespace Detail { std::string unprintableString = "{?}"; namespace { struct Endianness { enum Arch { Big, Little }; static Arch which() { union _{ int asInt; char asChar[sizeof (int)]; } u; u.asInt = 1; return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; } }; } std::string rawMemoryToString( const void *object, std::size_t size ) { // Reverse order for little endian architectures int i = 0, end = static_cast( size ), inc = 1; if( Endianness::which() == Endianness::Little ) { i = end-1; end = inc = -1; } unsigned char const *bytes = static_cast(object); std::ostringstream os; os << "0x" << std::setfill('0') << std::hex; for( ; i != end; i += inc ) os << std::setw(2) << static_cast(bytes[i]); return os.str(); } } std::string toString( std::string const& value ) { std::string s = value; if( getCurrentContext().getConfig()->showInvisibles() ) { for(size_t i = 0; i < s.size(); ++i ) { std::string subs; switch( s[i] ) { case '\n': subs = "\\n"; break; case '\t': subs = "\\t"; break; default: break; } if( !subs.empty() ) { s = s.substr( 0, i ) + subs + s.substr( i+1 ); ++i; } } } return "\"" + s + "\""; } std::string toString( std::wstring const& value ) { std::string s; s.reserve( value.size() ); for(size_t i = 0; i < value.size(); ++i ) s += value[i] <= 0xff ? static_cast( value[i] ) : '?'; return Catch::toString( s ); } std::string toString( const char* const value ) { return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); } std::string toString( char* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( const wchar_t* const value ) { return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); } std::string toString( wchar_t* const value ) { return Catch::toString( static_cast( value ) ); } std::string toString( int value ) { std::ostringstream oss; oss << value; if( value >= 255 ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned long value ) { std::ostringstream oss; oss << value; if( value >= 255 ) oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned int value ) { return Catch::toString( static_cast( value ) ); } template std::string fpToString( T value, int precision ) { std::ostringstream oss; oss << std::setprecision( precision ) << std::fixed << value; std::string d = oss.str(); std::size_t i = d.find_last_not_of( '0' ); if( i != std::string::npos && i != d.size()-1 ) { if( d[i] == '.' ) i++; d = d.substr( 0, i+1 ); } return d; } std::string toString( const double value ) { return fpToString( value, 10 ); } std::string toString( const float value ) { return fpToString( value, 5 ) + "f"; } std::string toString( bool value ) { return value ? "true" : "false"; } std::string toString( char value ) { return value < ' ' ? toString( static_cast( value ) ) : Detail::makeString( value ); } std::string toString( signed char value ) { return toString( static_cast( value ) ); } std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; } #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { if( !nsstring ) return "nil"; return "@" + toString([nsstring UTF8String]); } std::string toString( NSObject* const& nsObject ) { return toString( [nsObject description] ); } #endif } // end namespace Catch // #included from: catch_result_builder.hpp #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED namespace Catch { ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, ResultDisposition::Flags resultDisposition ) : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { m_data.resultType = result; return *this; } ResultBuilder& ResultBuilder::setResultType( bool result ) { m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; return *this; } ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { m_exprComponents.lhs = lhs; return *this; } ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { m_exprComponents.rhs = rhs; return *this; } ResultBuilder& ResultBuilder::setOp( std::string const& op ) { m_exprComponents.op = op; return *this; } void ResultBuilder::endExpression() { m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); captureExpression(); } void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { m_assertionInfo.resultDisposition = resultDisposition; m_stream.oss << Catch::translateActiveException(); captureResult( ResultWas::ThrewException ); } void ResultBuilder::captureResult( ResultWas::OfType resultType ) { setResultType( resultType ); captureExpression(); } void ResultBuilder::captureExpression() { AssertionResult result = build(); getResultCapture().assertionEnded( result ); if( !result.isOk() ) { if( getCurrentContext().getConfig()->shouldDebugBreak() ) m_shouldDebugBreak = true; if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) m_shouldThrow = true; } } void ResultBuilder::react() { if( m_shouldThrow ) throw Catch::TestFailureException(); } bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } AssertionResult ResultBuilder::build() const { assert( m_data.resultType != ResultWas::Unknown ); AssertionResultData data = m_data; // Flip bool results if testFalse is set if( m_exprComponents.testFalse ) { if( data.resultType == ResultWas::Ok ) data.resultType = ResultWas::ExpressionFailed; else if( data.resultType == ResultWas::ExpressionFailed ) data.resultType = ResultWas::Ok; } data.message = m_stream.oss.str(); data.reconstructedExpression = reconstructExpression(); if( m_exprComponents.testFalse ) { if( m_exprComponents.op == "" ) data.reconstructedExpression = "!" + data.reconstructedExpression; else data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; } return AssertionResult( m_assertionInfo, data ); } std::string ResultBuilder::reconstructExpression() const { if( m_exprComponents.op == "" ) return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; else if( m_exprComponents.op == "matches" ) return m_exprComponents.lhs + " " + m_exprComponents.rhs; else if( m_exprComponents.op != "!" ) { if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && m_exprComponents.lhs.find("\n") == std::string::npos && m_exprComponents.rhs.find("\n") == std::string::npos ) return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; else return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; } else return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; } } // end namespace Catch // #included from: catch_tag_alias_registry.hpp #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED // #included from: catch_tag_alias_registry.h #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED #include namespace Catch { class TagAliasRegistry : public ITagAliasRegistry { public: virtual ~TagAliasRegistry(); virtual Option find( std::string const& alias ) const; virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); static TagAliasRegistry& get(); private: std::map m_registry; }; } // end namespace Catch #include #include namespace Catch { TagAliasRegistry::~TagAliasRegistry() {} Option TagAliasRegistry::find( std::string const& alias ) const { std::map::const_iterator it = m_registry.find( alias ); if( it != m_registry.end() ) return it->second; else return Option(); } std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { std::string expandedTestSpec = unexpandedTestSpec; for( std::map::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); it != itEnd; ++it ) { std::size_t pos = expandedTestSpec.find( it->first ); if( pos != std::string::npos ) { expandedTestSpec = expandedTestSpec.substr( 0, pos ) + it->second.tag + expandedTestSpec.substr( pos + it->first.size() ); } } return expandedTestSpec; } void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { std::ostringstream oss; oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; throw std::domain_error( oss.str().c_str() ); } if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { std::ostringstream oss; oss << "error: tag alias, \"" << alias << "\" already registered.\n" << "\tFirst seen at " << find(alias)->lineInfo << "\n" << "\tRedefined at " << lineInfo; throw std::domain_error( oss.str().c_str() ); } } TagAliasRegistry& TagAliasRegistry::get() { static TagAliasRegistry instance; return instance; } ITagAliasRegistry::~ITagAliasRegistry() {} ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { try { TagAliasRegistry::get().add( alias, tag, lineInfo ); } catch( std::exception& ex ) { Colour colourGuard( Colour::Red ); Catch::cerr() << ex.what() << std::endl; exit(1); } } } // end namespace Catch // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED // #included from: catch_reporter_bases.hpp #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED #include namespace Catch { struct StreamingReporterBase : SharedImpl { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) {} virtual ~StreamingReporterBase(); virtual void noMatchingTestCases( std::string const& ) {} virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { currentTestRunInfo = _testRunInfo; } virtual void testGroupStarting( GroupInfo const& _groupInfo ) { currentGroupInfo = _groupInfo; } virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { currentTestCaseInfo = _testInfo; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) { m_sectionStack.push_back( _sectionInfo ); } virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { currentTestCaseInfo.reset(); } virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { currentGroupInfo.reset(); } virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } virtual void skipTest( TestCaseInfo const& ) { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; LazyStat currentGroupInfo; LazyStat currentTestCaseInfo; std::vector m_sectionStack; }; struct CumulativeReporterBase : SharedImpl { template struct Node : SharedImpl<> { explicit Node( T const& _value ) : value( _value ) {} virtual ~Node() {} typedef std::vector > ChildNodes; T value; ChildNodes children; }; struct SectionNode : SharedImpl<> { explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} virtual ~SectionNode(); bool operator == ( SectionNode const& other ) const { return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; } bool operator == ( Ptr const& other ) const { return operator==( *other ); } SectionStats stats; typedef std::vector > ChildSections; typedef std::vector Assertions; ChildSections childSections; Assertions assertions; std::string stdOut; std::string stdErr; }; struct BySectionInfo { BySectionInfo( SectionInfo const& other ) : m_other( other ) {} BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} bool operator() ( Ptr const& node ) const { return node->stats.sectionInfo.lineInfo == m_other.lineInfo; } private: void operator=( BySectionInfo const& ); SectionInfo const& m_other; }; typedef Node TestCaseNode; typedef Node TestGroupNode; typedef Node TestRunNode; CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) {} ~CumulativeReporterBase(); virtual void testRunStarting( TestRunInfo const& ) {} virtual void testGroupStarting( GroupInfo const& ) {} virtual void testCaseStarting( TestCaseInfo const& ) {} virtual void sectionStarting( SectionInfo const& sectionInfo ) { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { if( !m_rootSection ) m_rootSection = new SectionNode( incompleteStats ); node = m_rootSection; } else { SectionNode& parentNode = *m_sectionStack.back(); SectionNode::ChildSections::const_iterator it = std::find_if( parentNode.childSections.begin(), parentNode.childSections.end(), BySectionInfo( sectionInfo ) ); if( it == parentNode.childSections.end() ) { node = new SectionNode( incompleteStats ); parentNode.childSections.push_back( node ); } else node = *it; } m_sectionStack.push_back( node ); m_deepestSection = node; } virtual void assertionStarting( AssertionInfo const& ) {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); SectionNode& sectionNode = *m_sectionStack.back(); sectionNode.assertions.push_back( assertionStats ); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); m_testCases.push_back( node ); m_rootSection.reset(); assert( m_deepestSection ); m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } virtual void testRunEnded( TestRunStats const& testRunStats ) { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); testRunEndedCumulative(); } virtual void testRunEndedCumulative() = 0; virtual void skipTest( TestCaseInfo const& ) {} Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; std::vector > m_testCases; std::vector > m_testGroups; std::vector > m_testRuns; Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; }; template char const* getLineOfChars() { static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; if( !*line ) { memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; } return line; } } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED namespace Catch { template class LegacyReporterRegistrar { class ReporterFactory : public IReporterFactory { virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new LegacyReporterAdapter( new T( config ) ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: LegacyReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; template class ReporterRegistrar { class ReporterFactory : public IReporterFactory { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register // your custom reporter class be aware that the native reporter interface has changed // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. // However please consider updating to the new interface as the old one is now // deprecated and will probably be removed quite soon! // Please contact me via github if you have any questions at all about this. // In fact, ideally, please contact me anyway to let me know you've hit this - as I have // no idea who is actually using custom reporters at all (possibly no-one!). // The new interface is designed to minimise exposure to interface changes in the future. virtual IStreamingReporter* create( ReporterConfig const& config ) const { return new T( config ); } virtual std::string getDescription() const { return T::getDescription(); } }; public: ReporterRegistrar( std::string const& name ) { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include namespace Catch { class XmlWriter { public: class ScopedElement { public: ScopedElement( XmlWriter* writer ) : m_writer( writer ) {} ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ other.m_writer = NULL; } ~ScopedElement() { if( m_writer ) m_writer->endElement(); } ScopedElement& writeText( std::string const& text, bool indent = true ) { m_writer->writeText( text, indent ); return *this; } template ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { m_writer->writeAttribute( name, attribute ); return *this; } private: mutable XmlWriter* m_writer; }; XmlWriter() : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &Catch::cout() ) {} XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &os ) {} ~XmlWriter() { while( !m_tags.empty() ) endElement(); } XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); stream() << m_indent << "<" << name; m_tags.push_back( name ); m_indent += " "; m_tagIsOpen = true; return *this; } ScopedElement scopedElement( std::string const& name ) { ScopedElement scoped( this ); startElement( name ); return scoped; } XmlWriter& endElement() { newlineIfNecessary(); m_indent = m_indent.substr( 0, m_indent.size()-2 ); if( m_tagIsOpen ) { stream() << "/>\n"; m_tagIsOpen = false; } else { stream() << m_indent << "\n"; } m_tags.pop_back(); return *this; } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { if( !name.empty() && !attribute.empty() ) { stream() << " " << name << "=\""; writeEncodedText( attribute ); stream() << "\""; } return *this; } XmlWriter& writeAttribute( std::string const& name, bool attribute ) { stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; return *this; } template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { if( !name.empty() ) stream() << " " << name << "=\"" << attribute << "\""; return *this; } XmlWriter& writeText( std::string const& text, bool indent = true ) { if( !text.empty() ){ bool tagWasOpen = m_tagIsOpen; ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; writeEncodedText( text ); m_needsNewline = true; } return *this; } XmlWriter& writeComment( std::string const& text ) { ensureTagClosed(); stream() << m_indent << ""; m_needsNewline = true; return *this; } XmlWriter& writeBlankLine() { ensureTagClosed(); stream() << "\n"; return *this; } void setStream( std::ostream& os ) { m_os = &os; } private: XmlWriter( XmlWriter const& ); void operator=( XmlWriter const& ); std::ostream& stream() { return *m_os; } void ensureTagClosed() { if( m_tagIsOpen ) { stream() << ">\n"; m_tagIsOpen = false; } } void newlineIfNecessary() { if( m_needsNewline ) { stream() << "\n"; m_needsNewline = false; } } void writeEncodedText( std::string const& text ) { static const char* charsToEncode = "<&\""; std::string mtext = text; std::string::size_type pos = mtext.find_first_of( charsToEncode ); while( pos != std::string::npos ) { stream() << mtext.substr( 0, pos ); switch( mtext[pos] ) { case '<': stream() << "<"; break; case '&': stream() << "&"; break; case '\"': stream() << """; break; } mtext = mtext.substr( pos+1 ); pos = mtext.find_first_of( charsToEncode ); } stream() << mtext; } bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; std::string m_indent; std::ostream* m_os; }; } namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) {} virtual ~XmlReporter(); static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = true; return prefs; } virtual void noMatchingTestCases( std::string const& s ) { StreamingReporterBase::noMatchingTestCases( s ); } virtual void testRunStarting( TestRunInfo const& testInfo ) { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); if( !m_config->name().empty() ) m_xml.writeAttribute( "name", m_config->name() ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } virtual void testCaseStarting( TestCaseInfo const& testInfo ) { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); if ( m_config->showDurations() == ShowDurations::Always ) m_testCaseTimer.start(); } virtual void sectionStarting( SectionInfo const& sectionInfo ) { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) .writeAttribute( "name", trim( sectionInfo.name ) ) .writeAttribute( "description", sectionInfo.description ); } } virtual void assertionStarting( AssertionInfo const& ) { } virtual bool assertionEnded( AssertionStats const& assertionStats ) { const AssertionResult& assertionResult = assertionStats.assertionResult; // Print any info messages in tags. if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { for( std::vector::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); it != itEnd; ++it ) { if( it->type == ResultWas::Info ) { m_xml.scopedElement( "Info" ) .writeText( it->message ); } else if ( it->type == ResultWas::Warning ) { m_xml.scopedElement( "Warning" ) .writeText( it->message ); } } } // Drop out if result was successful but we're not printing them. if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) return true; // Print the expression if there is one. if( assertionResult.hasExpression() ) { m_xml.startElement( "Expression" ) .writeAttribute( "success", assertionResult.succeeded() ) .writeAttribute( "type", assertionResult.getTestMacroName() ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ); m_xml.scopedElement( "Original" ) .writeText( assertionResult.getExpression() ); m_xml.scopedElement( "Expanded" ) .writeText( assertionResult.getExpandedExpression() ); } // And... Print a result applicable to each result type. switch( assertionResult.getResultType() ) { case ResultWas::ThrewException: m_xml.scopedElement( "Exception" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); break; case ResultWas::FatalErrorCondition: m_xml.scopedElement( "Fatal Error Condition" ) .writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeText( assertionResult.getMessage() ); break; case ResultWas::Info: m_xml.scopedElement( "Info" ) .writeText( assertionResult.getMessage() ); break; case ResultWas::Warning: // Warning will already have been written break; case ResultWas::ExplicitFailure: m_xml.scopedElement( "Failure" ) .writeText( assertionResult.getMessage() ); break; default: break; } if( assertionResult.hasExpression() ) m_xml.endElement(); return true; } virtual void sectionEnded( SectionStats const& sectionStats ) { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); e.writeAttribute( "successes", sectionStats.assertions.passed ); e.writeAttribute( "failures", sectionStats.assertions.failed ); e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); m_xml.endElement(); } } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); if ( m_config->showDurations() == ShowDurations::Always ) e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); m_xml.endElement(); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); m_xml.endElement(); } virtual void testRunEnded( TestRunStats const& testRunStats ) { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); m_xml.endElement(); } private: Timer m_testCaseTimer; XmlWriter m_xml; int m_sectionDepth; }; INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_junit.hpp #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED #include namespace Catch { class JunitReporter : public CumulativeReporterBase { public: JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) {} ~JunitReporter(); static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = true; return prefs; } virtual void testRunStarting( TestRunInfo const& runInfo ) { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } virtual void testGroupStarting( GroupInfo const& groupInfo ) { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); unexpectedExceptions = 0; CumulativeReporterBase::testGroupStarting( groupInfo ); } virtual bool assertionEnded( AssertionStats const& assertionStats ) { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } virtual void testRunEndedCumulative() { xml.endElement(); } void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); xml.writeAttribute( "tests", stats.totals.assertions.total() ); xml.writeAttribute( "hostname", "tbd" ); // !TBD if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else xml.writeAttribute( "time", suiteTime ); xml.writeAttribute( "timestamp", "tbd" ); // !TBD // Write test cases for( TestGroupNode::ChildNodes::const_iterator it = groupNode.children.begin(), itEnd = groupNode.children.end(); it != itEnd; ++it ) writeTestCase( **it ); xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); } void writeTestCase( TestCaseNode const& testCaseNode ) { TestCaseStats const& stats = testCaseNode.value; // All test cases have exactly one section - which represents the // test case itself. That section may have 0-n nested sections assert( testCaseNode.children.size() == 1 ); SectionNode const& rootSection = *testCaseNode.children.front(); std::string className = stats.testInfo.className; if( className.empty() ) { if( rootSection.childSections.empty() ) className = "global"; } writeSection( className, "", rootSection ); } void writeSection( std::string const& className, std::string const& rootName, SectionNode const& sectionNode ) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + "/" + name; if( !sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty() ) { XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); if( className.empty() ) { xml.writeAttribute( "classname", name ); xml.writeAttribute( "name", "root" ); } else { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); writeAssertions( sectionNode ); if( !sectionNode.stdOut.empty() ) xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); if( !sectionNode.stdErr.empty() ) xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); } for( SectionNode::ChildSections::const_iterator it = sectionNode.childSections.begin(), itEnd = sectionNode.childSections.end(); it != itEnd; ++it ) if( className.empty() ) writeSection( name, "", **it ); else writeSection( className, name, **it ); } void writeAssertions( SectionNode const& sectionNode ) { for( SectionNode::Assertions::const_iterator it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); it != itEnd; ++it ) writeAssertion( *it ); } void writeAssertion( AssertionStats const& stats ) { AssertionResult const& result = stats.assertionResult; if( !result.isOk() ) { std::string elementName; switch( result.getResultType() ) { case ResultWas::ThrewException: case ResultWas::FatalErrorCondition: elementName = "error"; break; case ResultWas::ExplicitFailure: elementName = "failure"; break; case ResultWas::ExpressionFailed: elementName = "failure"; break; case ResultWas::DidntThrowException: elementName = "failure"; break; // We should never see these here: case ResultWas::Info: case ResultWas::Warning: case ResultWas::Ok: case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: elementName = "internalError"; break; } XmlWriter::ScopedElement e = xml.scopedElement( elementName ); xml.writeAttribute( "message", result.getExpandedExpression() ); xml.writeAttribute( "type", result.getTestMacroName() ); std::ostringstream oss; if( !result.getMessage().empty() ) oss << result.getMessage() << "\n"; for( std::vector::const_iterator it = stats.infoMessages.begin(), itEnd = stats.infoMessages.end(); it != itEnd; ++it ) if( it->type == ResultWas::Info ) oss << it->message << "\n"; oss << "at " << result.getSourceInfo(); xml.writeText( oss.str(), false ); } } XmlWriter xml; Timer suiteTimer; std::ostringstream stdOutForSuite; std::ostringstream stdErrForSuite; unsigned int unexpectedExceptions; }; INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_console.hpp #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED namespace Catch { struct ConsoleReporter : StreamingReporterBase { ConsoleReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_headerPrinted( false ) {} virtual ~ConsoleReporter(); static std::string getDescription() { return "Reports test results as plain lines of text"; } virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } virtual void noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << "'" << std::endl; } virtual void assertionStarting( AssertionInfo const& ) { } virtual bool assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } lazyPrint(); AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } virtual void sectionStarting( SectionInfo const& _sectionInfo ) { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } virtual void sectionEnded( SectionStats const& _sectionStats ) { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); if( m_sectionStack.size() > 1 ) stream << "\nNo assertions in section"; else stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } if( m_headerPrinted ) { if( m_config->showDurations() == ShowDurations::Always ) stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; m_headerPrinted = false; } else { if( m_config->showDurations() == ShowDurations::Always ) stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; } StreamingReporterBase::sectionEnded( _sectionStats ); } virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; printTotals( _testGroupStats.totals ); stream << "\n" << std::endl; } StreamingReporterBase::testGroupEnded( _testGroupStats ); } virtual void testRunEnded( TestRunStats const& _testRunStats ) { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ), stats( _stats ), result( _stats.assertionResult ), colour( Colour::None ), message( result.getMessage() ), messages( _stats.infoMessages ), printInfoMessages( _printInfoMessages ) { switch( result.getResultType() ) { case ResultWas::Ok: colour = Colour::Success; passOrFail = "PASSED"; //if( result.hasMessage() ) if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ExpressionFailed: if( result.isOk() ) { colour = Colour::Success; passOrFail = "FAILED - but was ok"; } else { colour = Colour::Error; passOrFail = "FAILED"; } if( _stats.infoMessages.size() == 1 ) messageLabel = "with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "with messages"; break; case ResultWas::ThrewException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to unexpected exception with message"; break; case ResultWas::FatalErrorCondition: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "due to a fatal error condition"; break; case ResultWas::DidntThrowException: colour = Colour::Error; passOrFail = "FAILED"; messageLabel = "because no exception was thrown where one was expected"; break; case ResultWas::Info: messageLabel = "info"; break; case ResultWas::Warning: messageLabel = "warning"; break; case ResultWas::ExplicitFailure: passOrFail = "FAILED"; colour = Colour::Error; if( _stats.infoMessages.size() == 1 ) messageLabel = "explicitly with message"; if( _stats.infoMessages.size() > 1 ) messageLabel = "explicitly with messages"; break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: passOrFail = "** internal error **"; colour = Colour::Error; break; } } void print() const { printSourceInfo(); if( stats.totals.assertions.total() > 0 ) { if( result.isOk() ) stream << "\n"; printResultType(); printOriginalExpression(); printReconstructedExpression(); } else { stream << "\n"; } printMessage(); } private: void printResultType() const { if( !passOrFail.empty() ) { Colour colourGuard( colour ); stream << passOrFail << ":\n"; } } void printOriginalExpression() const { if( result.hasExpression() ) { Colour colourGuard( Colour::OriginalExpression ); stream << " "; stream << result.getExpressionInMacro(); stream << "\n"; } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { stream << "with expansion:\n"; Colour colourGuard( Colour::ReconstructedExpression ); stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; } } void printMessage() const { if( !messageLabel.empty() ) stream << messageLabel << ":" << "\n"; for( std::vector::const_iterator it = messages.begin(), itEnd = messages.end(); it != itEnd; ++it ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || it->type != ResultWas::Info ) stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; } } void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ": "; } std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; Colour::Code colour; std::string passOrFail; std::string messageLabel; std::string message; std::vector messages; bool printInfoMessages; }; void lazyPrint() { if( !currentTestRunInfo.used ) lazyPrintRunInfo(); if( !currentGroupInfo.used ) lazyPrintGroupInfo(); if( !m_headerPrinted ) { printTestCaseAndSectionHeader(); m_headerPrinted = true; } } void lazyPrintRunInfo() { stream << "\n" << getLineOfChars<'~'>() << "\n"; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name << " is a Catch v" << libraryVersion << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; currentTestRunInfo.used = true; } void lazyPrintGroupInfo() { if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { printClosedHeader( "Group: " + currentGroupInfo->name ); currentGroupInfo.used = true; } } void printTestCaseAndSectionHeader() { assert( !m_sectionStack.empty() ); printOpenHeader( currentTestCaseInfo->name ); if( m_sectionStack.size() > 1 ) { Colour colourGuard( Colour::Headers ); std::vector::const_iterator it = m_sectionStack.begin()+1, // Skip first section (test case) itEnd = m_sectionStack.end(); for( ; it != itEnd; ++it ) printHeaderString( it->name, 2 ); } SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; if( !lineInfo.empty() ){ stream << getLineOfChars<'-'>() << "\n"; Colour colourGuard( Colour::FileName ); stream << lineInfo << "\n"; } stream << getLineOfChars<'.'>() << "\n" << std::endl; } void printClosedHeader( std::string const& _name ) { printOpenHeader( _name ); stream << getLineOfChars<'.'>() << "\n"; } void printOpenHeader( std::string const& _name ) { stream << getLineOfChars<'-'>() << "\n"; { Colour colourGuard( Colour::Headers ); printHeaderString( _name ); } } // if string has a : in first line will set indent to follow it on // subsequent lines void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { std::size_t i = _string.find( ": " ); if( i != std::string::npos ) i+=2; else i = 0; stream << Text( _string, TextAttributes() .setIndent( indent+i) .setInitialIndent( indent ) ) << "\n"; } struct SummaryColumn { SummaryColumn( std::string const& _label, Colour::Code _colour ) : label( _label ), colour( _colour ) {} SummaryColumn addRow( std::size_t count ) { std::ostringstream oss; oss << count; std::string row = oss.str(); for( std::vector::iterator it = rows.begin(); it != rows.end(); ++it ) { while( it->size() < row.size() ) *it = " " + *it; while( it->size() > row.size() ) row = " " + row; } rows.push_back( row ); return *this; } std::string label; Colour::Code colour; std::vector rows; }; void printTotals( Totals const& totals ) { if( totals.testCases.total() == 0 ) { stream << Colour( Colour::Warning ) << "No tests ran\n"; } else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { stream << Colour( Colour::ResultSuccess ) << "All tests passed"; stream << " (" << pluralise( totals.assertions.passed, "assertion" ) << " in " << pluralise( totals.testCases.passed, "test case" ) << ")" << "\n"; } else { std::vector columns; columns.push_back( SummaryColumn( "", Colour::None ) .addRow( totals.testCases.total() ) .addRow( totals.assertions.total() ) ); columns.push_back( SummaryColumn( "passed", Colour::Success ) .addRow( totals.testCases.passed ) .addRow( totals.assertions.passed ) ); columns.push_back( SummaryColumn( "failed", Colour::ResultError ) .addRow( totals.testCases.failed ) .addRow( totals.assertions.failed ) ); columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) .addRow( totals.testCases.failedButOk ) .addRow( totals.assertions.failedButOk ) ); printSummaryRow( "test cases", columns, 0 ); printSummaryRow( "assertions", columns, 1 ); } } void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { for( std::vector::const_iterator it = cols.begin(); it != cols.end(); ++it ) { std::string value = it->rows[row]; if( it->label.empty() ) { stream << label << ": "; if( value != "0" ) stream << value; else stream << Colour( Colour::Warning ) << "- none -"; } else if( value != "0" ) { stream << Colour( Colour::LightGrey ) << " | "; stream << Colour( it->colour ) << value << " " << it->label; } } stream << "\n"; } static std::size_t makeRatio( std::size_t number, std::size_t total ) { std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; return ( ratio == 0 && number > 0 ) ? 1 : ratio; } static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { if( i > j && i > k ) return i; else if( j > k ) return j; else return k; } void printTotalsDivider( Totals const& totals ) { if( totals.testCases.total() > 0 ) { std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )++; while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) findMax( failedRatio, failedButOkRatio, passedRatio )--; stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); if( totals.testCases.allPassed() ) stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); else stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); } else { stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); } stream << "\n"; } void printSummaryDivider() { stream << getLineOfChars<'-'>() << "\n"; } private: bool m_headerPrinted; }; INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) } // end namespace Catch // #included from: ../reporters/catch_reporter_compact.hpp #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED namespace Catch { struct CompactReporter : StreamingReporterBase { CompactReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ) {} virtual ~CompactReporter(); static std::string getDescription() { return "Reports test results on a single line, suitable for IDEs"; } virtual ReporterPreferences getPreferences() const { ReporterPreferences prefs; prefs.shouldRedirectStdOut = false; return prefs; } virtual void noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << "'" << std::endl; } virtual void assertionStarting( AssertionInfo const& ) { } virtual bool assertionEnded( AssertionStats const& _assertionStats ) { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; // Drop out if result was successful and we're not printing those if( !m_config->includeSuccessfulResults() && result.isOk() ) { if( result.getResultType() != ResultWas::Warning ) return false; printInfoMessages = false; } AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); printer.print(); stream << std::endl; return true; } virtual void testRunEnded( TestRunStats const& _testRunStats ) { printTotals( _testRunStats.totals ); stream << "\n" << std::endl; StreamingReporterBase::testRunEnded( _testRunStats ); } private: class AssertionPrinter { void operator= ( AssertionPrinter const& ); public: AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) : stream( _stream ) , stats( _stats ) , result( _stats.assertionResult ) , messages( _stats.infoMessages ) , itMessage( _stats.infoMessages.begin() ) , printInfoMessages( _printInfoMessages ) {} void print() { printSourceInfo(); itMessage = messages.begin(); switch( result.getResultType() ) { case ResultWas::Ok: printResultType( Colour::ResultSuccess, passedString() ); printOriginalExpression(); printReconstructedExpression(); if ( ! result.hasExpression() ) printRemainingMessages( Colour::None ); else printRemainingMessages(); break; case ResultWas::ExpressionFailed: if( result.isOk() ) printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); else printResultType( Colour::Error, failedString() ); printOriginalExpression(); printReconstructedExpression(); printRemainingMessages(); break; case ResultWas::ThrewException: printResultType( Colour::Error, failedString() ); printIssue( "unexpected exception with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::FatalErrorCondition: printResultType( Colour::Error, failedString() ); printIssue( "fatal error condition with message:" ); printMessage(); printExpressionWas(); printRemainingMessages(); break; case ResultWas::DidntThrowException: printResultType( Colour::Error, failedString() ); printIssue( "expected exception, got none" ); printExpressionWas(); printRemainingMessages(); break; case ResultWas::Info: printResultType( Colour::None, "info" ); printMessage(); printRemainingMessages(); break; case ResultWas::Warning: printResultType( Colour::None, "warning" ); printMessage(); printRemainingMessages(); break; case ResultWas::ExplicitFailure: printResultType( Colour::Error, failedString() ); printIssue( "explicitly" ); printRemainingMessages( Colour::None ); break; // These cases are here to prevent compiler warnings case ResultWas::Unknown: case ResultWas::FailureBit: case ResultWas::Exception: printResultType( Colour::Error, "** internal error **" ); break; } } private: // Colour::LightGrey static Colour::Code dimColour() { return Colour::FileName; } #ifdef CATCH_PLATFORM_MAC static const char* failedString() { return "FAILED"; } static const char* passedString() { return "PASSED"; } #else static const char* failedString() { return "failed"; } static const char* passedString() { return "passed"; } #endif void printSourceInfo() const { Colour colourGuard( Colour::FileName ); stream << result.getSourceInfo() << ":"; } void printResultType( Colour::Code colour, std::string passOrFail ) const { if( !passOrFail.empty() ) { { Colour colourGuard( colour ); stream << " " << passOrFail; } stream << ":"; } } void printIssue( std::string issue ) const { stream << " " << issue; } void printExpressionWas() { if( result.hasExpression() ) { stream << ";"; { Colour colour( dimColour() ); stream << " expression was:"; } printOriginalExpression(); } } void printOriginalExpression() const { if( result.hasExpression() ) { stream << " " << result.getExpression(); } } void printReconstructedExpression() const { if( result.hasExpandedExpression() ) { { Colour colour( dimColour() ); stream << " for: "; } stream << result.getExpandedExpression(); } } void printMessage() { if ( itMessage != messages.end() ) { stream << " '" << itMessage->message << "'"; ++itMessage; } } void printRemainingMessages( Colour::Code colour = dimColour() ) { if ( itMessage == messages.end() ) return; // using messages.end() directly yields compilation error: std::vector::const_iterator itEnd = messages.end(); const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); { Colour colourGuard( colour ); stream << " with " << pluralise( N, "message" ) << ":"; } for(; itMessage != itEnd; ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || itMessage->type != ResultWas::Info ) { stream << " '" << itMessage->message << "'"; if ( ++itMessage != itEnd ) { Colour colourGuard( dimColour() ); stream << " and"; } } } } private: std::ostream& stream; AssertionStats const& stats; AssertionResult const& result; std::vector messages; std::vector::const_iterator itMessage; bool printInfoMessages; }; // Colour, message variants: // - white: No tests ran. // - red: Failed [both/all] N test cases, failed [both/all] M assertions. // - white: Passed [both/all] N test cases (no assertions). // - red: Failed N tests cases, failed M assertions. // - green: Passed [both/all] N tests cases with M assertions. std::string bothOrAll( std::size_t count ) const { return count == 1 ? "" : count == 2 ? "both " : "all " ; } void printTotals( const Totals& totals ) const { if( totals.testCases.total() == 0 ) { stream << "No tests ran."; } else if( totals.testCases.failed == totals.testCases.total() ) { Colour colour( Colour::ResultError ); const std::string qualify_assertions_failed = totals.assertions.failed == totals.assertions.total() ? bothOrAll( totals.assertions.failed ) : ""; stream << "Failed " << bothOrAll( totals.testCases.failed ) << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << qualify_assertions_failed << pluralise( totals.assertions.failed, "assertion" ) << "."; } else if( totals.assertions.total() == 0 ) { stream << "Passed " << bothOrAll( totals.testCases.total() ) << pluralise( totals.testCases.total(), "test case" ) << " (no assertions)."; } else if( totals.assertions.failed ) { Colour colour( Colour::ResultError ); stream << "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; } else { Colour colour( Colour::ResultSuccess ); stream << "Passed " << bothOrAll( totals.testCases.passed ) << pluralise( totals.testCases.passed, "test case" ) << " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; } } }; INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch namespace Catch { NonCopyable::~NonCopyable() {} IShared::~IShared() {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} ITestCase::~ITestCase() {} ITestCaseRegistry::~ITestCaseRegistry() {} IRegistryHub::~IRegistryHub() {} IMutableRegistryHub::~IMutableRegistryHub() {} IExceptionTranslator::~IExceptionTranslator() {} IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} IReporter::~IReporter() {} IReporterFactory::~IReporterFactory() {} IReporterRegistry::~IReporterRegistry() {} IStreamingReporter::~IStreamingReporter() {} AssertionStats::~AssertionStats() {} SectionStats::~SectionStats() {} TestCaseStats::~TestCaseStats() {} TestGroupStats::~TestGroupStats() {} TestRunStats::~TestRunStats() {} CumulativeReporterBase::SectionNode::~SectionNode() {} CumulativeReporterBase::~CumulativeReporterBase() {} StreamingReporterBase::~StreamingReporterBase() {} ConsoleReporter::~ConsoleReporter() {} CompactReporter::~CompactReporter() {} IRunner::~IRunner() {} IMutableContext::~IMutableContext() {} IConfig::~IConfig() {} XmlReporter::~XmlReporter() {} JunitReporter::~JunitReporter() {} TestRegistry::~TestRegistry() {} FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} TestSpec::ExcludedPattern::~ExcludedPattern() {} Matchers::Impl::StdString::Equals::~Equals() {} Matchers::Impl::StdString::Contains::~Contains() {} Matchers::Impl::StdString::StartsWith::~StartsWith() {} Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} } #ifdef __clang__ #pragma clang diagnostic pop #endif #endif #ifdef CATCH_CONFIG_MAIN // #included from: internal/catch_default_main.hpp #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED #ifndef __OBJC__ // Standard C/C++ main entry point int main (int argc, char * const argv[]) { return Catch::Session().run( argc, argv ); } #else // __OBJC__ // Objective-C entry point int main (int argc, char * const argv[]) { #if !CATCH_ARC_ENABLED NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; #endif Catch::registerTestMethods(); int result = Catch::Session().run( argc, (char* const*)argv ); #if !CATCH_ARC_ENABLED [pool drain]; #endif return result; } #endif // __OBJC__ #endif #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) #else #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) #endif #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) #define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) #define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) #define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) #define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) #define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) #define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) #define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) #ifdef CATCH_CONFIG_VARIADIC_MACROS #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) #else #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) #endif #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) // "BDD-style" convenience wrappers #ifdef CATCH_CONFIG_VARIADIC_MACROS #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) #else #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif #define GIVEN( desc ) SECTION( " Given: " desc, "" ) #define WHEN( desc ) SECTION( " When: " desc, "" ) #define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) #define THEN( desc ) SECTION( " Then: " desc, "" ) #define AND_THEN( desc ) SECTION( " And: " desc, "" ) using Catch::Detail::Approx; // #included from: internal/catch_reenable_warnings.h #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(pop) # else # pragma clang diagnostic pop # endif #elif defined __GNUC__ # pragma GCC diagnostic pop #endif #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED giada-0.11.2/tests/conf.cpp000066400000000000000000000116031264622563000154420ustar00rootroot00000000000000#include "../src/core/const.h" #include "../src/core/conf.h" #include "catch.hpp" using std::string; TEST_CASE("Test Conf class") { Conf conf; SECTION("test write") { conf.header = "GIADACONFTEST"; conf.logMode = 1; conf.soundSystem = 2; conf.soundDeviceOut = 3; conf.soundDeviceIn = 4; conf.channelsOut = 5; conf.channelsIn = 6; conf.samplerate = 7; conf.buffersize = 8; conf.delayComp = 9; conf.limitOutput = true; conf.rsmpQuality = 10; conf.midiSystem = 11; conf.midiPortOut = 12; conf.midiPortIn = 13; conf.noNoteOff = false; conf.midiMapPath = "path/to/midi/map"; conf.lastFileMap = "path/to/last/midi/map"; conf.midiSync = 14; conf.midiTCfps = 15.1f; conf.midiInRewind = 16; conf.midiInStartStop = 17; conf.midiInActionRec = 18; conf.midiInInputRec = 19; conf.midiInMetronome = 20; conf.midiInVolumeIn = 21; conf.midiInVolumeOut = 22; conf.midiInBeatDouble = 23; conf.midiInBeatHalf = 24; conf.recsStopOnChanHalt = true; conf.chansStopOnSeqHalt = false; conf.treatRecsAsLoops = true; conf.resizeRecordings = false; conf.pluginPath = "path/to/plugins"; conf.patchPath = "path/to/patches"; conf.samplePath = "path/to/samples"; conf.mainWindowX = 0; conf.mainWindowY = 0; conf.mainWindowW = 800; conf.mainWindowH = 600; conf.browserX = 0; conf.browserY = 0; conf.browserW = 800; conf.browserH = 600; conf.actionEditorX = 0; conf.actionEditorY = 0; conf.actionEditorW = 800; conf.actionEditorH = 600; conf.actionEditorZoom = 1; conf.actionEditorGridVal = 10; conf.actionEditorGridOn = 1; conf.sampleEditorX = 0; conf.sampleEditorY = 0; conf.sampleEditorW = 800; conf.sampleEditorH = 600; conf.sampleEditorGridVal = 4; conf.sampleEditorGridOn = 0; conf.pianoRollY = 0; conf.pianoRollH = 900; conf.pluginListX = 0; conf.pluginListY = 50; conf.configX = 20; conf.configY = 20; conf.bpmX = 30; conf.bpmY = 36; conf.beatsX = 1; conf.beatsY = 1; conf.aboutX = 2; conf.aboutY = 2; REQUIRE(conf.write() == 1); } SECTION("test read") { REQUIRE(conf.read() == 1); REQUIRE(conf.header == "GIADACONFTEST"); REQUIRE(conf.logMode == 1); REQUIRE(conf.soundSystem == 2); REQUIRE(conf.soundDeviceOut == 3); REQUIRE(conf.soundDeviceIn == 4); REQUIRE(conf.channelsOut == 5); REQUIRE(conf.channelsIn == 6); REQUIRE(conf.samplerate == 44100); // sanitized REQUIRE(conf.buffersize == 8); REQUIRE(conf.delayComp == 9); REQUIRE(conf.limitOutput == true); REQUIRE(conf.rsmpQuality == 0); // sanitized REQUIRE(conf.midiSystem == 11); REQUIRE(conf.midiPortOut == 12); REQUIRE(conf.midiPortIn == 13); REQUIRE(conf.noNoteOff == false); REQUIRE(conf.midiMapPath == "path/to/midi/map"); REQUIRE(conf.lastFileMap == "path/to/last/midi/map"); REQUIRE(conf.midiSync == 14); REQUIRE(conf.midiTCfps == Approx(15.1)); REQUIRE(conf.midiInRewind == 16); REQUIRE(conf.midiInStartStop == 17); REQUIRE(conf.midiInActionRec == 18); REQUIRE(conf.midiInInputRec == 19); REQUIRE(conf.midiInMetronome == 20); REQUIRE(conf.midiInVolumeIn == 21); REQUIRE(conf.midiInVolumeOut == 22); REQUIRE(conf.midiInBeatDouble == 23); REQUIRE(conf.midiInBeatHalf == 24); REQUIRE(conf.recsStopOnChanHalt == true); REQUIRE(conf.chansStopOnSeqHalt == false); REQUIRE(conf.treatRecsAsLoops == true); REQUIRE(conf.resizeRecordings == false); REQUIRE(conf.pluginPath == "path/to/plugins"); REQUIRE(conf.patchPath == "path/to/patches"); REQUIRE(conf.samplePath == "path/to/samples"); REQUIRE(conf.mainWindowX == 0); REQUIRE(conf.mainWindowY == 0); REQUIRE(conf.mainWindowW == 800); REQUIRE(conf.mainWindowH == 600); REQUIRE(conf.browserX == 0); REQUIRE(conf.browserY == 0); REQUIRE(conf.browserW == 800); REQUIRE(conf.browserH == 600); REQUIRE(conf.actionEditorX == 0); REQUIRE(conf.actionEditorY == 0); REQUIRE(conf.actionEditorW == 800); REQUIRE(conf.actionEditorH == 600); REQUIRE(conf.actionEditorZoom == 100); // sanitized REQUIRE(conf.actionEditorGridVal == 10); REQUIRE(conf.actionEditorGridOn == 1); REQUIRE(conf.sampleEditorX == 0); REQUIRE(conf.sampleEditorY == 0); REQUIRE(conf.sampleEditorW == 800); REQUIRE(conf.sampleEditorH == 600); REQUIRE(conf.sampleEditorGridVal == 4); REQUIRE(conf.sampleEditorGridOn == 0); REQUIRE(conf.pianoRollY == 0); REQUIRE(conf.pianoRollH == 900); REQUIRE(conf.pluginListX == 0); REQUIRE(conf.pluginListY == 50); REQUIRE(conf.configX == 20); REQUIRE(conf.configY == 20); REQUIRE(conf.bpmX == 30); REQUIRE(conf.bpmY == 36); REQUIRE(conf.beatsX == 1); REQUIRE(conf.beatsY == 1); REQUIRE(conf.aboutX == 2); REQUIRE(conf.aboutY == 2); } } giada-0.11.2/tests/main.cpp000066400000000000000000000000601264622563000154340ustar00rootroot00000000000000#define CATCH_CONFIG_MAIN #include "catch.hpp" giada-0.11.2/tests/midiMapConf.cpp000066400000000000000000000077341264622563000167150ustar00rootroot00000000000000#include "../src/core/const.h" #include "../src/core/midiMapConf.h" #include "catch.hpp" using std::string; TEST_CASE("Test MidiMapConf class") { MidiMapConf midimap; SECTION("test default values") { midimap.setDefault(); REQUIRE(midimap.brand == ""); REQUIRE(midimap.device == ""); REQUIRE(midimap.muteOn.channel == 0); REQUIRE(midimap.muteOn.valueStr == ""); REQUIRE(midimap.muteOn.offset == -1); REQUIRE(midimap.muteOn.value == 0); REQUIRE(midimap.muteOff.channel == 0); REQUIRE(midimap.muteOff.valueStr == ""); REQUIRE(midimap.muteOff.offset == -1); REQUIRE(midimap.muteOff.value == 0); REQUIRE(midimap.soloOn.channel == 0); REQUIRE(midimap.soloOn.valueStr == ""); REQUIRE(midimap.soloOn.offset == -1); REQUIRE(midimap.soloOn.value == 0); REQUIRE(midimap.soloOff.channel == 0); REQUIRE(midimap.soloOff.valueStr == ""); REQUIRE(midimap.soloOff.offset == -1); REQUIRE(midimap.soloOff.value == 0); REQUIRE(midimap.waiting.channel == 0); REQUIRE(midimap.waiting.valueStr == ""); REQUIRE(midimap.waiting.offset == -1); REQUIRE(midimap.waiting.value == 0); REQUIRE(midimap.playing.channel == 0); REQUIRE(midimap.playing.valueStr == ""); REQUIRE(midimap.playing.offset == -1); REQUIRE(midimap.playing.value == 0); REQUIRE(midimap.stopping.channel == 0); REQUIRE(midimap.stopping.valueStr == ""); REQUIRE(midimap.stopping.offset == -1); REQUIRE(midimap.stopping.value == 0); REQUIRE(midimap.stopped.channel == 0); REQUIRE(midimap.stopped.valueStr == ""); REQUIRE(midimap.stopped.offset == -1); REQUIRE(midimap.stopped.value == 0); } SECTION("test read") { midimap.init(); midimap.setDefault(); /* expect more than 2 midifiles */ REQUIRE(midimap.maps.size() >= 2); /* try with deprecated mode */ int res = midimap.read("akai-lpd8.giadamap"); if (res != MIDIMAP_READ_OK) res = midimap.readMap_DEPR_("akai-lpd8.giadamap"); REQUIRE(res == MIDIMAP_READ_OK); REQUIRE(midimap.brand == "AKAI"); REQUIRE(midimap.device == "LPD8"); REQUIRE(midimap.initCommands.size() == 2); REQUIRE(midimap.initCommands[0].channel == 0); REQUIRE(midimap.initCommands[0].value == 0xB0000000); REQUIRE(midimap.initCommands[1].channel == 0); REQUIRE(midimap.initCommands[1].value == 0xB0002800); /* TODO - can't check 'valueStr' until deprecated methods are alive */ REQUIRE(midimap.muteOn.channel == 0); //REQUIRE(midimap.muteOn.valueStr == "90nn3F00"); REQUIRE(midimap.muteOn.offset == 16); REQUIRE(midimap.muteOn.value == 0x90003F00); REQUIRE(midimap.muteOff.channel == 0); //REQUIRE(midimap.muteOff.valueStr == "90nn0C00"); REQUIRE(midimap.muteOff.offset == 16); REQUIRE(midimap.muteOff.value == 0x90000C00); REQUIRE(midimap.soloOn.channel == 0); //REQUIRE(midimap.soloOn.valueStr == "90nn0F00"); REQUIRE(midimap.soloOn.offset == 16); REQUIRE(midimap.soloOn.value == 0x90000F00); REQUIRE(midimap.soloOff.channel == 0); //REQUIRE(midimap.soloOff.valueStr == "90nn0C00"); REQUIRE(midimap.soloOff.offset == 16); REQUIRE(midimap.soloOff.value == 0x90000C00); REQUIRE(midimap.waiting.channel == 0); //REQUIRE(midimap.waiting.valueStr == "90nn7f00"); REQUIRE(midimap.waiting.offset == 16); REQUIRE(midimap.waiting.value == 0x90007f00); REQUIRE(midimap.playing.channel == 0); //REQUIRE(midimap.playing.valueStr == "90nn7f00"); REQUIRE(midimap.playing.offset == 16); REQUIRE(midimap.playing.value == 0x90007f00); REQUIRE(midimap.stopping.channel == 0); //REQUIRE(midimap.stopping.valueStr == "90nn7f00"); REQUIRE(midimap.stopping.offset == 16); REQUIRE(midimap.stopping.value == 0x90007f00); REQUIRE(midimap.stopped.channel == 0); //REQUIRE(midimap.stopped.valueStr == "80nn7f00"); REQUIRE(midimap.stopped.offset == 16); REQUIRE(midimap.stopped.value == 0x80007f00); } } giada-0.11.2/tests/patch.cpp000066400000000000000000000167531264622563000156270ustar00rootroot00000000000000#include "../src/core/patch.h" #include "../src/core/const.h" #include "catch.hpp" using std::string; using std::vector; TEST_CASE("Test Patch class") { Patch patch; string filename = "./test-patch.json"; SECTION("test write") { Patch::action_t action1; Patch::action_t action2; Patch::channel_t channel1; Patch::channel_t channel2; Patch::column_t column; #ifdef WITH_VST Patch::plugin_t plugin1; Patch::plugin_t plugin2; Patch::plugin_t plugin3; #endif action1.type = 0; action1.frame = 50000; action1.fValue = 0.3f; action1.iValue = 1000; action2.type = 2; action2.frame = 589; action2.fValue = 1.0f; action2.iValue = 130; channel1.actions.push_back(action1); channel1.actions.push_back(action2); #ifdef WITH_VST plugin1.path = "/path/to/plugin1"; plugin1.bypass = false; plugin1.params.push_back(0.0f); plugin1.params.push_back(0.1f); plugin1.params.push_back(0.2f); channel1.plugins.push_back(plugin1); plugin2.path = "/another/path/to/plugin2"; plugin2.bypass = true; plugin2.params.push_back(0.6f); plugin2.params.push_back(0.6f); plugin2.params.push_back(0.6f); plugin2.params.push_back(0.0f); plugin2.params.push_back(1.0f); plugin2.params.push_back(1.0f); plugin2.params.push_back(0.333f); channel1.plugins.push_back(plugin2); #endif channel1.type = CHANNEL_SAMPLE; channel1.index = 666; channel1.column = 0; channel1.mute = 0; channel1.mute_s = 0; channel1.solo = 0; channel1.volume = 1.0f; channel1.panLeft = 0.5f; channel1.panRight = 0.5f; channel1.midiIn = true; channel1.midiInKeyPress = UINT32_MAX; // check maximum value channel1.midiInKeyRel = 1; channel1.midiInKill = 2; channel1.midiInVolume = 3; channel1.midiInMute = 4; channel1.midiInSolo = 5; channel1.midiOutL = true; channel1.midiOutLplaying = 7; channel1.midiOutLmute = 8; channel1.midiOutLsolo = 9; channel1.samplePath = "/tmp/test.wav"; channel1.key = 666; channel1.mode = 0; channel1.begin = 0; channel1.end = 0; channel1.boost = 0; channel1.recActive = 0; channel1.pitch = 1.2f; channel1.midiInReadActions = 0; channel1.midiInPitch = 0; channel1.midiOut = 0; channel1.midiOutChan = 5; patch.channels.push_back(channel1); column.index = 0; column.width = 500; patch.columns.push_back(column); patch.header = "GPTCH"; patch.version = "1.0"; patch.versionMajor = 6; patch.versionMinor = 6; patch.versionPatch = 6; patch.name = "test patch"; patch.bpm = 100.0f; patch.bars = 4; patch.beats = 23; patch.quantize = 1; patch.masterVolIn = 1.0f; patch.masterVolOut = 0.7f; patch.metronome = 0; patch.lastTakeId = 0; patch.samplerate = 44100; #ifdef WITH_VST patch.masterInPlugins.push_back(plugin1); patch.masterOutPlugins.push_back(plugin2); #endif REQUIRE(patch.write(filename) == 1); } SECTION("test read") { REQUIRE(patch.read(filename) == PATCH_READ_OK); REQUIRE(patch.header == "GPTCH"); REQUIRE(patch.version == "1.0"); REQUIRE(patch.versionMajor == 6); REQUIRE(patch.versionMinor == 6); REQUIRE(patch.versionPatch == 6); REQUIRE(patch.name == "test patch"); REQUIRE(patch.bpm == Approx(100.0f)); REQUIRE(patch.bars == 4); REQUIRE(patch.beats == 23); REQUIRE(patch.quantize == 1); REQUIRE(patch.masterVolIn == Approx(1.0f)); REQUIRE(patch.masterVolOut == Approx(0.7f)); REQUIRE(patch.metronome == 0); REQUIRE(patch.lastTakeId == 0); REQUIRE(patch.samplerate == 44100); Patch::column_t column0 = patch.columns.at(0); REQUIRE(column0.index == 0); REQUIRE(column0.width == 500); Patch::channel_t channel0 = patch.channels.at(0); REQUIRE(channel0.type == CHANNEL_SAMPLE); REQUIRE(channel0.index == 666); REQUIRE(channel0.column == 0); REQUIRE(channel0.mute == 0); REQUIRE(channel0.mute_s == 0); REQUIRE(channel0.solo == 0); REQUIRE(channel0.volume == Approx(1.0f)); REQUIRE(channel0.panLeft == Approx(0.5f)); REQUIRE(channel0.panRight == Approx(0.5f)); REQUIRE(channel0.midiIn == true); REQUIRE(channel0.midiInKeyPress == UINT32_MAX); REQUIRE(channel0.midiInKeyRel == 1); REQUIRE(channel0.midiInKill == 2); REQUIRE(channel0.midiInVolume == 3); REQUIRE(channel0.midiInMute == 4); REQUIRE(channel0.midiInSolo == 5); REQUIRE(channel0.midiOutL == true); REQUIRE(channel0.midiOutLplaying == 7); REQUIRE(channel0.midiOutLmute == 8); REQUIRE(channel0.midiOutLsolo == 9); REQUIRE(channel0.samplePath == "/tmp/test.wav"); REQUIRE(channel0.key == 666); REQUIRE(channel0.mode == 0); REQUIRE(channel0.begin == 0); REQUIRE(channel0.end == 0); REQUIRE(channel0.boost == 0); REQUIRE(channel0.recActive == 0); REQUIRE(channel0.pitch == Approx(1.2f)); REQUIRE(channel0.midiInReadActions == 0); REQUIRE(channel0.midiInPitch == 0); REQUIRE(channel0.midiOut == 0); REQUIRE(channel0.midiOutChan == 5); Patch::action_t action0 = channel0.actions.at(0); REQUIRE(action0.type == 0); REQUIRE(action0.frame == 50000); REQUIRE(action0.fValue == Approx(0.3f)); REQUIRE(action0.iValue == 1000); Patch::action_t action1 = channel0.actions.at(1); REQUIRE(action1.type == 2); REQUIRE(action1.frame == 589); REQUIRE(action1.fValue == Approx(1.0f)); REQUIRE(action1.iValue == 130); #ifdef WITH_VST Patch::plugin_t plugin0 = channel0.plugins.at(0); REQUIRE(plugin0.path == "/path/to/plugin1"); REQUIRE(plugin0.bypass == false); REQUIRE(plugin0.params.at(0) == Approx(0.0f)); REQUIRE(plugin0.params.at(1) == Approx(0.1f)); REQUIRE(plugin0.params.at(2) == Approx(0.2f)); Patch::plugin_t plugin1 = channel0.plugins.at(1); REQUIRE(plugin1.path == "/another/path/to/plugin2"); REQUIRE(plugin1.bypass == true); REQUIRE(plugin1.params.at(0) == Approx(0.6f)); REQUIRE(plugin1.params.at(1) == Approx(0.6f)); REQUIRE(plugin1.params.at(2) == Approx(0.6f)); REQUIRE(plugin1.params.at(3) == Approx(0.0f)); REQUIRE(plugin1.params.at(4) == Approx(1.0f)); REQUIRE(plugin1.params.at(5) == Approx(1.0f)); REQUIRE(plugin1.params.at(6) == Approx(0.333f)); Patch::plugin_t masterPlugin0 = patch.masterInPlugins.at(0); REQUIRE(masterPlugin0.path == "/path/to/plugin1"); REQUIRE(masterPlugin0.bypass == false); REQUIRE(masterPlugin0.params.at(0) == Approx(0.0f)); REQUIRE(masterPlugin0.params.at(1) == Approx(0.1f)); REQUIRE(masterPlugin0.params.at(2) == Approx(0.2f)); Patch::plugin_t masterPlugin1 = patch.masterOutPlugins.at(0); REQUIRE(masterPlugin1.path == "/another/path/to/plugin2"); REQUIRE(masterPlugin1.bypass == true); REQUIRE(masterPlugin1.params.at(0) == Approx(0.6f)); REQUIRE(masterPlugin1.params.at(1) == Approx(0.6f)); REQUIRE(masterPlugin1.params.at(2) == Approx(0.6f)); REQUIRE(masterPlugin1.params.at(3) == Approx(0.0f)); REQUIRE(masterPlugin1.params.at(4) == Approx(1.0f)); REQUIRE(masterPlugin1.params.at(5) == Approx(1.0f)); REQUIRE(masterPlugin1.params.at(6) == Approx(0.333f)); #endif } } giada-0.11.2/tests/utils.cpp000066400000000000000000000017061264622563000156600ustar00rootroot00000000000000#include "../src/utils/utils.h" #include "catch.hpp" using std::vector; TEST_CASE("Test filesystem utils") { REQUIRE(gFileExists("giada_tests") == true); REQUIRE(gFileExists("ghost_file") == false); REQUIRE(gDirExists("src/") == true); REQUIRE(gDirExists("ghost_dir/") == false); REQUIRE(gIsDir("src/") == true); REQUIRE(gIsDir("giada_tests") == false); REQUIRE(gBasename("tests/utils.cpp") == "utils.cpp"); REQUIRE(gDirname("tests/utils.cpp") == "tests"); REQUIRE(gGetExt("tests/utils.cpp") == "cpp"); REQUIRE(gStripExt("tests/utils.cpp") == "tests/utils"); } TEST_CASE("Test string utils") { REQUIRE(gReplace("Giada is cool", "cool", "hot") == "Giada is hot"); REQUIRE(gTrim(" Giada is cool ") == "Giada is cool"); REQUIRE(gItoa(666) == "666"); vector v; gSplit("Giada is cool", " ", &v); REQUIRE(v.size() == 3); REQUIRE(v.at(0) == "Giada"); REQUIRE(v.at(1) == "is"); REQUIRE(v.at(2) == "cool"); } giada-0.11.2/tests/wave.cpp000066400000000000000000000017041264622563000154600ustar00rootroot00000000000000#include "../src/core/wave.h" #include "catch.hpp" using std::string; #define G_SAMPLE_RATE 44100 #define G_BUFFER_SIZE 4096 TEST_CASE("Test Wave class") { Wave w1; SECTION("test read & write") { REQUIRE(w1.open("test.wav") == 1); REQUIRE(w1.readData() == 1); REQUIRE(w1.rate() == 11025); REQUIRE(w1.channels() == 2); REQUIRE(w1.basename() == "test"); REQUIRE(w1.extension() == "wav"); REQUIRE(w1.writeData("test-write.wav") == true); } SECTION("test copy constructor") { Wave w2(w1); REQUIRE(w2.size == w1.size); REQUIRE(w2.isLogical == true); REQUIRE(w2.rate() == 11025); REQUIRE(w2.channels() == 2); REQUIRE(w2.writeData("test-write.wav") == true); } SECTION("test rec") { Wave w3; REQUIRE(w3.allocEmpty(G_BUFFER_SIZE, G_SAMPLE_RATE) == 1); REQUIRE(w3.rate() == G_SAMPLE_RATE); REQUIRE(w3.channels() == 2); REQUIRE(w3.writeData("test-write.wav") == true); } }