diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 00000000..8829e64c --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,43 @@ +name: Rust + +on: [push, pull_request] + +jobs: + build_ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install alsa + run: sudo apt-get install libasound2-dev + - name: Build + run: cargo build --release --verbose + - name: Run tests + run: cargo test --verbose + - uses: actions/upload-artifact@v2 + with: + name: ubuntu-artifact + path: target/release/neothesia + build_windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Build + run: cargo build --release --verbose + - name: Run tests + run: cargo test --verbose + - uses: actions/upload-artifact@v2 + with: + name: windows-artifact + path: target/release/neothesia.exe + build_macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Build + run: cargo build --release --verbose + - name: Run tests + run: cargo test --verbose + - uses: actions/upload-artifact@v2 + with: + name: macos-artifact + path: target/release/neothesia diff --git a/.gitignore b/.gitignore index 190e0790..53eaa219 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,2 @@ -*.o -*.lo -Makefile -Makefile.in -aclocal.m4 -autom4te.cache/ -config.h -config.log -config.status -configure -libtool -src/.deps/ -src/.libs/ -src/Makefile -src/Makefile.in -src/libmidi.la -src/libmidi/.deps/ -src/libmidi/.dirstamp -src/linthesia -stamp-h1 - -build - -# generated with autoreconf -ivf -config.guess -config.sub -m4/ -missing -compile -config.h.in -depcomp -install-sh -ltmain.sh +/target +**/*.rs.bk diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c2ef12c3..00000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: c - -compiler: - - gcc - -sudo: required - -dist: trusty - -before_script: - - sudo apt-get update -qq - - sudo apt-get install -qq autoconf - - sudo apt-get install -qq libgtkmm-2.4-dev - - sudo apt-get install -qq libgconfmm-2.6-dev - - sudo apt-get install -qq libgtkglextmm-x11-1.2-dev - - sudo apt-get install -qq libasound2-dev - -script: - - autoconf --version - - mkdir m4 && ./autogen.sh && make && make check - - diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 58a7bd82..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/build/src/neothesia", - "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "preLaunchTask": "make" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index d88ded53..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "files.associations": { - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "array": "cpp", - "atomic": "cpp", - "*.tcc": "cpp", - "chrono": "cpp", - "condition_variable": "cpp", - "cstdint": "cpp", - "deque": "cpp", - "list": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "fstream": "cpp", - "functional": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "memory": "cpp", - "mutex": "cpp", - "new": "cpp", - "numeric": "cpp", - "optional": "cpp", - "ostream": "cpp", - "ratio": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "thread": "cpp", - "type_traits": "cpp", - "tuple": "cpp", - "typeinfo": "cpp", - "utility": "cpp", - "valarray": "cpp", - "__config": "cpp", - "__nullptr": "cpp", - "algorithm": "cpp", - "variant": "cpp" - }, - "editor.tabSize": 2 -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7a9e829e..516966d6 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,16 +1,13 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "make", - "type": "shell", - "command": "cd ${workspaceFolder}/build/ && make", - "group": { - "kind": "build", - "isDefault": true - } - } - ] -} \ No newline at end of file + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "cargo", + "subcommand": "run", + "problemMatcher": ["$rustc"], + "group": "build" + } + ] +} diff --git a/BUILD-DEPENDS b/BUILD-DEPENDS deleted file mode 100644 index 15da6a18..00000000 --- a/BUILD-DEPENDS +++ /dev/null @@ -1,5 +0,0 @@ -libgtkmm-2.4-dev -libgconfmm-2.6-dev -libgtkglextmm-x11-1.2-dev -libasound2-dev - diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index e3c8bb90..00000000 --- a/CHANGELOG +++ /dev/null @@ -1,34 +0,0 @@ -linthesia (0.4-2) unstable; urgency=low - - * Fixed "Unable to load PangoFont" bug on all platforms - * Added autoconf build system - - -- Victor Lavaud Tue, 10 Sept 2013 13:16:00 +0100 - -linthesia (0.4-1) unstable; urgency=low - - * New upstream release. - * Non-maintainer commit. - * (Closes: #2920321). - - -- Oscar Aceña Tue, 29 Dec 2009 17:19:38 +0100 - -linthesia (0.3-2) unstable; urgency=low - - * New upstream release - * Non-maintainer commit. - * (Closes: #2920683). - - -- Oscar Aceña Sat, 26 Dec 2009 14:06:28 +0100 - -linthesia (0.3-1) unstable; urgency=low - - * New upstream release - - -- Cleto Martin Angelina Thu, 24 Dec 2009 14:38:10 +0100 - -linthesia (0.1-1) unstable; urgency=low - - * Initial release (Closes: #562487) - - -- Cleto Martin Angelina Fri, 18 Dec 2009 13:49:36 +0100 diff --git a/COPYING b/COPYING deleted file mode 100644 index d511905c..00000000 --- a/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) 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 -this service 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 make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. 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. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -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 -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE 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. - - 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 -convey 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 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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision 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, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This 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. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..762ae24d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2063 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a0d4ebc8b23041c5de9bc9aee13b4bad844a589479701f31a5934cfe4aeb32" +dependencies = [ + "alsa-sys", + "bitflags 0.9.1", + "libc", + "nix 0.9.0", +] + +[[package]] +name = "alsa-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "andrew" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" +dependencies = [ + "bitflags 1.2.1", + "line_drawing", + "rusttype 0.7.9", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "android_glue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "ash" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69daec0742947f33a85931fa3cb0ce5f07929159dcbd1f0cbb5b2912e2978509" +dependencies = [ + "libloading", +] + +[[package]] +name = "atom" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "backtrace" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" +dependencies = [ + "backtrace-sys", + "cfg-if", + "libc", + "rustc-demangle", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "bitflags" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +dependencies = [ + "arrayref", + "byte-tools", +] + +[[package]] +name = "bumpalo" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" + +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "calloop" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160" +dependencies = [ + "mio", + "mio-extras", + "nix 0.14.1", +] + +[[package]] +name = "cc" +version = "1.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags 1.2.1", +] + +[[package]] +name = "cmake" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" +dependencies = [ + "cc", +] + +[[package]] +name = "cocoa" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" +dependencies = [ + "bitflags 1.2.1", + "block", + "core-foundation 0.6.4", + "core-graphics 0.17.3", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4736c86d51bd878b474400d9ec888156f4037015f5d09794fab9f26eab1ad4" +dependencies = [ + "bitflags 1.2.1", + "block", + "core-foundation 0.7.0", + "core-graphics 0.19.0", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "copyless" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127" + +[[package]] +name = "core-foundation" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" +dependencies = [ + "core-foundation-sys 0.2.3", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +dependencies = [ + "core-foundation-sys 0.6.2", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" +dependencies = [ + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-graphics" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" +dependencies = [ + "bitflags 1.2.1", + "core-foundation 0.6.4", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd" +dependencies = [ + "bitflags 1.2.1", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc065219542086f72d1e9f7aadbbab0989e980263695d129d502082d063a9d0" +dependencies = [ + "cfg-if", + "core-foundation-sys 0.6.2", + "core-graphics 0.17.3", + "libc", + "objc", +] + +[[package]] +name = "coremidi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f92de5534f182bad5f91cad85611ab222cb6e237a0555e06c65a24936c3173" +dependencies = [ + "core-foundation 0.2.3", + "core-foundation-sys 0.2.3", + "coremidi-sys", + "time", +] + +[[package]] +name = "coremidi-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f05827cebb30dcd539ff1ac9bf6764f574a15fa147f8572f99d7617142f95e" +dependencies = [ + "core-foundation-sys 0.2.3", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "d3d12" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7ed48e89905e5e146bcc1951cc3facb9e44aea9adf5dc01078cda1bd24b662" +dependencies = [ + "bitflags 1.2.1", + "libloading", + "winapi 0.3.8", +] + +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "failure" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" +dependencies = [ + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", + "synstructure", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.2.1", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" + +[[package]] +name = "futures-executor" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" + +[[package]] +name = "futures-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +dependencies = [ + "proc-macro-hack", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" + +[[package]] +name = "futures-task" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +dependencies = [ + "once_cell", +] + +[[package]] +name = "futures-util" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gfx-auxil" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b46e6f0031330a0be08d17820f2dcaaa91cb36710a97a9500cb4f1c36e785c8" +dependencies = [ + "fxhash", + "gfx-hal", + "spirv_cross", +] + +[[package]] +name = "gfx-backend-dx11" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b148219292624126f78245e50a9720d95ea149a415ce8ce73ab7014205301b88" +dependencies = [ + "bitflags 1.2.1", + "gfx-auxil", + "gfx-hal", + "libloading", + "log", + "parking_lot", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi 0.3.8", + "wio", +] + +[[package]] +name = "gfx-backend-dx12" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e526746379e974501551b08958947e67a81b5ea8cdc717a000cdd72577da05" +dependencies = [ + "bitflags 1.2.1", + "d3d12", + "gfx-auxil", + "gfx-hal", + "log", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi 0.3.8", +] + +[[package]] +name = "gfx-backend-empty" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67bd2d7bc022b257ddbdabc5fa3b10c29c292372c3409f2b6a6e3f4e11cdb85" +dependencies = [ + "gfx-hal", + "raw-window-handle", +] + +[[package]] +name = "gfx-backend-metal" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe128c29675b5afc8acdda1dfe096d6abd5e3528059ab0b98bda8215d8beed9" +dependencies = [ + "arrayvec", + "bitflags 1.2.1", + "block", + "cocoa 0.20.0", + "copyless", + "core-graphics 0.19.0", + "foreign-types", + "gfx-auxil", + "gfx-hal", + "lazy_static", + "log", + "metal", + "objc", + "parking_lot", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "storage-map", +] + +[[package]] +name = "gfx-backend-vulkan" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e4da6ab11e9cb972e52ed5e179ddfa1f2a910c61560d91cff92b4dfc682c27c" +dependencies = [ + "arrayvec", + "ash", + "byteorder", + "core-graphics 0.19.0", + "gfx-hal", + "lazy_static", + "log", + "objc", + "raw-window-handle", + "smallvec", + "winapi 0.3.8", + "x11", +] + +[[package]] +name = "gfx-descriptor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf35f5d66d1bc56e63e68d7528441453f25992bd954b84309d23c659df2c5da" +dependencies = [ + "fxhash", + "gfx-hal", + "log", +] + +[[package]] +name = "gfx-hal" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc96180204064c9493e0fe4a9efeb721e0ac59fe8e1906d0c659142a93114fb1" +dependencies = [ + "bitflags 1.2.1", + "raw-window-handle", +] + +[[package]] +name = "gfx-memory" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2eed6cda674d9cd4d92229102dbd544292124533d236904f987e9afab456137" +dependencies = [ + "fxhash", + "gfx-hal", + "hibitset", + "log", + "slab", +] + +[[package]] +name = "glsl-to-spirv" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28caebc98746d507603a2d3df66dcbe04e41d4febad0320f3eec1ef72b6bbef1" +dependencies = [ + "cmake", + "sha2", + "tempfile", +] + +[[package]] +name = "glyph_brush" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fca6f9d679bff1322c76c9a1ad4b8553b30a94f3f75bea6936e19032c2f2ec3" +dependencies = [ + "glyph_brush_layout", + "log", + "ordered-float", + "rustc-hash", + "rusttype 0.8.3", + "twox-hash", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70adc570f1dc71b6b32e241cbcc2b42175f5aea71951fbf41e68b04aec24c7" +dependencies = [ + "approx", + "rusttype 0.8.3", + "xi-unicode", +] + +[[package]] +name = "hermit-abi" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4" +dependencies = [ + "libc", +] + +[[package]] +name = "hibitset" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93a1bb8316a44459a7d14253c4d28dd7395cbd23cc04a68c46e851b8e46d64b1" +dependencies = [ + "atom", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "instant" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7152d2aed88aa566e7a342250f21ba2222c1ae230ad577499dbfa3c18475b80" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" + +[[package]] +name = "lib_midi" +version = "0.1.0" +dependencies = [ + "midly", +] + +[[package]] +name = "libc" +version = "0.2.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" + +[[package]] +name = "libloading" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +dependencies = [ + "cc", + "winapi 0.3.8", +] + +[[package]] +name = "line_drawing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" +dependencies = [ + "num-traits", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" + +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memalloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "memoffset" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e198a0ee42bdbe9ef2c09d0b9426f3b2b47d90d93a4a9b0395c4cea605e92dc0" +dependencies = [ + "bitflags 1.2.1", + "block", + "cocoa 0.20.0", + "core-graphics 0.19.0", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "midir" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76969e859af0b6dd93eb6bcbfd11029eec1b53035c015ce43b56e73bbbc02621" +dependencies = [ + "alsa", + "bitflags 1.2.1", + "coremidi", + "js-sys", + "libc", + "memalloc", + "nix 0.9.0", + "wasm-bindgen", + "web-sys", + "winapi 0.3.8", +] + +[[package]] +name = "midly" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8f2717d3da3d1b2e9a0df9fc66057e1c7c237b946e7a287223cc06f8a429e3" +dependencies = [ + "failure", + "rayon", +] + +[[package]] +name = "mio" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio", + "slab", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "neothesia" +version = "0.1.0" +dependencies = [ + "env_logger", + "futures", + "glsl-to-spirv", + "lib_midi", + "log", + "midir", + "tinyfiledialogs", + "wgpu", + "wgpu_glyph", + "winit", + "zerocopy", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "nix" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" +dependencies = [ + "bitflags 0.9.1", + "cfg-if", + "libc", + "void", +] + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +dependencies = [ + "bitflags 1.2.1", + "cc", + "cfg-if", + "libc", + "void", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" + +[[package]] +name = "ordered-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.8", +] + +[[package]] +name = "peek-poke" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93fd6a575ebf1ac2668d08443c97a22872cfb463fd8b7ddd141e9f6be59af2f" +dependencies = [ + "peek-poke-derive", +] + +[[package]] +name = "peek-poke-derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb44a25c5bba983be0fc8592dfaf3e6d0935ce8be0c6b15b2a39507af34a926" +dependencies = [ + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", + "synstructure", + "unicode-xid 0.2.0", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d480cb4e89522ccda96d0eed9af94180b7a5f93fb28f66e1fd7d68431663d1" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82996f11efccb19b685b14b5df818de31c1edcee3daa256ab5775dd98e72feb" +dependencies = [ + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", +] + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + +[[package]] +name = "proc-macro-hack" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" + +[[package]] +name = "proc-macro-nested" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid 0.2.0", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2 1.0.10", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "range-alloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9" + +[[package]] +name = "raw-window-handle" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" +dependencies = [ + "libc", +] + +[[package]] +name = "rayon" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" +dependencies = [ + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" +dependencies = [ + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "regex" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rusttype" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" +dependencies = [ + "rusttype 0.8.3", +] + +[[package]] +name = "rusttype" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0" +dependencies = [ + "approx", + "crossbeam-deque", + "crossbeam-utils", + "linked-hash-map", + "num_cpus", + "ordered-float", + "rustc-hash", + "stb_truetype", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sha2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" +dependencies = [ + "block-buffer", + "byte-tools", + "digest", + "fake-simd", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" + +[[package]] +name = "smithay-client-toolkit" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421c8dc7acf5cb205b88160f8b4cc2c5cfabe210e43b2f80f009f4c1ef910f1d" +dependencies = [ + "andrew", + "bitflags 1.2.1", + "dlib", + "lazy_static", + "memmap", + "nix 0.14.1", + "wayland-client", + "wayland-protocols", +] + +[[package]] +name = "spirv_cross" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "946216f8793f7199e3ea5b995ee8dc20a0ace1fcf46293a0ef4c17e1d046dbde" +dependencies = [ + "cc", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "stb_truetype" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" +dependencies = [ + "byteorder", +] + +[[package]] +name = "storage-map" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "syn" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213" +dependencies = [ + "proc-macro2 1.0.10", + "quote 1.0.3", + "unicode-xid 0.2.0", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +dependencies = [ + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", + "unicode-xid 0.2.0", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.8", +] + +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "tinyfiledialogs" +version = "3.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848eb50d6d21430349d82418c2244f611b1ad3e1c52c675320338b3102d06554" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "twox-hash" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" +dependencies = [ + "rand", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi 0.3.8", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasm-bindgen" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" +dependencies = [ + "quote 1.0.3", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" +dependencies = [ + "proc-macro2 1.0.10", + "quote 1.0.3", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639" + +[[package]] +name = "wayland-client" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" +dependencies = [ + "bitflags 1.2.1", + "calloop", + "downcast-rs", + "libc", + "mio", + "nix 0.14.1", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" +dependencies = [ + "nix 0.14.1", + "wayland-sys", +] + +[[package]] +name = "wayland-protocols" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" +dependencies = [ + "bitflags 1.2.1", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" +dependencies = [ + "dlib", + "lazy_static", +] + +[[package]] +name = "web-sys" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf715eb8571da470b856ecc67b057221360d9fce16f3e38001b2fb158d04012" +dependencies = [ + "arrayvec", + "parking_lot", + "raw-window-handle", + "smallvec", + "wgpu-core", + "wgpu-native", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50212a35d2c20de1c421d9a0d831f494a85f9afab240e19aae499cff9d0526f2" +dependencies = [ + "arrayvec", + "bitflags 1.2.1", + "copyless", + "fxhash", + "gfx-backend-dx11", + "gfx-backend-dx12", + "gfx-backend-empty", + "gfx-backend-metal", + "gfx-backend-vulkan", + "gfx-descriptor", + "gfx-hal", + "gfx-memory", + "log", + "parking_lot", + "peek-poke", + "smallvec", + "vec_map", + "wgpu-types", +] + +[[package]] +name = "wgpu-native" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a5051a357d071fd69c24671e0ea6d644a83c7418e47eac3511427379007403" +dependencies = [ + "arrayvec", + "lazy_static", + "libc", + "objc", + "parking_lot", + "raw-window-handle", + "wgpu-core", + "wgpu-types", +] + +[[package]] +name = "wgpu-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b69dfe001a8a6b78810c7e479717cd1898b9177dbf646611fa1f258f5a2512" +dependencies = [ + "bitflags 1.2.1", + "peek-poke", +] + +[[package]] +name = "wgpu_glyph" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fabe70968bf2cadd4055d2f36c38233936c3344db4597c542ec185df05dd97a" +dependencies = [ + "glyph_brush", + "log", + "wgpu", + "zerocopy", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winit" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc53342d3d1a3d57f3949e0692d93d5a8adb7814d8683cef4a09c2b550e94246" +dependencies = [ + "android_glue", + "bitflags 1.2.1", + "cocoa 0.19.1", + "core-foundation 0.6.4", + "core-graphics 0.17.3", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "mio-extras", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "web-sys", + "winapi 0.3.8", + "x11-dl", +] + +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "x11" +version = "2.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ecd092546cb16f25783a5451538e73afc8d32e242648d54f4ae5459ba1e773" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8" +dependencies = [ + "lazy_static", + "libc", + "maybe-uninit", + "pkg-config", +] + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" + +[[package]] +name = "xi-unicode" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7395cdb9d0a6219fa0ea77d08c946adf9c1984c72fcd443ace30365f3daadef7" + +[[package]] +name = "xml-rs" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb76e5c421bbbeb8924c60c030331b345555024d56261dae8f3e786ed817c23" + +[[package]] +name = "zerocopy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" +dependencies = [ + "proc-macro2 1.0.10", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..d2f924c4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "neothesia" +version = "0.1.0" +authors = ["Poly "] +edition = "2018" + +[features] +default = ["compile_shader"] +compile_shader = [] + +[dependencies] +zerocopy = "0.3.0" +futures = "0.3.5" + +winit = { version="0.22.1", features = ["web-sys"]} + +wgpu = "0.5.0" +wgpu_glyph = "0.8.0" + + +log = "0.4" +env_logger = "0.7.1" + +tinyfiledialogs = "3.3.9" + +lib_midi = {path="./lib_midi"} +midir = "0.6.0" + +# js-sys = { git = "https://github.com/rustwasm/wasm-bindgen" } +# web-sys = { git = "https://github.com/rustwasm/wasm-bindgen" } +# wasm-bindgen = { git = "https://github.com/rustwasm/wasm-bindgen" } +# wasm-bindgen-futures = { git = "https://github.com/rustwasm/wasm-bindgen" } +# console_error_panic_hook = "0.1.6" +# console_log = "0.2.0" + +[build-dependencies] +glsl-to-spirv = "0.1" + + +# [patch.crates-io] +# wgpu = {git ="https://github.com/gfx-rs/wgpu-rs.git"} +# wasm-bindgen = { git = "https://github.com/rustwasm/wasm-bindgen" } +# wasm-bindgen-futures = { git = "https://github.com/rustwasm/wasm-bindgen" } +# web-sys = { git = "https://github.com/rustwasm/wasm-bindgen" } +# js-sys = { git = "https://github.com/rustwasm/wasm-bindgen" } \ No newline at end of file diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 5f9f49f1..00000000 --- a/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -EXTRA_DIST = BUILD-DEPENDS CHANGELOG graphics extra music -nobase_pkgdata_DATA = graphics/app_icon.ico \ - graphics/InterfaceButtons.tga \ - graphics/neothesia.xpm \ - graphics/play_KeyHits.tga \ - graphics/play_KeyRail.tga \ - graphics/play_KeysBlack.tga \ - graphics/play_KeysWhite.tga \ - graphics/play_KeyShadow.tga \ - graphics/play_Keys.tga \ - graphics/play_NotesBlackColor.tga \ - graphics/play_NotesBlackShadow.tga \ - graphics/play_NotesWhiteColor.tga \ - graphics/play_NotesWhiteShadow.tga \ - graphics/play_Status2.tga \ - graphics/play_Status.tga \ - graphics/score_RetrySong.tga \ - graphics/stats_text.tga \ - graphics/title_ChooseTracks.tga \ - graphics/title_Exit.tga \ - graphics/title_GameMusicThemes.tga \ - graphics/title_InputBox.tga \ - graphics/title_Logo.tga \ - graphics/title_OutputBox.tga \ - graphics/title_SongBox.tga \ - graphics/trackbox.tga \ - graphics/tracks_BackToTitle.tga \ - graphics/tracks_PlaySong.tga \ - extra/neothesia.desktop \ - music/Popular/Jonh_Lennon_-_Imagine.mid - -SUBDIRS = src scripts -ACLOCAL_AMFLAGS = -I m4 - -ctags-dependencies: - @$(MAKE) -C src ctags-dependencies - -.PHONY:ctags-dependencies - diff --git a/README b/README deleted file mode 100644 index 2891afe4..00000000 --- a/README +++ /dev/null @@ -1,36 +0,0 @@ - -Linthesia is a fork of the Windows/Mac game called Synthesia. It is a game -of playing music using a MIDI keyboard (or your PC keyboard), following -a .mid file. - -Synthesia up to version 0.6.1a is Open Source. This project uses the -latest source from sourceforge. - -Compile -------- - -To compile, you need a basic c++ toolchain, and satisfy all dependences -which are on BUILD-DEPENDS file. Then, just: - - $ autoreconf -ivf - -Here you must choose: - - a) For developers - - $ mkdir build - $ cd build # Isolate compilation to speed future compilations - $ ../configure - - b) For general public - - $ ../configure --prefix=/usr - -Then: - - $ make - $ sudo make install - -Visit https://sourceforge.net/projects/linthesia/ for more info. - -Join the chat at https://gitter.im/linthesia/linthesia diff --git a/README.md b/README.md index 083c4b45..0c1bd5c2 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,9 @@ -![Neothesia Baner](https://i.imgur.com/3uiwId8.png) +![Neothesia Baner](https://i.imgur.com/QfdMwMI.png) # Neothesia -Neothesia is a fork of [Legacy Synthesia](https://github.com/johndpope/pianogame) Opensource Synthesia was abandoned in favour of [closed source commercial project](https://www.synthesiagame.com/) -Goal of this project is to bring back Legacy Synthesia to live, and make it look and work as good (or even better) than commercial Synthesia. - -Linux build is based on [Linthesia](https://github.com/linthesia/linthesia) - -![Prev](https://i.imgur.com/ljz6kjF.png) - -## Goals -* Make it look like modern software -* Treat Linux users as first class citizens -* Give Linux users good or even better alternative to windows Synthesia -* Make it flashy, particles and other cool effects -* Make it as friendly as possible for youtube piano tutorials creators (like myself) -* (Maybe) Support Windows in future - -## Windows Build? -For now I will not support windows build 😰, it is really annoying to open VM every time I want to test something, if you are windows user and you have bare minimum c++ knowledge, you can easily port it yourself. -I would really appreciate any help in maintaining windows branch. - -If you want to become full time windows maintainer you are welcome to do so, -You will have special place in my heart if you do so 😉 - -##### Noob Friendly Way To Port (not recomended) -* clone [Legacy Synthesia](https://github.com/johndpope/pianogame) -* add Neothesia commits -* build -##### Or you can try to crosscompile neothesia master branch -I didn't try it yet, but probably you can cross compile neothesia using mingw. -Remember that master branch of Neothesia uses AlsaLib, there is no way to crosscompile it, you'll have to replace some of the functions in Neothesia [libmidi](https://github.com/PolyMagic/Neothesia/tree/master/src/libmidi) -I recommend using original Windows version of [libmidi](https://github.com/johndpope/pianogame/tree/master/src/libmidi) for this - -## Todo -* Make it cross platform so ports are no longer needed -* Replace unnecessary sprites with shaders -* Create proper shader loading system instead of current placeholder one -* Modernise main screen and track selection screen -* Consider adding song select screen, instead of native dialogue - -## Compile - -To compile, you need a basic c++ toolchain, and satisfy all dependences which are on BUILD-DEPENDS file. -You also need [Roboto font](https://www.archlinux.org/packages/community/any/ttf-roboto/) and [glew](https://www.archlinux.org/packages/extra/x86_64/glew/) installed on your system -Then, just: - - - $ autoreconf -ivf - $ mkdir build - $ cd build # Isolate compilation to speed future compilations - -Here you must choose: - - a) For developers - - $ ../configure - b) For general public - - $ ../configure --prefix=/usr - -Then: (still in build directory) - - $ make - $ sudo make install - -## Credits -* Linux Build is based on master branch of [Linthesia](https://github.com/linthesia/linthesia) -* Windows Build is based on master branch of [Legacy Synthesia](https://github.com/johndpope/pianogame) +Goal of this project is to bring back Opensource Synthesia to live, and make it look and work as good (or even better) than commercial Synthesia. +## First Working Prototype +[![IMG](https://i.snag.gy/F8SCbv.jpg)](https://youtu.be/1fsii7kQDw0) +[Video](https://youtu.be/1fsii7kQDw0) +[![Video](https://i.imgur.com/t0IaVA1.png)](https://youtu.be/1fsii7kQDw0) diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index c0f7e543..00000000 --- a/autogen.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -autoreconf -ivf -./configure diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..f0e39705 --- /dev/null +++ b/build.rs @@ -0,0 +1,51 @@ +use std::fs::{self, File}; +use std::io::prelude::*; +use std::path::Path; + +pub fn generate_spirv(path: &Path, name: String, shader_type: glsl_to_spirv::ShaderType) { + let glsl = fs::read_to_string(&path).unwrap(); + let mut spirv = glsl_to_spirv::compile(&glsl, shader_type).unwrap(); + + let mut buffer = Vec::new(); + spirv.read_to_end(&mut buffer).unwrap(); + + let spirv_path = path.parent().unwrap().join(name + ".spv"); + let mut file = File::create(spirv_path).unwrap(); + file.write_all(&buffer).unwrap(); +} + +fn compile(path: &Path) { + for entry in fs::read_dir(path).unwrap() { + let entry = entry.unwrap(); + + let path = entry.path(); + + if path.is_dir() { + compile(&path); + } else { + let name = entry.file_name().into_string().unwrap(); + + if name.ends_with(".vert") { + println!( + "cargo:rerun-if-changed={}", + path.clone().into_os_string().into_string().unwrap() + ); + generate_spirv(&path, name, glsl_to_spirv::ShaderType::Vertex); + } else if name.ends_with(".frag") { + println!( + "cargo:rerun-if-changed={}", + path.clone().into_os_string().into_string().unwrap() + ); + generate_spirv(&path, name, glsl_to_spirv::ShaderType::Fragment); + } + } + } +} + +fn main() { + if cfg!(feature = "compile_shader") { + println!("cargo:warning=COMPILING_SHADERS"); + let path = Path::new("./src"); + compile(&path); + } +} diff --git a/config.h.in~ b/config.h.in~ deleted file mode 100644 index 8ee71a51..00000000 --- a/config.h.in~ +++ /dev/null @@ -1,124 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_ALGORITHM - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_EXCEPTION - -/* Define to 1 if you have the header file. */ -#undef HAVE_FUNCTIONAL - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_IOMANIP - -/* Define to 1 if you have the header file. */ -#undef HAVE_IOSTREAM - -/* Define to 1 if you have the header file. */ -#undef HAVE_LOCALE - -/* Define to 1 if you have the header file. */ -#undef HAVE_MAP - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_QUEUE - -/* Define to 1 if you have the header file. */ -#undef HAVE_SET - -/* Define to 1 if you have the header file. */ -#undef HAVE_SSTREAM - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_VECTOR - -/* Define to 1 if the system has the type `_Bool'. */ -#undef HAVE__BOOL - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#undef LT_OBJDIR - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define for Solaris 2.5.1 so the uint32_t typedef from , - , or is not used. If the typedef were allowed, the - #define below would cause a syntax error. */ -#undef _UINT32_T - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to `unsigned int' if does not define. */ -#undef size_t - -/* Define to the type of an unsigned integer type of width exactly 32 bits if - such a type exists and the standard includes do not define it. */ -#undef uint32_t diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 30af146f..00000000 --- a/configure.ac +++ /dev/null @@ -1,53 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ([2.69]) -AC_INIT([neothesia], [0.4.2], [victor.lavaud@gmail.com]) -AM_INIT_AUTOMAKE([foreign subdir-objects]) -AC_CONFIG_SRCDIR([src/main.cpp]) -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_MACRO_DIR([m4]) - -LT_PREREQ([2.2]) -LT_INIT() - -AC_ARG_WITH( - [scriptdir], - [AS_HELP_STRING([--with-scriptdir=],[load scripts from this directory, default: $(bindir)])], - [scriptdir="${with_scriptdir}"], - [scriptdir="\$(bindir)"] -) -AC_SUBST([scriptdir]) - -AC_ARG_WITH( - [graphdir], - [AS_HELP_STRING([--with-graphdir=],[load graphic resources from this directory, default: $(pkgdatadir)/graphics])], - [graphdir="${with_graphdir}"], - [graphdir="\$(pkgdatadir)/graphics"] -) -AC_SUBST([graphdir]) - -# Checks for programs. -AC_PROG_CXX -AC_PROG_INSTALL -AC_PROG_MKDIR_P - -# Checks for header files. -AC_CHECK_HEADERS([string string.h iostream algorithm locale vector sstream queue functional map iomanip set exception sys/time.h]) - -PKG_CHECK_MODULES([GTKGLEXTMM],[gtkglextmm-1.2]) -PKG_CHECK_MODULES([GTKMM],[gtkmm-2.4]) -PKG_CHECK_MODULES([GCONFMM],[gconfmm-2.6]) -PKG_CHECK_MODULES([ALSA],[alsa]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_CHECK_HEADER_STDBOOL -AC_C_INLINE -AC_TYPE_SIZE_T -AC_TYPE_UINT32_T - -# Checks for library functions. -AC_CHECK_FUNCS([gettimeofday]) - -AC_CONFIG_FILES([Makefile src/Makefile scripts/Makefile]) -AC_OUTPUT diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 802632d6..00000000 --- a/debian/changelog +++ /dev/null @@ -1,27 +0,0 @@ -linthesia (0.4-1) unstable; urgency=low - - * New upstream release. - * Non-maintainer commit. - * (Closes: #2920321). - - -- Oscar Aceña Tue, 29 Dec 2009 17:19:38 +0100 - -linthesia (0.3-2) unstable; urgency=low - - * New upstream release - * Non-maintainer commit. - * (Closes: #2920683). - - -- Oscar Aceña Sat, 26 Dec 2009 14:06:28 +0100 - -linthesia (0.3-1) unstable; urgency=low - - * New upstream release - - -- Cleto Martin Angelina Thu, 24 Dec 2009 14:38:10 +0100 - -linthesia (0.1-1) unstable; urgency=low - - * Initial release (Closes: #562487) - - -- Cleto Martin Angelina Fri, 18 Dec 2009 13:49:36 +0100 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7f8f011e..00000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debian/control b/debian/control deleted file mode 100644 index 8be1fcbe..00000000 --- a/debian/control +++ /dev/null @@ -1,16 +0,0 @@ -Source: neothesia -Section: games -Priority: extra -Maintainer: Cleto Martin Angelina -Build-Depends: debhelper (>= 7), libgtkmm-2.4-dev, libgconfmm-2.6-dev, - libgtkglextmm-x11-1.2-dev, libasound2-dev -Standards-Version: 3.8.3 -Homepage: http://sourceforge.net/projects/linthesia/ - -Package: neothesia -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: Fork of Synthesia to GNU/Linux - Synthesia is a software which teaches you to play piano using - piano-roll-style falling notes with any MIDI file, available under - Windows and Mac. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index a646222e..00000000 --- a/debian/copyright +++ /dev/null @@ -1,31 +0,0 @@ -This work was packaged for Debian by: - - Cleto Martin Angelina on Fri, 18 Dec 2009 13:49:36 +0100 - -It was downloaded http://sourceforge.net/projects/linthesia/ - -Upstream Author: - - Óscar Aceña - -Linthesia copyright: - - Copyright (C) 2009 Óscar Aceña - -Synthesia copyright: - - Copyright (C) 2007 Nicholas Piegdon - -License: - - Linthesia is a fork of Synthesia (v0.6.1a), whose author is Nicholas - Piegdon and is licensed under MIT License. - - Linthesia is distributed under GPL version 2. - -The Debian packaging is: - - Copyright (C) 2009 Cleto Martin Angelina - -and is licensed under the GPL version 3, -see `/usr/share/common-licenses/GPL-3'. diff --git a/debian/docs b/debian/docs deleted file mode 100644 index e845566c..00000000 --- a/debian/docs +++ /dev/null @@ -1 +0,0 @@ -README diff --git a/debian/linthesia.dirs b/debian/linthesia.dirs deleted file mode 100644 index 294259b4..00000000 --- a/debian/linthesia.dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/share/applications -usr/share/pixmaps diff --git a/debian/linthesia.manpages b/debian/linthesia.manpages deleted file mode 100644 index 76951b44..00000000 --- a/debian/linthesia.manpages +++ /dev/null @@ -1 +0,0 @@ -debian/linthesia.6 \ No newline at end of file diff --git a/debian/linthesia.xml b/debian/linthesia.xml deleted file mode 100644 index fe8ff5ea..00000000 --- a/debian/linthesia.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - ]> - - - - &dhtitle; - &dhpackage; - - - &dhfirstname; - &dhsurname; - Wrote this manpage for the Debian system. -
- &dhemail; -
-
-
- - 2009 - &dhusername; - - - This manual page was written for the Debian system - (and may be used by others). - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU General Public License, - Version 3 or (at your option) any later version published by - the Free Software Foundation. - On Debian systems, the complete text of the GNU General Public - License can be found in - /usr/share/common-licenses/GPL-3. - -
- - &dhucpackage; - &dhsection; - - - &dhpackage; - Fork of Synthesia to GNU/Linux. - - - - &dhpackage; - - - - DESCRIPTION - Synthesia is a software which teaches you to play piano using - piano-roll-style falling notes with any MIDI file, available under - Windows and Mac. - This manual page was written for the Debian distribution - because the original program does not have a manual page. - Instead, it has documentation in the GNU - info - 1 - format; see below. - -
- diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 780bfd20..00000000 --- a/debian/rules +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -export DH_OPTIONS - -DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl -SRC = src -VERSION = $(shell grep NeothesiaVersionString $(SRC)/Version.h | cut -f 6 -d " " | tr -d \"\;) - -%: - dh $@ - -override_dh_auto_build: - xsltproc -o debian/neothesia.6 --param man.charmap.use.subset "0" --novalid --nonet $(DB2MAN) debian/neothesia.xml - $(MAKE) GRAPHDIR=/usr/share/neothesia/graphics SCRIPTDIR=/usr/bin - -override_dh_install: - $(MAKE) install DESTDIR=debian/neothesia - cp extra/neothesia.desktop debian/neothesia/usr/share/applications - cp extra/neothesia.xpm debian/neothesia/usr/share/pixmaps - -override_dh_auto_clean: - $(RM) debian/neothesia.6 - $(MAKE) clean - -build-orig-source: - mkdir -p neothesia-$(VERSION) - tar --exclude=debian --exclude=\*~ --exclude=.svn --exclude=\*.pyc \ - --exclude=neothesia-$(VERSION) -cf - . \ - | ( cd neothesia-$(VERSION) && tar xf - ) - tar -czf ../tarballs/linthesia_$(VERSION).orig.tar.gz neothesia-$(VERSION) - $(RM) -r neothesia-$(VERSION) diff --git a/extra/neothesia.desktop b/extra/neothesia.desktop deleted file mode 100644 index 5c383d34..00000000 --- a/extra/neothesia.desktop +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Type=Application -Version=0.3 -Name=Neothesia -GenericName=Piano game -Icon=neothesia.xpm -Exec=linthesia -Categories=Game;Music;Education diff --git a/extra/neothesia.xpm b/extra/neothesia.xpm deleted file mode 100644 index 36438f98..00000000 --- a/extra/neothesia.xpm +++ /dev/null @@ -1,531 +0,0 @@ -/* XPM */ -static char * linthesia_xpm[] = { -"32 32 496 2", -" c None", -". c #3B373B", -"+ c #5B585C", -"@ c #606064", -"# c #616061", -"$ c #605D5F", -"% c #575759", -"& c #535456", -"* c #515154", -"= c #777777", -"- c #ADACAA", -"; c #9C9999", -"> c #888788", -", c #8C8C8C", -"' c #7D7D7E", -") c #5A5C5C", -"! c #585A5C", -"~ c #343434", -"{ c #5F5E5C", -"] c #D9D8D8", -"^ c #FFFFFF", -"/ c #FDFDFD", -"( c #F9F8F9", -"_ c #A09E9F", -": c #454546", -"< c #505051", -"[ c #232325", -"} c #504F52", -"| c #5A595C", -"1 c #525152", -"2 c #484548", -"3 c #38393A", -"4 c #3D4040", -"5 c #4E4D4F", -"6 c #716F72", -"7 c #7D7C7C", -"8 c #505050", -"9 c #464745", -"0 c #E1E1E0", -"a c #FAF9F9", -"b c #757374", -"c c #444546", -"d c #535356", -"e c #18171A", -"f c #131313", -"g c #858485", -"h c #F8F7F7", -"i c #FCFDFC", -"j c #C2C0C1", -"k c #3D3B3E", -"l c #202123", -"m c #4B4C4C", -"n c #38383A", -"o c #252627", -"p c #404342", -"q c #7D7D7C", -"r c #8C8788", -"s c #898787", -"t c #29292A", -"u c #121316", -"v c #0E1113", -"w c #151516", -"x c #ACA9A9", -"y c #9B9899", -"z c #393939", -"A c #444548", -"B c #2C2C31", -"C c #000000", -"D c #2C2B2B", -"E c #C9C9C8", -"F c #F3F3F4", -"G c #EAE9E9", -"H c #555456", -"I c #403F41", -"J c #312F32", -"K c #545453", -"L c #8F8C8C", -"M c #9C9799", -"N c #908D8B", -"O c #434241", -"P c #1D1D20", -"Q c #313133", -"R c #4A4C4C", -"S c #101113", -"T c #5F5F60", -"U c #F9F9F9", -"V c #D2D1D1", -"W c #4B4B4D", -"X c #343634", -"Y c #444648", -"Z c #818180", -"` c #F4F4F4", -" . c #F3F3F3", -".. c #D6D6D6", -"+. c #4C4D4F", -"@. c #37393C", -"#. c #615E5D", -"$. c #9B9796", -"%. c #969393", -"&. c #7E7B7C", -"*. c #484645", -"=. c #9A9999", -"-. c #EEEEEE", -";. c #CBC8C9", -">. c #484545", -",. c #484A4B", -"'. c #3E4043", -"). c #1E1D1E", -"!. c #BFBEBE", -"~. c #666464", -"{. c #262827", -"]. c #4B4F51", -"^. c #212124", -"/. c #373837", -"(. c #D7D7D6", -"_. c #F2F2F2", -":. c #424244", -"<. c #2E3031", -"[. c #3D3E40", -"}. c #908D8E", -"|. c #888685", -"1. c #454443", -"2. c #A5A4A4", -"3. c #E5E3E4", -"4. c #5A595B", -"5. c #3B3F40", -"6. c #545458", -"7. c #787676", -"8. c #9E9C9D", -"9. c #2B2A2B", -"0. c #434649", -"a. c #4A4D4F", -"b. c #939391", -"c. c #434344", -"d. c #3F3F41", -"e. c #202225", -"f. c #2D2E2E", -"g. c #4A4747", -"h. c #CAC9C9", -"i. c #F8F8F7", -"j. c #787878", -"k. c #353534", -"l. c #555858", -"m. c #232426", -"n. c #353635", -"o. c #DBDBDA", -"p. c #DAD7D9", -"q. c #424142", -"r. c #313233", -"s. c #5C5C5E", -"t. c #121617", -"u. c #4B4A4B", -"v. c #C5C5C4", -"w. c #8D8C8D", -"x. c #666667", -"y. c #131215", -"z. c #0D0E12", -"A. c #0F1013", -"B. c #353434", -"C. c #C9C7C7", -"D. c #FFFEFE", -"E. c #F7F3F5", -"F. c #A7A6A7", -"G. c #313033", -"H. c #4C4D50", -"I. c #4A484D", -"J. c #969696", -"K. c #6F6D6F", -"L. c #58575A", -"M. c #3E3E41", -"N. c #1E1F1E", -"O. c #ACA8A7", -"P. c #575353", -"Q. c #050408", -"R. c #252628", -"S. c #424547", -"T. c #979394", -"U. c #F5F4F4", -"V. c #F7F6F7", -"W. c #FBFCFB", -"X. c #D8D6D7", -"Y. c #424144", -"Z. c #3A3A3A", -"`. c #606160", -" + c #08090B", -".+ c #565656", -"++ c #FCFCFC", -"@+ c #A3A2A3", -"#+ c #2D2B2C", -"$+ c #464646", -"%+ c #515455", -"&+ c #161619", -"*+ c #747171", -"=+ c #A9A9A8", -"-+ c #D7D9DA", -";+ c #484647", -">+ c #535455", -",+ c #101418", -"'+ c #585758", -")+ c #F2F1F2", -"!+ c #F8F6F7", -"~+ c #FDFBFC", -"{+ c #666365", -"]+ c #2F2E2F", -"^+ c #656565", -"/+ c #313336", -"(+ c #C7C5C5", -"_+ c #444344", -":+ c #232326", -"<+ c #454849", -"[+ c #464647", -"}+ c #CAC9CA", -"|+ c #B2AFB3", -"1+ c #504C4E", -"2+ c #585855", -"3+ c #313738", -"4+ c #1E1F21", -"5+ c #C5C2C4", -"6+ c #FFFDFE", -"7+ c #F9F8F8", -"8+ c #969395", -"9+ c #28262A", -"0+ c #565658", -"a+ c #575558", -"b+ c #868484", -"c+ c #6F6E70", -"d+ c #191A1B", -"e+ c #1C1C1C", -"f+ c #0C0C0C", -"g+ c #868487", -"h+ c #D7D7D7", -"i+ c #525053", -"j+ c #525051", -"k+ c #4E5153", -"l+ c #8D8B8E", -"m+ c #F7F7F6", -"n+ c #CDCBCC", -"o+ c #343435", -"p+ c #3E3D3D", -"q+ c #68686A", -"r+ c #18191C", -"s+ c #6A6D6D", -"t+ c #A6A4A5", -"u+ c #605F63", -"v+ c #15191C", -"w+ c #5C5B5C", -"x+ c #636062", -"y+ c #4A4749", -"z+ c #626163", -"A+ c #070D0E", -"B+ c #555356", -"C+ c #F9F7F8", -"D+ c #F7F7F7", -"E+ c #FCFBFB", -"F+ c #F1F0F0", -"G+ c #595758", -"H+ c #2C2A2D", -"I+ c #6A686B", -"J+ c #2F2E32", -"K+ c #2D2E2D", -"L+ c #EAEAE9", -"M+ c #726E71", -"N+ c #5A5D5A", -"O+ c #262A2D", -"P+ c #2D2C2E", -"Q+ c #D3D0D2", -"R+ c #7E7E7E", -"S+ c #3D3B3D", -"T+ c #646566", -"U+ c #2D2F33", -"V+ c #CBCBCC", -"W+ c #FEFEFD", -"X+ c #FBFAFA", -"Y+ c #838384", -"Z+ c #222224", -"`+ c #4C4C4E", -" @ c #545553", -".@ c #B5B5B2", -"+@ c #D3D3D3", -"@@ c #D8D6D8", -"#@ c #595856", -"$@ c #505152", -"%@ c #414346", -"&@ c #050507", -"*@ c #9E9EA0", -"=@ c #605F61", -"-@ c #484B4C", -";@ c #929193", -">@ c #F7F5F6", -",@ c #FAFAFA", -"'@ c #C1C1C1", -")@ c #1D1C1E", -"!@ c #3D3D3E", -"~@ c #E6E5E4", -"{@ c #F3F3F2", -"]@ c #D5D6D6", -"^@ c #EBEAEB", -"/@ c #575957", -"(@ c #000001", -"_@ c #737174", -":@ c #CECDCD", -"<@ c #3B3A3B", -"[@ c #606363", -"}@ c #010507", -"|@ c #5A595A", -"1@ c #F9F9FA", -"2@ c #F7F6F6", -"3@ c #FBFBFA", -"4@ c #E9E9E9", -"5@ c #D5D5D5", -"6@ c #FDFCFD", -"7@ c #696869", -"8@ c #444340", -"9@ c #676769", -"0@ c #13191B", -"a@ c #434145", -"b@ c #EEEDEE", -"c@ c #525153", -"d@ c #404040", -"e@ c #6D6F6F", -"f@ c #1D2122", -"g@ c #2E2F31", -"h@ c #DEDFE0", -"i@ c #F6F5F6", -"j@ c #F6F6F6", -"k@ c #ECECEC", -"l@ c #646366", -"m@ c #F6F5F5", -"n@ c #828183", -"o@ c #3D393A", -"p@ c #2C3032", -"q@ c #1D1E1F", -"r@ c #C5C3C5", -"s@ c #706F70", -"t@ c #302F31", -"u@ c #747273", -"v@ c #424546", -"w@ c #0F1113", -"x@ c #E2E1E2", -"y@ c #FEFEFE", -"z@ c #F6F6F5", -"A@ c #FAFAF9", -"B@ c #EEEFEE", -"C@ c #323137", -"D@ c #A19FA0", -"E@ c #353234", -"F@ c #44494B", -"G@ c #969496", -"H@ c #9B979A", -"I@ c #2B292C", -"J@ c #686A69", -"K@ c #58595D", -"L@ c #141315", -"M@ c #989796", -"N@ c #F8F8F8", -"O@ c #EEEDED", -"P@ c #474C4D", -"Q@ c #101218", -"R@ c #B9B6B8", -"S@ c #C5C4C4", -"T@ c #353637", -"U@ c #5F5F63", -"V@ c #5D5D5E", -"W@ c #656467", -"X@ c #C4C3C3", -"Y@ c #2F2F30", -"Z@ c #414143", -"`@ c #646467", -" # c #636261", -".# c #EEEEEC", -"+# c #FCFCFB", -"@# c #F5F5F5", -"## c #FDFDFC", -"$# c #F2F1F1", -"%# c #7E7D7D", -"&# c #525455", -"*# c #00010A", -"=# c #939296", -"-# c #DFDFDE", -";# c #3D3A3B", -"># c #514F50", -",# c #717373", -"'# c #111315", -")# c #3D3D40", -"!# c #E8E8E8", -"~# c #4F4D4F", -"{# c #0C0E0F", -"]# c #888986", -"^# c #F9F8F7", -"/# c #F4F4F3", -"(# c #F0F0EF", -"_# c #7C7779", -":# c #666564", -"<# c #616363", -"[# c #000107", -"}# c #6C6A6D", -"|# c #FCFAFA", -"1# c #5A5959", -"2# c #434243", -"3# c #827F81", -"4# c #292E2F", -"5# c #1F1F22", -"6# c #E5E6E6", -"7# c #949392", -"8# c #E7E6E7", -"9# c #FCFCFD", -"0# c #FAFAF8", -"a# c #6C6B6D", -"b# c #595559", -"c# c #6A6C6C", -"d# c #070C10", -"e# c #434245", -"f# c #F0F0F0", -"g# c #727272", -"h# c #28282B", -"i# c #7E7A7C", -"j# c #424345", -"k# c #929293", -"l# c #F2F0F1", -"m# c #747473", -"n# c #4E4B4F", -"o# c #727277", -"p# c #1C1E22", -"q# c #272B2F", -"r# c #D3D3D4", -"s# c #919090", -"t# c #2B282B", -"u# c #565659", -"v# c #606365", -"w# c #595557", -"x# c #D9D7D8", -"y# c #EDEDED", -"z# c #898687", -"A# c #413D3F", -"B# c #7C7A7B", -"C# c #36393C", -"D# c #101318", -"E# c #AFB0B2", -"F# c #BCBBBB", -"G# c #2A292B", -"H# c #242428", -"I# c #595A5A", -"J# c #EFEFEF", -"K# c #F3F0F1", -"L# c #F5F3F4", -"M# c #EBEBEB", -"N# c #D4D4D4", -"O# c #F3F1F2", -"P# c #A6A3A2", -"Q# c #3A3A3C", -"R# c #7F7C7F", -"S# c #494C4D", -"T# c #98989B", -"U# c #E0DDDD", -"V# c #4D4B4A", -"W# c #D2D2D1", -"X# c #FEFBFB", -"Y# c #F7F8F7", -"Z# c #F2F0F0", -"`# c #E6E6E6", -" $ c #CACBCB", -".$ c #EFEDEE", -"+$ c #DCD9DA", -"@$ c #E5E4E4", -"#$ c #B3B2B2", -"$$ c #383536", -"%$ c #6C6A6A", -"&$ c #4D4D4E", -"*$ c #06070B", -"=$ c #0A0C0F", -"-$ c #C8C8C9", -";$ c #DFDDDE", -">$ c #E3E2E2", -",$ c #E5E5E5", -"'$ c #E1E1E1", -")$ c #E2E2E2", -"!$ c #DEDDDE", -"~$ c #D6D5D4", -"{$ c #CCCBCC", -"]$ c #B7B7B7", -"^$ c #BFBDBE", -"/$ c #ABA9AA", -"($ c #B3B3B3", -"_$ c #A1A09F", -":$ c #353333", -"<$ c #535053", -"[$ c #404041", -"}$ c #252727", -"|$ c #AEADAF", -"1$ c #B3B1B2", -"2$ c #ADABAB", -"3$ c #B2B2B2", -"4$ c #B2B3B3", -"5$ c #AEAEAE", -"6$ c #A4A1A2", -"7$ c #757575", -" ", -" ", -" . + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ ^ / ^ ( _ : < [ ", -" } | 1 2 3 4 5 6 7 8 9 0 ^ a b c d e f g ^ ^ h i ^ j k l ", -" & m n o p q r s t u v w x ^ ^ y z A B C D E ^ ^ F ^ G H ", -" } I J K L M N O P Q R S C T U ^ V W X Y C C Z ^ ^ ` ... ", -" +.@.#.$.%.&.*.=.-.;.>.,.'.C ).!.^ ^ ~.{.].^.C /.(.^ _... ", -" :.<.[.}.|.1.2.^ ^ ^ 3.4.5.6.C C 7.^ ^ 8.9.0.a.C C b. ... ", -" c.d.e.f.g.h.^ / i.a ^ ^ j.k.l.m.C n.o.^ p.q.r.s.t.C u.v. ", -" w.x.y.z.A.B.C.^ D.E.h ^ ^ F.G.H.I.C C J.^ ^ K.o L.M.C N. ", -" O.P.Q.R.S.C C T.^ ^ U.V.W.^ X.Y.Z.`. +C .+++^ @+#+$+%+&+ ", -" *+=+-+_ ;+>+,+C '+)+^ h !+U ^ ~+{+]+^+/+C ).(+^ 0 _+:+<+ ", -" [+}+^ ^ |+1+2+3+C 4+5+^ 6+!+7+^ ^ 8+9+0+a+C C b+^ ^ c+d+ ", -" e+f+g+^ ^ h+i+j+k+C C l+^ ^ m+7+D.^ n+o+p+q+r+C s+^ .t+ ", -" u+v+C w+( ^ )+x+y+z+A+C B+_.^ C+D+E+^ F+G+H+I+J+K+L+ ... ", -" M+N+O+C P+Q+^ ^ R+S+T+U+C [ V+^ W+h X+^ ^ Y+Z+`+ @.@ .+@ ", -" @@#@$@%@C &@*@^ ^ 2.n =@-@C C ;@^ ^ >@,@D.^ '@)@!@~@{@]@ ", -" ^ ^@B+u./@(@C _@^ ^ :@<@< [@}@C |@1@^ 2@X+3@^ ] !.^ 4@5@ ", -" ^ ^ 6@7@8@9@0@C a@^@^ b@c@d@e@f@C g@h@^ i@X+a ^ ^ j@k@+@ ", -" l@m@^ ^ n@o@6 p@C q@r@^ ^ s@t@u@v@C w@x@y@z@A@++h D+B@.. ", -" e+C@] ^ ^ D@E@K.F@C C G@^ ^ H@I@J@K@L@M@^ W+m+N@/ ,@O@.. ", -" P@f+Q@R@^ ^ S@T@U@V@C C W@^ ^ X@Y@Z@`@ #.#^ +#2@@###$#5@ ", -" %#&#C *#=#^ ^ -#;#>#,#'#C )#b@^ !#~#{#]#W+++3@E+^#/#(#.. ", -" _#:#<#[#C }#^ ^ |#1#2#3#4#C 5#6#^ ^ 7#8#9###a a X+N@4@+@ ", -" 0#a#b#c#d#C e#f#^ ^ g#h#i#j#C k#^ ^ ^ ^ l#X+++D+N@N@-.+@ ", -" ^ ^ m#n#o#p#C q#r#^ ^ s#t#u#v#w#x#^ 3@+#a $#!+++D+j@y#.. ", -" ^ ^ ^ z#A#B#C#C D#E#^ ^ F#G#H#I#J#^ a a ,@U K#L#+#N@M#N# ", -" O#^ y@^ P#Q#R#S#C C T#^ ^ U#V#W#X#++++7+N@Y#U K#Z#N@`# $ ", -" .$+$@$`#`##$$$%$&$*$=$-$`#`#`#`#;$] >$,$'$'$'$)$!$~${$]$ ", -" , ^$/$($($($_$:$<$[$}$1#|$($($($($1$2$#$($3$3$3$4$5$6$7$ ", -" ", -" "}; diff --git a/graphics/InterfaceButtons.tga b/graphics/InterfaceButtons.tga deleted file mode 100644 index ffcd7f77..00000000 Binary files a/graphics/InterfaceButtons.tga and /dev/null differ diff --git a/graphics/InterfaceButtons/.directory b/graphics/InterfaceButtons/.directory deleted file mode 100644 index 3908352a..00000000 --- a/graphics/InterfaceButtons/.directory +++ /dev/null @@ -1,4 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2015,5,2,0,11,40 -Version=3 diff --git a/graphics/InterfaceButtons/InterfaceButtons.xcf.rcm b/graphics/InterfaceButtons/InterfaceButtons.xcf.rcm deleted file mode 100644 index 501b42fd..00000000 --- a/graphics/InterfaceButtons/InterfaceButtons.xcf.rcm +++ /dev/null @@ -1,194 +0,0 @@ -"ATGrcm" -972 -252 -27 -7 -"blue-left-hover.xcf" -"blue-right-hover.xcf" -"blue-color-hover.xcf" -"blue-preview-on-hover.xcf" -"blue-preview-off-hover.xcf" -"blue-computer-hover.xcf" -"blue-human-hover.xcf" -"blue-retry-on-hover.xcf" -"blue-retry-off-hover.xcf" -"blue-left.xcf" -"blue-right.xcf" -"blue-color.xcf" -"blue-preview-on.xcf" -"blue-preview-off.xcf" -"blue-computer.xcf" -"blue-human.xcf" -"blue-retry-on.xcf" -"blue-retry-off.xcf" -"blue-left.xcf" -"blue-right.xcf" -"blue-color.xcf" -"blue-preview-on.xcf" -"blue-preview-off.xcf" -"blue-computer.xcf" -"blue-human.xcf" -"blue-retry-on.xcf" -"blue-retry-off.xcf" -"green-left-hover.xcf" -"green-right-hover.xcf" -"green-color-hover.xcf" -"green-preview-on-hover.xcf" -"green-preview-off-hover.xcf" -"green-computer-hover.xcf" -"green-human-hover.xcf" -"green-retry-on-hover.xcf" -"green-retry-off-hover.xcf" -"green-left.xcf" -"green-right.xcf" -"green-color.xcf" -"green-preview-on.xcf" -"green-preview-off.xcf" -"green-computer.xcf" -"green-human.xcf" -"green-retry-on.xcf" -"green-retry-off.xcf" -"green-left.xcf" -"green-right.xcf" -"green-color.xcf" -"green-preview-on.xcf" -"green-preview-off.xcf" -"green-computer.xcf" -"green-human.xcf" -"green-retry-on.xcf" -"green-retry-off.xcf" -"orange-left-hover.xcf" -"orange-right-hover.xcf" -"orange-color-hover.xcf" -"orange-preview-on-hover.xcf" -"orange-preview-off-hover.xcf" -"orange-computer-hover.xcf" -"orange-human-hover.xcf" -"orange-retry-on-hover.xcf" -"orange-retry-off-hover.xcf" -"orange-left.xcf" -"orange-right.xcf" -"orange-color.xcf" -"orange-preview-on.xcf" -"orange-preview-off.xcf" -"orange-computer.xcf" -"orange-human.xcf" -"orange-retry-on.xcf" -"orange-retry-off.xcf" -"orange-left.xcf" -"orange-right.xcf" -"orange-color.xcf" -"orange-preview-on.xcf" -"orange-preview-off.xcf" -"orange-computer.xcf" -"orange-human.xcf" -"orange-retry-on.xcf" -"orange-retry-off.xcf" -"yellow-left-hover.xcf" -"yellow-right-hover.xcf" -"yellow-color-hover.xcf" -"yellow-preview-on-hover.xcf" -"yellow-preview-off-hover.xcf" -"yellow-computer-hover.xcf" -"yellow-human-hover.xcf" -"yellow-retry-on-hover.xcf" -"yellow-retry-off-hover.xcf" -"yellow-left.xcf" -"yellow-right.xcf" -"yellow-color.xcf" -"yellow-preview-on.xcf" -"yellow-preview-off.xcf" -"yellow-computer.xcf" -"yellow-human.xcf" -"yellow-retry-on.xcf" -"yellow-retry-off.xcf" -"yellow-left.xcf" -"yellow-right.xcf" -"yellow-color.xcf" -"yellow-preview-on.xcf" -"yellow-preview-off.xcf" -"yellow-computer.xcf" -"yellow-human.xcf" -"yellow-retry-on.xcf" -"yellow-retry-off.xcf" -"violet-left-hover.xcf" -"violet-right-hover.xcf" -"violet-color-hover.xcf" -"violet-preview-on-hover.xcf" -"violet-preview-off-hover.xcf" -"violet-computer-hover.xcf" -"violet-human-hover.xcf" -"violet-retry-on-hover.xcf" -"violet-retry-off-hover.xcf" -"violet-left.xcf" -"violet-right.xcf" -"violet-color.xcf" -"violet-preview-on.xcf" -"violet-preview-off.xcf" -"violet-computer.xcf" -"violet-human.xcf" -"violet-retry-on.xcf" -"violet-retry-off.xcf" -"violet-left.xcf" -"violet-right.xcf" -"violet-color.xcf" -"violet-preview-on.xcf" -"violet-preview-off.xcf" -"violet-computer.xcf" -"violet-human.xcf" -"violet-retry-on.xcf" -"violet-retry-off.xcf" -"red-left-hover.xcf" -"red-right-hover.xcf" -"red-color-hover.xcf" -"red-preview-on-hover.xcf" -"red-preview-off-hover.xcf" -"red-computer-hover.xcf" -"red-human-hover.xcf" -"red-retry-on-hover.xcf" -"red-retry-off-hover.xcf" -"red-left.xcf" -"red-right.xcf" -"red-color.xcf" -"red-preview-on.xcf" -"red-preview-off.xcf" -"red-computer.xcf" -"red-human.xcf" -"red-retry-on.xcf" -"red-retry-off.xcf" -"red-left.xcf" -"red-right.xcf" -"red-color.xcf" -"red-preview-on.xcf" -"red-preview-off.xcf" -"red-computer.xcf" -"red-human.xcf" -"red-retry-on.xcf" -"red-retry-off.xcf" -"gray-left-hover.xcf" -"gray-right-hover.xcf" -"gray-color-hover.xcf" -"gray-preview-on-hover.xcf" -"gray-preview-off-hover.xcf" -"gray-computer-hover.xcf" -"gray-human-hover.xcf" -"gray-retry-on-hover.xcf" -"gray-retry-off-hover.xcf" -"gray-left.xcf" -"gray-right.xcf" -"gray-color.xcf" -"gray-preview-on.xcf" -"gray-preview-off.xcf" -"gray-computer.xcf" -"gray-human.xcf" -"gray-retry-on.xcf" -"gray-retry-off.xcf" -"gray-left.xcf" -"gray-right.xcf" -"gray-color.xcf" -"gray-preview-on.xcf" -"gray-preview-off.xcf" -"gray-computer.xcf" -"gray-human.xcf" -"gray-retry-on.xcf" -"gray-retry-off.xcf" diff --git a/graphics/InterfaceButtons/OpenSansEmoji.ttf b/graphics/InterfaceButtons/OpenSansEmoji.ttf deleted file mode 100644 index 57d86a62..00000000 Binary files a/graphics/InterfaceButtons/OpenSansEmoji.ttf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-color-hover.xcf b/graphics/InterfaceButtons/blue-color-hover.xcf deleted file mode 100644 index df4c0616..00000000 Binary files a/graphics/InterfaceButtons/blue-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-color.xcf b/graphics/InterfaceButtons/blue-color.xcf deleted file mode 100644 index c6201171..00000000 Binary files a/graphics/InterfaceButtons/blue-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-computer-hover.xcf b/graphics/InterfaceButtons/blue-computer-hover.xcf deleted file mode 100644 index fe01a7a3..00000000 Binary files a/graphics/InterfaceButtons/blue-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-computer.xcf b/graphics/InterfaceButtons/blue-computer.xcf deleted file mode 100644 index 81512b06..00000000 Binary files a/graphics/InterfaceButtons/blue-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-human-hover.xcf b/graphics/InterfaceButtons/blue-human-hover.xcf deleted file mode 100644 index 6391eb00..00000000 Binary files a/graphics/InterfaceButtons/blue-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-human.xcf b/graphics/InterfaceButtons/blue-human.xcf deleted file mode 100644 index 41c1bc31..00000000 Binary files a/graphics/InterfaceButtons/blue-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-left-hover.xcf b/graphics/InterfaceButtons/blue-left-hover.xcf deleted file mode 100644 index 39e7b22f..00000000 Binary files a/graphics/InterfaceButtons/blue-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-left.xcf b/graphics/InterfaceButtons/blue-left.xcf deleted file mode 100644 index c2d4f864..00000000 Binary files a/graphics/InterfaceButtons/blue-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-preview-off-hover.xcf b/graphics/InterfaceButtons/blue-preview-off-hover.xcf deleted file mode 100644 index c5643bd1..00000000 Binary files a/graphics/InterfaceButtons/blue-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-preview-off.xcf b/graphics/InterfaceButtons/blue-preview-off.xcf deleted file mode 100644 index 6b1c476f..00000000 Binary files a/graphics/InterfaceButtons/blue-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-preview-on-hover.xcf b/graphics/InterfaceButtons/blue-preview-on-hover.xcf deleted file mode 100644 index 1fadc4a4..00000000 Binary files a/graphics/InterfaceButtons/blue-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-preview-on.xcf b/graphics/InterfaceButtons/blue-preview-on.xcf deleted file mode 100644 index b5b3739d..00000000 Binary files a/graphics/InterfaceButtons/blue-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-retry-off-hover.xcf b/graphics/InterfaceButtons/blue-retry-off-hover.xcf deleted file mode 100644 index 757532ce..00000000 Binary files a/graphics/InterfaceButtons/blue-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-retry-off.xcf b/graphics/InterfaceButtons/blue-retry-off.xcf deleted file mode 100644 index a6b8ba66..00000000 Binary files a/graphics/InterfaceButtons/blue-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-retry-on-hover.xcf b/graphics/InterfaceButtons/blue-retry-on-hover.xcf deleted file mode 100644 index 86f601ca..00000000 Binary files a/graphics/InterfaceButtons/blue-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-retry-on.xcf b/graphics/InterfaceButtons/blue-retry-on.xcf deleted file mode 100644 index e1877b7c..00000000 Binary files a/graphics/InterfaceButtons/blue-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-right-hover.xcf b/graphics/InterfaceButtons/blue-right-hover.xcf deleted file mode 100644 index 2fcd2722..00000000 Binary files a/graphics/InterfaceButtons/blue-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/blue-right.xcf b/graphics/InterfaceButtons/blue-right.xcf deleted file mode 100644 index a645afae..00000000 Binary files a/graphics/InterfaceButtons/blue-right.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-color-hover.xcf b/graphics/InterfaceButtons/gray-color-hover.xcf deleted file mode 100644 index f9755e97..00000000 Binary files a/graphics/InterfaceButtons/gray-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-color.xcf b/graphics/InterfaceButtons/gray-color.xcf deleted file mode 100644 index 4e9cc501..00000000 Binary files a/graphics/InterfaceButtons/gray-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-computer-hover.xcf b/graphics/InterfaceButtons/gray-computer-hover.xcf deleted file mode 100644 index ef878031..00000000 Binary files a/graphics/InterfaceButtons/gray-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-computer.xcf b/graphics/InterfaceButtons/gray-computer.xcf deleted file mode 100644 index 2cc0575b..00000000 Binary files a/graphics/InterfaceButtons/gray-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-human-hover.xcf b/graphics/InterfaceButtons/gray-human-hover.xcf deleted file mode 100644 index f559f9a5..00000000 Binary files a/graphics/InterfaceButtons/gray-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-human.xcf b/graphics/InterfaceButtons/gray-human.xcf deleted file mode 100644 index 1e286d43..00000000 Binary files a/graphics/InterfaceButtons/gray-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-left-hover.xcf b/graphics/InterfaceButtons/gray-left-hover.xcf deleted file mode 100644 index edd55818..00000000 Binary files a/graphics/InterfaceButtons/gray-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-left.xcf b/graphics/InterfaceButtons/gray-left.xcf deleted file mode 100644 index 28827346..00000000 Binary files a/graphics/InterfaceButtons/gray-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-preview-off-hover.xcf b/graphics/InterfaceButtons/gray-preview-off-hover.xcf deleted file mode 100644 index 16c1e123..00000000 Binary files a/graphics/InterfaceButtons/gray-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-preview-off.xcf b/graphics/InterfaceButtons/gray-preview-off.xcf deleted file mode 100644 index 0923430a..00000000 Binary files a/graphics/InterfaceButtons/gray-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-preview-on-hover.xcf b/graphics/InterfaceButtons/gray-preview-on-hover.xcf deleted file mode 100644 index db3f13b7..00000000 Binary files a/graphics/InterfaceButtons/gray-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-preview-on.xcf b/graphics/InterfaceButtons/gray-preview-on.xcf deleted file mode 100644 index 1861e240..00000000 Binary files a/graphics/InterfaceButtons/gray-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-retry-off-hover.xcf b/graphics/InterfaceButtons/gray-retry-off-hover.xcf deleted file mode 100644 index 3ecfb9e1..00000000 Binary files a/graphics/InterfaceButtons/gray-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-retry-off.xcf b/graphics/InterfaceButtons/gray-retry-off.xcf deleted file mode 100644 index 7607e14e..00000000 Binary files a/graphics/InterfaceButtons/gray-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-retry-on-hover.xcf b/graphics/InterfaceButtons/gray-retry-on-hover.xcf deleted file mode 100644 index 2a83296b..00000000 Binary files a/graphics/InterfaceButtons/gray-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-retry-on.xcf b/graphics/InterfaceButtons/gray-retry-on.xcf deleted file mode 100644 index b27483b8..00000000 Binary files a/graphics/InterfaceButtons/gray-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-right-hover.xcf b/graphics/InterfaceButtons/gray-right-hover.xcf deleted file mode 100644 index 8805ae7f..00000000 Binary files a/graphics/InterfaceButtons/gray-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/gray-right.xcf b/graphics/InterfaceButtons/gray-right.xcf deleted file mode 100644 index a02099cc..00000000 Binary files a/graphics/InterfaceButtons/gray-right.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-color-hover.xcf b/graphics/InterfaceButtons/green-color-hover.xcf deleted file mode 100644 index e005b780..00000000 Binary files a/graphics/InterfaceButtons/green-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-color.xcf b/graphics/InterfaceButtons/green-color.xcf deleted file mode 100644 index 7809a481..00000000 Binary files a/graphics/InterfaceButtons/green-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-computer-hover.xcf b/graphics/InterfaceButtons/green-computer-hover.xcf deleted file mode 100644 index 0c3483ad..00000000 Binary files a/graphics/InterfaceButtons/green-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-computer.xcf b/graphics/InterfaceButtons/green-computer.xcf deleted file mode 100644 index b83d509e..00000000 Binary files a/graphics/InterfaceButtons/green-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-human-hover.xcf b/graphics/InterfaceButtons/green-human-hover.xcf deleted file mode 100644 index cf610a84..00000000 Binary files a/graphics/InterfaceButtons/green-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-human.xcf b/graphics/InterfaceButtons/green-human.xcf deleted file mode 100644 index 41b19abf..00000000 Binary files a/graphics/InterfaceButtons/green-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-left-hover.xcf b/graphics/InterfaceButtons/green-left-hover.xcf deleted file mode 100644 index 920bf79b..00000000 Binary files a/graphics/InterfaceButtons/green-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-left.xcf b/graphics/InterfaceButtons/green-left.xcf deleted file mode 100644 index d02ccc00..00000000 Binary files a/graphics/InterfaceButtons/green-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-preview-off-hover.xcf b/graphics/InterfaceButtons/green-preview-off-hover.xcf deleted file mode 100644 index 24ed0e71..00000000 Binary files a/graphics/InterfaceButtons/green-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-preview-off.xcf b/graphics/InterfaceButtons/green-preview-off.xcf deleted file mode 100644 index c1bcfcd5..00000000 Binary files a/graphics/InterfaceButtons/green-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-preview-on-hover.xcf b/graphics/InterfaceButtons/green-preview-on-hover.xcf deleted file mode 100644 index 712bcc7d..00000000 Binary files a/graphics/InterfaceButtons/green-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-preview-on.xcf b/graphics/InterfaceButtons/green-preview-on.xcf deleted file mode 100644 index c08fc078..00000000 Binary files a/graphics/InterfaceButtons/green-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-retry-off-hover.xcf b/graphics/InterfaceButtons/green-retry-off-hover.xcf deleted file mode 100644 index 6048f690..00000000 Binary files a/graphics/InterfaceButtons/green-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-retry-off.xcf b/graphics/InterfaceButtons/green-retry-off.xcf deleted file mode 100644 index 30e14d99..00000000 Binary files a/graphics/InterfaceButtons/green-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-retry-on-hover.xcf b/graphics/InterfaceButtons/green-retry-on-hover.xcf deleted file mode 100644 index ef49da77..00000000 Binary files a/graphics/InterfaceButtons/green-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-retry-on.xcf b/graphics/InterfaceButtons/green-retry-on.xcf deleted file mode 100644 index fae1581f..00000000 Binary files a/graphics/InterfaceButtons/green-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-right-hover.xcf b/graphics/InterfaceButtons/green-right-hover.xcf deleted file mode 100644 index 492edac4..00000000 Binary files a/graphics/InterfaceButtons/green-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/green-right.xcf b/graphics/InterfaceButtons/green-right.xcf deleted file mode 100644 index 8d5c00fd..00000000 Binary files a/graphics/InterfaceButtons/green-right.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-color-hover.xcf b/graphics/InterfaceButtons/orange-color-hover.xcf deleted file mode 100644 index 2cde6ead..00000000 Binary files a/graphics/InterfaceButtons/orange-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-color.xcf b/graphics/InterfaceButtons/orange-color.xcf deleted file mode 100644 index d7dc4ea6..00000000 Binary files a/graphics/InterfaceButtons/orange-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-computer-hover.xcf b/graphics/InterfaceButtons/orange-computer-hover.xcf deleted file mode 100644 index 35d82642..00000000 Binary files a/graphics/InterfaceButtons/orange-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-computer.xcf b/graphics/InterfaceButtons/orange-computer.xcf deleted file mode 100644 index 82934fb7..00000000 Binary files a/graphics/InterfaceButtons/orange-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-human-hover.xcf b/graphics/InterfaceButtons/orange-human-hover.xcf deleted file mode 100644 index f9be23d8..00000000 Binary files a/graphics/InterfaceButtons/orange-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-human.xcf b/graphics/InterfaceButtons/orange-human.xcf deleted file mode 100644 index f9ddc991..00000000 Binary files a/graphics/InterfaceButtons/orange-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-left-hover.xcf b/graphics/InterfaceButtons/orange-left-hover.xcf deleted file mode 100644 index 3e2786da..00000000 Binary files a/graphics/InterfaceButtons/orange-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-left.xcf b/graphics/InterfaceButtons/orange-left.xcf deleted file mode 100644 index 1f7d78fd..00000000 Binary files a/graphics/InterfaceButtons/orange-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-preview-off-hover.xcf b/graphics/InterfaceButtons/orange-preview-off-hover.xcf deleted file mode 100644 index f2f5cf25..00000000 Binary files a/graphics/InterfaceButtons/orange-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-preview-off.xcf b/graphics/InterfaceButtons/orange-preview-off.xcf deleted file mode 100644 index 65803b99..00000000 Binary files a/graphics/InterfaceButtons/orange-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-preview-on-hover.xcf b/graphics/InterfaceButtons/orange-preview-on-hover.xcf deleted file mode 100644 index fd454823..00000000 Binary files a/graphics/InterfaceButtons/orange-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-preview-on.xcf b/graphics/InterfaceButtons/orange-preview-on.xcf deleted file mode 100644 index 94f2aa59..00000000 Binary files a/graphics/InterfaceButtons/orange-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-retry-off-hover.xcf b/graphics/InterfaceButtons/orange-retry-off-hover.xcf deleted file mode 100644 index f4a26f00..00000000 Binary files a/graphics/InterfaceButtons/orange-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-retry-off.xcf b/graphics/InterfaceButtons/orange-retry-off.xcf deleted file mode 100644 index ef92293c..00000000 Binary files a/graphics/InterfaceButtons/orange-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-retry-on-hover.xcf b/graphics/InterfaceButtons/orange-retry-on-hover.xcf deleted file mode 100644 index 2659a484..00000000 Binary files a/graphics/InterfaceButtons/orange-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-retry-on.xcf b/graphics/InterfaceButtons/orange-retry-on.xcf deleted file mode 100644 index e325f73c..00000000 Binary files a/graphics/InterfaceButtons/orange-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-right-hover.xcf b/graphics/InterfaceButtons/orange-right-hover.xcf deleted file mode 100644 index 8a88e0a6..00000000 Binary files a/graphics/InterfaceButtons/orange-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/orange-right.xcf b/graphics/InterfaceButtons/orange-right.xcf deleted file mode 100644 index 41aefeab..00000000 Binary files a/graphics/InterfaceButtons/orange-right.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-color-hover.xcf b/graphics/InterfaceButtons/red-color-hover.xcf deleted file mode 100644 index 929b101e..00000000 Binary files a/graphics/InterfaceButtons/red-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-color.xcf b/graphics/InterfaceButtons/red-color.xcf deleted file mode 100644 index 5766cbbd..00000000 Binary files a/graphics/InterfaceButtons/red-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-computer-hover.xcf b/graphics/InterfaceButtons/red-computer-hover.xcf deleted file mode 100644 index 2ba11278..00000000 Binary files a/graphics/InterfaceButtons/red-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-computer.xcf b/graphics/InterfaceButtons/red-computer.xcf deleted file mode 100644 index 6c6dd655..00000000 Binary files a/graphics/InterfaceButtons/red-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-human-hover.xcf b/graphics/InterfaceButtons/red-human-hover.xcf deleted file mode 100644 index 24c793e4..00000000 Binary files a/graphics/InterfaceButtons/red-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-human.xcf b/graphics/InterfaceButtons/red-human.xcf deleted file mode 100644 index d459015b..00000000 Binary files a/graphics/InterfaceButtons/red-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-left-hover.xcf b/graphics/InterfaceButtons/red-left-hover.xcf deleted file mode 100644 index 7d216725..00000000 Binary files a/graphics/InterfaceButtons/red-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-left.xcf b/graphics/InterfaceButtons/red-left.xcf deleted file mode 100644 index 1add5746..00000000 Binary files a/graphics/InterfaceButtons/red-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-preview-off-hover.xcf b/graphics/InterfaceButtons/red-preview-off-hover.xcf deleted file mode 100644 index e1d6f655..00000000 Binary files a/graphics/InterfaceButtons/red-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-preview-off.xcf b/graphics/InterfaceButtons/red-preview-off.xcf deleted file mode 100644 index a7b3d8cb..00000000 Binary files a/graphics/InterfaceButtons/red-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-preview-on-hover.xcf b/graphics/InterfaceButtons/red-preview-on-hover.xcf deleted file mode 100644 index 6f063cfc..00000000 Binary files a/graphics/InterfaceButtons/red-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-preview-on.xcf b/graphics/InterfaceButtons/red-preview-on.xcf deleted file mode 100644 index 555280f1..00000000 Binary files a/graphics/InterfaceButtons/red-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-retry-off-hover.xcf b/graphics/InterfaceButtons/red-retry-off-hover.xcf deleted file mode 100644 index fba433ce..00000000 Binary files a/graphics/InterfaceButtons/red-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-retry-off.xcf b/graphics/InterfaceButtons/red-retry-off.xcf deleted file mode 100644 index e64e53d4..00000000 Binary files a/graphics/InterfaceButtons/red-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-retry-on-hover.xcf b/graphics/InterfaceButtons/red-retry-on-hover.xcf deleted file mode 100644 index e7d59d77..00000000 Binary files a/graphics/InterfaceButtons/red-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-retry-on.xcf b/graphics/InterfaceButtons/red-retry-on.xcf deleted file mode 100644 index bbe0445f..00000000 Binary files a/graphics/InterfaceButtons/red-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-right-hover.xcf b/graphics/InterfaceButtons/red-right-hover.xcf deleted file mode 100644 index 92e2c92d..00000000 Binary files a/graphics/InterfaceButtons/red-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/red-right.xcf b/graphics/InterfaceButtons/red-right.xcf deleted file mode 100644 index ffdc1e17..00000000 Binary files a/graphics/InterfaceButtons/red-right.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-color-hover.xcf b/graphics/InterfaceButtons/violet-color-hover.xcf deleted file mode 100644 index e6ee8e92..00000000 Binary files a/graphics/InterfaceButtons/violet-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-color.xcf b/graphics/InterfaceButtons/violet-color.xcf deleted file mode 100644 index 0c838b3b..00000000 Binary files a/graphics/InterfaceButtons/violet-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-computer-hover.xcf b/graphics/InterfaceButtons/violet-computer-hover.xcf deleted file mode 100644 index 419eaff8..00000000 Binary files a/graphics/InterfaceButtons/violet-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-computer.xcf b/graphics/InterfaceButtons/violet-computer.xcf deleted file mode 100644 index 641e99bf..00000000 Binary files a/graphics/InterfaceButtons/violet-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-human-hover.xcf b/graphics/InterfaceButtons/violet-human-hover.xcf deleted file mode 100644 index ea41c936..00000000 Binary files a/graphics/InterfaceButtons/violet-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-human.xcf b/graphics/InterfaceButtons/violet-human.xcf deleted file mode 100644 index 890af0ba..00000000 Binary files a/graphics/InterfaceButtons/violet-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-left-hover.xcf b/graphics/InterfaceButtons/violet-left-hover.xcf deleted file mode 100644 index 3760c29c..00000000 Binary files a/graphics/InterfaceButtons/violet-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-left.xcf b/graphics/InterfaceButtons/violet-left.xcf deleted file mode 100644 index d359f8da..00000000 Binary files a/graphics/InterfaceButtons/violet-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-preview-off-hover.xcf b/graphics/InterfaceButtons/violet-preview-off-hover.xcf deleted file mode 100644 index b81858e9..00000000 Binary files a/graphics/InterfaceButtons/violet-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-preview-off.xcf b/graphics/InterfaceButtons/violet-preview-off.xcf deleted file mode 100644 index 621dcfec..00000000 Binary files a/graphics/InterfaceButtons/violet-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-preview-on-hover.xcf b/graphics/InterfaceButtons/violet-preview-on-hover.xcf deleted file mode 100644 index 31f65df4..00000000 Binary files a/graphics/InterfaceButtons/violet-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-preview-on.xcf b/graphics/InterfaceButtons/violet-preview-on.xcf deleted file mode 100644 index 0ee7d93f..00000000 Binary files a/graphics/InterfaceButtons/violet-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-retry-off-hover.xcf b/graphics/InterfaceButtons/violet-retry-off-hover.xcf deleted file mode 100644 index 5da58738..00000000 Binary files a/graphics/InterfaceButtons/violet-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-retry-off.xcf b/graphics/InterfaceButtons/violet-retry-off.xcf deleted file mode 100644 index d7fe6598..00000000 Binary files a/graphics/InterfaceButtons/violet-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-retry-on-hover.xcf b/graphics/InterfaceButtons/violet-retry-on-hover.xcf deleted file mode 100644 index dc28ba54..00000000 Binary files a/graphics/InterfaceButtons/violet-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-retry-on.xcf b/graphics/InterfaceButtons/violet-retry-on.xcf deleted file mode 100644 index 52e4d784..00000000 Binary files a/graphics/InterfaceButtons/violet-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-right-hover.xcf b/graphics/InterfaceButtons/violet-right-hover.xcf deleted file mode 100644 index 46fabb0a..00000000 Binary files a/graphics/InterfaceButtons/violet-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/violet-right.xcf b/graphics/InterfaceButtons/violet-right.xcf deleted file mode 100644 index a2b1552a..00000000 Binary files a/graphics/InterfaceButtons/violet-right.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-color-hover.xcf b/graphics/InterfaceButtons/yellow-color-hover.xcf deleted file mode 100644 index 4107ec84..00000000 Binary files a/graphics/InterfaceButtons/yellow-color-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-color.xcf b/graphics/InterfaceButtons/yellow-color.xcf deleted file mode 100644 index ba0ec9d9..00000000 Binary files a/graphics/InterfaceButtons/yellow-color.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-computer-hover.xcf b/graphics/InterfaceButtons/yellow-computer-hover.xcf deleted file mode 100644 index db69afc8..00000000 Binary files a/graphics/InterfaceButtons/yellow-computer-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-computer.xcf b/graphics/InterfaceButtons/yellow-computer.xcf deleted file mode 100644 index 2a57d1c0..00000000 Binary files a/graphics/InterfaceButtons/yellow-computer.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-human-hover.xcf b/graphics/InterfaceButtons/yellow-human-hover.xcf deleted file mode 100644 index 773d98b8..00000000 Binary files a/graphics/InterfaceButtons/yellow-human-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-human.xcf b/graphics/InterfaceButtons/yellow-human.xcf deleted file mode 100644 index 6f4fa0e0..00000000 Binary files a/graphics/InterfaceButtons/yellow-human.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-left-hover.xcf b/graphics/InterfaceButtons/yellow-left-hover.xcf deleted file mode 100644 index 2b1b8784..00000000 Binary files a/graphics/InterfaceButtons/yellow-left-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-left.xcf b/graphics/InterfaceButtons/yellow-left.xcf deleted file mode 100644 index 2aefffec..00000000 Binary files a/graphics/InterfaceButtons/yellow-left.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-preview-off-hover.xcf b/graphics/InterfaceButtons/yellow-preview-off-hover.xcf deleted file mode 100644 index 410fe3a1..00000000 Binary files a/graphics/InterfaceButtons/yellow-preview-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-preview-off.xcf b/graphics/InterfaceButtons/yellow-preview-off.xcf deleted file mode 100644 index c46f640e..00000000 Binary files a/graphics/InterfaceButtons/yellow-preview-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-preview-on-hover.xcf b/graphics/InterfaceButtons/yellow-preview-on-hover.xcf deleted file mode 100644 index 958140eb..00000000 Binary files a/graphics/InterfaceButtons/yellow-preview-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-preview-on.xcf b/graphics/InterfaceButtons/yellow-preview-on.xcf deleted file mode 100644 index 68d9bc69..00000000 Binary files a/graphics/InterfaceButtons/yellow-preview-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-retry-off-hover.xcf b/graphics/InterfaceButtons/yellow-retry-off-hover.xcf deleted file mode 100644 index 26b85b99..00000000 Binary files a/graphics/InterfaceButtons/yellow-retry-off-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-retry-off.xcf b/graphics/InterfaceButtons/yellow-retry-off.xcf deleted file mode 100644 index 5fcd31d3..00000000 Binary files a/graphics/InterfaceButtons/yellow-retry-off.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-retry-on-hover.xcf b/graphics/InterfaceButtons/yellow-retry-on-hover.xcf deleted file mode 100644 index 0a551399..00000000 Binary files a/graphics/InterfaceButtons/yellow-retry-on-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-retry-on.xcf b/graphics/InterfaceButtons/yellow-retry-on.xcf deleted file mode 100644 index d9194376..00000000 Binary files a/graphics/InterfaceButtons/yellow-retry-on.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-right-hover.xcf b/graphics/InterfaceButtons/yellow-right-hover.xcf deleted file mode 100644 index f9a7a6b2..00000000 Binary files a/graphics/InterfaceButtons/yellow-right-hover.xcf and /dev/null differ diff --git a/graphics/InterfaceButtons/yellow-right.xcf b/graphics/InterfaceButtons/yellow-right.xcf deleted file mode 100644 index db72c2a8..00000000 Binary files a/graphics/InterfaceButtons/yellow-right.xcf and /dev/null differ diff --git a/graphics/app_icon.ico b/graphics/app_icon.ico deleted file mode 100644 index 2d6bd501..00000000 Binary files a/graphics/app_icon.ico and /dev/null differ diff --git a/graphics/neothesia.xpm b/graphics/neothesia.xpm deleted file mode 100644 index 36438f98..00000000 --- a/graphics/neothesia.xpm +++ /dev/null @@ -1,531 +0,0 @@ -/* XPM */ -static char * linthesia_xpm[] = { -"32 32 496 2", -" c None", -". c #3B373B", -"+ c #5B585C", -"@ c #606064", -"# c #616061", -"$ c #605D5F", -"% c #575759", -"& c #535456", -"* c #515154", -"= c #777777", -"- c #ADACAA", -"; c #9C9999", -"> c #888788", -", c #8C8C8C", -"' c #7D7D7E", -") c #5A5C5C", -"! c #585A5C", -"~ c #343434", -"{ c #5F5E5C", -"] c #D9D8D8", -"^ c #FFFFFF", -"/ c #FDFDFD", -"( c #F9F8F9", -"_ c #A09E9F", -": c #454546", -"< c #505051", -"[ c #232325", -"} c #504F52", -"| c #5A595C", -"1 c #525152", -"2 c #484548", -"3 c #38393A", -"4 c #3D4040", -"5 c #4E4D4F", -"6 c #716F72", -"7 c #7D7C7C", -"8 c #505050", -"9 c #464745", -"0 c #E1E1E0", -"a c #FAF9F9", -"b c #757374", -"c c #444546", -"d c #535356", -"e c #18171A", -"f c #131313", -"g c #858485", -"h c #F8F7F7", -"i c #FCFDFC", -"j c #C2C0C1", -"k c #3D3B3E", -"l c #202123", -"m c #4B4C4C", -"n c #38383A", -"o c #252627", -"p c #404342", -"q c #7D7D7C", -"r c #8C8788", -"s c #898787", -"t c #29292A", -"u c #121316", -"v c #0E1113", -"w c #151516", -"x c #ACA9A9", -"y c #9B9899", -"z c #393939", -"A c #444548", -"B c #2C2C31", -"C c #000000", -"D c #2C2B2B", -"E c #C9C9C8", -"F c #F3F3F4", -"G c #EAE9E9", -"H c #555456", -"I c #403F41", -"J c #312F32", -"K c #545453", -"L c #8F8C8C", -"M c #9C9799", -"N c #908D8B", -"O c #434241", -"P c #1D1D20", -"Q c #313133", -"R c #4A4C4C", -"S c #101113", -"T c #5F5F60", -"U c #F9F9F9", -"V c #D2D1D1", -"W c #4B4B4D", -"X c #343634", -"Y c #444648", -"Z c #818180", -"` c #F4F4F4", -" . c #F3F3F3", -".. c #D6D6D6", -"+. c #4C4D4F", -"@. c #37393C", -"#. c #615E5D", -"$. c #9B9796", -"%. c #969393", -"&. c #7E7B7C", -"*. c #484645", -"=. c #9A9999", -"-. c #EEEEEE", -";. c #CBC8C9", -">. c #484545", -",. c #484A4B", -"'. c #3E4043", -"). c #1E1D1E", -"!. c #BFBEBE", -"~. c #666464", -"{. c #262827", -"]. c #4B4F51", -"^. c #212124", -"/. c #373837", -"(. c #D7D7D6", -"_. c #F2F2F2", -":. c #424244", -"<. c #2E3031", -"[. c #3D3E40", -"}. c #908D8E", -"|. c #888685", -"1. c #454443", -"2. c #A5A4A4", -"3. c #E5E3E4", -"4. c #5A595B", -"5. c #3B3F40", -"6. c #545458", -"7. c #787676", -"8. c #9E9C9D", -"9. c #2B2A2B", -"0. c #434649", -"a. c #4A4D4F", -"b. c #939391", -"c. c #434344", -"d. c #3F3F41", -"e. c #202225", -"f. c #2D2E2E", -"g. c #4A4747", -"h. c #CAC9C9", -"i. c #F8F8F7", -"j. c #787878", -"k. c #353534", -"l. c #555858", -"m. c #232426", -"n. c #353635", -"o. c #DBDBDA", -"p. c #DAD7D9", -"q. c #424142", -"r. c #313233", -"s. c #5C5C5E", -"t. c #121617", -"u. c #4B4A4B", -"v. c #C5C5C4", -"w. c #8D8C8D", -"x. c #666667", -"y. c #131215", -"z. c #0D0E12", -"A. c #0F1013", -"B. c #353434", -"C. c #C9C7C7", -"D. c #FFFEFE", -"E. c #F7F3F5", -"F. c #A7A6A7", -"G. c #313033", -"H. c #4C4D50", -"I. c #4A484D", -"J. c #969696", -"K. c #6F6D6F", -"L. c #58575A", -"M. c #3E3E41", -"N. c #1E1F1E", -"O. c #ACA8A7", -"P. c #575353", -"Q. c #050408", -"R. c #252628", -"S. c #424547", -"T. c #979394", -"U. c #F5F4F4", -"V. c #F7F6F7", -"W. c #FBFCFB", -"X. c #D8D6D7", -"Y. c #424144", -"Z. c #3A3A3A", -"`. c #606160", -" + c #08090B", -".+ c #565656", -"++ c #FCFCFC", -"@+ c #A3A2A3", -"#+ c #2D2B2C", -"$+ c #464646", -"%+ c #515455", -"&+ c #161619", -"*+ c #747171", -"=+ c #A9A9A8", -"-+ c #D7D9DA", -";+ c #484647", -">+ c #535455", -",+ c #101418", -"'+ c #585758", -")+ c #F2F1F2", -"!+ c #F8F6F7", -"~+ c #FDFBFC", -"{+ c #666365", -"]+ c #2F2E2F", -"^+ c #656565", -"/+ c #313336", -"(+ c #C7C5C5", -"_+ c #444344", -":+ c #232326", -"<+ c #454849", -"[+ c #464647", -"}+ c #CAC9CA", -"|+ c #B2AFB3", -"1+ c #504C4E", -"2+ c #585855", -"3+ c #313738", -"4+ c #1E1F21", -"5+ c #C5C2C4", -"6+ c #FFFDFE", -"7+ c #F9F8F8", -"8+ c #969395", -"9+ c #28262A", -"0+ c #565658", -"a+ c #575558", -"b+ c #868484", -"c+ c #6F6E70", -"d+ c #191A1B", -"e+ c #1C1C1C", -"f+ c #0C0C0C", -"g+ c #868487", -"h+ c #D7D7D7", -"i+ c #525053", -"j+ c #525051", -"k+ c #4E5153", -"l+ c #8D8B8E", -"m+ c #F7F7F6", -"n+ c #CDCBCC", -"o+ c #343435", -"p+ c #3E3D3D", -"q+ c #68686A", -"r+ c #18191C", -"s+ c #6A6D6D", -"t+ c #A6A4A5", -"u+ c #605F63", -"v+ c #15191C", -"w+ c #5C5B5C", -"x+ c #636062", -"y+ c #4A4749", -"z+ c #626163", -"A+ c #070D0E", -"B+ c #555356", -"C+ c #F9F7F8", -"D+ c #F7F7F7", -"E+ c #FCFBFB", -"F+ c #F1F0F0", -"G+ c #595758", -"H+ c #2C2A2D", -"I+ c #6A686B", -"J+ c #2F2E32", -"K+ c #2D2E2D", -"L+ c #EAEAE9", -"M+ c #726E71", -"N+ c #5A5D5A", -"O+ c #262A2D", -"P+ c #2D2C2E", -"Q+ c #D3D0D2", -"R+ c #7E7E7E", -"S+ c #3D3B3D", -"T+ c #646566", -"U+ c #2D2F33", -"V+ c #CBCBCC", -"W+ c #FEFEFD", -"X+ c #FBFAFA", -"Y+ c #838384", -"Z+ c #222224", -"`+ c #4C4C4E", -" @ c #545553", -".@ c #B5B5B2", -"+@ c #D3D3D3", -"@@ c #D8D6D8", -"#@ c #595856", -"$@ c #505152", -"%@ c #414346", -"&@ c #050507", -"*@ c #9E9EA0", -"=@ c #605F61", -"-@ c #484B4C", -";@ c #929193", -">@ c #F7F5F6", -",@ c #FAFAFA", -"'@ c #C1C1C1", -")@ c #1D1C1E", -"!@ c #3D3D3E", -"~@ c #E6E5E4", -"{@ c #F3F3F2", -"]@ c #D5D6D6", -"^@ c #EBEAEB", -"/@ c #575957", -"(@ c #000001", -"_@ c #737174", -":@ c #CECDCD", -"<@ c #3B3A3B", -"[@ c #606363", -"}@ c #010507", -"|@ c #5A595A", -"1@ c #F9F9FA", -"2@ c #F7F6F6", -"3@ c #FBFBFA", -"4@ c #E9E9E9", -"5@ c #D5D5D5", -"6@ c #FDFCFD", -"7@ c #696869", -"8@ c #444340", -"9@ c #676769", -"0@ c #13191B", -"a@ c #434145", -"b@ c #EEEDEE", -"c@ c #525153", -"d@ c #404040", -"e@ c #6D6F6F", -"f@ c #1D2122", -"g@ c #2E2F31", -"h@ c #DEDFE0", -"i@ c #F6F5F6", -"j@ c #F6F6F6", -"k@ c #ECECEC", -"l@ c #646366", -"m@ c #F6F5F5", -"n@ c #828183", -"o@ c #3D393A", -"p@ c #2C3032", -"q@ c #1D1E1F", -"r@ c #C5C3C5", -"s@ c #706F70", -"t@ c #302F31", -"u@ c #747273", -"v@ c #424546", -"w@ c #0F1113", -"x@ c #E2E1E2", -"y@ c #FEFEFE", -"z@ c #F6F6F5", -"A@ c #FAFAF9", -"B@ c #EEEFEE", -"C@ c #323137", -"D@ c #A19FA0", -"E@ c #353234", -"F@ c #44494B", -"G@ c #969496", -"H@ c #9B979A", -"I@ c #2B292C", -"J@ c #686A69", -"K@ c #58595D", -"L@ c #141315", -"M@ c #989796", -"N@ c #F8F8F8", -"O@ c #EEEDED", -"P@ c #474C4D", -"Q@ c #101218", -"R@ c #B9B6B8", -"S@ c #C5C4C4", -"T@ c #353637", -"U@ c #5F5F63", -"V@ c #5D5D5E", -"W@ c #656467", -"X@ c #C4C3C3", -"Y@ c #2F2F30", -"Z@ c #414143", -"`@ c #646467", -" # c #636261", -".# c #EEEEEC", -"+# c #FCFCFB", -"@# c #F5F5F5", -"## c #FDFDFC", -"$# c #F2F1F1", -"%# c #7E7D7D", -"&# c #525455", -"*# c #00010A", -"=# c #939296", -"-# c #DFDFDE", -";# c #3D3A3B", -"># c #514F50", -",# c #717373", -"'# c #111315", -")# c #3D3D40", -"!# c #E8E8E8", -"~# c #4F4D4F", -"{# c #0C0E0F", -"]# c #888986", -"^# c #F9F8F7", -"/# c #F4F4F3", -"(# c #F0F0EF", -"_# c #7C7779", -":# c #666564", -"<# c #616363", -"[# c #000107", -"}# c #6C6A6D", -"|# c #FCFAFA", -"1# c #5A5959", -"2# c #434243", -"3# c #827F81", -"4# c #292E2F", -"5# c #1F1F22", -"6# c #E5E6E6", -"7# c #949392", -"8# c #E7E6E7", -"9# c #FCFCFD", -"0# c #FAFAF8", -"a# c #6C6B6D", -"b# c #595559", -"c# c #6A6C6C", -"d# c #070C10", -"e# c #434245", -"f# c #F0F0F0", -"g# c #727272", -"h# c #28282B", -"i# c #7E7A7C", -"j# c #424345", -"k# c #929293", -"l# c #F2F0F1", -"m# c #747473", -"n# c #4E4B4F", -"o# c #727277", -"p# c #1C1E22", -"q# c #272B2F", -"r# c #D3D3D4", -"s# c #919090", -"t# c #2B282B", -"u# c #565659", -"v# c #606365", -"w# c #595557", -"x# c #D9D7D8", -"y# c #EDEDED", -"z# c #898687", -"A# c #413D3F", -"B# c #7C7A7B", -"C# c #36393C", -"D# c #101318", -"E# c #AFB0B2", -"F# c #BCBBBB", -"G# c #2A292B", -"H# c #242428", -"I# c #595A5A", -"J# c #EFEFEF", -"K# c #F3F0F1", -"L# c #F5F3F4", -"M# c #EBEBEB", -"N# c #D4D4D4", -"O# c #F3F1F2", -"P# c #A6A3A2", -"Q# c #3A3A3C", -"R# c #7F7C7F", -"S# c #494C4D", -"T# c #98989B", -"U# c #E0DDDD", -"V# c #4D4B4A", -"W# c #D2D2D1", -"X# c #FEFBFB", -"Y# c #F7F8F7", -"Z# c #F2F0F0", -"`# c #E6E6E6", -" $ c #CACBCB", -".$ c #EFEDEE", -"+$ c #DCD9DA", -"@$ c #E5E4E4", -"#$ c #B3B2B2", -"$$ c #383536", -"%$ c #6C6A6A", -"&$ c #4D4D4E", -"*$ c #06070B", -"=$ c #0A0C0F", -"-$ c #C8C8C9", -";$ c #DFDDDE", -">$ c #E3E2E2", -",$ c #E5E5E5", -"'$ c #E1E1E1", -")$ c #E2E2E2", -"!$ c #DEDDDE", -"~$ c #D6D5D4", -"{$ c #CCCBCC", -"]$ c #B7B7B7", -"^$ c #BFBDBE", -"/$ c #ABA9AA", -"($ c #B3B3B3", -"_$ c #A1A09F", -":$ c #353333", -"<$ c #535053", -"[$ c #404041", -"}$ c #252727", -"|$ c #AEADAF", -"1$ c #B3B1B2", -"2$ c #ADABAB", -"3$ c #B2B2B2", -"4$ c #B2B3B3", -"5$ c #AEAEAE", -"6$ c #A4A1A2", -"7$ c #757575", -" ", -" ", -" . + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ ^ / ^ ( _ : < [ ", -" } | 1 2 3 4 5 6 7 8 9 0 ^ a b c d e f g ^ ^ h i ^ j k l ", -" & m n o p q r s t u v w x ^ ^ y z A B C D E ^ ^ F ^ G H ", -" } I J K L M N O P Q R S C T U ^ V W X Y C C Z ^ ^ ` ... ", -" +.@.#.$.%.&.*.=.-.;.>.,.'.C ).!.^ ^ ~.{.].^.C /.(.^ _... ", -" :.<.[.}.|.1.2.^ ^ ^ 3.4.5.6.C C 7.^ ^ 8.9.0.a.C C b. ... ", -" c.d.e.f.g.h.^ / i.a ^ ^ j.k.l.m.C n.o.^ p.q.r.s.t.C u.v. ", -" w.x.y.z.A.B.C.^ D.E.h ^ ^ F.G.H.I.C C J.^ ^ K.o L.M.C N. ", -" O.P.Q.R.S.C C T.^ ^ U.V.W.^ X.Y.Z.`. +C .+++^ @+#+$+%+&+ ", -" *+=+-+_ ;+>+,+C '+)+^ h !+U ^ ~+{+]+^+/+C ).(+^ 0 _+:+<+ ", -" [+}+^ ^ |+1+2+3+C 4+5+^ 6+!+7+^ ^ 8+9+0+a+C C b+^ ^ c+d+ ", -" e+f+g+^ ^ h+i+j+k+C C l+^ ^ m+7+D.^ n+o+p+q+r+C s+^ .t+ ", -" u+v+C w+( ^ )+x+y+z+A+C B+_.^ C+D+E+^ F+G+H+I+J+K+L+ ... ", -" M+N+O+C P+Q+^ ^ R+S+T+U+C [ V+^ W+h X+^ ^ Y+Z+`+ @.@ .+@ ", -" @@#@$@%@C &@*@^ ^ 2.n =@-@C C ;@^ ^ >@,@D.^ '@)@!@~@{@]@ ", -" ^ ^@B+u./@(@C _@^ ^ :@<@< [@}@C |@1@^ 2@X+3@^ ] !.^ 4@5@ ", -" ^ ^ 6@7@8@9@0@C a@^@^ b@c@d@e@f@C g@h@^ i@X+a ^ ^ j@k@+@ ", -" l@m@^ ^ n@o@6 p@C q@r@^ ^ s@t@u@v@C w@x@y@z@A@++h D+B@.. ", -" e+C@] ^ ^ D@E@K.F@C C G@^ ^ H@I@J@K@L@M@^ W+m+N@/ ,@O@.. ", -" P@f+Q@R@^ ^ S@T@U@V@C C W@^ ^ X@Y@Z@`@ #.#^ +#2@@###$#5@ ", -" %#&#C *#=#^ ^ -#;#>#,#'#C )#b@^ !#~#{#]#W+++3@E+^#/#(#.. ", -" _#:#<#[#C }#^ ^ |#1#2#3#4#C 5#6#^ ^ 7#8#9###a a X+N@4@+@ ", -" 0#a#b#c#d#C e#f#^ ^ g#h#i#j#C k#^ ^ ^ ^ l#X+++D+N@N@-.+@ ", -" ^ ^ m#n#o#p#C q#r#^ ^ s#t#u#v#w#x#^ 3@+#a $#!+++D+j@y#.. ", -" ^ ^ ^ z#A#B#C#C D#E#^ ^ F#G#H#I#J#^ a a ,@U K#L#+#N@M#N# ", -" O#^ y@^ P#Q#R#S#C C T#^ ^ U#V#W#X#++++7+N@Y#U K#Z#N@`# $ ", -" .$+$@$`#`##$$$%$&$*$=$-$`#`#`#`#;$] >$,$'$'$'$)$!$~${$]$ ", -" , ^$/$($($($_$:$<$[$}$1#|$($($($($1$2$#$($3$3$3$4$5$6$7$ ", -" ", -" "}; diff --git a/graphics/play_KeyHits.tga b/graphics/play_KeyHits.tga deleted file mode 100644 index b52737e9..00000000 Binary files a/graphics/play_KeyHits.tga and /dev/null differ diff --git a/graphics/play_KeyRail.tga b/graphics/play_KeyRail.tga deleted file mode 100755 index 27c8421b..00000000 Binary files a/graphics/play_KeyRail.tga and /dev/null differ diff --git a/graphics/play_KeyShadow.tga b/graphics/play_KeyShadow.tga deleted file mode 100644 index a2558ec9..00000000 Binary files a/graphics/play_KeyShadow.tga and /dev/null differ diff --git a/graphics/play_Keys.tga b/graphics/play_Keys.tga deleted file mode 100644 index 8253095c..00000000 Binary files a/graphics/play_Keys.tga and /dev/null differ diff --git a/graphics/play_Keys.xcf b/graphics/play_Keys.xcf deleted file mode 100644 index c4ada76c..00000000 Binary files a/graphics/play_Keys.xcf and /dev/null differ diff --git a/graphics/play_KeysBlack.tga b/graphics/play_KeysBlack.tga deleted file mode 100755 index 4909c6da..00000000 Binary files a/graphics/play_KeysBlack.tga and /dev/null differ diff --git a/graphics/play_KeysWhite.png b/graphics/play_KeysWhite.png deleted file mode 100755 index 73ec511b..00000000 Binary files a/graphics/play_KeysWhite.png and /dev/null differ diff --git a/graphics/play_KeysWhite.tga b/graphics/play_KeysWhite.tga deleted file mode 100755 index 078ba290..00000000 Binary files a/graphics/play_KeysWhite.tga and /dev/null differ diff --git a/graphics/play_NotesBlackColor.tga b/graphics/play_NotesBlackColor.tga deleted file mode 100755 index 07b00545..00000000 Binary files a/graphics/play_NotesBlackColor.tga and /dev/null differ diff --git a/graphics/play_NotesBlackShadow.tga b/graphics/play_NotesBlackShadow.tga deleted file mode 100644 index 8428dcf2..00000000 Binary files a/graphics/play_NotesBlackShadow.tga and /dev/null differ diff --git a/graphics/play_NotesWhiteColor.tga b/graphics/play_NotesWhiteColor.tga deleted file mode 100755 index 8b545c6f..00000000 Binary files a/graphics/play_NotesWhiteColor.tga and /dev/null differ diff --git a/graphics/play_NotesWhiteShadow.tga b/graphics/play_NotesWhiteShadow.tga deleted file mode 100644 index 8811b8f1..00000000 Binary files a/graphics/play_NotesWhiteShadow.tga and /dev/null differ diff --git a/graphics/play_Status.tga b/graphics/play_Status.tga deleted file mode 100644 index f06f9ccc..00000000 Binary files a/graphics/play_Status.tga and /dev/null differ diff --git a/graphics/play_Status2.tga b/graphics/play_Status2.tga deleted file mode 100644 index 124a6099..00000000 Binary files a/graphics/play_Status2.tga and /dev/null differ diff --git a/graphics/score_RetrySong.tga b/graphics/score_RetrySong.tga deleted file mode 100644 index a8ac5efb..00000000 Binary files a/graphics/score_RetrySong.tga and /dev/null differ diff --git a/graphics/stats_text.tga b/graphics/stats_text.tga deleted file mode 100644 index 249be85b..00000000 Binary files a/graphics/stats_text.tga and /dev/null differ diff --git a/graphics/title_ChooseTracks.tga b/graphics/title_ChooseTracks.tga deleted file mode 100644 index de709db1..00000000 Binary files a/graphics/title_ChooseTracks.tga and /dev/null differ diff --git a/graphics/title_Exit.tga b/graphics/title_Exit.tga deleted file mode 100644 index 5dc85a16..00000000 Binary files a/graphics/title_Exit.tga and /dev/null differ diff --git a/graphics/title_GameMusicThemes.tga b/graphics/title_GameMusicThemes.tga deleted file mode 100644 index 38f63422..00000000 Binary files a/graphics/title_GameMusicThemes.tga and /dev/null differ diff --git a/graphics/title_InputBox.tga b/graphics/title_InputBox.tga deleted file mode 100644 index e9659d6f..00000000 Binary files a/graphics/title_InputBox.tga and /dev/null differ diff --git a/graphics/title_Logo.tga b/graphics/title_Logo.tga deleted file mode 100755 index 6cadb0bb..00000000 Binary files a/graphics/title_Logo.tga and /dev/null differ diff --git a/graphics/title_OutputBox.tga b/graphics/title_OutputBox.tga deleted file mode 100644 index b0c8e86b..00000000 Binary files a/graphics/title_OutputBox.tga and /dev/null differ diff --git a/graphics/title_SongBox.tga b/graphics/title_SongBox.tga deleted file mode 100644 index f6de7535..00000000 Binary files a/graphics/title_SongBox.tga and /dev/null differ diff --git a/graphics/trackbox.tga b/graphics/trackbox.tga deleted file mode 100644 index 14e8772d..00000000 Binary files a/graphics/trackbox.tga and /dev/null differ diff --git a/graphics/trackbox.xcf b/graphics/trackbox.xcf deleted file mode 100644 index fb9ef5d0..00000000 Binary files a/graphics/trackbox.xcf and /dev/null differ diff --git a/graphics/tracks_BackToTitle.tga b/graphics/tracks_BackToTitle.tga deleted file mode 100644 index c969eee8..00000000 Binary files a/graphics/tracks_BackToTitle.tga and /dev/null differ diff --git a/graphics/tracks_PlaySong.tga b/graphics/tracks_PlaySong.tga deleted file mode 100644 index a2a3572f..00000000 Binary files a/graphics/tracks_PlaySong.tga and /dev/null differ diff --git a/lib_midi/Cargo.toml b/lib_midi/Cargo.toml new file mode 100644 index 00000000..5ffae56a --- /dev/null +++ b/lib_midi/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "lib_midi" +version = "0.1.0" +authors = ["Poly "] +edition = "2018" + +[dependencies] +midly = "0.4.0" \ No newline at end of file diff --git a/lib_midi/src/lib.rs b/lib_midi/src/lib.rs new file mode 100644 index 00000000..13c710dc --- /dev/null +++ b/lib_midi/src/lib.rs @@ -0,0 +1,9 @@ +mod track; +mod tracks_parser; +mod midi; + +pub use { + track::*, + tracks_parser::*, + midi::*, +}; diff --git a/lib_midi/src/midi.rs b/lib_midi/src/midi.rs new file mode 100644 index 00000000..d712e306 --- /dev/null +++ b/lib_midi/src/midi.rs @@ -0,0 +1,86 @@ +use { + crate::{MidiTrack, TracksParser}, + midly::{Format, Smf, Timing}, + std::fs, +}; + +#[derive(Debug)] +pub struct Midi { + // pub tracks_count: u16, + pub format: Format, + pub tracks: Vec, + pub merged_track: MidiTrack, +} + +impl Midi { + pub fn new(path: &str) -> Result { + let data = match fs::read(path) { + Ok(buff) => buff, + Err(_) => return Err(String::from("Could Not Open File")), + }; + + let smf = match Smf::parse(&data) { + Ok(smf) => smf, + Err(_) => return Err(String::from("Midi Parsing Error (midly lib)")), + }; + + let u_per_quarter_note: u16; + + match smf.header.timing { + Timing::Metrical(t) => u_per_quarter_note = t.as_int(), + Timing::Timecode(_fps, _u) => { + return Err(String::from("Midi With Timecode Timing, Not Supported!")); + } + }; + + if smf.tracks.is_empty() { + return Err(String::from("Midi File Has No Tracks")); + } + + let mut tracks: Vec = Vec::new(); + for (i, trk) in smf.tracks.iter().enumerate() { + tracks.push(MidiTrack::new(trk, i)); + } + + let tp = &mut TracksParser::new(u_per_quarter_note); + + match smf.header.format { + Format::SingleTrack => { + tp.parse(&mut tracks, &smf.tracks); + } + Format::Parallel => { + tp.parse(&mut tracks, &smf.tracks); + } + Format::Sequential => { + return Err(String::from("MultiSong Midi Not Supported")); + } + } + + let mut merged_track: MidiTrack = tracks[0].clone(); + + for (i, trk) in tracks.iter().enumerate() { + if i > 0 { + for n in trk.notes.iter() { + let n = n.clone(); + merged_track.notes.push(n); + } + } + } + + merged_track + .notes + .sort_by(|a, b| a.start.partial_cmp(&b.start).unwrap()); + + // Asign Unique Id + for (i, note) in merged_track.notes.iter_mut().enumerate() { + note.id = i; + } + + Ok(Self { + // tracks_count: tracks.len() as u16, + format: smf.header.format, + tracks, + merged_track, + }) + } +} diff --git a/lib_midi/src/track.rs b/lib_midi/src/track.rs new file mode 100644 index 00000000..15dd6022 --- /dev/null +++ b/lib_midi/src/track.rs @@ -0,0 +1,151 @@ +use { + crate::TracksParser, + midly::{Event, EventKind, MetaMessage, MidiMessage}, + std::collections::HashMap, +}; + +#[derive(Debug, Clone)] +pub struct TempoEvent { + pub time_in_units: f32, + pub tempo: u32, +} + +#[derive(Debug, Clone)] +pub struct MidiNote { + pub start: f32, + pub duration: f32, + pub note: u8, + pub vel: u8, + pub ch: u8, + pub track_id: usize, + pub id: usize, +} + +#[derive(Debug, Clone)] +pub struct MidiTrack { + pub tempo: u32, + pub tempo_events: Vec, + pub has_tempo: bool, + pub notes: Vec, + pub track_id: usize, +} + +impl MidiTrack { + pub fn new(track: &[Event], track_id: usize) -> Self { + let mut tempo = 500_000; // 120 bpm + + let mut has_tempo = false; + let mut tempo_events = Vec::new(); + + let mut time_in_units: f32 = 0.0; + for event in track.iter() { + time_in_units += event.delta.as_int() as f32; + + if let EventKind::Meta(meta) = &event.kind { + if let MetaMessage::Tempo(t) = &meta { + if !has_tempo { + tempo = t.as_int(); + has_tempo = true; + } + tempo_events.push(TempoEvent { + time_in_units, + tempo: t.as_int(), + }); + } + }; + } + + Self { + tempo, + tempo_events, + has_tempo, + track_id, + notes: Vec::new(), + } + } + + pub fn extract_notes(&mut self, events: &[Event], parent_parser: &mut TracksParser) { + self.notes.clear(); + + let mut time_in_units = 0.0; + + struct Note { + time_in_units: f32, + vel: u8, + channel: u8, + }; + let mut current_notes: HashMap = HashMap::new(); + + macro_rules! end_note { + (k => $e:expr) => { + let k = $e; + if current_notes.contains_key(&k) { + let n = current_notes.get(&k).unwrap(); + + let start = parent_parser.pulses_to_ms(n.time_in_units) / 1000.0; + let duration = parent_parser.pulses_to_ms(time_in_units) / 1000.0 - start; + + let mn = MidiNote { + start: start as f32, + duration: duration as f32, + note: k, + vel: n.vel, + ch: n.channel, + track_id: self.track_id, + id: 0, // Placeholder + }; + self.notes.push(mn); + current_notes.remove(&k); + } + }; + } + + for event in events.iter() { + time_in_units += event.delta.as_int() as f32; + + if let EventKind::Midi { channel, message } = &event.kind { + match &message { + MidiMessage::NoteOn { key, vel } => { + let key = key.as_int(); + let vel = vel.as_int(); + + match vel.cmp(&0) { + std::cmp::Ordering::Greater => { + let k = key; + + match current_notes.entry(k) { + std::collections::hash_map::Entry::Occupied(_e) => { + end_note!(k=>k); + } + std::collections::hash_map::Entry::Vacant(_e) => { + current_notes.insert( + k, + Note { + time_in_units, + vel, + channel: channel.as_int(), + }, + ); + } + } + } + std::cmp::Ordering::Equal => { + end_note!(k=>key); + } + _ => {} + } + } + MidiMessage::NoteOff { key, .. } => { + let key = key.as_int(); + + end_note!(k=>key); + } + _ => {} + } + } + } + + self.notes + .sort_by(|a, b| a.start.partial_cmp(&b.start).unwrap()); + } +} diff --git a/lib_midi/src/tracks_parser.rs b/lib_midi/src/tracks_parser.rs new file mode 100644 index 00000000..1ceb1fa1 --- /dev/null +++ b/lib_midi/src/tracks_parser.rs @@ -0,0 +1,84 @@ +use { + crate::{TempoEvent, MidiTrack}, + midly::Event +}; + +pub struct TracksParser { + tempo_events: Vec, + u_per_quarter_note: f32, +} + +impl TracksParser { + pub fn new(u_per_quarter_note: u16) -> Self { + let u_per_quarter_note = f32::from(u_per_quarter_note); + + Self { + tempo_events: Vec::new(), + u_per_quarter_note, + } + } + pub fn parse(&mut self, tracks: &mut Vec, midly_tracks: &[Vec]) { + let mut tempo_track = 0; + for (i, trk) in tracks.iter().enumerate() { + if trk.has_tempo { + tempo_track = i; + break; + } + } + + // TODO: Merge tempo events if there is more than one tempo track + if tracks[tempo_track].has_tempo { + self.tempo_events = tracks[tempo_track].tempo_events.clone(); + } else { + // TODO: Return to caller to inform user that fallback bpm is used + println!("There is no tempo track! Useing 120 bpm as fallback"); + + //panic!("There is no track with tempo info"); // ! For Debug Only + } + + for trk in tracks.iter_mut() { + trk.extract_notes(&midly_tracks[trk.track_id], self); + } + + } + fn p_to_ms(&self, time_in_units: f32, tempo: u32) -> f32 { + let u_time = tempo as f32 / self.u_per_quarter_note; + u_time * time_in_units / 1000.0 + } + pub fn pulses_to_ms(&self, event_pulses: f32) -> f32 { + let mut res: f32 = 0.0; + + let mut hit = false; + let mut last_tempo_event_pulses: f32 = 0.0; + let mut running_tempo = 500_000; + + let event_pulses = event_pulses; + + for tempo_event in self.tempo_events.iter() { + let tempo_event_pulses = tempo_event.time_in_units; + + let delta_pulses = if event_pulses > tempo_event_pulses { + tempo_event_pulses - last_tempo_event_pulses + } else { + hit = true; + event_pulses - last_tempo_event_pulses + }; + + res += self.p_to_ms(delta_pulses, running_tempo); + + if hit { + break; + } + + running_tempo = tempo_event.tempo; + last_tempo_event_pulses = tempo_event_pulses; + } + + if !hit { + let remaining_pulses = event_pulses - last_tempo_event_pulses; + res += self.p_to_ms(remaining_pulses, running_tempo); + } + + res + } +} diff --git a/music/Game_Themes/Bubble_Bobble_-_Main_Theme.mid b/music/Game_Themes/Bubble_Bobble_-_Main_Theme.mid deleted file mode 100644 index f5f0e20a..00000000 Binary files a/music/Game_Themes/Bubble_Bobble_-_Main_Theme.mid and /dev/null differ diff --git a/music/Game_Themes/Dragon_Warrior_-_Town_Theme.mid b/music/Game_Themes/Dragon_Warrior_-_Town_Theme.mid deleted file mode 100644 index bff2dc7a..00000000 Binary files a/music/Game_Themes/Dragon_Warrior_-_Town_Theme.mid and /dev/null differ diff --git a/music/Game_Themes/Sonic_the_Hedgehog_-_Green_Hill_Zone.mid b/music/Game_Themes/Sonic_the_Hedgehog_-_Green_Hill_Zone.mid deleted file mode 100644 index cca3b2d3..00000000 Binary files a/music/Game_Themes/Sonic_the_Hedgehog_-_Green_Hill_Zone.mid and /dev/null differ diff --git a/music/Game_Themes/Super_Mario_Bros_-_Overworld.mid b/music/Game_Themes/Super_Mario_Bros_-_Overworld.mid deleted file mode 100644 index 97974dcc..00000000 Binary files a/music/Game_Themes/Super_Mario_Bros_-_Overworld.mid and /dev/null differ diff --git a/music/Game_Themes/Super_Mario_Bros_-_Underwater.mid b/music/Game_Themes/Super_Mario_Bros_-_Underwater.mid deleted file mode 100644 index a512cccb..00000000 Binary files a/music/Game_Themes/Super_Mario_Bros_-_Underwater.mid and /dev/null differ diff --git a/music/Game_Themes/Tetris_-_Theme_A.mid b/music/Game_Themes/Tetris_-_Theme_A.mid deleted file mode 100644 index 30b165f3..00000000 Binary files a/music/Game_Themes/Tetris_-_Theme_A.mid and /dev/null differ diff --git a/music/Game_Themes/The_Sims_-_Buying_Theme_1.mid b/music/Game_Themes/The_Sims_-_Buying_Theme_1.mid deleted file mode 100644 index 182508ca..00000000 Binary files a/music/Game_Themes/The_Sims_-_Buying_Theme_1.mid and /dev/null differ diff --git a/music/Game_Themes/Zelda_A_Link_to_the_Past_-_Overworld_Theme.mid b/music/Game_Themes/Zelda_A_Link_to_the_Past_-_Overworld_Theme.mid deleted file mode 100644 index 53a6c5ff..00000000 Binary files a/music/Game_Themes/Zelda_A_Link_to_the_Past_-_Overworld_Theme.mid and /dev/null differ diff --git a/music/Game_Themes/Zelda_Ocarina_of_Time_-_Lost_Woods.mid b/music/Game_Themes/Zelda_Ocarina_of_Time_-_Lost_Woods.mid deleted file mode 100644 index 884c41d3..00000000 Binary files a/music/Game_Themes/Zelda_Ocarina_of_Time_-_Lost_Woods.mid and /dev/null differ diff --git a/music/Game_Themes/Zelda_Ocarina_of_Time_-_Zelda_s_Lullaby.mid b/music/Game_Themes/Zelda_Ocarina_of_Time_-_Zelda_s_Lullaby.mid deleted file mode 100644 index d7f05b35..00000000 Binary files a/music/Game_Themes/Zelda_Ocarina_of_Time_-_Zelda_s_Lullaby.mid and /dev/null differ diff --git a/music/Hannon/Lesson_1.mid b/music/Hannon/Lesson_1.mid deleted file mode 100644 index 8143807c..00000000 Binary files a/music/Hannon/Lesson_1.mid and /dev/null differ diff --git a/music/Hannon/Lesson_2.mid b/music/Hannon/Lesson_2.mid deleted file mode 100644 index 702cc387..00000000 Binary files a/music/Hannon/Lesson_2.mid and /dev/null differ diff --git a/music/Hannon/Lesson_3.mid b/music/Hannon/Lesson_3.mid deleted file mode 100644 index 986d7580..00000000 Binary files a/music/Hannon/Lesson_3.mid and /dev/null differ diff --git a/music/Hannon/Lesson_4.mid b/music/Hannon/Lesson_4.mid deleted file mode 100644 index 4aeca546..00000000 Binary files a/music/Hannon/Lesson_4.mid and /dev/null differ diff --git a/music/Hannon/Lesson_5.mid b/music/Hannon/Lesson_5.mid deleted file mode 100644 index 889c57e9..00000000 Binary files a/music/Hannon/Lesson_5.mid and /dev/null differ diff --git a/music/Hannon/Lesson_6.mid b/music/Hannon/Lesson_6.mid deleted file mode 100644 index e328423b..00000000 Binary files a/music/Hannon/Lesson_6.mid and /dev/null differ diff --git a/music/Hannon/Lesson_7.mid b/music/Hannon/Lesson_7.mid deleted file mode 100644 index e9ed435a..00000000 Binary files a/music/Hannon/Lesson_7.mid and /dev/null differ diff --git a/music/Hannon/Lesson_8.mid b/music/Hannon/Lesson_8.mid deleted file mode 100644 index 7653ede9..00000000 Binary files a/music/Hannon/Lesson_8.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Aria-Notebook_AM_Bach.mid b/music/Keyboard_Classics/Aria-Notebook_AM_Bach.mid deleted file mode 100644 index cc213fad..00000000 Binary files a/music/Keyboard_Classics/Aria-Notebook_AM_Bach.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Clementi_Opus_36_no_1_First_Movement.mid b/music/Keyboard_Classics/Clementi_Opus_36_no_1_First_Movement.mid deleted file mode 100644 index 5667409d..00000000 Binary files a/music/Keyboard_Classics/Clementi_Opus_36_no_1_First_Movement.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Fur_Elise-Beethoven.mid b/music/Keyboard_Classics/Fur_Elise-Beethoven.mid deleted file mode 100644 index 7f4c26dd..00000000 Binary files a/music/Keyboard_Classics/Fur_Elise-Beethoven.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Minuet_in_F-Leopold_Mozart.mid b/music/Keyboard_Classics/Minuet_in_F-Leopold_Mozart.mid deleted file mode 100644 index 8b44f5bf..00000000 Binary files a/music/Keyboard_Classics/Minuet_in_F-Leopold_Mozart.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Minuet_in_G-JS_Bach.mid b/music/Keyboard_Classics/Minuet_in_G-JS_Bach.mid deleted file mode 100644 index 0dfd4f9a..00000000 Binary files a/music/Keyboard_Classics/Minuet_in_G-JS_Bach.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Rondino-Rameau.mid b/music/Keyboard_Classics/Rondino-Rameau.mid deleted file mode 100644 index 65f5a173..00000000 Binary files a/music/Keyboard_Classics/Rondino-Rameau.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Russian_Folksong-Beethoven.mid b/music/Keyboard_Classics/Russian_Folksong-Beethoven.mid deleted file mode 100644 index 39de6120..00000000 Binary files a/music/Keyboard_Classics/Russian_Folksong-Beethoven.mid and /dev/null differ diff --git a/music/Keyboard_Classics/Sonatina_in_C-Latour.mid b/music/Keyboard_Classics/Sonatina_in_C-Latour.mid deleted file mode 100644 index f0bb7550..00000000 Binary files a/music/Keyboard_Classics/Sonatina_in_C-Latour.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/A_Tisket,_A_Tasket.mid b/music/Learning/0_-_First_Steps/A_Tisket,_A_Tasket.mid deleted file mode 100644 index 6f02c96c..00000000 Binary files a/music/Learning/0_-_First_Steps/A_Tisket,_A_Tasket.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Au_Clair_de_la_Lune.mid b/music/Learning/0_-_First_Steps/Au_Clair_de_la_Lune.mid deleted file mode 100644 index 8b8b8bfc..00000000 Binary files a/music/Learning/0_-_First_Steps/Au_Clair_de_la_Lune.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Aura_Lee_(Love_Me_Tender).mid b/music/Learning/0_-_First_Steps/Aura_Lee_(Love_Me_Tender).mid deleted file mode 100644 index 573798f6..00000000 Binary files a/music/Learning/0_-_First_Steps/Aura_Lee_(Love_Me_Tender).mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Away_in_the_Deep_Forest.mid b/music/Learning/0_-_First_Steps/Away_in_the_Deep_Forest.mid deleted file mode 100644 index 9f69440f..00000000 Binary files a/music/Learning/0_-_First_Steps/Away_in_the_Deep_Forest.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Bridal_March.mid b/music/Learning/0_-_First_Steps/Bridal_March.mid deleted file mode 100644 index 2581beb3..00000000 Binary files a/music/Learning/0_-_First_Steps/Bridal_March.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Chopsticks_(Short_Version).mid b/music/Learning/0_-_First_Steps/Chopsticks_(Short_Version).mid deleted file mode 100644 index f57d2ba1..00000000 Binary files a/music/Learning/0_-_First_Steps/Chopsticks_(Short_Version).mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Fais_Dodo.mid b/music/Learning/0_-_First_Steps/Fais_Dodo.mid deleted file mode 100644 index 01b81002..00000000 Binary files a/music/Learning/0_-_First_Steps/Fais_Dodo.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/For_Health_and_Strength.mid b/music/Learning/0_-_First_Steps/For_Health_and_Strength.mid deleted file mode 100644 index 7df69684..00000000 Binary files a/music/Learning/0_-_First_Steps/For_Health_and_Strength.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Good_King_Wenceslas.mid b/music/Learning/0_-_First_Steps/Good_King_Wenceslas.mid deleted file mode 100644 index 77cf96e7..00000000 Binary files a/music/Learning/0_-_First_Steps/Good_King_Wenceslas.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Hot_Cross_Buns.mid b/music/Learning/0_-_First_Steps/Hot_Cross_Buns.mid deleted file mode 100644 index a0a4131f..00000000 Binary files a/music/Learning/0_-_First_Steps/Hot_Cross_Buns.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/I_Saw_Three_Ships.mid b/music/Learning/0_-_First_Steps/I_Saw_Three_Ships.mid deleted file mode 100644 index dd78c133..00000000 Binary files a/music/Learning/0_-_First_Steps/I_Saw_Three_Ships.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Jolly_Old_Saint_Nicholas.mid b/music/Learning/0_-_First_Steps/Jolly_Old_Saint_Nicholas.mid deleted file mode 100644 index de05bc13..00000000 Binary files a/music/Learning/0_-_First_Steps/Jolly_Old_Saint_Nicholas.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Mary_Had_a_Little_Lamb.mid b/music/Learning/0_-_First_Steps/Mary_Had_a_Little_Lamb.mid deleted file mode 100644 index c7632c04..00000000 Binary files a/music/Learning/0_-_First_Steps/Mary_Had_a_Little_Lamb.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Mexican_Hat_Dance.mid b/music/Learning/0_-_First_Steps/Mexican_Hat_Dance.mid deleted file mode 100644 index 31e62e51..00000000 Binary files a/music/Learning/0_-_First_Steps/Mexican_Hat_Dance.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Ode_to_Joy.mid b/music/Learning/0_-_First_Steps/Ode_to_Joy.mid deleted file mode 100644 index 75680667..00000000 Binary files a/music/Learning/0_-_First_Steps/Ode_to_Joy.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Once_a_Small_Green_Mousie.mid b/music/Learning/0_-_First_Steps/Once_a_Small_Green_Mousie.mid deleted file mode 100644 index d277eacc..00000000 Binary files a/music/Learning/0_-_First_Steps/Once_a_Small_Green_Mousie.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Rain,_Rain,_Go_Away.mid b/music/Learning/0_-_First_Steps/Rain,_Rain,_Go_Away.mid deleted file mode 100644 index 5495d79d..00000000 Binary files a/music/Learning/0_-_First_Steps/Rain,_Rain,_Go_Away.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/Row,_Row,_Row_your_Boat.mid b/music/Learning/0_-_First_Steps/Row,_Row,_Row_your_Boat.mid deleted file mode 100644 index 07933483..00000000 Binary files a/music/Learning/0_-_First_Steps/Row,_Row,_Row_your_Boat.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/The_Monkey_and_the_Mirror.mid b/music/Learning/0_-_First_Steps/The_Monkey_and_the_Mirror.mid deleted file mode 100644 index 90c34f00..00000000 Binary files a/music/Learning/0_-_First_Steps/The_Monkey_and_the_Mirror.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/The_Silly_Seal.mid b/music/Learning/0_-_First_Steps/The_Silly_Seal.mid deleted file mode 100644 index f906122e..00000000 Binary files a/music/Learning/0_-_First_Steps/The_Silly_Seal.mid and /dev/null differ diff --git a/music/Learning/0_-_First_Steps/We_Three_Kings_(Short_Version).mid b/music/Learning/0_-_First_Steps/We_Three_Kings_(Short_Version).mid deleted file mode 100644 index 253a0b8a..00000000 Binary files a/music/Learning/0_-_First_Steps/We_Three_Kings_(Short_Version).mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Alouette.mid b/music/Learning/1_-_Very_Easy/Alouette.mid deleted file mode 100644 index 26bfac92..00000000 Binary files a/music/Learning/1_-_Very_Easy/Alouette.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Amazing_Grace.mid b/music/Learning/1_-_Very_Easy/Amazing_Grace.mid deleted file mode 100644 index a685101c..00000000 Binary files a/music/Learning/1_-_Very_Easy/Amazing_Grace.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Are_You_Sleeping.mid b/music/Learning/1_-_Very_Easy/Are_You_Sleeping.mid deleted file mode 100644 index cc363f0c..00000000 Binary files a/music/Learning/1_-_Very_Easy/Are_You_Sleeping.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Away_in_a_Manger.mid b/music/Learning/1_-_Very_Easy/Away_in_a_Manger.mid deleted file mode 100644 index 10dfffb7..00000000 Binary files a/music/Learning/1_-_Very_Easy/Away_in_a_Manger.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Beethoven_s_Fifth_Symphony.mid b/music/Learning/1_-_Very_Easy/Beethoven_s_Fifth_Symphony.mid deleted file mode 100644 index 338a32cd..00000000 Binary files a/music/Learning/1_-_Very_Easy/Beethoven_s_Fifth_Symphony.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Bingo.mid b/music/Learning/1_-_Very_Easy/Bingo.mid deleted file mode 100644 index 78b3d9ef..00000000 Binary files a/music/Learning/1_-_Very_Easy/Bingo.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Clementine.mid b/music/Learning/1_-_Very_Easy/Clementine.mid deleted file mode 100644 index df42f4dc..00000000 Binary files a/music/Learning/1_-_Very_Easy/Clementine.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Five_Fat_Turkeys_Are_We.mid b/music/Learning/1_-_Very_Easy/Five_Fat_Turkeys_Are_We.mid deleted file mode 100644 index 6e3c2a0b..00000000 Binary files a/music/Learning/1_-_Very_Easy/Five_Fat_Turkeys_Are_We.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Go_Tell_It_on_the_Mountain.mid b/music/Learning/1_-_Very_Easy/Go_Tell_It_on_the_Mountain.mid deleted file mode 100644 index b2a8b666..00000000 Binary files a/music/Learning/1_-_Very_Easy/Go_Tell_It_on_the_Mountain.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/I_Have_a_Little_Dreidle.mid b/music/Learning/1_-_Very_Easy/I_Have_a_Little_Dreidle.mid deleted file mode 100644 index ee092eb2..00000000 Binary files a/music/Learning/1_-_Very_Easy/I_Have_a_Little_Dreidle.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Jesu,_Joy_of_Man_s_Desiring.mid b/music/Learning/1_-_Very_Easy/Jesu,_Joy_of_Man_s_Desiring.mid deleted file mode 100644 index 8cb96cf5..00000000 Binary files a/music/Learning/1_-_Very_Easy/Jesu,_Joy_of_Man_s_Desiring.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Jingle_Bells.mid b/music/Learning/1_-_Very_Easy/Jingle_Bells.mid deleted file mode 100644 index 112175f5..00000000 Binary files a/music/Learning/1_-_Very_Easy/Jingle_Bells.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Les_Cloches_(The_Bells).mid b/music/Learning/1_-_Very_Easy/Les_Cloches_(The_Bells).mid deleted file mode 100644 index 8de93928..00000000 Binary files a/music/Learning/1_-_Very_Easy/Les_Cloches_(The_Bells).mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/London_Bridge.mid b/music/Learning/1_-_Very_Easy/London_Bridge.mid deleted file mode 100644 index c32d0cfc..00000000 Binary files a/music/Learning/1_-_Very_Easy/London_Bridge.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/My_Palm_Leaf_Hut.mid b/music/Learning/1_-_Very_Easy/My_Palm_Leaf_Hut.mid deleted file mode 100644 index 1ba14a0e..00000000 Binary files a/music/Learning/1_-_Very_Easy/My_Palm_Leaf_Hut.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Ode_to_Joy.mid b/music/Learning/1_-_Very_Easy/Ode_to_Joy.mid deleted file mode 100644 index 0749b49c..00000000 Binary files a/music/Learning/1_-_Very_Easy/Ode_to_Joy.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Oh,_When_the_Saints.mid b/music/Learning/1_-_Very_Easy/Oh,_When_the_Saints.mid deleted file mode 100644 index f298e38c..00000000 Binary files a/music/Learning/1_-_Very_Easy/Oh,_When_the_Saints.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Old_MacDonald.mid b/music/Learning/1_-_Very_Easy/Old_MacDonald.mid deleted file mode 100644 index df24618f..00000000 Binary files a/music/Learning/1_-_Very_Easy/Old_MacDonald.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Persian_Market_Monkey.mid b/music/Learning/1_-_Very_Easy/Persian_Market_Monkey.mid deleted file mode 100644 index b7aadba7..00000000 Binary files a/music/Learning/1_-_Very_Easy/Persian_Market_Monkey.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Row,_Row_Row_your_Boat.mid b/music/Learning/1_-_Very_Easy/Row,_Row_Row_your_Boat.mid deleted file mode 100644 index a9cb48e6..00000000 Binary files a/music/Learning/1_-_Very_Easy/Row,_Row_Row_your_Boat.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Surprise!.mid b/music/Learning/1_-_Very_Easy/Surprise!.mid deleted file mode 100644 index 413a608c..00000000 Binary files a/music/Learning/1_-_Very_Easy/Surprise!.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/The_Chimes.mid b/music/Learning/1_-_Very_Easy/The_Chimes.mid deleted file mode 100644 index c3edadc2..00000000 Binary files a/music/Learning/1_-_Very_Easy/The_Chimes.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/The_First_Noel.mid b/music/Learning/1_-_Very_Easy/The_First_Noel.mid deleted file mode 100644 index 8fc3d258..00000000 Binary files a/music/Learning/1_-_Very_Easy/The_First_Noel.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Turkey_in_the_Straw.mid b/music/Learning/1_-_Very_Easy/Turkey_in_the_Straw.mid deleted file mode 100644 index 49db0975..00000000 Binary files a/music/Learning/1_-_Very_Easy/Turkey_in_the_Straw.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Twinkle,_Twinkle,_Little_Star.mid b/music/Learning/1_-_Very_Easy/Twinkle,_Twinkle,_Little_Star.mid deleted file mode 100644 index 261f5c7a..00000000 Binary files a/music/Learning/1_-_Very_Easy/Twinkle,_Twinkle,_Little_Star.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/We_Gather_Together.mid b/music/Learning/1_-_Very_Easy/We_Gather_Together.mid deleted file mode 100644 index 7fadac72..00000000 Binary files a/music/Learning/1_-_Very_Easy/We_Gather_Together.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/We_Wish_You_a_Merry_Christmas.mid b/music/Learning/1_-_Very_Easy/We_Wish_You_a_Merry_Christmas.mid deleted file mode 100644 index db8360a1..00000000 Binary files a/music/Learning/1_-_Very_Easy/We_Wish_You_a_Merry_Christmas.mid and /dev/null differ diff --git a/music/Learning/1_-_Very_Easy/Yankee_Doodle.mid b/music/Learning/1_-_Very_Easy/Yankee_Doodle.mid deleted file mode 100644 index 3b9c32f5..00000000 Binary files a/music/Learning/1_-_Very_Easy/Yankee_Doodle.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/America,_the_Beautiful.mid b/music/Learning/2_-_Easy/America,_the_Beautiful.mid deleted file mode 100644 index 3124907c..00000000 Binary files a/music/Learning/2_-_Easy/America,_the_Beautiful.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Angels_We_Have_Heard_on_High.mid b/music/Learning/2_-_Easy/Angels_We_Have_Heard_on_High.mid deleted file mode 100644 index ac06510c..00000000 Binary files a/music/Learning/2_-_Easy/Angels_We_Have_Heard_on_High.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Beethoven_s_Fifth_Symphony.mid b/music/Learning/2_-_Easy/Beethoven_s_Fifth_Symphony.mid deleted file mode 100644 index fcb3fc9e..00000000 Binary files a/music/Learning/2_-_Easy/Beethoven_s_Fifth_Symphony.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Can_You_Plant_your_Cabbage_So.mid b/music/Learning/2_-_Easy/Can_You_Plant_your_Cabbage_So.mid deleted file mode 100644 index bb35e177..00000000 Binary files a/music/Learning/2_-_Easy/Can_You_Plant_your_Cabbage_So.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Chopsticks.mid b/music/Learning/2_-_Easy/Chopsticks.mid deleted file mode 100644 index d376108d..00000000 Binary files a/music/Learning/2_-_Easy/Chopsticks.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Do_Your_Ears_Hang_Low.mid b/music/Learning/2_-_Easy/Do_Your_Ears_Hang_Low.mid deleted file mode 100644 index 5559e0da..00000000 Binary files a/music/Learning/2_-_Easy/Do_Your_Ears_Hang_Low.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Fur_Elise.mid b/music/Learning/2_-_Easy/Fur_Elise.mid deleted file mode 100644 index 25af79ea..00000000 Binary files a/music/Learning/2_-_Easy/Fur_Elise.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Going_Home_-_Dvorak.mid b/music/Learning/2_-_Easy/Going_Home_-_Dvorak.mid deleted file mode 100644 index 0e69f372..00000000 Binary files a/music/Learning/2_-_Easy/Going_Home_-_Dvorak.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Have_You_Ever_Thought.mid b/music/Learning/2_-_Easy/Have_You_Ever_Thought.mid deleted file mode 100644 index 14e7ef94..00000000 Binary files a/music/Learning/2_-_Easy/Have_You_Ever_Thought.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/How_They_Dance,_Dance.mid b/music/Learning/2_-_Easy/How_They_Dance,_Dance.mid deleted file mode 100644 index 5684a628..00000000 Binary files a/music/Learning/2_-_Easy/How_They_Dance,_Dance.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/I_ve_Been_Working_on_the_Railroad.mid b/music/Learning/2_-_Easy/I_ve_Been_Working_on_the_Railroad.mid deleted file mode 100644 index 05f64d2a..00000000 Binary files a/music/Learning/2_-_Easy/I_ve_Been_Working_on_the_Railroad.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Jana-Gana-Mana.mid b/music/Learning/2_-_Easy/Jana-Gana-Mana.mid deleted file mode 100644 index 1280fb3c..00000000 Binary files a/music/Learning/2_-_Easy/Jana-Gana-Mana.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Jolly_Old_Saint_Nicholas.mid b/music/Learning/2_-_Easy/Jolly_Old_Saint_Nicholas.mid deleted file mode 100644 index 31e98965..00000000 Binary files a/music/Learning/2_-_Easy/Jolly_Old_Saint_Nicholas.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/La_Cucaracha.mid b/music/Learning/2_-_Easy/La_Cucaracha.mid deleted file mode 100644 index 743638dc..00000000 Binary files a/music/Learning/2_-_Easy/La_Cucaracha.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Lightly_Row.mid b/music/Learning/2_-_Easy/Lightly_Row.mid deleted file mode 100644 index 5f1125a0..00000000 Binary files a/music/Learning/2_-_Easy/Lightly_Row.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/O_Christmas_Tree.mid b/music/Learning/2_-_Easy/O_Christmas_Tree.mid deleted file mode 100644 index 59518568..00000000 Binary files a/music/Learning/2_-_Easy/O_Christmas_Tree.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Ode_to_Joy.mid b/music/Learning/2_-_Easy/Ode_to_Joy.mid deleted file mode 100644 index d09a79ed..00000000 Binary files a/music/Learning/2_-_Easy/Ode_to_Joy.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Oh,_When_the_Saints.mid b/music/Learning/2_-_Easy/Oh,_When_the_Saints.mid deleted file mode 100644 index 5c47d560..00000000 Binary files a/music/Learning/2_-_Easy/Oh,_When_the_Saints.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Oh_There_Was_Once_a_Little_Ship.mid b/music/Learning/2_-_Easy/Oh_There_Was_Once_a_Little_Ship.mid deleted file mode 100644 index 0ff366e3..00000000 Binary files a/music/Learning/2_-_Easy/Oh_There_Was_Once_a_Little_Ship.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Skip_to_my_Lou.mid b/music/Learning/2_-_Easy/Skip_to_my_Lou.mid deleted file mode 100644 index 443de587..00000000 Binary files a/music/Learning/2_-_Easy/Skip_to_my_Lou.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/Sonatina_Piccolina.mid b/music/Learning/2_-_Easy/Sonatina_Piccolina.mid deleted file mode 100644 index c43c221b..00000000 Binary files a/music/Learning/2_-_Easy/Sonatina_Piccolina.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/The_Muffin_Man.mid b/music/Learning/2_-_Easy/The_Muffin_Man.mid deleted file mode 100644 index e06e8203..00000000 Binary files a/music/Learning/2_-_Easy/The_Muffin_Man.mid and /dev/null differ diff --git a/music/Learning/2_-_Easy/The_Wheels_on_the_Bus.mid b/music/Learning/2_-_Easy/The_Wheels_on_the_Bus.mid deleted file mode 100644 index 0a7e55d0..00000000 Binary files a/music/Learning/2_-_Easy/The_Wheels_on_the_Bus.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/A_Mighty_Fortress_is_Our_God.mid b/music/Learning/3_-_Medium/A_Mighty_Fortress_is_Our_God.mid deleted file mode 100644 index 9dd7e519..00000000 Binary files a/music/Learning/3_-_Medium/A_Mighty_Fortress_is_Our_God.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/A_la_Claire_Fontaine.mid b/music/Learning/3_-_Medium/A_la_Claire_Fontaine.mid deleted file mode 100644 index 6dba42bf..00000000 Binary files a/music/Learning/3_-_Medium/A_la_Claire_Fontaine.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/America.mid b/music/Learning/3_-_Medium/America.mid deleted file mode 100644 index 53d330a3..00000000 Binary files a/music/Learning/3_-_Medium/America.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Au_Clair_de_la_Lune.mid b/music/Learning/3_-_Medium/Au_Clair_de_la_Lune.mid deleted file mode 100644 index e6bd5aa5..00000000 Binary files a/music/Learning/3_-_Medium/Au_Clair_de_la_Lune.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Bahay_Kubo_My_Palm_Leaf_Hut.mid b/music/Learning/3_-_Medium/Bahay_Kubo_My_Palm_Leaf_Hut.mid deleted file mode 100644 index 2276dfeb..00000000 Binary files a/music/Learning/3_-_Medium/Bahay_Kubo_My_Palm_Leaf_Hut.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Bridal_March.mid b/music/Learning/3_-_Medium/Bridal_March.mid deleted file mode 100644 index 4f5f2750..00000000 Binary files a/music/Learning/3_-_Medium/Bridal_March.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Eine_kleine_Nachtmusik.mid b/music/Learning/3_-_Medium/Eine_kleine_Nachtmusik.mid deleted file mode 100644 index 645280e1..00000000 Binary files a/music/Learning/3_-_Medium/Eine_kleine_Nachtmusik.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/God_Save_the_Queen.mid b/music/Learning/3_-_Medium/God_Save_the_Queen.mid deleted file mode 100644 index c37f97c3..00000000 Binary files a/music/Learning/3_-_Medium/God_Save_the_Queen.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Hanukkah,_Hanukkah.mid b/music/Learning/3_-_Medium/Hanukkah,_Hanukkah.mid deleted file mode 100644 index 7a671577..00000000 Binary files a/music/Learning/3_-_Medium/Hanukkah,_Hanukkah.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/In_My_Hot_Air_Balloon.mid b/music/Learning/3_-_Medium/In_My_Hot_Air_Balloon.mid deleted file mode 100644 index 2afb0d3e..00000000 Binary files a/music/Learning/3_-_Medium/In_My_Hot_Air_Balloon.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Jesu,_Joy_of_Man_s_Desiring.mid b/music/Learning/3_-_Medium/Jesu,_Joy_of_Man_s_Desiring.mid deleted file mode 100644 index 148ac05c..00000000 Binary files a/music/Learning/3_-_Medium/Jesu,_Joy_of_Man_s_Desiring.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Joy_to_the_World.mid b/music/Learning/3_-_Medium/Joy_to_the_World.mid deleted file mode 100644 index 9e326c5e..00000000 Binary files a/music/Learning/3_-_Medium/Joy_to_the_World.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Mexican_Hat_Dance.mid b/music/Learning/3_-_Medium/Mexican_Hat_Dance.mid deleted file mode 100644 index 18044a00..00000000 Binary files a/music/Learning/3_-_Medium/Mexican_Hat_Dance.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Morning_Song.mid b/music/Learning/3_-_Medium/Morning_Song.mid deleted file mode 100644 index be312912..00000000 Binary files a/music/Learning/3_-_Medium/Morning_Song.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/My_Bonnie_Lies_Over_the_Ocean_Long.mid b/music/Learning/3_-_Medium/My_Bonnie_Lies_Over_the_Ocean_Long.mid deleted file mode 100644 index 9fbf6e98..00000000 Binary files a/music/Learning/3_-_Medium/My_Bonnie_Lies_Over_the_Ocean_Long.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/My_Bonnie_Lies_over_the_Ocean.mid b/music/Learning/3_-_Medium/My_Bonnie_Lies_over_the_Ocean.mid deleted file mode 100644 index 329683b2..00000000 Binary files a/music/Learning/3_-_Medium/My_Bonnie_Lies_over_the_Ocean.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Ode_to_Joy.mid b/music/Learning/3_-_Medium/Ode_to_Joy.mid deleted file mode 100644 index 1b45af5c..00000000 Binary files a/music/Learning/3_-_Medium/Ode_to_Joy.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Oh_When_the_Saints.mid b/music/Learning/3_-_Medium/Oh_When_the_Saints.mid deleted file mode 100644 index 2363ccfa..00000000 Binary files a/music/Learning/3_-_Medium/Oh_When_the_Saints.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Old_MacDonald.mid b/music/Learning/3_-_Medium/Old_MacDonald.mid deleted file mode 100644 index 3c509470..00000000 Binary files a/music/Learning/3_-_Medium/Old_MacDonald.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Silent_Night.mid b/music/Learning/3_-_Medium/Silent_Night.mid deleted file mode 100644 index 65a965c6..00000000 Binary files a/music/Learning/3_-_Medium/Silent_Night.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Sur_le_Pont_d_Avignon.mid b/music/Learning/3_-_Medium/Sur_le_Pont_d_Avignon.mid deleted file mode 100644 index 6ec8e17f..00000000 Binary files a/music/Learning/3_-_Medium/Sur_le_Pont_d_Avignon.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/The_Ants_Go_Marching.mid b/music/Learning/3_-_Medium/The_Ants_Go_Marching.mid deleted file mode 100644 index f148c9fd..00000000 Binary files a/music/Learning/3_-_Medium/The_Ants_Go_Marching.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/The_Barn_Cat.mid b/music/Learning/3_-_Medium/The_Barn_Cat.mid deleted file mode 100644 index fa377bcf..00000000 Binary files a/music/Learning/3_-_Medium/The_Barn_Cat.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/The_Ghost_Of_Tom.mid b/music/Learning/3_-_Medium/The_Ghost_Of_Tom.mid deleted file mode 100644 index bc24b38b..00000000 Binary files a/music/Learning/3_-_Medium/The_Ghost_Of_Tom.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/The_Star-Spangled_Banner.mid b/music/Learning/3_-_Medium/The_Star-Spangled_Banner.mid deleted file mode 100644 index 8408f256..00000000 Binary files a/music/Learning/3_-_Medium/The_Star-Spangled_Banner.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/This_Old_Man.mid b/music/Learning/3_-_Medium/This_Old_Man.mid deleted file mode 100644 index 5ec7fd7a..00000000 Binary files a/music/Learning/3_-_Medium/This_Old_Man.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Toccata_and_Fugue_in_D_minor_-_intro.mid b/music/Learning/3_-_Medium/Toccata_and_Fugue_in_D_minor_-_intro.mid deleted file mode 100644 index 330b9ebc..00000000 Binary files a/music/Learning/3_-_Medium/Toccata_and_Fugue_in_D_minor_-_intro.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/We_Three_Kings.mid b/music/Learning/3_-_Medium/We_Three_Kings.mid deleted file mode 100644 index ac302e5f..00000000 Binary files a/music/Learning/3_-_Medium/We_Three_Kings.mid and /dev/null differ diff --git a/music/Learning/3_-_Medium/Ye_Knights_of_the_Round_Table.mid b/music/Learning/3_-_Medium/Ye_Knights_of_the_Round_Table.mid deleted file mode 100644 index 16bfab96..00000000 Binary files a/music/Learning/3_-_Medium/Ye_Knights_of_the_Round_Table.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Aupres_de_ma_Blonde.mid b/music/Learning/4_-_Hard/Aupres_de_ma_Blonde.mid deleted file mode 100644 index cbae7d3f..00000000 Binary files a/music/Learning/4_-_Hard/Aupres_de_ma_Blonde.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Ave_Maria.mid b/music/Learning/4_-_Hard/Ave_Maria.mid deleted file mode 100644 index 887720a1..00000000 Binary files a/music/Learning/4_-_Hard/Ave_Maria.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Beethoven_s_Fifth_Symphony.mid b/music/Learning/4_-_Hard/Beethoven_s_Fifth_Symphony.mid deleted file mode 100644 index bd3fe867..00000000 Binary files a/music/Learning/4_-_Hard/Beethoven_s_Fifth_Symphony.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Brahms__Lullaby.mid b/music/Learning/4_-_Hard/Brahms__Lullaby.mid deleted file mode 100644 index fd0abe81..00000000 Binary files a/music/Learning/4_-_Hard/Brahms__Lullaby.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Canon_in_D.mid b/music/Learning/4_-_Hard/Canon_in_D.mid deleted file mode 100644 index e18b8530..00000000 Binary files a/music/Learning/4_-_Hard/Canon_in_D.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Chinese_Folk_Song.mid b/music/Learning/4_-_Hard/Chinese_Folk_Song.mid deleted file mode 100644 index 3d3dc118..00000000 Binary files a/music/Learning/4_-_Hard/Chinese_Folk_Song.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Cripple_Creek.mid b/music/Learning/4_-_Hard/Cripple_Creek.mid deleted file mode 100644 index f52d4a8e..00000000 Binary files a/music/Learning/4_-_Hard/Cripple_Creek.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/God_Rest_Ye_Merry_Gentlemen.mid b/music/Learning/4_-_Hard/God_Rest_Ye_Merry_Gentlemen.mid deleted file mode 100644 index 3b359dee..00000000 Binary files a/music/Learning/4_-_Hard/God_Rest_Ye_Merry_Gentlemen.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/God_Save_the_Queen.mid b/music/Learning/4_-_Hard/God_Save_the_Queen.mid deleted file mode 100644 index 8c89bfaa..00000000 Binary files a/music/Learning/4_-_Hard/God_Save_the_Queen.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Hark!_The_Herald_Angels_Sing.mid b/music/Learning/4_-_Hard/Hark!_The_Herald_Angels_Sing.mid deleted file mode 100644 index 281c758b..00000000 Binary files a/music/Learning/4_-_Hard/Hark!_The_Herald_Angels_Sing.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Head,_Shoulders,_Knees_and_Toes.mid b/music/Learning/4_-_Hard/Head,_Shoulders,_Knees_and_Toes.mid deleted file mode 100644 index 1489b494..00000000 Binary files a/music/Learning/4_-_Hard/Head,_Shoulders,_Knees_and_Toes.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/In_a_Cabin_in_the_Woods.mid b/music/Learning/4_-_Hard/In_a_Cabin_in_the_Woods.mid deleted file mode 100644 index 010a0bd0..00000000 Binary files a/music/Learning/4_-_Hard/In_a_Cabin_in_the_Woods.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/La_Marseillaise.mid b/music/Learning/4_-_Hard/La_Marseillaise.mid deleted file mode 100644 index 4eb01a95..00000000 Binary files a/music/Learning/4_-_Hard/La_Marseillaise.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Lupang_Hinirang.mid b/music/Learning/4_-_Hard/Lupang_Hinirang.mid deleted file mode 100644 index fec6ba73..00000000 Binary files a/music/Learning/4_-_Hard/Lupang_Hinirang.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Moonlight_Sonata.mid b/music/Learning/4_-_Hard/Moonlight_Sonata.mid deleted file mode 100644 index 425efe05..00000000 Binary files a/music/Learning/4_-_Hard/Moonlight_Sonata.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/My_Grandfather_s_Clock.mid b/music/Learning/4_-_Hard/My_Grandfather_s_Clock.mid deleted file mode 100644 index 320f6152..00000000 Binary files a/music/Learning/4_-_Hard/My_Grandfather_s_Clock.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/O_Canada!.mid b/music/Learning/4_-_Hard/O_Canada!.mid deleted file mode 100644 index 6a24171b..00000000 Binary files a/music/Learning/4_-_Hard/O_Canada!.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Oh_Hanukah.mid b/music/Learning/4_-_Hard/Oh_Hanukah.mid deleted file mode 100644 index a479edf3..00000000 Binary files a/music/Learning/4_-_Hard/Oh_Hanukah.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Over_the_River_and_Through_the_Woods.mid b/music/Learning/4_-_Hard/Over_the_River_and_Through_the_Woods.mid deleted file mode 100644 index 01428ac7..00000000 Binary files a/music/Learning/4_-_Hard/Over_the_River_and_Through_the_Woods.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Sevivon,_Sov,_Sov,_Sov.mid b/music/Learning/4_-_Hard/Sevivon,_Sov,_Sov,_Sov.mid deleted file mode 100644 index fb23fc14..00000000 Binary files a/music/Learning/4_-_Hard/Sevivon,_Sov,_Sov,_Sov.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Shuha_D-Maryam.mid b/music/Learning/4_-_Hard/Shuha_D-Maryam.mid deleted file mode 100644 index 3d6a5a5f..00000000 Binary files a/music/Learning/4_-_Hard/Shuha_D-Maryam.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Sonatina_in_G.mid b/music/Learning/4_-_Hard/Sonatina_in_G.mid deleted file mode 100644 index f7d9ed66..00000000 Binary files a/music/Learning/4_-_Hard/Sonatina_in_G.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Swing_Low,_Sweet_Chariot.mid b/music/Learning/4_-_Hard/Swing_Low,_Sweet_Chariot.mid deleted file mode 100644 index 30e446f2..00000000 Binary files a/music/Learning/4_-_Hard/Swing_Low,_Sweet_Chariot.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/The_Entertainer.mid b/music/Learning/4_-_Hard/The_Entertainer.mid deleted file mode 100644 index 532b7832..00000000 Binary files a/music/Learning/4_-_Hard/The_Entertainer.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/The_First_Noel.mid b/music/Learning/4_-_Hard/The_First_Noel.mid deleted file mode 100644 index 4535c4a9..00000000 Binary files a/music/Learning/4_-_Hard/The_First_Noel.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/The_Yellow_Rose_of_Texas.mid b/music/Learning/4_-_Hard/The_Yellow_Rose_of_Texas.mid deleted file mode 100644 index f9ec69d8..00000000 Binary files a/music/Learning/4_-_Hard/The_Yellow_Rose_of_Texas.mid and /dev/null differ diff --git a/music/Learning/4_-_Hard/Waltzing_Matilda.mid b/music/Learning/4_-_Hard/Waltzing_Matilda.mid deleted file mode 100644 index 67a30790..00000000 Binary files a/music/Learning/4_-_Hard/Waltzing_Matilda.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Amazing_Grace.mid b/music/Learning/5_-_Harder/Amazing_Grace.mid deleted file mode 100644 index 83b7164c..00000000 Binary files a/music/Learning/5_-_Harder/Amazing_Grace.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Big_Bad_Goblin_Blues.mid b/music/Learning/5_-_Harder/Big_Bad_Goblin_Blues.mid deleted file mode 100644 index 17dc3482..00000000 Binary files a/music/Learning/5_-_Harder/Big_Bad_Goblin_Blues.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Carribean_Cruise.mid b/music/Learning/5_-_Harder/Carribean_Cruise.mid deleted file mode 100644 index 794107e4..00000000 Binary files a/music/Learning/5_-_Harder/Carribean_Cruise.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Danny_Boy.mid b/music/Learning/5_-_Harder/Danny_Boy.mid deleted file mode 100644 index c97884bf..00000000 Binary files a/music/Learning/5_-_Harder/Danny_Boy.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Evening_Falls.mid b/music/Learning/5_-_Harder/Evening_Falls.mid deleted file mode 100644 index dfc95de6..00000000 Binary files a/music/Learning/5_-_Harder/Evening_Falls.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Greensleeves.mid b/music/Learning/5_-_Harder/Greensleeves.mid deleted file mode 100644 index b424fe73..00000000 Binary files a/music/Learning/5_-_Harder/Greensleeves.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Habanera_from_Carmen.mid b/music/Learning/5_-_Harder/Habanera_from_Carmen.mid deleted file mode 100644 index 3abc14cd..00000000 Binary files a/music/Learning/5_-_Harder/Habanera_from_Carmen.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Jana-Gana-Mana.mid b/music/Learning/5_-_Harder/Jana-Gana-Mana.mid deleted file mode 100644 index 0aaa6e46..00000000 Binary files a/music/Learning/5_-_Harder/Jana-Gana-Mana.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/March_on_Android_Moon.mid b/music/Learning/5_-_Harder/March_on_Android_Moon.mid deleted file mode 100644 index eec04869..00000000 Binary files a/music/Learning/5_-_Harder/March_on_Android_Moon.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Moonlight_Sonata.mid b/music/Learning/5_-_Harder/Moonlight_Sonata.mid deleted file mode 100644 index 10f5faa2..00000000 Binary files a/music/Learning/5_-_Harder/Moonlight_Sonata.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Once_a_Canadian_Lad.mid b/music/Learning/5_-_Harder/Once_a_Canadian_Lad.mid deleted file mode 100644 index 326e292d..00000000 Binary files a/music/Learning/5_-_Harder/Once_a_Canadian_Lad.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Rock_Solid_Blues.mid b/music/Learning/5_-_Harder/Rock_Solid_Blues.mid deleted file mode 100644 index 16af772b..00000000 Binary files a/music/Learning/5_-_Harder/Rock_Solid_Blues.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/See_How_the_Night_Arrives.mid b/music/Learning/5_-_Harder/See_How_the_Night_Arrives.mid deleted file mode 100644 index 16a50ae2..00000000 Binary files a/music/Learning/5_-_Harder/See_How_the_Night_Arrives.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/The_Four_Seasons_-_Autumn.mid b/music/Learning/5_-_Harder/The_Four_Seasons_-_Autumn.mid deleted file mode 100644 index a78126b2..00000000 Binary files a/music/Learning/5_-_Harder/The_Four_Seasons_-_Autumn.mid and /dev/null differ diff --git a/music/Learning/5_-_Harder/Toreador_from_Carmen.mid b/music/Learning/5_-_Harder/Toreador_from_Carmen.mid deleted file mode 100644 index 1bfc24a3..00000000 Binary files a/music/Learning/5_-_Harder/Toreador_from_Carmen.mid and /dev/null differ diff --git a/music/Learning/G_Major_Music.txt b/music/Learning/G_Major_Music.txt deleted file mode 100644 index f68f8bc7..00000000 --- a/music/Learning/G_Major_Music.txt +++ /dev/null @@ -1,5 +0,0 @@ -All of these songs are from the G Major Music Theory "Free Piano Music!" page. - -Go to www.gmajormusictheory.org to find more. - -There are new beginner pieces being added all the time, another set of intermediate pieces, and printable sheet music for all of it! diff --git a/music/Popular/Gymnopedie.mid b/music/Popular/Gymnopedie.mid deleted file mode 100644 index 95ebc61b..00000000 Binary files a/music/Popular/Gymnopedie.mid and /dev/null differ diff --git a/music/Popular/Jonh_Lennon_-_Imagine.mid b/music/Popular/Jonh_Lennon_-_Imagine.mid deleted file mode 100644 index 3cef910a..00000000 Binary files a/music/Popular/Jonh_Lennon_-_Imagine.mid and /dev/null differ diff --git a/scripts/Makefile.am b/scripts/Makefile.am deleted file mode 100644 index a5a5078e..00000000 --- a/scripts/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -dist_bin_SCRIPTS = delay_screensaver.sh diff --git a/scripts/delay_screensaver.sh b/scripts/delay_screensaver.sh deleted file mode 100755 index dbaab235..00000000 --- a/scripts/delay_screensaver.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -# Original idea from https://github.com/iye/lightsOn/blob/master/lightsOn.sh - -# Detect screensaver been used (xscreensaver, kscreensaver or none) - screensaver=$(pgrep -l xscreensaver | grep -wc xscreensaver) -if [ $screensaver -ge 1 ]; then - screensaver=xscreensaver -else - screensaver=$(pgrep -l kscreensaver | grep -wc kscreensaver) - if [ $screensaver -ge 1 ]; then - screensaver=kscreensaver - else - screensaver=None - fi -fi - -# reset inactivity time counter so screensaver is not started -if [ "$screensaver" == "xscreensaver" ]; then - xscreensaver-command -deactivate > /dev/null -elif [ "$screensaver" == "kscreensaver" ]; then - simulate=true -fi - -# SimulateUserActivity disables auto screen dimming in KDE4 -if [ "$KDE_FULL_SESSION" == true ]; then - simulate=true -fi - -if [ "$simulate" == true ]; then - qdbus org.freedesktop.ScreenSaver /ScreenSaver SimulateUserActivity > /dev/null -fi - -# Check if DPMS is on. If it is, deactivate and reactivate again. If it is not, do nothing. -dpmsStatus=$(xset -q | grep -ce 'DPMS is Enabled') -if [ $dpmsStatus == 1 ]; then - xset -dpms - xset +dpms -fi - -# Move the mouse http://xkcd.com/196/ -#xte 'mousermove 1 1' diff --git a/src/CompatibleSystem.cpp b/src/CompatibleSystem.cpp deleted file mode 100644 index 7d6fc4f7..00000000 --- a/src/CompatibleSystem.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include -#include - -#include "MidiComm.h" -#include "CompatibleSystem.h" -#include "StringUtil.h" -#include "Version.h" - -using namespace std; - -namespace Compatible { - - unsigned long GetMilliseconds() { - - timeval tv; - gettimeofday(&tv, 0); - return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); - } - - - void ShowError(const string &err) { - - const static string friendly_app_name = - STRING("Neothesia " << NeothesiaVersionString); - const static string message_box_title = - STRING(friendly_app_name << " Error"); - - Gtk::MessageDialog dialog(err, false, Gtk::MESSAGE_ERROR); - dialog.run(); - } - - void HideMouseCursor() { - // TODO - } - - void ShowMouseCursor() { - // TODO - } - - void GetDisplayRect(Gdk::Rectangle &rect) { - static bool inited = false; - static Gdk::Rectangle monitor_geometry; - - if (!inited) { - auto display = Gdk::Display::get_default(); - - int pointer_x, pointer_y; - Gdk::ModifierType pointer_mask; - display->get_pointer(pointer_x, pointer_y, pointer_mask); - - auto screen = display->get_default_screen(); - - screen->get_monitor_geometry( - screen->get_monitor_at_point(pointer_x, pointer_y), - monitor_geometry - ); - inited = true; - } - rect = monitor_geometry; - } - - int GetDisplayLeft() { - Gdk::Rectangle rect; - GetDisplayRect(rect); - return rect.get_x(); - } - - int GetDisplayTop() { - Gdk::Rectangle rect; - GetDisplayRect(rect); - return rect.get_y(); - } - - int GetDisplayWidth() { - Gdk::Rectangle rect; - GetDisplayRect(rect); - return rect.get_width(); - } - - int GetDisplayHeight() { - Gdk::Rectangle rect; - GetDisplayRect(rect); - return rect.get_height(); - } - - void GracefulShutdown() { - midiStop(); - Gtk::Main::instance()->quit(); - } - -}; // End namespace diff --git a/src/CompatibleSystem.h b/src/CompatibleSystem.h deleted file mode 100644 index c305c2ff..00000000 --- a/src/CompatibleSystem.h +++ /dev/null @@ -1,35 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __COMPATIBLE_SYSTEM_H -#define __COMPATIBLE_SYSTEM_H - -#include - -namespace Compatible { - - // Some monotonically increasing value tied to the system - // clock (but not necessarily based on app-start) - unsigned long GetMilliseconds(); - - // Shows an error box with an OK button - void ShowError(const std::string &err); - - int GetDisplayLeft(); - int GetDisplayTop(); - int GetDisplayWidth(); - int GetDisplayHeight(); - - void HideMouseCursor(); - void ShowMouseCursor(); - - // Send a message to terminate the application loop gracefully - void GracefulShutdown(); -}; - -#endif // __COMPATIBLE_SYSTEM_H diff --git a/src/DeviceTile.cpp b/src/DeviceTile.cpp deleted file mode 100644 index 7ceb1f43..00000000 --- a/src/DeviceTile.cpp +++ /dev/null @@ -1,168 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "DeviceTile.h" -#include "TextWriter.h" -#include "Renderer.h" -#include "Tga.h" - -const static int GraphicWidth = 36; -const static int GraphicHeight = 36; - -DeviceTile::DeviceTile(int x, int y, int device_id, DeviceTileType type, - const MidiCommDescriptionList &device_list, - Tga *button_graphics, Tga *frame_graphics) : - m_x(x), - m_y(y), - m_preview_on(false), - m_device_id(device_id), - m_device_list(device_list), - m_tile_type(type), - m_button_graphics(button_graphics), - m_frame_graphics(frame_graphics) { - - // Initialize the size and position of each button - whole_tile = ButtonState(0, 0, DeviceTileWidth, DeviceTileHeight); - button_mode_left = ButtonState( 6, 38, GraphicWidth, GraphicHeight); - button_mode_right = ButtonState(428, 38, GraphicWidth, GraphicHeight); - button_preview = ButtonState(469, 38, GraphicWidth, GraphicHeight); -} - -void DeviceTile::Update(const MouseInfo &translated_mouse) { - - // Update the mouse state of each button - whole_tile.Update(translated_mouse); - button_preview.Update(translated_mouse); - button_mode_left.Update(translated_mouse); - button_mode_right.Update(translated_mouse); - - if (m_device_list.size() > 0) { - const int last_device = static_cast(m_device_list.size() - 1); - - if (button_mode_left.hit) { - if (m_device_id == -1) - m_device_id = last_device; - - else - --m_device_id; - } - - if (button_mode_right.hit) { - if (m_device_id == last_device) - m_device_id = -1; - - else - ++m_device_id; - } - } - - if (button_preview.hit) - m_preview_on = !m_preview_on; -} - -int DeviceTile::LookupGraphic(TrackTileGraphic graphic, bool button_hovering) const { - - // There are three sets of graphics - // set 0: window lit, hovering - // set 1: window lit, not-hovering - // set 2: window unlit, (implied not-hovering) - int graphic_set = 2; - if (whole_tile.hovering) - graphic_set--; - - if (button_hovering) - graphic_set--; - - const int set_offset = GraphicWidth * Graphic_COUNT; - const int graphic_offset = GraphicWidth * graphic; - - return (set_offset * graphic_set) + graphic_offset; -} - -void DeviceTile::Draw(Renderer &renderer) const { - - renderer.SetOffset(m_x, m_y); - - const Color hover = Renderer::ToColor(0xFF,0xFF,0xFF); - const Color no_hover = Renderer::ToColor(0xE0,0xE0,0xE0); - renderer.SetColor(whole_tile.hovering ? hover : no_hover); - renderer.DrawTga(m_frame_graphics, 0, 0); - - // Choose the last (gray) color in the TrackTile bitmap - int color_offset = GraphicHeight * Track::UserSelectableColorCount; - - renderer.DrawTga(m_button_graphics, BUTTON_RECT(button_mode_left), - LookupGraphic(GraphicLeftArrow, button_mode_left.hovering), - color_offset); - - renderer.DrawTga(m_button_graphics, BUTTON_RECT(button_mode_right), - LookupGraphic(GraphicRightArrow, button_mode_right.hovering), - color_offset); - - TrackTileGraphic preview_graphic = GraphicPreviewTurnOn; - if (m_preview_on) - preview_graphic = GraphicPreviewTurnOff; - - renderer.DrawTga(m_button_graphics, BUTTON_RECT(button_preview), - LookupGraphic(preview_graphic, button_preview.hovering), - color_offset); - - // Draw mode text - TextWriter mode(44, 49, renderer, false, 14); - if (m_device_list.size() == 0) - mode << "[No Devices Found]"; - - else { - - // A -1 for device_id means "disabled" - if (m_device_id >= 0) - mode << m_device_list[m_device_id].name; - - else { - switch (m_tile_type) { - case DeviceTileOutput: - mode << "[Output Off: Display only with no audio]"; - break; - - case DeviceTileInput: - mode << "[Input Off: Play along with no scoring]"; - break; - } - } - } - - renderer.ResetOffset(); -} - -void DeviceTile::ReplaceDeviceList(const MidiCommDescriptionList &device_list) -{ - if (m_device_id != -1) - { - // Try to find currently selected device amoung devices in the new list - std::string current_name = m_device_list[m_device_id].name; - int device_id = 0; - bool replaced = false; - int size = device_list.size(); - for (; device_id < size; device_id++) - { - std::string iter_name = device_list[device_id].name; - if (current_name == iter_name) - { - // Found device - m_device_id = device_id; - replaced = true; - break; - } - } - // The selected device was removed - if (!replaced) - m_device_id = -1; - } - m_device_list = device_list; -} - diff --git a/src/DeviceTile.h b/src/DeviceTile.h deleted file mode 100644 index ac21e712..00000000 --- a/src/DeviceTile.h +++ /dev/null @@ -1,106 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __DEVICE_TILE_H -#define __DEVICE_TILE_H - -#include "GameState.h" -#include "MenuLayout.h" -#include "TrackTile.h" -#include - -#include "libmidi/Midi.h" -#include "MidiComm.h" - -const int DeviceTileWidth = 510; -const int DeviceTileHeight = 80; - -enum TrackTileGraphic; - -enum DeviceTileType { - - DeviceTileOutput, - DeviceTileInput -}; - -class DeviceTile { -public: - - DeviceTile(int x, int y, int device_id, - DeviceTileType type, const MidiCommDescriptionList &device_list, - Tga *button_graphics, Tga *frame_graphics); - - void Update(const MouseInfo &translated_mouse); - void Draw(Renderer &renderer) const; - void ReplaceDeviceList(const MidiCommDescriptionList &device_list); - - int GetX() const { - return m_x; - } - - int GetY() const { - return m_y; - } - - bool HitPreviewButton() const { - return button_preview.hit; - } - - bool IsPreviewOn() const { - return m_preview_on; - } - - void TurnOffPreview() { - m_preview_on = false; - } - - int GetDeviceId() const { - return m_device_id; - } - - const ButtonState WholeTile() const { - return whole_tile; - } - - const ButtonState ButtonPreview() const { - return button_preview; - } - - const ButtonState ButtonLeft() const { - return button_mode_left; - } - - const ButtonState ButtonRight() const { - return button_mode_right; - } - -private: - DeviceTile operator=(const DeviceTile &); - - int m_x; - int m_y; - - bool m_preview_on; - int m_device_id; - - MidiCommDescriptionList m_device_list; - - DeviceTileType m_tile_type; - - Tga *m_button_graphics; - Tga *m_frame_graphics; - - ButtonState whole_tile; - ButtonState button_preview; - ButtonState button_mode_left; - ButtonState button_mode_right; - - int LookupGraphic(TrackTileGraphic graphic, bool button_hovering) const; -}; - -#endif // __DEVICE_TILE_H diff --git a/src/DpmsThread.h b/src/DpmsThread.h deleted file mode 100644 index cf95515b..00000000 --- a/src/DpmsThread.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __DPMS_THREAD_H -#define __DPMS_THREAD_H - -#include -#include -#include -#include -#include - -#ifndef SCRIPTDIR -#define SCRIPTDIR "../scripts" -#endif - -class DpmsThread -{ - std::atomic m_is_keyboard_active{false}; - std::atomic m_should_exit{false}; - std::condition_variable m_should_exit_cv; - std::mutex m_should_exit_cv_m; - std::string m_delay_screensaver_cmd; - - std::thread m_thread; - - void run() - { - while (!m_should_exit) - { - // Required for wait_for - std::unique_lock cv_lock(m_should_exit_cv_m); - - // Sleep for 5 seconds or until program exit - // std::condition_variable::wait_for unlocks mutex - if (std::cv_status::no_timeout == - m_should_exit_cv.wait_for(cv_lock, std::chrono::seconds(5))) - // Handle exit (m_should_exit == true) - continue; - - if (m_is_keyboard_active == false) - // no activity - continue; - - // Handle timeout - delayScreensaver(); - - // Reset value - m_is_keyboard_active.store(false); - } - } - - void delayScreensaver() - { - system(m_delay_screensaver_cmd.c_str()); - } - - public: - DpmsThread() : - m_thread(&DpmsThread::run, this), - m_delay_screensaver_cmd(std::string(SCRIPTDIR) + "/delay_screensaver.sh") - { - } - - ~DpmsThread() - { - m_should_exit.store(true); - m_should_exit_cv.notify_all(); - m_thread.join(); - } - - void handleKeyPress() - { - m_is_keyboard_active.store(true); - } -}; - -#endif // __DPMS_THREAD_H diff --git a/src/FileSelector.cpp b/src/FileSelector.cpp deleted file mode 100644 index 074f4d9d..00000000 --- a/src/FileSelector.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include -#include - -#include "LinthesiaError.h" -#include "FileSelector.h" -#include "UserSettings.h" -#include "StringUtil.h" - -using namespace std; - -const static char PathDelimiter = '/'; - -namespace FileSelector { - - void RequestMidiFilename(string *returned_filename, - string *returned_file_title) { - - // Grab the filename of the last song we played - // and pre-load it into the open dialog - string last_filename = UserSetting::Get("last_file", ""); - - Gtk::FileChooserDialog dialog("Linthesia: Choose a MIDI song to play"); - dialog.add_button(Gtk::StockID("gtk-open"), Gtk::RESPONSE_ACCEPT); - dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); - - // Try to populate our "File Open" box with the last file selected - if (!last_filename.empty()) - dialog.set_filename(last_filename); - - // If there wasn't a last file, default to the built-in Music directory - else { - string default_dir = UserSetting::Get("default_music_directory", ""); - dialog.set_current_folder(default_dir); - } - - // Set file filters - Gtk::FileFilter filter_midi; - filter_midi.set_name("MIDI files (*.mid, *.midi)"); - filter_midi.add_pattern("*.mid"); - filter_midi.add_pattern("*.midi"); - dialog.add_filter(filter_midi); - - Gtk::FileFilter filter_all; - filter_all.set_name("All files (*.*)"); - filter_all.add_pattern("*.*"); - dialog.add_filter(filter_all); - - int response = dialog.run(); - switch (response) { - case Gtk::RESPONSE_ACCEPT: - - string filename = dialog.get_filename(); - SetLastMidiFilename(filename); - - if (returned_file_title) - *returned_file_title = filename.substr(filename.rfind(PathDelimiter)+1); - - if (returned_filename) - *returned_filename = filename; - - return; - } - - if (returned_file_title) - *returned_file_title = ""; - - if (returned_filename) - *returned_filename = ""; - } - - void SetLastMidiFilename(const string &filename) { - UserSetting::Set("last_file", filename); - } - - string TrimFilename(const string &filename) { - - // lowercase - string lower = StringLower(filename); - - // remove extension, if known - set exts; - exts.insert(".mid"); - exts.insert(".midi"); - for (set::const_iterator i = exts.begin(); i != exts.end(); i++) { - int len = i->length(); - if (lower.substr(lower.length() - len, len) == *i) - lower = lower.substr(0, lower.length() - len); - } - - // remove path - string::size_type i = lower.find_last_of("/"); - if (i != string::npos) - lower = lower.substr(i+1, lower.length()); - - return lower; - } - -}; // End namespace diff --git a/src/FileSelector.h b/src/FileSelector.h deleted file mode 100644 index b7dc303c..00000000 --- a/src/FileSelector.h +++ /dev/null @@ -1,29 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __FILE_SELECTOR_H -#define __FILE_SELECTOR_H - -#include - -namespace FileSelector { - - // Presents a standard "File Open" dialog box. Returns empty string - // in [filename] if user presses cancel. Also, remembers last filename - void RequestMidiFilename(std::string *filename, std::string *file_title); - - // If a filename was passed in on the command line, we - // can remember it for future file-open dialogs - void SetLastMidiFilename(const std::string &filename); - - // Returns a filename with no path or .mid/.midi extension - std::string TrimFilename(const std::string &filename); -}; - -#endif // __FILE_SELECTOR_H - diff --git a/src/FrameCounter.h b/src/FrameCounter.h deleted file mode 100644 index 9b817fbe..00000000 --- a/src/FrameCounter.h +++ /dev/null @@ -1,54 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __FRAME_COUNTER_H -#define __FRAME_COUNTER_H - -class FrameCounter { -public: - - // averaged_over_milliseconds is the length of time GetFramesPerSecond - // should average the frame count over in order to smooth the rate. - FrameCounter(double averaged_over_milliseconds) : - m_average_over_ms(averaged_over_milliseconds), - m_period_ms(0), - m_frames(0), - m_cached_fps(0) { - - if (m_average_over_ms <= 50.0) m_average_over_ms = 50.0; - } - - void Frame(double delta_ms) { - - if (delta_ms < 0.0) - return; - - m_period_ms += delta_ms; - m_frames++; - - if (m_period_ms > m_average_over_ms) { - m_cached_fps = static_cast(m_frames) / m_period_ms * 1000.0; - - m_frames = 0; - m_period_ms = 0; - } - } - - double GetFramesPerSecond() const { - return m_cached_fps; - } - -private: - double m_average_over_ms; - double m_period_ms; - int m_frames; - - double m_cached_fps; -}; - -#endif // __FRAME_COUNTER_H diff --git a/src/GameState.cpp b/src/GameState.cpp deleted file mode 100644 index 6ad874d0..00000000 --- a/src/GameState.cpp +++ /dev/null @@ -1,303 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "GameState.h" -#include "Renderer.h" -#include "Textures.h" -#include "CompatibleSystem.h" -#include "Tga.h" -#include "OSGraphics.h" - -// For FPS display -#include "TextWriter.h" -#include - -using namespace std; - -// only used on here -const static char* TextureResourceNames[_TextureEnumCount] = { - - "title_Logo", - "InterfaceButtons", - "title_GameMusicThemes", - - "score_RetrySong", - "title_ChooseTracks", - "title_Exit", - "tracks_BackToTitle", - "tracks_PlaySong", - - "title_InputBox", - "title_OutputBox", - "title_SongBox", - - "trackbox", // TrackPanel - - "stats_text", - - "play_Status", - "play_Status2", - "play_Keys", - - "play_NotesBlackColor", - "play_NotesBlackShadow", - "play_NotesWhiteColor", - "play_NotesWhiteShadow", - - "play_KeyRail", - "play_KeyShadow", - "play_KeysBlack", - "play_KeysWhite" -}; - -Tga *GameState::GetTexture(Texture tex_name, bool smooth) const { - - if (!m_manager) - throw GameStateError("Cannot retrieve texture if manager not set!"); - - return m_manager->GetTexture(tex_name, smooth); -} - -void GameState::ChangeState(GameState *new_state) { - - if (!m_manager) - throw GameStateError("Cannot change state if manager not set!"); - - m_manager->ChangeState(new_state); -} - -int GameState::GetStateWidth() const { - - if (!m_manager) - throw GameStateError("Cannot retrieve state width if manager not set!"); - - return m_manager->GetStateWidth(); -} - -int GameState::GetStateHeight() const { - - if (!m_manager) - throw GameStateError("Cannot retrieve state height if manager not set!"); - - return m_manager->GetStateHeight(); -} - -bool GameState::IsKeyPressed(GameKey key) const { - - if (!m_manager) - throw GameStateError("Cannot determine key presses if manager not set!"); - - return m_manager->IsKeyPressed(key); -} - -const MouseInfo &GameState::Mouse() const { - - if (!m_manager) - throw GameStateError("Cannot determine mouse input if manager not set!"); - - return m_manager->Mouse(); -} - -void GameState::SetManager(GameStateManager *manager) { - - if (m_manager) - throw GameStateError("State already has a manager!"); - - m_manager = manager; - Init(); -} - - -GameStateManager::~GameStateManager() { - - for (map::iterator i = m_textures.begin(); - i != m_textures.end(); ++i) { - - if (i->second) Tga::Release(i->second); - i->second = 0; - } -} - -Tga *GameStateManager::GetTexture(Texture tex_name, bool smooth) const { - - if (!m_textures[tex_name]) - m_textures[tex_name] = Tga::Load(TextureResourceNames[tex_name]); - - m_textures[tex_name]->SetSmooth(smooth); - return m_textures[tex_name]; -} - -void GameStateManager::KeyPress(GameKey key) { - - m_key_presses |= static_cast(key); -} - -bool GameStateManager::IsKeyPressed(GameKey key) const { - - return ( (m_key_presses & static_cast(key)) != 0); -} - -bool GameStateManager::IsKeyReleased(GameKey key) const { - return (!IsKeyPressed(key) && - ((m_last_key_presses & static_cast(key)) != 0)); -} - -void GameStateManager::MousePress(MouseButton button) { - - switch (button) { - case MouseLeft: - m_mouse.held.left = true; - m_mouse.released.left = false; - m_mouse.newPress.left = true; - break; - - case MouseRight: - m_mouse.held.right = true; - m_mouse.released.right = false; - m_mouse.newPress.right = true; - break; - } -} - -void GameStateManager::MouseRelease(MouseButton button) { - - switch (button) { - case MouseLeft: - m_mouse.held.left = false; - m_mouse.released.left = true; - m_mouse.newPress.left = false; - break; - - case MouseRight: - m_mouse.held.right = false; - m_mouse.released.right = true; - m_mouse.newPress.right = false; - break; - } -} - -void GameStateManager::MouseMove(int x, int y) { - - m_mouse.x = x; - m_mouse.y = y; -} - -void GameStateManager::SetInitialState(GameState *first_state) { - - if (m_current_state) - throw GameStateError("Cannot set an initial state because GameStateManager" - " already has a state!"); - - first_state->SetManager(this); - m_current_state = first_state; -} - -void GameStateManager::ChangeState(GameState *new_state) { - - if (!m_current_state) - throw GameStateError("Cannot change state without a state! " - "Use SetInitialState()!"); - - if (!new_state) - throw GameStateError("Cannot change to a null state!"); - - if (!m_inside_update) - throw GameStateError("ChangeState must be called from inside another " - "state's Update() function! (This is so we can " - "guarantee the ordering of the draw/update calls.)"); - - m_next_state = new_state; -} - -void GameStateManager::Update(bool skip_this_update) { - - // Manager's timer grows constantly - const unsigned long now = Compatible::GetMilliseconds(); - const unsigned long delta = now - m_last_milliseconds; - m_last_milliseconds = now; - - // Now that we've updated the time, we can return if - // we've been told to skip this one. - if (skip_this_update) - return; - - m_fps.Frame(delta); - if (IsKeyReleased(KeyF6)) - m_show_fps = !m_show_fps; - - if (m_next_state && m_current_state) { - - delete m_current_state; - m_current_state = 0; - - // We return here to insert a blank frame (that may or may - // not last a long time) while the next state's Init() - // and first Update() are being called. - return; - } - - if (m_next_state) { - - m_current_state = m_next_state; - m_next_state = 0; - - m_current_state->SetManager(this); - } - - if (!m_current_state) - return; - - m_inside_update = true; - - m_current_state->m_last_delta_milliseconds = delta; - m_current_state->m_state_milliseconds += delta; - m_current_state->Update(); - - m_inside_update = false; - - // Reset our keypresses for the next frame - m_last_key_presses = m_key_presses; - m_key_presses = 0; - - // Reset our mouse clicks for the next frame - m_mouse.newPress = MouseButtons(); - m_mouse.released = MouseButtons(); -} - -void GameStateManager::Draw(Renderer &renderer) { - - if (!m_current_state) - return; - - // NOTE: Sweet transition effects are *very* possible here... rendering - // the previous state *and* the current state during some transition - // would be really easy. - - // const static float gray = 32.0f / 255.0f; - const static float gray = 32.0f / 255.0f; - glClearColor(gray, gray, gray, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0., static_cast(GetStateHeight()), 0.); - glScalef (1., -1., 1.); - glTranslatef(0.375, 0.375, 0.); - - m_current_state->Draw(renderer); - - if (m_show_fps) { - TextWriter fps_writer(0, 0, renderer); - fps_writer << Text("FPS: ", Gray) << - Text(STRING(setprecision(6) << m_fps.GetFramesPerSecond()), White); - } - - glFlush (); - renderer.SwapBuffers(); -} - diff --git a/src/GameState.h b/src/GameState.h deleted file mode 100644 index fd01ac3b..00000000 --- a/src/GameState.h +++ /dev/null @@ -1,245 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __GAMESTATE_H -#define __GAMESTATE_H - -#include -#include -#include - -#include "Textures.h" -#include "CompatibleSystem.h" -#include "FrameCounter.h" -#include "Renderer.h" - -class GameStateError : public std::exception { -public: - - GameStateError(const std::string &error) throw() : - m_error(error) { - } - - virtual const char *what() const throw() { - return m_error.c_str(); - } - - ~GameStateError() throw() { - } - -private: - - const std::string m_error; - - GameStateError operator=(const GameStateError&); -}; - -class GameStateManager; - -enum GameKey { - - // Magic numbers (used in this app only) - // Key combinations are packed into "unsigned integer" - // So, each key should set its own bit - KeySpace = 0x0001, // 0 - KeyEscape = 0x0002, // 10 - KeyUp = 0x0004, // 100 and so on - KeyDown = 0x0008, - KeyLeft = 0x0010, - KeyRight = 0x0020, - KeyEnter = 0x0040, - - KeyF6 = 0x0080, - - KeyGreater = 0x0100, - KeyLess = 0x0200, - - KeyForward = 0x0400, - KeyBackward = 0x0800, - - KeyVolumeUp = 0x1000, - KeyVolumeDown = 0x2000 - - // = 0x4000 - // = 0x8000 -}; - -enum MouseButton { - - MouseLeft, - MouseRight -}; - -struct MouseButtons { - - MouseButtons() : - left(false), right(false) { - } - - bool left; - bool right; -}; - -struct MouseInfo { - - MouseInfo() : - x(0), y(0) { - } - - int x; - int y; - - MouseButtons held; - MouseButtons newPress; - MouseButtons released; -}; - -class GameState { -public: - - // Don't initialize anything that is dependent - // on the protected functions (GetStateWidth, - // GetStateMilliseconds, etc) here. Wait until - // Init() to do that. - GameState() : - m_manager(0), - m_state_milliseconds(0), - m_last_delta_milliseconds(0) { - } - - virtual ~GameState() { - } - -protected: - - // This is called just after the state's manager - // is set for the first time - virtual void Init() = 0; - - // Called every frame - virtual void Update() = 0; - - // Called each frame. Drawing bounds are [0, - // GetStateWidth()) and [0, GetStateHeight()) - virtual void Draw(Renderer &renderer) const = 0; - - // How long has this state been running - unsigned long GetStateMilliseconds() const { - return m_state_milliseconds; - } - - // How much time elapsed since the last update - unsigned long GetDeltaMilliseconds() const { - return m_last_delta_milliseconds; - } - - int GetStateWidth() const; - int GetStateHeight() const; - - // Once finished executing, use this to change - // state to something new. This can only be - // called from inside Update(). After calling - // this function, you're guaranteed that the only - // function that will still be called (before - // the destructor) is Draw(). You *must* be able - // to continue supporting Draw() after you call - // this function. - // - // new_state *must* be dynamically allocated and - // by calling this function you hand off ownership - // of the memory to the state handling subsystem. - void ChangeState(GameState *new_state); - - Tga *GetTexture(Texture tex_name, bool smooth = false) const; - - // These are usable inside Update() - bool IsKeyPressed(GameKey key) const; - const MouseInfo &Mouse() const; - -private: - - void SetManager(GameStateManager *manager); - GameStateManager *m_manager; - - void UpdateStateMicroseconds(unsigned long delta_ms) { - m_state_milliseconds += delta_ms; - m_last_delta_milliseconds = delta_ms; - } - - unsigned long m_state_milliseconds; - unsigned long m_last_delta_milliseconds; - - friend class GameStateManager; -}; - -// Your app calls this from the top level -class GameStateManager { -public: - - GameStateManager(int screen_width, int screen_height) : - m_next_state(0), - m_current_state(0), - m_last_milliseconds(Compatible::GetMilliseconds()), - m_key_presses(0), - m_last_key_presses(0), - m_inside_update(false), - m_fps(500.0), - m_show_fps(false), - m_screen_x(screen_width), - m_screen_y(screen_height) { - } - - ~GameStateManager(); - - // first_state must be dynamically allocated. - // GameStateManager takes ownership of the memory - // from this point forward. - void SetInitialState(GameState *first_state); - - void KeyPress(GameKey key); - bool IsKeyPressed(GameKey key) const; - bool IsKeyReleased(GameKey key) const; - - void MousePress(MouseButton button); - void MouseRelease(MouseButton button); - void MouseMove(int x, int y); - const MouseInfo &Mouse() const { return m_mouse; } - - void Update(bool skip_this_update); - void Draw(Renderer &renderer); - - void ChangeState(GameState *new_state); - - Tga *GetTexture(Texture tex_name, bool smooth) const; - - int GetStateWidth() const { return m_screen_x; } - int GetStateHeight() const { return m_screen_y; } - -private: - GameState *m_next_state; - GameState *m_current_state; - - unsigned long m_last_milliseconds; - unsigned long m_key_presses; - unsigned long m_last_key_presses; - - bool m_inside_update; - - MouseInfo m_mouse; - - FrameCounter m_fps; - bool m_show_fps; - - int m_screen_x; - int m_screen_y; - - mutable std::map m_textures; -}; - -#endif // __GAMESTATE_H - diff --git a/src/KeyboardDisplay.cpp b/src/KeyboardDisplay.cpp deleted file mode 100644 index c4c4372a..00000000 --- a/src/KeyboardDisplay.cpp +++ /dev/null @@ -1,752 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "KeyboardDisplay.h" -#include "LinthesiaError.h" -#include "StringUtil.h" -#include "TrackProperties.h" - -#include "Renderer.h" -#include "Textures.h" -#include "Tga.h" - -#include "neolib/GLShader.h" - -#include "shaders/BlurParticleGLShader.h" -#include "shaders/RenderTextureGLShader.h" - -#include "neolib/NeoFBO.h" -#include "neolib/ParticleSystem.h" - -using namespace std; - -const KeyboardDisplay::NoteTexDimensions KeyboardDisplay::WhiteNoteDimensions = - {32, 128, 4, 25, 22, 28, 93, 100}; -const KeyboardDisplay::NoteTexDimensions KeyboardDisplay::BlackNoteDimensions = - {32, 64, 8, 20, 3, 8, 49, 55}; - -struct KeyTexDimensions { - int tex_width; - int tex_height; - - int left; - int right; - - int top; - int bottom; -}; - -GLuint blurProgram; -GLuint normalProgram; - -// GLuint FramebufferName = 0; -// GLuint renderedTexture; - -ParticleSystem particleSystem; - -std::shared_ptr particlesFBO; -std::shared_ptr blurParticlesFBO; - -const KeyboardDisplay::KeyTexDimensions KeyboardDisplay::BlackKeyDimensions = { - 32, 128, 8, 20, 15, 109}; - -KeyboardDisplay::KeyboardDisplay(KeyboardSize size, int pixelWidth, - int pixelHeight, int stateX_, int stateY_) - : m_size(size), m_width(pixelWidth), m_height(pixelHeight), stateX(stateX_), - stateY(stateY_) { - - particlesFBO = std::shared_ptr(new NeoFBO(stateX, stateY)); - blurParticlesFBO = std::shared_ptr(new NeoFBO(stateX, stateY)); - - normalProgram = - LoadShader(RenderTexture_GLShader::vert, RenderTexture_GLShader::frag); - blurProgram = - LoadShader(BlurParticle_GLShader::vert, BlurParticle_GLShader::frag); - - particleSystem.RemoveParticles(); -} - -bool FullScreanQuadInited; - -GLuint _vao; -GLuint _ebo; - -void FullScreanQuad(int stateX, int stateY, GLuint textureToBlur, - GLuint program) { - - if (!FullScreanQuadInited) { - float quadVertices[8] = { - -1.0, -1.0, - 1.0, -1.0, - -1.0, 1.0, - 1.0, 1.0 - }; - - unsigned int quadIndices[6]={ - 0, 1, 2, - 2, 1, 3 - }; - - GLuint vbo = 0; - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, quadVertices, - GL_STATIC_DRAW); - glGenVertexArrays(1, &_vao); - glBindVertexArray(_vao); - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); - - glGenBuffers(1, &_ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - sizeof(unsigned int) * 6, quadIndices, - GL_STATIC_DRAW); - - glBindVertexArray(0); - - FullScreanQuadInited = true; - } - - glUseProgram(program); - - glActiveTexture(GL_TEXTURE0); - - glBindTexture(GL_TEXTURE_2D, textureToBlur); - glBindVertexArray(_vao); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo); - - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *)0); - - glBindVertexArray(0); - - glBindTexture(GL_TEXTURE_2D, 0); - - glUseProgram(0); -} - -void KeyboardDisplay::Draw(Renderer &renderer, const Tga *key_tex[4], - const Tga *note_tex[4], int x, int y, - const TranslatedNoteSet ¬es, - microseconds_t show_duration, - microseconds_t current_time, - const vector &track_properties, - const MidiEventMicrosecondList &bar_line_usecs) { - glViewport(0, 0, stateX, stateY); - - // Source: Measured from Yamaha P-70 - const static double WhiteWidthHeightRatio = 6.8181818; - const static double BlackWidthHeightRatio = 7.9166666; - const static double WhiteBlackWidthRatio = 0.5454545; - - const int white_key_count = GetWhiteKeyCount(); - - // Calculate the largest white key size we can, and then - // leave room for a single pixel space between each key - int white_width = (m_width / white_key_count) - 1; - int white_space = 1; - - int white_height = static_cast(white_width * WhiteWidthHeightRatio); - - const int black_width = static_cast(white_width * WhiteBlackWidthRatio); - const int black_height = - static_cast(black_width * BlackWidthHeightRatio); - const int black_offset = white_width - (black_width / 2); - - // The dimensions given to the keyboard object are bounds. Because of pixel - // rounding, the keyboard will usually occupy less than the maximum in - // either direction. - // - // So, we just try to center the keyboard inside the bounds. - const int final_width = (white_width + white_space) * white_key_count; - const int x_offset = (m_width - final_width) / 2; - const int y_offset = (m_height - white_height); - - // Give the notes a little more room to work with so they can roll under - // the keys without distortion - const int y_roll_under = white_height * 3 / 4; - - // Symbolic names for the arbitrary array passed in here - enum { Rail, Shadow, BlackKey }; - - - // Particles Blur { - particleSystem.UpdateParticles(); - - particlesFBO->Bind(); - glViewport(0, 0, stateX, stateY); - - FullScreanQuad(stateX, stateY, blurParticlesFBO->GetTexture(), normalProgram); - - particleSystem.DrawParticles(renderer); - - renderer.SetColor(Renderer::ToColor(255, 255, 255)); - - particlesFBO->Unbind(); - - blurParticlesFBO->Bind(); - glViewport(0, 0, stateX, stateY); - - FullScreanQuad(stateX, stateY, particlesFBO->GetTexture(), blurProgram); - - blurParticlesFBO->Unbind(); - - FullScreanQuad(stateX, stateY, particlesFBO->GetTexture(), normalProgram); - // } Particles Blur - - - DrawGuides(renderer, white_key_count, white_width, white_space, x + x_offset,y, y_offset); - - renderer.SetColor(Renderer::ToColor(255, 255, 255)); - DrawNotePass(renderer, note_tex[2], note_tex[3], white_width, white_space, - black_width, black_offset, x + x_offset, y, y_offset, - y_roll_under, notes, show_duration, current_time, - track_properties); - - const int ActualKeyboardWidth = - white_width * white_key_count + white_space * (white_key_count - 1); - - // Black out the background of where the keys are about to appear - - renderer.SetColor(Renderer::ToColor(0, 0, 0)); - renderer.DrawQuad(x + x_offset, y + y_offset, ActualKeyboardWidth, - white_height); - - DrawShadow(renderer, key_tex[Shadow], x + x_offset, - y + y_offset + white_height - 10, ActualKeyboardWidth); - DrawWhiteKeys(renderer, key_tex[3], false, white_key_count, white_width, - white_height, white_space, x + x_offset, y + y_offset); - DrawBlackKeys(renderer, key_tex[BlackKey], false, white_key_count, - white_width, black_width, black_height, white_space, - x + x_offset, y + y_offset, black_offset); - DrawShadow(renderer, key_tex[Shadow], x + x_offset, y + y_offset, - ActualKeyboardWidth); - DrawRail(renderer, key_tex[Rail], x + x_offset, y + y_offset, - ActualKeyboardWidth); -} - -int KeyboardDisplay::GetStartingOctave() const { - - // Source: Various "Specification" pages at Yamaha's website - const static int StartingOctaveOn37 = 2; - const static int StartingOctaveOn49 = 1; - const static int StartingOctaveOn61 = 1; // TODO! - const static int StartingOctaveOn76 = 0; // TODO! - const static int StartingOctaveOn88 = 0; - - switch (m_size) { - case KeyboardSize37: - return StartingOctaveOn37; - case KeyboardSize49: - return StartingOctaveOn49; - case KeyboardSize61: - return StartingOctaveOn61; - case KeyboardSize76: - return StartingOctaveOn76; - case KeyboardSize88: - return StartingOctaveOn88; - default: - throw LinthesiaError(Error_BadPianoType); - } -} - -char KeyboardDisplay::GetStartingNote() const { - - // Source: Various "Specification" pages at Yamaha's website - const static char StartingKeyOn37 = 'F'; // F3-F6 - const static char StartingKeyOn49 = 'C'; // C3-C6 - const static char StartingKeyOn61 = 'C'; // C1-C6 // TODO! - const static char StartingKeyOn76 = 'E'; // E0-G6 // TODO! - const static char StartingKeyOn88 = 'A'; // A0-C6 - - switch (m_size) { - case KeyboardSize37: - return StartingKeyOn37; - case KeyboardSize49: - return StartingKeyOn49; - case KeyboardSize61: - return StartingKeyOn61; - case KeyboardSize76: - return StartingKeyOn76; - case KeyboardSize88: - return StartingKeyOn88; - default: - throw LinthesiaError(Error_BadPianoType); - } -} - -int KeyboardDisplay::GetWhiteKeyCount() const { - - // Source: Google Image Search - const static int WhiteKeysOn37 = 22; - const static int WhiteKeysOn49 = 29; - const static int WhiteKeysOn61 = 36; - const static int WhiteKeysOn76 = 45; - const static int WhiteKeysOn88 = 52; - - switch (m_size) { - case KeyboardSize37: - return WhiteKeysOn37; - case KeyboardSize49: - return WhiteKeysOn49; - case KeyboardSize61: - return WhiteKeysOn61; - case KeyboardSize76: - return WhiteKeysOn76; - case KeyboardSize88: - return WhiteKeysOn88; - default: - throw LinthesiaError(Error_BadPianoType); - } -} - -void KeyboardDisplay::DrawWhiteKeys(Renderer &renderer, const Tga *tex, - bool active_only, int key_count, - int key_width, int key_height, - int key_space, int x_offset, - int y_offset) const { - Color white = Renderer::ToColor(255, 255, 255); - - char current_white = GetStartingNote(); - int current_octave = GetStartingOctave() + 1; - for (int i = 0; i < key_count; ++i) { - - // Check to see if this is one of the active notes - const string note_name = STRING(current_white << current_octave); - - KeyNames::const_iterator find_result = m_active_keys.find(note_name); - bool active = (find_result != m_active_keys.end()); - - Color c = white; - - if (active) - c = Track::ColorNoteWhite[find_result->second]; - - if ((active_only && active) || !active_only) { - renderer.SetColor(c); - - const int key_x = i * (key_width + key_space) + x_offset; - - int press = 0; - - if (active) { - particleSystem.SpawnParticle(key_x + key_width / 2, y_offset, c); - press = 3; - } - - renderer.DrawStretchedTga(tex, key_x, y_offset, key_width, - key_height + press, 0, 0, 32, 128); - } - - current_white++; - - if (current_white == 'H') - current_white = 'A'; - - if (current_white == 'C') - current_octave++; - } - - renderer.SetColor(white); -} - -void KeyboardDisplay::DrawBlackKey(Renderer &renderer, const Tga *tex, - const KeyTexDimensions &tex_dimensions, - int x, int y, int w, int h, - Track::TrackColor color) const { - - const KeyTexDimensions &d = tex_dimensions; - - const int tex_w = d.right - d.left; - const double width_scale = double(w) / double(tex_w); - const double full_tex_width = d.tex_width * width_scale; - const double left_offset = d.left * width_scale; - - const int src_x = (int(color) * d.tex_width); - const int dest_x = int(x - left_offset) - 1; - const int dest_w = int(full_tex_width); - - const int tex_h = d.bottom - d.top; - const double height_scale = double(h) / double(tex_h); - const double full_tex_height = d.tex_height * height_scale; - const double top_offset = d.top * height_scale; - - const int dest_y = int(y - top_offset) - 1; - const int dest_h = int(full_tex_height); - - renderer.DrawStretchedTga(tex, dest_x, dest_y, dest_w, dest_h, src_x, 0, - d.tex_width, d.tex_height); -} - -void KeyboardDisplay::DrawBlackKeys(Renderer &renderer, const Tga *tex, - bool active_only, int white_key_count, - int white_width, int black_width, - int black_height, int key_space, - int x_offset, int y_offset, - int black_offset) const { - - char current_white = GetStartingNote(); - int current_octave = GetStartingOctave() + 1; - for (int i = 0; i < white_key_count; ++i) { - // Don't allow a very last black key - if (i == white_key_count - 1) - break; - - switch (current_white) { - case 'A': - case 'C': - case 'D': - case 'F': - case 'G': { - // Check to see if this is one of the active notes - const string note_name = STRING(current_white << '#' << current_octave); - - KeyNames::const_iterator find_result = m_active_keys.find(note_name); - bool active = (find_result != m_active_keys.end()); - - // In this case, MissedNote isn't actually MissedNote. In the black key - // texture we use this value (which doesn't make any sense in this - // context) as the default "Black" color. - Track::TrackColor c = Track::MissedNote; - if (active) - c = find_result->second; - - if (!active_only || (active_only && active)) { - const int start_x = - i * (white_width + key_space) + x_offset + black_offset; - - if (active) - particleSystem.SpawnParticle(start_x + black_width / 2, y_offset, - Track::ColorNoteWhite[c]); - DrawBlackKey(renderer, tex, BlackKeyDimensions, start_x, y_offset, - black_width, black_height, c); - } - } - } - - current_white++; - if (current_white == 'H') - current_white = 'A'; - - if (current_white == 'C') - current_octave++; - } -} - -void DrawWidthStretched(Renderer &renderer, const Tga *tex, int x, int y, - int width) { - - renderer.DrawStretchedTga(tex, x, y, width, tex->GetHeight(), 0, 0, - tex->GetWidth(), tex->GetWidth()); -} - -void KeyboardDisplay::DrawRail(Renderer &renderer, const Tga *tex, int x, int y, - int width) const { - - const static int RailOffsetY = -4; - DrawWidthStretched(renderer, tex, x, y + RailOffsetY, width); -} - -void KeyboardDisplay::DrawShadow(Renderer &renderer, const Tga *tex, int x, - int y, int width) const { - - const static int ShadowOffsetY = 10; - DrawWidthStretched(renderer, tex, x, y + ShadowOffsetY, width); -} - -void KeyboardDisplay::DrawGuides(Renderer &renderer, int key_count, - int key_width, int key_space, int x_offset, - int y, int y_offset) const { - - const static int PixelsOffKeyboard = 2; - int keyboard_width = key_width * key_count + key_space * (key_count - 1); - - const Color thick(Renderer::ToColor(0x47, 0x47, 0x47,100)); - const Color thin(Renderer::ToColor(0x47, 0x47, 0x47,100)); - - char current_white = GetStartingNote() - 1; - int current_octave = GetStartingOctave() + 1; - for (int i = 0; i < key_count + 1; ++i) { - const int key_x = i * (key_width + key_space) + x_offset - 1; - - int guide_thickness = 1; - Color guide_color = thin; - - bool draw_guide = true; - switch (current_white) { - case 'B': - guide_color = thick; - guide_thickness = 2; - break; - case 'E': - guide_color = thin; - break; - default: - draw_guide = false; - break; - } - - if (draw_guide) { - renderer.SetColor(guide_color); - renderer.DrawQuad(key_x - guide_thickness / 2, y, guide_thickness, - y_offset - PixelsOffKeyboard); - } - - current_white++; - if (current_white == 'H') - current_white = 'A'; - if (current_white == 'C') - current_octave++; - } -} - -void KeyboardDisplay::DrawBars( - Renderer &renderer, int x, int y, int y_offset, int y_roll_under, - int final_width, microseconds_t show_duration, microseconds_t current_time, - const MidiEventMicrosecondList &bar_line_usecs) const { - int i = 0; - MidiEventMicrosecondList::const_iterator j = bar_line_usecs.begin(); - const Color bar_color(Renderer::ToColor(0x50, 0x50, 0x50)); - const Color text_color1(Renderer::ToColor(0x50, 0x50, 0x50)); - const Color text_color2(Renderer::ToColor(0x90, 0x90, 0x90)); - for (; j != bar_line_usecs.end(); ++j, ++i) { - renderer.SetColor(bar_color); - microseconds_t bar_usec = *j; - // Skip previous bars - if (bar_usec < current_time) - continue; - // This list is sorted by note start time. The moment we encounter - // a bar scrolled off the window, we're done drawing - if (bar_usec > current_time + show_duration) - break; - - const double scaling_factor = - static_cast(y_offset) / static_cast(show_duration); - - const long long roll_under = - static_cast(y_roll_under / scaling_factor); - const long long adjusted_offset = max(bar_usec - current_time, -roll_under); - - // Convert our times to pixel coordinates - const int y_bar_offset = - y - static_cast(adjusted_offset * scaling_factor) + y_offset; - renderer.DrawQuad(x, y_bar_offset, final_width, 2); - - // Add a label with a bar number - // Background text - TextWriter bar_writer2(x + 3, y_bar_offset - 13, renderer, false, 11); - bar_writer2 << Text(STRING(i + 1), text_color1); - - TextWriter bar_writer3(x + 5, y_bar_offset - 15, renderer, false, 11); - bar_writer3 << Text(STRING(i + 1), text_color1); - - TextWriter bar_writer4(x + 3, y_bar_offset - 15, renderer, false, 11); - bar_writer4 << Text(STRING(i + 1), text_color1); - - TextWriter bar_writer5(x + 5, y_bar_offset - 13, renderer, false, 11); - bar_writer5 << Text(STRING(i + 1), text_color1); - - // Foreground text - TextWriter bar_writer(x + 4, y_bar_offset - 14, renderer, false, 11); - bar_writer << Text(STRING(i + 1), text_color2); - } -} - -void KeyboardDisplay::DrawNote(Renderer &renderer, const Tga *tex, - const NoteTexDimensions &tex_dimensions, int x, - int y, int w, int h, int color_id) const { - - const NoteTexDimensions &d = tex_dimensions; - - // Width is super-easy - const int tex_note_w = d.right - d.left; - - const double width_scale = double(w) / double(tex_note_w); - const double full_tex_width = d.tex_width * width_scale; - const double left_offset = d.left * width_scale; - - const int src_x = (color_id * d.tex_width); - const int dest_x = int(x - left_offset); - const int dest_w = int(full_tex_width); - - // Now we draw the note in three sections: - // - Crown (fixed (relative) height) - // - Middle (variable height) - // - Heel (fixed (relative) height) - - // Force the note to be at least as large as the crown + heel height - const double crown_h = (d.crown_end - d.crown_start) * width_scale; - const double heel_h = (d.heel_end - d.heel_start) * width_scale; - const double min_height = crown_h + heel_h + 1.0; - - if (h < min_height) { - const int diff = int(min_height - h); - h += diff; - y -= diff; - } - - // We actually use the width scale in height calculations - // to keep the proportions fixed. - const double crown_start_offset = d.crown_start * width_scale; - const double crown_end_offset = d.crown_end * width_scale; - const double heel_height = double(d.heel_end - d.heel_start) * width_scale; - const double bottom_height = double(d.tex_height - d.heel_end) * width_scale; - - const int dest_y1 = int(y - crown_start_offset); - const int dest_y2 = int(dest_y1 + crown_end_offset); - const int dest_y3 = int((y + h) - heel_height); - const int dest_y4 = int(dest_y3 + bottom_height); - - renderer.DrawStretchedTga(tex, dest_x, dest_y1, dest_w, dest_y2 - dest_y1, - src_x, 0, d.tex_width, d.crown_end); - renderer.DrawStretchedTga(tex, dest_x, dest_y2, dest_w, dest_y3 - dest_y2, - src_x, d.crown_end, d.tex_width, - d.heel_start - d.crown_end); - - renderer.DrawStretchedTga(tex, dest_x, dest_y3, dest_w, dest_y4 - dest_y3, - src_x, d.heel_start, d.tex_width, - d.tex_height - d.heel_start); -} - -void KeyboardDisplay::DrawNotePass( - Renderer &renderer, const Tga *tex_white, const Tga *tex_black, - int white_width, int key_space, int black_width, int black_offset, - int x_offset, int y, int y_offset, int y_roll_under, - const TranslatedNoteSet ¬es, microseconds_t show_duration, - microseconds_t current_time, - const vector &track_properties) const { - - // Shiny music domain knowledge - const static unsigned int NotesPerOctave = 12; - const static unsigned int WhiteNotesPerOctave = 7; - const static bool IsBlackNote[12] = {false, true, false, true, - false, false, true, false, - true, false, true, false}; - - // The constants used in the switch below refer to the number - // of white keys off 'C' that type of piano starts on - int keyboard_type_offset = 0; - - switch (m_size) { - case KeyboardSize37: - keyboard_type_offset = 4 - WhiteNotesPerOctave; - break; - case KeyboardSize49: - keyboard_type_offset = 0 - WhiteNotesPerOctave; - break; - case KeyboardSize61: - keyboard_type_offset = 7 - WhiteNotesPerOctave; - break; // TODO! - case KeyboardSize76: - keyboard_type_offset = 5 - WhiteNotesPerOctave; - break; // TODO! - case KeyboardSize88: - keyboard_type_offset = 2 - WhiteNotesPerOctave; - break; - default: - throw LinthesiaError(Error_BadPianoType); - } - - // This array describes how to "stack" notes in a single place. The - // IsBlackNote array then tells which one should be shifted slightly to the - // right - const static int NoteToWhiteNoteOffset[12] = {0, -1, -1, -2, -2, -2, - -3, -3, -4, -4, -5, -5}; - - const static int MinNoteHeight = 3; - - bool drawing_black = false; - for (int toggle = 0; toggle < 2; ++toggle) { - - for (TranslatedNoteSet::const_iterator i = notes.begin(); i != notes.end(); - ++i) { - // This list is sorted by note start time. The moment we encounter - // a note scrolled off the window, we're done drawing - if (i->start > current_time + show_duration) - break; - - const Track::Mode mode = track_properties[i->track_id].mode; - if (mode == Track::ModeNotPlayed || mode == Track::ModePlayedButHidden) - continue; - - const int octave = (i->note_id / NotesPerOctave) - GetStartingOctave(); - const int octave_base = i->note_id % NotesPerOctave; - const int stack_offset = NoteToWhiteNoteOffset[octave_base]; - const bool is_black = IsBlackNote[octave_base]; - - if (drawing_black != is_black) - continue; - - const int octave_offset = (max(octave - 1, 0) * WhiteNotesPerOctave); - const int inner_octave_offset = (octave_base + stack_offset); - const int generalized_black_offset = (is_black ? black_offset : 0); - - const double scaling_factor = - static_cast(y_offset) / static_cast(show_duration); - - const long long roll_under = - static_cast(y_roll_under / scaling_factor); - const long long adjusted_start = - max(i->start - current_time, -roll_under); - const long long adjusted_end = max(i->end - current_time, 0LL); - - if (adjusted_end < adjusted_start) - continue; - - // Convert our times to pixel coordinates - const int y_end = - y - static_cast(adjusted_start * scaling_factor) + y_offset; - const int y_start = - y - static_cast(adjusted_end * scaling_factor) + y_offset; - - const int start_x = - (octave_offset + inner_octave_offset + keyboard_type_offset) * - (white_width + key_space) + - generalized_black_offset + x_offset; - - const int left = start_x - 1; - const int top = y_start; - const int width = (is_black ? black_width : white_width) + 2; - int height = y_end - y_start; - - // Force a note to be a minimum height at all times - // except when scrolling off underneath the keyboard and - // coming in from the top of the screen. - const bool hitting_bottom = (adjusted_start + current_time != i->start); - const bool hitting_top = (adjusted_end + current_time != i->end); - - if (!hitting_bottom && !hitting_top) { - while ((height) < MinNoteHeight) - height++; - } - - const Track::TrackColor color = track_properties[i->track_id].color; - const int &brush_id = - (((i->state == UserMissed) || (i->retry_state == UserMissed)) - ? Track::MissedNote - : color); - - DrawNote(renderer, (drawing_black ? tex_black : tex_white), - (drawing_black ? BlackNoteDimensions : WhiteNoteDimensions), - left, top, width, height, brush_id); - } - - drawing_black = !drawing_black; - } -} - -void KeyboardDisplay::SetKeyActive(const string &key_name, bool active, - Track::TrackColor color) { - if (active) - m_active_keys[key_name] = color; - - else - m_active_keys.erase(key_name); -} diff --git a/src/KeyboardDisplay.h b/src/KeyboardDisplay.h deleted file mode 100644 index 2a33baa3..00000000 --- a/src/KeyboardDisplay.h +++ /dev/null @@ -1,142 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __KEYBOARDDISPLAY_H -#define __KEYBOARDDISPLAY_H - -#include -#include -#include - -#include "TrackTile.h" -#include "TrackProperties.h" - -#include "libmidi/Note.h" -#include "libmidi/MidiTypes.h" - -enum KeyboardSize { - - KeyboardSize37, - KeyboardSize49, - KeyboardSize61, - KeyboardSize76, - KeyboardSize88 -}; - -typedef std::map KeyNames; - -class KeyboardDisplay { -public: - - const static microseconds_t NoteWindowLength = 330000; - - KeyboardDisplay(KeyboardSize size, int pixelWidth, int pixelHeight,int stateX_,int stateY_); - - void Draw(Renderer &renderer, const Tga *key_tex[4], const Tga *note_tex[4], - int x, int y, const TranslatedNoteSet ¬es, microseconds_t show_duration, - microseconds_t current_time, const std::vector &track_properties, - const MidiEventMicrosecondList &bar_line_usecs); - - void SetKeyActive(const std::string &key_name, bool active, Track::TrackColor color); - - void ResetActiveKeys() { - m_active_keys.clear(); - } - - int stateX; - int stateY; - -private: - struct NoteTexDimensions { - - int tex_width; - int tex_height; - - int left; - int right; - - int crown_start; - int crown_end; - - int heel_start; - int heel_end; - }; - - const static NoteTexDimensions WhiteNoteDimensions; - const static NoteTexDimensions BlackNoteDimensions; - - struct KeyTexDimensions { - - int tex_width; - int tex_height; - - int left; - int right; - - int top; - int bottom; - }; - - const static KeyTexDimensions BlackKeyDimensions; - - // std::shared_ptr particlesFBO; - - void DrawWhiteKeys(Renderer &renderer,const Tga *tex, bool active_only, int key_count, int key_width, - int key_height, int key_space, int x_offset, int y_offset) const; - - void DrawBlackKeys(Renderer &renderer, const Tga *tex, bool active_only, int white_key_count, - int white_width, int black_width, int black_height, int key_space, - int x_offset, int y_offset, int black_offset) const; - - void DrawRail(Renderer &renderer, const Tga *tex, int x, int y, int width) const; - void DrawShadow(Renderer &renderer, const Tga *tex, int x, int y, int width) const; - - void DrawGuides(Renderer &renderer, int key_count, int key_width, int key_space, - int x_offset, int y, int y_offset) const; - void DrawBars(Renderer &renderer, int x, int y, int y_offset, - int y_roll_under, int final_width, - microseconds_t show_duration, microseconds_t current_time, - const MidiEventMicrosecondList &bar_line_usecs) const; - - void DrawNotePass(Renderer &renderer, const Tga *tex_white, const Tga *tex_black, - int white_width, int key_space, int black_width, int black_offset, - int x_offset, int y, int y_offset, int y_roll_under, - const TranslatedNoteSet ¬es, microseconds_t show_duration, - microseconds_t current_time, const std::vector &track_properties) const; - - // This takes the rectangle where the actual note block should appear and transforms - // it to the multi-quad (with relatively complicated texture coordinates) using the - // passed-in texture descriptor, and then draws the result - void DrawNote(Renderer &renderer, const Tga *tex, const NoteTexDimensions &tex_dimensions, - int x, int y, int w, int h, int color_id) const; - - // This works very much like DrawNote - void DrawBlackKey(Renderer &renderer, const Tga *tex, const KeyTexDimensions &tex_dimensions, - int x, int y, int w, int h, Track::TrackColor color) const; - - // Retrieves which white-key a piano with the given key count - // will start with on the far left side - char GetStartingNote() const; - - // Retrieves which octave a piano with the given key count - // will start with on the far left side - int GetStartingOctave() const; - - // Retrieves the number of white keys a piano with the given - // key count will contain - int GetWhiteKeyCount() const; - - KeyboardSize m_size; - KeyNames m_active_keys; - - int m_width; - int m_height; - -}; - -#endif // __KEYBOARDDISPLAY_H diff --git a/src/LinthesiaError.cpp b/src/LinthesiaError.cpp deleted file mode 100644 index d283e70a..00000000 --- a/src/LinthesiaError.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "LinthesiaError.h" -#include "StringUtil.h" - -using namespace std; - -string LinthesiaError::GetErrorDescription() const { - - switch (m_error) { - case Error_StringSpecified: - return m_optional_string; - - case Error_BadPianoType: - return "Bad piano type specified."; - - case Error_BadGameState: - return "Internal Error: Linthesia entered bad game state!"; - - default: - return STRING("Unknown LinthesiaError Code (" << m_error << ")."); - } -} - diff --git a/src/LinthesiaError.h b/src/LinthesiaError.h deleted file mode 100644 index c429b162..00000000 --- a/src/LinthesiaError.h +++ /dev/null @@ -1,49 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __LINTHESIA_ERROR_H__ -#define __LINTHESIA_ERROR_H__ - -#include -#include - -enum LinthesiaErrorCode { - - Error_StringSpecified, - Error_BadPianoType, - Error_BadGameState -}; - - -class LinthesiaError : public std::exception { -public: - - // TODO: This would be a sweet place to add stack-trace information... - - LinthesiaError(LinthesiaErrorCode error) : - m_error(error), - m_optional_string("") { - } - - LinthesiaError(const std::string error) : - m_error(Error_StringSpecified), - m_optional_string(error) { - } - - std::string GetErrorDescription() const; - - ~LinthesiaError() throw() { } - - const LinthesiaErrorCode m_error; - -private: - const std::string m_optional_string; - LinthesiaError operator=(const LinthesiaError&); -}; - -#endif // __LINTHESIA_ERROR_H__ diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 942f12ae..00000000 --- a/src/Makefile.am +++ /dev/null @@ -1,79 +0,0 @@ -noinst_LTLIBRARIES = libmidi.la -dist_libmidi_la_SOURCES = libmidi/Midi.cpp \ - libmidi/MidiUtil.cpp \ - libmidi/MidiTrack.cpp \ - libmidi/MidiEvent.cpp -noinst_HEADERS = libmidi/MidiEvent.h \ - libmidi/Midi.h \ - libmidi/MidiTrack.h \ - libmidi/MidiTypes.h \ - libmidi/MidiUtil.h \ - libmidi/Note.h - -libmidi_la_CPPFLAGS = -iquote $(srcdir)/libmidi - -bin_PROGRAMS = neothesia -dist_neothesia_SOURCES = CompatibleSystem.cpp \ - KeyboardDisplay.cpp \ - MenuLayout.cpp \ - Renderer.cpp \ - TextWriter.cpp \ - TrackSelectionState.cpp \ - DeviceTile.cpp \ - FileSelector.cpp \ - LinthesiaError.cpp \ - MidiComm.cpp \ - StatsState.cpp \ - Tga.cpp \ - TrackTile.cpp \ - GameState.cpp \ - main.cpp \ - PlayingState.cpp \ - StringTile.cpp \ - TitleState.cpp \ - UserSettings.cpp \ - neolib/GLShader.cpp\ - neolib/ParticleSystem.cpp \ - neolib/NeoFBO.cpp -noinst_HEADERS += CompatibleSystem.h \ - DeviceTile.h \ - FileSelector.h \ - FrameCounter.h \ - GameState.h \ - KeyboardDisplay.h \ - LinthesiaError.h \ - MenuLayout.h \ - MidiComm.h \ - OSGraphics.h \ - PlayingState.h \ - Renderer.h \ - SharedState.h \ - StatsState.h \ - StringTile.h \ - StringUtil.h \ - Textures.h \ - TextWriter.h \ - Tga.h \ - TitleState.h \ - TrackProperties.h \ - TrackSelectionState.h \ - TrackTile.h \ - UserSettings.h \ - Version.h \ - neolib/GLShader.h \ - neolib/ParticleSystem.h \ - neolib/NeoFBO.h - -neothesia_LDFLAGS = @GTKMM_LIBS@ @GCONFMM_LIBS@ @GTKGLEXTMM_LIBS@ @ALSA_LIBS@ -neothesia_LDADD = libmidi.la -neothesia_CXXFLAGS = -std=c++11 -iquote $(srcdir)/libmidi -lGLEW -neothesia_CPPFLAGS = @GTKMM_CFLAGS@ @GCONFMM_CFLAGS@ @GTKGLEXTMM_CFLAGS@ @ALSA_CFLAGS@ -DGRAPHDIR="\"${graphdir}\"" -DSCRIPTDIR="\"${scriptdir}\"" - -ctags-dependencies: - @$(CC) -M -std=c++11 -I/usr/include @GTKMM_CFLAGS@ @GCONFMM_CFLAGS@ @GTKGLEXTMM_CFLAGS@ @ALSA_CFLAGS@ \ - $(dist_libmidi_la_SOURCES) $(noinst_HEADERS) $(dist_neothesia_SOURCES) 2>/dev/null | \ - sed 's/^.*://;s/^ //;s/ \\//;s/ /\n/g' | \ - sort -u | \ - $(CTAGS) --tag-relative=yes -L - --c++-kinds=+p --fields=+iaS --extra=+q -f $(top_srcdir)/tags - -.PHONY:ctags-dependencies diff --git a/src/MenuLayout.cpp b/src/MenuLayout.cpp deleted file mode 100644 index 57663f2e..00000000 --- a/src/MenuLayout.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "MenuLayout.h" -#include "TextWriter.h" -#include "Renderer.h" - -using namespace std; - -namespace Layout { - - void DrawTitle(Renderer &renderer, const string &title) { - - TextWriter title_writer(ScreenMarginX, ScreenMarginY - TitleFontSize - 10, - renderer, false, TitleFontSize); - title_writer << title; - } - - void DrawHorizontalRule(Renderer &renderer, int state_width, int y) { - - renderer.SetColor(0x50, 0x50, 0x50); - renderer.DrawQuad(ScreenMarginX, y - 1, state_width - 2*ScreenMarginX, 3); - } - - void DrawButton(Renderer &renderer, const ButtonState &button, const string Title) { - - const static Color color = Renderer::ToColor(32,32,32); - const static Color color_hover = Renderer::ToColor(42,42,42); - - renderer.SetColor(button.hovering ? color_hover : color); - // renderer.DrawTga(tga, button.x, button.y); - renderer.ForceTexture(0); - renderer.DrawQuad(button.x,button.y,button.w,button.h); - - TextWriter title_writer(button.x + button.w/2 - 10, button.y + button.h/2 - 5, renderer, true, 10); - title_writer << Title; - } - - -} // End namespace Layout diff --git a/src/MenuLayout.h b/src/MenuLayout.h deleted file mode 100644 index cfc36fb9..00000000 --- a/src/MenuLayout.h +++ /dev/null @@ -1,74 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MENU_LAYOUT_H -#define __MENU_LAYOUT_H - -#include "GameState.h" - -#include -using namespace std; - -struct ButtonState { - - ButtonState() : - hovering(false), - depressed(false), - x(0), y(0), w(0), h(0) { - } - - ButtonState(int x, int y, int w, int h) : - hovering(false), - depressed(false), - x(x), y(y), w(w), h(h) {} - - void Update(const MouseInfo &mouse) { - hovering = mouse.x > x && mouse.x < x+w && mouse.y > y && mouse.y < y+h; - depressed = hovering && mouse.held.left; - hit = hovering && mouse.released.left; - } - - // Simple mouse over - bool hovering; - - // Mouse over while (left) button is held down - bool depressed; - - // Mouse over just as the (left) button is released - bool hit; - - int x, y; - int w, h; -}; - -// Macro to turn replace Renderer::DrawTga()'s 4 parameters with one -#define BUTTON_RECT(button) ((button).x), ((button).y), ((button).w), ((button).h) - -namespace Layout { - - void DrawTitle(Renderer &renderer, const std::string &title); - void DrawHorizontalRule(Renderer &renderer, int state_width, int y); - void DrawButton(Renderer &renderer, - const ButtonState &button, - const string Title); - - // Pixel margin forced at edges of screen - const static int ScreenMarginX = 16; - const static int ScreenMarginY = 86; - - const static int TitleFontSize = 16; - const static int ScoreFontSize = 26; - const static int ButtonFontSize = 14; - const static int SmallFontSize = 12; - - const static int ButtonWidth = 176; - const static int ButtonHeight = 46; - -}; - -#endif // __MENU_LAYOUT_H diff --git a/src/MidiComm.cpp b/src/MidiComm.cpp deleted file mode 100644 index 8dcb95fb..00000000 --- a/src/MidiComm.cpp +++ /dev/null @@ -1,424 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include -#include -#include - -#include "libmidi/MidiEvent.h" -#include "libmidi/MidiUtil.h" - -#include "MidiComm.h" -#include "UserSettings.h" -#include "CompatibleSystem.h" -#include "StringUtil.h" - -using namespace std; - -// ALSA sequencer descriptor -static bool midi_initiated = false; -static bool emulate_kb = false; -static snd_seq_t* alsa_seq; - -// ALSA ports -static int local_out, local_in, anon_in, keybd_out = -1; - -void midiInit() { - - if (midi_initiated) - return; - - int err = snd_seq_open(&alsa_seq, "default", SND_SEQ_OPEN_DUPLEX, 0); - int ownid = snd_seq_client_id(alsa_seq); - midi_initiated = true; - - // Could not open sequencer, no out devices - if (err < 0) { - alsa_seq = NULL; - Compatible::ShowError("Could not open MIDI sequencer. No MIDI available"); - return; - } - - snd_seq_set_client_name(alsa_seq, "Linthesia"); - - // meanings of READ and WRITE are permissions of the port from the viewpoint of other ports - // READ: port allows to send events to other ports - local_out = snd_seq_create_simple_port(alsa_seq, "Linthesia Output", - SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, - SND_SEQ_PORT_TYPE_MIDI_GENERIC); - - keybd_out = snd_seq_create_simple_port(alsa_seq, "Linthesia Keyboard", - SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, - SND_SEQ_PORT_TYPE_MIDI_GENERIC); - - // WRITE: port allows to receive events from other ports - local_in = snd_seq_create_simple_port(alsa_seq, "Linthesia Input", - SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_MIDI_GENERIC); - - anon_in = snd_seq_create_simple_port(alsa_seq, "Linthesia Annonce Listener", - SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT, - SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); - - if (anon_in < 0) - return; // handle error - - // Subscribe on port opening - snd_seq_port_subscribe_t *sub; - snd_seq_addr_t sender, dest; - - snd_seq_port_subscribe_alloca(&sub); - // Receive events from annoncer's port - sender.client = SND_SEQ_CLIENT_SYSTEM; - sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; - snd_seq_port_subscribe_set_sender(sub, &sender); - // Forward them to our port - dest.client = ownid; - dest.port = anon_in; - snd_seq_port_subscribe_set_dest(sub, &dest); - err = snd_seq_subscribe_port(alsa_seq, sub); - if (err<0) { - fprintf(stderr, "Cannot subscribe announce port: %s\n", snd_strerror(err)); - return; - } - -} - -void midiStop() { - - snd_seq_close(alsa_seq); -} - -void sendNote(const unsigned char note, bool on) { - - if (emulate_kb) { - snd_seq_event_t ev; - snd_seq_ev_clear(&ev); - - snd_seq_ev_set_source(&ev, keybd_out); - snd_seq_ev_set_subs(&ev); - snd_seq_ev_set_direct(&ev); - - if (on) - // velocity ~ 60 for audio preview - snd_seq_ev_set_noteon(&ev, 0, note, 60); - else - snd_seq_ev_set_noteoff(&ev, 0, note, 0); - - snd_seq_event_output(alsa_seq, &ev); - snd_seq_drain_output(alsa_seq); - } -} - -// private use -void doRetrieveDevices(unsigned int perms, MidiCommDescriptionList& devices) { - - midiInit(); - if (alsa_seq == NULL) - return; - - snd_seq_client_info_t* cinfo; - snd_seq_port_info_t* pinfo; - int count = 0, ownid = snd_seq_client_id(alsa_seq); - - snd_seq_client_info_alloca(&cinfo); - snd_seq_port_info_alloca(&pinfo); - snd_seq_client_info_set_client(cinfo, -1); - - while (snd_seq_query_next_client(alsa_seq, cinfo) >= 0) { - - // reset query info - snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); - snd_seq_port_info_set_port(pinfo, -1); - - while (snd_seq_query_next_port(alsa_seq, pinfo) >= 0) { - if ((snd_seq_port_info_get_capability(pinfo) & perms) == perms) { - - int client = snd_seq_client_info_get_client(cinfo); - int port = snd_seq_port_info_get_port(pinfo); - - // filter own ports - if (client == ownid && (port == local_in || port == local_out)) - continue; - - MidiCommDescription d; - d.id = count++; - d.name = snd_seq_port_info_get_name(pinfo); - d.client = client; - d.port = port; - - devices.push_back(d); - } - } - } -} - -// Midi IN Ports - -static bool built_input_list = false; -static MidiCommDescriptionList in_list(MidiCommIn::GetDeviceList()); - -MidiCommIn::MidiCommIn(unsigned int device_id) { - m_should_reconnect = false; - - m_description = GetDeviceList()[device_id]; - - // Connect local in to selected port - int res = snd_seq_connect_from(alsa_seq, local_in, m_description.client, m_description.port); - if (res < 0) { - string msg = snd_strerror(res); - cout << "[WARNING] Input, cannot connect from '" << m_description.name << "': " << msg << endl; - } - - // enable internal keyboard - if (m_description.client == snd_seq_client_id(alsa_seq) and - m_description.port == keybd_out) - emulate_kb = true; -} - -MidiCommIn::~MidiCommIn() { - - // Disconnect local in to selected port - snd_seq_disconnect_from(alsa_seq, local_in, m_description.client, m_description.port); -} - -MidiCommDescriptionList MidiCommIn::GetDeviceList() { - - if (built_input_list) - return in_list; - - built_input_list = true; - MidiCommDescriptionList devices; - - unsigned int perms = SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ; - doRetrieveDevices(perms, devices); - - return devices; -} - -void MidiCommIn::UpdateDeviceList() -{ - built_input_list = false; - in_list = MidiCommIn::GetDeviceList(); -} - -MidiEvent MidiCommIn::Read() { - - if (snd_seq_event_input_pending(alsa_seq, 1) < 1) - return MidiEvent::NullEvent(); - - MidiEventSimple simple; - snd_seq_event_t* ev; - snd_seq_event_input(alsa_seq, &ev); - - switch(ev->type) { - case SND_SEQ_EVENT_NOTEON: - simple.status = 0x90 | (ev->data.note.channel & 0x0F); // Type and Channel - simple.byte1 = ev->data.note.note; // Note number - simple.byte2 = ev->data.note.velocity; // Velocity - break; - - case SND_SEQ_EVENT_NOTEOFF: - simple.status = 0x80 | (ev->data.note.channel & 0x0F); // Type and Channel - simple.byte1 = ev->data.note.note; // Note number - simple.byte2 = 0; // Velocity - break; - - case SND_SEQ_EVENT_PGMCHANGE: - simple.status = 0xC0 | (ev->data.note.channel & 0x0F); // Type and Channel - simple.byte1 = ev->data.control.value; // Program number - break; - - case SND_SEQ_EVENT_PORT_EXIT: - // USB device is disconnected - the input client is closed - { - cout << "MIDI device is lost" << endl; - int lost_client = ev->data.addr.client; - int lost_port = ev->data.addr.port; - // TODO add better error reporting - } - break; - - case SND_SEQ_EVENT_PORT_START: - { - int new_client = ev->data.addr.client; - int new_port = ev->data.addr.port; - snd_seq_port_info_t* pinfo; - snd_seq_port_info_alloca(&pinfo); - - cout << "New MIDI device client=" << new_client << ", port=" << new_port << endl; - int err = snd_seq_get_any_port_info(alsa_seq, new_client, new_port, pinfo); - - if (err < 0) - return MidiEvent::NullEvent(); // error - - int port = snd_seq_port_info_get_port(pinfo); - int client = snd_seq_port_info_get_client(pinfo); - cout << "Port info client=" << client << ", port=" << port << endl; - - std::string new_name = snd_seq_port_info_get_name(pinfo); - cout << "New MIDI device " << new_name << endl; - - m_should_reconnect = true; - } - break; - - // unknown type, do nothing - default: - return MidiEvent::NullEvent(); - } - - return MidiEvent::Build(simple); -} - -bool MidiCommIn::KeepReading() const { - - return snd_seq_event_input_pending(alsa_seq, 1); -} - -void MidiCommIn::Reset() { - - snd_seq_drop_input(alsa_seq); -} - -bool MidiCommIn::ShouldReconnect() const { - - return m_should_reconnect; -} - -void MidiCommIn::Reconnect() { - // We assume, that the client and the port is the same after device's reconnect - // Connect local in to selected port - int res = snd_seq_connect_from(alsa_seq, local_in, m_description.client, m_description.port); - m_should_reconnect = false; -} - - -// Midi OUT Ports - -static bool built_output_list = false; -static MidiCommDescriptionList out_list(MidiCommOut::GetDeviceList()); - -MidiCommOut::MidiCommOut(unsigned int device_id) { - - m_description = GetDeviceList()[device_id]; - - // Connect local out to selected port - int res = snd_seq_connect_to(alsa_seq, local_out, m_description.client, m_description.port); - if (res < 0) { - string msg = snd_strerror(res); - cout << "[WARNING] Output, cannot connect to '" << m_description.name - << "': " << msg << endl; - } -} - -MidiCommOut::~MidiCommOut() { - - // Disconnect local out to selected port - snd_seq_disconnect_to(alsa_seq, local_out, m_description.client, m_description.port); - - // This does not harm if done everytime... - emulate_kb = false; -} - -void MidiCommOut::UpdateDeviceList() -{ - built_output_list = false; - out_list = MidiCommOut::GetDeviceList(); -} - -MidiCommDescriptionList MidiCommOut::GetDeviceList() { - - if (built_output_list) - return out_list; - - built_output_list = true; - MidiCommDescriptionList devices; - - unsigned int perms = SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE; - doRetrieveDevices(perms, devices); - - return devices; -} - -void MidiCommOut::Write(const MidiEvent &out) { - - snd_seq_event_t ev; - snd_seq_ev_clear(&ev); - - // Set my source, to all subscribers, direct delivery - snd_seq_ev_set_source(&ev, local_out); - snd_seq_ev_set_subs(&ev); - snd_seq_ev_set_direct(&ev); - - // set event type - switch (out.Type()) { - case MidiEventType_NoteOn: { - int ch = out.Channel(); - int note = out.NoteNumber(); - snd_seq_ev_set_noteon(&ev, ch, note, out.NoteVelocity()); - - // save for reset - notes_on.push_back(pair(ch, note)); - break; - } - - case MidiEventType_NoteOff: { - int note = out.NoteNumber(); - int ch = out.Channel(); - snd_seq_ev_set_noteoff(&ev, ch, note, out.NoteVelocity()); - - // remove from reset - pair p(ch, note); - vector >::iterator i; - for (i = notes_on.begin(); i != notes_on.end(); ++i) { - if (*i == p) { - notes_on.erase(i); - break; - } - } - - break; - } - - case MidiEventType_ProgramChange: - snd_seq_ev_set_pgmchange(&ev, out.Channel(), out.ProgramNumber()); - break; - - // Unknown type, do nothing - default: - return; - } - - snd_seq_event_output(alsa_seq, &ev); - snd_seq_drain_output(alsa_seq); -} - -void MidiCommOut::Reset() { - - // Sent Note-Off to every open note - snd_seq_event_t ev; - snd_seq_ev_clear(&ev); - snd_seq_ev_set_source(&ev, local_out); - snd_seq_ev_set_subs(&ev); - snd_seq_ev_set_direct(&ev); - - vector >::const_iterator i; - for (i = notes_on.begin(); i != notes_on.end(); ++i) { - snd_seq_ev_set_noteoff(&ev, i->first, i->second, 0); - - snd_seq_event_output(alsa_seq, &ev); - snd_seq_drain_output(alsa_seq); - } - -} - -void MidiCommOut::Reconnect() { - // We assume, that the client and the port is the same after device's reconnect - int res = snd_seq_connect_to(alsa_seq, local_out, m_description.client, m_description.port); -} diff --git a/src/MidiComm.h b/src/MidiComm.h deleted file mode 100644 index 17130d8f..00000000 --- a/src/MidiComm.h +++ /dev/null @@ -1,102 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_COMM_H -#define __MIDI_COMM_H - -#include -#include -#include -// #include - -#include "libmidi/MidiEvent.h" - -struct MidiCommDescription { - - unsigned int id; - std::string name; - - int client; - int port; -}; - -typedef std::vector MidiCommDescriptionList; - -// Start/Stop midi services (i.e. open/close sequencer) -void midiInit(); -void midiStop(); - -// Emulate MIDI keyboard using PC keyboard -void sendNote(const unsigned char note, bool on); - -// Once you create a MidiCommIn object. Use the Read() function -// to grab one event at a time from the buffer. -class MidiCommIn { -public: - - static MidiCommDescriptionList GetDeviceList(); - static void UpdateDeviceList(); - - // device_id is obtained from GetDeviceList() - MidiCommIn(unsigned int device_id); - ~MidiCommIn(); - - MidiCommDescription GetDeviceDescription() const { - return m_description; - } - - // Returns the next buffered input event. Use KeepReading() (usually in - // a while loop) to see if you should call this function. If called when - // KeepReading() is false, this will throw MidiError_NoInputAvailable. - MidiEvent Read(); - - // Discard events from the input buffer - void Reset(); - - // Returns whether the input device has more buffered events. - bool KeepReading() const; - bool ShouldReconnect() const; - void Reconnect(); - -private: - MidiCommDescription m_description; - bool m_should_reconnect; - -}; - -class MidiCommOut { -public: - - static MidiCommDescriptionList GetDeviceList(); - static void UpdateDeviceList(); - - // device_id is obtained from GetDeviceList() - MidiCommOut(unsigned int device_id); - ~MidiCommOut(); - - MidiCommDescription GetDeviceDescription() const { - return m_description; - } - - // Send a single event out to the device. - void Write(const MidiEvent &out); - - // Turns all notes off and resets all controllers - void Reset(); - - void Reconnect(); - -private: - void Release(); - - MidiCommDescription m_description; - std::vector > notes_on; - -}; - -#endif // __MIDI_COMM_H diff --git a/src/OSGraphics.h b/src/OSGraphics.h deleted file mode 100644 index bdd519d6..00000000 --- a/src/OSGraphics.h +++ /dev/null @@ -1,30 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __OS_GRAPHICS_H -#define __OS_GRAPHICS_H - -// only for 'Ms. pepis' debugging -#include - - - -#include -#include - -#include -#include - -// #include -// #include - - - -#endif // __OS_GRAPHICS_H - - diff --git a/src/PlayingState.cpp b/src/PlayingState.cpp deleted file mode 100644 index 55604c41..00000000 --- a/src/PlayingState.cpp +++ /dev/null @@ -1,857 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "PlayingState.h" -#include "TrackSelectionState.h" -#include "StatsState.h" -#include "Renderer.h" -#include "Textures.h" -#include "CompatibleSystem.h" - -#include -#include - -#include "StringUtil.h" -#include "MenuLayout.h" -#include "TextWriter.h" - -#include "libmidi/Midi.h" -#include "libmidi/MidiTrack.h" -#include "libmidi/MidiEvent.h" -#include "libmidi/MidiUtil.h" - -#include "MidiComm.h" - -using namespace std; - - -void PlayingState::SetupNoteState() { - - TranslatedNoteSet old = m_notes; - m_notes.clear(); - - for (TranslatedNoteSet::const_iterator i = old.begin(); i != old.end(); ++i) { - TranslatedNote n = *i; - - n.state = AutoPlayed; - n.retry_state = AutoPlayed; - if (isUserPlayableTrack(n.track_id)) - { - n.state = UserPlayable; - n.retry_state = UserPlayable; - } - - m_notes.insert(n); - } -} - -void PlayingState::ResetSong() { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - if (m_state.midi_in) - m_state.midi_in->Reset(); - - // TODO: These should be moved to a configuration file - // along with ALL other "const static something" variables. - const static microseconds_t LeadIn = 5500000; - const static microseconds_t LeadOut = 1000000; - - if (!m_state.midi) - return; - - m_state.midi->Reset(LeadIn, LeadOut); - - m_notes = m_state.midi->Notes(); - m_notes_history.clear(); - SetupNoteState(); - - m_state.stats = SongStatistics(); - m_state.stats.total_note_count = static_cast(m_notes.size()); - - m_current_combo = 0; - - m_note_offset = 0; - m_max_allowed_title_alpha = 1.0; - - m_should_retry = false; - m_should_wait_after_retry = false; - m_retry_start = m_state.midi->GetNextBarInMicroseconds(-1000000000); -} - -PlayingState::PlayingState(const SharedState &state) : - m_paused(false), - m_keyboard(0), - m_any_you_play_tracks(false), - m_first_update(true), - m_should_retry(false), - m_should_wait_after_retry(false), - m_retry_start(0), - m_state(state) { -} - -void PlayingState::Init() { - - if (!m_state.midi) - throw GameStateError("PlayingState: Init was passed a null MIDI!"); - - m_look_ahead_you_play_note_count = 0; - for (size_t i = 0; i < m_state.track_properties.size(); ++i) { - - if (m_state.track_properties[i].mode == Track::ModeYouPlay || - m_state.track_properties[i].mode == Track::ModeYouPlaySilently || - m_state.track_properties[i].mode == Track::ModeLearning || - m_state.track_properties[i].mode == Track::ModeLearningSilently) { - m_look_ahead_you_play_note_count += m_state.midi->Tracks()[i].Notes().size(); - m_any_you_play_tracks = true; - } - } - - // This many microseconds of the song will - // be shown on the screen at once - const static microseconds_t DefaultShowDurationMicroseconds = 3250000; - m_show_duration = DefaultShowDurationMicroseconds; - - int w = GetStateWidth(); - int h = GetStateHeight(); - - m_keyboard = new KeyboardDisplay(KeyboardSize88, GetStateWidth() - Layout::ScreenMarginX*2, CalcKeyboardHeight(),w,h); - - // Hide the mouse cursor while we're playing - Compatible::HideMouseCursor(); - - ResetSong(); -} - -PlayingState::~PlayingState() { - Compatible::ShowMouseCursor(); -} - -int PlayingState::CalcKeyboardHeight() const { - // Start with the size of the screen - int height = GetStateHeight(); - - // Allow a couple lines of text below the keys - height -= 10; - - return height; -} - -void PlayingState::Play(microseconds_t delta_microseconds) { - - // Move notes, time tracking, everything - // delta_microseconds = 0 means, that we are on pause - MidiEventListWithTrackId evs = m_state.midi->Update(delta_microseconds); - - // These cycle is for keyboard updates (not falling keys) - const size_t length = evs.size(); - for(size_t i = 0; i < length; ++i) { - - const size_t &track_id = evs[i].first; - const MidiEvent &ev = evs[i].second; - - // Draw refers to the keys lighting up (automatically) -- not necessarily - // the falling notes. The KeyboardDisplay object contains its own logic - // to decide how to draw the falling notes - bool draw = false; - bool play = false; - switch (m_state.track_properties[track_id].mode) { - case Track::ModeNotPlayed: draw = false; play = false; break; - case Track::ModePlayedButHidden: draw = false; play = true; break; - case Track::ModeYouPlay: draw = false; play = false; break; - case Track::ModeYouPlaySilently: draw = false; play = false; break; - case Track::ModeLearning: draw = false; play = false; break; - case Track::ModeLearningSilently: draw = false; play = false; break; - case Track::ModePlayedAutomatically: draw = true; play = true; break; - case Track::ModeCount: break; - } - - // Even in "You Play" tracks, we have to play the non-note - // events as per usual. - if (m_state.track_properties[track_id].mode - && ev.Type() != MidiEventType_NoteOn - && ev.Type() != MidiEventType_NoteOff) - play = true; - - if (ev.Type() == MidiEventType_NoteOn || ev.Type() == MidiEventType_NoteOff) { - int vel = ev.NoteVelocity(); - const string name = MidiEvent::NoteName(ev.NoteNumber()); - - bool active = (vel > 0); - // Display pressed or released a key based on information from a MIDI-file. - // If this line is deleted, than no notes will be pressed automatically. - // It is not related to falling notes. - if (draw) - m_keyboard->SetKeyActive(name, active, m_state.track_properties[track_id].color); - filePressedKey(ev.NoteNumber(), active, track_id); - } - - if (play && m_state.midi_out) - { - // Clone event - MidiEvent ev_out = ev; - int vel = ev.NoteVelocity(); - // Scale note's volume before playing - ev_out.SetVelocity(vel * m_state.base_volume); - m_state.midi_out->Write(ev_out); - } - } -} - -double PlayingState::CalculateScoreMultiplier() const { - const static double MaxMultiplier = 5.0; - double multiplier = 1.0; - - const double combo_addition = m_current_combo / 10.0; - multiplier += combo_addition; - - return min(MaxMultiplier, multiplier); -} - -void PlayingState::Listen() { - if (!m_state.midi_in) - return; - - while (m_state.midi_in->KeepReading()) { - - microseconds_t cur_time = m_state.midi->GetSongPositionInMicroseconds(); - MidiEvent ev = m_state.midi_in->Read(); - if (m_state.midi_in->ShouldReconnect()) - { - m_state.midi_in->Reconnect(); - m_state.midi_out->Reconnect(); - continue; - } - - - // Just eat input if we're paused - if (m_paused) - continue; - - // We're only interested in NoteOn and NoteOff - if (ev.Type() != MidiEventType_NoteOn && ev.Type() != MidiEventType_NoteOff) - continue; - - // Octave Sliding - ev.ShiftNote(m_note_offset); - - int note_number = ev.NoteNumber(); - string note_name = MidiEvent::NoteName(note_number); - - // On key release we have to look for existing "active" notes and turn them off. - if (ev.Type() == MidiEventType_NoteOff || ev.NoteVelocity() == 0) { - - // NOTE: This assumes mono-channel input. If they're piping an entire MIDI file - // (or even the *same* MIDI file) through another source, we could get the - // same NoteId on different channels -- and this code would start behaving - // incorrectly. - for (ActiveNoteSet::iterator i = m_active_notes.begin(); i != m_active_notes.end(); ++i) { - if (ev.NoteNumber() != i->note_id) - continue; - - // Play it on the correct channel to turn the note we started - // previously, off. - ev.SetChannel(i->channel); - if (m_state.midi_out) - m_state.midi_out->Write(ev); - - m_active_notes.erase(i); - break; - } - - // User releases the key - // If we delete this line, than all pressed keys will be gray until - // it is unpressed automatically - m_keyboard->SetKeyActive(note_name, false, Track::FlatGray); - userPressedKey(note_number, false); - continue; - } - - TranslatedNoteSet::iterator closest_match = m_notes.end(); - for (TranslatedNoteSet::iterator i = m_notes.begin(); i != m_notes.end(); ++i) { - - const microseconds_t window_start = i->start - (KeyboardDisplay::NoteWindowLength / 2); - const microseconds_t window_end = i->start + (KeyboardDisplay::NoteWindowLength / 2); - - // As soon as we start processing notes that couldn't possibly - // have been played yet, we're done. - if (window_start > cur_time) - break; - - if (i->state != UserPlayable) - continue; - - if (window_end > cur_time && i->note_id == ev.NoteNumber()) { - - if (closest_match == m_notes.end()) { - closest_match = i; - continue; - } - - microseconds_t this_distance = cur_time - i->start; - if (i->start > cur_time) - this_distance = i->start - cur_time; - - microseconds_t known_best = cur_time - closest_match->start; - if (closest_match->start > cur_time) - known_best = closest_match->start - cur_time; - - if (this_distance < known_best) - closest_match = i; - } - } - - Track::TrackColor note_color = Track::FlatGray; - - if (closest_match != m_notes.end()) { - note_color = m_state.track_properties[closest_match->track_id].color; - - // "Open" this note so we can catch the close later and turn off - // the note. - ActiveNote n; - n.channel = closest_match->channel; - n.note_id = closest_match->note_id; - n.velocity = closest_match->velocity; - m_active_notes.insert(n); - - // Play it - ev.SetChannel(n.channel); - ev.SetVelocity(n.velocity); - - bool silently = - m_state.track_properties[closest_match->track_id].mode == Track::ModeYouPlaySilently || - m_state.track_properties[closest_match->track_id].mode == Track::ModeLearningSilently; - if (m_state.midi_out && !silently) - m_state.midi_out->Write(ev); - - // Adjust our statistics - const static double NoteValue = 100.0; - m_state.stats.score += NoteValue * CalculateScoreMultiplier() * (m_state.song_speed / 100.0); - - m_state.stats.notes_user_could_have_played++; - m_state.stats.speed_integral += m_state.song_speed; - - m_state.stats.notes_user_actually_played++; - m_current_combo++; - m_state.stats.longest_combo = max(m_current_combo, m_state.stats.longest_combo); - - TranslatedNote replacement = *closest_match; - replacement.state = UserHit; - - m_notes.erase(closest_match); - m_notes.insert(replacement); - } - - else - m_state.stats.stray_notes++; - - m_state.stats.total_notes_user_pressed++; - // Display a pressed key by an user - // Display a colored key, if it is pressed correctly - // Otherwise display a grey key - // - // If we comment this code, than a missed user pressed key will not shown. - // But correct presed key will be shown as usual. - m_keyboard->SetKeyActive(note_name, true, note_color); - userPressedKey(note_number, true); - } -} - -void PlayingState::Update() { - // Calculate how visible the title bar should be - const static double fade_in_ms = 350.0; - const static double stay_ms = 2500.0; - const static double fade_ms = 500.0; - - m_title_alpha = 0.0; - unsigned long ms = GetStateMilliseconds() * max(m_state.song_speed, 50) / 100; - - if (double(ms) <= stay_ms) - m_title_alpha = min(1.0, ms / fade_in_ms); - - if (double(ms) >= stay_ms) - m_title_alpha = min(max((fade_ms - (ms - stay_ms)) / fade_ms, 0.0), 1.0); - - // Lock down the alpha so that if you are slowing the song down as it - // fades out, it doesn't cut back into a much higher alpha value - m_title_alpha = min(m_title_alpha, m_max_allowed_title_alpha); - - if (double(ms) > stay_ms) - m_max_allowed_title_alpha = m_title_alpha; - - microseconds_t delta_microseconds = static_cast(GetDeltaMilliseconds()) * 1000; - - // The 100 term is really paired with the playback speed, but this - // formation is less likely to produce overflow errors. - delta_microseconds = (delta_microseconds / 100) * m_state.song_speed; - - if (m_paused) - delta_microseconds = 0; - - // Our delta milliseconds on the first frame after state start is extra - // long because we just reset the MIDI. By skipping the "Play" that - // update, we don't have an artificially fast-forwarded start. - if (!m_first_update) { - if (areAllRequiredKeysPressed()) - { - Play(delta_microseconds); -// m_should_wait_after_retry = false; // always reset onces pressed - } - else - m_current_combo = 0; - - Listen(); - } - - m_first_update = false; - - microseconds_t cur_time = m_state.midi->GetSongPositionInMicroseconds(); - - // Delete notes that are finished playing (and are no longer available to hit) - TranslatedNoteSet::iterator i = m_notes.begin(); - while (i != m_notes.end()) { - TranslatedNoteSet::iterator note = i++; - - const microseconds_t window_end = note->start + (KeyboardDisplay::NoteWindowLength / 2); - - if (m_state.midi_in && note->state == UserPlayable && window_end <= cur_time){ - TranslatedNote note_copy = *note; - note_copy.state = UserMissed; - - m_notes.erase(note); - m_notes.insert(note_copy); - - // Re-connect the (now-invalid) iterator to the replacement - note = m_notes.find(note_copy); - - if (m_state.track_properties[note->track_id].is_retry_on - && !m_should_wait_after_retry) - // They missed a note and should retry - // We don't count misses while waiting after retry - m_should_retry = true; - } - - if (note->start > cur_time) - break; - - if (note->end < cur_time && window_end < cur_time) { - - if (note->state == UserMissed) { - // They missed a note, reset the combo counter - m_current_combo = 0; - - m_state.stats.notes_user_could_have_played++; - m_state.stats.speed_integral += m_state.song_speed; - } - - TranslatedNote history_note = *note; - m_notes_history.insert(history_note); - m_notes.erase(note); - } - } - - if(IsKeyPressed(KeyGreater)) - m_note_offset += 12; - - if(IsKeyPressed(KeyLess)) - m_note_offset -= 12; - - if (IsKeyPressed(KeyUp)) { - m_show_duration -= 250000; - - const static microseconds_t MinShowDuration = 250000; - if (m_show_duration < MinShowDuration) - m_show_duration = MinShowDuration; - } - - if (IsKeyPressed(KeyDown)) { - m_show_duration += 250000; - - const static microseconds_t MaxShowDuration = 10000000; - if (m_show_duration > MaxShowDuration) - m_show_duration = MaxShowDuration; - } - - if (IsKeyPressed(KeyLeft)) { - m_state.song_speed -= 10; - if (m_state.song_speed < 0) - m_state.song_speed = 0; - } - - if (IsKeyPressed(KeyRight)) { - m_state.song_speed += 10; - if (m_state.song_speed > 400) - m_state.song_speed = 400; - } - - if (IsKeyPressed(KeyVolumeDown)) { - m_state.base_volume -= 0.1; - if (m_state.base_volume < 0) - m_state.base_volume = 0; - } - - if (IsKeyPressed(KeyVolumeUp)) { - m_state.base_volume += 0.1; - if (m_state.base_volume > 2) // Maximum volume is 200% - m_state.base_volume = 2; - } - - if (IsKeyPressed(KeyForward)) { - // Go 5 seconds forward - microseconds_t cur_time = m_state.midi->GetSongPositionInMicroseconds(); - microseconds_t new_time = cur_time + 5000000; - m_state.midi->GoTo(new_time); - m_required_notes.clear(); - m_state.midi_out->Reset(); - m_keyboard->ResetActiveKeys(); - m_notes = m_state.midi->Notes(); - m_notes_history.clear(); - SetupNoteState(); - m_should_retry = false; - m_should_wait_after_retry = false; - m_retry_start = new_time; - } - else - if (IsKeyPressed(KeyBackward)) { - // Go 5 seconds back - microseconds_t cur_time = m_state.midi->GetSongPositionInMicroseconds(); - microseconds_t new_time = cur_time - 5000000; - m_state.midi->GoTo(new_time); - m_required_notes.clear(); - m_state.midi_out->Reset(); - m_keyboard->ResetActiveKeys(); - m_notes = m_state.midi->Notes(); - m_notes_history.clear(); - SetupNoteState(); - m_should_retry = false; - m_should_wait_after_retry = false; - m_retry_start = new_time; - } - else - { - // Check retry conditions - // track_properties - microseconds_t next_bar_time = - m_state.midi->GetNextBarInMicroseconds(m_retry_start); - microseconds_t cur_time = m_state.midi->GetSongPositionInMicroseconds(); - // Check point in future - microseconds_t checkpoint_time = cur_time + delta_microseconds + 1; -// microseconds_t checkpoint_time = cur_time; - bool next_bar_exists = next_bar_time != 0; - bool next_bar_reached = checkpoint_time > next_bar_time; - if (next_bar_exists && next_bar_reached) - { - if (m_should_retry) - { - TranslatedNoteSet old = m_notes; - old.insert(m_notes_history.begin(), m_notes_history.end()); - - // Forget failed notes - m_should_retry = false; - // Should wait after retry for initial keys to be pressed - m_should_wait_after_retry = true; - - microseconds_t delta_microseconds = static_cast(GetDeltaMilliseconds()) * 1000; - microseconds_t new_time= m_retry_start-delta_microseconds; - // Retry - m_state.midi->GoTo(new_time); - m_required_notes.clear(); - m_pressed_notes.clear(); - m_state.midi_out->Reset(); - m_keyboard->ResetActiveKeys(); - TranslatedNoteSet def = m_state.midi->Notes(); - - // Set retry_state - // For each current node - // from SetupNoteState - m_notes.clear(); - m_notes_history.clear(); - for (TranslatedNoteSet::iterator i = def.begin(); i != def.end(); i++) { - TranslatedNote n = *i; - - n.state = AutoPlayed; - n.retry_state = AutoPlayed; - if (isUserPlayableTrack(n.track_id)) - { - n.state = UserPlayable; - n.retry_state = findNodeState(n, old, UserPlayable); - } - - m_notes.insert(n); - } - - // To avoid checks for keys that start before and stop after new_time - eraseUntilTime(new_time); - } - else - { - // Handle new retry block - m_retry_start = cur_time; - } - } - } - - if (IsKeyPressed(KeySpace)) - m_paused = !m_paused; - - if (IsKeyPressed(KeyEscape)) { - if (m_state.midi_out) - m_state.midi_out->Reset(); - - if (m_state.midi_in) - m_state.midi_in->Reset(); - - ChangeState(new TrackSelectionState(m_state)); - return; - } - - if (m_state.midi->IsSongOver()) { - if (m_state.midi_out) - m_state.midi_out->Reset(); - - if (m_state.midi_in) - m_state.midi_in->Reset(); - - if (m_state.midi_in && m_any_you_play_tracks) - ChangeState(new StatsState(m_state)); - - else - ChangeState(new TrackSelectionState(m_state)); - - return; - } -} - -void PlayingState::Draw(Renderer &renderer) const { - - const Tga *key_tex[4] = { GetTexture(PlayKeyRail), - GetTexture(PlayKeyShadow), - GetTexture(PlayKeysBlack, true), - GetTexture(PlayKeysWhite, true) }; - - const Tga *note_tex[4] = { GetTexture(PlayNotesWhiteShadow, true), - GetTexture(PlayNotesBlackShadow, true), - GetTexture(PlayNotesWhiteColor, true), - GetTexture(PlayNotesBlackColor, true) }; - renderer.ForceTexture(0); - - // Draw a keyboard, fallen keys and background for them - m_keyboard->Draw(renderer, key_tex, note_tex, Layout::ScreenMarginX, 0, m_notes, m_show_duration, - m_state.midi->GetSongPositionInMicroseconds(), m_state.track_properties, - m_state.midi->GetBarLines()); - - const int time_pb_width = static_cast(m_state.midi->GetSongPercentageComplete() * (GetStateWidth() - Layout::ScreenMarginX*2)); - //const int pb_x = Layout::ScreenMarginX+8; - //const int pb_y = CalcKeyboardHeight() - 238; - - const int pb_x = 0; - const int pb_y = 0; - - renderer.SetColor(0x60, 0x223, 0x60); - renderer.DrawQuad(pb_x, pb_y, time_pb_width, 6); - - // string title_text = m_state.song_title; - - // double alpha = m_title_alpha; - // if (m_paused) { - // alpha = 1.0; - // title_text = "Game Paused"; - // } - - // if (alpha > 0.001) { - // renderer.SetColor(0, 0, 0, int(alpha * 160)); - // renderer.DrawQuad(0, GetStateHeight() / 3, GetStateWidth(), 80); - // const Color c = Renderer::ToColor(255, 255, 255, int(alpha * 0xFF)); - // TextWriter title(GetStateWidth()/2, GetStateHeight()/3 + 25, renderer, true, 24); - // title << Text(title_text, c); - - // // While we're at it, show the key legend - // renderer.SetColor(c); - // const Tga *keys = GetTexture(PlayKeys); - // renderer.DrawTga(keys, GetStateWidth() / 2 - 250, GetStateHeight() / 2); - // } - - // int text_y = CalcKeyboardHeight() + 42; - - // renderer.SetColor(White); - // renderer.DrawTga(GetTexture(PlayStatus), Layout::ScreenMarginX - 1, text_y); - // renderer.DrawTga(GetTexture(PlayStatus2), Layout::ScreenMarginX + 273, text_y); - - // string multiplier_text = STRING(fixed << setprecision(1) << CalculateScoreMultiplier() << - // " Multiplier"); - // string speed_text = STRING(m_state.song_speed << "% Speed"); - - // TextWriter score(Layout::ScreenMarginX + 92, text_y + 5, renderer, - // false, Layout::ScoreFontSize); - // score << static_cast(m_state.stats.score); - - // TextWriter multipliers(Layout::ScreenMarginX + 232, text_y + 12, renderer, - // false, Layout::TitleFontSize+2); - // multipliers << Text(multiplier_text, Renderer::ToColor(138, 226, 52)); - - // int speed_x_offset = (m_state.song_speed >= 100 ? 0 : 11); - // TextWriter speed(Layout::ScreenMarginX + 412 + speed_x_offset, text_y + 12, - // renderer, false, Layout::TitleFontSize+2); - // speed << Text(speed_text, Renderer::ToColor(114, 159, 207)); - - // string retry_text = m_should_retry ? "R" : ""; - - // TextWriter retry(Layout::ScreenMarginX + 600, text_y + 12, - // renderer, false, Layout::TitleFontSize+2); - // retry << Text(retry_text, Renderer::ToColor(114, 159, 207)); - - // double non_zero_playback_speed = ( (m_state.song_speed == 0) ? 0.1 : (m_state.song_speed/100.0) ); - // microseconds_t tot_seconds = static_cast((m_state.midi->GetSongLengthInMicroseconds() / - // 100000.0) / non_zero_playback_speed); - // microseconds_t cur_seconds = static_cast((m_state.midi->GetSongPositionInMicroseconds() / - // 100000.0) / non_zero_playback_speed); - - // if (cur_seconds < 0) - // cur_seconds = 0; - - // if (cur_seconds > tot_seconds) - // cur_seconds = tot_seconds; - - // int completion = static_cast(m_state.midi->GetSongPercentageComplete() * 100.0); - - // unsigned int tot_min = static_cast((tot_seconds/10) / 60); - // unsigned int tot_sec = static_cast((tot_seconds/10) % 60); - // unsigned int tot_ten = static_cast( tot_seconds%10); - // const string total_time = STRING(tot_min << ":" << setfill('0') << setw(2) << tot_sec << "." << tot_ten); - - // unsigned int cur_min = static_cast((cur_seconds/10) / 60); - // unsigned int cur_sec = static_cast((cur_seconds/10) % 60); - // unsigned int cur_ten = static_cast( cur_seconds%10 ); - // const string current_time = STRING(cur_min << ":" << setfill('0') << setw(2) << cur_sec << "." << cur_ten); - // const string percent_complete = STRING(" (" << completion << "%)"); - - // text_y += 30 + Layout::SmallFontSize; - // TextWriter time_text(Layout::ScreenMarginX + 39, text_y+2, renderer, false, Layout::SmallFontSize); - // time_text << STRING(current_time << " / " << total_time << percent_complete); - - // // Draw a song progress bar along the top of the screen - // const int time_pb_width = static_cast(m_state.midi->GetSongPercentageComplete() * (GetStateWidth() - - // Layout::ScreenMarginX*2)); - // const int pb_x = Layout::ScreenMarginX; - // const int pb_y = CalcKeyboardHeight() + 25; - - // renderer.SetColor(0x50, 0x50, 0x50); - // renderer.DrawQuad(pb_x, pb_y, time_pb_width, 16); - - // if (m_look_ahead_you_play_note_count > 0) { - - // const double note_count = 1.0 * m_look_ahead_you_play_note_count; - - // const int note_miss_pb_width = static_cast(m_state.stats.notes_user_could_have_played / - // note_count * (GetStateWidth() - Layout::ScreenMarginX*2)); - - // const int note_hit_pb_width = static_cast(m_state.stats.notes_user_actually_played / - // note_count * (GetStateWidth() - Layout::ScreenMarginX*2)); - - // renderer.SetColor(0xCE,0x5C,0x00); - // renderer.DrawQuad(pb_x, pb_y - 20, note_miss_pb_width, 16); - - // renderer.SetColor(0xFC,0xAF,0x3E); - // renderer.DrawQuad(pb_x, pb_y - 20, note_hit_pb_width, 16); - // } - - // // Show the combo - // if (m_current_combo > 5) { - // int combo_font_size = 20; - // combo_font_size += (m_current_combo / 10); - - // int combo_x = GetStateWidth() / 2; - // int combo_y = GetStateHeight() - CalcKeyboardHeight() + 30 - (combo_font_size/2); - - // TextWriter combo_text(combo_x, combo_y, renderer, true, combo_font_size); - // combo_text << STRING(m_current_combo << " Combo!"); - // } -} - - -void PlayingState::userPressedKey(int note_number, bool active) -{ - if (active) - { - if (m_should_wait_after_retry) - { - m_should_retry = false; // to ensure - m_should_wait_after_retry = false; - } - m_pressed_notes.insert(note_number); - m_required_notes.erase(note_number); - m_state.dpms_thread->handleKeyPress(); - } - else - m_pressed_notes.erase(note_number); -} - -void PlayingState::filePressedKey(int note_number, bool active, size_t track_id) -{ - if (m_state.track_properties[track_id].mode == Track::ModeLearning || - m_state.track_properties[track_id].mode == Track::ModeLearningSilently || - (m_should_wait_after_retry && isUserPlayableTrack(track_id))) - { - if (active) - { - m_required_notes.insert(note_number); - } - else - m_required_notes.erase(note_number); - } -} - -bool PlayingState::isKeyPressed(int note_number) -{ - return (m_pressed_notes.find(note_number) != m_pressed_notes.end()); -} - -bool PlayingState::areAllRequiredKeysPressed() -{ - return m_required_notes.empty(); -} - -bool PlayingState::isUserPlayableTrack(size_t track_id) -{ - return (m_state.track_properties[track_id].mode == Track::ModeYouPlay || - m_state.track_properties[track_id].mode == Track::ModeYouPlaySilently || - m_state.track_properties[track_id].mode == Track::ModeLearning || - m_state.track_properties[track_id].mode == Track::ModeLearningSilently); -} - -void PlayingState::eraseUntilTime(microseconds_t time) -{ - for (TranslatedNoteSet::const_iterator i = m_notes.begin(); i != m_notes.end();) { - TranslatedNoteSet::const_iterator j = i; - TranslatedNote n = *i; - i++; - - // Erase very old notes - if (n.end < time) - m_notes.erase(j); - else - // Hit still visible once - if (n.start <= time) - { - n.state = UserHit; - m_notes.erase(j); - m_notes.insert(n); - } - } -} - -NoteState PlayingState::findNodeState(const TranslatedNote& note, TranslatedNoteSet& notes, NoteState default_note_state) -{ - // Search by comparing start, end, note_id and track_id - TranslatedNoteSet::iterator n = notes.find(note); - if (n == notes.end()) - return default_note_state; - - return n->state; -} diff --git a/src/PlayingState.h b/src/PlayingState.h deleted file mode 100644 index b797aeb6..00000000 --- a/src/PlayingState.h +++ /dev/null @@ -1,112 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __PLAYING_STATE_H -#define __PLAYING_STATE_H - -#include -#include -#include - -#include "libmidi/Midi.h" -#include "SharedState.h" -#include "GameState.h" -#include "KeyboardDisplay.h" -#include "MidiComm.h" - -struct ActiveNote { - - bool operator()(const ActiveNote &lhs, const ActiveNote &rhs) { - if (lhs.note_id < rhs.note_id) - return true; - - if (lhs.note_id > rhs.note_id) - return false; - - if (lhs.channel < rhs.channel) - return true; - - if (lhs.channel > rhs.channel) - return false; - - return false; - } - - NoteId note_id; - unsigned char channel; - int velocity; -}; - -typedef std::set ActiveNoteSet; - - -class PlayingState : public GameState { -public: - PlayingState(const SharedState &state); - ~PlayingState(); - bool ResetKeyboardActive(); - -protected: - virtual void Init(); - virtual void Update(); - virtual void Draw(Renderer &renderer) const; - -private: - - std::set m_pressed_notes; - std::set m_required_notes; - - void userPressedKey(int note_number, bool active); - void filePressedKey(int note_number, bool active, size_t track_id); - bool areAllRequiredKeysPressed(); - bool isKeyPressed(int note_number); - bool isUserPlayableTrack(size_t track_id); - - int CalcKeyboardHeight() const; - void SetupNoteState(); - - void ResetSong(); - void Play(microseconds_t delta_microseconds); - void Listen(); - - double CalculateScoreMultiplier() const; - - bool m_paused; - - KeyboardDisplay *m_keyboard; - microseconds_t m_show_duration; - TranslatedNoteSet m_notes; - TranslatedNoteSet m_notes_history; - - bool m_any_you_play_tracks; - size_t m_look_ahead_you_play_note_count; - - ActiveNoteSet m_active_notes; - - bool m_first_update; - - SharedState m_state; - int m_current_combo; - - double m_title_alpha; - double m_max_allowed_title_alpha; - - // For octave sliding - int m_note_offset; - - // For retries - bool m_should_retry; - bool m_should_wait_after_retry; - microseconds_t m_retry_start; - - void eraseUntilTime(microseconds_t time); - - NoteState findNodeState(const TranslatedNote& note, TranslatedNoteSet& notes, NoteState default_note_state); -}; - -#endif // __PLAYING_STATE_H diff --git a/src/Renderer.cpp b/src/Renderer.cpp deleted file mode 100644 index 74065404..00000000 --- a/src/Renderer.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "Renderer.h" -#include "Tga.h" -#include "OSGraphics.h" - -#include - -using namespace std; - -// These are static because OpenGL is (essentially) static -static unsigned int last_texture_id = numeric_limits::max(); - -void SelectTexture(unsigned int texture_id) { - - if (texture_id == last_texture_id) - return; - - glBindTexture(GL_TEXTURE_2D, texture_id); - last_texture_id = texture_id; -} - -unsigned int Renderer::GetLastTGAID() { - return last_texture_id; -} - -Renderer::Renderer(GLContext glcontext, PGContext pangocontext) : - m_xoffset(0), - m_yoffset(0), - m_glcontext(glcontext), - m_pangocontext(pangocontext) { - glewInit(); -} - -Color Renderer::ToColor(int r, int g, int b, int a) { - - Color c; - c.r = r; - c.g = g; - c.b = b; - c.a = a; - - return c; -} - -void Renderer::SetVSyncInterval(int interval) { -// #ifdef WIN32 - -// const char *extensions = reinterpret_cast(static_cast(glGetString( GL_EXTENSIONS ))); - -// // Check if the WGL_EXT_swap_control extension is supported. -// if (strstr(extensions, "WGL_EXT_swap_control") == 0) return; - -// typedef BOOL (APIENTRY *SWAP_INTERVAL_PROC)( int ); -// SWAP_INTERVAL_PROC wglSwapIntervalEXT = (SWAP_INTERVAL_PROC)wglGetProcAddress( "wglSwapIntervalEXT" ); -// if (wglSwapIntervalEXT) wglSwapIntervalEXT(interval); - -// #else - -// GLint i = interval; -// GLboolean ret = aglSetInteger(m_glcontext, AGL_SWAP_INTERVAL, &i); -// if (ret == GL_FALSE) -// { -// // LOGTODO! -// // This is non-critical. V-Sync might just not be supported. -// } - -// #endif -} - -void Renderer::SwapBuffers() { - m_glcontext->get_gl_drawable()->swap_buffers(); -} - -void Renderer::ForceTexture(unsigned int texture_id) { - last_texture_id = numeric_limits::max(); - SelectTexture(texture_id); -} - -void Renderer::SetColor(Color c) { - SetColor(c.r, c.g, c.b, c.a); -} - -void Renderer::SetColor(int r, int g, int b, int a) { - glColor4f(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); -} - -void Renderer::DrawQuad(int x, int y, int w, int h) { - SelectTexture(0); - - glBegin(GL_QUADS); - glVertex3i( x + m_xoffset, y + m_yoffset, 0); - glVertex3i( x+w + m_xoffset, y + m_yoffset, 0); - glVertex3i( x+w + m_xoffset, y+h + m_yoffset, 0); - glVertex3i( x + m_xoffset, y+h + m_yoffset, 0); - glEnd(); -} - -void Renderer::DrawTga(const Tga *tga, int x, int y) const { - DrawTga(tga, x, y, (int)tga->GetWidth(), (int)tga->GetHeight(), 0, 0); -} - -void Renderer::DrawTga(const Tga *tga, int in_x, int in_y, int width, int height, - int src_x, int src_y) const { - - const int x = in_x + m_xoffset; - const int y = in_y + m_yoffset; - - const double tx = static_cast(src_x) / static_cast(tga->GetWidth()); - const double ty = -static_cast(src_y) / static_cast(tga->GetHeight()); - const double tw = static_cast(width) / static_cast(tga->GetWidth()); - const double th = -static_cast(height)/ static_cast(tga->GetHeight()); - - SelectTexture(tga->GetId()); - glBegin(GL_QUADS); - glTexCoord2d( tx, ty); glVertex3i( x, y, 0); - glTexCoord2d( tx, ty+th); glVertex3i( x, y+height, 0); - glTexCoord2d(tx+tw, ty+th); glVertex3i(x+width, y+height, 0); - glTexCoord2d(tx+tw, ty); glVertex3i(x+width, y, 0); - glEnd(); -} - -void Renderer::DrawStretchedTga(const Tga *tga, int x, int y, int w, int h) const { - DrawStretchedTga(tga, x, y, w, h, 0, 0, (int)tga->GetWidth(), (int)tga->GetHeight()); -} - -void Renderer::DrawStretchedTga(const Tga *tga, int x, int y, int w, int h, - int src_x, int src_y, int src_w, int src_h) const { - const int sx = x + m_xoffset; - const int sy = y + m_yoffset; - - const double tx = static_cast(src_x) / static_cast(tga->GetWidth()); - const double ty = -static_cast(src_y) / static_cast(tga->GetHeight()); - const double tw = static_cast(src_w) / static_cast(tga->GetWidth()); - const double th = -static_cast(src_h) / static_cast(tga->GetHeight()); - - SelectTexture(tga->GetId()); - - glBegin(GL_QUADS); - glTexCoord2d( tx, ty); glVertex3i( sx, sy, 0); - glTexCoord2d( tx, ty+th); glVertex3i( sx, sy+h, 0); - glTexCoord2d(tx+tw, ty+th); glVertex3i(sx+w, sy+h, 0); - glTexCoord2d(tx+tw, ty); glVertex3i(sx+w, sy, 0); - glEnd(); -} diff --git a/src/Renderer.h b/src/Renderer.h deleted file mode 100644 index b07af5d2..00000000 --- a/src/Renderer.h +++ /dev/null @@ -1,72 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __RENDERER_H -#define __RENDERER_H - -#include "OSGraphics.h" -#include "Tga.h" - -typedef Glib::RefPtr GLContext; -typedef Glib::RefPtr PGContext; - -struct Color { - int r, g, b, a; -}; - -class Renderer { -public: - Renderer(GLContext glcontext, PGContext pangocontext); - - - unsigned int GetLastTGAID(); - - static Color ToColor(int r, int g, int b, int a = 0xFF); - - void SwapBuffers(); - - // 0 will disable vsync, 1 will enable. - void SetVSyncInterval(int interval = 1); - - void SetOffset(int x, int y) { - m_xoffset = x; m_yoffset = y; - } - - void ResetOffset() { - SetOffset(0,0); - } - - void ForceTexture(unsigned int texture_id); - - void SetColor(Color c); - void SetColor(int r, int g, int b, int a = 0xFF); - void DrawQuad(int x, int y, int w, int h); - - void DrawTga(const Tga *tga, int x, int y) const; - void DrawTga(const Tga *tga, int x, int y, int width, int height, - int src_x, int src_y) const; - - void DrawStretchedTga(const Tga *tga, int x, int y, int w, int h) const; - void DrawStretchedTga(const Tga *tga, int x, int y, int w, int h, - int src_x, int src_y, int src_w, int src_h) const; - -private: - - // NOTE: These are used externally by the friend - // class TextWriter (along with the context) - int m_xoffset; - int m_yoffset; - - GLContext m_glcontext; - PGContext m_pangocontext; - - friend class Text; - friend class TextWriter; -}; - -#endif // __RENDERER_H diff --git a/src/SharedState.h b/src/SharedState.h deleted file mode 100644 index 505ad3af..00000000 --- a/src/SharedState.h +++ /dev/null @@ -1,73 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __SHARED_STATE_H -#define __SHARED_STATE_H - -#include -#include - -#include "TrackProperties.h" -#include "MidiComm.h" -#include "libmidi/Midi.h" -#include "DpmsThread.h" - -struct SongStatistics { - - SongStatistics() : - total_note_count(0), - notes_user_could_have_played(0), - speed_integral(0), - notes_user_actually_played(0), - stray_notes(0), - total_notes_user_pressed(0), - longest_combo(0), - score(0) { - } - - int total_note_count; - - int notes_user_could_have_played; - long speed_integral; - - int notes_user_actually_played; - - int stray_notes; - int total_notes_user_pressed; - - int longest_combo; - double score; - -}; - -struct SharedState { - - SharedState() : - midi(0), - midi_out(0), - midi_in(0), - dpms_thread(0), - song_speed(100), - base_volume(1) - {} - - Midi *midi; - MidiCommOut *midi_out; - MidiCommIn *midi_in; - DpmsThread *dpms_thread; - - SongStatistics stats; - - int song_speed; - double base_volume; - - std::vector track_properties; - std::string song_title; -}; - -#endif // __SHARED_STATE_H diff --git a/src/StatsState.cpp b/src/StatsState.cpp deleted file mode 100644 index b4c9e4d8..00000000 --- a/src/StatsState.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "StatsState.h" -#include "TrackSelectionState.h" -#include "PlayingState.h" -#include "Renderer.h" -#include "Textures.h" - -#include - -using namespace std; - -void StatsState::Init() { - m_back_button = ButtonState( - Layout::ScreenMarginX, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::ButtonHeight/2, - Layout::ButtonWidth, Layout::ButtonHeight); - - m_continue_button = ButtonState( - GetStateWidth() - Layout::ScreenMarginX - Layout::ButtonWidth, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::ButtonHeight/2, - Layout::ButtonWidth, Layout::ButtonHeight); -} - -void StatsState::Update() { - - MouseInfo mouse = Mouse(); - - m_continue_button.Update(mouse); - m_back_button.Update(mouse); - - if (IsKeyPressed(KeyEscape) || m_back_button.hit) { - ChangeState(new TrackSelectionState(m_state)); - return; - } - - if (IsKeyPressed(KeyEnter) || m_continue_button.hit) { - ChangeState(new PlayingState(m_state)); - return; - } - - m_tooltip = ""; - if (m_back_button.hovering) - m_tooltip = "Return to the track selection screen."; - - if (m_continue_button.hovering) - m_tooltip = "Try this song again with the same settings."; -} - -void StatsState::Draw(Renderer &renderer) const { - - const bool ConstrainedHeight = (GetStateHeight() < 720); - - int left = GetStateWidth() / 2 + 40; - const int InstructionsY = ConstrainedHeight ? 120 : 263; - - renderer.SetColor(White); - renderer.DrawTga(GetTexture(StatsText), left - 270, InstructionsY - 113); - - if (!ConstrainedHeight) { - Layout::DrawTitle(renderer, m_state.song_title); - Layout::DrawHorizontalRule(renderer, GetStateWidth(), Layout::ScreenMarginY); - } - - Layout::DrawHorizontalRule(renderer, GetStateWidth(), GetStateHeight() - Layout::ScreenMarginY); - - Layout::DrawButton(renderer, m_continue_button, "RetrySong"); - Layout::DrawButton(renderer, m_back_button, "ChooseTracks"); - - const SongStatistics &s = m_state.stats; - - double hit_percent = 0.0; - if (s.notes_user_could_have_played > 0) { - hit_percent = 100.0 * (s.notes_user_actually_played / (s.notes_user_could_have_played * 1.0)); - } - - string grade = "F"; - if (hit_percent >= 50) grade = "D-"; - if (hit_percent >= 55) grade = "D"; - if (hit_percent >= 63) grade = "D+"; - if (hit_percent >= 70) grade = "C-"; - if (hit_percent >= 73) grade = "C"; - if (hit_percent >= 77) grade = "C+"; - if (hit_percent >= 80) grade = "B-"; - if (hit_percent >= 83) grade = "B"; - if (hit_percent >= 87) grade = "B+"; - if (hit_percent >= 90) grade = "A-"; - if (hit_percent >= 93) grade = "A"; - if (hit_percent >= 97) grade = "A+"; - if (hit_percent >= 99) grade = "A++"; - if (hit_percent >= 100) grade = "A+++"; - - int stray_percent = 0; - if (s.total_notes_user_pressed > 0) - stray_percent = static_cast((100.0 * s.stray_notes) / s.total_notes_user_pressed); - - int average_speed = 0; - if (s.notes_user_could_have_played > 0) - average_speed = s.speed_integral / s.notes_user_could_have_played; - - // Choose a dynamic color for the grade - const double p = hit_percent / 100.0; - const double r = max(0.0, 1 - (p*p*p*p)); - const double g = max(0.0, 1 - (((p- 1)*4)*((p- 1)*4))); - const double b = max(0.0, 1 - (((p-.75)*5)*((p-.75)*5))); - - const Color c = Renderer::ToColor(int(r*0xFF), int(g*0xFF), int(b*0xFF)); - - TextWriter grade_text(left - 5, InstructionsY - 15, renderer, false, 100); - grade_text << Text(grade, c); - - TextWriter score(left, InstructionsY + 112, renderer, false, 28); - score << STRING(static_cast(s.score)); - - TextWriter speed(left, InstructionsY + 147, renderer, false, 28); - speed << STRING(average_speed << " %"); - - TextWriter good(left, InstructionsY + 218, renderer, false, 28); - good << STRING(s.notes_user_actually_played << " / " << - s.notes_user_could_have_played << " (" << - static_cast(hit_percent) << " %" << ")"); - - TextWriter stray(left, InstructionsY + 255, renderer, false, 28); - stray << STRING(s.stray_notes << " (" << stray_percent << " %" << ")"); - - TextWriter combo(left, InstructionsY + 323, renderer, false, 28); - combo << STRING(s.longest_combo); - - TextWriter tooltip(GetStateWidth() / 2, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::TitleFontSize/2, - renderer, true, Layout::TitleFontSize); - - tooltip << m_tooltip; -} diff --git a/src/StatsState.h b/src/StatsState.h deleted file mode 100644 index 97f2c80d..00000000 --- a/src/StatsState.h +++ /dev/null @@ -1,37 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __STATS_STATE_H -#define __STATS_STATE_H - -#include "SharedState.h" -#include "GameState.h" -#include "MenuLayout.h" - -class StatsState : public GameState { -public: - - StatsState(const SharedState &state) : - m_state(state) { - } - -protected: - virtual void Init(); - virtual void Update(); - virtual void Draw(Renderer &renderer) const; - -private: - ButtonState m_continue_button; - ButtonState m_back_button; - - std::string m_tooltip; - - SharedState m_state; -}; - -#endif // __STATS_STATE_H diff --git a/src/StringTile.cpp b/src/StringTile.cpp deleted file mode 100644 index e1299057..00000000 --- a/src/StringTile.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "StringTile.h" -#include "TextWriter.h" -#include "Renderer.h" - -StringTile::StringTile(int x, int y, Tga *graphics) : - m_x(x), m_y(y), m_graphics(graphics) { - - whole_tile = ButtonState(0, 0, StringTileWidth, StringTileHeight); -} - -void StringTile::Update(const MouseInfo &translated_mouse) { - - whole_tile.Update(translated_mouse); -} - -void StringTile::Draw(Renderer &renderer) const { - - renderer.SetOffset(m_x, m_y); - - const Color hover = Renderer::ToColor(0xFF, 0xFF, 0xFF); - const Color no_hover = Renderer::ToColor(0xE0, 0xE0, 0xE0); - renderer.SetColor(whole_tile.hovering ? hover : no_hover); - renderer.DrawTga(m_graphics, 0, 0); - - TextWriter text(20, 46, renderer, false, 14); - text << m_string; - - renderer.ResetOffset(); -} - diff --git a/src/StringTile.h b/src/StringTile.h deleted file mode 100644 index 0b85df70..00000000 --- a/src/StringTile.h +++ /dev/null @@ -1,63 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __STRING_TILE_H -#define __STRING_TILE_H - -#include "GameState.h" -#include "MenuLayout.h" -#include - -const int StringTileWidth = 510; -const int StringTileHeight = 80; - -class StringTile { -public: - - StringTile(int x, int y, Tga *graphics); - - void Update(const MouseInfo &translated_mouse); - void Draw(Renderer &renderer) const; - - int GetX() const { - return m_x; - } - - int GetY() const { - return m_y; - } - - bool Hit() const { - return whole_tile.hit; - } - - void SetString(const std::string &s) { - m_string = s; - } - - void SetTitle(const std::string &s) { - m_title = s; - } - - const ButtonState WholeTile() const { - return whole_tile; - } - -private: - int m_x; - int m_y; - - Tga *m_graphics; - - std::string m_string; - std::string m_title; - - ButtonState whole_tile; -}; - -#endif // __STRING_TILE_H diff --git a/src/StringUtil.h b/src/StringUtil.h deleted file mode 100644 index 97f47a7e..00000000 --- a/src/StringUtil.h +++ /dev/null @@ -1,71 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __STRING_UTIL_H -#define __STRING_UTIL_H - -// Handy string macros -#ifndef STRING -#include -#define STRING(v) ((static_cast(std::ostringstream().\ - flush() << v)).str()) -#endif - -#include -#include -#include -#include -#include -#include - -// string_type here can be things like std::string or std::wstring -template -const string_type StringLower(string_type s) { - - std::locale loc; - - std::transform(s.begin(), s.end(), s.begin(), - std::bind1st( std::mem_fun( &std::ctype::tolower ), - &std::use_facet< std::ctype >( loc ) ) ); - - return s; -} - -// E here is usually wchar_t -template, class A = std::allocator > -class Widen : public std::unary_function< const std::string&, std::basic_string > { - -public: - - Widen(const std::locale& loc = std::locale()) : loc_(loc) { - pCType_ = &std::use_facet >(loc); - } - - std::basic_string operator() (const std::string& str) const { - if (str.length() == 0) return std::basic_string(); - - typename std::basic_string::size_type srcLen = str.length(); - const char* pSrcBeg = str.c_str(); - std::vector tmp(srcLen); - - pCType_->widen(pSrcBeg, pSrcBeg + srcLen, &tmp[0]); - return std::basic_string(&tmp[0], srcLen); - } - -private: - - std::locale loc_; - const std::ctype* pCType_; - - // No copy-constructor or no assignment operator - Widen(const Widen&); - Widen& operator= (const Widen&); - -}; - -#endif // __STRING_UTIL_H diff --git a/src/TextWriter.cpp b/src/TextWriter.cpp deleted file mode 100644 index d071ca12..00000000 --- a/src/TextWriter.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "TextWriter.h" -#include "Renderer.h" -#include "LinthesiaError.h" -#include "OSGraphics.h" -#include "UserSettings.h" - -#include -#include - -using namespace std; - -// TODO: This should be deleted at shutdown -static map font_size_lookup; - -// TODO: This should be deleted at shutdown -static map font_lookup; - -// Returns the most suitable font available on the platform -// or an empty string if no font is available; -static const std::string get_default_font(); - -TextWriter::TextWriter(int in_x, int in_y, Renderer &in_renderer, - bool in_centered, int in_size, string fontname) : - x(in_x), - y(in_y), - size(in_size), - original_x(0), - last_line_height(0), - centered(in_centered), - renderer(in_renderer) { - - x += renderer.m_xoffset; - original_x = x; - - y += renderer.m_yoffset; - point_size = size; - - - if (font_size_lookup[size] == 0) { - - // Get font from user settings - // if (fontname.empty()) { - // string key = "font_desc"; - // fontname = UserSetting::Get(key, ""); - - // // Or set it if there is no default - // if (fontname.empty()) { - // fontname = get_default_font(); - // UserSetting::Set(key, fontname); - // } - // } - - int list_start = glGenLists(128); - fontname = STRING(fontname << " " << in_size); - - //@TODO Beter Font System!!! - Pango::FontDescription* font_desc = new Pango::FontDescription("Roboto Medium"); - - Glib::RefPtr ret = Gdk::GL::Font::use_pango_font(*font_desc, 0, 128, list_start); - if (!ret) - throw LinthesiaError("An error ocurred while trying to use use_pango_font() with " - "font '" + fontname + "'"); - - font_size_lookup[size] = list_start; - font_lookup[size] = font_desc; - } -} - -int TextWriter::get_point_size() { - return point_size; -} - -TextWriter& TextWriter::next_line() { - y += max(last_line_height, get_point_size()); - x = original_x; - - last_line_height = 0; - return *this; -} - -TextWriter& Text::operator<<(TextWriter& tw) const { - int draw_x; - int draw_y; - calculate_position_and_advance_cursor(tw, &draw_x, &draw_y); - - string narrow(m_text.begin(), m_text.end()); - - glBindTexture(GL_TEXTURE_2D, 0); - - glPushMatrix(); - tw.renderer.SetColor(m_color); - glListBase(font_size_lookup[tw.size]); - glRasterPos2i(draw_x, draw_y + tw.size); - glCallLists(static_cast(narrow.length()), GL_UNSIGNED_BYTE, narrow.c_str()); - glPopMatrix(); - - // TODO: Should probably delete these on shutdown. - //glDeleteLists(1000, 128); - - return tw; -} - -void Text::calculate_position_and_advance_cursor(TextWriter &tw, int *out_x, int *out_y) const { - - Glib::RefPtr layout = Pango::Layout::create(tw.renderer.m_pangocontext); - layout->set_text(m_text); - layout->set_font_description(*(font_lookup[tw.size])); - - Pango::Rectangle drawing_rect = layout->get_pixel_logical_extents(); - tw.last_line_height = drawing_rect.get_height(); - - if (tw.centered) - *out_x = tw.x - drawing_rect.get_width() / 2; - - else { - *out_x = tw.x; - tw.x += drawing_rect.get_width(); - } - - *out_y = tw.y; -} - -TextWriter& operator<<(TextWriter& tw, const Text& t) { - return t.operator <<(tw); -} - -TextWriter& newline(TextWriter& tw) { - return tw.next_line(); -} - -TextWriter& operator<<(TextWriter& tw, const string& s) { return tw << Text(s, White); } -TextWriter& operator<<(TextWriter& tw, const int& i) { return tw << Text(i, White); } -TextWriter& operator<<(TextWriter& tw, const unsigned int& i) { return tw << Text(i, White); } -TextWriter& operator<<(TextWriter& tw, const long& l) { return tw << Text(l, White); } -TextWriter& operator<<(TextWriter& tw, const unsigned long& l) { return tw << Text(l, White); } - -static -const std::string get_default_font() -{ - // populate a vector of candidates with the most common choices - vector< string > allCandidates; - allCandidates.push_back("serif"); - allCandidates.push_back("sans"); - allCandidates.push_back("clean"); - allCandidates.push_back("courier"); // Debian suggests using courier - - vector< string >::const_iterator candidate; - const vector< string >::const_iterator end = allCandidates.end(); - - // retrieve all fonts from the X server - Display * const display = XOpenDisplay(NULL); - int nbFonts = 0, i = 0; - char ** const allFonts = XListFonts(display, "-*", 32767, &nbFonts); - - string returnedFont = (nbFonts > 0) ? allFonts[0] : ""; - - // check if we have a candidate, and returns it if we do - string currentFont; - bool found = false; - for (i = 0; i < nbFonts && !found; ++i) - { - currentFont = allFonts[i]; - - for (candidate = allCandidates.begin(); - candidate != end && !found; ++candidate) - { - // any font that contains the name of the candidate ( "serif" ) will do - if (currentFont.find(*candidate) != string::npos) - { - returnedFont = *candidate; - found = true; - } - } - } - // raise(SIGINT); - XFreeFontNames(allFonts); - XCloseDisplay(display); - - return returnedFont; -} diff --git a/src/TextWriter.h b/src/TextWriter.h deleted file mode 100644 index bfb9c083..00000000 --- a/src/TextWriter.h +++ /dev/null @@ -1,125 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TEXTWRITER_H -#define __TEXTWRITER_H - -#ifndef __cdecl -#define __cdecl -#endif - -#include -#include -#include - -#include "StringUtil.h" -#include "TrackProperties.h" - -// A nice ostream-like class for drawing OS-specific (or OpenGL) text to the -// screen in varying colors, fonts, and sizes. -class TextWriter { -public: - - // Centering only works for single-write lines... in other words, centered - // lines can only be 1 color. - TextWriter(int in_x, int in_y, - Renderer &in_renderer, bool in_centered = false, - int in_size = 12, std::string fontname = ""); - - // Skips at least 1 line, or the height of the last write... whichever - // is greater (so that you can skip down past a multiline write) - TextWriter& next_line(); - - // Allow manipulators - TextWriter& operator<<(TextWriter& (__cdecl *_Pfn)(TextWriter&)) { - (*_Pfn)(*(TextWriter *)this); - return (*this); - } - -private: - TextWriter operator=(const TextWriter&); - TextWriter(const TextWriter&); - - int get_point_size(); - - int point_size; - int x, y, size, original_x; - int last_line_height; - bool centered; - Renderer renderer; - - friend class Text; -}; - -// Some colors to choose from, for convenience -const static Color Black = { 0x00,0x00,0x00, 0xFF }; -const static Color Dk_Blue = { 0xC4,0x00,0x00, 0xFF }; -const static Color Dk_Green = { 0x00,0xC4,0x00, 0xFF }; -const static Color Dk_Cyan = { 0xFF,0x80,0x00, 0xFF }; -const static Color Dk_Red = { 0x00,0x00,0xC4, 0xFF }; -const static Color Dk_Purple = { 0x80,0x00,0x80, 0xFF }; -const static Color Brown = { 0x00,0x40,0x80, 0xFF }; -const static Color Gray = { 0xBB,0xBB,0xBB, 0xFF }; -const static Color Dk_Gray = { 0x55,0x55,0x55, 0xFF }; -const static Color Blue = { 0xFF,0x00,0x00, 0xFF }; -const static Color Green = { 0x00,0xFF,0x00, 0xFF }; -const static Color Cyan = { 0xFF,0xFF,0x00, 0xFF }; -const static Color Red = { 0x00,0x00,0xFF, 0xFF }; -const static Color Magenta = { 0xFF,0x00,0xFF, 0xFF }; -const static Color Yellow = { 0x00,0xFF,0xFF, 0xFF }; -const static Color White = { 0xFF,0xFF,0xFF, 0xFF }; -const static Color Orange = { 0x20,0x80,0xFF, 0xFF }; -const static Color Pink = { 0xA0,0x80,0xFF, 0xFF }; -const static Color CheatYellow = { 0x00,0xCC,0xFF, 0xFF }; - - -// A class to use TextWriter, and write to the screen -class Text { -public: - - Text(std::string t, Color color) : - m_color(color), - m_text(t) { - } - - Text(int i, Color color) : - m_color(color), - m_text(STRING(i)) { - } - - Text(double d, int prec, Color color) : - m_color(color), - m_text(STRING(std::setprecision(prec) << d)) { - } - - TextWriter& operator<<(TextWriter& tw) const; - -private: - - // This will return where the text should be drawn on - // the screen (determined in an OS dependent way) and - // advance the TextWriter's position by the width and/or - // height of the text. - void calculate_position_and_advance_cursor(TextWriter &tw, int *out_x, - int *out_y) const; - - Color m_color; - std::string m_text; -}; - -// newline manipulator -TextWriter& newline(TextWriter& tw); - -TextWriter& operator<<(TextWriter& tw, const Text& t); -TextWriter& operator<<(TextWriter& tw, const std::string& s); -TextWriter& operator<<(TextWriter& tw, const int& i); -TextWriter& operator<<(TextWriter& tw, const unsigned int& i); -TextWriter& operator<<(TextWriter& tw, const long& l); -TextWriter& operator<<(TextWriter& tw, const unsigned long& l); - -#endif // __TEXTWRITER_H diff --git a/src/Textures.h b/src/Textures.h deleted file mode 100644 index d33b4cd7..00000000 --- a/src/Textures.h +++ /dev/null @@ -1,50 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TEXTURES_H -#define __TEXTURES_H - -enum Texture { - - // TextureResourceNames should have the same order - TitleLogo, - InterfaceButtons, - GameMusicThemes, - - ButtonRetrySong, - ButtonChooseTracks, - ButtonExit, - ButtonBackToTitle, - ButtonPlaySong, - - InputBox, - OutputBox, - SongBox, - - TrackPanel, - - StatsText, - - PlayStatus, - PlayStatus2, - PlayKeys, - - PlayNotesBlackColor, - PlayNotesBlackShadow, - PlayNotesWhiteColor, - PlayNotesWhiteShadow, - - PlayKeyRail, - PlayKeyShadow, - PlayKeysBlack, - PlayKeysWhite, - - _TextureEnumCount -}; - -#endif // __TEXTURES_H diff --git a/src/Tga.cpp b/src/Tga.cpp deleted file mode 100644 index 5fedb9ff..00000000 --- a/src/Tga.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include -#include -#include // Fix Artifact ID: 2927098 - -#include "Tga.h" -#include "OSGraphics.h" -#include "StringUtil.h" -#include "LinthesiaError.h" - -#ifndef GRAPHDIR -#define GRAPHDIR "../graphics" -#endif - -using namespace std; - -Tga* Tga::Load(const string &resource_name) { - - // Append extension - string full_name = resource_name + ".tga"; - - // FIXME this! - full_name = string(GRAPHDIR) + "/" + full_name; - - ifstream file(full_name.c_str(), ios::in|ios::binary|ios::ate); - if (!file.is_open()) - throw LinthesiaError("Couldn't open TGA resource (" + full_name + ")."); - - int size = file.tellg(); - unsigned char *bytes = new unsigned char[size]; - - file.seekg(0, ios::beg); - file.read((char*)bytes, size); - file.close(); - - Tga *ret = LoadFromData(bytes); - delete[] bytes; - - ret->SetSmooth(false); - return ret; -} - -void Tga::Release(Tga *tga) { - if (!tga) - return; - - glDeleteTextures(1, &tga->m_texture_id); - delete tga; -} - -const static int TgaTypeHeaderLength = 12; -const static unsigned char UncompressedTgaHeader[TgaTypeHeaderLength] = {0,0,2,0,0,0,0,0,0,0,0,0}; -const static unsigned char CompressedTgaHeader[TgaTypeHeaderLength] = {0,0,10,0,0,0,0,0,0,0,0,0}; - -void Tga::SetSmooth(bool smooth) { - GLint filter = GL_NEAREST; - if (smooth) - filter = GL_LINEAR; - - glBindTexture(GL_TEXTURE_2D, m_texture_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); -} - -enum TgaType { - - TgaUncompressed, - TgaCompressed, - TgaUnknown -}; - -Tga *Tga::LoadFromData(const unsigned char *bytes) { - if (!bytes) - return 0; - - const unsigned char *pos = bytes; - - TgaType type = TgaUnknown; - if (memcmp(UncompressedTgaHeader, pos, TgaTypeHeaderLength) == 0) - type = TgaUncompressed; - - if (memcmp(CompressedTgaHeader, pos, TgaTypeHeaderLength) == 0) - type = TgaCompressed; - - if (type == TgaUnknown) - throw LinthesiaError("Unsupported TGA type."); - - // We're done with the type header - pos += TgaTypeHeaderLength; - - unsigned int width = pos[1] * 256 + pos[0]; - unsigned int height = pos[3] * 256 + pos[2]; - unsigned int bpp = pos[4]; - - // We're done with the data header - const static int TgaDataHeaderLength = 6; - pos += TgaDataHeaderLength; - - if (width <= 0 || height <= 0) - throw LinthesiaError("Invalid TGA dimensions."); - - if (bpp != 24 && bpp != 32) - throw LinthesiaError("Unsupported TGA BPP."); - - const unsigned int data_size = width * height * bpp/8; - unsigned char *image_data = new unsigned char[data_size]; - - Tga *t = 0; - if (type == TgaCompressed) - t = LoadCompressed(pos, image_data, width, height, bpp); - - if (type == TgaUncompressed) - t = LoadUncompressed(pos, image_data, data_size, width, height, bpp); - - delete[] image_data; - return t; -} - -Tga *Tga::LoadUncompressed(const unsigned char *src, unsigned char *dest, - unsigned int size, unsigned int width, unsigned int height, - unsigned int bpp) { - // We can use most of the data as-is with little modification - memcpy(dest, src, size); - - for (unsigned int cswap = 0; cswap < size; cswap += bpp/8) { - dest[cswap] ^= dest[cswap+2] ^= dest[cswap] ^= dest[cswap+2]; - } - - return BuildFromParameters(dest, width, height, bpp); -} - -Tga *Tga::LoadCompressed(const unsigned char *src, unsigned char *dest, - unsigned int width, unsigned int height, unsigned int bpp) { - - const unsigned char *pos = src; - - const unsigned int BytesPerPixel = bpp / 8; - const unsigned int PixelCount = height * width; - - const static unsigned int MaxBytesPerPixel = 4; - unsigned char pixel_buffer[MaxBytesPerPixel]; - - unsigned int pixel = 0; - unsigned int byte = 0; - - while (pixel < PixelCount) { - unsigned char chunkheader = 0; - memcpy(&chunkheader, pos, sizeof(unsigned char)); - pos += sizeof(unsigned char); - - if (chunkheader < 128) { - chunkheader++; - - for (short i = 0; i < chunkheader; i++) { - memcpy(pixel_buffer, pos, BytesPerPixel); - pos += BytesPerPixel; - - dest[byte + 0] = pixel_buffer[2]; - dest[byte + 1] = pixel_buffer[1]; - dest[byte + 2] = pixel_buffer[0]; - - if (BytesPerPixel == 4) - dest[byte + 3] = pixel_buffer[3]; - - byte += BytesPerPixel; - pixel++; - - if (pixel > PixelCount) - throw LinthesiaError("Too many pixels in TGA."); - } - } - - else { - chunkheader -= 127; - - memcpy(pixel_buffer, pos, BytesPerPixel); - pos += BytesPerPixel; - - for (short i = 0; i < chunkheader; i++) { - - dest[byte + 0] = pixel_buffer[2]; - dest[byte + 1] = pixel_buffer[1]; - dest[byte + 2] = pixel_buffer[0]; - - if (BytesPerPixel == 4) - dest[byte + 3] = pixel_buffer[3]; - - byte += BytesPerPixel; - pixel++; - - if (pixel > PixelCount) - throw LinthesiaError("Too many pixels in TGA."); - - } - } - } - - return BuildFromParameters(dest, width, height, bpp); -} - - -Tga *Tga::BuildFromParameters(const unsigned char *raw, unsigned int width, - unsigned int height, unsigned int bpp) { - - unsigned int pixel_format = 0; - if (bpp == 24) - pixel_format = GL_RGB; - - if (bpp == 32) - pixel_format = GL_RGBA; - - TextureId id; - glGenTextures(1, &id); - if (!id) - return 0; - - glBindTexture(GL_TEXTURE_2D, id); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexImage2D(GL_TEXTURE_2D, 0, bpp/8, width, height, - 0, pixel_format, GL_UNSIGNED_BYTE, raw); - - Tga *t = new Tga(); - t->m_width = width; - t->m_height = height; - t->m_texture_id = id; - - return t; -} diff --git a/src/Tga.h b/src/Tga.h deleted file mode 100644 index 39fe53bb..00000000 --- a/src/Tga.h +++ /dev/null @@ -1,62 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TGA_H -#define __TGA_H - -#include - -typedef unsigned int TextureId; - -class Tga { -public: - - static Tga *Load(const std::string &resource_name); - static void Release(Tga *tga); - - TextureId GetId() const { - return m_texture_id; - } - - unsigned int GetWidth() const { - return m_width; - } - - unsigned int GetHeight() const { - return m_height; - } - - void SetSmooth(bool smooth); - -private: - - TextureId m_texture_id; - unsigned int m_width; - unsigned int m_height; - - Tga() { } - ~Tga() { } - - Tga(const Tga& rhs); - Tga &operator=(const Tga& rhs); - - - static Tga *LoadFromData(const unsigned char *bytes); - - static Tga *LoadCompressed(const unsigned char *src, unsigned char *dest, - unsigned int width, unsigned int height, unsigned int bpp); - - static Tga *LoadUncompressed(const unsigned char *src, unsigned char *dest, - unsigned int size, unsigned int width, unsigned int height, - unsigned int bpp); - - static Tga *BuildFromParameters(const unsigned char *data, unsigned int width, - unsigned int height, unsigned int bpp); -}; - -#endif // __TGA_H diff --git a/src/TitleState.cpp b/src/TitleState.cpp deleted file mode 100644 index 94d7e327..00000000 --- a/src/TitleState.cpp +++ /dev/null @@ -1,455 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "TitleState.h" -#include "TrackSelectionState.h" - -#include "Version.h" -#include "CompatibleSystem.h" - -#include "MenuLayout.h" -#include "UserSettings.h" -#include "FileSelector.h" -#include "Renderer.h" -#include "Textures.h" -#include "GameState.h" - -#include "libmidi/Midi.h" -#include "libmidi/MidiUtil.h" -#include "MidiComm.h" - -using namespace std; - -const static string OutputDeviceKey = "last_output_device"; -const static string OutputKeySpecialDisabled = "[no output device]"; - -const static string InputDeviceKey = "last_input_device"; -const static string InputKeySpecialDisabled = "[no input device]"; - -TitleState::~TitleState() { - - if (m_output_tile) delete m_output_tile; - if (m_input_tile) delete m_input_tile; - if (m_file_tile) delete m_file_tile; -} - -void TitleState::Init() { - - m_back_button = ButtonState( - Layout::ScreenMarginX, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::ButtonHeight/2, - Layout::ButtonWidth, Layout::ButtonHeight); - - m_continue_button = ButtonState( - GetStateWidth() - Layout::ScreenMarginX - Layout::ButtonWidth, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::ButtonHeight/2, - Layout::ButtonWidth, Layout::ButtonHeight); - - string last_output_device = UserSetting::Get(OutputDeviceKey, ""); - string last_input_device = UserSetting::Get(InputDeviceKey, ""); - - // midi_out could be in one of three states right now: - // 1. We just started and were passed a null MidiCommOut pointer - // Or, we're returning from track selection either with: - // 2. a null MidiCommOut because the user didn't want any output, or - // 3. a valid MidiCommOut we constructed previously. - if (!m_state.midi_out) { - - // Try to find the previously used device - MidiCommDescriptionList devices = MidiCommOut::GetDeviceList(); - MidiCommDescriptionList::const_iterator it; - for (it = devices.begin(); it != devices.end(); it++) { - if (it->name == last_output_device) { - m_state.midi_out = new MidiCommOut(it->id); - break; - } - } - - // Next, if we couldn't find a previously used device, - // use the first one - if (last_output_device != OutputKeySpecialDisabled && - !m_state.midi_out && devices.size() > 0) - - m_state.midi_out = new MidiCommOut(devices[0].id); - } - - if (!m_state.midi_in) { - - // Try to find the previously used device - MidiCommDescriptionList devices = MidiCommIn::GetDeviceList(); - MidiCommDescriptionList::const_iterator it; - for (it = devices.begin(); it != devices.end(); it++) { - if (it->name == last_input_device) { - try { - m_state.midi_in = new MidiCommIn(it->id); - break; - } - catch (MidiErrorCode) { - m_state.midi_in = 0; - } - } - } - - // If we couldn't find the previously used device, - // disabling by default (i.e. leaving it null) is - // completely acceptable. - } - - int output_device_id = -1; - if (m_state.midi_out) { - output_device_id = m_state.midi_out->GetDeviceDescription().id; - m_state.midi_out->Reset(); - } - - int input_device_id = -1; - if (m_state.midi_in) { - input_device_id = m_state.midi_in->GetDeviceDescription().id; - m_state.midi_in->Reset(); - } - - const bool compress_height = (GetStateHeight() < 750); - const int initial_y = (compress_height ? 230 : 360); - const int each_y = (compress_height ? 94 : 100); - - m_file_tile = new StringTile((GetStateWidth() - StringTileWidth) / 2, - initial_y + each_y*0, - GetTexture(SongBox)); - - m_file_tile->SetString(m_state.song_title); - - const MidiCommDescriptionList output_devices = MidiCommOut::GetDeviceList(); - const MidiCommDescriptionList input_devices = MidiCommIn::GetDeviceList(); - - m_output_tile = new DeviceTile((GetStateWidth() - DeviceTileWidth) / 2, - initial_y + each_y*1, - output_device_id, - DeviceTileOutput, - output_devices, - GetTexture(InterfaceButtons), - GetTexture(OutputBox)); - - m_input_tile = new DeviceTile((GetStateWidth() - DeviceTileWidth) / 2, - initial_y + each_y*2, - input_device_id, - DeviceTileInput, - input_devices, - GetTexture(InterfaceButtons), - GetTexture(InputBox)); -} - -void TitleState::Update() { - MidiCommOut::UpdateDeviceList(); - MidiCommIn::UpdateDeviceList(); - m_input_tile->ReplaceDeviceList(MidiCommIn::GetDeviceList()); - m_output_tile->ReplaceDeviceList(MidiCommOut::GetDeviceList()); - - MouseInfo mouse = Mouse(); - - if (m_skip_next_mouse_up) { - mouse.released.left = false; - m_skip_next_mouse_up = false; - } - - m_continue_button.Update(mouse); - m_back_button.Update(mouse); - - MouseInfo output_mouse(mouse); - output_mouse.x -= m_output_tile->GetX(); - output_mouse.y -= m_output_tile->GetY(); - m_output_tile->Update(output_mouse); - - MouseInfo input_mouse(mouse); - input_mouse.x -= m_input_tile->GetX(); - input_mouse.y -= m_input_tile->GetY(); - m_input_tile->Update(input_mouse); - - MouseInfo file_mouse(mouse); - file_mouse.x -= m_file_tile->GetX(); - file_mouse.y -= m_file_tile->GetY(); - m_file_tile->Update(file_mouse); - - // Check to see for clicks on the file box - if (m_file_tile->Hit()) { - m_skip_next_mouse_up = true; - - if (m_state.midi_out) { - m_state.midi_out->Reset(); - m_output_tile->TurnOffPreview(); - } - - Midi *new_midi = 0; - - string filename; - string file_title; - FileSelector::RequestMidiFilename(&filename, &file_title); - - if (filename != "") { - try { - new_midi = new Midi(Midi::ReadFromFile(filename)); - } - catch (const MidiError &e) { - string description = STRING("Problem while loading file: " << - file_title << "\n") + e.GetErrorDescription(); - Compatible::ShowError(description); - new_midi = 0; - } - - if (new_midi) { - - SharedState new_state; - new_state.midi = new_midi; - new_state.midi_in = m_state.midi_in; - new_state.midi_out = m_state.midi_out; - new_state.song_title = FileSelector::TrimFilename(filename); - new_state.dpms_thread = m_state.dpms_thread; - - delete m_state.midi; - m_state = new_state; - - m_file_tile->SetString(m_state.song_title); - } - } - } - - // Check to see if we need to switch to a newly selected output device - int output_id = m_output_tile->GetDeviceId(); - if (!m_state.midi_out || - output_id != static_cast(m_state.midi_out->GetDeviceDescription().id)) { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - delete m_state.midi_out; - m_state.midi_out = 0; - - // save to user preferences - if (output_id >= 0) { - - m_state.midi_out = new MidiCommOut(output_id); - m_state.midi->Reset(0,0); - - UserSetting::Set(OutputDeviceKey, m_state.midi_out->GetDeviceDescription().name); - } - else - UserSetting::Set(OutputDeviceKey, OutputKeySpecialDisabled); - - } - - if (m_state.midi_out) { - if (m_output_tile->HitPreviewButton()) { - m_state.midi_out->Reset(); - - if (m_output_tile->IsPreviewOn()) { - - const microseconds_t PreviewLeadIn = 250000; - const microseconds_t PreviewLeadOut = 250000; - m_state.midi->Reset(PreviewLeadIn, PreviewLeadOut); - - PlayDevicePreview(0); - } - } - - else - PlayDevicePreview(static_cast(GetDeltaMilliseconds()) * 1000); - - } - - int input_id = m_input_tile->GetDeviceId(); - if (!m_state.midi_in || - input_id != static_cast(m_state.midi_in->GetDeviceDescription().id)) { - - if (m_state.midi_in) - m_state.midi_in->Reset(); - - m_last_input_note_name = ""; - - delete m_state.midi_in; - m_state.midi_in = 0; - - if (input_id >= 0) { - - try { - m_state.midi_in = new MidiCommIn(input_id); - UserSetting::Set(InputDeviceKey, m_state.midi_in->GetDeviceDescription().name); - } - - catch (MidiErrorCode) { - m_state.midi_in = 0; - } - } - - else - UserSetting::Set(InputDeviceKey, InputKeySpecialDisabled); - - } - - if (m_state.midi_in && m_input_tile->IsPreviewOn()) { - - // Read note events to display on screen - while (m_state.midi_in->KeepReading()) { - MidiEvent ev = m_state.midi_in->Read(); - - // send to output (for a possible audio preview) - if (m_state.midi_out) - m_state.midi_out->Write(ev); - - if (ev.Type() == MidiEventType_NoteOff || ev.Type() == MidiEventType_NoteOn) { - string note = MidiEvent::NoteName(ev.NoteNumber()); - - if (ev.Type() == MidiEventType_NoteOn && ev.NoteVelocity() > 0) - m_last_input_note_name = note; - - else - if (note == m_last_input_note_name) - m_last_input_note_name = ""; - - } - } - } - - else - m_last_input_note_name = ""; - - if (IsKeyPressed(KeyEscape) || m_back_button.hit) { - delete m_state.midi_out; - m_state.midi_out = 0; - - delete m_state.midi_in; - m_state.midi_in = 0; - - delete m_state.midi; - m_state.midi = 0; - - Compatible::GracefulShutdown(); - return; - } - - if (IsKeyPressed(KeyEnter) || m_continue_button.hit) { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - if (m_state.midi_in) - m_state.midi_in->Reset(); - - ChangeState(new TrackSelectionState(m_state)); - return; - } - - m_tooltip = ""; - - if (m_back_button.hovering) - m_tooltip = "Click to exit Linthesia."; - - if (m_continue_button.hovering) - m_tooltip = "Click to continue on to the track selection screen."; - - if (m_file_tile->WholeTile().hovering) - m_tooltip = "Click to choose a different MIDI file."; - - if (m_input_tile->ButtonLeft().hovering) - m_tooltip = "Cycle through available input devices."; - - if (m_input_tile->ButtonRight().hovering) - m_tooltip = "Cycle through available input devices."; - - if (m_input_tile->ButtonPreview().hovering) { - if (m_input_tile->IsPreviewOn()) - m_tooltip = "Turn off test MIDI input for this device."; - else - m_tooltip = "Click to test your MIDI input device by playing notes."; - } - - if (m_output_tile->ButtonLeft().hovering) - m_tooltip = "Cycle through available output devices."; - - if (m_output_tile->ButtonRight().hovering) - m_tooltip = "Cycle through available output devices."; - - if (m_output_tile->ButtonPreview().hovering) { - if (m_output_tile->IsPreviewOn()) - m_tooltip = "Turn off output test for this device."; - else - m_tooltip = "Click to test MIDI output on this device."; - } -} - -void TitleState::PlayDevicePreview(microseconds_t delta_microseconds) { - if (!m_output_tile->IsPreviewOn()) - return; - - if (!m_state.midi_out) - return; - - MidiEventListWithTrackId evs = m_state.midi->Update(delta_microseconds); - - for (MidiEventListWithTrackId::const_iterator i = evs.begin(); i != evs.end(); ++i) { - m_state.midi_out->Write(i->second); - } -} - -void TitleState::Draw(Renderer &renderer) const { - - const bool compress_height = (GetStateHeight() < 750); - const bool compress_width = (GetStateWidth() < 850); - - const static int TitleWidth = 507; - const static int TitleY = (compress_height ? 20 : 100); - - int left = GetStateWidth() / 2 - TitleWidth / 2; - - renderer.SetColor(White); - renderer.DrawTga(GetTexture(TitleLogo), left, TitleY); - //renderer.DrawTga(GetTexture(GameMusicThemes), left+3, TitleY + (compress_height ? 120 : 150) ); - - TextWriter version(Layout::ScreenMarginX, - GetStateHeight() - Layout::ScreenMarginY - Layout::SmallFontSize * 2, - renderer, false, Layout::SmallFontSize); - - version << Text("version " + NeothesiaVersionString, Gray); - - Layout::DrawHorizontalRule(renderer, - GetStateWidth(), - GetStateHeight() - Layout::ScreenMarginY); - - Layout::DrawButton(renderer, m_continue_button, "ChooseTracks"); - Layout::DrawButton(renderer, m_back_button, "Exit"); - - m_output_tile->Draw(renderer); - m_input_tile->Draw(renderer); - m_file_tile->Draw(renderer); - - if (m_input_tile->IsPreviewOn()) { - - const static int PreviewWidth = 60; - const static int PreviewHeight = 40; - - const int x = m_input_tile->GetX() + DeviceTileWidth + 12; - const int y = m_input_tile->GetY() + 38; - - renderer.SetColor(0xFF, 0xFF, 0xFF); - renderer.DrawQuad(x, y, PreviewWidth, PreviewHeight); - - renderer.SetColor(0, 0, 0); - renderer.DrawQuad(x+1, y+1, PreviewWidth-2, PreviewHeight-2); - - TextWriter last_note(x + PreviewWidth/2 - 1, - m_input_tile->GetY() + 44, - renderer, true, Layout::TitleFontSize); - - Widen w; - last_note << w(m_last_input_note_name); - } - - const int tooltip_font_size = (compress_width ? Layout::ButtonFontSize : Layout::TitleFontSize); - TextWriter tooltip(GetStateWidth() / 2, - GetStateHeight() - Layout::ScreenMarginY/2 - tooltip_font_size/2, - renderer, true, tooltip_font_size); - - tooltip << m_tooltip; -} diff --git a/src/TitleState.h b/src/TitleState.h deleted file mode 100644 index 5a4fca09..00000000 --- a/src/TitleState.h +++ /dev/null @@ -1,61 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TITLE_STATE_H -#define __TITLE_STATE_H - -#include "SharedState.h" -#include "GameState.h" -#include "MenuLayout.h" -#include "libmidi/MidiTypes.h" -#include "DeviceTile.h" -#include "StringTile.h" - -// class Midi; -// class MidiCommOut; -// class Tga; - -class TitleState : public GameState { -public: - - // You can pass 0 in for state.midi_out to have the title - // screen pick a device for you. - TitleState(const SharedState &state) : - m_state(state), - m_output_tile(0), - m_input_tile(0), - m_file_tile(0), - m_skip_next_mouse_up(false) { - } - - ~TitleState(); - -protected: - virtual void Init(); - virtual void Update(); - virtual void Draw(Renderer &renderer) const; - -private: - void PlayDevicePreview(microseconds_t delta_microseconds); - - ButtonState m_continue_button; - ButtonState m_back_button; - - SharedState m_state; - - std::string m_last_input_note_name; - std::string m_tooltip; - - DeviceTile *m_output_tile; - DeviceTile *m_input_tile; - StringTile *m_file_tile; - - bool m_skip_next_mouse_up; -}; - -#endif // __TITLE_STATE_H diff --git a/src/TrackProperties.h b/src/TrackProperties.h deleted file mode 100644 index db249f47..00000000 --- a/src/TrackProperties.h +++ /dev/null @@ -1,102 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TRACK_PROPERTIES_H -#define __TRACK_PROPERTIES_H - -#include "Renderer.h" - -namespace Track { - - // See ModeText in TrackTile.cpp for titles - // See TractSelectionState.cpp for description - enum Mode { - - ModePlayedAutomatically, - ModeYouPlay, - ModeYouPlaySilently, - ModeLearning, - ModeLearningSilently, - ModePlayedButHidden, - ModeNotPlayed, - - ModeCount - }; - - // Based on the Open Source icon theme "Tango" color scheme - // with a few changes. (e.g. Chameleon NoteBlack is a little - // darker to distinguish it from NoteWhite, ScarletRed is a - // little brighter to make it easier on the eyes, etc.) - const static int ColorCount = 8; - const static int UserSelectableColorCount = ColorCount - 2; - - enum TrackColor { - - TangoSkyBlue = 0, - TangoChameleon, - TangoOrange, - TangoButter, - TangoPlum, - TangoScarletRed, - - FlatGray, - MissedNote - }; - - const static Color ColorNoteWhite[ColorCount] = { - { 114, 159, 207, 0xFF }, - { 138, 226, 52, 0xFF }, - { 252, 175, 62, 0xFF }, - { 252, 235, 87, 0xFF }, - { 173, 104, 180, 0xFF }, - { 238, 94, 94, 0xFF }, - - { 90, 90, 90, 0xFF }, - { 60, 60, 60, 0xFF } - }; - - const static Color ColorNoteHit[ColorCount] = { - { 192, 222, 255, 0xFF }, - { 203, 255, 152, 0xFF }, - { 255, 216, 152, 0xFF }, - { 255, 247, 178, 0xFF }, - { 255, 218, 251, 0xFF }, - { 255, 178, 178, 0xFF }, - - { 180, 180, 180, 0xFF }, - { 60, 60, 60, 0xFF } - }; - - const static Color ColorNoteBlack[ColorCount] = { - { 52, 101, 164, 0xFF }, - { 86, 157, 17, 0xFF }, - { 245, 121, 0, 0xFF }, - { 218, 195, 0, 0xFF }, - { 108, 76, 113, 0xFF }, - { 233, 49, 49, 0xFF }, - - { 90, 90, 90, 0xFF }, - { 60, 60, 60, 0xFF } - }; - - struct Properties { - - Properties() : - mode(ModeNotPlayed), - color(TangoSkyBlue), - is_retry_on(false) { - } - - Mode mode; - TrackColor color; - bool is_retry_on; - }; - -}; // end namespace - -#endif // __TRACK_PROPERTIES_H diff --git a/src/TrackSelectionState.cpp b/src/TrackSelectionState.cpp deleted file mode 100644 index 53631c6a..00000000 --- a/src/TrackSelectionState.cpp +++ /dev/null @@ -1,376 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "TrackSelectionState.h" - -#include "TitleState.h" -#include "PlayingState.h" -#include "MenuLayout.h" -#include "Renderer.h" -#include "Textures.h" - -#include "libmidi/Midi.h" -#include "libmidi/MidiUtil.h" -#include "MidiComm.h" - -using namespace std; - -TrackSelectionState::TrackSelectionState(const SharedState &state) : - m_page_count(0), - m_current_page(0), - m_tiles_per_page(0), - m_preview_on(false), - m_first_update_after_seek(false), - m_preview_track_id(0), - m_state(state) { -} - -void TrackSelectionState::Init() { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - Midi &m = *m_state.midi; - - // Prepare a very simple count of the playable tracks first - int track_count = 0; - for (size_t i = 0; i < m.Tracks().size(); ++i) { - if (m.Tracks()[i].Notes().size()) - track_count++; - } - - m_back_button = ButtonState( - Layout::ScreenMarginX, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::ButtonHeight/2, - Layout::ButtonWidth, Layout::ButtonHeight); - - m_continue_button = ButtonState( - GetStateWidth() - Layout::ScreenMarginX - Layout::ButtonWidth, - GetStateHeight() - Layout::ScreenMarginY/2 - Layout::ButtonHeight/2, - Layout::ButtonWidth, Layout::ButtonHeight); - - // Determine how many track tiles we can fit - // horizontally and vertically. Integer division - // helps us round down here. - int tiles_across = (GetStateWidth() + Layout::ScreenMarginX) / - (TrackTileWidth + Layout::ScreenMarginX); - - tiles_across = max(tiles_across, 1); - - int tiles_down = (GetStateHeight() - Layout::ScreenMarginX - Layout::ScreenMarginY * 2) / - (TrackTileHeight + Layout::ScreenMarginX); - - tiles_down = max(tiles_down, 1); - - // Calculate how many pages of tracks there will be - m_tiles_per_page = tiles_across * tiles_down; - - m_page_count = track_count / m_tiles_per_page; - const int remainder = track_count % m_tiles_per_page; - if (remainder > 0) - m_page_count++; - - // If we have fewer than one row of tracks, just - // center the tracks we do have - if (track_count < tiles_across) - tiles_across = track_count; - - // Determine how wide that many track tiles will - // actually be, so we can center the list - int all_tile_widths = tiles_across * TrackTileWidth + (tiles_across-1) * Layout::ScreenMarginX; - int global_x_offset = (GetStateWidth() - all_tile_widths) / 2; - - const static int starting_y = 100; - - int tiles_on_this_line = 0; - int tiles_on_this_page = 0; - int current_y = starting_y; - - for (size_t i = 0; i < m.Tracks().size(); ++i) { - - const MidiTrack &t = m.Tracks()[i]; - if (t.Notes().size() == 0) - continue; - - int x = global_x_offset + (TrackTileWidth + Layout::ScreenMarginX)*tiles_on_this_line; - int y = current_y; - - Track::Mode mode = Track::ModePlayedAutomatically; - bool is_retry_on = false; - if (t.IsPercussion()) - mode = Track::ModePlayedButHidden; - - Track::TrackColor color = static_cast((m_track_tiles.size()) % Track::UserSelectableColorCount); - - // If we came back here from StatePlaying, reload all our preferences - if (m_state.track_properties.size() > i) { - - color = m_state.track_properties[i].color; - mode = m_state.track_properties[i].mode; - is_retry_on = m_state.track_properties[i].is_retry_on; - } - - TrackTile tile(x, y, i, color, mode, is_retry_on); - - m_track_tiles.push_back(tile); - - - tiles_on_this_line++; - tiles_on_this_line %= tiles_across; - - if (!tiles_on_this_line) - current_y += TrackTileHeight + Layout::ScreenMarginX; - - - tiles_on_this_page++; - tiles_on_this_page %= m_tiles_per_page; - - if (!tiles_on_this_page) { - current_y = starting_y; - tiles_on_this_line = 0; - } - } -} - -vector TrackSelectionState::BuildTrackProperties() const { - - vector props; - for (size_t i = 0; i < m_state.midi->Tracks().size(); ++i) { - props.push_back(Track::Properties()); - } - - // Populate it with the tracks that have notes - for (vector::const_iterator i = m_track_tiles.begin(); i != m_track_tiles.end(); ++i) { - props[i->GetTrackId()].color = i->GetColor(); - props[i->GetTrackId()].mode = i->GetMode(); - props[i->GetTrackId()].is_retry_on = i->IsRetryOn(); - } - - return props; -} - -void TrackSelectionState::Update() { - m_continue_button.Update(MouseInfo(Mouse())); - m_back_button.Update(MouseInfo(Mouse())); - - if (IsKeyPressed(KeyEscape) || m_back_button.hit) { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - m_state.track_properties = BuildTrackProperties(); - ChangeState(new TitleState(m_state)); - return; - } - - if (IsKeyPressed(KeyEnter) || m_continue_button.hit) { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - m_state.track_properties = BuildTrackProperties(); - ChangeState(new PlayingState(m_state)); - - return; - } - - if (IsKeyPressed(KeyDown) || IsKeyPressed(KeyRight)) { - m_current_page++; - - if (m_current_page == m_page_count) - m_current_page = 0; - } - - if (IsKeyPressed(KeyUp) || IsKeyPressed(KeyLeft)) { - m_current_page--; - - if (m_current_page < 0) - m_current_page += m_page_count; - } - - m_tooltip = ""; - - if (m_back_button.hovering) - m_tooltip = "Click to return to the title screen."; - - if (m_continue_button.hovering) - m_tooltip = "Click to begin playing with these settings."; - - // Our delta milliseconds on the first frame after we seek down to the - // first note is extra long because the seek takes a while. By skipping - // the "Play" that update, we don't have an artificially fast-forwarded - // start. - if (!m_first_update_after_seek) - PlayTrackPreview(static_cast(GetDeltaMilliseconds()) * 1000); - - m_first_update_after_seek = false; - - // Do hit testing on each tile button on this page - size_t start = m_current_page * m_tiles_per_page; - size_t end = min( static_cast((m_current_page+1) * m_tiles_per_page), m_track_tiles.size() ); - for (size_t i = start; i < end; ++i) { - - TrackTile &t = m_track_tiles[i]; - - MouseInfo mouse = MouseInfo(Mouse()); - mouse.x -= t.GetX(); - mouse.y -= t.GetY(); - - t.Update(mouse); - - if (t.ButtonLeft().hovering || t.ButtonRight().hovering) { - - switch (t.GetMode()) { - case Track::ModeNotPlayed: - m_tooltip = "Track won't be played or shown during the game."; - break; - - case Track::ModePlayedAutomatically: - m_tooltip = "Track will be played automatically by the game."; - break; - - case Track::ModePlayedButHidden: - m_tooltip = "Track will be played automatically by the game, but also hidden from view."; - break; - - case Track::ModeYouPlay: - m_tooltip = "'You Play' means you want to play this track yourself."; - break; - - case Track::ModeYouPlaySilently: - m_tooltip = "Same as 'You Play', ignore velocity from MIDI."; - break; - - case Track::ModeLearning: - m_tooltip = "Wait for you to play."; - break; - - case Track::ModeLearningSilently: - m_tooltip = "Wait for you to play, do not produce sounds from MIDI."; - break; - - case Track::ModeCount: - break; - } - } - - if (t.ButtonPreview().hovering) { - if (t.IsPreviewOn()) - m_tooltip = "Turn track preview off."; - - else - m_tooltip = "Preview how this track sounds."; - } - - if (t.ButtonColor().hovering) - m_tooltip = "Pick a color for this track's notes."; - - if (t.ButtonRetry().hovering) { - if (t.IsRetryOn()) - m_tooltip = "Ignore failed tempo blocks."; - - else - m_tooltip = "Repeat failed tempo blocks."; - } - - if (t.HitPreviewButton()) { - - if (m_state.midi_out) - m_state.midi_out->Reset(); - - if (t.IsPreviewOn()) { - - // Turn off any other preview modes - for (size_t j = 0; j < m_track_tiles.size(); ++j) { - if (i == j) - continue; - - m_track_tiles[j].TurnOffPreview(); - } - - const microseconds_t PreviewLeadIn = 25000; - const microseconds_t PreviewLeadOut = 25000; - - m_preview_on = true; - m_preview_track_id = t.GetTrackId(); - m_state.midi->Reset(PreviewLeadIn, PreviewLeadOut); - PlayTrackPreview(0); - - // Find the first note in this track so we can skip right to the good part. - microseconds_t additional_time = -PreviewLeadIn; - const MidiTrack &track = m_state.midi->Tracks()[m_preview_track_id]; - for (size_t i = 0; i < track.Events().size(); ++i) { - - const MidiEvent &ev = track.Events()[i]; - if (ev.Type() == MidiEventType_NoteOn && ev.NoteVelocity() > 0) { - additional_time += track.EventUsecs()[i] - m_state.midi->GetDeadAirStartOffsetMicroseconds() - 1; - break; - } - } - - PlayTrackPreview(additional_time); - m_first_update_after_seek = true; - } - - else - m_preview_on = false; - } - } -} - -void TrackSelectionState::PlayTrackPreview(microseconds_t delta_microseconds) { - - if (!m_preview_on) - return; - - MidiEventListWithTrackId evs = m_state.midi->Update(delta_microseconds); - - for (MidiEventListWithTrackId::const_iterator i = evs.begin(); i != evs.end(); ++i) { - const MidiEvent &ev = i->second; - - if (i->first != m_preview_track_id) - continue; - - if (m_state.midi_out) - m_state.midi_out->Write(ev); - } -} - -void TrackSelectionState::Draw(Renderer &renderer) const { - - Layout::DrawTitle(renderer, "Choose Tracks To Play"); - - Layout::DrawHorizontalRule(renderer, GetStateWidth(), Layout::ScreenMarginY); - Layout::DrawHorizontalRule(renderer, GetStateWidth(), GetStateHeight() - Layout::ScreenMarginY); - - Layout::DrawButton(renderer, m_continue_button, "PlaySong"); - Layout::DrawButton(renderer, m_back_button, "BackToTitle"); - - // Write our page count on the screen - TextWriter pagination(GetStateWidth()/2, GetStateHeight() - Layout::SmallFontSize - 30, - renderer, true, Layout::ButtonFontSize); - - pagination << Text(STRING("Page " << (m_current_page+1) << " of " << - m_page_count << " (arrow keys change page)"), Gray); - - TextWriter tooltip(GetStateWidth()/2, GetStateHeight() - Layout::SmallFontSize - 54, - renderer, true, Layout::ButtonFontSize); - - tooltip << m_tooltip; - - Tga *buttons = GetTexture(InterfaceButtons); - Tga *box = GetTexture(TrackPanel); - - // Draw each track tile on the current page - size_t start = m_current_page * m_tiles_per_page; - size_t end = min(static_cast((m_current_page+1) * m_tiles_per_page), m_track_tiles.size()); - - for (size_t i = start; i < end; ++i) { - m_track_tiles[i].Draw(renderer, m_state.midi, buttons, box); - } -} diff --git a/src/TrackSelectionState.h b/src/TrackSelectionState.h deleted file mode 100644 index 6ebb9e2b..00000000 --- a/src/TrackSelectionState.h +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TRACKSELECTION_STATE_H -#define __TRACKSELECTION_STATE_H - -#include "SharedState.h" -#include "GameState.h" -#include "TrackTile.h" -#include "libmidi/MidiTypes.h" -#include "MidiComm.h" - -#include - -class TrackSelectionState : public GameState { -public: - - TrackSelectionState(const SharedState &state); - -protected: - virtual void Init(); - virtual void Update(); - virtual void Draw(Renderer &renderer) const; - -private: - void PlayTrackPreview(microseconds_t additional_time); - std::vector BuildTrackProperties() const; - - int m_page_count; - int m_current_page; - int m_tiles_per_page; - - bool m_preview_on; - bool m_first_update_after_seek; - size_t m_preview_track_id; - - ButtonState m_continue_button; - ButtonState m_back_button; - - std::string m_tooltip; - - std::vector m_track_tiles; - - SharedState m_state; -}; - -#endif // __TRACKSELECTION_STATE_H diff --git a/src/TrackTile.cpp b/src/TrackTile.cpp deleted file mode 100644 index 9583add1..00000000 --- a/src/TrackTile.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "libmidi/Midi.h" - -#include "TrackTile.h" -#include "Renderer.h" -#include "Tga.h" - -const static int GraphicWidth = 36; -const static int GraphicHeight = 36; - -// Only used here -const static char* ModeText[Track::ModeCount] = { - "Played Automatically", - "You Play", // You Press, we help - "You Play Silently", // You Play - "Learning", - "Learning Silently", - "Played But Hidden", - "Not Played" -}; - -TrackTile::TrackTile(int x, int y, size_t track_id, Track::TrackColor color, Track::Mode mode, - bool is_retry_on) : - m_x(x), - m_y(y), - m_mode(mode), - m_color(color), - m_preview_on(false), - m_retry_on(is_retry_on), - m_track_id(track_id) { - - // Initialize the size and position of each button - whole_tile = ButtonState(0, 0, TrackTileWidth, TrackTileHeight); - button_mode_left = ButtonState( 2, 68, GraphicWidth, GraphicHeight); - button_mode_right = ButtonState(192, 68, GraphicWidth, GraphicHeight); - button_color = ButtonState(228, 68, GraphicWidth, GraphicHeight); - button_preview = ButtonState(264, 68, GraphicWidth, GraphicHeight); - button_retry = ButtonState(300, 68, GraphicWidth, GraphicHeight); -} - -void TrackTile::Update(const MouseInfo &translated_mouse) { - - // Update the mouse state of each button - whole_tile.Update(translated_mouse); - button_preview.Update(translated_mouse); - button_retry.Update(translated_mouse); - button_color.Update(translated_mouse); - button_mode_left.Update(translated_mouse); - button_mode_right.Update(translated_mouse); - - if (button_mode_left.hit) { - - int mode = static_cast(m_mode) - 1; - if (mode < 0) - mode = Track::ModeCount - 1; - - m_mode = static_cast(mode); - } - - if (button_mode_right.hit) { - - int mode = static_cast(m_mode) + 1; - if (mode >= Track::ModeCount) - mode = 0; - - m_mode = static_cast(mode); - } - - if (button_preview.hit) - m_preview_on = !m_preview_on; - - if (button_retry.hit) - m_retry_on = !m_retry_on; - - if (button_color.hit && m_mode != Track::ModeNotPlayed && m_mode != Track::ModePlayedButHidden) { - int color = static_cast(m_color) + 1; - if (color >= Track::UserSelectableColorCount) - color = 0; - - m_color = static_cast(color); - } - -} - -int TrackTile::LookupGraphic(TrackTileGraphic graphic, bool button_hovering) const { - - // There are three sets of graphics - // set 0: window lit, hovering - // set 1: window lit, not-hovering - // set 2: window unlit, (implied not-hovering) - int graphic_set = 2; - if (whole_tile.hovering) - graphic_set--; - - if (button_hovering) - graphic_set--; - - const int set_offset = GraphicWidth * Graphic_COUNT; - const int graphic_offset = GraphicWidth * graphic; - - return (set_offset * graphic_set) + graphic_offset; -} - -void TrackTile::Draw(Renderer &renderer, const Midi *midi, Tga *buttons, Tga *box) const { - - const MidiTrack &track = midi->Tracks()[m_track_id]; - - bool gray_out_buttons = false; - Color light = Track::ColorNoteWhite[m_color]; - Color medium = Track::ColorNoteBlack[m_color]; - - if (m_mode == Track::ModePlayedButHidden || m_mode == Track::ModeNotPlayed) { - - gray_out_buttons = true; - light = Renderer::ToColor(0xB0,0xB0,0xB0); - medium = Renderer::ToColor(0x70,0x70,0x70); - } - - Color color_tile = medium; - Color color_tile_hovered = light; - - renderer.SetOffset(m_x, m_y); - - renderer.SetColor(whole_tile.hovering ? color_tile_hovered : color_tile); - renderer.DrawTga(box, -10, -6); - - renderer.SetColor(White); - - // Write song info to the tile - TextWriter instrument(95, 14, renderer, false, 14); - instrument << track.InstrumentName(); - TextWriter note_count(95, 35, renderer, false, 14); - note_count << static_cast(track.Notes().size()); - - int color_offset = GraphicHeight * static_cast(m_color); - if (gray_out_buttons) - color_offset = GraphicHeight * Track::UserSelectableColorCount; - - renderer.DrawTga(buttons, BUTTON_RECT(button_mode_left), - LookupGraphic(GraphicLeftArrow, button_mode_left.hovering), - color_offset); - - renderer.DrawTga(buttons, BUTTON_RECT(button_mode_right), - LookupGraphic(GraphicRightArrow, button_mode_right.hovering), - color_offset); - - renderer.DrawTga(buttons, BUTTON_RECT(button_color), - LookupGraphic(GraphicColor, button_color.hovering), - color_offset); - - TrackTileGraphic preview_graphic = GraphicPreviewTurnOn; - if (m_preview_on) - preview_graphic = GraphicPreviewTurnOff; - - TrackTileGraphic retry_graphic = GraphicRetryOff; - if (m_retry_on) - retry_graphic = GraphicRetryOn; - - renderer.DrawTga(buttons, BUTTON_RECT(button_preview), - LookupGraphic(preview_graphic, button_preview.hovering), - color_offset); - - renderer.DrawTga(buttons, BUTTON_RECT(button_retry), - LookupGraphic(retry_graphic, button_retry.hovering), - color_offset); - - // Draw mode text - TextWriter mode(42, 81, renderer, false, 12); - mode << ModeText[m_mode]; - - renderer.ResetOffset(); -} - diff --git a/src/TrackTile.h b/src/TrackTile.h deleted file mode 100644 index 1b37df93..00000000 --- a/src/TrackTile.h +++ /dev/null @@ -1,133 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __TRACK_TILE_H -#define __TRACK_TILE_H - -#include "GameState.h" -#include "TextWriter.h" -#include "TrackProperties.h" -#include "MenuLayout.h" - -#include "libmidi/Midi.h" - -#include - -const int TrackTileWidth = 336; -const int TrackTileHeight = 110; - -enum TrackTileGraphic { - - GraphicLeftArrow = 0, - GraphicRightArrow, - GraphicColor, - GraphicPreviewTurnOn, - GraphicPreviewTurnOff, - - GraphicComputerPlays, - GraphicHumanPlays, - GraphicRetryOn, - GraphicRetryOff, - - Graphic_COUNT -}; - -class TrackTile { -public: - - TrackTile(int x, int y, size_t track_id, - Track::TrackColor color, Track::Mode mode, - bool is_retry_on); - - void Update(const MouseInfo &translated_mouse); - void Draw(Renderer &renderer, const Midi *midi, Tga *buttons, Tga *box) const; - - int GetX() { - return m_x; - } - - int GetY() { - return m_y; - } - - Track::Mode GetMode() const { - return m_mode; - } - - Track::TrackColor GetColor() const { - return m_color; - } - - bool HitPreviewButton() const { - return button_preview.hit; - } - - bool IsPreviewOn() const { - return m_preview_on; - } - - bool IsRetryOn() const { - return m_retry_on; - } - - void TurnOffPreview() { - m_preview_on = false; - } - - size_t GetTrackId() const { - return m_track_id; - } - - const ButtonState WholeTile() const { - return whole_tile; - } - - const ButtonState ButtonPreview() const { - return button_preview; - } - - const ButtonState ButtonColor() const { - return button_color; - } - - const ButtonState ButtonRetry() const { - return button_retry; - } - - const ButtonState ButtonLeft() const { - return button_mode_left; - } - - const ButtonState ButtonRight() const { - return button_mode_right; - } - -private: - int m_x; - int m_y; - - Track::Mode m_mode; - Track::TrackColor m_color; - - bool m_preview_on; - bool m_retry_on; - - ButtonState whole_tile; - ButtonState button_preview; - ButtonState button_color; - ButtonState button_retry; - ButtonState button_mode_left; - ButtonState button_mode_right; - - int LookupGraphic(TrackTileGraphic graphic, bool button_hovering) const; - - // Link to the track index of the Midi object - size_t m_track_id; -}; - -#endif // __TRACK_TILE_H diff --git a/src/UserSettings.cpp b/src/UserSettings.cpp deleted file mode 100644 index 9edf211f..00000000 --- a/src/UserSettings.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include - -#include "StringUtil.h" - -using namespace std; - -namespace UserSetting { - - static bool g_initialized(false); - static string g_app_name(""); - static Glib::RefPtr gconf; - - void Initialize(const string &app_name) { - if (g_initialized) - return; - - Gnome::Conf::init(); - - gconf = Gnome::Conf::Client::get_default_client(); - g_app_name = "/apps/" + app_name; - g_initialized = true; - } - - string Get(const string &setting, const string &default_value) { - if (!g_initialized) - return default_value; - - string result = gconf->get_string(g_app_name + "/" + setting); - if (result.empty()) - return default_value; - - return result; - } - - void Set(const string &setting, const string &value) { - if (!g_initialized) - return; - - gconf->set(g_app_name + "/" + setting, value); - } - -}; // End namespace diff --git a/src/UserSettings.h b/src/UserSettings.h deleted file mode 100644 index a5ba6a6d..00000000 --- a/src/UserSettings.h +++ /dev/null @@ -1,26 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __USER_SETTINGS_H -#define __USER_SETTINGS_H - -#include - -namespace UserSetting { - - // This must be called exactly once before any of the following will work - void Initialize(const std::string &app_name); - - std::string Get(const std::string &setting, - const std::string &default_value); - - void Set(const std::string &setting, - const std::string &value); -}; - -#endif // __USER_SETTINGS_H diff --git a/src/Version.h b/src/Version.h deleted file mode 100644 index 774424ae..00000000 --- a/src/Version.h +++ /dev/null @@ -1,16 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Neothesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __NEOTHESIA_VERSION_H__ -#define __NEOTHESIA_VERSION_H__ - -#include - -static const std::string NeothesiaVersionString = "0.1"; - -#endif diff --git a/src/event_loop.rs b/src/event_loop.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/libmidi/Midi.cpp b/src/libmidi/Midi.cpp deleted file mode 100644 index 47e4e439..00000000 --- a/src/libmidi/Midi.cpp +++ /dev/null @@ -1,526 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "Midi.h" -#include "MidiEvent.h" -#include "MidiTrack.h" -#include "MidiUtil.h" - -#include -#include -#include - -using namespace std; - -Midi Midi::ReadFromFile(const string &filename) { - - fstream file(filename.c_str(), ios::in | ios::binary); - - if (!file.good()) - throw MidiError(MidiError_BadFilename); - - Midi m; - - try { - m = ReadFromStream(file); - } - - catch (const MidiError &e) { - // Close our file resource before handing the error up - file.close(); - throw e; - } - - return m; -} - -Midi Midi::ReadFromStream(istream &stream) { - Midi m; - - // header_id is always "MThd" by definition - const static string MidiFileHeader = "MThd"; - const static string RiffFileHeader = "RIFF"; - - // I could use (MidiFileHeader.length() + 1), but then this has to be - // dynamically allocated. More hassle than it's worth. MIDI is well - // defined and will always have a 4-byte header. We use 5 so we get - // free null termination. - char header_id[5] = { 0, 0, 0, 0, 0 }; - uint32_t header_length; - unsigned short format; - unsigned short track_count; - unsigned short time_division; - - stream.read(header_id, static_cast(MidiFileHeader.length())); - string header(header_id); - if (header != MidiFileHeader) { - if (header != RiffFileHeader) - throw MidiError(MidiError_UnknownHeaderType); - - else { - // We know how to support RIFF files - unsigned long throw_away; - stream.read(reinterpret_cast(&throw_away), sizeof(unsigned long)); // RIFF length - stream.read(reinterpret_cast(&throw_away), sizeof(unsigned long)); // "RMID" - stream.read(reinterpret_cast(&throw_away), sizeof(unsigned long)); // "data" - stream.read(reinterpret_cast(&throw_away), sizeof(unsigned long)); // data size - - // Call this recursively, without the RIFF header this time - return ReadFromStream(stream); - } - } - - stream.read(reinterpret_cast(&header_length), sizeof(uint32_t)); - stream.read(reinterpret_cast(&format), sizeof(unsigned short)); - stream.read(reinterpret_cast(&track_count), sizeof(unsigned short)); - stream.read(reinterpret_cast(&time_division), sizeof(unsigned short)); - - if (stream.fail()) - throw MidiError(MidiError_NoHeader); - - // Chunk Size is always 6 by definition - const static unsigned int MidiFileHeaderChunkLength = 6; - - header_length = BigToSystem32(header_length); - if (header_length != MidiFileHeaderChunkLength) - throw MidiError(MidiError_BadHeaderSize); - - enum MidiFormat { MidiFormat0 = 0, MidiFormat1, MidiFormat2 }; - - format = BigToSystem16(format); - if (format == MidiFormat2) { - // MIDI 0: All information in 1 track - // MIDI 1: Multiple tracks intended to be played simultaneously - // MIDI 2: Multiple tracks intended to be played separately - // - // We do not support MIDI 2 at this time - throw MidiError(MidiError_Type2MidiNotSupported); - } - - track_count = BigToSystem16(track_count); - if (format == 0 && track_count != 1) - // MIDI 0 has only 1 track by definition - throw MidiError(MidiError_BadType0Midi); - - // Time division can be encoded two ways based on a bit-flag: - // - pulses per quarter note (15-bits) - // - SMTPE frames per second (7-bits for SMPTE frame count and 8-bits for clock ticks per frame) - time_division = BigToSystem16(time_division); - bool in_smpte = ((time_division & 0x8000) != 0); - - if (in_smpte) - throw MidiError(MidiError_SMTPETimingNotImplemented); - - // We ignore the possibility of SMPTE timing, so we can - // use the time division value directly as PPQN. - unsigned short pulses_per_quarter_note = time_division; - - // Read in our tracks - for (int i = 0; i < track_count; ++i) { - m.m_tracks.push_back(MidiTrack::ReadFromStream(stream)); - } - - m.BuildTempoTrack(); - - // Tell our tracks their IDs - for (int i = 0; i < track_count; ++i) { - m.m_tracks[i].SetTrackId(i); - } - - // Translate each track's list of notes and list - // of events into microseconds. - for (MidiTrackList::iterator i = m.m_tracks.begin(); i != m.m_tracks.end(); ++i) { - i->Reset(); - m.TranslateNotes(i->Notes(), pulses_per_quarter_note); - - MidiEventMicrosecondList event_usecs; - for (MidiEventPulsesList::const_iterator j = i->EventPulses().begin(); j != i->EventPulses().end(); ++j) { - event_usecs.push_back(m.GetEventPulseInMicroseconds(*j, pulses_per_quarter_note)); - } - - i->SetEventUsecs(event_usecs); - } - - m.m_initialized = true; - - // Just grab the end of the last note to find out how long the song is - m.m_microsecond_base_song_length = m.m_translated_notes.rbegin()->end; - - // Eat everything up until *just* before the first note event - m.m_microsecond_dead_start_air = m.GetEventPulseInMicroseconds(m.FindFirstNotePulse(), pulses_per_quarter_note) - 1; - - // Calculate positions for bar_lines - MidiEventMicrosecondList bar_line_usecs; - const microseconds_t len = m.GetSongLengthInMicroseconds(); - microseconds_t bar_usec = 0; - int bar_no = 0; - while (bar_usec <= len) - { - bar_usec = m.GetEventPulseInMicroseconds(bar_no*pulses_per_quarter_note*4, pulses_per_quarter_note); - bar_line_usecs.push_back(bar_usec); - bar_no++; - } - m.m_bar_line_usecs = bar_line_usecs; - - return m; -} - -// NOTE: This is required for much of the other functionality provided -// by this class, however, this causes a destructive change in the way -// the MIDI is represented internally which means we can never save the -// file back out to disk exactly as we loaded it. -// -// This adds an extra track dedicated to tempo change events. Tempo events -// are extracted from every other track and placed in the new one. -// -// This allows quick(er) calculation of wall-clock event times -void Midi::BuildTempoTrack() { - // This map will help us get rid of duplicate events if - // the tempo is specified in every track (as is common). - // - // It also does sorting for us so we can just copy the - // events right over to the new track. - map tempo_events; - - // Run through each track looking for tempo events - for (MidiTrackList::iterator t = m_tracks.begin(); t != m_tracks.end(); ++t) { - for (size_t i = 0; i < t->Events().size(); ++i) { - MidiEvent ev = t->Events()[i]; - unsigned long ev_pulses = t->EventPulses()[i]; - - if (ev.Type() == MidiEventType_Meta && - ev.MetaType() == MidiMetaEvent_TempoChange) { - - // Pull tempo event out of both lists - // - // Vector is kind of a hassle this way -- we have to - // walk an iterator to that point in the list because - // erase MUST take an iterator... but erasing from a - // list invalidates iterators. bleah. - MidiEventList::iterator event_to_erase = t->Events().begin(); - MidiEventPulsesList::iterator event_pulse_to_erase = t->EventPulses().begin(); - for (size_t j = 0; j < i; ++j) { - ++event_to_erase; - ++event_pulse_to_erase; - } - - t->Events().erase(event_to_erase); - t->EventPulses().erase(event_pulse_to_erase); - - // Adjust next event's delta time - if (t->Events().size() > i) { - // (We just erased the element at i, so - // now i is pointing to the next element) - unsigned long next_dt = t->Events()[i].GetDeltaPulses(); - - t->Events()[i].SetDeltaPulses(ev.GetDeltaPulses() + next_dt); - } - - // We have to roll i back for the next loop around - --i; - - // Insert our newly stolen event into the auto-sorting map - tempo_events[ev_pulses] = ev; - } - } - } - - // Create a new track (always the last track in the track list) - m_tracks.push_back(MidiTrack::CreateBlankTrack()); - - MidiEventList &tempo_track_events = m_tracks[m_tracks.size()-1].Events(); - MidiEventPulsesList &tempo_track_event_pulses = m_tracks[m_tracks.size()-1].EventPulses(); - - // Copy over all our tempo events - unsigned long previous_absolute_pulses = 0; - for (map::const_iterator i = tempo_events.begin(); - i != tempo_events.end(); ++i) { - - unsigned long absolute_pulses = i->first; - MidiEvent ev = i->second; - - // Reset each of their delta times while we go - ev.SetDeltaPulses(absolute_pulses - previous_absolute_pulses); - previous_absolute_pulses = absolute_pulses; - - // Add them to the track - tempo_track_event_pulses.push_back(absolute_pulses); - tempo_track_events.push_back(ev); - } -} - -unsigned long Midi::FindFirstNotePulse() { - unsigned long first_note_pulse = 0; - - // Find the very last value it could ever possibly be, to start with - for (MidiTrackList::const_iterator t = m_tracks.begin(); t != m_tracks.end(); ++t) { - if (t->EventPulses().size() == 0) - continue; - - unsigned long pulses = t->EventPulses().back(); - - if (pulses > first_note_pulse) - first_note_pulse = pulses; - } - - // Now run through each event in each track looking for the very - // first note_on event - for (MidiTrackList::const_iterator t = m_tracks.begin(); t != m_tracks.end(); ++t) { - for (size_t ev_id = 0; ev_id < t->Events().size(); ++ev_id) { - if (t->Events()[ev_id].Type() == MidiEventType_NoteOn) { - unsigned long note_pulse = t->EventPulses()[ev_id]; - - if (note_pulse < first_note_pulse) - first_note_pulse = note_pulse; - - // We found the first note event in this - // track. No need to keep searching. - break; - } - } - } - - return first_note_pulse; -} - -microseconds_t Midi::ConvertPulsesToMicroseconds(unsigned long pulses, - microseconds_t tempo, - unsigned short pulses_per_quarter_note) { - // Here's what we have to work with: - // pulses is given - // tempo is given (units of microseconds/quarter_note) - // (pulses/quarter_note) is given as a constant in this object file - const double quarter_notes = static_cast(pulses) / static_cast(pulses_per_quarter_note); - const double microseconds = quarter_notes * static_cast(tempo); - - return static_cast(microseconds); -} - -microseconds_t Midi::GetEventPulseInMicroseconds(unsigned long event_pulses, - unsigned short pulses_per_quarter_note) const { - if (m_tracks.size() == 0) - return 0; - - const MidiTrack &tempo_track = m_tracks.back(); - - microseconds_t running_result = 0; - - bool hit = false; - unsigned long last_tempo_event_pulses = 0; - microseconds_t running_tempo = DefaultUSTempo; - - for (size_t i = 0; i < tempo_track.Events().size(); ++i) { - unsigned long tempo_event_pulses = tempo_track.EventPulses()[i]; - - // If the time we're asking to convert is still beyond - // this tempo event, just add the last time slice (at - // the previous tempo) to the running wall-clock time. - unsigned long delta_pulses = 0; - if (event_pulses > tempo_event_pulses) - delta_pulses = tempo_event_pulses - last_tempo_event_pulses; - - else { - hit = true; - delta_pulses = event_pulses - last_tempo_event_pulses; - } - - running_result += ConvertPulsesToMicroseconds(delta_pulses, running_tempo, pulses_per_quarter_note); - - // If the time we're calculating is before the tempo event we're - // looking at, we're done. - if (hit) - break; - - running_tempo = tempo_track.Events()[i].GetTempoInUsPerQn(); - last_tempo_event_pulses = tempo_event_pulses; - } - - // The requested time may be after the very last tempo event - if (!hit) { - unsigned long remaining_pulses = event_pulses - last_tempo_event_pulses; - running_result += ConvertPulsesToMicroseconds(remaining_pulses, running_tempo, pulses_per_quarter_note); - } - - return running_result; -} - -void Midi::Reset(microseconds_t lead_in_microseconds, microseconds_t lead_out_microseconds) { - m_microsecond_lead_in = lead_in_microseconds; - m_microsecond_lead_out = lead_out_microseconds; - m_microsecond_song_position = m_microsecond_dead_start_air - lead_in_microseconds; - m_first_update_after_reset = true; - - for (MidiTrackList::iterator i = m_tracks.begin(); i != m_tracks.end(); ++i) { - i->Reset(); - } -} - -void Midi::TranslateNotes(const NoteSet ¬es, unsigned short pulses_per_quarter_note) { - for (NoteSet::const_iterator i = notes.begin(); i != notes.end(); ++i) { - TranslatedNote trans; - - trans.note_id = i->note_id; - trans.track_id = i->track_id; - trans.channel = i->channel; - trans.velocity = i->velocity; - trans.start = GetEventPulseInMicroseconds(i->start, pulses_per_quarter_note); - trans.end = GetEventPulseInMicroseconds(i->end, pulses_per_quarter_note); - - m_translated_notes.insert(trans); - } -} - -MidiEventListWithTrackId Midi::Update(microseconds_t delta_microseconds) { - MidiEventListWithTrackId aggregated_events; - if (!m_initialized) - return aggregated_events; - - // Move everything forward (fallen keys, the screen keyboard) - // These variable is used on redraw later - m_microsecond_song_position += delta_microseconds; - if (m_first_update_after_reset) { - delta_microseconds += m_microsecond_song_position; - m_first_update_after_reset = false; - } - - if (delta_microseconds == 0) - return aggregated_events; - - if (m_microsecond_song_position < 0) - return aggregated_events; - - if (delta_microseconds > m_microsecond_song_position) - delta_microseconds = m_microsecond_song_position; - - const size_t track_count = m_tracks.size(); - // These code is not related to fallen keys - for (size_t i = 0; i < track_count; ++i) { - MidiEventList track_events = m_tracks[i].Update(delta_microseconds); - - const size_t event_count = track_events.size(); - // Collect events to be passed to a screen keyboard - for (size_t j = 0; j < event_count; ++j) { - aggregated_events.insert(aggregated_events.end(), make_pair(i, track_events[j])); - } - } - - // Pass to a keyboard - return aggregated_events; -} - -void Midi::GoTo(microseconds_t microsecond_song_position) { - if (!m_initialized) - return; - - // Do not let go back too far (causes bugs) - // There is some black magic for negative values of - // microsecond_song_position, just skip it -//if (microsecond_song_position <= 0) -//{ -// Reset(m_microsecond_lead_in, m_microsecond_lead_out); -// return; -//} - - m_microsecond_song_position = microsecond_song_position; - - const size_t track_count = m_tracks.size(); - for (size_t i = 0; i < track_count; ++i) { - m_tracks[i].GoTo(microsecond_song_position); - } -} - -microseconds_t Midi::GetSongLengthInMicroseconds() const { - if (!m_initialized) - return 0; - - return m_microsecond_base_song_length - m_microsecond_dead_start_air; -} - - -// Gets next bar after point of time -microseconds_t Midi::GetNextBarInMicroseconds(const microseconds_t point) const { - MidiEventMicrosecondList::const_iterator j = m_bar_line_usecs.begin(); - microseconds_t first_bar_usec = *j; - for (; j != m_bar_line_usecs.end(); ++j) { - microseconds_t bar_usec = *j; - // Add offset - bar_usec -= first_bar_usec + 1; - if (bar_usec > point) - return bar_usec; - } - return 0; // not found -} - -unsigned int Midi::AggregateEventsRemain() const { - if (!m_initialized) - return 0; - - unsigned int aggregate = 0; - for (MidiTrackList::const_iterator i = m_tracks.begin(); i != m_tracks.end(); ++i) - aggregate += i->AggregateEventsRemain(); - - return aggregate; -} - -unsigned int Midi::AggregateNotesRemain() const { - if (!m_initialized) - return 0; - - unsigned int aggregate = 0; - for (MidiTrackList::const_iterator i = m_tracks.begin(); i != m_tracks.end(); ++i) - aggregate += i->AggregateNotesRemain(); - - return aggregate; -} - -unsigned int Midi::AggregateEventCount() const { - if (!m_initialized) - return 0; - - unsigned int aggregate = 0; - for (MidiTrackList::const_iterator i = m_tracks.begin(); i != m_tracks.end(); ++i) - aggregate += i->AggregateEventCount(); - - return aggregate; -} - -unsigned int Midi::AggregateNoteCount() const { - if (!m_initialized) - return 0; - - unsigned int aggregate = 0; - for (MidiTrackList::const_iterator i = m_tracks.begin(); i != m_tracks.end(); ++i) - aggregate += i->AggregateNoteCount(); - - return aggregate; -} - -// This function is used for the progress bar -double Midi::GetSongPercentageComplete() const { - if (!m_initialized) - return 0.0; - - const double pos = static_cast(m_microsecond_song_position - m_microsecond_dead_start_air); - const double len = static_cast(GetSongLengthInMicroseconds()); - - if (pos < 0) - return 0.0; - - if (len == 0) - return 1.0; - - return min( (pos / len), 1.0 ); -} - -bool Midi::IsSongOver() const { - if (!m_initialized) - return true; - - return (m_microsecond_song_position - m_microsecond_dead_start_air) >= - GetSongLengthInMicroseconds() + m_microsecond_lead_out; -} diff --git a/src/libmidi/Midi.h b/src/libmidi/Midi.h deleted file mode 100644 index d4db4c9c..00000000 --- a/src/libmidi/Midi.h +++ /dev/null @@ -1,124 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_H -#define __MIDI_H - -#include -#include - -#include "Note.h" -#include "MidiTrack.h" -#include "MidiTypes.h" - -class MidiError; -class MidiEvent; - -typedef std::vector MidiTrackList; - -typedef std::vector MidiEventList; -typedef std::vector > MidiEventListWithTrackId; - -// NOTE: This library's MIDI loading and handling is destructive. Perfect -// 1:1 serialization routines will not be possible without quite a -// bit of additional work. -class Midi { - -public: - static Midi ReadFromFile(const std::string &filename); - static Midi ReadFromStream(std::istream &stream); - - const std::vector &Tracks() const { - return m_tracks; - } - - const TranslatedNoteSet &Notes() const { - return m_translated_notes; - } - - MidiEventListWithTrackId Update(microseconds_t delta_microseconds); - void GoTo(microseconds_t microsecond_song_position); - - void Reset(microseconds_t lead_in_microseconds, - microseconds_t lead_out_microseconds); - - microseconds_t GetSongPositionInMicroseconds() const { - return m_microsecond_song_position; - } - - microseconds_t GetSongLengthInMicroseconds() const; - - microseconds_t GetDeadAirStartOffsetMicroseconds() const { - return m_microsecond_dead_start_air; - } - - // This doesn't include lead-in (so it's perfect for a progress bar). - // (It is also clamped to [0.0, 1.0], so lead-in and lead-out won't give any - // unexpected results.) - double GetSongPercentageComplete() const; - - // This will report when the lead-out period is complete. - bool IsSongOver() const; - - unsigned int AggregateEventsRemain() const; - unsigned int AggregateEventCount() const; - - unsigned int AggregateNotesRemain() const; - unsigned int AggregateNoteCount() const; - - const MidiEventMicrosecondList & GetBarLines() const { - return m_bar_line_usecs; - } - - microseconds_t GetNextBarInMicroseconds(const microseconds_t point) const; - -private: - const static unsigned long DefaultBPM = 120; - const static microseconds_t OneMinuteInMicroseconds = 60000000; - const static microseconds_t DefaultUSTempo = OneMinuteInMicroseconds / DefaultBPM; - - static microseconds_t ConvertPulsesToMicroseconds(unsigned long pulses, - microseconds_t tempo, - unsigned short pulses_per_quarter_note); - - Midi(): - m_initialized(false), m_microsecond_dead_start_air(0) { - - Reset(0, 0); - } - - // This is O(n) where n is the number of tempo changes (across all tracks) in - // the song up to the specified time. Tempo changes are usually a small number. - // (Almost always 0 or 1, going up to maybe 30-100 in rare cases.) - microseconds_t GetEventPulseInMicroseconds(unsigned long event_pulses, - unsigned short pulses_per_quarter_note) const; - - unsigned long FindFirstNotePulse(); - - void BuildTempoTrack(); - void TranslateNotes(const NoteSet ¬es, unsigned short pulses_per_quarter_note); - - bool m_initialized; - - TranslatedNoteSet m_translated_notes; - - // Position can be negative (for lead-in). - microseconds_t m_microsecond_song_position; - microseconds_t m_microsecond_base_song_length; - - microseconds_t m_microsecond_lead_in; - microseconds_t m_microsecond_lead_out; - microseconds_t m_microsecond_dead_start_air; - - bool m_first_update_after_reset; - double m_playback_speed; - MidiTrackList m_tracks; - MidiEventMicrosecondList m_bar_line_usecs; -}; - -#endif diff --git a/src/libmidi/MidiEvent.cpp b/src/libmidi/MidiEvent.cpp deleted file mode 100644 index 2f6dede1..00000000 --- a/src/libmidi/MidiEvent.cpp +++ /dev/null @@ -1,350 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "MidiEvent.h" -#include "MidiUtil.h" -#include "Note.h" - -using namespace std; - -MidiEvent MidiEvent::ReadFromStream(istream &stream, - unsigned char last_status, - bool contains_delta_pulses) { - MidiEvent ev; - - if (contains_delta_pulses) - ev.m_delta_pulses = parse_variable_length(stream); - else - ev.m_delta_pulses = 0; - - // MIDI uses a compression mechanism called "running status". - // Anytime you read a status byte that doesn't have the highest- - // order bit set, what you actually read is the 1st data byte - // of a message with the status of the previous message. - ev.m_status = static_cast(stream.peek()); - - if ((ev.m_status & 0x80) == 0) - ev.m_status = last_status; - - else - // It was a status byte after all, just read past it - // in the stream - stream.read(reinterpret_cast(&ev.m_status), sizeof(unsigned char)); - - switch (ev.Type()) { - case MidiEventType_Meta: - ev.ReadMeta(stream); - break; - - case MidiEventType_SysEx: - ev.ReadSysEx(stream); - break; - - default: - ev.ReadStandard(stream); - break; - } - - return ev; -} - -MidiEvent MidiEvent::Build(const MidiEventSimple &simple) { - MidiEvent ev; - - ev.m_delta_pulses = 0; - ev.m_status = simple.status; - ev.m_data1 = simple.byte1; - ev.m_data2 = simple.byte2; - - if (ev.Type() == MidiEventType_Meta) - throw MidiError(MidiError_MetaEventOnInput); - - return ev; -} - -MidiEvent MidiEvent::NullEvent() { - MidiEvent ev; - - ev.m_status = 0xFF; - ev.m_meta_type = MidiMetaEvent_Proprietary; - ev.m_delta_pulses = 0; - - return ev; -} - -void MidiEvent::ReadMeta(istream &stream) { - stream.read(reinterpret_cast(&m_meta_type), sizeof(unsigned char)); - unsigned long meta_length = parse_variable_length(stream); - - char *buffer = new char[meta_length + 1]; - buffer[meta_length] = 0; - - stream.read(buffer, meta_length); - if (stream.fail()) { - delete[] buffer; - throw MidiError(MidiError_EventTooShort); - } - - switch (m_meta_type) { - case MidiMetaEvent_Text: - case MidiMetaEvent_Copyright: - case MidiMetaEvent_TrackName: - case MidiMetaEvent_Instrument: - case MidiMetaEvent_Lyric: - case MidiMetaEvent_Marker: - case MidiMetaEvent_Cue: - case MidiMetaEvent_PatchName: - case MidiMetaEvent_DeviceName: - m_text = string(buffer, meta_length); - break; - - case MidiMetaEvent_TempoChange: { - if (meta_length < 3) - throw MidiError(MidiError_EventTooShort); - - // We have to convert to unsigned char first for some reason or the - // conversion gets all wacky and tries to look at more than just its - // one byte at a time. - unsigned int b0 = static_cast(buffer[0]); - unsigned int b1 = static_cast(buffer[1]); - unsigned int b2 = static_cast(buffer[2]); - m_tempo_uspqn = (b0 << 16) + (b1 << 8) + b2; - - break; - } - - case MidiMetaEvent_SequenceNumber: - case MidiMetaEvent_EndOfTrack: - case MidiMetaEvent_SMPTEOffset: - case MidiMetaEvent_TimeSignature: - case MidiMetaEvent_KeySignature: - case MidiMetaEvent_Proprietary: - case MidiMetaEvent_ChannelPrefix: - case MidiMetaEvent_MidiPort: - // NOTE: We would have to keep all of this around if we - // wanted to reproduce 1:1 MIDIs between file Save/Load - break; - - default: - // Ignore unknown event - std::cerr << "Ignore unknown midi event type " << (m_meta_type * 1) - << " of length " << meta_length << endl; -// delete[] buffer; -// throw MidiError(MidiError_UnknownMetaEventType); - } - - delete[] buffer; -} - -void MidiEvent::ReadSysEx(istream &stream) { - // NOTE: We would have to keep SysEx events around if we - // wanted to reproduce 1:1 MIDIs between file Save/Load - unsigned long sys_ex_length = parse_variable_length(stream); - - // Discard - char *buffer = new char[sys_ex_length]; - stream.read(buffer, sys_ex_length); - delete[] buffer; -} - -void MidiEvent::ReadStandard(istream &stream) { - switch (Type()) { - case MidiEventType_NoteOff: - case MidiEventType_NoteOn: - case MidiEventType_Aftertouch: - case MidiEventType_Controller: - case MidiEventType_PitchWheel: - stream.read(reinterpret_cast(&m_data1), sizeof(unsigned char)); - stream.read(reinterpret_cast(&m_data2), sizeof(unsigned char)); - break; - - case MidiEventType_ProgramChange: - case MidiEventType_ChannelPressure: - stream.read(reinterpret_cast(&m_data1), sizeof(unsigned char)); - m_data2 = 0; - break; - - default: - throw MidiError(MidiError_UnknownEventType); - } -} - -bool MidiEvent::GetSimpleEvent(MidiEventSimple *simple) const { - MidiEventType t = Type(); - if (t == MidiEventType_Meta || - t == MidiEventType_SysEx || - t == MidiEventType_Unknown) - return false; - - simple->status = m_status; - simple->byte1 = m_data1; - simple->byte2 = m_data2; - - return true; -} - -MidiEventType MidiEvent::Type() const { - if (m_status > 0xEF && m_status < 0xFF) - return MidiEventType_SysEx; - - if (m_status < 0x80) - return MidiEventType_Unknown; - - if (m_status == 0xFF) - return MidiEventType_Meta; - - // The 0x8_ through 0xE_ events contain channel numbers - // in the lowest 4 bits - unsigned char status_top = m_status >> 4; - - switch (status_top) { - case 0x8: - return MidiEventType_NoteOff; - - case 0x9: - return MidiEventType_NoteOn; - - case 0xA: - return MidiEventType_Aftertouch; - - case 0xB: - return MidiEventType_Controller; - - case 0xC: - return MidiEventType_ProgramChange; - - case 0xD: - return MidiEventType_ChannelPressure; - - case 0xE: - return MidiEventType_PitchWheel; - - default: - return MidiEventType_Unknown; - } -} - -MidiMetaEventType MidiEvent::MetaType() const { - if (Type() != MidiEventType_Meta) - return MidiMetaEvent_Unknown; - - return static_cast(m_meta_type); -} - -bool MidiEvent::IsEnd() const { - return (Type() == MidiEventType_Meta && - MetaType() == MidiMetaEvent_EndOfTrack); -} - -unsigned char MidiEvent::Channel() const { - // The channel is held in the lower nibble of the status code - return (m_status & 0x0F); -} - -void MidiEvent::SetChannel(unsigned char channel) { - if (channel > 15) - return; - - // Clear out the old channel - m_status = m_status & 0xF0; - - // Set the new channel - m_status = m_status | channel; -} - -void MidiEvent::SetVelocity(int velocity) { - if (Type() != MidiEventType_NoteOn) - return; - - m_data2 = static_cast(velocity); -} - -bool MidiEvent::HasText() const { - if (Type() != MidiEventType_Meta) - return false; - - switch (m_meta_type) { - case MidiMetaEvent_Text: - case MidiMetaEvent_Copyright: - case MidiMetaEvent_TrackName: - case MidiMetaEvent_Instrument: - case MidiMetaEvent_Lyric: - case MidiMetaEvent_Marker: - case MidiMetaEvent_Cue: - case MidiMetaEvent_PatchName: - case MidiMetaEvent_DeviceName: - return true; - - default: - return false; - } -} - -NoteId MidiEvent::NoteNumber() const { - if (Type() != MidiEventType_NoteOn && - Type() != MidiEventType_NoteOff) - return 0; - - return m_data1; -} - -void MidiEvent::ShiftNote(int shift_amount) { - if (Type() != MidiEventType_NoteOn && - Type() != MidiEventType_NoteOff) - return; - - m_data1 = m_data1 + static_cast(shift_amount); -} - -int MidiEvent::ProgramNumber() const { - if (Type() != MidiEventType_ProgramChange) - return 0; - - return m_data1; -} - -string MidiEvent::NoteName(unsigned int note_number) { - // Music domain knowledge - const static unsigned int NotesPerOctave = 12; - const static string NoteBases[NotesPerOctave] = { - STRING("C"), STRING("C#"), STRING("D"), - STRING("D#"), STRING("E"), STRING("F"), - STRING("F#"), STRING("G"), STRING("G#"), - STRING("A"), STRING("A#"), STRING("B") - }; - - unsigned int octave = (note_number / NotesPerOctave); - const string note_base = NoteBases[note_number % NotesPerOctave]; - - return STRING(note_base << octave); -} - -int MidiEvent::NoteVelocity() const { - if (Type() == MidiEventType_NoteOff) - return 0; - - if (Type() != MidiEventType_NoteOn) - return -1; - - return static_cast(m_data2); -} - -string MidiEvent::Text() const { - if (!HasText()) - return ""; - - return m_text; -} - -unsigned long MidiEvent::GetTempoInUsPerQn() const { - if (Type() != MidiEventType_Meta || - MetaType() != MidiMetaEvent_TempoChange) - throw MidiError(MidiError_RequestedTempoFromNonTempoEvent); - - return m_tempo_uspqn; -} diff --git a/src/libmidi/MidiEvent.h b/src/libmidi/MidiEvent.h deleted file mode 100644 index 2f369e44..00000000 --- a/src/libmidi/MidiEvent.h +++ /dev/null @@ -1,131 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_EVENT_H -#define __MIDI_EVENT_H - -#include -#include - -#include "Note.h" -#include "MidiUtil.h" - -struct MidiEventSimple { - - MidiEventSimple() : - status(0), byte1(0), byte2(0) { - } - - MidiEventSimple(unsigned char s, unsigned char b1, unsigned char b2) : - status(s), byte1(b1), byte2(b2) { - } - - unsigned char status; - unsigned char byte1; - unsigned char byte2; -}; - -class MidiEvent { -public: - - static MidiEvent ReadFromStream(std::istream &stream, - unsigned char last_status, - bool contains_delta_pulses = true); - - static MidiEvent Build(const MidiEventSimple &simple); - static MidiEvent NullEvent(); - - // NOTE: There is a VERY good chance you don't want to use this directly. - // The only reason it's not private is because the standard containers - // require a default constructor. - MidiEvent() : - m_status(0), m_data1(0), m_data2(0), m_tempo_uspqn(0) { - } - - // Returns true if the event could be expressed in a simple event. (So, - // this will return false for Meta and SysEx events.) - bool GetSimpleEvent(MidiEventSimple *simple) const; - - MidiEventType Type() const; - - unsigned long GetDeltaPulses() const { - return m_delta_pulses; - } - - // This is generally for internal Midi library use only. - void SetDeltaPulses(unsigned long delta_pulses) { - m_delta_pulses = delta_pulses; - } - - void ShiftNote(int shift_amount); - - NoteId NoteNumber() const; - - // Returns a friendly name for this particular Note-On or Note- - // Off event. (e.g. "A#2") Returns empty string on other types - // of events. - static std::string NoteName(NoteId note_number); - - // Returns the "Program to change to" value if this is a Program - // Change event, 0 otherwise. - int ProgramNumber() const; - - // Returns the "velocity" of a Note-On (or 0 if this is a Note- - // Off event). Returns -1 for other event types. - int NoteVelocity() const; - - void SetVelocity(int velocity); - - // Returns which type of meta event this is (or - // MetaEvent_Unknown if type() is not EventType_Meta). - MidiMetaEventType MetaType() const; - - // Retrieve the tempo from a tempo meta event in microseconds - // per quarter note. (Non-meta-tempo events will throw an error). - unsigned long GetTempoInUsPerQn() const; - - // Convenience function: Is this the special End-Of-Track event - bool IsEnd() const; - - // Returns which channel this event operates on. This is - // only defined for standard MIDI events that require a - // channel argument. - unsigned char Channel() const; - - void SetChannel(unsigned char channel); - - // Does this event type allow arbitrary text - bool HasText() const; - - // Returns the text content of the event (or empty-string if - // this isn't a text event.) - std::string Text() const; - - // Returns the status code of the MIDI event - unsigned char StatusCode() const { - return m_status; - } - -private: - void ReadMeta(std::istream &stream); - void ReadSysEx(std::istream &stream); - void ReadStandard(std::istream &stream); - - unsigned char m_status; - unsigned char m_data1; - unsigned char m_data2; - unsigned long m_delta_pulses; - - unsigned char m_meta_type; - - unsigned long m_tempo_uspqn; - std::string m_text; -}; - - -#endif // __MIDI_EVENT_H diff --git a/src/libmidi/MidiTrack.cpp b/src/libmidi/MidiTrack.cpp deleted file mode 100644 index d095506d..00000000 --- a/src/libmidi/MidiTrack.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include "MidiTrack.h" -#include "MidiEvent.h" -#include "MidiUtil.h" -#include "Midi.h" - -#include -#include -#include -#include - -using namespace std; - -MidiTrack MidiTrack::ReadFromStream(std::istream &stream) { - // Verify the track header - const static string MidiTrackHeader = "MTrk"; - - // I could use (MidiTrackHeader.length() + 1), but then this has to be - // dynamically allocated. More hassle than it's worth. MIDI is well - // defined and will always have a 4-byte header. We use 5 so we get - // free null termination. - char header_id[5] = { 0, 0, 0, 0, 0 }; - uint32_t track_length; - - stream.read(header_id, static_cast(MidiTrackHeader.length())); - stream.read(reinterpret_cast(&track_length), sizeof(uint32_t)); - - if (stream.fail()) - throw MidiError(MidiError_TrackHeaderTooShort); - - string header(header_id); - if (header != MidiTrackHeader) - throw MidiError_BadTrackHeaderType; - - // Pull the full track out of the file all at once -- there is an - // End-Of-Track event, but this allows us handle malformed MIDI a - // little more gracefully. - track_length = BigToSystem32(track_length); - char *buffer = new char[track_length + 1]; - buffer[track_length] = 0; - - stream.read(buffer, track_length); - if (stream.fail()) { - delete[] buffer; - throw MidiError(MidiError_TrackTooShort); - } - - // We have to jump through a couple hoops because istringstream - // can't handle binary data unless constructed through an std::string. - string buffer_string(buffer, track_length); - istringstream event_stream(buffer_string, ios::binary); - delete[] buffer; - - MidiTrack t; - - // Read events until we run out of track - char last_status = 0; - unsigned long current_pulse_count = 0; - while (event_stream.peek() != char_traits::eof()) { - MidiEvent ev = MidiEvent::ReadFromStream(event_stream, last_status); - last_status = ev.StatusCode(); - - t.m_events.push_back(ev); - - current_pulse_count += ev.GetDeltaPulses(); - t.m_event_pulses.push_back(current_pulse_count); - } - - t.BuildNoteSet(); - t.DiscoverInstrument(); - - return t; -} - -struct NoteInfo { - - int velocity; - unsigned char channel; - unsigned long pulses; -}; - -void MidiTrack::BuildNoteSet() { - m_note_set.clear(); - - // Keep a list of all the notes currently "on" (and the pulse that - // it was started). On a note_on event, we create an element. On - // a note_off event we check that an element exists, make a "Note", - // and remove the element from the list. If there is already an - // element on a note_on we both cap off the previous "Note" and - // begin a new one. - // - // A note_on with velocity 0 is a note_off - map m_active_notes; - - for (size_t i = 0; i < m_events.size(); ++i) { - const MidiEvent &ev = m_events[i]; - if (ev.Type() != MidiEventType_NoteOn && ev.Type() != MidiEventType_NoteOff) - continue; - - bool on = (ev.Type() == MidiEventType_NoteOn && ev.NoteVelocity() > 0); - NoteId id = ev.NoteNumber(); - - // Check for an active note - map::iterator find_ret = m_active_notes.find(id); - bool active_event = (find_ret != m_active_notes.end()); - - // Close off the last event if there was one - if (active_event) { - Note n; - n.start = find_ret->second.pulses; - n.end = m_event_pulses[i]; - n.note_id = id; - n.channel = find_ret->second.channel; - n.velocity = find_ret->second.velocity; - - // NOTE: This must be set at the next level up. The track - // itself has no idea what its index is. - n.track_id = 0; - - // Add a note and remove this NoteId from the active list - m_note_set.insert(n); - m_active_notes.erase(find_ret); - } - - // We've handled any active events. If this was a note_off we're done. - if (!on) - continue; - - // Add a new active event - NoteInfo info; - info.channel = ev.Channel(); - info.velocity = ev.NoteVelocity(); - info.pulses = m_event_pulses[i]; - - m_active_notes[id] = info; - } - - if (m_active_notes.size() > 0) { - // LOGTODO! - - // This is mostly non-critical. - // - // Erroring out would be needlessly restrictive against - // promiscuous MIDI files. As-is, a note just won't be - // inserted if it isn't closed properly. - } -} - -void MidiTrack::DiscoverInstrument() { - // Default to Program 0 per the MIDI Standard - m_instrument_id = 0; - bool instrument_found = false; - - // These are actually 10 and 16 in the MIDI standard. However, MIDI - // channels are 1-based facing the user. They're stored 0-based. - const static int PercussionChannel1 = 9; - const static int PercussionChannel2 = 15; - - // Check to see if any/all of the notes - // in this track use Channel 10. - bool any_note_uses_percussion = false; - bool any_note_does_not_use_percussion = false; - - for (size_t i = 0; i < m_events.size(); ++i) { - const MidiEvent &ev = m_events[i]; - - if (ev.Type() != MidiEventType_NoteOn) - continue; - - if (ev.Channel() == PercussionChannel1 || ev.Channel() == PercussionChannel2) - any_note_uses_percussion = true; - - if (ev.Channel() != PercussionChannel1 && ev.Channel() != PercussionChannel2) - any_note_does_not_use_percussion = true; - } - - if (any_note_uses_percussion && !any_note_does_not_use_percussion) { - m_instrument_id = InstrumentIdPercussion; - return; - } - - if (any_note_uses_percussion && any_note_does_not_use_percussion) { - m_instrument_id = InstrumentIdVarious; - return; - } - - for (size_t i = 0; i < m_events.size(); ++i) { - const MidiEvent &ev = m_events[i]; - - if (ev.Type() != MidiEventType_ProgramChange) - continue; - - // If we've already hit a different instrument in this - // same track, just tag it as "various" and exit early - // - // Also check that the same instrument isn't just set - // multiple times in the same track - if (instrument_found && m_instrument_id != ev.ProgramNumber()) { - m_instrument_id = InstrumentIdVarious; - return; - } - - m_instrument_id = ev.ProgramNumber(); - instrument_found = true; - } -} - -void MidiTrack::SetTrackId(size_t track_id) { - NoteSet old = m_note_set; - - m_note_set.clear(); - for (NoteSet::const_iterator i = old.begin(); i != old.end(); ++i) { - Note n = *i; - n.track_id = track_id; - - m_note_set.insert(n); - } -} - -void MidiTrack::Reset() { - m_running_microseconds = 0; - m_last_event = -1; - - m_notes_remaining = static_cast(m_note_set.size()); -} - -MidiEventList MidiTrack::Update(microseconds_t delta_microseconds) { - m_running_microseconds += delta_microseconds; - - MidiEventList evs; - for (size_t i = m_last_event + 1; i < m_events.size(); ++i) { - if (m_event_usecs[i] <= m_running_microseconds) { - evs.push_back(m_events[i]); - m_last_event = static_cast(i); - - if (m_events[i].Type() == MidiEventType_NoteOn && m_events[i].NoteVelocity() > 0) - m_notes_remaining--; - } - - else - break; - } - - return evs; -} - -void MidiTrack::GoTo(microseconds_t microsecond_song_position) { - m_running_microseconds = microsecond_song_position; - m_last_event = -1; - m_notes_remaining = static_cast(m_note_set.size()); - - for (size_t i = 0; i < m_events.size(); ++i) { - if (m_event_usecs[i] <= m_running_microseconds) { - m_last_event = static_cast(i); - - if (m_events[i].Type() == MidiEventType_NoteOn && m_events[i].NoteVelocity() > 0) - m_notes_remaining--; - } - - else - break; - } -} diff --git a/src/libmidi/MidiTrack.h b/src/libmidi/MidiTrack.h deleted file mode 100644 index fa5f877f..00000000 --- a/src/libmidi/MidiTrack.h +++ /dev/null @@ -1,124 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_TRACK_H -#define __MIDI_TRACK_H - -#include -#include - -#include "Note.h" -#include "MidiEvent.h" -#include "MidiUtil.h" - -class MidiEvent; - -typedef std::vector MidiEventList; -typedef std::vector MidiEventPulsesList; -typedef std::vector MidiEventMicrosecondList; - -class MidiTrack { -public: - static MidiTrack ReadFromStream(std::istream &stream); - static MidiTrack CreateBlankTrack() { - return MidiTrack(); - } - - MidiEventList &Events() { - return m_events; - } - - MidiEventPulsesList &EventPulses() { - return m_event_pulses; - } - - MidiEventMicrosecondList &EventUsecs() { - return m_event_usecs; - } - - const MidiEventList &Events() const { - return m_events; - } - - const MidiEventPulsesList &EventPulses() const { - return m_event_pulses; - } - - const MidiEventMicrosecondList &EventUsecs() const { - return m_event_usecs; - } - - void SetEventUsecs(const MidiEventMicrosecondList &event_usecs) { - m_event_usecs = event_usecs; - } - - const std::string InstrumentName() const { - return InstrumentNames[m_instrument_id]; - } - - bool IsPercussion() const { - return m_instrument_id == InstrumentIdPercussion; - } - - const NoteSet &Notes() const { - return m_note_set; - } - - void SetTrackId(size_t track_id); - - // Reports whether this track contains any Note-On MIDI events - // (vs. just being an information track with a title or copyright) - bool hasNotes() const { - return (m_note_set.size() > 0); - } - - void Reset(); - MidiEventList Update(microseconds_t delta_microseconds); - void GoTo(microseconds_t microsecond_song_position); - - unsigned int AggregateEventsRemain() const { - return static_cast(m_events.size() - (m_last_event + 1)); - } - - unsigned int AggregateEventCount() const { - return static_cast(m_events.size()); - } - - unsigned int AggregateNotesRemain() const { - return m_notes_remaining; - } - - unsigned int AggregateNoteCount() const { - return static_cast(m_note_set.size()); - } - -private: - MidiTrack() : - m_instrument_id(0) { - - Reset(); - } - - void BuildNoteSet(); - void DiscoverInstrument(); - - MidiEventList m_events; - MidiEventPulsesList m_event_pulses; - MidiEventMicrosecondList m_event_usecs; - - NoteSet m_note_set; - - int m_instrument_id; - - microseconds_t m_running_microseconds; - long m_last_event; - - unsigned int m_notes_remaining; -}; - -#endif diff --git a/src/libmidi/MidiTypes.h b/src/libmidi/MidiTypes.h deleted file mode 100644 index 7bf7309f..00000000 --- a/src/libmidi/MidiTypes.h +++ /dev/null @@ -1,15 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_TYPES_H -#define __MIDI_TYPES_H - -typedef long long microseconds_t; - -#endif - diff --git a/src/libmidi/MidiUtil.cpp b/src/libmidi/MidiUtil.cpp deleted file mode 100644 index f6abb425..00000000 --- a/src/libmidi/MidiUtil.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include - -#include "MidiUtil.h" - -using namespace std; - -unsigned long BigToSystem32(unsigned long x) { - return ntohl(x); -} - -unsigned short BigToSystem16(unsigned short x) { - return ntohs(x); -} - -unsigned long parse_variable_length(istream &in) { - register unsigned long value = in.get(); - - if (in.good() && (value & 0x80) ) { - value &= 0x7F; - - register unsigned long c; - do { - c = in.get(); - value = (value << 7) + (c & 0x7F); - } while (in.good() && (c & 0x80) ); - } - - return(value); -} - -string MidiError::GetErrorDescription() const { - switch (m_error) { - case MidiError_UnknownHeaderType: - return "Found an unknown header type.\n\nThis probably isn't a valid MIDI file."; - case MidiError_BadFilename: - return "Could not open file for input. Check that file exists."; - case MidiError_NoHeader: - return "No MIDI header could be read. File too short."; - case MidiError_BadHeaderSize: - return "Incorrect header size."; - case MidiError_Type2MidiNotSupported: - return "Type 2 MIDI is not supported."; - case MidiError_BadType0Midi: - return "Type 0 MIDI should only have 1 track."; - case MidiError_SMTPETimingNotImplemented: - return "MIDI using SMTP time division is not implemented."; - - case MidiError_BadTrackHeaderType: - return "Found an unknown track header type."; - case MidiError_TrackHeaderTooShort: - return "File terminated before reading track header."; - case MidiError_TrackTooShort: - return "Data stream too short to read entire track."; - case MidiError_BadTrackEnd: - return "MIDI track did not end with End-Of-Track event."; - - case MidiError_EventTooShort: - return "Data stream ended before reported end of MIDI event."; - case MidiError_UnknownEventType: - return "Found an unknown MIDI Event Type."; - case MidiError_UnknownMetaEventType: - return "Found an unknown MIDI Meta Event Type."; - - case MidiError_MM_NoDevice: - return "Could not open the specified MIDI device."; - case MidiError_MM_NotEnabled: - return "MIDI device failed enable."; - case MidiError_MM_AlreadyAllocated: - return "The specified MIDI device is already in use."; - case MidiError_MM_BadDeviceID: - return "The MIDI device ID specified is out of range."; - case MidiError_MM_InvalidParameter: - return "An invalid parameter was used with the MIDI device."; - case MidiError_MM_NoDriver: - return "The specified MIDI driver is not installed."; - case MidiError_MM_NoMemory: - return "Cannot allocate or lock memory for MIDI device."; - case MidiError_MM_Unknown: - return "An unknown MIDI I/O error has occurred."; - - case MidiError_NoInputAvailable: - return "Attempted to read MIDI event from an empty input buffer."; - case MidiError_MetaEventOnInput: - return "MIDI Input device sent a Meta Event."; - - case MidiError_InputError: - return "MIDI input driver reported an error."; - case MidiError_InvalidInputErrorBehavior: - return "Invalid InputError value. Choices are 'report', 'ignore', and 'use'."; - - case MidiError_RequestedTempoFromNonTempoEvent: - return "Tempo data was requested from a non-tempo MIDI event."; - - default: - return STRING("Unknown MidiError Code (" << m_error << ")."); - } -} - -string GetMidiEventTypeDescription(MidiEventType type) { - switch (type) { - case MidiEventType_Meta: return "Meta"; - case MidiEventType_SysEx: return "System Exclusive"; - - case MidiEventType_NoteOff: return "Note-Off"; - case MidiEventType_NoteOn: return "Note-On"; - case MidiEventType_Aftertouch: return "Aftertouch"; - case MidiEventType_Controller: return "Controller"; - case MidiEventType_ProgramChange: return "Program Change"; - case MidiEventType_ChannelPressure: return "Channel Pressure"; - case MidiEventType_PitchWheel: return "Pitch Wheel"; - - case MidiEventType_Unknown: return "Unknown"; - default: return "BAD EVENT TYPE"; - } -} - -string GetMidiMetaEventTypeDescription(MidiMetaEventType type) { - switch (type) { - case MidiMetaEvent_SequenceNumber: return "Sequence Number"; - - case MidiMetaEvent_Text: return "Text"; - case MidiMetaEvent_Copyright: return "Copyright"; - case MidiMetaEvent_TrackName: return "Track Name"; - case MidiMetaEvent_Instrument: return "Instrument"; - case MidiMetaEvent_Lyric: return "Lyric"; - case MidiMetaEvent_Marker: return "Marker"; - case MidiMetaEvent_Cue: return "Cue Point"; - case MidiMetaEvent_PatchName: return "Patch Name"; - case MidiMetaEvent_DeviceName: return "Device Name"; - - case MidiMetaEvent_EndOfTrack: return "End Of Track"; - case MidiMetaEvent_TempoChange: return "Tempo Change"; - case MidiMetaEvent_SMPTEOffset: return "SMPTE Offset"; - case MidiMetaEvent_TimeSignature: return "Time Signature"; - case MidiMetaEvent_KeySignature: return "Key Signature"; - - case MidiMetaEvent_Proprietary: return "Proprietary"; - - case MidiMetaEvent_ChannelPrefix: return "(Deprecated) Channel Prefix"; - case MidiMetaEvent_MidiPort: return "(Deprecated) MIDI Port"; - - case MidiMetaEvent_Unknown: return "Unknown Meta Event Type"; - default: return "BAD META EVENT TYPE"; - } -} - -string const InstrumentNames[InstrumentCount] = { - "Acoustic Grand Piano", - "Bright Acoustic Piano", - "Electric Grand Piano", - "Honky-tonk Piano", - "Electric Piano 1", - "Electric Piano 2", - "Harpsichord", - "Clavi", - "Celesta", - "Glockenspiel", - "Music Box", - "Vibraphone", - "Marimba", - "Xylophone", - "Tubular Bells", - "Dulcimer", - "Drawbar Organ", - "Percussive Organ", - "Rock Organ", - "Church Organ", - "Reed Organ", - "Accordion", - "Harmonica", - "Tango Accordion", - "Acoustic Guitar (nylon)", - "Acoustic Guitar (steel)", - "Electric Guitar (jazz)", - "Electric Guitar (clean)", - "Electric Guitar (muted)", - "Overdriven Guitar", - "Distortion Guitar", - "Guitar harmonics", - "Acoustic Bass", - "Electric Bass (finger)", - "Electric Bass (pick)", - "Fretless Bass", - "Slap Bass 1", - "Slap Bass 2", - "Synth Bass 1", - "Synth Bass 2", - "Violin", - "Viola", - "Cello", - "Contrabass", - "Tremolo Strings", - "Pizzicato Strings", - "Orchestral Harp", - "Timpani", - "String Ensemble 1", - "String Ensemble 2", - "SynthStrings 1", - "SynthStrings 2", - "Choir Aahs", - "Voice Oohs", - "Synth Voice", - "Orchestra Hit", - "Trumpet", - "Trombone", - "Tuba", - "Muted Trumpet", - "French Horn", - "Brass Section", - "SynthBrass 1", - "SynthBrass 2", - "Soprano Sax", - "Alto Sax", - "Tenor Sax", - "Baritone Sax", - "Oboe", - "English Horn", - "Bassoon", - "Clarinet", - "Piccolo", - "Flute", - "Recorder", - "Pan Flute", - "Blown Bottle", - "Shakuhachi", - "Whistle", - "Ocarina", - "Lead 1 (square)", - "Lead 2 (sawtooth)", - "Lead 3 (calliope)", - "Lead 4 (chiff)", - "Lead 5 (charang)", - "Lead 6 (voice)", - "Lead 7 (fifths)", - "Lead 8 (bass + lead)", - "Pad 1 (new age)", - "Pad 2 (warm)", - "Pad 3 (polysynth)", - "Pad 4 (choir)", - "Pad 5 (bowed)", - "Pad 6 (metallic)", - "Pad 7 (halo)", - "Pad 8 (sweep)", - "FX 1 (rain)", - "FX 2 (soundtrack)", - "FX 3 (crystal)", - "FX 4 (atmosphere)", - "FX 5 (brightness)", - "FX 6 (goblins)", - "FX 7 (echoes)", - "FX 8 (sci-fi)", - "Sitar", - "Banjo", - "Shamisen", - "Koto", - "Kalimba", - "Bag pipe", - "Fiddle", - "Shanai", - "Tinkle Bell", - "Agogo", - "Steel Drums", - "Woodblock", - "Taiko Drum", - "Melodic Tom", - "Synth Drum", - "Reverse Cymbal", - "Guitar Fret Noise", - "Breath Noise", - "Seashore", - "Bird Tweet", - "Telephone Ring", - "Helicopter", - "Applause", - "Gunshot", - - // - // NOTE: These aren't actually General MIDI instruments! - // - "Percussion", // for Tracks that use Channel 10 or 16 - "Various" // for Tracks that use more than one -}; diff --git a/src/libmidi/MidiUtil.h b/src/libmidi/MidiUtil.h deleted file mode 100644 index 0d130b93..00000000 --- a/src/libmidi/MidiUtil.h +++ /dev/null @@ -1,138 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_UTILS_H -#define __MIDI_UTILS_H - -#include -#include - -// Handy string macros -#ifndef STRING -#include -#define STRING(v) ((static_cast(std::ostringstream().flush() << v)).str()) -#endif - -// Cross-platform Endian conversion functions -// -// MIDI is big endian. Some platforms aren't -unsigned long BigToSystem32(unsigned long x); -unsigned short BigToSystem16(unsigned short x); - -// MIDI contains these wacky variable length numbers where -// the value is stored only in the first 7 bits of each -// byte, and the last bit is a kind of "keep going" flag. -unsigned long parse_variable_length(std::istream &in); - -const static int InstrumentCount = 130; -const static int InstrumentIdVarious = InstrumentCount - 1; -const static int InstrumentIdPercussion = InstrumentCount - 2; -extern std::string const InstrumentNames[InstrumentCount]; - -enum MidiErrorCode { - - MidiError_BadFilename, - MidiError_NoHeader, - MidiError_UnknownHeaderType, - MidiError_BadHeaderSize, - MidiError_Type2MidiNotSupported, - MidiError_BadType0Midi, - MidiError_SMTPETimingNotImplemented, - - MidiError_TrackHeaderTooShort, - MidiError_BadTrackHeaderType, - MidiError_TrackTooShort, - MidiError_BadTrackEnd, - - MidiError_EventTooShort, - MidiError_UnknownEventType, - MidiError_UnknownMetaEventType, - - // MMSYSTEM Errors for MIDI I/O - MidiError_MM_NoDevice, - MidiError_MM_NotEnabled, - MidiError_MM_AlreadyAllocated, - MidiError_MM_BadDeviceID, - MidiError_MM_InvalidParameter, - MidiError_MM_NoDriver, - MidiError_MM_NoMemory, - MidiError_MM_Unknown, - - MidiError_NoInputAvailable, - MidiError_MetaEventOnInput, - - MidiError_InputError, - MidiError_InvalidInputErrorBehavior, - - MidiError_RequestedTempoFromNonTempoEvent -}; - -class MidiError : public std::exception { -public: - MidiError(MidiErrorCode error) : m_error(error) { } - std::string GetErrorDescription() const; - - const MidiErrorCode m_error; - -private: - MidiError operator =(const MidiError&); -}; - -enum MidiEventType { - - MidiEventType_Meta, - MidiEventType_SysEx, - MidiEventType_Unknown, - - MidiEventType_NoteOff, - MidiEventType_NoteOn, - MidiEventType_Aftertouch, - MidiEventType_Controller, - MidiEventType_ProgramChange, - MidiEventType_ChannelPressure, - MidiEventType_PitchWheel -}; - -std::string GetMidiEventTypeDescription(MidiEventType type); - -enum MidiMetaEventType { - - MidiMetaEvent_SequenceNumber = 0x00, - - MidiMetaEvent_Text = 0x01, - MidiMetaEvent_Copyright = 0x02, - MidiMetaEvent_TrackName = 0x03, - MidiMetaEvent_Instrument = 0x04, - MidiMetaEvent_Lyric = 0x05, - MidiMetaEvent_Marker = 0x06, - MidiMetaEvent_Cue = 0x07, - MidiMetaEvent_PatchName = 0x08, - MidiMetaEvent_DeviceName = 0x09, - - MidiMetaEvent_EndOfTrack = 0x2F, - MidiMetaEvent_TempoChange = 0x51, - MidiMetaEvent_SMPTEOffset = 0x54, - MidiMetaEvent_TimeSignature = 0x58, - MidiMetaEvent_KeySignature = 0x59, - - MidiMetaEvent_Proprietary = 0x7F, - - // Deprecated Meta Events - MidiMetaEvent_ChannelPrefix = 0x20, - MidiMetaEvent_MidiPort = 0x21, - - MidiMetaEvent_Unknown = 0xFF -}; - -// Returns a human-readable description of this meta type -// type type of the text ought to contain in -// this event. (e.g. Copyright, Lyric, Track name, etc.) -// (If this isn't a meta event, returns an empty string) -std::string GetMidiMetaEventTypeDescription(MidiMetaEventType type); - -#endif diff --git a/src/libmidi/Note.h b/src/libmidi/Note.h deleted file mode 100644 index 2b6d6f2c..00000000 --- a/src/libmidi/Note.h +++ /dev/null @@ -1,73 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#ifndef __MIDI_NOTE_H -#define __MIDI_NOTE_H - -#include -#include "MidiTypes.h" - -// Range of all 128 MIDI notes possible -typedef unsigned int NoteId; - -// Arbitrary value outside the usual range -const static NoteId InvalidNoteId = 2048; - -enum NoteState { - - AutoPlayed, - UserPlayable, - UserHit, - UserMissed -}; - -template -struct GenericNote { - - bool operator()(const GenericNote &lhs, const GenericNote &rhs) const { - if (lhs.start < rhs.start) return true; - if (lhs.start > rhs.start) return false; - - if (lhs.end < rhs.end) return true; - if (lhs.end > rhs.end) return false; - - if (lhs.note_id < rhs.note_id) return true; - if (lhs.note_id > rhs.note_id) return false; - - if (lhs.track_id < rhs.track_id) return true; - if (lhs.track_id > rhs.track_id) return false; - - return false; - } - - T start; - T end; - NoteId note_id; - size_t track_id; - - // We have to drag a little extra info around so we can - // play the user's input correctly - unsigned char channel; - int velocity; - - NoteState state; - // State before retry (last try) - NoteState retry_state; -}; - -// Note keeps the internal pulses found in the MIDI file which are -// independent of tempo or playback speed. TranslatedNote contains -// the exact (translated) microsecond that notes start and stop on -// based on a given playback speed, after dereferencing tempo changes. -typedef GenericNote Note; -typedef GenericNote TranslatedNote; - -typedef std::set NoteSet; -typedef std::set TranslatedNoteSet; - -#endif diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 02b1c397..00000000 --- a/src/main.cpp +++ /dev/null @@ -1,527 +0,0 @@ -// -*- mode: c++; coding: utf-8 -*- - -// Linthesia - -// Copyright (c) 2007 Nicholas Piegdon -// Adaptation to GNU/Linux by Oscar Aceña -// See COPYING for license information - -#include - -#include "OSGraphics.h" -#include "StringUtil.h" -#include "FileSelector.h" -#include "UserSettings.h" -#include "Version.h" -#include "CompatibleSystem.h" -#include "LinthesiaError.h" -#include "Tga.h" -#include "Renderer.h" -#include "SharedState.h" -#include "GameState.h" -#include "TitleState.h" -#include "DpmsThread.h" - -#include "libmidi/Midi.h" -#include "libmidi/MidiUtil.h" -#include - -#ifndef GRAPHDIR -#define GRAPHDIR "../graphics" -#endif - -using namespace std; - -GameStateManager* state_manager; - -const static string application_name = "Neothesia"; -const static string friendly_app_name = STRING("Neothesia " << - NeothesiaVersionString); - -const static string error_header1 = "Neothesia detected a"; -const static string error_header2 = " problem and must close:\n\n"; -const static string error_footer = "\n\n Error )-: "; - -class EdgeTracker { -public: - - EdgeTracker() : - active(true), - just_active(true) { - } - - void Activate() { - just_active = true; - active = true; - } - - void Deactivate() { - just_active = false; - active = false; - } - - bool IsActive() { - return active; - } - - bool JustActivated() { - bool was_active = just_active; - just_active = false; - return was_active; - } - -private: - bool active; - bool just_active; -}; - -static EdgeTracker window_state; - -class DrawingArea : public Gtk::GL::DrawingArea { -public: - - DrawingArea(const Glib::RefPtr& config) : - Gtk::GL::DrawingArea(config) { - - set_events(Gdk::POINTER_MOTION_MASK | - Gdk::BUTTON_PRESS_MASK | - Gdk::BUTTON_RELEASE_MASK | - Gdk::KEY_PRESS_MASK | - Gdk::KEY_RELEASE_MASK); - - set_can_focus(); - - signal_motion_notify_event().connect(sigc::mem_fun(*this, &DrawingArea::on_motion_notify)); - signal_button_press_event().connect(sigc::mem_fun(*this, &DrawingArea::on_button_press)); - signal_button_release_event().connect(sigc::mem_fun(*this, &DrawingArea::on_button_press)); - signal_key_press_event().connect(sigc::mem_fun(*this, &DrawingArea::on_key_press)); - signal_key_release_event().connect(sigc::mem_fun(*this, &DrawingArea::on_key_release)); - } - - bool GameLoop(); - -protected: - virtual void on_realize(); - virtual bool on_configure_event(GdkEventConfigure* event); - virtual bool on_expose_event(GdkEventExpose* event); - - virtual bool on_motion_notify(GdkEventMotion* event); - virtual bool on_button_press(GdkEventButton* event); - virtual bool on_key_press(GdkEventKey* event); - virtual bool on_key_release(GdkEventKey* event); -}; - -bool DrawingArea::on_motion_notify(GdkEventMotion* event) { - - state_manager->MouseMove(event->x, event->y); - return true; -} - -bool DrawingArea::on_button_press(GdkEventButton* event) { - - MouseButton b; - - // left and right click allowed - if (event->button == 1) - b = MouseLeft; - else if (event->button == 3) - b = MouseRight; - - // ignore other buttons - else - return false; - - // press or release? - if (event->type == GDK_BUTTON_PRESS) - state_manager->MousePress(b); - else if (event->type == GDK_BUTTON_RELEASE) - state_manager->MouseRelease(b); - else - return false; - - return true; -} - -// FIXME: use user settings to do this mapping -int keyToNote(GdkEventKey* event) { - const unsigned short oct = 4; - - switch(event->keyval) { - /* no key for C :( */ - case GDK_masculine: return 12*oct + 1; /* C# */ - case GDK_Tab: return 12*oct + 2; /* D */ - case GDK_1: return 12*oct + 3; /* D# */ - case GDK_q: return 12*oct + 4; /* E */ - case GDK_w: return 12*oct + 5; /* F */ - case GDK_3: return 12*oct + 6; /* F# */ - case GDK_e: return 12*oct + 7; /* G */ - case GDK_4: return 12*oct + 8; /* G# */ - case GDK_r: return 12*oct + 9; /* A */ - case GDK_5: return 12*oct + 10; /* A# */ - case GDK_t: return 12*oct + 11; /* B */ - - case GDK_y: return 12*(oct+1) + 0; /* C */ - case GDK_7: return 12*(oct+1) + 1; /* C# */ - case GDK_u: return 12*(oct+1) + 2; /* D */ - case GDK_8: return 12*(oct+1) + 3; /* D# */ - case GDK_i: return 12*(oct+1) + 4; /* E */ - case GDK_o: return 12*(oct+1) + 5; /* F */ - case GDK_0: return 12*(oct+1) + 6; /* F# */ - case GDK_p: return 12*(oct+1) + 7; /* G */ - case GDK_apostrophe: return 12*(oct+1) + 8; /* G# */ - case GDK_dead_grave: return 12*(oct+1) + 9; /* A */ - case GDK_exclamdown: return 12*(oct+1) + 10; /* A# */ - case GDK_plus: return 12*(oct+1) + 11; /* B */ - } - - return -1; -} - -typedef map ConnectMap; -ConnectMap pressed; - -bool __sendNoteOff(int note) { - - ConnectMap::iterator it = pressed.find(note); - if (it == pressed.end()) - return false; - - sendNote(note, false); - pressed.erase(it); - - return true; -} - -bool DrawingArea::on_key_press(GdkEventKey* event) { - - // if is a note... - int note = keyToNote(event); - if (note >= 0) { - - // if first press, send Note-On - ConnectMap::iterator it = pressed.find(note); - if (it == pressed.end()) - sendNote(note, true); - - // otherwise, cancel emission of Note-off - else - it->second.disconnect(); - - return true; - } - - switch (event->keyval) { - case GDK_Up: state_manager->KeyPress(KeyUp); break; - case GDK_Down: state_manager->KeyPress(KeyDown); break; - case GDK_Left: state_manager->KeyPress(KeyLeft); break; - case GDK_Right: state_manager->KeyPress(KeyRight); break; - case GDK_space: state_manager->KeyPress(KeySpace); break; - case GDK_Return: state_manager->KeyPress(KeyEnter); break; - case GDK_Escape: state_manager->KeyPress(KeyEscape); break; - - // show FPS - case GDK_F6: state_manager->KeyPress(KeyF6); break; - - // increase/decrease octave - case GDK_greater: state_manager->KeyPress(KeyGreater); break; - case GDK_less: state_manager->KeyPress(KeyLess); break; - - // +/- 5 seconds - case GDK_Page_Down:state_manager->KeyPress(KeyForward); break; - case GDK_Page_Up: state_manager->KeyPress(KeyBackward); break; - - case GDK_bracketleft: state_manager->KeyPress(KeyVolumeDown); break; // [ - case GDK_bracketright: state_manager->KeyPress(KeyVolumeUp); break; // ] - - default: - return false; - } - - return true; -} - -bool DrawingArea::on_key_release(GdkEventKey* event) { - - // if is a note... - int note = keyToNote(event); - if (note >= 0) { - - // setup a timeout with Note-Off - pressed[note] = Glib::signal_timeout().connect( - sigc::bind(sigc::ptr_fun(&__sendNoteOff), note), 20); - return true; - } - - return false; -} - -void DrawingArea::on_realize() { - // we need to call the base on_realize() - Gtk::GL::DrawingArea::on_realize(); - - Glib::RefPtr glwindow = get_gl_window(); - if (!glwindow->gl_begin(get_gl_context())) - return; - - glwindow->gl_end(); -} - -bool DrawingArea::on_configure_event(GdkEventConfigure* event) { - - Glib::RefPtr glwindow = get_gl_window(); - if (!glwindow->gl_begin(get_gl_context())) - return false; - - glClearColor(.25, .25, .25, 1.0); - glClearDepth(1.0); - - glDisable(GL_DEPTH_TEST); - glEnable(GL_TEXTURE_2D); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - - glShadeModel(GL_SMOOTH); - - glViewport(0, 0, get_width(), get_height()); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(0, get_width(), 0, get_height()); - - state_manager->Update(window_state.JustActivated()); - - glwindow->gl_end(); - return true; -} - -bool DrawingArea::on_expose_event(GdkEventExpose* event) { - - Glib::RefPtr glwindow = get_gl_window(); - if (!glwindow->gl_begin(get_gl_context())) - return false; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glCallList(1); - - Renderer rend(get_gl_context(), get_pango_context()); - rend.SetVSyncInterval(1); - state_manager->Draw(rend); - - // swap buffers. - if (glwindow->is_double_buffered()) - glwindow->swap_buffers(); - else - glFlush(); - - glwindow->gl_end(); - return true; -} - -bool DrawingArea::GameLoop() { - - if (window_state.IsActive()) { - - state_manager->Update(window_state.JustActivated()); - - Renderer rend(get_gl_context(), get_pango_context()); - rend.SetVSyncInterval(1); - - state_manager->Draw(rend); - } - - return true; -} - -int main(int argc, char *argv[]) { - Gtk::Main main_loop(argc, argv); - Gtk::GL::init(argc, argv); - - state_manager = new GameStateManager( - Compatible::GetDisplayWidth(), - Compatible::GetDisplayHeight() - ); - - try { - string command_line(""); - - UserSetting::Initialize(application_name); - - if (argc > 1) - command_line = string(argv[1]); - - // strip any leading or trailing quotes from the filename - // argument (to match the format returned by the open-file - // dialog later). - if (command_line.length() > 0 && - command_line[0] == '\"') - command_line = command_line.substr(1, command_line.length() - 1); - - if (command_line.length() > 0 && - command_line[command_line.length()-1] == '\"') - command_line = command_line.substr(0, command_line.length() - 1); - - Midi *midi = 0; - - // attempt to open the midi file given on the command line first - if (command_line != "") { - try { - midi = new Midi(Midi::ReadFromFile(command_line)); - } - - catch (const MidiError &e) { - string wrapped_description = STRING("Problem while loading file: " << - command_line << - "\n") + e.GetErrorDescription(); - Compatible::ShowError(wrapped_description); - - command_line = ""; - midi = 0; - } - } - - // if midi couldn't be opened from command line filename or there - // simply was no command line filename, use a "file open" dialog. - if (command_line == "") { - while (!midi) { - string file_title; - FileSelector::RequestMidiFilename(&command_line, &file_title); - - if (command_line != "") { - try { - midi = new Midi(Midi::ReadFromFile(command_line)); - } - catch (const MidiError &e) { - string wrapped_description = \ - STRING("Problem while loading file: " << - file_title << - "\n") + e.GetErrorDescription(); - Compatible::ShowError(wrapped_description); - - midi = 0; - } - } - - else { - // they pressed cancel, so they must not want to run - // the app anymore. - return 0; - } - } - } - - Glib::RefPtr glconfig; - - // try double-buffered visual - glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB | - Gdk::GL::MODE_DEPTH | - Gdk::GL::MODE_DOUBLE); - if (!glconfig) { - cerr << "*** Cannot find the double-buffered visual.\n" - << "*** Trying single-buffered visual.\n"; - - // try single-buffered visual - glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB | - Gdk::GL::MODE_DEPTH); - if (!glconfig) { - string description = STRING(error_header1 << - " OpenGL" << - error_header2 << - "Cannot find any OpenGL-capable visual." << - error_footer); - Compatible::ShowError(description); - return 1; - } - } - - Gtk::Window window; - DrawingArea da(glconfig); - window.add(da); - window.show_all(); - window.move(Compatible::GetDisplayLeft() + Compatible::GetDisplayWidth()/2, Compatible::GetDisplayTop() + Compatible::GetDisplayHeight()/2); - - - // Init DHMS thread once for the whole program - DpmsThread* dpms_thread = new DpmsThread(); - - // do this after gl context is created (ie. after da realized) - SharedState state; - state.song_title = FileSelector::TrimFilename(command_line); - state.midi = midi; - state.dpms_thread = dpms_thread; - state_manager->SetInitialState(new TitleState(state)); - - window.fullscreen(); - window.set_title(friendly_app_name); - - window.set_icon_from_file(string(GRAPHDIR) + "/app_icon.ico"); - - // get refresh rate from user settings - string key = "refresh_rate"; - int rate = 65; - string user_rate = UserSetting::Get(key, ""); - if (user_rate.empty()) { - user_rate = STRING(rate); - UserSetting::Set(key, user_rate); - } - - else { - istringstream iss(user_rate); - if (not (iss >> rate)) { - Compatible::ShowError("Invalid setting for '"+ key +"' key.\n\nReset to default value when reload."); - UserSetting::Set(key, ""); - } - } - - Glib::signal_timeout().connect(sigc::mem_fun(da, &DrawingArea::GameLoop), 1000/rate); - - main_loop.run(window); - window_state.Deactivate(); - - delete dpms_thread; - - return 0; - } - - catch (const LinthesiaError &e) { - string wrapped_description = STRING(error_header1 << - error_header2 << - e.GetErrorDescription() << - error_footer); - Compatible::ShowError(wrapped_description); - } - - catch (const MidiError &e) { - string wrapped_description = STRING(error_header1 << - " MIDI" << - error_header2 << - e.GetErrorDescription() << - error_footer); - Compatible::ShowError(wrapped_description); - } - - catch (const Gnome::Conf::Error& e) { - string wrapped_description = STRING(error_header1 << - " Gnome::Conf::Error" << - error_header2 << - e.what() << - error_footer); - Compatible::ShowError(wrapped_description); - } - - catch (const exception &e) { - string wrapped_description = STRING("Linthesia detected an unknown " - "problem and must close! '" << - e.what() << "'" << error_footer); - Compatible::ShowError(wrapped_description); - } - - catch (...) { - string wrapped_description = STRING("Linthesia detected an unknown " - "problem and must close!" << - error_footer); - Compatible::ShowError(wrapped_description); - } - - return 1; -} - diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..e5f34776 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,268 @@ +mod wgpu_jumpstart; +use wgpu_jumpstart::{Gpu, Uniform, Window}; + +mod ui; +use ui::Ui; + +mod scene; +use scene::{Scene, SceneType}; + +mod time_menager; +use time_menager::TimeMenager; + +mod midi_device; + +mod transform_uniform; +use transform_uniform::TransformUniform; + +#[cfg(target_arch = "wasm32")] +mod web_wrappers; + +use wgpu_glyph::Section; +use winit::{ + event::{Event, VirtualKeyCode, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, +}; + +mod rectangle_pipeline; + +pub struct MainState { + pub window_size: (f32, f32), + pub mouse_pos: (f32, f32), + /// Mouse Was Clicked This Frame + pub mouse_clicked: bool, + /// Mouse Is Pressed This Frame + pub mouse_pressed: bool, + pub time_menager: TimeMenager, + pub transform_uniform: Uniform, +} + +impl MainState { + fn new(gpu: &Gpu) -> Self { + Self { + window_size: (0.0, 0.0), + mouse_pos: (0.0, 0.0), + mouse_clicked: false, + mouse_pressed: false, + time_menager: TimeMenager::new(), + transform_uniform: Uniform::new( + &gpu.device, + TransformUniform::default(), + wgpu::ShaderStage::VERTEX, + ), + } + } + fn resize(&mut self, gpu: &mut Gpu, w: f32, h: f32) { + self.window_size = (w, h); + self.transform_uniform.data.update(w, h); + self.transform_uniform.update(&mut gpu.encoder, &gpu.device); + } + fn update_mouse_pos(&mut self, x: f32, y: f32) { + self.mouse_pos = (x, y); + } + fn update_mouse_pressed(&mut self, state: bool) { + self.mouse_pressed = state; + + if state { + self.update_mouse_clicked(true); + } + } + fn update_mouse_clicked(&mut self, clicked: bool) { + self.mouse_clicked = clicked; + } +} + +struct App<'a> { + pub window: Window, + pub gpu: Gpu, + pub ui: Ui<'a>, + pub main_state: MainState, + game_scene: Box, +} + +impl<'a> App<'a> { + fn new(mut gpu: Gpu, window: Window) -> Self { + let mut main_state = MainState::new(&gpu); + + let ui = Ui::new(&main_state, &mut gpu); + let game_scene: Box = + Box::new(scene::menu_scene::MenuScene::new(&mut gpu, &mut main_state)); + + Self { + window, + gpu, + ui, + main_state, + game_scene, + } + } + fn resize(&mut self) { + self.window + .surface + .resize(&mut self.gpu, self.window.physical_size()); + + let (w, h) = self.window.size(); + + self.main_state.resize(&mut self.gpu, w, h); + self.game_scene.resize(&mut self.main_state, &mut self.gpu); + self.ui.resize(&self.main_state, &mut self.gpu); + } + fn go_back(&mut self, control_flow: &mut ControlFlow) { + match self.game_scene.state_type() { + SceneType::MainMenu => { + *control_flow = ControlFlow::Exit; + } + SceneType::Playing => { + let mut state = + scene::menu_scene::MenuScene::new(&mut self.gpu, &mut self.main_state); + state.resize(&mut self.main_state, &mut self.gpu); + + self.game_scene = Box::new(state); + } + } + } + fn key_released(&mut self, key: VirtualKeyCode) { + self.game_scene.key_released(&mut self.main_state, key); + } + fn render_fps(&mut self) { + self.ui.queue_text(Section { + text: &format!("FPS: {}", self.main_state.time_menager.fps()), + color: [1.0, 1.0, 1.0, 1.0], + screen_position: (0.0, 5.0), + scale: wgpu_glyph::Scale::uniform(20.0), + layout: wgpu_glyph::Layout::Wrap { + line_breaker: Default::default(), + h_align: wgpu_glyph::HorizontalAlign::Left, + v_align: wgpu_glyph::VerticalAlign::Top, + }, + ..Default::default() + }); + } + fn clear(&mut self, frame: &wgpu::SwapChainOutput) { + self.gpu + .encoder + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }, + }], + depth_stencil_attachment: None, + }); + } + fn render(&mut self) { + self.main_state.time_menager.update(); + + let frame = self.window.surface.get_next_texture(); + + self.clear(&frame); + + let event = self + .game_scene + .update(&mut self.main_state, &mut self.gpu, &mut self.ui); + + match event { + scene::SceneEvent::MainMenu(event) => match event { + scene::menu_scene::Event::MidiOpen(midi, port) => { + let mut state = scene::playing_scene::PlayingScene::new( + &mut self.gpu, + &mut self.main_state, + midi, + port, + ); + state.resize(&mut self.main_state, &mut self.gpu); + + self.game_scene = Box::new(state); + } + }, + _ => {} + } + + self.game_scene + .render(&mut self.main_state, &mut self.gpu, &frame); + + self.render_fps(); + + self.ui.render(&mut self.main_state, &mut self.gpu, &frame); + + self.gpu.submit(); + + self.main_state.update_mouse_clicked(false); + } +} + +async fn main_async() { + let event_loop = EventLoop::new(); + + let builder = winit::window::WindowBuilder::new().with_title("Neothesia"); + let (window, gpu) = Window::new(builder, (1080, 720), &event_loop).await; + let mut app = App::new(gpu, window); + app.resize(); + app.gpu.submit(); + + event_loop.run(move |event, _, mut control_flow| match &event { + Event::MainEventsCleared => app.window.request_redraw(), + Event::WindowEvent { event, .. } => match event { + WindowEvent::Resized(_) => { + app.resize(); + app.gpu.submit(); + } + WindowEvent::CursorMoved { position, .. } => { + let dpi = &app.window.dpi; + let x = (position.x / dpi).round(); + let y = (position.y / dpi).round(); + + app.main_state.update_mouse_pos(x as f32, y as f32); + } + WindowEvent::MouseInput { state, .. } => { + if let winit::event::ElementState::Pressed = state { + app.main_state.update_mouse_pressed(true); + } else { + app.main_state.update_mouse_pressed(false); + } + } + WindowEvent::KeyboardInput { input, .. } => { + if input.state == winit::event::ElementState::Released { + match input.virtual_keycode { + Some(winit::event::VirtualKeyCode::Escape) => { + app.go_back(&mut control_flow); + } + Some(key) => { + app.key_released(key); + } + _ => {} + } + } + } + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + _ => {} + }, + Event::RedrawRequested(_) => { + app.render(); + } + _ => {} + }); +} + +fn main() { + #[cfg(not(target_arch = "wasm32"))] + { + env_logger::init(); + futures::executor::block_on(main_async()); + } + + #[cfg(target_arch = "wasm32")] + { + console_log::init().expect("could not initialize logger"); + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + + wasm_bindgen_futures::spawn_local(main_async()); + } +} diff --git a/src/midi_device/devices_menager.rs b/src/midi_device/devices_menager.rs new file mode 100644 index 00000000..3328096b --- /dev/null +++ b/src/midi_device/devices_menager.rs @@ -0,0 +1,100 @@ +use midir::{ + MidiInput, MidiInputConnection, MidiInputPort, MidiOutput, MidiOutputConnection, MidiOutputPort, +}; + +pub struct MidiDevicesMenager { + midi_out: Option, + // midi_in: Option, + midi_out_c: Option, + // midi_in_c: Option, +} + +impl MidiDevicesMenager { + pub fn new() -> Self { + let midi_out = MidiOutput::new("midi_out").ok(); + // let midi_in = MidiInput::new("midi_in").ok(); + + Self { + midi_out, + // midi_in, + midi_out_c: None, + // midi_in_c: None, + } + } + pub fn get_outs(&self) -> Vec { + match &self.midi_out { + Some(midi_out) => { + let mut outs = Vec::new(); + let ports = midi_out.ports(); + for p in ports { + let name = match midi_out.port_name(&p).ok() { + Some(name) => name, + None => String::from("Unknown"), + }; + outs.push(MidiPortInfo { port: p, name }) + } + outs + } + None => Vec::new(), + } + } + // pub fn get_ins(&self) -> Vec { + // match &self.midi_in { + // Some(midi_in) => { + // let mut ins = Vec::new(); + // let ports = midi_in.ports(); + + // for p in ports { + // // for i in 0..midi_in.port_count() { + // let name = match midi_in.port_name(&p).ok() { + // Some(name) => name, + // None => String::from("Unknown"), + // }; + // ins.push(MidiPortInfo { + // port: MidiPort::Input(p), + // name, + // }) + // } + // ins + // } + // None => Vec::new(), + // } + // } + pub fn connect_out(&mut self, port: MidiPortInfo) { + let midi_out = MidiOutput::new("midi_out").ok(); + + if let Some(midi_out) = midi_out { + self.midi_out_c = midi_out.connect(&port.port, "out").ok(); + } + } + pub fn send(&mut self, message: &[u8]) { + let _res = match &mut self.midi_out_c { + Some(out) => out.send(message), + None => Ok(()), + }; + } +} + +// pub enum MidiPort { +// Output(MidiOutputPort), +// Input(MidiInputPort), +// } +// impl std::fmt::Debug for MidiPort { +// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { +// match self { +// Self::Output(_) => write!(f, "Output"), +// Self::Input(_) => write!(f, "Input"), +// } +// } +// } + +pub struct MidiPortInfo { + pub port: MidiOutputPort, + pub name: String, +} + +impl std::fmt::Debug for MidiPortInfo { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} diff --git a/src/midi_device/mod.rs b/src/midi_device/mod.rs new file mode 100644 index 00000000..ba298f5a --- /dev/null +++ b/src/midi_device/mod.rs @@ -0,0 +1,4 @@ +#[allow(dead_code)] +mod devices_menager; +pub use devices_menager::MidiDevicesMenager; +pub use devices_menager::MidiPortInfo; diff --git a/src/neolib/GLShader.cpp b/src/neolib/GLShader.cpp deleted file mode 100644 index dfc9f931..00000000 --- a/src/neolib/GLShader.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "GLShader.h" - -#include -#include -#include -#include -#include - -GLuint LoadShader(std::string vert,std::string frag) { - GLuint vertShader = glCreateShader(GL_VERTEX_SHADER); - GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); - - const char *vertShaderSrc = vert.c_str(); - const char *fragShaderSrc = frag.c_str(); - - GLint result = GL_FALSE; - int logLength; - - // Compile - glShaderSource(vertShader, 1, &vertShaderSrc, NULL); - glCompileShader(vertShader); - - // Check - glGetShaderiv(vertShader, GL_COMPILE_STATUS, &result); - glGetShaderiv(vertShader, GL_INFO_LOG_LENGTH, &logLength); - std::vector vertShaderError((logLength > 1) ? logLength : 1); - glGetShaderInfoLog(vertShader, logLength, NULL, &vertShaderError[0]); - std::cout << &vertShaderError[0] << std::endl; - - // Compile - glShaderSource(fragShader, 1, &fragShaderSrc, NULL); - glCompileShader(fragShader); - - // Check - glGetShaderiv(fragShader, GL_COMPILE_STATUS, &result); - glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength); - std::vector fragShaderError((logLength > 1) ? logLength : 1); - glGetShaderInfoLog(fragShader, logLength, NULL, &fragShaderError[0]); - std::cout << &fragShaderError[0] << std::endl; - - // Link - GLuint program = glCreateProgram(); - glAttachShader(program, vertShader); - glAttachShader(program, fragShader); - glLinkProgram(program); - - // Check - glGetProgramiv(program, GL_LINK_STATUS, &result); - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); - std::vector programError( (logLength > 1) ? logLength : 1 ); - glGetProgramInfoLog(program, logLength, NULL, &programError[0]); - std::cout << &programError[0] << std::endl; - - // Delete - glDeleteShader(vertShader); - glDeleteShader(fragShader); - - return program; -} \ No newline at end of file diff --git a/src/neolib/GLShader.h b/src/neolib/GLShader.h deleted file mode 100644 index f7d58abd..00000000 --- a/src/neolib/GLShader.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef GLSHADER_H -#define GLSHADER_H - -#include "OSGraphics.h" -#include - -GLuint LoadShader(std::string vert,std::string frag); - -#endif \ No newline at end of file diff --git a/src/neolib/NeoFBO.cpp b/src/neolib/NeoFBO.cpp deleted file mode 100644 index afaeb235..00000000 --- a/src/neolib/NeoFBO.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "NeoFBO.h" - -NeoFBO::NeoFBO(int width_, int height_) : width(width_),height(height_){ - glGenFramebuffers(1, &FboId); - glBindFramebuffer(GL_FRAMEBUFFER, FboId); - - glGenTextures(1, &TextureId); - glBindTexture(GL_TEXTURE_2D, TextureId); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glFramebufferTexture(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,TextureId,0); - - GLenum drawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - glDrawBuffers(1, drawBuffers); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void NeoFBO::Bind(){ - glBindFramebuffer(GL_FRAMEBUFFER, FboId); -} - -void NeoFBO::Unbind(){ - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} \ No newline at end of file diff --git a/src/neolib/NeoFBO.h b/src/neolib/NeoFBO.h deleted file mode 100644 index 032408fe..00000000 --- a/src/neolib/NeoFBO.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __NEOFBO_H -#define __NEOFBO_H - -#include "OSGraphics.h" - -class NeoFBO { - -public: - NeoFBO(int width_, int height_); - - void Bind(); - void Unbind(); - - GLuint GetTexture() { return TextureId; } -private: - GLuint FboId; - GLuint TextureId; - - int width; - int height; -}; - -#endif \ No newline at end of file diff --git a/src/neolib/ParticleSystem.cpp b/src/neolib/ParticleSystem.cpp deleted file mode 100644 index 584f72e2..00000000 --- a/src/neolib/ParticleSystem.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "ParticleSystem.h" -#include "Renderer.h" - -ParticleSystem::ParticleSystem() {} - -void ParticleSystem::RemoveParticles(){ - particleArr.clear(); -}; - -void ParticleSystem::SpawnParticle(float x1, float y1, Color c1) { - Particle p(x1, y1, c1); - particleArr.push_back(p); -} - -void ParticleSystem::DrawParticles(Renderer &renderer) { - glBindTexture(GL_TEXTURE_2D, 0); - for (int i = 0; i < particleArr.size(); i++) { - particleArr[i].Draw(renderer); - } -} - -void ParticleSystem::UpdateParticles() { - for (int i = 0; i < particleArr.size(); i++) { - particleArr[i].Update(particleArr); - } -} - -Particle::Particle(float x1, float y1, Color c1) : x(x1), y(y1), c(c1) { - ax = 0.01; - ay = -0.005; - - vx = (static_cast(rand()) / static_cast(RAND_MAX)) * 2 - 1; - vy = -(static_cast(rand()) / static_cast(RAND_MAX)) * 2; - - c.r-=50; - c.g-=50; - c.b-=50; -} - -void Particle::Update(std::vector &pa) { - vx += ax; - vy += ay; - - x += vx; - y += vy; - - alpha -= 1; - - if (alpha < 0) { - if (pa.empty()) - return; - pa.erase(pa.begin()); - } -} - -void Particle::Draw(Renderer &renderer) { - c.a = alpha; - renderer.SetColor(c); - renderer.DrawQuad(x, y, 2, 2); -} \ No newline at end of file diff --git a/src/neolib/ParticleSystem.h b/src/neolib/ParticleSystem.h deleted file mode 100644 index e54e92eb..00000000 --- a/src/neolib/ParticleSystem.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __NEOPARTICLESYSTEM_H -#define __NEOPARTICLESYSTEM_H - -#include "Renderer.h" - -class Particle { -public: - Particle(float x1, float y1, Color c1); - void Update(std::vector &particleArr); - void Draw(Renderer &renderer); - -private: - float x, y; - float alpha = 255; - float vx, vy; - float ax; - float ay; - Color c; -}; - - - -class ParticleSystem -{ -private: - std::vector particleArr; -public: - ParticleSystem(); - void UpdateParticles(); - void RemoveParticles(); - void DrawParticles(Renderer &renderer); - void SpawnParticle(float x1, float y1, Color c1); -}; - - - -#endif \ No newline at end of file diff --git a/src/rectangle_pipeline/instance_data.rs b/src/rectangle_pipeline/instance_data.rs new file mode 100644 index 00000000..91d79fb6 --- /dev/null +++ b/src/rectangle_pipeline/instance_data.rs @@ -0,0 +1,20 @@ +use wgpu::vertex_attr_array; + +use zerocopy::AsBytes; + +#[repr(C)] +#[derive(Debug, Copy, Clone, AsBytes, PartialEq)] +pub struct RectangleInstance { + pub position: [f32; 2], + pub size: [f32; 2], + pub color: [f32; 4], +} +impl RectangleInstance { + pub fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> { + wgpu::VertexBufferDescriptor { + stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &vertex_attr_array!(1 => Float2,2 => Float2,3 => Float4), + } + } +} diff --git a/src/rectangle_pipeline/mod.rs b/src/rectangle_pipeline/mod.rs new file mode 100644 index 00000000..d35a2fc0 --- /dev/null +++ b/src/rectangle_pipeline/mod.rs @@ -0,0 +1,6 @@ +mod instance_data; + +mod rectangle_pipeline; + +pub use instance_data::RectangleInstance; +pub use rectangle_pipeline::RectanglePipeline; diff --git a/src/rectangle_pipeline/rectangle_pipeline.rs b/src/rectangle_pipeline/rectangle_pipeline.rs new file mode 100644 index 00000000..c1434812 --- /dev/null +++ b/src/rectangle_pipeline/rectangle_pipeline.rs @@ -0,0 +1,66 @@ +use super::RectangleInstance; + +use crate::wgpu_jumpstart::{shader, Instances, RenderPipelineBuilder, SimpleQuad}; + +use crate::MainState; + +pub struct RectanglePipeline { + render_pipeline: wgpu::RenderPipeline, + + simple_quad: SimpleQuad, + + instances: Instances, +} + +impl<'a> RectanglePipeline { + pub fn new(state: &MainState, device: &wgpu::Device) -> Self { + let vs_module = shader::create_module(device, include_bytes!("shader/quad.vert.spv")); + let fs_module = shader::create_module(device, include_bytes!("shader/quad.frag.spv")); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&state.transform_uniform.bind_group_layout], + }); + + let render_pipeline = RenderPipelineBuilder::new(&render_pipeline_layout, &vs_module) + .fragment_stage(&fs_module) + .vertex_buffers(&[ + SimpleQuad::vertex_buffer_descriptor(), + RectangleInstance::desc(), + ]) + .build(device); + + let simple_quad = SimpleQuad::new(device); + let instances = Instances::new(device, 100_000); + + Self { + render_pipeline, + + simple_quad, + + instances, + } + } + pub fn render(&'a self, state: &'a MainState, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &state.transform_uniform.bind_group, &[]); + + render_pass.set_vertex_buffer(0, &self.simple_quad.vertex_buffer, 0, 0); + render_pass.set_vertex_buffer(1, &self.instances.buffer, 0, 0); + + render_pass.set_index_buffer(&self.simple_quad.index_buffer, 0, 0); + + render_pass.draw_indexed(0..SimpleQuad::indices_len(), 0, 0..self.instances.len()); + } + pub fn update_instance_buffer( + &mut self, + command_encoder: &mut wgpu::CommandEncoder, + device: &wgpu::Device, + instances: Vec, + ) { + if self.instances.data != instances { + self.instances.data = instances; + self.instances.update(command_encoder, device); + } + } +} diff --git a/src/rectangle_pipeline/shader/quad.frag b/src/rectangle_pipeline/shader/quad.frag new file mode 100644 index 00000000..7bfecc90 --- /dev/null +++ b/src/rectangle_pipeline/shader/quad.frag @@ -0,0 +1,10 @@ +#version 450 + + +layout(location=0) in vec4 color; + +layout(location=0) out vec4 f_color; + +void main() { + f_color = color; +} \ No newline at end of file diff --git a/src/rectangle_pipeline/shader/quad.frag.spv b/src/rectangle_pipeline/shader/quad.frag.spv new file mode 100644 index 00000000..fe52ae4e Binary files /dev/null and b/src/rectangle_pipeline/shader/quad.frag.spv differ diff --git a/src/rectangle_pipeline/shader/quad.vert b/src/rectangle_pipeline/shader/quad.vert new file mode 100644 index 00000000..324cf53f --- /dev/null +++ b/src/rectangle_pipeline/shader/quad.vert @@ -0,0 +1,28 @@ +#version 450 + +layout(location=0) in vec2 a_position; + +layout(location=1) in vec2 i_pos; +layout(location=2) in vec2 i_size; +layout(location=3) in vec4 i_color; + +layout(location=0) out vec4 color; + +layout(set=0, binding=0) +uniform Uniforms { + mat4 u_Transform; +}; + +void main() { + color = i_color; + + mat4 i_Transform = mat4( + vec4(0.5*i_size.x, 0.0, 0.0, 0.0), + vec4(0.0, 0.5*i_size.y, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(i_pos, 0.0, 1.0) + ); + + + gl_Position = u_Transform * i_Transform * vec4(a_position, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/rectangle_pipeline/shader/quad.vert.spv b/src/rectangle_pipeline/shader/quad.vert.spv new file mode 100644 index 00000000..bb5e6cf7 Binary files /dev/null and b/src/rectangle_pipeline/shader/quad.vert.spv differ diff --git a/src/scene/menu_scene/bg_pipeline/bg_pipeline.rs b/src/scene/menu_scene/bg_pipeline/bg_pipeline.rs new file mode 100644 index 00000000..46354d94 --- /dev/null +++ b/src/scene/menu_scene/bg_pipeline/bg_pipeline.rs @@ -0,0 +1,68 @@ +use crate::wgpu_jumpstart::{shader, Gpu, RenderPipelineBuilder, SimpleQuad, Uniform}; +use zerocopy::AsBytes; + +pub struct BgPipeline { + render_pipeline: wgpu::RenderPipeline, + + simple_quad: SimpleQuad, + time_uniform: Uniform, +} + +impl<'a> BgPipeline { + pub fn new(gpu: &Gpu) -> Self { + let vs_module = shader::create_module(&gpu.device, include_bytes!("shader/quad.vert.spv")); + let fs_module = shader::create_module(&gpu.device, include_bytes!("shader/quad.frag.spv")); + + let time_uniform = Uniform::new( + &gpu.device, + TimeUniform::default(), + wgpu::ShaderStage::FRAGMENT, + ); + + let render_pipeline_layout = + &gpu.device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&time_uniform.bind_group_layout], + }); + + let render_pipeline = RenderPipelineBuilder::new(&render_pipeline_layout, &vs_module) + .fragment_stage(&fs_module) + .vertex_buffers(&[SimpleQuad::vertex_buffer_descriptor()]) + .build(&gpu.device); + + let simple_quad = SimpleQuad::new(&gpu.device); + + Self { + render_pipeline, + + simple_quad, + + time_uniform, + } + } + pub fn render(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &self.time_uniform.bind_group, &[]); + + render_pass.set_vertex_buffer(0, &self.simple_quad.vertex_buffer, 0, 0); + + render_pass.set_index_buffer(&self.simple_quad.index_buffer, 0, 0); + + render_pass.draw_indexed(0..SimpleQuad::indices_len(), 0, 0..1); + } + pub fn update_time(&mut self, gpu: &mut Gpu, time: f32) { + self.time_uniform.data.time = time; + self.time_uniform.update(&mut gpu.encoder, &gpu.device); + } +} + +#[repr(C)] +#[derive(Clone, Copy, AsBytes)] +struct TimeUniform { + time: f32, +} +impl Default for TimeUniform { + fn default() -> Self { + Self { time: 0.0 } + } +} diff --git a/src/scene/menu_scene/bg_pipeline/mod.rs b/src/scene/menu_scene/bg_pipeline/mod.rs new file mode 100644 index 00000000..75928280 --- /dev/null +++ b/src/scene/menu_scene/bg_pipeline/mod.rs @@ -0,0 +1,3 @@ +mod bg_pipeline; + +pub use bg_pipeline::BgPipeline; diff --git a/src/scene/menu_scene/bg_pipeline/shader/quad.frag b/src/scene/menu_scene/bg_pipeline/shader/quad.frag new file mode 100644 index 00000000..230b35da --- /dev/null +++ b/src/scene/menu_scene/bg_pipeline/shader/quad.frag @@ -0,0 +1,83 @@ +#version 450 + + +layout(location=0) in vec2 uv; +layout(location=0) out vec4 f_color; + + +layout(set=0, binding=0) +uniform Uniforms2 { + float u_time; +}; + +mat2 rotZ(float angle) { + float ca = cos(angle); + float sa = sin(angle); + return mat2(ca, -sa, sa, ca); +} + +void note_render(vec2 uv, float pos, inout vec3 color) { + float mod_x = mod(uv.x, 0.1 * 2.5 * 2.0); + + vec3 col = vec3(160.0 / 255.0, 81.0 / 255.0, 238.0 / 255.0); + + if (pos == 0.5) { + col = vec3(113.0 / 255.0, 48.0 / 255.0, 178.0 / 255.0); + } + + if (uv.y > 0.0 && uv.y < 0.5) { + color = mix(color, col, + smoothstep(-0.002, 0., 127. / 5800. - abs(mod_x - pos))); + } +} + +#define speed -0.5 +#define liveTime 2.6 + +void main() { + vec2 st = uv; + vec3 color = vec3(0.12); + + float d = 0.0; + + st *= rotZ(0.7); + st.x *= 1.5; + st.x = mod(st.x, 0.5); + + { + st.y += 0.5; + + float off = 0.0; + vec2 pos = st; + + pos.y -= mod((u_time * speed + off) / 5.0, 1.0) * liveTime; + note_render(pos, 0.1, color); + + off = 1.0; + pos = st; + pos.y -= mod((u_time * speed + off) / 5.0, 1.0) * liveTime; + note_render(pos, 0.1 * 2.0, color); + + off = 3.0; + pos = st; + pos.y -= mod((u_time * speed + off) / 5.0, 1.0) * liveTime; + note_render(pos, 0.1 * 3.0, color); + + off = 2.0; + pos = st; + pos.y -= mod((u_time * speed + off) / 5.0, 1.0) * liveTime; + note_render(pos, 0.1 * 4.0, color); + + off = 0.0; + pos = st; + pos.y -= mod((u_time * speed + off) / 5.0, 1.0) * liveTime; + note_render(pos, 0.1 * 5.0, color); + + off = 4.0; + pos = st; + pos.y -= mod((u_time * speed + off) / 5.0, 1.0) * liveTime; + note_render(pos, 0.1 * 5.0, color); + } + + f_color = vec4(color / 2.5, 1.0); +} \ No newline at end of file diff --git a/src/scene/menu_scene/bg_pipeline/shader/quad.frag.spv b/src/scene/menu_scene/bg_pipeline/shader/quad.frag.spv new file mode 100644 index 00000000..4023df18 Binary files /dev/null and b/src/scene/menu_scene/bg_pipeline/shader/quad.frag.spv differ diff --git a/src/scene/menu_scene/bg_pipeline/shader/quad.vert b/src/scene/menu_scene/bg_pipeline/shader/quad.vert new file mode 100644 index 00000000..10cbc510 --- /dev/null +++ b/src/scene/menu_scene/bg_pipeline/shader/quad.vert @@ -0,0 +1,11 @@ +#version 450 + +layout(location=0) in vec2 a_position; + +layout(location=0) out vec2 uv; + +void main() { + uv = (a_position + vec2(1.0,1.0))/2.0; + gl_Position = vec4(a_position,0.0,1.0); +} +// \ No newline at end of file diff --git a/src/scene/menu_scene/bg_pipeline/shader/quad.vert.spv b/src/scene/menu_scene/bg_pipeline/shader/quad.vert.spv new file mode 100644 index 00000000..5eeba45e Binary files /dev/null and b/src/scene/menu_scene/bg_pipeline/shader/quad.vert.spv differ diff --git a/src/scene/menu_scene/menu_scene.rs b/src/scene/menu_scene/menu_scene.rs new file mode 100644 index 00000000..a9ef3d9e --- /dev/null +++ b/src/scene/menu_scene/menu_scene.rs @@ -0,0 +1,310 @@ +use crate::{ + midi_device::{MidiDevicesMenager, MidiPortInfo}, + scene::{Scene, SceneEvent, SceneType}, + time_menager::Timer, + ui::Ui, + wgpu_jumpstart::Gpu, + MainState, +}; + +use super::bg_pipeline::BgPipeline; +use std::sync::mpsc; +use std::thread; + +pub enum Event { + MidiOpen(lib_midi::Midi, MidiPortInfo), +} + +pub struct MenuScene { + aysnc_job: async_job::Job, + bg_pipeline: BgPipeline, + midi_device_select: MidiDeviceSelect, + file: Option, + timer: Timer, +} + +impl MenuScene { + pub fn new(gpu: &mut Gpu, _state: &mut MainState) -> Self { + let (sender, receiver) = mpsc::channel(); + + let midi_device_select = MidiDeviceSelect::new(); + + let timer = Timer::new(); + + Self { + aysnc_job: async_job::Job::new(receiver, sender), + bg_pipeline: BgPipeline::new(&gpu), + midi_device_select, + file: None, + timer, + } + } +} + +impl Scene for MenuScene { + fn state_type(&self) -> SceneType { + SceneType::MainMenu + } + fn update(&mut self, state: &mut MainState, gpu: &mut Gpu, ui: &mut Ui) -> SceneEvent { + self.timer.update(); + let time = self.timer.get_elapsed() / 1000.0; + + self.bg_pipeline.update_time(gpu, time); + // Listen To Async Job Finish Event + if self.aysnc_job.working { + if let Ok(event) = self.aysnc_job.receiver.try_recv() { + self.aysnc_job.working = false; + + match event { + async_job::Event::MidiLoaded(mut midi) => { + midi.merged_track.notes = midi + .merged_track + .notes + .into_iter() + .filter(|n| n.ch != 9) + .collect(); + self.file = Some(midi); + } + async_job::Event::Err(e) => log::warn!("Midi Load: {}", e), + } + } + } + + // Select File Button + if button::queue( + state, + ui, + "Select File", + (state.window_size.0 / 2.0, state.window_size.1 / 2.0 - 100.0), + (500.0, 100.0), + false, + ) { + let tx = self.aysnc_job.sender.clone(); + + self.aysnc_job.working = true; + thread::spawn(move || { + let path = tinyfiledialogs::open_file_dialog("Select Midi", "", None); + + if let Some(path) = path { + let midi = lib_midi::Midi::new(&path); + + if let Ok(midi) = midi { + tx.send(async_job::Event::MidiLoaded(midi)) + .expect("tx send failed in midi loader"); + } else if let Err(e) = midi { + tx.send(async_job::Event::Err(e)) + .expect("tx send failed in midi loader"); + } + } else { + tx.send(async_job::Event::Err("File dialog returned None".into())) + .expect("tx send failed in midi loader"); + } + }); + } + + self.midi_device_select.queue(ui, &state); + + if self.file.is_some() + && button::queue( + state, + ui, + "Play", + ( + state.window_size.0 - 250.0 / 2.0 - 10.0, + state.window_size.1 - 80.0 / 2.0 - 10.0, + ), + (250.0, 80.0), + false, + ) + { + let file = std::mem::replace(&mut self.file, None); + let select = std::mem::replace(&mut self.midi_device_select, MidiDeviceSelect::new()); + return SceneEvent::MainMenu(Event::MidiOpen(file.unwrap(), select.get_selected())); + } + + SceneEvent::None + } + fn render(&mut self, _state: &mut MainState, gpu: &mut Gpu, frame: &wgpu::SwapChainOutput) { + let encoder = &mut gpu.encoder; + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }], + depth_stencil_attachment: None, + }); + self.bg_pipeline.render(&mut render_pass); + } + } +} + +struct MidiDeviceSelect { + midi_device_menager: MidiDevicesMenager, + midi_outs: Vec, + pub selected_id: usize, +} +impl MidiDeviceSelect { + fn new() -> Self { + let midi_device_menager = MidiDevicesMenager::new(); + Self { + midi_outs: midi_device_menager.get_outs(), + midi_device_menager, + selected_id: 0, + } + } + fn get_selected(mut self) -> MidiPortInfo { + self.midi_outs.remove(self.selected_id) + } + fn next(&mut self) { + self.selected_id += 1; + } + fn prev(&mut self) { + self.selected_id -= 1; + } + fn update_outs_list(&mut self) { + self.midi_outs = self.midi_device_menager.get_outs(); + log::info!("{:?}", self.midi_outs); + } + fn queue(&mut self, ui: &mut Ui, state: &MainState) { + self.update_outs_list(); + + let text = if self.midi_outs.len() > self.selected_id { + &self.midi_outs[self.selected_id].name + } else { + "No Midi Devices" + }; + + ui.queue_text(wgpu_glyph::Section { + text, + color: [1.0, 1.0, 1.0, 1.0], + screen_position: (state.window_size.0 / 2.0, state.window_size.1 / 2.0 + 25.0), + scale: wgpu_glyph::Scale::uniform(40.0), + layout: wgpu_glyph::Layout::Wrap { + line_breaker: Default::default(), + h_align: wgpu_glyph::HorizontalAlign::Center, + v_align: wgpu_glyph::VerticalAlign::Center, + }, + ..Default::default() + }); + + if button::queue( + state, + ui, + "<", + ( + state.window_size.0 / 2.0 - 250.0 / 2.0, + state.window_size.1 / 2.0 + 100.0, + ), + (250.0, 50.0), + self.selected_id == 0, + ) { + self.prev(); + } + + if button::queue( + state, + ui, + ">", + ( + state.window_size.0 / 2.0 + 250.0 / 2.01, + state.window_size.1 / 2.0 + 100.0, + ), + (250.0, 50.0), + self.selected_id + 1 >= self.midi_outs.len(), + ) { + self.next(); + } + } +} + +mod async_job { + use std::sync::mpsc::{Receiver, Sender}; + + pub enum Event { + MidiLoaded(lib_midi::Midi), + Err(String), + } + + pub struct Job { + pub receiver: Receiver, + pub sender: Sender, + + pub working: bool, + } + impl Job { + pub fn new(receiver: Receiver, sender: Sender) -> Self { + Self { + receiver, + sender, + working: false, + } + } + } +} + +mod button { + use crate::ui::ButtonInstance; + pub fn queue( + state: &super::MainState, + ui: &mut super::Ui, + text: &str, + pos: (f32, f32), + size: (f32, f32), + disabled: bool, + ) -> bool { + let (x, y) = pos; + let (w, h) = size; + + let coll_x = x - w / 2.0; + let coll_y = y - h / 2.0; + + let is_hover = state.mouse_pos.0 > coll_x + && state.mouse_pos.0 < coll_x + w + && state.mouse_pos.1 > coll_y + && state.mouse_pos.1 < coll_y + h; + + let color = if is_hover { + // [121.0 / 255.0, 85.0 / 255.0, 195.0 / 255.0] + [56.0 / 255.0, 145.0 / 255.0, 1.0] + } else { + // [111.0 / 255.0, 75.0 / 255.0, 185.0 / 255.0] + [160.0 / 255.0, 81.0 / 255.0, 232_558.0 / 255.0] + }; + + ui.queue_button(ButtonInstance { + position: [x, y], + size: [w, h], + color, + radius: 15.0, + is_hovered: if is_hover { 1 } else { 0 }, + }); + + ui.queue_text(wgpu_glyph::Section { + text, + color: if !disabled { + [1.0, 1.0, 1.0, 1.0] + } else { + [0.3, 0.3, 0.3, 1.0] + }, + screen_position: (x, y), + scale: wgpu_glyph::Scale::uniform(40.0), + layout: wgpu_glyph::Layout::Wrap { + line_breaker: Default::default(), + h_align: wgpu_glyph::HorizontalAlign::Center, + v_align: wgpu_glyph::VerticalAlign::Center, + }, + ..Default::default() + }); + + is_hover && state.mouse_clicked && !disabled + } +} diff --git a/src/scene/menu_scene/mod.rs b/src/scene/menu_scene/mod.rs new file mode 100644 index 00000000..4c78908d --- /dev/null +++ b/src/scene/menu_scene/mod.rs @@ -0,0 +1,5 @@ +mod bg_pipeline; +mod menu_scene; + +pub use bg_pipeline::BgPipeline; +pub use menu_scene::{Event, MenuScene}; diff --git a/src/scene/mod.rs b/src/scene/mod.rs new file mode 100644 index 00000000..2da0a6c6 --- /dev/null +++ b/src/scene/mod.rs @@ -0,0 +1,6 @@ +pub mod menu_scene; +pub mod playing_scene; + +mod scene; + +pub use scene::*; diff --git a/src/scene/playing_scene/keyboard.rs b/src/scene/playing_scene/keyboard.rs new file mode 100644 index 00000000..e5464c89 --- /dev/null +++ b/src/scene/playing_scene/keyboard.rs @@ -0,0 +1,164 @@ +use super::keyboard_pipeline::{KeyInstance, KeyStateInstance, KeyboardPipeline}; +use crate::wgpu_jumpstart::Gpu; +use crate::MainState; + +// const KEY_C: u8 = 0; +const KEY_CIS: u8 = 1; +// const KEY_D: u8 = 2; +const KEY_DIS: u8 = 3; +// const KEY_E: u8 = 4; +// const KEY_F: u8 = 5; +const KEY_FIS: u8 = 6; +// const KEY_G: u8 = 7; +const KEY_GIS: u8 = 8; +// const KEY_A: u8 = 9; +const KEY_AIS: u8 = 10; +// const KEY_B: u8 = 11; + +pub struct Key { + pub x: f32, + pub w: f32, + pub is_black: bool, +} + +pub struct PianoKeyboard { + pub keyboard_pipeline: KeyboardPipeline, + pub all_keys: Vec, +} + +impl PianoKeyboard { + pub fn new(state: &MainState, gpu: &Gpu) -> Self { + let keyboard_pipeline = KeyboardPipeline::new(state, gpu); + Self { + keyboard_pipeline, + all_keys: Vec::new(), + } + } + pub fn resize(&mut self, state: &crate::MainState, gpu: &mut Gpu) { + let w = state.window_size.0 / 52.0; + let h = 120.0 * state.window_size.0 / state.window_size.1; + + let mut x_offset = 0.0; + + self.all_keys.clear(); + let mut white_keys = Vec::new(); + let mut black_keys = Vec::new(); + + let mut rectangles = Vec::new(); + for id in 0..88 { + let x = id as f32 * w; + let y = 0.0; + + let key_id = id + 9; + let note_id = key_id % 12; + + if note_id == KEY_CIS + || note_id == KEY_DIS + || note_id == KEY_FIS + || note_id == KEY_GIS + || note_id == KEY_AIS + { + x_offset -= w; + + let w = w / 1.5; + let h = h / 1.5; + + let black_offset = w; + + let x = x_offset + black_offset + x + w / 2.0; + let y = y + h / 2.0 + state.window_size.1 - h * 1.5; + + self.all_keys.push(Key { + x, + w, + is_black: true, + }); + black_keys.push((x, y, w, h)); + } else { + let x = x_offset + x + w / 2.0; + let y = y + h / 2.0 + state.window_size.1 - h; + + self.all_keys.push(Key { + x, + w, + is_black: false, + }); + white_keys.push((x, y, w, h)); + } + } + + // To lazy to use depth buffer so we draw white keys first + for rect in white_keys { + rectangles.push(KeyInstance { + position: [rect.0, rect.1], + size: [rect.2 - 1.0, rect.3], + is_black: 0, + radius: 5.0 * state.window_size.0 / state.window_size.1, + }); + } + for rect in black_keys { + rectangles.push(KeyInstance { + position: [rect.0, rect.1], + size: [rect.2 - 1.0, rect.3], + is_black: 1, + radius: 5.0 * state.window_size.0 / state.window_size.1, + }); + } + + self.keyboard_pipeline + .update_instance_buffer(gpu, rectangles); + } + pub fn update_notes(&mut self, gpu: &mut Gpu, notes: [bool; 88]) { + let mut white_keys = Vec::new(); + let mut black_keys = Vec::new(); + + // Becouse white keys are first in instance bufer we need to split input + for id in 0..88 { + let key_id = id + 9; + let note_id = key_id % 12; + let on = notes[id as usize]; + + if note_id == KEY_CIS + || note_id == KEY_DIS + || note_id == KEY_FIS + || note_id == KEY_GIS + || note_id == KEY_AIS + { + black_keys.push(on); + } else { + white_keys.push(on); + } + } + + let notes_out = white_keys + .into_iter() + .chain(black_keys.into_iter()) + .map(|b| if b { 1 } else { 0 }) + .map(|b| KeyStateInstance { on: b }) + .collect(); + + self.keyboard_pipeline + .update_notes_state(&mut gpu.encoder, &gpu.device, notes_out); + } + pub fn render(&mut self, state: &MainState, gpu: &mut Gpu, frame: &wgpu::SwapChainOutput) { + let encoder = &mut gpu.encoder; + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }], + depth_stencil_attachment: None, + }); + self.keyboard_pipeline.render(state, &mut render_pass); + } + } +} diff --git a/src/scene/playing_scene/keyboard_pipeline/instance_data.rs b/src/scene/playing_scene/keyboard_pipeline/instance_data.rs new file mode 100644 index 00000000..d5d5ef1b --- /dev/null +++ b/src/scene/playing_scene/keyboard_pipeline/instance_data.rs @@ -0,0 +1,36 @@ +use wgpu::vertex_attr_array; + +use zerocopy::AsBytes; + +#[repr(C)] +#[derive(Debug, Copy, Clone, AsBytes)] +pub struct KeyInstance { + pub position: [f32; 2], + pub size: [f32; 2], + pub is_black: u32, + pub radius: f32, +} +impl KeyInstance { + pub fn vertex_buffer_descriptor<'a>() -> wgpu::VertexBufferDescriptor<'a> { + wgpu::VertexBufferDescriptor { + stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &vertex_attr_array!(1 => Float2,2 => Float2,3 => Uint,4 => Float), + } + } +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, AsBytes, PartialEq)] +pub struct KeyStateInstance { + pub on: u32, +} +impl KeyStateInstance { + pub fn vertex_buffer_descriptor<'a>() -> wgpu::VertexBufferDescriptor<'a> { + wgpu::VertexBufferDescriptor { + stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &vertex_attr_array!(5 => Uint), + } + } +} diff --git a/src/scene/playing_scene/keyboard_pipeline/keyboard_pipeline.rs b/src/scene/playing_scene/keyboard_pipeline/keyboard_pipeline.rs new file mode 100644 index 00000000..3fc98400 --- /dev/null +++ b/src/scene/playing_scene/keyboard_pipeline/keyboard_pipeline.rs @@ -0,0 +1,73 @@ +use super::{KeyInstance, KeyStateInstance}; + +use crate::wgpu_jumpstart::{shader, Gpu, Instances, RenderPipelineBuilder, SimpleQuad}; + +use crate::MainState; + +pub struct KeyboardPipeline { + render_pipeline: wgpu::RenderPipeline, + simple_quad: SimpleQuad, + + instances: Instances, + instances_state: Instances, +} + +impl<'a> KeyboardPipeline { + pub fn new(state: &MainState, gpu: &Gpu) -> Self { + let vs_module = shader::create_module(&gpu.device, include_bytes!("shader/quad.vert.spv")); + let fs_module = shader::create_module(&gpu.device, include_bytes!("shader/quad.frag.spv")); + + let render_pipeline_layout = + &gpu.device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&state.transform_uniform.bind_group_layout], + }); + + let render_pipeline = RenderPipelineBuilder::new(&render_pipeline_layout, &vs_module) + .fragment_stage(&fs_module) + .vertex_buffers(&[ + SimpleQuad::vertex_buffer_descriptor(), + KeyInstance::vertex_buffer_descriptor(), + KeyStateInstance::vertex_buffer_descriptor(), + ]) + .build(&gpu.device); + + let simple_quad = SimpleQuad::new(&gpu.device); + let instances = Instances::new(&gpu.device, 88); + let instances_state = Instances::new(&gpu.device, 88); + + Self { + render_pipeline, + simple_quad, + instances, + instances_state, + } + } + pub fn render(&'a self, state: &'a MainState, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &state.transform_uniform.bind_group, &[]); + + render_pass.set_vertex_buffer(0, &self.simple_quad.vertex_buffer, 0, 0); + render_pass.set_vertex_buffer(1, &self.instances.buffer, 0, 0); + render_pass.set_vertex_buffer(2, &self.instances_state.buffer, 0, 0); + + render_pass.set_index_buffer(&self.simple_quad.index_buffer, 0, 0); + + render_pass.draw_indexed(0..SimpleQuad::indices_len(), 0, 0..self.instances.len()); + } + pub fn update_instance_buffer(&mut self, gpu: &mut Gpu, instances: Vec) { + self.instances.data = instances; + self.instances.update(&mut gpu.encoder, &gpu.device); + } + pub fn update_notes_state( + &mut self, + command_encoder: &mut wgpu::CommandEncoder, + device: &wgpu::Device, + instances_state: Vec, + ) { + if self.instances_state.data != instances_state { + self.instances_state.data = instances_state; + self.instances_state.update(command_encoder, device); + } + } +} diff --git a/src/scene/playing_scene/keyboard_pipeline/mod.rs b/src/scene/playing_scene/keyboard_pipeline/mod.rs new file mode 100644 index 00000000..2169b28f --- /dev/null +++ b/src/scene/playing_scene/keyboard_pipeline/mod.rs @@ -0,0 +1,6 @@ +mod instance_data; + +mod keyboard_pipeline; + +pub use instance_data::{KeyInstance, KeyStateInstance}; +pub use keyboard_pipeline::KeyboardPipeline; diff --git a/src/scene/playing_scene/keyboard_pipeline/shader/quad.frag b/src/scene/playing_scene/keyboard_pipeline/shader/quad.frag new file mode 100644 index 00000000..125d8bfb --- /dev/null +++ b/src/scene/playing_scene/keyboard_pipeline/shader/quad.frag @@ -0,0 +1,33 @@ +#version 450 + + +layout(location=0) in vec3 color; +layout(location=1) in vec2 uv; +layout(location=2) in vec2 size; +layout(location=3) in float radius; +layout(location=4) in float is_black; + +layout(location=0) out vec4 f_color; + +void main() { + vec3 col = color; + + float alpha = 1.0; + + vec2 pos = uv * size; + + float xMax = size.x - radius; + float yMax = size.y - radius; + + if (pos.x < radius && pos.y > yMax ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(radius,yMax))); + }else if (pos.x > xMax && pos.y > yMax ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(xMax,yMax))); + } + + if(is_black==1.0){ + f_color = vec4(col, alpha); + }else{ + f_color = vec4(col*alpha,1.0); + } +} \ No newline at end of file diff --git a/src/scene/playing_scene/keyboard_pipeline/shader/quad.frag.spv b/src/scene/playing_scene/keyboard_pipeline/shader/quad.frag.spv new file mode 100644 index 00000000..b30e79c7 Binary files /dev/null and b/src/scene/playing_scene/keyboard_pipeline/shader/quad.frag.spv differ diff --git a/src/scene/playing_scene/keyboard_pipeline/shader/quad.vert b/src/scene/playing_scene/keyboard_pipeline/shader/quad.vert new file mode 100644 index 00000000..1bac0d80 --- /dev/null +++ b/src/scene/playing_scene/keyboard_pipeline/shader/quad.vert @@ -0,0 +1,62 @@ +#version 450 + +layout(location=0) in vec2 a_position; + +layout(location=1) in vec2 i_pos; +layout(location=2) in vec2 i_size; +layout(location=3) in uint i_is_black; +layout(location=4) in float i_radius; +layout(location=5) in uint i_on; + +layout(location=0) out vec3 color; +layout(location=1) out vec2 uv; +layout(location=2) out vec2 size; +layout(location=3) out float radius; +layout(location=4) out float is_black; + +layout(set=0, binding=0) +uniform Uniforms { + mat4 u_Transform; + vec2 u_size; +}; + +void main() { + + if(i_on==1){ + // if (i_is_black==1) { + // color = vec3( 91.0 / 255.0, 55.0 / 255.0, 165.0 / 255.0 ); + // } else { + // color = vec3( 121.0 / 255.0, 85.0 / 255.0, 195.0 / 255.0 ); + // }; + if (i_is_black==1){ + color=vec3(0.5,0.5,0.5); + } + else{ + color=vec3(0.7,0.7,0.7); + } + } + else{ + if (i_is_black==1){ + color=vec3(0.1,0.1,0.1); + } + else{ + color=vec3(1.0,1.0,1.0); + } + } + + size = i_size; + radius = i_radius; + uv = (a_position + vec2(1.0,1.0))/2.0; + is_black = float(i_is_black); + + mat4 i_Transform = mat4( + vec4(0.5*i_size.x, 0.0, 0.0, 0.0), + vec4(0.0, 0.5*i_size.y, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(i_pos, 0.0, 1.0) + ); + + + // if (i_is_black==0){z=0.0;}else{z=1.0;} + gl_Position = u_Transform * i_Transform * vec4(a_position, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/scene/playing_scene/keyboard_pipeline/shader/quad.vert.spv b/src/scene/playing_scene/keyboard_pipeline/shader/quad.vert.spv new file mode 100644 index 00000000..138e2eda Binary files /dev/null and b/src/scene/playing_scene/keyboard_pipeline/shader/quad.vert.spv differ diff --git a/src/scene/playing_scene/mod.rs b/src/scene/playing_scene/mod.rs new file mode 100644 index 00000000..d4753fb6 --- /dev/null +++ b/src/scene/playing_scene/mod.rs @@ -0,0 +1,9 @@ +mod keyboard; +mod keyboard_pipeline; + +mod notes; +mod notes_pipeline; + +mod playing_scene; + +pub use playing_scene::PlayingScene; diff --git a/src/scene/playing_scene/notes.rs b/src/scene/playing_scene/notes.rs new file mode 100644 index 00000000..400265c0 --- /dev/null +++ b/src/scene/playing_scene/notes.rs @@ -0,0 +1,104 @@ +use super::notes_pipeline::{NoteInstance, NotesPipeline}; +use crate::wgpu_jumpstart::Gpu; +use crate::MainState; + +pub struct Notes { + notes_pipeline: NotesPipeline, +} + +impl Notes { + pub fn new(state: &MainState, gpu: &Gpu, midi: &lib_midi::Midi) -> Self { + let notes_pipeline = NotesPipeline::new(state, gpu, midi); + Self { notes_pipeline } + } + pub fn resize( + &mut self, + state: &crate::MainState, + gpu: &mut Gpu, + keys: &[super::keyboard::Key], + midi: &lib_midi::Midi, + ) { + let mut instances = Vec::new(); + + let mut longer_than_88 = false; + for note in midi.merged_track.notes.iter() { + if note.note >= 21 && note.note <= 108 { + let key = &keys[note.note as usize - 21]; + let ar = state.window_size.0 / state.window_size.1; + + // let colors: [[[f32; 3]; 2]; 2] = [ + // [ + // [146.0 / 255.0, 255.0 / 255.0, 48.0 / 255.0], + // [87.0 / 255.0, 183.0 / 255.0, 12.0 / 255.0], + // ], + // [ + // [118.0 / 255.0, 166.0 / 255.0, 211.0 / 255.0], + // [54.0 / 255.0, 109.0 / 255.0, 173.0 / 255.0], + // ], + // ]; + let colors: [[[f32; 3]; 2]; 2] = [ + [ + [93.0 / 255.0, 188.0 / 255.0, 1.0], + [48.0 / 255.0, 124.0 / 255.0, 1.0], + // [49.0 / 255.0, 151.0 / 255.0, 255.0 / 255.0], + // [5.0 / 255.0, 92.0 / 255.0, 182.0 / 255.0], + ], + [ + [210.0 / 255.0, 89.0 / 255.0, 222.0 / 255.0], + [125.0 / 255.0, 69.0 / 255.0, 134.0 / 255.0], + // [165.0 / 255.0, 84.0 / 255.0, 255.0 / 255.0], + // [114.0 / 255.0, 0.0 / 255.0, 219.0 / 255.0], + ], + ]; + + let color = colors[note.track_id % 2]; + let color = if key.is_black { color[1] } else { color[0] }; + + let h = if note.duration >= 0.1 { + note.duration + } else { + 0.1 + }; + + instances.push(NoteInstance { + position: [key.x, note.start], + size: [key.w - 1.0, h], + color, + radius: 4.0 * ar, + }); + } else { + longer_than_88 = true; + } + } + + if longer_than_88 { + log::warn!("Midi Wider Than 88 Keys!"); + } + + self.notes_pipeline.update_instance_buffer(gpu, instances); + } + pub fn update(&mut self, gpu: &mut Gpu, time: f32) { + self.notes_pipeline.update_time(gpu, time); + } + pub fn render(&mut self, state: &MainState, gpu: &mut Gpu, frame: &wgpu::SwapChainOutput) { + let encoder = &mut gpu.encoder; + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }], + depth_stencil_attachment: None, + }); + self.notes_pipeline.render(state, &mut render_pass); + } + } +} diff --git a/src/scene/playing_scene/notes_pipeline/instance_data.rs b/src/scene/playing_scene/notes_pipeline/instance_data.rs new file mode 100644 index 00000000..01434dc5 --- /dev/null +++ b/src/scene/playing_scene/notes_pipeline/instance_data.rs @@ -0,0 +1,21 @@ +use wgpu::vertex_attr_array; + +use zerocopy::AsBytes; + +#[repr(C)] +#[derive(Debug, Copy, Clone, AsBytes)] +pub struct NoteInstance { + pub position: [f32; 2], + pub size: [f32; 2], + pub color: [f32; 3], + pub radius: f32, +} +impl NoteInstance { + pub fn vertex_buffer_descriptor<'a>() -> wgpu::VertexBufferDescriptor<'a> { + wgpu::VertexBufferDescriptor { + stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &vertex_attr_array!(1 => Float2,2 => Float2,3 => Float3,4 => Float), + } + } +} diff --git a/src/scene/playing_scene/notes_pipeline/mod.rs b/src/scene/playing_scene/notes_pipeline/mod.rs new file mode 100644 index 00000000..16264431 --- /dev/null +++ b/src/scene/playing_scene/notes_pipeline/mod.rs @@ -0,0 +1,6 @@ +mod instance_data; + +mod notes_pipeline; + +pub use instance_data::NoteInstance; +pub use notes_pipeline::NotesPipeline; diff --git a/src/scene/playing_scene/notes_pipeline/notes_pipeline.rs b/src/scene/playing_scene/notes_pipeline/notes_pipeline.rs new file mode 100644 index 00000000..9f3512d0 --- /dev/null +++ b/src/scene/playing_scene/notes_pipeline/notes_pipeline.rs @@ -0,0 +1,91 @@ +use super::NoteInstance; + +use crate::wgpu_jumpstart::{shader, Gpu, Instances, RenderPipelineBuilder, SimpleQuad, Uniform}; + +use crate::MainState; + +use zerocopy::AsBytes; + +pub struct NotesPipeline { + render_pipeline: wgpu::RenderPipeline, + + simple_quad: SimpleQuad, + + instances: Instances, + time_uniform: Uniform, +} + +impl<'a> NotesPipeline { + pub fn new(state: &MainState, gpu: &Gpu, midi: &lib_midi::Midi) -> Self { + let vs_module = shader::create_module(&gpu.device, include_bytes!("shader/quad.vert.spv")); + let fs_module = shader::create_module(&gpu.device, include_bytes!("shader/quad.frag.spv")); + + let time_uniform = Uniform::new( + &gpu.device, + TimeUniform::default(), + wgpu::ShaderStage::VERTEX, + ); + + let render_pipeline_layout = + &gpu.device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[ + &state.transform_uniform.bind_group_layout, + &time_uniform.bind_group_layout, + ], + }); + + let render_pipeline = RenderPipelineBuilder::new(&render_pipeline_layout, &vs_module) + .fragment_stage(&fs_module) + .vertex_buffers(&[ + SimpleQuad::vertex_buffer_descriptor(), + NoteInstance::vertex_buffer_descriptor(), + ]) + .build(&gpu.device); + + let simple_quad = SimpleQuad::new(&gpu.device); + + let instances = Instances::new(&gpu.device, midi.merged_track.notes.len()); + + Self { + render_pipeline, + + simple_quad, + + instances, + + time_uniform, + } + } + pub fn render(&'a self, state: &'a MainState, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &state.transform_uniform.bind_group, &[]); + render_pass.set_bind_group(1, &self.time_uniform.bind_group, &[]); + + render_pass.set_vertex_buffer(0, &self.simple_quad.vertex_buffer, 0, 0); + render_pass.set_vertex_buffer(1, &self.instances.buffer, 0, 0); + + render_pass.set_index_buffer(&self.simple_quad.index_buffer, 0, 0); + + render_pass.draw_indexed(0..SimpleQuad::indices_len(), 0, 0..self.instances.len()); + } + pub fn update_instance_buffer(&mut self, gpu: &mut Gpu, instances: Vec) { + self.instances.data = instances; + self.instances.update(&mut gpu.encoder, &gpu.device); + } + pub fn update_time(&mut self, gpu: &mut Gpu, time: f32) { + self.time_uniform.data.time = time; + self.time_uniform.update(&mut gpu.encoder, &gpu.device); + } +} + +#[repr(C)] +#[derive(Clone, Copy, AsBytes)] +struct TimeUniform { + time: f32, +} +impl Default for TimeUniform { + fn default() -> Self { + Self { time: 0.0 } + } +} diff --git a/src/scene/playing_scene/notes_pipeline/shader/quad.frag b/src/scene/playing_scene/notes_pipeline/shader/quad.frag new file mode 100644 index 00000000..d7968ea7 --- /dev/null +++ b/src/scene/playing_scene/notes_pipeline/shader/quad.frag @@ -0,0 +1,33 @@ +#version 450 + + +layout(location=0) in vec3 color; +layout(location=1) in vec2 uv; +layout(location=2) in vec2 size; +layout(location=3) in float radius; + +layout(location=0) out vec4 f_color; + + +void main() { + vec3 col = color; + + float alpha = 1.0; + + vec2 pos = uv * size; + + float xMax = size.x - radius; + float yMax = size.y - radius; + + if (pos.x < radius && pos.y < radius ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(radius,radius))); + }else if (pos.x < radius && pos.y > yMax ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(radius,yMax))); + }else if (pos.x > xMax && pos.y > yMax ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(xMax,yMax))); + }else if (pos.x > xMax && pos.y < radius ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(xMax,radius))); + } + + f_color = vec4(col, alpha); +} \ No newline at end of file diff --git a/src/scene/playing_scene/notes_pipeline/shader/quad.frag.spv b/src/scene/playing_scene/notes_pipeline/shader/quad.frag.spv new file mode 100644 index 00000000..3f3f8eff Binary files /dev/null and b/src/scene/playing_scene/notes_pipeline/shader/quad.frag.spv differ diff --git a/src/scene/playing_scene/notes_pipeline/shader/quad.vert b/src/scene/playing_scene/notes_pipeline/shader/quad.vert new file mode 100644 index 00000000..99668767 --- /dev/null +++ b/src/scene/playing_scene/notes_pipeline/shader/quad.vert @@ -0,0 +1,54 @@ +#version 450 + +layout(location=0) in vec2 a_position; + +layout(location=1) in vec2 i_pos; +layout(location=2) in vec2 i_size; +layout(location=3) in vec3 i_color; +layout(location=4) in float i_radius; + +layout(location=0) out vec3 o_color; +layout(location=1) out vec2 o_uv; +layout(location=2) out vec2 o_size; +layout(location=3) out float o_radius; + +layout(set=0, binding=0) +uniform Uniforms { + mat4 u_Transform; + vec2 u_size; +}; +layout(set=1, binding=0) +uniform Uniforms2 { + float u_time; +}; + + +#define speed 400.0 +void main() { + vec2 pos = i_pos; + float start = pos.y; + pos.y = u_size.y - 120.0 * u_size.x/u_size.y; + + vec2 size = i_size; + size.y = size.y * speed; + + pos = pos - vec2(0.0,size.y/2.0); + + vec2 offset = vec2(0.0, -(start - u_time) * speed); + + + mat4 i_Transform = mat4( + vec4(size.x / 2.0, 0.0, 0.0, 0.0), + vec4(0.0, size.y / 2.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(pos + offset, 0.0, 1.0) + ); + + + o_color = i_color; + o_radius = i_radius; + o_uv = (a_position + vec2(1.0,1.0))/2.0; + o_size = size; + + gl_Position = u_Transform * i_Transform * vec4(a_position, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/scene/playing_scene/notes_pipeline/shader/quad.vert.spv b/src/scene/playing_scene/notes_pipeline/shader/quad.vert.spv new file mode 100644 index 00000000..b6ee4bc3 Binary files /dev/null and b/src/scene/playing_scene/notes_pipeline/shader/quad.vert.spv differ diff --git a/src/scene/playing_scene/playing_scene.rs b/src/scene/playing_scene/playing_scene.rs new file mode 100644 index 00000000..c2b2350f --- /dev/null +++ b/src/scene/playing_scene/playing_scene.rs @@ -0,0 +1,198 @@ +use super::{ + super::{Scene, SceneEvent, SceneType}, + keyboard::PianoKeyboard, + notes::Notes, +}; + +use crate::{ + rectangle_pipeline::{RectangleInstance, RectanglePipeline}, + time_menager::Timer, + ui::Ui, + wgpu_jumpstart::Gpu, + MainState, +}; + +use winit::event::VirtualKeyCode; + +pub struct PlayingScene { + piano_keyboard: PianoKeyboard, + notes: Notes, + player: Player, + rectangle_pipeline: RectanglePipeline, +} + +impl PlayingScene { + pub fn new( + gpu: &mut Gpu, + state: &mut MainState, + midi: lib_midi::Midi, + port: MidiPortInfo, + ) -> Self { + let piano_keyboard = PianoKeyboard::new(state, &gpu); + let notes = Notes::new(state, &gpu, &midi); + + Self { + piano_keyboard, + notes, + player: Player::new(midi, port), + rectangle_pipeline: RectanglePipeline::new(&state, &gpu.device), + } + } +} + +impl Scene for PlayingScene { + fn state_type(&self) -> SceneType { + SceneType::Playing + } + fn resize(&mut self, state: &mut MainState, gpu: &mut Gpu) { + self.piano_keyboard.resize(state, gpu); + self.notes + .resize(state, gpu, &self.piano_keyboard.all_keys, &self.player.midi); + } + fn update(&mut self, state: &mut MainState, gpu: &mut Gpu, ui: &mut Ui) -> SceneEvent { + let notes_on = self.player.update(); + + let size_x = state.window_size.0 * self.player.percentage; + ui.queue_rectangle(RectangleInstance { + position: [size_x / 2.0, 0.0], + size: [size_x, 10.0], + color: [56.0 / 255.0, 145.0 / 255.0, 1.0, 1.0], + }); + + self.piano_keyboard.update_notes(gpu, notes_on); + self.notes.update(gpu, self.player.time); + + SceneEvent::None + } + fn render(&mut self, state: &mut MainState, gpu: &mut Gpu, frame: &wgpu::SwapChainOutput) { + self.notes.render(state, gpu, frame); + self.piano_keyboard.render(state, gpu, frame); + + let encoder = &mut gpu.encoder; + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }], + depth_stencil_attachment: None, + }); + self.rectangle_pipeline.render(state, &mut render_pass) + } + } + fn key_released(&mut self, _state: &mut MainState, key: VirtualKeyCode) { + match key { + VirtualKeyCode::Space => { + self.player.pause_resume(); + } + _ => {} + } + } +} + +use crate::midi_device::MidiPortInfo; +use std::collections::HashMap; +struct Player { + midi: lib_midi::Midi, + midi_first_note_start: f32, + midi_last_note_end: f32, + midi_device: crate::midi_device::MidiDevicesMenager, + active_notes: HashMap, + timer: Timer, + /// Time from start of the song without offsets + percentage: f32, + time: f32, +} + +impl Player { + fn new(midi: lib_midi::Midi, port: MidiPortInfo) -> Self { + let mut midi_device = crate::midi_device::MidiDevicesMenager::new(); + + log::info!("{:?}", midi_device.get_outs()); + + midi_device.connect_out(port); + + let midi_first_note_start = if let Some(note) = midi.merged_track.notes.first() { + note.start + } else { + 0.0 + }; + let midi_last_note_end = if let Some(note) = midi.merged_track.notes.last() { + note.start + note.duration + } else { + 0.0 + }; + + Self { + midi, + midi_first_note_start, + midi_last_note_end, + midi_device, + active_notes: HashMap::new(), + timer: Timer::new(), + percentage: 0.0, + time: 0.0, + } + } + fn update(&mut self) -> [bool; 88] { + self.timer.update(); + let raw_time = self.timer.get_elapsed() / 1000.0; + self.percentage = raw_time / self.midi_last_note_end; + self.time = raw_time + self.midi_first_note_start - 3.0; + + let mut notes_state: [bool; 88] = [false; 88]; + + let filtered: Vec<&lib_midi::MidiNote> = self + .midi + .merged_track + .notes + .iter() + .filter(|n| n.start <= self.time && n.start + n.duration + 0.5 > self.time) + .collect(); + + let midi_out = &mut self.midi_device; + for n in filtered { + use std::collections::hash_map::Entry; + + if n.start + n.duration >= self.time { + if n.note >= 21 && n.note <= 108 { + notes_state[n.note as usize - 21] = true; + } + + if let Entry::Vacant(_e) = self.active_notes.entry(n.id) { + self.active_notes.insert(n.id, n.note); + midi_out.send(&[0x90, n.note, n.vel]); + } + } else if let Entry::Occupied(_e) = self.active_notes.entry(n.id) { + self.active_notes.remove(&n.id); + midi_out.send(&[0x80, n.note, n.vel]); + } + } + + notes_state + } + fn pause_resume(&mut self) { + self.clear(); + self.timer.pause_resume(); + } + fn clear(&mut self) { + for (_id, n) in self.active_notes.iter() { + self.midi_device.send(&[0x80, *n, 0]); + } + self.active_notes.clear(); + } +} + +impl Drop for Player { + fn drop(&mut self) { + self.clear(); + } +} diff --git a/src/scene/scene.rs b/src/scene/scene.rs new file mode 100644 index 00000000..0f246b89 --- /dev/null +++ b/src/scene/scene.rs @@ -0,0 +1,23 @@ +use crate::ui::Ui; +use crate::wgpu_jumpstart::Gpu; +use crate::MainState; + +use winit::event::VirtualKeyCode; + +pub trait Scene { + fn state_type(&self) -> SceneType; + fn resize(&mut self, _state: &mut MainState, _gpu: &mut Gpu) {} + fn update(&mut self, state: &mut MainState, gpu: &mut Gpu, ui: &mut Ui) -> SceneEvent; + fn render(&mut self, state: &mut MainState, gpu: &mut Gpu, frame: &wgpu::SwapChainOutput); + fn key_released(&mut self, _state: &mut MainState, _key: VirtualKeyCode) {} +} + +pub enum SceneType { + MainMenu, + Playing, +} + +pub enum SceneEvent { + MainMenu(super::menu_scene::Event), + None, +} diff --git a/src/shaders/BlurParticleGLShader.h b/src/shaders/BlurParticleGLShader.h deleted file mode 100644 index 29d016e4..00000000 --- a/src/shaders/BlurParticleGLShader.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef BlurParticleGLShader_H -#define BlurParticleGLShader_H - -#include - -namespace BlurParticle_GLShader { - -std::string frag = - "#version 330 \n" - "in vec2 uv;" - "uniform sampler2D screenTexture;" - "out vec4 fragColor;" - "void main(){" - " vec3 color = texture(screenTexture, uv).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(-2,-2)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(-2,2)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(-1,0)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(0,-1)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(0,1)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(1,0)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(2,-2)).rgb;" - " color += textureOffset(screenTexture, uv, 2*ivec2(2,2)).rgb;" - " fragColor = vec4(mix(vec3(0.0, 0.0, 0.0), color/9.0, 0.99),1);" - "}"; -std::string vert = "#version 330 \n " - "layout(location = 0) in vec2 v;" - "out vec2 uv;" - "void main(){" - " gl_Position = vec4(v, 0.0, 1.0);" - " uv = v.xy * 0.5 + 0.5;" - "}"; -} // namespace BlurParticle_GLShader -#endif \ No newline at end of file diff --git a/src/shaders/RenderTextureGLShader.h b/src/shaders/RenderTextureGLShader.h deleted file mode 100644 index 3a336093..00000000 --- a/src/shaders/RenderTextureGLShader.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef RenderTextureGLShader_H -#define RenderTextureGLShader_H - -#include - -namespace RenderTexture_GLShader { - -std::string frag = "#version 330 \n" - "in vec2 uv;" - "uniform sampler2D screenTexture;" - "out vec4 color;" - "void main(){" - " color = texture(screenTexture,uv);" - "}"; -std::string vert = "#version 330 \n " - "layout(location = 0) in vec2 v;" - "out vec2 uv;" - "void main(){" - " gl_Position = vec4(v.xy,0.0f,1.0f);" - " uv = v.xy * 0.5 + 0.5;" - "}"; -} // namespace RenderTexture_GLShader -#endif \ No newline at end of file diff --git a/src/shaders/test.frag b/src/shaders/test.frag deleted file mode 100644 index aba93df4..00000000 --- a/src/shaders/test.frag +++ /dev/null @@ -1,17 +0,0 @@ - -void main(){ - vec2 st = gl_FragCoord.xy/iResolution.xy; - float pct = 0.0; - - pct = 1.0 - distance(st.x,0.5)*2.0; - - if(st.y>0.5){ - pct -= distance(st.y,0.5); - } - - - - vec4 color = vec4(1,0,0,pct); - - gl_FragColor = color; -} \ No newline at end of file diff --git a/src/shaders/test.vert b/src/shaders/test.vert deleted file mode 100644 index dde4458c..00000000 --- a/src/shaders/test.vert +++ /dev/null @@ -1,5 +0,0 @@ -in vec4 position; - -void main(){ - gl_Position = position; -} \ No newline at end of file diff --git a/src/shaders/test2.frag b/src/shaders/test2.frag deleted file mode 100644 index 64fdb463..00000000 --- a/src/shaders/test2.frag +++ /dev/null @@ -1,18 +0,0 @@ -float roundedRectangle (vec2 pos, vec2 size, float radius, float thickness, vec2 uv) -{ - float d = length(max(abs(uv - pos),size) - size) - radius; - return smoothstep(0.66, 0.33, d / thickness * 5.0); -} - -void main(){ - vec2 uv = (gl_FragCoord.xy / iResolution.xx - 0.5) * 8.0; - - - - vec3 rectColor = vec3( sin(iTime), cos(iTime), 0.5); - float intensity = roundedRectangle(vec2(0.0,0.0), vec2(1,1),0.1,0.1,uv); - - vec3 col; - col = mix(col,rectColor, intensity); - gl_FragColor = vec4(col,1.0); -} \ No newline at end of file diff --git a/src/shaders/test3.frag b/src/shaders/test3.frag deleted file mode 100644 index 3eb519e5..00000000 --- a/src/shaders/test3.frag +++ /dev/null @@ -1,21 +0,0 @@ -float roundedRectangle(vec2 pos, vec2 size, float radius, vec2 uv) { - float d = length(max(abs(uv - pos), size) - size) - radius; - return smoothstep(0.66, 0.33, d / 40.0 * 5.0); -} - -void main() { - // vec2 uv = gl_FragCoord.xy / iResolution.y * 2. - 1.; - // uv.x -= (iResolution.x - iResolution.y) / iResolution.y; -// vec2 uv = gl_FragCoord.xy / iResolution.xy; - - vec3 color; - - vec2 size = vec2(100.); - vec2 pos = vec2(6.0+size.x,iResolution.y-size.y-6.0); - - float rect = roundedRectangle(pos,size,1.0,gl_FragCoord.xy); - color += rect; - - - gl_FragColor = vec4(color, 1.0); -} \ No newline at end of file diff --git a/src/shaders/test3.vert b/src/shaders/test3.vert deleted file mode 100644 index cfced1ec..00000000 --- a/src/shaders/test3.vert +++ /dev/null @@ -1,38 +0,0 @@ -#version 330 - -layout(location = 0) in vec2 v; -layout(location = 1) in vec4 id; //note id, start, duration, is minor - -uniform float time; -uniform float mainSpeed; -uniform float minorsWidth = 1.0; - -#define notesCount 52.0 - -out INTERFACE { - float isMinor; - vec2 uv; - vec2 noteSize; -} Out; - - -void main(){ - - float scalingFactor = id.w != 0.0 ? minorsWidth : 1.0; - // Size of the note : width, height based on duration and current speed. - Out.noteSize = vec2(0.9*2.0/notesCount * scalingFactor, id.z*mainSpeed); - - // Compute note shift. - // Horizontal shift based on note id, width of keyboard, and if the note is minor or not. - // Vertical shift based on note start time, current time, speed, and height of the note quad. - const float a = (1.0/(notesCount-1.0)) * (2.0 - 2.0/notesCount); - const float b = -1.0 + 1.0/notesCount; - vec2 noteShift = vec2(id.x * a + b + id.w/notesCount, Out.noteSize.y * 0.5 - 0.5 + mainSpeed * (id.y - time)); - - // Scale uv. - Out.uv = Out.noteSize * v; - Out.isMinor = id.w; - // Output position. - gl_Position = vec4(Out.noteSize * v + noteShift, 0.0 , 1.0) ; - -} \ No newline at end of file diff --git a/src/time_menager.rs b/src/time_menager.rs new file mode 100644 index 00000000..c51a84e2 --- /dev/null +++ b/src/time_menager.rs @@ -0,0 +1,98 @@ +#[cfg(not(target_arch = "wasm32"))] +use std::time::Instant; + +#[cfg(target_arch = "wasm32")] +use crate::web_wrappers::time::Instant; + +pub struct TimeMenager { + fps: Fps, + pub last_time: Instant, +} + +impl Default for TimeMenager { + fn default() -> Self { + Self { + fps: Fps::new(), + last_time: Instant::now(), + } + } +} + +impl TimeMenager { + pub fn new() -> Self { + TimeMenager::default() + } + pub fn update(&mut self) { + self.last_time = Instant::now(); + self.fps.update(); + } + pub fn fps(&self) -> i32 { + self.fps.fps + } +} + +pub struct Timer { + pub time_elapsed: u128, + last_time: Instant, + pub paused: bool, +} +impl Timer { + pub fn new() -> Self { + Self { + time_elapsed: 0, + last_time: Instant::now(), + paused: false, + } + } + pub fn update(&mut self) { + if !self.paused { + // We use nanos only because when using secs timing error quickly piles up + // It is not visible when running 60FPS + // but on higher refresh rate it is important + self.time_elapsed += self.last_time.elapsed().as_nanos(); + } + self.last_time = Instant::now(); + } + pub fn get_elapsed(&self) -> f32 { + self.time_elapsed as f32 / 1_000_000.0 + } + pub fn pause(&mut self) { + self.paused = true; + } + pub fn resume(&mut self) { + self.paused = false; + } + pub fn pause_resume(&mut self) { + if self.paused { + self.paused = false; + } else { + self.paused = true; + } + } +} + +struct Fps { + fps: i32, + fps_counter: i32, + last_time: Instant, +} +impl Fps { + fn new() -> Self { + Self { + fps: 0, + fps_counter: 0, + last_time: Instant::now(), + } + } + fn update(&mut self) { + self.fps_counter += 1; + + if self.last_time.elapsed().as_secs() >= 1 { + self.last_time = Instant::now(); + + self.fps = self.fps_counter; + + self.fps_counter = 0; + } + } +} diff --git a/src/transform_uniform.rs b/src/transform_uniform.rs new file mode 100644 index 00000000..ee8299cd --- /dev/null +++ b/src/transform_uniform.rs @@ -0,0 +1,32 @@ +use zerocopy::AsBytes; + +#[repr(C)] +#[derive(Clone, Copy, AsBytes)] +pub struct TransformUniform { + transform: [f32; 16], + size: [f32; 2], +} +impl Default for TransformUniform { + fn default() -> Self { + Self { + transform: orthographic_projection(1080.0, 720.0), + size: [1080.0, 720.0], + } + } +} +impl TransformUniform { + pub fn update(&mut self, width: f32, height: f32) { + self.transform = orthographic_projection(width, height); + self.size = [width, height]; + } +} + +fn orthographic_projection(width: f32, height: f32) -> [f32; 16] { + #[cfg_attr(rustfmt, rustfmt_skip)] + [ + 2.0 / width, 0.0, 0.0, 0.0, + 0.0, -2.0 / height, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + -1.0, 1.0, 0.0, 1.0, + ] +} diff --git a/src/ui/Roboto-Regular.ttf b/src/ui/Roboto-Regular.ttf new file mode 100644 index 00000000..2b6392ff Binary files /dev/null and b/src/ui/Roboto-Regular.ttf differ diff --git a/src/ui/button_pipeline/button_pipeline.rs b/src/ui/button_pipeline/button_pipeline.rs new file mode 100644 index 00000000..ab71bbfd --- /dev/null +++ b/src/ui/button_pipeline/button_pipeline.rs @@ -0,0 +1,66 @@ +use super::ButtonInstance; + +use crate::wgpu_jumpstart::{shader, Instances, RenderPipelineBuilder, SimpleQuad}; + +use crate::MainState; + +pub struct ButtonPipeline { + render_pipeline: wgpu::RenderPipeline, + + simple_quad: SimpleQuad, + + instances: Instances, +} + +impl<'a> ButtonPipeline { + pub fn new(state: &MainState, device: &wgpu::Device) -> Self { + let vs_module = shader::create_module(device, include_bytes!("shader/quad.vert.spv")); + let fs_module = shader::create_module(device, include_bytes!("shader/quad.frag.spv")); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&state.transform_uniform.bind_group_layout], + }); + + let render_pipeline = RenderPipelineBuilder::new(&render_pipeline_layout, &vs_module) + .fragment_stage(&fs_module) + .vertex_buffers(&[ + SimpleQuad::vertex_buffer_descriptor(), + ButtonInstance::desc(), + ]) + .build(device); + + let simple_quad = SimpleQuad::new(device); + let instances = Instances::new(device, 100_000); + + Self { + render_pipeline, + + simple_quad, + + instances, + } + } + pub fn render(&'a self, state: &'a MainState, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &state.transform_uniform.bind_group, &[]); + + render_pass.set_vertex_buffer(0, &self.simple_quad.vertex_buffer, 0, 0); + render_pass.set_vertex_buffer(1, &self.instances.buffer, 0, 0); + + render_pass.set_index_buffer(&self.simple_quad.index_buffer, 0, 0); + + render_pass.draw_indexed(0..SimpleQuad::indices_len(), 0, 0..self.instances.len()); + } + pub fn update_instance_buffer( + &mut self, + command_encoder: &mut wgpu::CommandEncoder, + device: &wgpu::Device, + instances: Vec, + ) { + if self.instances.data != instances { + self.instances.data = instances; + self.instances.update(command_encoder, device); + } + } +} diff --git a/src/ui/button_pipeline/instance_data.rs b/src/ui/button_pipeline/instance_data.rs new file mode 100644 index 00000000..5fcb967f --- /dev/null +++ b/src/ui/button_pipeline/instance_data.rs @@ -0,0 +1,22 @@ +use wgpu::vertex_attr_array; + +use zerocopy::AsBytes; + +#[repr(C)] +#[derive(Debug, Copy, Clone, AsBytes, PartialEq)] +pub struct ButtonInstance { + pub position: [f32; 2], + pub size: [f32; 2], + pub color: [f32; 3], + pub radius: f32, + pub is_hovered: u32, +} +impl ButtonInstance { + pub fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> { + wgpu::VertexBufferDescriptor { + stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &vertex_attr_array!(1 => Float2,2 => Float2,3 => Float3,4 => Float, 5 => Uint), + } + } +} diff --git a/src/ui/button_pipeline/mod.rs b/src/ui/button_pipeline/mod.rs new file mode 100644 index 00000000..0d6f89b6 --- /dev/null +++ b/src/ui/button_pipeline/mod.rs @@ -0,0 +1,6 @@ +mod instance_data; + +mod button_pipeline; + +pub use button_pipeline::ButtonPipeline; +pub use instance_data::ButtonInstance; diff --git a/src/ui/button_pipeline/shader/quad.frag b/src/ui/button_pipeline/shader/quad.frag new file mode 100644 index 00000000..39b24fb1 --- /dev/null +++ b/src/ui/button_pipeline/shader/quad.frag @@ -0,0 +1,49 @@ +#version 450 + + +layout(location=0) in vec3 color; +layout(location=1) in vec2 uv; +layout(location=2) in vec2 size; +layout(location=3) in float radius; +layout(location=4) in float is_hovered; + +layout(location=0) out vec4 f_color; + + + + +void main() { + // vec3 col = color; + + vec3 col = vec3(0.08); + float alpha = 0.6; + + // float radius = 15.0; + + vec2 pos = uv * size; + + float xMax = size.x - radius; + float yMax = size.y - radius; + + + if (is_hovered == 1.0) { + col = vec3(0.05); + } + + if(pos.y > size.y - 8.0){ + col = color; + alpha = 1.0; + } + + if (pos.x < radius && pos.y < radius ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(radius,radius))); + }else if (pos.x < radius && pos.y > yMax ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(radius,yMax))); + }else if (pos.x > xMax && pos.y > yMax ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(xMax,yMax))); + }else if (pos.x > xMax && pos.y < radius ){ + alpha *= 1.0 - smoothstep(radius - 0.7,radius+ 0.7, length(pos - vec2(xMax,radius))); + } + + f_color = vec4(col, alpha); +} \ No newline at end of file diff --git a/src/ui/button_pipeline/shader/quad.frag.spv b/src/ui/button_pipeline/shader/quad.frag.spv new file mode 100644 index 00000000..05235a4c Binary files /dev/null and b/src/ui/button_pipeline/shader/quad.frag.spv differ diff --git a/src/ui/button_pipeline/shader/quad.vert b/src/ui/button_pipeline/shader/quad.vert new file mode 100644 index 00000000..b58f5b52 --- /dev/null +++ b/src/ui/button_pipeline/shader/quad.vert @@ -0,0 +1,39 @@ +#version 450 + +layout(location=0) in vec2 a_position; + +layout(location=1) in vec2 i_pos; +layout(location=2) in vec2 i_size; +layout(location=3) in vec3 i_color; +layout(location=4) in float i_radius; +layout(location=5) in uint i_is_hovered; + +layout(location=0) out vec3 color; +layout(location=1) out vec2 uv; +layout(location=2) out vec2 size; +layout(location=3) out float radius; +layout(location=4) out float is_hovered; + +layout(set=0, binding=0) +uniform Uniforms { + mat4 u_Transform; +}; + +void main() { + color = i_color; + + size = i_size; + radius = i_radius; + is_hovered = float(i_is_hovered); + uv = (a_position + vec2(1.0,1.0))/2.0; + + mat4 i_Transform = mat4( + vec4(0.5*i_size.x, 0.0, 0.0, 0.0), + vec4(0.0, 0.5*i_size.y, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(i_pos, 0.0, 1.0) + ); + + + gl_Position = u_Transform * i_Transform * vec4(a_position, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/ui/button_pipeline/shader/quad.vert.spv b/src/ui/button_pipeline/shader/quad.vert.spv new file mode 100644 index 00000000..cc2240a8 Binary files /dev/null and b/src/ui/button_pipeline/shader/quad.vert.spv differ diff --git a/src/ui/mod.rs b/src/ui/mod.rs new file mode 100644 index 00000000..51c12dec --- /dev/null +++ b/src/ui/mod.rs @@ -0,0 +1,5 @@ +mod button_pipeline; +mod ui; + +pub use button_pipeline::ButtonInstance; +pub use ui::Ui; diff --git a/src/ui/ui.rs b/src/ui/ui.rs new file mode 100644 index 00000000..0ba175ee --- /dev/null +++ b/src/ui/ui.rs @@ -0,0 +1,111 @@ +use wgpu_glyph::{GlyphBrush, GlyphBrushBuilder, Section}; + +use super::button_pipeline::{ButtonInstance, ButtonPipeline}; +use crate::rectangle_pipeline::{RectangleInstance, RectanglePipeline}; +use crate::wgpu_jumpstart::Gpu; +use crate::MainState; + +pub struct Ui<'a> { + rectangle_pipeline: RectanglePipeline, + button_pipeline: ButtonPipeline, + glyph_brush: GlyphBrush<'a, ()>, + queue: UiQueue, +} + +impl<'a> Ui<'a> { + pub fn new(state: &MainState, gpu: &mut Gpu) -> Self { + let button_pipeline = ButtonPipeline::new(state, &gpu.device); + let rectangle_pipeline = RectanglePipeline::new(state, &gpu.device); + let font: &[u8] = include_bytes!("./Roboto-Regular.ttf"); + let glyph_brush = GlyphBrushBuilder::using_font_bytes(font) + .expect("Load font") + .build(&gpu.device, wgpu::TextureFormat::Bgra8Unorm); + + Self { + rectangle_pipeline, + button_pipeline, + glyph_brush, + queue: UiQueue::new(), + } + } + pub fn queue_button(&mut self, button: ButtonInstance) { + self.queue.add_button(button); + } + pub fn queue_rectangle(&mut self, rectangle: RectangleInstance) { + self.queue.add_rectangle(rectangle); + } + pub fn queue_text(&mut self, section: Section) { + self.glyph_brush.queue(section); + } + pub fn resize(&mut self, _state: &crate::MainState, _gpu: &mut Gpu) {} + fn update(&mut self, gpu: &mut Gpu) { + self.rectangle_pipeline.update_instance_buffer( + &mut gpu.encoder, + &gpu.device, + self.queue.clear_rectangles(), + ); + self.button_pipeline.update_instance_buffer( + &mut gpu.encoder, + &gpu.device, + self.queue.clear_buttons(), + ); + } + pub fn render(&mut self, state: &mut MainState, gpu: &mut Gpu, frame: &wgpu::SwapChainOutput) { + self.update(gpu); + let encoder = &mut gpu.encoder; + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Load, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }, + }], + depth_stencil_attachment: None, + }); + self.rectangle_pipeline.render(state, &mut render_pass); + self.button_pipeline.render(state, &mut render_pass); + } + self.glyph_brush + .draw_queued( + &gpu.device, + encoder, + &frame.view, + state.window_size.0 as u32, + state.window_size.1 as u32, + ) + .expect("glyph_brush"); + } +} + +struct UiQueue { + buttons: Vec, + rectangles: Vec, +} + +impl UiQueue { + pub fn new() -> Self { + Self { + buttons: Vec::new(), + rectangles: Vec::new(), + } + } + pub fn add_button(&mut self, button: ButtonInstance) { + self.buttons.push(button); + } + pub fn add_rectangle(&mut self, rectangle: RectangleInstance) { + self.rectangles.push(rectangle); + } + pub fn clear_buttons(&mut self) -> Vec { + std::mem::replace(&mut self.buttons, Vec::new()) + } + pub fn clear_rectangles(&mut self) -> Vec { + std::mem::replace(&mut self.rectangles, Vec::new()) + } +} diff --git a/src/web_wrappers/mod.rs b/src/web_wrappers/mod.rs new file mode 100644 index 00000000..077885d7 --- /dev/null +++ b/src/web_wrappers/mod.rs @@ -0,0 +1 @@ +pub mod time; diff --git a/src/web_wrappers/time.rs b/src/web_wrappers/time.rs new file mode 100644 index 00000000..eec2d918 --- /dev/null +++ b/src/web_wrappers/time.rs @@ -0,0 +1,32 @@ +use js_sys::Date; +use wasm_bindgen::JsValue; + +pub struct Instant { + start_date: f64, +} + +impl Instant { + pub fn now() -> Self { + Self { + start_date: Date::now(), + } + } + pub fn elapsed(&self) -> Duration { + let milis = JsValue::from_f64(Date::now() - self.start_date); + Duration { + milis: milis.as_f64().unwrap(), + } + } +} + +pub struct Duration { + milis: f64, +} +impl Duration { + pub fn as_nanos(&self) -> u128 { + (self.milis * 1000000.0).round() as u128 + } + pub fn as_secs(&self) -> u64 { + (self.milis / 1000.0).round() as u64 + } +} diff --git a/src/wgpu_jumpstart/gpu.rs b/src/wgpu_jumpstart/gpu.rs new file mode 100644 index 00000000..d3955ac0 --- /dev/null +++ b/src/wgpu_jumpstart/gpu.rs @@ -0,0 +1,57 @@ +use super::surface::Surface; + +pub struct Gpu { + pub device: wgpu::Device, + pub queue: wgpu::Queue, + pub encoder: wgpu::CommandEncoder, +} + +impl Gpu { + pub async fn for_window(window: &winit::window::Window) -> (Self, Surface) { + let surface = wgpu::Surface::create(window); + + let adapter = wgpu::Adapter::request( + &wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + }, + wgpu::BackendBit::PRIMARY, + ) + .await + .expect("Failed to create adapter"); + + let (device, queue) = adapter + .request_device(&wgpu::DeviceDescriptor { + extensions: wgpu::Extensions { + anisotropic_filtering: false, + }, + limits: Default::default(), + }) + .await; + + let surface = Surface::new(window, surface, &device); + + let encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + ( + Self { + device, + queue, + encoder, + }, + surface, + ) + } + pub fn submit(&mut self) { + let new_encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + // We swap the current decoder by a new one here, so we can finish the + // current frame + let encoder = std::mem::replace(&mut self.encoder, new_encoder); + + self.queue.submit(&[encoder.finish()]); + } +} diff --git a/src/wgpu_jumpstart/instances.rs b/src/wgpu_jumpstart/instances.rs new file mode 100644 index 00000000..e3f497aa --- /dev/null +++ b/src/wgpu_jumpstart/instances.rs @@ -0,0 +1,40 @@ +use zerocopy::AsBytes; + +pub struct Instances +where + I: 'static + Copy + AsBytes, +{ + pub data: Vec, + pub buffer: wgpu::Buffer, +} +impl Instances +where + I: 'static + Copy + AsBytes, +{ + pub fn new(device: &wgpu::Device, max_size: usize) -> Self { + let instance_size = std::mem::size_of::(); + let buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: (instance_size * max_size) as u64, + usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, + }); + + Self { + data: Vec::new(), + buffer, + } + } + pub fn update(&self, command_encoder: &mut wgpu::CommandEncoder, device: &wgpu::Device) { + if self.data.is_empty() { + return; + } + let buffer_size = (self.data.len() * std::mem::size_of::()) as u64; + let staging_buffer = + device.create_buffer_with_data(&self.data.as_bytes(), wgpu::BufferUsage::COPY_SRC); + + command_encoder.copy_buffer_to_buffer(&staging_buffer, 0, &self.buffer, 0, buffer_size); + } + pub fn len(&self) -> u32 { + self.data.len() as u32 + } +} diff --git a/src/wgpu_jumpstart/mod.rs b/src/wgpu_jumpstart/mod.rs new file mode 100644 index 00000000..e6d78369 --- /dev/null +++ b/src/wgpu_jumpstart/mod.rs @@ -0,0 +1,15 @@ +mod gpu; +mod instances; +mod render_pipeline_builder; +mod simple_quad; +mod surface; +mod uniform; +mod window; + +pub mod shader; +pub use { + gpu::Gpu, instances::Instances, render_pipeline_builder::RenderPipelineBuilder, + simple_quad::SimpleQuad, uniform::Uniform, window::Window, +}; + +pub const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8Unorm; diff --git a/src/wgpu_jumpstart/render_pipeline_builder.rs b/src/wgpu_jumpstart/render_pipeline_builder.rs new file mode 100644 index 00000000..eac2cf3d --- /dev/null +++ b/src/wgpu_jumpstart/render_pipeline_builder.rs @@ -0,0 +1,70 @@ +use wgpu::{ + PipelineLayout, ProgrammableStageDescriptor, RasterizationStateDescriptor, + RenderPipelineDescriptor, ShaderModule, +}; + +pub struct RenderPipelineBuilder<'a> { + render_pipeline_descriptor: RenderPipelineDescriptor<'a>, +} + +impl<'a> RenderPipelineBuilder<'a> { + pub fn new(layout: &'a PipelineLayout, vertex_module: &'a ShaderModule) -> Self { + Self { + render_pipeline_descriptor: RenderPipelineDescriptor { + layout: &layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: vertex_module, + entry_point: "main", + }, + fragment_stage: None, + rasterization_state: Some(RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[wgpu::ColorStateDescriptor { + format: super::TEXTURE_FORMAT, + color_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha_blend: wgpu::BlendDescriptor { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + write_mask: wgpu::ColorWrite::ALL, + }], + depth_stencil_state: None, + vertex_state: wgpu::VertexStateDescriptor { + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[], + }, + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }, + } + } + + pub fn fragment_stage(mut self, fragment_module: &'a ShaderModule) -> Self { + self.render_pipeline_descriptor.fragment_stage = Some(ProgrammableStageDescriptor { + module: fragment_module, + entry_point: "main", + }); + self + } + + pub fn vertex_buffers(mut self, vertex_buffers: &'a [wgpu::VertexBufferDescriptor]) -> Self { + self.render_pipeline_descriptor.vertex_state.vertex_buffers = vertex_buffers; + self + } + + pub fn build(self, device: &wgpu::Device) -> wgpu::RenderPipeline { + device.create_render_pipeline(&self.render_pipeline_descriptor) + } +} diff --git a/src/wgpu_jumpstart/shader.rs b/src/wgpu_jumpstart/shader.rs new file mode 100644 index 00000000..6770fae4 --- /dev/null +++ b/src/wgpu_jumpstart/shader.rs @@ -0,0 +1,4 @@ +pub fn create_module(device: &wgpu::Device, spv: &[u8]) -> wgpu::ShaderModule { + let spirv = wgpu::read_spirv(std::io::Cursor::new(&spv[..])).unwrap(); + device.create_shader_module(&spirv) +} diff --git a/src/wgpu_jumpstart/simple_quad.rs b/src/wgpu_jumpstart/simple_quad.rs new file mode 100644 index 00000000..75d2b560 --- /dev/null +++ b/src/wgpu_jumpstart/simple_quad.rs @@ -0,0 +1,67 @@ +use zerocopy::AsBytes; + +pub struct SimpleQuad { + pub vertex_buffer: wgpu::Buffer, + pub index_buffer: wgpu::Buffer, +} +impl SimpleQuad { + pub fn new(device: &wgpu::Device) -> Self { + let vertex_buffer = + device.create_buffer_with_data(&VERTICES.as_bytes(), wgpu::BufferUsage::VERTEX); + + let index_buffer = + device.create_buffer_with_data(&INDICES.as_bytes(), wgpu::BufferUsage::INDEX); + + Self { + vertex_buffer, + index_buffer, + } + } + pub fn vertex_buffer_descriptor<'a>() -> wgpu::VertexBufferDescriptor<'a> { + Vertex::desc() + } + pub fn indices_len() -> u32 { + INDICES.len() as u32 + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, AsBytes)] +pub struct Vertex { + position: [f32; 2], +} +impl Vertex { + fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> { + use std::mem; + wgpu::VertexBufferDescriptor { + stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &[wgpu::VertexAttributeDescriptor { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float2, + }], + } + } +} + +const VERTICES: &[Vertex] = &[ + Vertex { + position: [-1.0, -1.0], + }, + Vertex { + position: [-1.0, 1.0], + }, + Vertex { + position: [1.0, 1.0], + }, + Vertex { + position: [1.0, -1.0], + }, +]; + +#[cfg_attr(rustfmt, rustfmt_skip)] +const INDICES: &[u16] = &[ + 0, 1, 2, + 2, 3, 0 +]; diff --git a/src/wgpu_jumpstart/surface.rs b/src/wgpu_jumpstart/surface.rs new file mode 100644 index 00000000..cae17cf9 --- /dev/null +++ b/src/wgpu_jumpstart/surface.rs @@ -0,0 +1,44 @@ +pub struct Surface { + surface: wgpu::Surface, + swap_chain: wgpu::SwapChain, + swap_chain_descriptor: wgpu::SwapChainDescriptor, +} + +impl Surface { + pub fn new( + window: &winit::window::Window, + surface: wgpu::Surface, + device: &wgpu::Device, + ) -> Self { + let size = window.inner_size(); + + let swap_chain_descriptor = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: super::TEXTURE_FORMAT, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + }; + + let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor); + + Self { + surface, + swap_chain, + swap_chain_descriptor, + } + } + pub fn resize(&mut self, gpu: &mut super::gpu::Gpu, size: winit::dpi::PhysicalSize) { + self.swap_chain_descriptor.width = size.width; + self.swap_chain_descriptor.height = size.height; + + self.swap_chain = gpu + .device + .create_swap_chain(&self.surface, &self.swap_chain_descriptor); + } + pub fn get_next_texture(&mut self) -> wgpu::SwapChainOutput { + self.swap_chain + .get_next_texture() + .expect("get_next_texture") + } +} diff --git a/src/wgpu_jumpstart/uniform.rs b/src/wgpu_jumpstart/uniform.rs new file mode 100644 index 00000000..3242ba15 --- /dev/null +++ b/src/wgpu_jumpstart/uniform.rs @@ -0,0 +1,63 @@ +use zerocopy::AsBytes; + +pub struct Uniform +where + U: 'static + Copy + AsBytes, +{ + pub data: U, + buffer: wgpu::Buffer, + pub bind_group_layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup, +} +impl Uniform +where + U: 'static + Copy + AsBytes, +{ + pub fn new(device: &wgpu::Device, data: U, visibility: wgpu::ShaderStage) -> Self { + let bind_group_layout_descriptor = wgpu::BindGroupLayoutDescriptor { + label: None, + bindings: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }; + + let buffer = device.create_buffer_with_data( + &data.as_bytes(), + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ); + + let bind_group_layout = device.create_bind_group_layout(&bind_group_layout_descriptor); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &buffer, + range: 0..std::mem::size_of_val(&data) as wgpu::BufferAddress, + }, + }], + }); + + Self { + data, + bind_group, + bind_group_layout, + buffer, + } + } + pub fn update(&self, command_encoder: &mut wgpu::CommandEncoder, device: &wgpu::Device) { + let staging_buffer = + device.create_buffer_with_data(&self.data.as_bytes(), wgpu::BufferUsage::COPY_SRC); + command_encoder.copy_buffer_to_buffer( + &staging_buffer, + 0, + &self.buffer, + 0, + std::mem::size_of::() as wgpu::BufferAddress, + ); + } +} diff --git a/src/wgpu_jumpstart/window.rs b/src/wgpu_jumpstart/window.rs new file mode 100644 index 00000000..caf15bfb --- /dev/null +++ b/src/wgpu_jumpstart/window.rs @@ -0,0 +1,71 @@ +use super::gpu::Gpu; +use super::surface::Surface; + +use winit::event_loop::EventLoop; +use winit::window::WindowBuilder; + +pub struct Window { + pub surface: Surface, + pub winit_window: winit::window::Window, + pub width: f32, + pub height: f32, + pub dpi: f64, +} + +impl Window { + pub async fn new( + builder: WindowBuilder, + size: (u32, u32), + event_loop: &EventLoop<()>, + ) -> (Self, Gpu) { + let dpi = event_loop.primary_monitor().scale_factor(); + + let (width, height) = size; + + let width = (width as f64 / dpi).round(); + let height = (height as f64 / dpi).round(); + + let winit_window = builder + .with_inner_size(winit::dpi::LogicalSize { width, height }) + .build(event_loop) + .unwrap(); + + #[cfg(target_arch = "wasm32")] + { + use winit::platform::web::WindowExtWebSys; + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| doc.body()) + .and_then(|body| { + body.append_child(&web_sys::Element::from(winit_window.canvas())) + .ok() + }) + .expect("couldn't append canvas to document body"); + } + + let (gpu, surface) = Gpu::for_window(&winit_window).await; + + let size = winit_window.inner_size(); + + ( + Self { + surface, + winit_window, + width: size.width as f32, + height: size.height as f32, + dpi, + }, + gpu, + ) + } + pub fn size(&self) -> (f32, f32) { + let size = self.winit_window.inner_size(); + (size.width as f32 / self.dpi as f32, size.height as f32 / self.dpi as f32) + } + pub fn physical_size(&self) -> winit::dpi::PhysicalSize { + self.winit_window.inner_size() + } + pub fn request_redraw(&self) { + self.winit_window.request_redraw(); + } +} diff --git a/test.mid b/test.mid new file mode 100644 index 00000000..c0b1c1c0 Binary files /dev/null and b/test.mid differ