├── .github └── workflows │ ├── build_emscripten.yml │ ├── build_linux.yml │ ├── build_osx.yml │ ├── build_windows.yml │ ├── publish_crate.yml │ └── publish_sys_crate.yml ├── .gitignore ├── .gitmodules ├── Cargo.toml ├── LICENSE ├── README.md ├── presets ├── 000-empty.milk ├── 001-line.milk ├── 100-square.milk ├── 101-per_frame.milk ├── 102-per_frame3.milk ├── 103-multiple-eqn.milk ├── 104-continued-eqn.milk ├── 105-per_frame_init.milk ├── 110-per_pixel.milk ├── 200-wave.milk ├── 201-wave.milk ├── 202-wave.milk ├── 203-wave.milk ├── 204-wave.milk ├── 205-wave.milk ├── 206-wave.milk ├── 207-wave.milk ├── 210-wave-smooth-00.milk ├── 210-wave-smooth-01.milk └── 210-wave-smooth-80.milk ├── projectm-sys ├── .cargo │ ├── config.toml │ └── linker-emscripten ├── .github │ └── workflows │ │ ├── build_emscripten.yml │ │ ├── build_linux.yml │ │ ├── build_osx.yml │ │ ├── build_windows.yml │ │ └── publish_crate.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── bindgen │ ├── default.h │ └── playlist.h ├── build.rs ├── build_bindgen.rs └── src │ └── lib.rs ├── src ├── core.rs ├── lib.rs └── playlist.rs └── tests ├── core.rs └── playlist.rs /.github/workflows/build_emscripten.yml: -------------------------------------------------------------------------------- 1 | name: Emscripten 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: ubuntu-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | 27 | - name: Setup EMSDK 28 | uses: mymindstorm/setup-emsdk@v14 29 | with: 30 | # Make sure to set a version number! 31 | version: 3.1.69 32 | # This is the name of the cache folder. 33 | # The cache folder will be placed in the build directory, 34 | # so make sure it doesn't conflict with anything! 35 | actions-cache-folder: "emsdk-cache" 36 | 37 | - name: Verify EMSDK 38 | run: emcc -v 39 | 40 | - name: Install Packages 41 | run: | 42 | sudo apt-get update 43 | sudo apt-get install -y gcc-multilib libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev 44 | 45 | - name: Update Local Toolchain 46 | run: | 47 | rustup update 48 | rustup component add clippy 49 | rustup target add wasm32-unknown-emscripten 50 | 51 | - name: Toolchain Info 52 | run: | 53 | cargo --version --verbose 54 | rustc --version 55 | cargo clippy --version 56 | 57 | - name: Lint 58 | run: | 59 | cargo fmt -- --check 60 | # cargo clippy -- -D warnings 61 | 62 | - name: Run Tests 63 | run: | 64 | cargo check 65 | # cargo test --all 66 | 67 | - name: Build Debug 68 | run: cargo build --target wasm32-unknown-emscripten -------------------------------------------------------------------------------- /.github/workflows/build_linux.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu Linux (x86_64) 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: ubuntu-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | 27 | - name: Install Packages 28 | run: | 29 | sudo apt-get update 30 | sudo apt-get install -y libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev 31 | 32 | - name: Update Local Toolchain 33 | run: | 34 | rustup update 35 | rustup component add clippy 36 | 37 | - name: Toolchain Info 38 | run: | 39 | cargo --version --verbose 40 | rustc --version 41 | cargo clippy --version 42 | 43 | - name: Lint 44 | run: | 45 | cargo fmt -- --check 46 | # cargo clippy -- -D warnings 47 | 48 | - name: Run Tests 49 | run: | 50 | cargo check 51 | # cargo test --all 52 | 53 | - name: Build Debug 54 | run: cargo build 55 | -------------------------------------------------------------------------------- /.github/workflows/build_osx.yml: -------------------------------------------------------------------------------- 1 | name: macOS (x86_64) 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: macos-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | 27 | - name: Update Local Toolchain 28 | run: | 29 | rustup update 30 | rustup component add clippy 31 | 32 | - name: Toolchain Info 33 | run: | 34 | cargo --version --verbose 35 | rustc --version 36 | cargo clippy --version 37 | 38 | - name: Lint 39 | run: | 40 | cargo fmt -- --check 41 | # cargo clippy -- -D warnings 42 | 43 | - name: Run Tests 44 | run: | 45 | cargo check 46 | # cargo test --all 47 | 48 | - name: Build Debug 49 | run: cargo build 50 | -------------------------------------------------------------------------------- /.github/workflows/build_windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows (x64) 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: windows-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: recursive 26 | 27 | - name: Install Dependencies 28 | run: vcpkg --triplet=x64-windows-static-md install glew 29 | 30 | - name: Update Local Toolchain 31 | run: | 32 | rustup update 33 | rustup component add clippy 34 | 35 | - name: Toolchain Info 36 | run: | 37 | cargo --version --verbose 38 | rustc --version 39 | cargo clippy --version 40 | 41 | - name: Lint 42 | run: | 43 | cargo fmt -- --check 44 | # cargo clippy -- -D warnings 45 | 46 | - name: Run Tests 47 | run: | 48 | cargo check 49 | # cargo test --all 50 | 51 | - name: Build Debug 52 | run: cargo build 53 | 54 | -------------------------------------------------------------------------------- /.github/workflows/publish_crate.yml: -------------------------------------------------------------------------------- 1 | name: Publish to crates.io 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | publish: 12 | name: Publish 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Packages 21 | run: | 22 | sudo apt-get update 23 | sudo apt-get install -y libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev 24 | 25 | - name: Update Local Toolchain 26 | run: | 27 | rustup update 28 | rustup component add clippy 29 | 30 | - name: Toolchain Info 31 | run: | 32 | cargo --version --verbose 33 | rustc --version 34 | cargo clippy --version 35 | 36 | - name: Lint 37 | run: | 38 | cargo fmt -- --check 39 | # cargo clippy -- -D warnings 40 | 41 | - name: Run Tests 42 | run: | 43 | cargo check 44 | # cargo test --all 45 | 46 | - name: Wait On Publish_SYS 47 | uses: tomchv/wait-my-workflow@v1.1.0 48 | with: 49 | token: ${{ secrets.GITHUB_TOKEN }} 50 | checkName: 'Publish_SYS' 51 | ref: ${{ github.sha }} 52 | intervalSeconds: 30 53 | timeoutSeconds: 3600 54 | 55 | - name: Publish 56 | env: 57 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 58 | run: | 59 | cargo publish --token $CARGO_REGISTRY_TOKEN -------------------------------------------------------------------------------- /.github/workflows/publish_sys_crate.yml: -------------------------------------------------------------------------------- 1 | name: Publish SYS to crates.io 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | publish: 12 | name: Publish_SYS 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Packages 21 | run: | 22 | sudo apt-get update 23 | sudo apt-get install -y libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev 24 | 25 | - name: Update Local Toolchain 26 | run: | 27 | rustup update 28 | rustup component add clippy 29 | 30 | - name: Toolchain Info 31 | run: | 32 | cargo --version --verbose 33 | rustc --version 34 | cargo clippy --version 35 | 36 | - name: Lint 37 | run: | 38 | cd projectm-sys 39 | cargo fmt -- --check 40 | # cargo clippy -- -D warnings 41 | 42 | - name: Run Tests 43 | run: | 44 | cd projectm-sys 45 | cargo check 46 | # cargo test --all 47 | 48 | - name: Publish 49 | env: 50 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 51 | run: | 52 | cd projectm-sys 53 | cargo publish --token $CARGO_REGISTRY_TOKEN -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | .DS_Store 13 | 14 | .idea/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "projectm-sys/libprojectM"] 2 | path = projectm-sys/libprojectM 3 | url = https://github.com/projectM-visualizer/projectm.git 4 | [submodule "libprojectM"] 5 | branch = v4.1.2 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "projectm" 3 | version = "3.1.2" 4 | edition = "2021" 5 | rust-version = "1.65" 6 | authors = ["AnomieVision ", "Mischa Spiegelmock "] 7 | description = "Bindings for ProjectM" 8 | license = " LGPL-3.0-or-later" 9 | repository = "https://github.com/projectM-visualizer/projectm-rs" 10 | keywords = ["visualization", "audio", "sound", "projectm"] 11 | categories = ["multimedia", "multimedia::video", "multimedia::audio"] 12 | readme = "README.md" 13 | 14 | [dependencies] 15 | libc = "0.2" 16 | #projectm-sys = { path = "projectm-sys", version = "1", features = ["playlist", "static"] } 17 | projectm-sys = { version = "1" } 18 | rand = "0.8" 19 | 20 | [features] 21 | default = ["playlist"] 22 | playlist = ["projectm-sys/playlist"] 23 | static = ["projectm-sys/static"] 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | [![Contributors][contributors-shield]][contributors-url] 6 | [![Forks][forks-shield]][forks-url] 7 | [![Stargazers][stars-shield]][stars-url] 8 | [![Issues][issues-shield]][issues-url] 9 | [![MIT License][license-shield]][license-url] 10 | [![Crates.io][crates-shield]][crates-url] 11 | [![Downloads][crates-dl-shield]][crates-dl-url] 12 | 13 |
14 | 15 |

projectM

16 | 17 |

18 | Safe-wrapper bindings for ProjectM 19 |
20 |
21 | Docs 22 | · 23 | Example 24 | · 25 | Report Bug 26 | · 27 | Request Feature 28 |

29 |
30 | 31 |
32 | 33 | 34 |
35 | Table of Contents 36 |
    37 |
  1. 38 | Getting Started 39 | 42 |
  2. 43 |
  3. Usage
  4. 44 |
  5. Contributing
  6. 45 |
  7. License
  8. 46 |
  9. Support
  10. 47 |
  11. Contact
  12. 48 |
49 |
50 | 51 |
52 | 53 | 54 | ## Getting Started 55 | 56 | To get this crate up and running properly, you'll need to install some prerequisites. 57 | 58 | ### Prerequisites 59 | 60 | Depending on the OS/distribution and packaging system, libraries might be split into separate packages with binaries and 61 | development files. To build projectM, both binaries and development files need to be installed. 62 | 63 | #### General build dependencies for all platforms: 64 | 65 | * [**Rust**](https://www.rust-lang.org/tools/install) 66 | * A working build toolchain. 67 | * [**CMake**](https://cmake.org/): Used to generate platform-specific build files. 68 | * **OpenGL**: 3D graphics library. Used to render the visualizations. 69 | * or **GLES3**: OpenGL libraries for embedded systems, version 3. Required to build projectM on Android devices, 70 | Raspberry Pi, Emscripten and the Universal Windows Platform. 71 | 72 | #### Only relevant for Windows: 73 | 74 | * [**vcpkg**](https://github.com/microsoft/vcpkg): C++ Library Manager for Windows. _Optional_, but recommended to 75 | install the aforementioned library dependencies. 76 | * [**GLEW**](http://glew.sourceforge.net/): The OpenGL Extension Wrangler Library. Only required if using CMake to 77 | configure the build, the pre-created solutions use a bundled copy of GLEW. 78 |

(back to top)

79 | 80 | 81 | 82 | ## Usage 83 | 84 | ``` 85 | # Cargo.toml 86 | 87 | [dependencies] 88 | projectm = { version = "1.0", features = [] } # Available features: playlist 89 | ``` 90 | 91 |

(back to top)

92 | 93 | 94 | ## Example 95 | 96 | Check out the frontend-sdl repo for an example on how to utilize the projectM library. 97 |
98 | * [**frontend-sdl-rust**](https://github.com/projectM-visualizer/frontend-sdl-rust) 99 | 100 |

(back to top)

101 | 102 | 103 | ## Contributing 104 | 105 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 106 | 107 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 108 | Don't forget to give the project a star! Thanks again! 109 | 110 | 1. Fork the Project 111 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 112 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 113 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 114 | 5. Open a Pull Request 115 | 116 |

(back to top)

117 | 118 | 119 | 120 | 121 | ## License 122 | 123 | Distributed under the LGPL-2.1 license. See `LICENSE` for more information. 124 | 125 |

(back to top)

126 | 127 | 128 | ## Support 129 | 130 | [![Discord][discord-shield]][discord-url] 131 | 132 |

(back to top)

133 | 134 | 135 | ## Contact 136 | 137 | Blaquewithaq (Discord: SoFloppy#1289) - [@anomievision](https://twitter.com/anomievision) - anomievision@gmail.com 138 | 139 |

(back to top)

140 | 141 | 142 | 143 | [contributors-shield]: https://img.shields.io/github/contributors/projectM-visualizer/projectm-rs.svg?style=for-the-badge 144 | [contributors-url]: https://github.com/projectM-visualizer/projectm-rs/graphs/contributors 145 | [forks-shield]: https://img.shields.io/github/forks/projectM-visualizer/projectm-rs.svg?style=for-the-badge 146 | [forks-url]: https://github.com/projectM-visualizer/projectm-rs/network/members 147 | [stars-shield]: https://img.shields.io/github/stars/projectM-visualizer/projectm-rs.svg?style=for-the-badge 148 | [stars-url]: https://github.com/projectM-visualizer/projectm-rs/stargazers 149 | [issues-shield]: https://img.shields.io/github/issues/projectM-visualizer/projectm-rs.svg?style=for-the-badge 150 | [issues-url]: https://github.com/projectM-visualizer/projectm-rs/issues 151 | [license-shield]: https://img.shields.io/github/license/projectM-visualizer/projectm-rs.svg?style=for-the-badge 152 | [license-url]: https://github.com/projectM-visualizer/projectm-rs/blob/master/LICENSE 153 | [crates-shield]: https://img.shields.io/crates/v/projectm-rs?style=for-the-badge 154 | [crates-url]: https://crates.io/crates/projectm-rs 155 | [crates-dl-shield]: https://img.shields.io/crates/d/projectm-rs?style=for-the-badge 156 | [crates-dl-url]: https://crates.io/crates/projectm-rs 157 | [discord-shield]: https://img.shields.io/discord/737206408482914387?style=for-the-badge 158 | [discord-url]: https://discord.gg/7fQXN43n9W 159 | -------------------------------------------------------------------------------- /presets/000-empty.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | // test preset defaults, see BuiltinParams.cpp 3 | // most minimal preset to make something visible 4 | wave_r=1 5 | -------------------------------------------------------------------------------- /presets/001-line.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | // test preset defaults, see BuiltinParams.cpp 3 | // minimal preset to make something visible 4 | fdecay=0 5 | warp=0; 6 | nWaveMode=6 7 | fWaveScale=1 8 | fwavesmoothing=0.01 9 | wave_r=1.0 10 | wave_g=1.0 11 | wave_b=1.0 12 | wave_x=0.500000 13 | wave_y=0.500000 14 | -------------------------------------------------------------------------------- /presets/100-square.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// just a double box 3 | per_frame_1001=// 4 | 5 | fDecay=1 6 | zoom=0 7 | rot=0.0 8 | warp=1 9 | ob_size=0.2 10 | ob_r=0.0 11 | ob_g=0.0 12 | ob_b=0.0 13 | ob_a=0.0 14 | ib_size=0.1 15 | ib_r=1.0 16 | ib_g=0.0 17 | ib_b=0.0 18 | ib_a=1.0 19 | -------------------------------------------------------------------------------- /presets/101-per_frame.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// one per frame equation 3 | per_frame_1001=// varies outer frame color - red only 4 | 5 | fDecay=0.98 6 | zoom=0 7 | rot=0.0 8 | warp=0.0 9 | ob_size=0.2 10 | ob_r=0.0 11 | ob_g=0.0 12 | ob_b=0.0 13 | ob_a=0.0 14 | ib_size=0.1 15 | ib_r=1.0 16 | ib_g=0.0 17 | ib_b=0.0 18 | ib_a=1.0 19 | 20 | per_frame_1=ib_r=0.7+0.4*sin(3*time); 21 | -------------------------------------------------------------------------------- /presets/102-per_frame3.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// one per frame equation 3 | per_frame_1001=// varies outer frame color - multi-color 4 | 5 | fDecay=0.98 6 | zoom=0 7 | rot=0.0 8 | warp=0.0 9 | ob_size=0.2 10 | ob_r=0.0 11 | ob_g=0.0 12 | ob_b=0.0 13 | ob_a=0.0 14 | ib_size=0.1 15 | ib_r=0.0 16 | ib_g=0.0 17 | ib_b=0.0 18 | ib_a=1.0 19 | 20 | per_frame_1=ib_r=0.7+0.4*sin(3*time); 21 | per_frame_2=ib_g=0.7+0.4*sin(4*time); 22 | per_frame_3=ib_b=0.7+0.4*sin(5*time); -------------------------------------------------------------------------------- /presets/103-multiple-eqn.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// one per frame equation 3 | per_frame_1001=// test multiple equations one line 4 | 5 | fDecay=0.98 6 | zoom=0 7 | rot=0.0 8 | warp=0.0 9 | ob_size=0.2 10 | ob_r=0.0 11 | ob_g=0.0 12 | ob_b=0.0 13 | ob_a=0.0 14 | ib_size=0.1 15 | ib_r=0.0 16 | ib_g=0.0 17 | ib_b=0.0 18 | ib_a=1.0 19 | 20 | per_frame_1=ib_r=0.7+0.4*sin(3*time); ib_g=0.7+0.4*sin(4*time); ib_b=0.7+0.4*sin(5*time); -------------------------------------------------------------------------------- /presets/104-continued-eqn.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// one per frame equation 3 | per_frame_1001=// test equation spanning two lines 4 | 5 | fDecay=0.98 6 | zoom=0 7 | rot=0.0 8 | warp=0.0 9 | ob_size=0.2 10 | ob_r=0.0 11 | ob_g=0.0 12 | ob_b=0.0 13 | ob_a=0.0 14 | ib_size=0.1 15 | ib_r=0.0 16 | ib_g=0.0 17 | ib_b=0.0 18 | ib_a=1.0 19 | 20 | per_frame_1=ib_r=0.7+0.4* 21 | per_frame_2= sin(3*time); -------------------------------------------------------------------------------- /presets/105-per_frame_init.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// one per frame equation 3 | per_frame_1001=// initialize user variable 4 | 5 | fDecay=0.98 6 | zoom=0 7 | rot=0.0 8 | warp=0.0 9 | ob_size=0.2 10 | ob_r=0.0 11 | ob_b=0.0 12 | ob_a=0.0 13 | ib_size=0.1 14 | ib_r=1.0 15 | ib_g=0.0 16 | ib_a=1.0 17 | 18 | per_frame_init_1=SPEED=10; 19 | 20 | per_frame_1=ib_r=0.7+0.4*sin(time*SPEED); 21 | -------------------------------------------------------------------------------- /presets/110-per_pixel.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | fDecay=0.980000 3 | fWarpScale=2.853000 4 | fZoomExponent=1.000000 5 | warp=0.000000 6 | sx=1.000000 7 | sy=1.000000 8 | ob_size=0.2 9 | ob_r=0.0 10 | ob_g=0.0 11 | ob_b=0.0 12 | ob_a=0.0 13 | ib_size=0.01 14 | ib_r=1.0 15 | ib_g=0.0 16 | ib_b=0.0 17 | ib_a=1.0 18 | 19 | per_frame_1=ib_r=0.7+0.4*sin(3*time); 20 | per_frame_2=ib_g=0.7+0.4*sin(4*time); 21 | per_frame_3=ib_b=0.7+0.4*sin(5*time); 22 | 23 | per_pixel_1=zoom=0.9615-rad*0.1; 24 | -------------------------------------------------------------------------------- /presets/200-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=0 Circle 4 | 5 | fDecay=0 6 | nWaveMode=0 7 | fZoomExponent=1.000000 8 | warp=0.000000 9 | wave_r=1 10 | wave_x=0.500000 11 | wave_y=0.500000 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /presets/201-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=1 RadialBlob 4 | 5 | fDecay=0 6 | nWaveMode=1 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 11 | -------------------------------------------------------------------------------- /presets/202-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=2 Blob2 4 | 5 | fDecay=0 6 | nWaveMode=2 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 -------------------------------------------------------------------------------- /presets/203-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=3 Blob3 4 | 5 | fDecay=0 6 | nWaveMode=3 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 11 | -------------------------------------------------------------------------------- /presets/204-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=4 DerivativeLine 4 | 5 | fDecay=0 6 | nWaveMode=4 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 -------------------------------------------------------------------------------- /presets/205-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=5 Blob5 4 | 5 | fDecay=0 6 | nWaveMode=5 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 11 | -------------------------------------------------------------------------------- /presets/206-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=6 Line 4 | 5 | fDecay=0 6 | nWaveMode=6 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 11 | -------------------------------------------------------------------------------- /presets/207-wave.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=7 DoubleLine 4 | 5 | fDecay=0 6 | nWaveMode=7 7 | warp=0.000000 8 | wave_r=1 9 | wave_x=0.500000 10 | wave_y=0.500000 11 | -------------------------------------------------------------------------------- /presets/210-wave-smooth-00.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=6 Line 4 | 5 | fDecay=0 6 | warp=0.000000 7 | wave_r=1 8 | 9 | // MilkdropWaveform 10 | nWaveMode=6 11 | fWaveSmoothing=0.00 12 | wave_x=0.600000 13 | wave_y=0.5 14 | 15 | // CustomWaveform 16 | wavecode_0_enabled=1 17 | wavecode_0_scaling=0.05 18 | wavecode_0_smoothing=0 19 | wavecode_0_r=0.000000 20 | wavecode_0_g=1.000000 21 | wavecode_0_b=1.000000 22 | wavecode_0_a=1.000000 23 | wavecode_0_x=0.5 24 | wavecode_0_y=0.4 25 | wave_0_per_point1=x=sample; 26 | wave_0_per_point2=y=y+value1; 27 | -------------------------------------------------------------------------------- /presets/210-wave-smooth-01.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=6 Line 4 | 5 | fDecay=0 6 | warp=0.000000 7 | wave_r=1 8 | 9 | // MilkdropWaveform 10 | nWaveMode=6 11 | fWaveSmoothing=0.01 12 | wave_x=0.600000 13 | wave_y=0.5 14 | 15 | // CustomWaveform 16 | wavecode_0_enabled=1 17 | wavecode_0_scaling=0.05 18 | wavecode_0_smoothing=0.01 19 | wavecode_0_r=0.000000 20 | wavecode_0_g=1.000000 21 | wavecode_0_b=1.000000 22 | wavecode_0_a=1.000000 23 | wavecode_0_x=0.5 24 | wavecode_0_y=0.4 25 | wave_0_per_point1=x=sample; 26 | wave_0_per_point2=y=y+value1; 27 | -------------------------------------------------------------------------------- /presets/210-wave-smooth-80.milk: -------------------------------------------------------------------------------- 1 | [preset00] 2 | per_frame_1000=// simple wave 3 | per_frame_1001=// MODE=6 Line 4 | 5 | fDecay=0 6 | warp=0.000000 7 | wave_r=1 8 | 9 | // MilkdropWaveform 10 | nWaveMode=6 11 | fWaveSmoothing=0.80 12 | wave_x=0.600000 13 | wave_y=0.5 14 | 15 | // CustomWaveform 16 | wavecode_0_enabled=1 17 | wavecode_0_scaling=0.05 18 | wavecode_0_smoothing=0.80 19 | wavecode_0_r=0.000000 20 | wavecode_0_g=1.000000 21 | wavecode_0_b=1.000000 22 | wavecode_0_a=1.000000 23 | wavecode_0_x=0.5 24 | wavecode_0_y=0.4 25 | wave_0_per_point1=x=sample; 26 | wave_0_per_point2=y=y+value1; 27 | -------------------------------------------------------------------------------- /projectm-sys/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.wasm32-unknown-emscripten] 2 | linker = ".cargo/linker-emscripten" -------------------------------------------------------------------------------- /projectm-sys/.cargo/linker-emscripten: -------------------------------------------------------------------------------- 1 | emcc "-s" "USE_SDL=2" \ 2 | "-s" "DISABLE_EXCEPTION_CATCHING=true" \ 3 | # "-s" "NO_DISABLE_EXCEPTION_CATCHING" \ 4 | "-s" "ERROR_ON_UNDEFINED_SYMBOLS=0" \ 5 | "-s" "NO_EXIT_RUNTIME=1" \ 6 | "-s" "MIN_WEBGL_VERSION=2" \ 7 | "-s" "MAX_WEBGL_VERSION=2" \ 8 | "-s" "FULL_ES2=1" \ 9 | "-s" "ALLOW_MEMORY_GROWTH=1" \ 10 | "-s" "MODULARIZE=1" \ 11 | "-s" "EXPORT_NAME=avPluginProjectM" \ 12 | "-s" "EXPORT_ES6=1" \ 13 | "-s" "EXIT_RUNTIME=1" \ 14 | "-s" "FORCE_FILESYSTEM" \ 15 | $@ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /projectm-sys/.github/workflows/build_emscripten.yml: -------------------------------------------------------------------------------- 1 | name: Emscripten 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: ubuntu-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Setup EMSDK 26 | uses: mymindstorm/setup-emsdk@v14 27 | with: 28 | # Make sure to set a version number! 29 | version: 3.1.27 30 | # This is the name of the cache folder. 31 | # The cache folder will be placed in the build directory, 32 | # so make sure it doesn't conflict with anything! 33 | actions-cache-folder: "emsdk-cache" 34 | 35 | - name: Verify EMSDK 36 | run: emcc -v 37 | 38 | - name: Install Packages 39 | run: | 40 | sudo apt-get update 41 | sudo apt-get install -y libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev llvm-dev 42 | 43 | - name: Update Local Toolchain 44 | run: | 45 | rustup update 46 | rustup component add clippy 47 | rustup target add wasm32-unknown-emscripten 48 | 49 | - name: Toolchain Info 50 | run: | 51 | cargo --version --verbose 52 | rustc --version 53 | cargo clippy --version 54 | 55 | - name: Lint 56 | run: | 57 | cargo fmt -- --check 58 | cargo clippy -- -D warnings 59 | 60 | - name: Run Tests 61 | run: | 62 | cargo check 63 | cargo test --all 64 | 65 | - name: Build Debug 66 | run: cargo build --target wasm32-unknown-emscripten 67 | -------------------------------------------------------------------------------- /projectm-sys/.github/workflows/build_linux.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu Linux (x86_64) 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: ubuntu-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Install Packages 26 | run: | 27 | sudo apt-get update 28 | sudo apt-get install -y libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev llvm-dev 29 | 30 | - name: Update Local Toolchain 31 | run: | 32 | rustup update 33 | rustup component add clippy 34 | 35 | - name: Toolchain Info 36 | run: | 37 | cargo --version --verbose 38 | rustc --version 39 | cargo clippy --version 40 | 41 | - name: Lint 42 | run: | 43 | cargo fmt -- --check 44 | cargo clippy -- -D warnings 45 | 46 | - name: Run Tests 47 | run: | 48 | cargo check 49 | cargo test --all 50 | 51 | - name: Build Debug 52 | run: cargo build 53 | -------------------------------------------------------------------------------- /projectm-sys/.github/workflows/build_osx.yml: -------------------------------------------------------------------------------- 1 | name: macOS (x86_64) 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: macos-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Update Local Toolchain 26 | run: | 27 | rustup update 28 | rustup component add clippy 29 | 30 | - name: Toolchain Info 31 | run: | 32 | cargo --version --verbose 33 | rustc --version 34 | cargo clippy --version 35 | 36 | - name: Lint 37 | run: | 38 | cargo fmt -- --check 39 | cargo clippy -- -D warnings 40 | 41 | - name: Run Tests 42 | run: | 43 | cargo check 44 | cargo test --all 45 | 46 | - name: Build Debug 47 | run: cargo build 48 | -------------------------------------------------------------------------------- /projectm-sys/.github/workflows/build_windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows (x64) 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | tags: 8 | - "*" 9 | 10 | pull_request: 11 | branches: 12 | - "*" 13 | 14 | jobs: 15 | build: 16 | name: Build & Test Rust Crate 17 | runs-on: windows-latest 18 | 19 | env: 20 | RUST_BACKTRACE: full 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Install Dependencies 26 | run: vcpkg --triplet=x64-windows-static-md install glew 27 | 28 | - name: Update Local Toolchain 29 | run: | 30 | rustup update 31 | rustup component add clippy 32 | 33 | - name: Toolchain Info 34 | run: | 35 | cargo --version --verbose 36 | rustc --version 37 | cargo clippy --version 38 | 39 | - name: Lint 40 | run: | 41 | cargo fmt -- --check 42 | cargo clippy -- -D warnings 43 | 44 | - name: Run Tests 45 | run: | 46 | cargo check 47 | cargo test --all 48 | 49 | - name: Build Debug 50 | run: cargo build 51 | 52 | -------------------------------------------------------------------------------- /projectm-sys/.github/workflows/publish_crate.yml: -------------------------------------------------------------------------------- 1 | name: Publish to crates.io 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | workflow_dispatch: 9 | 10 | jobs: 11 | publish: 12 | name: Publish 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Install Packages 19 | run: | 20 | sudo apt-get update 21 | sudo apt-get install -y libgl1-mesa-dev mesa-common-dev libsdl2-dev libglm-dev llvm-dev 22 | 23 | - name: Update Local Toolchain 24 | run: | 25 | rustup update 26 | rustup component add clippy 27 | 28 | - name: Toolchain Info 29 | run: | 30 | cargo --version --verbose 31 | rustc --version 32 | cargo clippy --version 33 | 34 | - name: Lint 35 | run: | 36 | cargo fmt -- --check 37 | cargo clippy -- -D warnings 38 | 39 | - name: Run Tests 40 | run: | 41 | cargo check 42 | cargo test --all 43 | 44 | - name: Publish 45 | env: 46 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 47 | run: | 48 | cargo publish --token $CARGO_REGISTRY_TOKEN -------------------------------------------------------------------------------- /projectm-sys/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /projectm-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "projectm-sys" 3 | version = "1.2.2" 4 | edition = "2021" 5 | rust-version = "1.65" 6 | authors = ["AnomieVision ", "Mischa Spiegelmock "] 7 | description = "Bindings for ProjectM" 8 | license = "LGPL-3.0-or-later" 9 | repository = "https://github.com/projectM-visualizer/projectm-rs" 10 | documentation = "https://docs.rs/projectm-sys/latest" 11 | keywords = ["visualization", "audio", "sound", "projectm"] 12 | categories = ["multimedia", "multimedia::video", "multimedia::audio"] 13 | readme = "README.md" 14 | links = "projectm" 15 | 16 | include = [ 17 | "src/**", 18 | "Cargo.toml", 19 | "build.rs", 20 | "README.md", 21 | "LICENSE", 22 | "build_bindgen.rs", 23 | "libprojectM/CMakeLists.txt", 24 | "libprojectM/src/**", 25 | "libprojectM/include/**", 26 | "libprojectM/presets/CMakeLists.txt", 27 | "libprojectM/cmake/**", 28 | "libprojectM/vendor/**", 29 | "libprojectM/vendor/projectm-eval/**", 30 | "libprojectM/vendor/**/CMakeLists.txt", 31 | "libprojectM/vendor/**/cmake/**", 32 | "libprojectM/**/*.cmake", 33 | "libprojectM/**/*.h", 34 | "libprojectM/**/*.hpp", 35 | "libprojectM/config*", 36 | "libprojectM/vcpkg*", 37 | "bindgen/**", 38 | ] 39 | 40 | [dependencies] 41 | 42 | [build-dependencies] 43 | cmake = "0.1.50" 44 | bindgen = "0.70.1" 45 | lazy_static = "1.4.0" 46 | 47 | [features] 48 | default = ["playlist"] 49 | playlist = [] 50 | static = [] 51 | 52 | -------------------------------------------------------------------------------- /projectm-sys/LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /projectm-sys/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | [![Contributors][contributors-shield]][contributors-url] 6 | [![Forks][forks-shield]][forks-url] 7 | [![Stargazers][stars-shield]][stars-url] 8 | [![Issues][issues-shield]][issues-url] 9 | [![MIT License][license-shield]][license-url] 10 | [![Crates.io][crates-shield]][crates-url] 11 | [![Downloads][crates-dl-shield]][crates-dl-url] 12 | [![Discord][discord-shield]][discord-url] 13 | 14 |
15 | 16 |

projectM-sys

17 | 18 |

19 | Rust bindings for ProjectM, built using Bindgen 20 |
21 |
22 | Docs 23 | · 24 | Example 25 | · 26 | Report Bug 27 | · 28 | Request Feature 29 |

30 |
31 | 32 |
33 | 34 | 35 |
36 | Table of Contents 37 |
    38 |
  1. 39 | Getting Started 40 | 43 |
  2. 44 |
  3. Usage
  4. 45 |
  5. Building
  6. 46 |
  7. Contributing
  8. 47 |
  9. License
  10. 48 |
  11. Support
  12. 49 |
  13. Contact
  14. 50 |
51 |
52 | 53 |
54 | 55 | 56 | ## Getting Started 57 | 58 | To get this crate up and running properly, you'll need to install some prerequisites. 59 | 60 | ### Prerequisites 61 | 62 | Depending on the OS/distribution and packaging system, libraries might be split into separate packages with binaries and 63 | development files. To build projectM, both binaries and development files need to be installed. 64 | 65 | #### General build dependencies for all platforms: 66 | 67 | * [**Rust**](https://www.rust-lang.org/tools/install) 68 | * A working build toolchain. 69 | * [**CMake**](https://cmake.org/): Used to generate platform-specific build files. 70 | * **OpenGL**: 3D graphics library. Used to render the visualizations. 71 | * or **GLES3**: OpenGL libraries for embedded systems, version 3. Required to build projectM on Android devices, 72 | Raspberry Pi, Emscripten and the Universal Windows Platform. 73 | * [**glm**](https://github.com/g-truc/glm): OpenGL Mathematics library. Optional, will use a bundled version with 74 | autotools or if not installed. 75 | * [**SDL2**](https://github.com/libsdl-org/SDL): Simple Directmedia Layer. Version 2.0.5 or higher is required to build 76 | the test UI. 77 | * [**LLVM**](https://llvm.org/): Low-Level Virtual Machine. Optional and **experimental**, used to speed up preset 78 | execution by leveraging the LLVM JIT compiler. 79 | 80 | #### Only relevant for Windows: 81 | 82 | * [**vcpkg**](https://github.com/microsoft/vcpkg): C++ Library Manager for Windows. _Optional_, but recommended to 83 | install the aforementioned library dependencies. 84 | * [**GLEW**](http://glew.sourceforge.net/): The OpenGL Extension Wrangler Library. Only required if using CMake to 85 | configure the build, the pre-created solutions use a bundled copy of GLEW. 86 |

(back to top)

87 | 88 | 89 | 90 | ## Usage 91 | 92 | ``` 93 | cargo.toml 94 | 95 | [dependencies] 96 | projectm-sys = { version = "1.0", features = [] } # Available features: playlist 97 | ``` 98 | 99 |

(back to top)

100 | 101 | 102 | 103 | ## Building 104 | 105 |
106 | 107 | ### Windows Platform 108 | To compile the ProjectM library from source, you are required to set the VCPKG_INSTALLATION_ROOT env variable. 109 | ```powershell 110 | # Powershell 111 | $Env:VCPKG_INSTALLATION_ROOT="C:\path\to\vcpkg"; cargo build 112 | ``` 113 | 114 |

(back to top)

115 | 116 | 117 | ## Contributing 118 | 119 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 120 | 121 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 122 | Don't forget to give the project a star! Thanks again! 123 | 124 | 1. Fork the Project 125 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 126 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 127 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 128 | 5. Open a Pull Request 129 | 130 |

(back to top)

131 | 132 | 133 | 134 | 135 | ## License 136 | 137 | Distributed under the LGPL-2.1 license. See `LICENSE` for more information. 138 | 139 |

(back to top)

140 | 141 | 142 | ## Support 143 | 144 | [![Discord][discord-shield]][discord-url] 145 | 146 |

(back to top)

147 | 148 | 149 | ## Contact 150 | 151 | Blaquewithaq (Discord: SoFloppy#1289) - [@anomievision](https://twitter.com/anomievision) - anomievision@gmail.com 152 | 153 |

(back to top)

154 | 155 | 156 | 157 | [contributors-shield]: https://img.shields.io/github/contributors/projectM-visualizer/projectm-sys.svg?style=for-the-badge 158 | [contributors-url]: https://github.com/projectM-visualizer/projectm-sys/graphs/contributors 159 | [forks-shield]: https://img.shields.io/github/forks/projectM-visualizer/projectm-sys.svg?style=for-the-badge 160 | [forks-url]: https://github.com/projectM-visualizer/projectm-sys/network/members 161 | [stars-shield]: https://img.shields.io/github/stars/projectM-visualizer/projectm-sys.svg?style=for-the-badge 162 | [stars-url]: https://github.com/projectM-visualizer/projectm-sys/stargazers 163 | [issues-shield]: https://img.shields.io/github/issues/projectM-visualizer/projectm-sys.svg?style=for-the-badge 164 | [issues-url]: https://github.com/projectM-visualizer/projectm-sys/issues 165 | [license-shield]: https://img.shields.io/github/license/projectM-visualizer/projectm-sys.svg?style=for-the-badge 166 | [license-url]: https://github.com/projectM-visualizer/projectm-sys/blob/master/LICENSE 167 | [crates-shield]: https://img.shields.io/crates/v/projectm-sys?style=for-the-badge 168 | [crates-url]: https://crates.io/crates/projectm-sys 169 | [crates-dl-shield]: https://img.shields.io/crates/d/projectm-sys?style=for-the-badge 170 | [crates-dl-url]: https://crates.io/crates/projectm-sys 171 | [discord-shield]: https://img.shields.io/discord/737206408482914387?style=for-the-badge 172 | [discord-url]: https://discord.gg/7fQXN43n9W 173 | -------------------------------------------------------------------------------- /projectm-sys/bindgen/default.h: -------------------------------------------------------------------------------- 1 | #include "projectM-4/projectM.h" -------------------------------------------------------------------------------- /projectm-sys/bindgen/playlist.h: -------------------------------------------------------------------------------- 1 | #include "projectM-4/projectM.h" 2 | #include "projectM-4/playlist.h" -------------------------------------------------------------------------------- /projectm-sys/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | 4 | mod build_bindgen; 5 | use crate::build_bindgen::bindgen; 6 | 7 | // Functions to determine feature flags 8 | fn enable_playlist() -> &'static str { 9 | if cfg!(feature = "playlist") { 10 | "ON" 11 | } else { 12 | "OFF" 13 | } 14 | } 15 | 16 | // Are we linking to shared or static libraries? 17 | fn build_shared_libs_flag() -> &'static str { 18 | if cfg!(feature = "static") { 19 | "OFF" // Disable shared libs to enable static linking 20 | } else { 21 | "ON" // Enable shared libs 22 | } 23 | } 24 | 25 | fn main() { 26 | // Path to the projectM source code 27 | let projectm_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("libprojectM"); 28 | 29 | // Verify the existence of the libprojectM directory 30 | if !projectm_path.exists() { 31 | println!("cargo:warning=The libprojectM source code is missing."); 32 | println!( 33 | "cargo:warning=If you are building from a git clone, please run 'git submodule update --init --recursive'." 34 | ); 35 | println!("cargo:warning=If you downloaded this crate from crates.io, please ensure that the crate was packaged correctly."); 36 | std::process::exit(1); 37 | } 38 | 39 | // Determine feature flags 40 | let enable_playlist_flag = enable_playlist(); 41 | let build_shared_libs = build_shared_libs_flag(); 42 | 43 | let dst; 44 | 45 | // Platform-specific CMake configurations 46 | if cfg!(target_os = "windows") { 47 | // Ensure VCPKG installation root is set 48 | let vcpkg_root = match env::var("VCPKG_INSTALLATION_ROOT") { 49 | Ok(val) => val, 50 | Err(_) => { 51 | println!("cargo:warning=VCPKG_INSTALLATION_ROOT is not set. Please set it to your VCPKG installation directory."); 52 | std::process::exit(1); 53 | } 54 | }; 55 | 56 | let vcpkg_root = PathBuf::from(vcpkg_root); 57 | let vcpkg_toolchain = vcpkg_root 58 | .join("scripts") 59 | .join("buildsystems") 60 | .join("vcpkg.cmake"); 61 | 62 | if !vcpkg_toolchain.exists() { 63 | println!( 64 | "cargo:warning=The vcpkg toolchain file was not found at: {}", 65 | vcpkg_toolchain.display() 66 | ); 67 | std::process::exit(1); 68 | } 69 | 70 | // Set VCPKG_ROOT for CMake 71 | env::set_var("VCPKG_ROOT", &vcpkg_root); 72 | 73 | // Define the installation path for vcpkg 74 | let vcpkg_installed = vcpkg_root.join("installed").join("x64-windows-static-md"); 75 | let vcpkg_installed_str = vcpkg_installed.to_str().unwrap(); 76 | 77 | // Define projectM_Eval_DIR and store in a variable 78 | let projectm_eval_dir = projectm_path.join("vendor").join("projectm-eval"); 79 | let projectm_eval_dir_str = projectm_eval_dir.to_str().unwrap(); 80 | 81 | // Convert vcpkg_toolchain to string 82 | let vcpkg_toolchain_str = vcpkg_toolchain.to_str().unwrap(); 83 | 84 | // Configure and build libprojectM using CMake for Windows 85 | let mut cmake_config = cmake::Config::new(&projectm_path); 86 | cmake_config 87 | .generator("Visual Studio 17 2022") 88 | .define("CMAKE_TOOLCHAIN_FILE", vcpkg_toolchain_str) 89 | .define("VCPKG_TARGET_TRIPLET", "x64-windows-static-md") 90 | .define( 91 | "CMAKE_MSVC_RUNTIME_LIBRARY", 92 | "MultiThreaded$<$:Debug>DLL", 93 | ) 94 | .define("ENABLE_PLAYLIST", enable_playlist_flag) 95 | .define("projectM_Eval_DIR", projectm_eval_dir_str) 96 | .define("CMAKE_PREFIX_PATH", vcpkg_installed_str) 97 | .define("CMAKE_VERBOSE_MAKEFILE", "ON") 98 | .define("BUILD_TESTING", "OFF") 99 | .define("BUILD_EXAMPLES", "OFF") 100 | .define("BUILD_SHARED_LIBS", build_shared_libs); // static/dynamic 101 | 102 | dst = cmake_config.build(); 103 | } else if cfg!(target_os = "emscripten") { 104 | // Configure and build libprojectM using CMake for Emscripten 105 | dst = cmake::Config::new(&projectm_path) 106 | .define("ENABLE_PLAYLIST", enable_playlist_flag) 107 | .define("BUILD_TESTING", "OFF") 108 | .define("BUILD_EXAMPLES", "OFF") 109 | .define("ENABLE_EMSCRIPTEN", "ON") 110 | .define("BUILD_SHARED_LIBS", build_shared_libs) // static/dynamic 111 | .build(); 112 | } else { 113 | // Configure and build libprojectM using CMake for other platforms (Linux, macOS) 114 | dst = cmake::Config::new(&projectm_path) 115 | .define("ENABLE_PLAYLIST", enable_playlist_flag) 116 | .define("BUILD_TESTING", "OFF") 117 | .define("BUILD_EXAMPLES", "OFF") 118 | .define("BUILD_SHARED_LIBS", build_shared_libs) // static/dynamic 119 | .build(); 120 | } 121 | 122 | // Specify the library search path 123 | println!("cargo:rustc-link-search=native={}/lib", dst.display()); 124 | 125 | // Determine the build profile (release or debug) 126 | let profile = env::var("PROFILE").unwrap_or_else(|_| "release".to_string()); 127 | 128 | // Platform and feature-specific library linking 129 | if cfg!(target_os = "windows") || cfg!(target_os = "emscripten") { 130 | // Static or Dynamic linking based on 'static' feature 131 | if cfg!(feature = "static") { 132 | if profile == "release" { 133 | println!("cargo:rustc-link-lib=static=projectM-4"); 134 | if cfg!(feature = "playlist") { 135 | println!("cargo:rustc-link-lib=static=projectM-4-playlist"); 136 | } 137 | } else { 138 | println!("cargo:rustc-link-lib=static=projectM-4d"); 139 | if cfg!(feature = "playlist") { 140 | println!("cargo:rustc-link-lib=static=projectM-4-playlistd"); 141 | } 142 | } 143 | } else { 144 | if profile == "release" { 145 | println!("cargo:rustc-link-lib=dylib=projectM-4"); 146 | if cfg!(feature = "playlist") { 147 | println!("cargo:rustc-link-lib=dylib=projectM-4-playlist"); 148 | } 149 | } else { 150 | println!("cargo:rustc-link-lib=dylib=projectM-4d"); 151 | if cfg!(feature = "playlist") { 152 | println!("cargo:rustc-link-lib=dylib=projectM-4-playlistd"); 153 | } 154 | } 155 | } 156 | } else { 157 | // For other platforms (Linux, macOS) 158 | if cfg!(feature = "static") { 159 | if profile == "release" { 160 | println!("cargo:rustc-link-lib=static=projectM-4"); 161 | if cfg!(feature = "playlist") { 162 | println!("cargo:rustc-link-lib=static=projectM-4-playlist"); 163 | } 164 | } else { 165 | println!("cargo:rustc-link-lib=static=projectM-4d"); 166 | if cfg!(feature = "playlist") { 167 | println!("cargo:rustc-link-lib=static=projectM-4-playlistd"); 168 | } 169 | } 170 | } else { 171 | if profile == "release" { 172 | println!("cargo:rustc-link-lib=dylib=projectM-4"); 173 | if cfg!(feature = "playlist") { 174 | println!("cargo:rustc-link-lib=dylib=projectM-4-playlist"); 175 | } 176 | } else { 177 | println!("cargo:rustc-link-lib=dylib=projectM-4d"); 178 | if cfg!(feature = "playlist") { 179 | println!("cargo:rustc-link-lib=dylib=projectM-4-playlistd"); 180 | } 181 | } 182 | } 183 | } 184 | 185 | // Platform-specific link flags for C++ and OpenGL 186 | #[cfg(target_os = "macos")] 187 | { 188 | println!("cargo:rustc-link-lib=c++"); 189 | println!("cargo:rustc-link-lib=framework=OpenGL"); 190 | } 191 | #[cfg(target_os = "linux")] 192 | { 193 | // On Linux, link stdc++ and GL. 194 | println!("cargo:rustc-link-lib=stdc++"); 195 | println!("cargo:rustc-link-lib=GL"); 196 | println!("cargo:rustc-link-lib=gomp"); 197 | } 198 | #[cfg(target_os = "windows")] 199 | { 200 | println!("cargo:rustc-link-lib=opengl32"); 201 | } 202 | #[cfg(target_os = "emscripten")] 203 | { 204 | // Emscripten typically handles GL calls differently, so you might skip or rely on the 205 | // emscripten compiler for linking. 206 | } 207 | 208 | // Generate Rust bindings using bindgen 209 | bindgen(); 210 | } 211 | -------------------------------------------------------------------------------- /projectm-sys/build_bindgen.rs: -------------------------------------------------------------------------------- 1 | use std::{env, path::PathBuf}; 2 | 3 | pub fn bindgen() { 4 | println!("cargo:rerun-if-changed=wrapper.h"); 5 | 6 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); 7 | let out_path = out_dir.join("bindings.rs"); 8 | 9 | fn get_header() -> String { 10 | if cfg!(feature = "playlist") { 11 | "bindgen/playlist.h".to_string() 12 | } else { 13 | "bindgen/default.h".to_string() 14 | } 15 | } 16 | 17 | let bindings = bindgen::Builder::default() 18 | .header(get_header()) 19 | .allowlist_function("projectm_.*") 20 | .clang_arg(format!("-I{}/include", out_dir.display())) 21 | .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) 22 | .generate() 23 | .expect("Unable to generate bindings"); 24 | 25 | bindings 26 | .write_to_file(out_path) 27 | .expect("Couldn't write bindings!"); 28 | } 29 | -------------------------------------------------------------------------------- /projectm-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | 5 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 6 | -------------------------------------------------------------------------------- /src/core.rs: -------------------------------------------------------------------------------- 1 | //! ProjectM for Rust 2 | //! 3 | //! This library contains bindings to libprojectm. Its purpose 4 | //! is to read an audio input and to produce mesmerizing visuals 5 | //! by detecting tempo, and rendering advanced equations into a 6 | //! limitless array of user-contributed visualizations. 7 | //! 8 | //! # Example 9 | //! 10 | // ! use projectm_rs::core::*; 11 | // ! 12 | // ! let ProjectMHandle = Projectm::create(); 13 | //! 14 | 15 | extern crate libc; 16 | extern crate projectm_sys as ffi; 17 | 18 | use std::cell::RefCell; 19 | use std::ffi::CString; 20 | use std::rc::Rc; 21 | 22 | pub type ProjectMHandle = *mut ffi::projectm; 23 | 24 | pub type ProjectMChannels = u32; 25 | pub const MONO: ProjectMChannels = 1; 26 | pub const STEREO: ProjectMChannels = 2; 27 | 28 | pub type ProjectMTouchType = u32; 29 | pub const TOUCH_TYPE_RANDOM: ProjectMTouchType = 0; 30 | pub const TOUCH_TYPE_CIRCLE: ProjectMTouchType = 1; 31 | pub const TOUCH_TYPE_RADIAL_BLOB: ProjectMTouchType = 2; 32 | pub const TOUCH_TYPE_BLOB2: ProjectMTouchType = 3; 33 | pub const TOUCH_TYPE_BLOB3: ProjectMTouchType = 4; 34 | pub const TOUCH_TYPE_DERIVATIVE_LINE: ProjectMTouchType = 5; 35 | pub const TOUCH_TYPE_BLOB5: ProjectMTouchType = 6; 36 | pub const TOUCH_TYPE_LINE: ProjectMTouchType = 7; 37 | pub const TOUCH_TYPE_DOUBLE_LINE: ProjectMTouchType = 8; 38 | 39 | struct Projectm {} 40 | 41 | impl Projectm { 42 | // ----------------- 43 | // Core 44 | // ----------------- 45 | 46 | fn create() -> *mut ffi::projectm { 47 | unsafe { ffi::projectm_create() } 48 | } 49 | 50 | fn destroy(instance: ProjectMHandle) { 51 | unsafe { ffi::projectm_destroy(instance) }; 52 | } 53 | 54 | fn load_preset_file(instance: ProjectMHandle, filename: &str, smooth_transition: bool) { 55 | unsafe { 56 | ffi::projectm_load_preset_file( 57 | instance, 58 | filename.as_ptr() as *mut i8, 59 | smooth_transition, 60 | ) 61 | }; 62 | } 63 | 64 | fn load_preset_data(instance: ProjectMHandle, data: &str, smooth_transition: bool) { 65 | unsafe { 66 | ffi::projectm_load_preset_data(instance, data.as_ptr() as *mut i8, smooth_transition) 67 | }; 68 | } 69 | 70 | fn reset_textures(instance: ProjectMHandle) { 71 | unsafe { ffi::projectm_reset_textures(instance) }; 72 | } 73 | 74 | fn get_version_components() -> (i32, i32, i32) { 75 | #[derive(Debug, Default, Copy, Clone)] 76 | #[repr(C, packed)] 77 | struct Version { 78 | major: i32, 79 | minor: i32, 80 | patch: i32, 81 | } 82 | 83 | let mut version = Version::default(); 84 | 85 | unsafe { 86 | ffi::projectm_get_version_components( 87 | std::ptr::addr_of_mut!(version.major), 88 | std::ptr::addr_of_mut!(version.minor), 89 | std::ptr::addr_of_mut!(version.patch), 90 | ); 91 | } 92 | 93 | (version.major, version.minor, version.patch) 94 | } 95 | 96 | fn get_version_string() -> String { 97 | let get_version = unsafe { ffi::projectm_get_version_string() }; 98 | let version_str = unsafe { std::ffi::CStr::from_ptr(get_version) }; 99 | let version_str_slice = version_str.to_str().unwrap(); 100 | let version = version_str_slice.to_owned(); 101 | 102 | unsafe { ffi::projectm_free_string(get_version) }; 103 | 104 | version 105 | } 106 | 107 | fn get_vcs_version_string() -> String { 108 | let get_vcs_version = unsafe { ffi::projectm_get_vcs_version_string() }; 109 | let vcs_version_str = unsafe { std::ffi::CStr::from_ptr(get_vcs_version) }; 110 | let vcs_version_str_slice = vcs_version_str.to_str().unwrap(); 111 | let vcs_version = vcs_version_str_slice.to_owned(); 112 | 113 | unsafe { ffi::projectm_free_string(get_vcs_version) }; 114 | 115 | vcs_version 116 | } 117 | 118 | // ----------------- 119 | // Callbacks 120 | // ----------------- 121 | 122 | fn set_preset_switch_requested_event_callback( 123 | instance: ProjectMHandle, 124 | callback: F, 125 | ) { 126 | unsafe extern "C" fn trampoline( 127 | is_hard_cut: bool, 128 | user_data: *mut std::os::raw::c_void, 129 | ) { 130 | unsafe { (*user_data.cast::())(is_hard_cut) } 131 | } 132 | unsafe { 133 | ffi::projectm_set_preset_switch_requested_event_callback( 134 | instance, 135 | Some(trampoline::), 136 | (Box::leak(Box::new(callback)) as *mut F).cast::(), 137 | ) 138 | } 139 | } 140 | 141 | fn set_preset_switch_failed_event_callback( 142 | instance: ProjectMHandle, 143 | callback: F, 144 | ) { 145 | unsafe extern "C" fn trampoline( 146 | preset_filename: *const i8, 147 | message: *const i8, 148 | user_data: *mut std::os::raw::c_void, 149 | ) { 150 | let preset_filename_str = unsafe { std::ffi::CStr::from_ptr(preset_filename) }; 151 | let preset_filename_str_slice = preset_filename_str.to_str().unwrap(); 152 | let preset_filename = preset_filename_str_slice.to_owned(); 153 | 154 | let message_str = unsafe { std::ffi::CStr::from_ptr(message) }; 155 | let message_str_slice = message_str.to_str().unwrap(); 156 | let message = message_str_slice.to_owned(); 157 | unsafe { (*user_data.cast::())(preset_filename, message) } 158 | } 159 | unsafe { 160 | ffi::projectm_set_preset_switch_failed_event_callback( 161 | instance, 162 | Some(trampoline::), 163 | (Box::leak(Box::new(callback)) as *mut F).cast::(), 164 | ) 165 | } 166 | } 167 | 168 | // ----------------- 169 | // Parameters 170 | // ----------------- 171 | 172 | fn set_texture_search_paths( 173 | instance: ProjectMHandle, 174 | texture_search_paths: &[String], 175 | count: usize, 176 | ) { 177 | let texture_search_paths_cstr: Vec<_> = texture_search_paths 178 | .iter() 179 | .map(|arg| CString::new(arg.as_str()).unwrap()) 180 | .collect(); 181 | 182 | let mut texture_search_paths_pointer: Vec<_> = texture_search_paths_cstr 183 | .iter() 184 | .map(|arg| arg.as_ptr()) 185 | .collect(); 186 | 187 | texture_search_paths_pointer.push(std::ptr::null()); 188 | 189 | unsafe { 190 | ffi::projectm_set_texture_search_paths( 191 | instance, 192 | texture_search_paths_pointer.as_ptr() as *mut *const ::std::os::raw::c_char, 193 | count, 194 | ) 195 | }; 196 | } 197 | 198 | fn get_beat_sensitivity(instance: ProjectMHandle) -> f32 { 199 | unsafe { ffi::projectm_get_beat_sensitivity(instance) } 200 | } 201 | 202 | fn set_beat_sensitivity(instance: ProjectMHandle, sensitivity: f32) { 203 | unsafe { ffi::projectm_set_beat_sensitivity(instance, sensitivity) }; 204 | } 205 | 206 | fn get_hard_cut_duration(instance: ProjectMHandle) -> f64 { 207 | unsafe { ffi::projectm_get_hard_cut_duration(instance) } 208 | } 209 | 210 | fn set_hard_cut_duration(instance: ProjectMHandle, seconds: f64) { 211 | unsafe { ffi::projectm_set_hard_cut_duration(instance, seconds) }; 212 | } 213 | 214 | fn get_hard_cut_enabled(instance: ProjectMHandle) -> bool { 215 | unsafe { ffi::projectm_get_hard_cut_enabled(instance) } 216 | } 217 | 218 | fn set_hard_cut_enabled(instance: ProjectMHandle, enabled: bool) { 219 | unsafe { ffi::projectm_set_hard_cut_enabled(instance, enabled) } 220 | } 221 | 222 | fn get_hard_cut_sensitivity(instance: ProjectMHandle) -> f32 { 223 | unsafe { ffi::projectm_get_hard_cut_sensitivity(instance) } 224 | } 225 | 226 | fn set_hard_cut_sensitivity(instance: ProjectMHandle, sensitivity: f32) { 227 | unsafe { ffi::projectm_set_hard_cut_sensitivity(instance, sensitivity) } 228 | } 229 | 230 | fn get_soft_cut_duration(instance: ProjectMHandle) -> f64 { 231 | unsafe { ffi::projectm_get_soft_cut_duration(instance) } 232 | } 233 | 234 | fn set_soft_cut_duration(instance: ProjectMHandle, seconds: f64) { 235 | unsafe { ffi::projectm_set_soft_cut_duration(instance, seconds) } 236 | } 237 | 238 | fn get_preset_duration(instance: ProjectMHandle) -> f64 { 239 | unsafe { ffi::projectm_get_preset_duration(instance) } 240 | } 241 | 242 | fn set_preset_duration(instance: ProjectMHandle, seconds: f64) { 243 | unsafe { ffi::projectm_set_preset_duration(instance, seconds) } 244 | } 245 | 246 | fn get_mesh_size(instance: ProjectMHandle) -> (usize, usize) { 247 | #[derive(Debug, Default, Copy, Clone)] 248 | #[repr(C, packed)] 249 | struct Mesh { 250 | mesh_x: usize, 251 | mesh_y: usize, 252 | } 253 | 254 | let mut mesh = Mesh::default(); 255 | 256 | unsafe { 257 | ffi::projectm_get_mesh_size( 258 | instance, 259 | std::ptr::addr_of_mut!(mesh.mesh_x), 260 | std::ptr::addr_of_mut!(mesh.mesh_y), 261 | ); 262 | } 263 | 264 | (mesh.mesh_x, mesh.mesh_y) 265 | } 266 | 267 | fn set_mesh_size(instance: ProjectMHandle, mesh_x: usize, mesh_y: usize) { 268 | unsafe { 269 | ffi::projectm_set_mesh_size(instance, mesh_x, mesh_y); 270 | } 271 | } 272 | 273 | fn get_fps(instance: ProjectMHandle) -> u32 { 274 | unsafe { ffi::projectm_get_fps(instance).try_into().unwrap() } 275 | } 276 | 277 | // FIXME: shouldn't it also be a usize? 278 | fn set_fps(instance: ProjectMHandle, fps: u32) { 279 | unsafe { ffi::projectm_set_fps(instance, fps as i32) }; 280 | } 281 | 282 | fn get_aspect_correction(instance: ProjectMHandle) -> bool { 283 | unsafe { ffi::projectm_get_aspect_correction(instance) } 284 | } 285 | 286 | fn set_aspect_correction(instance: ProjectMHandle, enabled: bool) { 287 | unsafe { ffi::projectm_set_aspect_correction(instance, enabled) }; 288 | } 289 | 290 | fn get_easter_egg(instance: ProjectMHandle) -> f32 { 291 | unsafe { ffi::projectm_get_easter_egg(instance) } 292 | } 293 | 294 | fn set_easter_egg(instance: ProjectMHandle, sensitivity: f32) { 295 | unsafe { ffi::projectm_set_easter_egg(instance, sensitivity) }; 296 | } 297 | 298 | fn get_preset_locked(instance: ProjectMHandle) -> bool { 299 | unsafe { ffi::projectm_get_preset_locked(instance) } 300 | } 301 | 302 | fn set_preset_locked(instance: ProjectMHandle, lock: bool) { 303 | unsafe { ffi::projectm_set_preset_locked(instance, lock) }; 304 | } 305 | 306 | fn get_window_size(instance: ProjectMHandle) -> (usize, usize) { 307 | #[derive(Debug, Default, Copy, Clone)] 308 | #[repr(C, packed)] 309 | struct Mesh { 310 | width: usize, 311 | height: usize, 312 | } 313 | 314 | let mut window = Mesh::default(); 315 | 316 | unsafe { 317 | ffi::projectm_get_window_size( 318 | instance, 319 | std::ptr::addr_of_mut!(window.width), 320 | std::ptr::addr_of_mut!(window.height), 321 | ); 322 | } 323 | 324 | (window.width, window.height) 325 | } 326 | 327 | fn set_window_size(instance: ProjectMHandle, width: usize, height: usize) { 328 | unsafe { ffi::projectm_set_window_size(instance, width, height) }; 329 | } 330 | 331 | // ----------------- 332 | // Render OpenGL 333 | // ----------------- 334 | 335 | fn render_frame(instance: ProjectMHandle) { 336 | unsafe { ffi::projectm_opengl_render_frame(instance) }; 337 | } 338 | 339 | // ----------------- 340 | // Touch 341 | // ----------------- 342 | 343 | fn touch( 344 | instance: ProjectMHandle, 345 | x: f32, 346 | y: f32, 347 | pressure: i32, 348 | touch_type: ProjectMTouchType, 349 | ) { 350 | unsafe { ffi::projectm_touch(instance, x, y, pressure, touch_type.try_into().unwrap()) }; 351 | } 352 | 353 | fn touch_drag(instance: ProjectMHandle, x: f32, y: f32, pressure: i32) { 354 | unsafe { ffi::projectm_touch_drag(instance, x, y, pressure) }; 355 | } 356 | 357 | fn touch_destroy(instance: ProjectMHandle, x: f32, y: f32) { 358 | unsafe { ffi::projectm_touch_destroy(instance, x, y) }; 359 | } 360 | 361 | fn touch_destroy_all(instance: ProjectMHandle) { 362 | unsafe { ffi::projectm_touch_destroy_all(instance) }; 363 | } 364 | 365 | // ----------------- 366 | // Audio 367 | // ----------------- 368 | 369 | fn pcm_get_max_samples() -> u32 { 370 | unsafe { ffi::projectm_pcm_get_max_samples() } 371 | } 372 | 373 | fn pcm_add_float(instance: ProjectMHandle, samples: &[f32], channels: ProjectMChannels) { 374 | assert!( 375 | samples.len() <= Self::pcm_get_max_samples() as usize, 376 | "Number of samples is greater than max samples" 377 | ); 378 | let samples_per_channel = samples.len() / channels as usize; 379 | unsafe { 380 | ffi::projectm_pcm_add_float( 381 | instance, 382 | samples.as_ptr(), 383 | samples_per_channel as u32, 384 | channels.try_into().unwrap(), 385 | ) 386 | } 387 | } 388 | 389 | fn pcm_add_int16(instance: ProjectMHandle, samples: &[i16], channels: ProjectMChannels) { 390 | assert!( 391 | samples.len() <= Self::pcm_get_max_samples() as usize, 392 | "Number of samples is greater than max samples" 393 | ); 394 | let samples_per_channel = samples.len() / channels as usize; 395 | unsafe { 396 | ffi::projectm_pcm_add_int16( 397 | instance, 398 | samples.as_ptr(), 399 | samples_per_channel as u32, 400 | channels.try_into().unwrap(), 401 | ) 402 | } 403 | } 404 | 405 | fn pcm_add_uint8(instance: ProjectMHandle, samples: &[u8], channels: ProjectMChannels) { 406 | assert!( 407 | samples.len() <= Self::pcm_get_max_samples() as usize, 408 | "Number of samples is greater than max samples" 409 | ); 410 | let samples_per_channel = samples.len() / channels as usize; 411 | unsafe { 412 | ffi::projectm_pcm_add_uint8( 413 | instance, 414 | samples.as_ptr(), 415 | samples_per_channel as u32, 416 | channels.try_into().unwrap(), 417 | ) 418 | } 419 | } 420 | 421 | // ----------------- 422 | // Debug 423 | // ----------------- 424 | 425 | fn write_debug_image_on_next_frame(instance: ProjectMHandle, output_file: Option<&String>) { 426 | // Transform the Rust String into a C String - this is needed due to the 427 | // fact that Rust Strings are not null terminated. 428 | let path = output_file.map(|p| { 429 | CString::new(p.as_str()) 430 | .expect("Provided output file path could not be converted to a C string") 431 | }); 432 | 433 | // `path` will be alive until the end of the scope, so we can safely get 434 | // a pointer to it. 435 | let ptr = path 436 | .as_ref() 437 | .map(|s| s.as_ptr()) 438 | .unwrap_or(std::ptr::null()); 439 | 440 | unsafe { ffi::projectm_write_debug_image_on_next_frame(instance, ptr) }; 441 | } 442 | } 443 | 444 | pub struct ProjectM { 445 | instance: Rc>, 446 | } 447 | 448 | impl ProjectM { 449 | pub fn create() -> Self { 450 | let instance = Rc::new(RefCell::new(Projectm::create())); 451 | 452 | ProjectM { instance } 453 | } 454 | 455 | pub fn destroy(&self) { 456 | if let Ok(instance) = self.instance.try_borrow() { 457 | let _ = &Projectm::destroy(*instance); 458 | } else { 459 | panic!("Failed to borrow instance"); 460 | } 461 | } 462 | 463 | pub fn load_preset_file(&self, filename: &str, smooth_transition: bool) { 464 | if let Ok(instance) = self.instance.try_borrow() { 465 | Projectm::load_preset_file(*instance, filename, smooth_transition); 466 | } else { 467 | panic!("Failed to borrow instance"); 468 | } 469 | } 470 | 471 | pub fn load_preset_data(&self, data: &str, smooth_transition: bool) { 472 | if let Ok(instance) = self.instance.try_borrow() { 473 | Projectm::load_preset_data(*instance, data, smooth_transition); 474 | } else { 475 | panic!("Failed to borrow instance"); 476 | } 477 | } 478 | 479 | pub fn reset_textures(&self) { 480 | if let Ok(instance) = self.instance.try_borrow() { 481 | Projectm::reset_textures(*instance); 482 | } else { 483 | panic!("Failed to borrow instance"); 484 | } 485 | } 486 | 487 | pub fn get_version_components() -> (i32, i32, i32) { 488 | Projectm::get_version_components() 489 | } 490 | 491 | pub fn get_version_string() -> String { 492 | Projectm::get_version_string() 493 | } 494 | 495 | pub fn get_vcs_version_string() -> String { 496 | Projectm::get_vcs_version_string() 497 | } 498 | 499 | pub fn set_preset_switch_requested_event_callback( 500 | &self, 501 | callback: F, 502 | ) { 503 | if let Ok(instance) = self.instance.try_borrow() { 504 | Projectm::set_preset_switch_requested_event_callback(*instance, callback); 505 | } else { 506 | panic!("Failed to borrow instance"); 507 | } 508 | } 509 | 510 | pub fn set_preset_switch_failed_event_callback( 511 | &self, 512 | callback: F, 513 | ) { 514 | if let Ok(instance) = self.instance.try_borrow() { 515 | Projectm::set_preset_switch_failed_event_callback(*instance, callback); 516 | } else { 517 | panic!("Failed to borrow instance"); 518 | } 519 | } 520 | 521 | pub fn set_texture_search_paths(&self, texture_search_paths: &[String], count: usize) { 522 | if let Ok(instance) = self.instance.try_borrow() { 523 | Projectm::set_texture_search_paths(*instance, texture_search_paths, count); 524 | } else { 525 | panic!("Failed to borrow instance"); 526 | } 527 | } 528 | 529 | pub fn get_beat_sensitivity(&self) -> f32 { 530 | if let Ok(instance) = self.instance.try_borrow() { 531 | Projectm::get_beat_sensitivity(*instance) 532 | } else { 533 | panic!("Failed to borrow instance"); 534 | } 535 | } 536 | 537 | pub fn set_beat_sensitivity(&self, sensitivity: f32) { 538 | if let Ok(instance) = self.instance.try_borrow() { 539 | Projectm::set_beat_sensitivity(*instance, sensitivity); 540 | } else { 541 | panic!("Failed to borrow instance"); 542 | } 543 | } 544 | 545 | pub fn get_hard_cut_duration(&self) -> f64 { 546 | if let Ok(instance) = self.instance.try_borrow() { 547 | Projectm::get_hard_cut_duration(*instance) 548 | } else { 549 | panic!("Failed to borrow instance"); 550 | } 551 | } 552 | 553 | pub fn set_hard_cut_duration(&self, seconds: f64) { 554 | if let Ok(instance) = self.instance.try_borrow() { 555 | Projectm::set_hard_cut_duration(*instance, seconds); 556 | } else { 557 | panic!("Failed to borrow instance"); 558 | } 559 | } 560 | 561 | pub fn get_hard_cut_enabled(&self) -> bool { 562 | if let Ok(instance) = self.instance.try_borrow() { 563 | Projectm::get_hard_cut_enabled(*instance) 564 | } else { 565 | panic!("Failed to borrow instance"); 566 | } 567 | } 568 | 569 | pub fn set_hard_cut_enabled(&self, enabled: bool) { 570 | if let Ok(instance) = self.instance.try_borrow() { 571 | Projectm::set_hard_cut_enabled(*instance, enabled); 572 | } else { 573 | panic!("Failed to borrow instance"); 574 | } 575 | } 576 | 577 | pub fn get_hard_cut_sensitivity(&self) -> f32 { 578 | if let Ok(instance) = self.instance.try_borrow() { 579 | Projectm::get_hard_cut_sensitivity(*instance) 580 | } else { 581 | panic!("Failed to borrow instance"); 582 | } 583 | } 584 | 585 | pub fn set_hard_cut_sensitivity(&self, sensitivity: f32) { 586 | if let Ok(instance) = self.instance.try_borrow() { 587 | Projectm::set_hard_cut_sensitivity(*instance, sensitivity); 588 | } else { 589 | panic!("Failed to borrow instance"); 590 | } 591 | } 592 | 593 | pub fn get_soft_cut_duration(&self) -> f64 { 594 | if let Ok(instance) = self.instance.try_borrow() { 595 | Projectm::get_soft_cut_duration(*instance) 596 | } else { 597 | panic!("Failed to borrow instance"); 598 | } 599 | } 600 | 601 | pub fn set_soft_cut_duration(&self, seconds: f64) { 602 | if let Ok(instance) = self.instance.try_borrow() { 603 | Projectm::set_soft_cut_duration(*instance, seconds); 604 | } else { 605 | panic!("Failed to borrow instance"); 606 | } 607 | } 608 | 609 | pub fn get_preset_duration(&self) -> f64 { 610 | if let Ok(instance) = self.instance.try_borrow() { 611 | Projectm::get_preset_duration(*instance) 612 | } else { 613 | panic!("Failed to borrow instance"); 614 | } 615 | } 616 | 617 | pub fn set_preset_duration(&self, seconds: f64) { 618 | if let Ok(instance) = self.instance.try_borrow() { 619 | Projectm::set_preset_duration(*instance, seconds); 620 | } else { 621 | panic!("Failed to borrow instance"); 622 | } 623 | } 624 | 625 | pub fn get_mesh_size(&self) -> (usize, usize) { 626 | if let Ok(instance) = self.instance.try_borrow() { 627 | Projectm::get_mesh_size(*instance) 628 | } else { 629 | panic!("Failed to borrow instance"); 630 | } 631 | } 632 | 633 | pub fn set_mesh_size(&self, mesh_x: usize, mesh_y: usize) { 634 | if let Ok(instance) = self.instance.try_borrow() { 635 | Projectm::set_mesh_size(*instance, mesh_x, mesh_y); 636 | } else { 637 | panic!("Failed to borrow instance"); 638 | } 639 | } 640 | 641 | pub fn get_fps(&self) -> u32 { 642 | if let Ok(instance) = self.instance.try_borrow() { 643 | Projectm::get_fps(*instance) 644 | } else { 645 | panic!("Failed to borrow instance"); 646 | } 647 | } 648 | 649 | pub fn set_fps(&self, fps: u32) { 650 | if let Ok(instance) = self.instance.try_borrow() { 651 | Projectm::set_fps(*instance, fps); 652 | } else { 653 | panic!("Failed to borrow instance"); 654 | } 655 | } 656 | 657 | pub fn get_aspect_correction(&self) -> bool { 658 | if let Ok(instance) = self.instance.try_borrow() { 659 | Projectm::get_aspect_correction(*instance) 660 | } else { 661 | panic!("Failed to borrow instance"); 662 | } 663 | } 664 | 665 | pub fn set_aspect_correction(&self, enabled: bool) { 666 | if let Ok(instance) = self.instance.try_borrow() { 667 | Projectm::set_aspect_correction(*instance, enabled); 668 | } else { 669 | panic!("Failed to borrow instance"); 670 | } 671 | } 672 | 673 | pub fn get_easter_egg(&self) -> f32 { 674 | if let Ok(instance) = self.instance.try_borrow() { 675 | Projectm::get_easter_egg(*instance) 676 | } else { 677 | panic!("Failed to borrow instance"); 678 | } 679 | } 680 | 681 | pub fn set_easter_egg(&self, sensitivity: f32) { 682 | if let Ok(instance) = self.instance.try_borrow() { 683 | Projectm::set_easter_egg(*instance, sensitivity); 684 | } else { 685 | panic!("Failed to borrow instance"); 686 | } 687 | } 688 | 689 | pub fn get_preset_locked(&self) -> bool { 690 | if let Ok(instance) = self.instance.try_borrow() { 691 | Projectm::get_preset_locked(*instance) 692 | } else { 693 | panic!("Failed to borrow instance"); 694 | } 695 | } 696 | 697 | pub fn set_preset_locked(&self, lock: bool) { 698 | if let Ok(instance) = self.instance.try_borrow() { 699 | Projectm::set_preset_locked(*instance, lock); 700 | } else { 701 | panic!("Failed to borrow instance"); 702 | } 703 | } 704 | 705 | pub fn get_window_size(&self) -> (usize, usize) { 706 | if let Ok(instance) = self.instance.try_borrow() { 707 | Projectm::get_window_size(*instance) 708 | } else { 709 | panic!("Failed to borrow instance"); 710 | } 711 | } 712 | 713 | pub fn set_window_size(&self, width: usize, height: usize) { 714 | if let Ok(instance) = self.instance.try_borrow() { 715 | Projectm::set_window_size(*instance, width, height); 716 | } else { 717 | panic!("Failed to borrow instance"); 718 | } 719 | } 720 | 721 | pub fn render_frame(&self) { 722 | if let Ok(instance) = self.instance.try_borrow() { 723 | Projectm::render_frame(*instance); 724 | } else { 725 | panic!("Failed to borrow instance"); 726 | } 727 | } 728 | 729 | pub fn touch(&self, x: f32, y: f32, pressure: i32, touch_type: ProjectMTouchType) { 730 | if let Ok(instance) = self.instance.try_borrow() { 731 | Projectm::touch(*instance, x, y, pressure, touch_type); 732 | } else { 733 | panic!("Failed to borrow instance"); 734 | } 735 | } 736 | 737 | pub fn touch_drag(&self, x: f32, y: f32, pressure: i32) { 738 | if let Ok(instance) = self.instance.try_borrow() { 739 | Projectm::touch_drag(*instance, x, y, pressure); 740 | } else { 741 | panic!("Failed to borrow instance"); 742 | } 743 | } 744 | 745 | pub fn touch_destroy(&self, x: f32, y: f32) { 746 | if let Ok(instance) = self.instance.try_borrow() { 747 | Projectm::touch_destroy(*instance, x, y); 748 | } else { 749 | panic!("Failed to borrow instance"); 750 | } 751 | } 752 | 753 | pub fn touch_destroy_all(&self) { 754 | if let Ok(instance) = self.instance.try_borrow() { 755 | Projectm::touch_destroy_all(*instance); 756 | } else { 757 | panic!("Failed to borrow instance"); 758 | } 759 | } 760 | 761 | pub fn pcm_get_max_samples() -> u32 { 762 | Projectm::pcm_get_max_samples() 763 | } 764 | 765 | pub fn pcm_add_float(&self, samples: &[f32], channels: ProjectMChannels) { 766 | if let Ok(instance) = self.instance.try_borrow() { 767 | Projectm::pcm_add_float(*instance, samples, channels); 768 | } else { 769 | panic!("Failed to borrow instance"); 770 | } 771 | } 772 | 773 | pub fn pcm_add_int16(&self, samples: &[i16], channels: ProjectMChannels) { 774 | if let Ok(instance) = self.instance.try_borrow() { 775 | Projectm::pcm_add_int16(*instance, samples, channels); 776 | } else { 777 | panic!("Failed to borrow instance"); 778 | } 779 | } 780 | 781 | pub fn pcm_add_uint8(&self, samples: &[u8], channels: ProjectMChannels) { 782 | if let Ok(instance) = self.instance.try_borrow() { 783 | Projectm::pcm_add_uint8(*instance, samples, channels); 784 | } else { 785 | panic!("Failed to borrow instance"); 786 | } 787 | } 788 | 789 | pub fn write_debug_image_on_next_frame(&self, output_file: Option<&String>) { 790 | if let Ok(instance) = self.instance.try_borrow() { 791 | Projectm::write_debug_image_on_next_frame(*instance, output_file); 792 | } else { 793 | panic!("Failed to borrow instance"); 794 | } 795 | } 796 | 797 | pub fn get_instance(&self) -> Rc> { 798 | self.instance.clone() 799 | } 800 | } 801 | 802 | unsafe impl Send for ProjectM {} 803 | unsafe impl Sync for ProjectM {} 804 | 805 | // allow cloning the handle 806 | impl Clone for ProjectM { 807 | fn clone(&self) -> Self { 808 | ProjectM { 809 | instance: self.instance.clone(), 810 | } 811 | } 812 | } 813 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod core; 2 | 3 | // #[cfg(playlist)] 4 | pub mod playlist; 5 | -------------------------------------------------------------------------------- /src/playlist.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | extern crate projectm_sys as ffi; 3 | 4 | use rand::Rng; 5 | use std::ffi::CString; 6 | 7 | use crate::core::ProjectM; 8 | 9 | pub struct Playlist { 10 | playlist: *mut ffi::projectm_playlist, 11 | rng: rand::rngs::ThreadRng, 12 | } 13 | 14 | impl Playlist { 15 | /// Create a new playlist for [Projectm](ProjectMHandle) 16 | pub fn create(projectm: &ProjectM) -> Playlist { 17 | let projectm = projectm.get_instance(); 18 | let instance = projectm.borrow_mut(); 19 | 20 | let playlist; 21 | unsafe { 22 | playlist = ffi::projectm_playlist_create(*instance); 23 | } 24 | Playlist { 25 | playlist, 26 | rng: rand::thread_rng(), 27 | } 28 | } 29 | 30 | pub fn len(&self) -> u32 { 31 | unsafe { ffi::projectm_playlist_size(self.playlist) } 32 | } 33 | 34 | pub fn is_empty(&self) -> bool { 35 | self.len() == 0 36 | } 37 | 38 | /// Scan and add a directory of presets to the playlist. 39 | pub fn add_path(&self, path: &str, recursive: bool) { 40 | unsafe { 41 | let c_path = CString::new(path).unwrap(); 42 | ffi::projectm_playlist_add_path(self.playlist, c_path.as_ptr(), recursive, false); 43 | } 44 | } 45 | 46 | /// Go to the next preset in the playlist (hard cut). 47 | pub fn play_next(&mut self) { 48 | unsafe { 49 | ffi::projectm_playlist_play_next(self.playlist, true); 50 | } 51 | } 52 | 53 | /// Go to the previous preset in the playlist (hard cut). 54 | pub fn play_prev(&mut self) { 55 | unsafe { 56 | // FIXME THIS IS WRONG 57 | ffi::projectm_playlist_play_previous(self.playlist, true); 58 | } 59 | } 60 | 61 | /// Go to a random preset in the playlist (hard cut). 62 | pub fn play_random(&mut self) { 63 | let len = self.len(); 64 | let index: u32 = self.rng.gen_range(0..len); 65 | unsafe { 66 | ffi::projectm_playlist_set_position(self.playlist, index, true); 67 | } 68 | } 69 | 70 | /// Set shuffle mode. 71 | pub fn set_shuffle(&self, shuffle: bool) { 72 | unsafe { 73 | ffi::projectm_playlist_set_shuffle(self.playlist, shuffle); 74 | } 75 | } 76 | 77 | /// Get shuffle mode. 78 | pub fn get_shuffle(&self) -> bool { 79 | unsafe { ffi::projectm_playlist_get_shuffle(self.playlist) } 80 | } 81 | } 82 | 83 | unsafe impl Send for Playlist {} 84 | unsafe impl Sync for Playlist {} 85 | -------------------------------------------------------------------------------- /tests/core.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod core { 3 | use projectm::core::*; 4 | use std::process::Command; 5 | use std::str; 6 | 7 | fn get_git_hash_by_command() -> Option { 8 | let output = Command::new("git") 9 | .arg("rev-parse") 10 | .arg("HEAD") 11 | .output() 12 | .ok()?; 13 | 14 | if output.status.success() { 15 | let git_hash = str::from_utf8(&output.stdout).ok()?.trim().to_string(); 16 | println!("git_hash: {}", git_hash); 17 | Some(git_hash) 18 | } else { 19 | None 20 | } 21 | } 22 | 23 | #[test] 24 | fn test_get_versions() { 25 | let version_tuple = ProjectM::get_version_components(); 26 | assert_eq!(version_tuple, (4, 0, 0)); 27 | 28 | let version_string = ProjectM::get_version_string(); 29 | assert_eq!(version_string, "4.0.0"); 30 | 31 | let vcs_version_string = ProjectM::get_vcs_version_string(); 32 | assert_eq!(vcs_version_string, get_git_hash_by_command().unwrap()); 33 | } 34 | 35 | // #[test] 36 | // fn test_create() { 37 | // let projectm = ProjectM::create(); 38 | // } 39 | } 40 | -------------------------------------------------------------------------------- /tests/playlist.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod playlist { 3 | use projectm::core::ProjectM; 4 | use projectm::playlist::Playlist; 5 | 6 | #[test] 7 | fn playlist() { 8 | let projectm = ProjectM::create(); 9 | let playlist = Playlist::create(&projectm); 10 | assert_eq!(playlist.is_empty(), true); 11 | 12 | // add ../presets to playlist 13 | // get absolute path to ../presets 14 | let path = std::env::current_dir().unwrap(); 15 | let presets_dir = path.join("presets"); 16 | playlist.add_path(presets_dir.to_str().unwrap(), true); 17 | assert_eq!(playlist.len(), 20); 18 | } 19 | } 20 | --------------------------------------------------------------------------------