diff --git a/.gitignore b/.gitignore
index dc84dae..386c146 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
/target
wasabi_config.toml
.direnv
-.vscode
\ No newline at end of file
+.vscode
diff --git a/Cargo.lock b/Cargo.lock
index 204aff2..7708fb6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,6 +18,16 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
+[[package]]
+name = "accesskit"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef7442f1f520649b8e11ee3af6caeec24123fed4b63bc36a85b67308d8514fdf"
+dependencies = [
+ "enumn",
+ "serde",
+]
+
[[package]]
name = "adler"
version = "1.0.2"
@@ -33,6 +43,7 @@ dependencies = [
"cfg-if",
"getrandom",
"once_cell",
+ "serde",
"version_check",
"zerocopy",
]
@@ -46,6 +57,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "aligned-vec"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
+
[[package]]
name = "alsa"
version = "0.9.0"
@@ -86,58 +103,37 @@ dependencies = [
]
[[package]]
-name = "android-properties"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
-
-[[package]]
-name = "anstream"
-version = "0.6.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.3"
+name = "android-activity"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
+checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046"
dependencies = [
- "utf8parse",
+ "android-properties",
+ "bitflags 2.5.0",
+ "cc",
+ "cesu8",
+ "jni",
+ "jni-sys",
+ "libc",
+ "log",
+ "ndk 0.9.0",
+ "ndk-context",
+ "ndk-sys 0.6.0+11769913",
+ "num_enum 0.7.3",
+ "thiserror",
]
[[package]]
-name = "anstyle-query"
-version = "1.0.2"
+name = "android-properties"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
-dependencies = [
- "windows-sys 0.52.0",
-]
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
[[package]]
-name = "anstyle-wincon"
-version = "3.0.2"
+name = "anyhow"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
-dependencies = [
- "anstyle",
- "windows-sys 0.52.0",
-]
+checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]]
name = "approx"
@@ -148,6 +144,12 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "arbitrary"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
+
[[package]]
name = "arboard"
version = "3.3.2"
@@ -164,6 +166,17 @@ dependencies = [
"x11rb",
]
+[[package]]
+name = "arg_enum_proc_macro"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
[[package]]
name = "arrayref"
version = "0.3.7"
@@ -176,6 +189,12 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+[[package]]
+name = "as-raw-xcb-connection"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
+
[[package]]
name = "ash"
version = "0.37.3+1.3.251"
@@ -187,139 +206,101 @@ dependencies = [
[[package]]
name = "ashpd"
-version = "0.6.8"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ac22eda5891cc086690cb6fa10121c0390de0e3b04eb269f2d766b00d3f2d81"
+checksum = "bfe7e0dd0ac5a401dc116ed9f9119cf9decc625600474cb41f0fc0a0050abc9a"
dependencies = [
- "async-fs 2.1.1",
+ "async-fs",
"async-net",
"enumflags2",
"futures-channel",
"futures-util",
- "once_cell",
"rand",
+ "raw-window-handle 0.6.2",
"serde",
"serde_repr",
"url",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+ "wayland-protocols 0.32.4",
"zbus",
]
[[package]]
name = "async-broadcast"
-version = "0.5.1"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b"
+checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e"
dependencies = [
- "event-listener 2.5.3",
+ "event-listener",
+ "event-listener-strategy",
"futures-core",
+ "pin-project-lite",
]
[[package]]
name = "async-channel"
-version = "2.2.0"
+version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
+checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
dependencies = [
"concurrent-queue",
- "event-listener 5.2.0",
- "event-listener-strategy 0.5.1",
+ "event-listener-strategy",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-executor"
-version = "1.9.1"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10b3e585719c2358d2660232671ca8ca4ddb4be4ce8a1842d6c2dc8685303316"
+checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec"
dependencies = [
- "async-lock 3.3.0",
"async-task",
"concurrent-queue",
- "fastrand 2.0.2",
- "futures-lite 2.3.0",
+ "fastrand",
+ "futures-lite",
"slab",
]
[[package]]
name = "async-fs"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
-dependencies = [
- "async-lock 2.8.0",
- "autocfg",
- "blocking",
- "futures-lite 1.13.0",
-]
-
-[[package]]
-name = "async-fs"
-version = "2.1.1"
+version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1"
+checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
dependencies = [
- "async-lock 3.3.0",
+ "async-lock",
"blocking",
- "futures-lite 2.3.0",
-]
-
-[[package]]
-name = "async-io"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
-dependencies = [
- "async-lock 2.8.0",
- "autocfg",
- "cfg-if",
- "concurrent-queue",
- "futures-lite 1.13.0",
- "log",
- "parking",
- "polling 2.8.0",
- "rustix 0.37.27",
- "slab",
- "socket2",
- "waker-fn",
+ "futures-lite",
]
[[package]]
name = "async-io"
-version = "2.3.2"
+version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884"
+checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
dependencies = [
- "async-lock 3.3.0",
+ "async-lock",
"cfg-if",
"concurrent-queue",
"futures-io",
- "futures-lite 2.3.0",
+ "futures-lite",
"parking",
- "polling 3.6.0",
- "rustix 0.38.32",
+ "polling",
+ "rustix",
"slab",
"tracing",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "async-lock"
-version = "2.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
-dependencies = [
- "event-listener 2.5.3",
+ "windows-sys 0.59.0",
]
[[package]]
name = "async-lock"
-version = "3.3.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
+checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
dependencies = [
- "event-listener 4.0.3",
- "event-listener-strategy 0.4.0",
+ "event-listener",
+ "event-listener-strategy",
"pin-project-lite",
]
@@ -329,33 +310,35 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
dependencies = [
- "async-io 2.3.2",
+ "async-io",
"blocking",
- "futures-lite 2.3.0",
+ "futures-lite",
]
[[package]]
name = "async-process"
-version = "1.8.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
+checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb"
dependencies = [
- "async-io 1.13.0",
- "async-lock 2.8.0",
+ "async-channel",
+ "async-io",
+ "async-lock",
"async-signal",
+ "async-task",
"blocking",
"cfg-if",
- "event-listener 3.1.0",
- "futures-lite 1.13.0",
- "rustix 0.38.32",
- "windows-sys 0.48.0",
+ "event-listener",
+ "futures-lite",
+ "rustix",
+ "tracing",
]
[[package]]
name = "async-recursion"
-version = "1.1.0"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5"
+checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
@@ -364,33 +347,33 @@ dependencies = [
[[package]]
name = "async-signal"
-version = "0.2.5"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
+checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3"
dependencies = [
- "async-io 2.3.2",
- "async-lock 2.8.0",
+ "async-io",
+ "async-lock",
"atomic-waker",
"cfg-if",
"futures-core",
"futures-io",
- "rustix 0.38.32",
+ "rustix",
"signal-hook-registry",
"slab",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "async-task"
-version = "4.7.0"
+version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
+checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
-version = "0.1.79"
+version = "0.1.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681"
+checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
dependencies = [
"proc-macro2",
"quote",
@@ -405,9 +388,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atomic_float"
-version = "0.1.0"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62af46d040ba9df09edc6528dae9d8e49f5f3e82f55b7d2ec31a733c38dbc49d"
+checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a"
[[package]]
name = "atomic_refcell"
@@ -432,6 +415,29 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
+[[package]]
+name = "av1-grain"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf"
+dependencies = [
+ "anyhow",
+ "arrayvec",
+ "log",
+ "nom",
+ "num-rational",
+ "v_frame",
+]
+
+[[package]]
+name = "avif-serialize"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2"
+dependencies = [
+ "arrayvec",
+]
+
[[package]]
name = "base64"
version = "0.21.7"
@@ -453,7 +459,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
- "rustc-hash",
+ "rustc-hash 1.1.0",
"shlex",
"syn 2.0.58",
]
@@ -485,6 +491,12 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+[[package]]
+name = "bitstream-io"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b81e1519b0d82120d2fd469d5bfb2919a9361c48b02d82d04befc1cdd2002452"
+
[[package]]
name = "block"
version = "0.1.6"
@@ -506,7 +518,7 @@ version = "0.1.0-beta.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146"
dependencies = [
- "objc-sys",
+ "objc-sys 0.2.0-beta.2",
]
[[package]]
@@ -516,36 +528,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"
dependencies = [
"block-sys",
- "objc2-encode",
+ "objc2-encode 2.0.0-pre.2",
+]
+
+[[package]]
+name = "block2"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
+dependencies = [
+ "objc2 0.5.2",
]
[[package]]
name = "blocking"
-version = "1.5.1"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
+checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
dependencies = [
"async-channel",
- "async-lock 3.3.0",
"async-task",
- "fastrand 2.0.2",
"futures-io",
- "futures-lite 2.3.0",
+ "futures-lite",
"piper",
- "tracing",
]
+[[package]]
+name = "built"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4"
+
[[package]]
name = "bumpalo"
version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
+[[package]]
+name = "by_address"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
+
[[package]]
name = "bytemuck"
-version = "1.16.3"
+version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83"
+checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
dependencies = [
"bytemuck_derive",
]
@@ -567,6 +597,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+[[package]]
+name = "byteorder-lite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
+
[[package]]
name = "bytes"
version = "1.6.0"
@@ -587,14 +623,40 @@ dependencies = [
"vec_map",
]
+[[package]]
+name = "calloop"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
+dependencies = [
+ "bitflags 2.5.0",
+ "log",
+ "polling",
+ "rustix",
+ "slab",
+ "thiserror",
+]
+
+[[package]]
+name = "calloop-wayland-source"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
+dependencies = [
+ "calloop 0.13.0",
+ "rustix",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+]
+
[[package]]
name = "cbindgen"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
dependencies = [
- "clap 3.2.25",
- "heck",
+ "clap",
+ "heck 0.4.1",
"indexmap 1.9.3",
"log",
"proc-macro2",
@@ -631,6 +693,16 @@ dependencies = [
"nom",
]
+[[package]]
+name = "cfg-expr"
+version = "0.15.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
+dependencies = [
+ "smallvec",
+ "target-lexicon",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -643,6 +715,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
[[package]]
name = "clang-sys"
version = "1.7.0"
@@ -662,34 +740,13 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
- "clap_lex 0.2.4",
+ "clap_lex",
"indexmap 1.9.3",
- "strsim 0.10.0",
+ "strsim",
"termcolor",
"textwrap",
]
-[[package]]
-name = "clap"
-version = "4.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
-dependencies = [
- "clap_builder",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex 0.7.0",
- "strsim 0.11.1",
-]
-
[[package]]
name = "clap_lex"
version = "0.2.4"
@@ -699,12 +756,6 @@ dependencies = [
"os_str_bytes",
]
-[[package]]
-name = "clap_lex"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
-
[[package]]
name = "clipboard-win"
version = "5.3.0"
@@ -729,12 +780,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
-[[package]]
-name = "colorchoice"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
-
[[package]]
name = "colors-transform"
version = "0.2.11"
@@ -753,25 +798,13 @@ dependencies = [
[[package]]
name = "concurrent-queue"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
]
-[[package]]
-name = "confy"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e37668cb35145dcfaa1931a5f37fde375eeae8068b4c0d2f289da28a270b2d2c"
-dependencies = [
- "directories 4.0.1",
- "serde",
- "thiserror",
- "toml 0.5.11",
-]
-
[[package]]
name = "convert_case"
version = "0.4.0"
@@ -803,7 +836,20 @@ dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-graphics-types",
- "foreign-types",
+ "foreign-types 0.3.2",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types 0.5.0",
"libc",
]
@@ -838,6 +884,27 @@ dependencies = [
"bindgen",
]
+[[package]]
+name = "coremidi"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "964eb3e10ea8b0d29c797086aab3ca730f75e06dced0cb980642fd274a5cca30"
+dependencies = [
+ "block",
+ "core-foundation",
+ "core-foundation-sys",
+ "coremidi-sys",
+]
+
+[[package]]
+name = "coremidi-sys"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709d142e542467e028d5dc5f0374392339ab7dead0c48c129504de2ccd667e1b"
+dependencies = [
+ "core-foundation-sys",
+]
+
[[package]]
name = "cpal"
version = "0.15.3"
@@ -858,7 +925,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows",
+ "windows 0.54.0",
]
[[package]]
@@ -938,6 +1005,12 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "cursor-icon"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
+
[[package]]
name = "dasp_sample"
version = "0.11.0"
@@ -951,13 +1024,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
[[package]]
-name = "deranged"
-version = "0.3.11"
+name = "data-url"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
-dependencies = [
- "powerfmt",
-]
+checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
[[package]]
name = "derivative"
@@ -980,38 +1050,18 @@ dependencies = [
"crypto-common",
]
-[[package]]
-name = "directories"
-version = "4.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
-dependencies = [
- "dirs-sys 0.3.7",
-]
-
[[package]]
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
- "dirs-sys 0.4.1",
+ "dirs-sys",
]
[[package]]
name = "dirs-sys"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "dirs-sys"
-version = "0.4.1"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
@@ -1042,53 +1092,82 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
+[[package]]
+name = "dpi"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
+
[[package]]
name = "ecolor"
-version = "0.21.0"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f99fe3cac305af9d6d92971af60d0f7ea4d783201ef1673571567b6699964d9"
+checksum = "5629649a8ae57c73f175f4a96419905a8102cfbfcbce96ea25a826bbf468e990"
+dependencies = [
+ "bytemuck",
+ "emath",
+ "serde",
+]
[[package]]
name = "egui"
-version = "0.21.0"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6412a21e0bde7c0918f7fb44bbbb86b5e1f88e63c026a4e747cc7af02f76dfbe"
+checksum = "26bab3b3572566257a497b5f87d2cccaf7f7f122d4b8b620cba0493becc7955e"
dependencies = [
+ "accesskit",
"ahash",
+ "emath",
"epaint",
+ "log",
"nohash-hasher",
- "tracing",
+ "serde",
]
[[package]]
name = "egui-winit"
-version = "0.21.1"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab43597ba41f0ce39a364ad83185594578bfd8b3409b99dbcbb01df23afc3dbb"
+checksum = "642c749bf221b5a3ecae3144c98b837729d87b9fde6c39a6ad00f07b71dbee94"
dependencies = [
- "android-activity",
+ "ahash",
"arboard",
"egui",
- "instant",
+ "log",
+ "raw-window-handle 0.6.2",
"smithay-clipboard",
- "tracing",
+ "web-time",
"webbrowser",
- "winit",
+ "winit 0.30.5",
]
[[package]]
-name = "egui_winit_vulkano"
-version = "0.24.0"
+name = "egui_extras"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "203c1ad521328c178e24d16f5b26ca151a5b1669adafa2c6aa9eb3f904cdfd52"
+checksum = "d9f1beb57a3c942fac2f058655188c79ac1cd200555e4f3684cd0c965ceb3a67"
+dependencies = [
+ "ahash",
+ "egui",
+ "enum-map",
+ "log",
+ "mime_guess2",
+ "resvg 0.37.0",
+]
+
+[[package]]
+name = "egui_winit_vulkano"
+version = "0.27.0"
+source = "git+https://github.com/MyBlackMIDIScore/egui_winit_vulkano.git?rev=aa24f97#aa24f979edad909749dc74e78fee5252c650979c"
dependencies = [
"ahash",
"egui",
"egui-winit",
"image",
+ "raw-window-handle 0.6.2",
"vulkano",
"vulkano-shaders",
- "winit",
+ "winit 0.30.5",
]
[[package]]
@@ -1099,9 +1178,13 @@ checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "emath"
-version = "0.21.0"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8ecd80612937e0267909d5351770fe150004e24dab93954f69ca62eecd3f77e"
+checksum = "af86c4efae11da2a3dcbb4afebd0e9ed1916345e8d187b4051d443c8bd79af93"
+dependencies = [
+ "bytemuck",
+ "serde",
+]
[[package]]
name = "encoding_rs"
@@ -1121,6 +1204,33 @@ dependencies = [
"encoding_rs",
]
+[[package]]
+name = "endi"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
+
+[[package]]
+name = "enum-map"
+version = "2.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
+dependencies = [
+ "enum-map-derive",
+ "serde",
+]
+
+[[package]]
+name = "enum-map-derive"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
[[package]]
name = "enum_dispatch"
version = "0.3.13"
@@ -1135,9 +1245,9 @@ dependencies = [
[[package]]
name = "enumflags2"
-version = "0.7.9"
+version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d"
+checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d"
dependencies = [
"enumflags2_derive",
"serde",
@@ -1145,9 +1255,20 @@ dependencies = [
[[package]]
name = "enumflags2_derive"
-version = "0.7.9"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
+[[package]]
+name = "enumn"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
+checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
dependencies = [
"proc-macro2",
"quote",
@@ -1156,19 +1277,28 @@ dependencies = [
[[package]]
name = "epaint"
-version = "0.21.0"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12e78b5c58a1f7f621f9d546add2adce20636422c9b251e29f749e8a2f713c95"
+checksum = "445e11ec86a4d85e1350578ba20b2d89977ed937f3faab32e1c3ec81d20c1842"
dependencies = [
"ab_glyph",
"ahash",
- "atomic_refcell",
+ "bytemuck",
"ecolor",
"emath",
+ "epaint_default_fonts",
+ "log",
"nohash-hasher",
"parking_lot",
+ "serde",
]
+[[package]]
+name = "epaint_default_fonts"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5202b64bef2b2c42a7f6e2e5b40fa83dd04aa61fdb08bfd116553adc149fe47a"
+
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -1193,60 +1323,22 @@ checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b"
[[package]]
name = "event-listener"
-version = "2.5.3"
+version = "5.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
-
-[[package]]
-name = "event-listener"
-version = "3.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
+checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
-[[package]]
-name = "event-listener"
-version = "4.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
-dependencies = [
- "concurrent-queue",
- "parking",
- "pin-project-lite",
-]
-
-[[package]]
-name = "event-listener"
-version = "5.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91"
-dependencies = [
- "concurrent-queue",
- "parking",
- "pin-project-lite",
-]
-
-[[package]]
-name = "event-listener-strategy"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
-dependencies = [
- "event-listener 4.0.3",
- "pin-project-lite",
-]
-
[[package]]
name = "event-listener-strategy"
-version = "0.5.1"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3"
+checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
dependencies = [
- "event-listener 5.2.0",
+ "event-listener",
"pin-project-lite",
]
@@ -1278,15 +1370,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
-[[package]]
-name = "fastrand"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
-dependencies = [
- "instant",
-]
-
[[package]]
name = "fastrand"
version = "2.0.2"
@@ -1333,7 +1416,28 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
- "foreign-types-shared",
+ "foreign-types-shared 0.1.1",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared 0.3.1",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
]
[[package]]
@@ -1342,6 +1446,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@@ -1372,28 +1482,13 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
-[[package]]
-name = "futures-lite"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
-dependencies = [
- "fastrand 1.9.0",
- "futures-core",
- "futures-io",
- "memchr",
- "parking",
- "pin-project-lite",
- "waker-fn",
-]
-
[[package]]
name = "futures-lite"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
dependencies = [
- "fastrand 2.0.2",
+ "fastrand",
"futures-core",
"futures-io",
"parking",
@@ -1521,6 +1616,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -1532,9 +1633,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
-version = "0.3.9"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "hex"
@@ -1554,7 +1655,8 @@ dependencies = [
[[package]]
name = "ico"
version = "0.3.0"
-source = "git+https://github.com/StratusFearMe21/rust-ico?branch=patch-1#aa5924babb52ee5559cdb3a376d0c060a478c9f1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae"
dependencies = [
"byteorder",
"png",
@@ -1572,20 +1674,35 @@ dependencies = [
[[package]]
name = "image"
-version = "0.24.9"
+version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
+checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10"
dependencies = [
"bytemuck",
- "byteorder",
+ "byteorder-lite",
"color_quant",
"exr",
"gif",
- "jpeg-decoder",
+ "image-webp",
"num-traits",
"png",
"qoi",
+ "ravif",
+ "rayon",
+ "rgb",
"tiff",
+ "zune-core",
+ "zune-jpeg",
+]
+
+[[package]]
+name = "image-webp"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904"
+dependencies = [
+ "byteorder-lite",
+ "quick-error",
]
[[package]]
@@ -1594,6 +1711,18 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b72ad49b554c1728b1e83254a1b1565aea4161e28dabbfa171fc15fe62299caf"
+[[package]]
+name = "imagesize"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
+
+[[package]]
+name = "imgref"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126"
+
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -1606,9 +1735,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.2.6"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
@@ -1616,9 +1745,9 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.12"
+version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if",
"js-sys",
@@ -1627,14 +1756,33 @@ dependencies = [
]
[[package]]
-name = "io-lifetimes"
-version = "1.0.11"
+name = "interpolate_name"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
- "hermit-abi 0.3.9",
- "libc",
- "windows-sys 0.48.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
+[[package]]
+name = "is-docker"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "is-wsl"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
+dependencies = [
+ "is-docker",
+ "once_cell",
]
[[package]]
@@ -1688,9 +1836,6 @@ name = "jpeg-decoder"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
-dependencies = [
- "rayon",
-]
[[package]]
name = "js-sys"
@@ -1766,6 +1911,17 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+[[package]]
+name = "libfuzzer-sys"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
+dependencies = [
+ "arbitrary",
+ "cc",
+ "once_cell",
+]
+
[[package]]
name = "libloading"
version = "0.7.4"
@@ -1813,12 +1969,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "linux-raw-sys"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
-
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
@@ -1841,6 +1991,15 @@ version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+[[package]]
+name = "loop9"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
+dependencies = [
+ "imgref",
+]
+
[[package]]
name = "mach2"
version = "0.4.2"
@@ -1859,6 +2018,16 @@ dependencies = [
"libc",
]
+[[package]]
+name = "maybe-rayon"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
+dependencies = [
+ "cfg-if",
+ "rayon",
+]
+
[[package]]
name = "memchr"
version = "2.7.2"
@@ -1875,19 +2044,19 @@ dependencies = [
]
[[package]]
-name = "memoffset"
-version = "0.6.5"
+name = "memmap2"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
dependencies = [
- "autocfg",
+ "libc",
]
[[package]]
name = "memoffset"
-version = "0.7.1"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
@@ -1928,6 +2097,39 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "midir"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe36f39751eb1f449490d4a236e8642c8efee1a87fa81785b063289b689dc84e"
+dependencies = [
+ "alsa",
+ "bitflags 1.3.2",
+ "coremidi",
+ "js-sys",
+ "libc",
+ "parking_lot",
+ "wasm-bindgen",
+ "web-sys",
+ "windows 0.56.0",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mime_guess2"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25a3333bb1609500601edc766a39b4c1772874a4ce26022f4d866854dc020c41"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1966,7 +2168,7 @@ dependencies = [
"jni-sys",
"ndk-sys 0.4.1+23.1.7779620",
"num_enum 0.5.11",
- "raw-window-handle",
+ "raw-window-handle 0.5.2",
"thiserror",
]
@@ -1980,7 +2182,22 @@ dependencies = [
"jni-sys",
"log",
"ndk-sys 0.5.0+25.2.9519653",
- "num_enum 0.7.2",
+ "num_enum 0.7.3",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
+dependencies = [
+ "bitflags 2.5.0",
+ "jni-sys",
+ "log",
+ "ndk-sys 0.6.0+11769913",
+ "num_enum 0.7.3",
+ "raw-window-handle 0.6.2",
"thiserror",
]
@@ -2008,6 +2225,21 @@ dependencies = [
"jni-sys",
]
+[[package]]
+name = "ndk-sys"
+version = "0.6.0+11769913"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
[[package]]
name = "nix"
version = "0.24.3"
@@ -2035,14 +2267,15 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.26.4"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
+checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.5.0",
"cfg-if",
+ "cfg_aliases 0.1.1",
"libc",
- "memoffset 0.7.1",
+ "memoffset 0.9.1",
]
[[package]]
@@ -2062,19 +2295,29 @@ dependencies = [
]
[[package]]
-name = "num-complex"
+name = "noop_proc_macro"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
+
+[[package]]
+name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
+ "num-integer",
"num-traits",
]
[[package]]
-name = "num-conv"
-version = "0.1.0"
+name = "num-complex"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
[[package]]
name = "num-derive"
@@ -2096,6 +2339,17 @@ dependencies = [
"num-traits",
]
+[[package]]
+name = "num-rational"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
+dependencies = [
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.18"
@@ -2125,11 +2379,11 @@ dependencies = [
[[package]]
name = "num_enum"
-version = "0.7.2"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
+checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
dependencies = [
- "num_enum_derive 0.7.2",
+ "num_enum_derive 0.7.3",
]
[[package]]
@@ -2158,9 +2412,9 @@ dependencies = [
[[package]]
name = "num_enum_derive"
-version = "0.7.2"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
+checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
@@ -2169,49 +2423,252 @@ dependencies = [
]
[[package]]
-name = "objc"
-version = "0.2.7"
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+]
+
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
+name = "objc-sys"
+version = "0.2.0-beta.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
+
+[[package]]
+name = "objc-sys"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
+
+[[package]]
+name = "objc2"
+version = "0.3.0-beta.3.patch-leaks.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468"
+dependencies = [
+ "block2 0.2.0-alpha.6",
+ "objc-sys 0.2.0-beta.2",
+ "objc2-encode 2.0.0-pre.2",
+]
+
+[[package]]
+name = "objc2"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
+dependencies = [
+ "objc-sys 0.3.5",
+ "objc2-encode 4.0.3",
+]
+
+[[package]]
+name = "objc2-app-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
+dependencies = [
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "libc",
+ "objc2 0.5.2",
+ "objc2-core-data",
+ "objc2-core-image",
+ "objc2-foundation",
+ "objc2-quartz-core",
+]
+
+[[package]]
+name = "objc2-cloud-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
+dependencies = [
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-contacts"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
+dependencies = [
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-data"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
+dependencies = [
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-image"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
+dependencies = [
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation",
+ "objc2-metal",
+]
+
+[[package]]
+name = "objc2-core-location"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
+dependencies = [
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-contacts",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "2.0.0-pre.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
+dependencies = [
+ "objc-sys 0.2.0-beta.2",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
+dependencies = [
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "dispatch",
+ "libc",
+ "objc2 0.5.2",
+]
+
+[[package]]
+name = "objc2-link-presentation"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
+dependencies = [
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-app-kit",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-metal"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
+dependencies = [
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [
- "malloc_buf",
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation",
+ "objc2-metal",
]
[[package]]
-name = "objc-foundation"
-version = "0.1.1"
+name = "objc2-symbols"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
dependencies = [
- "block",
- "objc",
- "objc_id",
+ "objc2 0.5.2",
+ "objc2-foundation",
]
[[package]]
-name = "objc-sys"
-version = "0.2.0-beta.2"
+name = "objc2-ui-kit"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
-
-[[package]]
-name = "objc2"
-version = "0.3.0-beta.3.patch-leaks.3"
+checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
+dependencies = [
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-cloud-kit",
+ "objc2-core-data",
+ "objc2-core-image",
+ "objc2-core-location",
+ "objc2-foundation",
+ "objc2-link-presentation",
+ "objc2-quartz-core",
+ "objc2-symbols",
+ "objc2-uniform-type-identifiers",
+ "objc2-user-notifications",
+]
+
+[[package]]
+name = "objc2-uniform-type-identifiers"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468"
+checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
dependencies = [
- "block2",
- "objc-sys",
- "objc2-encode",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-foundation",
]
[[package]]
-name = "objc2-encode"
-version = "2.0.0-pre.2"
+name = "objc2-user-notifications"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
+checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [
- "objc-sys",
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "objc2 0.5.2",
+ "objc2-core-location",
+ "objc2-foundation",
]
[[package]]
@@ -2252,6 +2709,17 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+[[package]]
+name = "open"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3"
+dependencies = [
+ "is-wsl",
+ "libc",
+ "pathdiff",
+]
+
[[package]]
name = "option-ext"
version = "0.2.0"
@@ -2294,9 +2762,9 @@ dependencies = [
[[package]]
name = "palette"
-version = "0.7.5"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebfc23a4b76642983d57e4ad00bb4504eb30a8ce3c70f4aee1f725610e36d97a"
+checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
dependencies = [
"approx",
"fast-srgb8",
@@ -2306,10 +2774,11 @@ dependencies = [
[[package]]
name = "palette_derive"
-version = "0.7.5"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8890702dbec0bad9116041ae586f84805b13eecd1d8b1df27c29998a9969d6d"
+checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
dependencies = [
+ "by_address",
"proc-macro2",
"quote",
"syn 2.0.58",
@@ -2317,9 +2786,9 @@ dependencies = [
[[package]]
name = "parking"
-version = "2.2.0"
+version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "parking_lot"
@@ -2350,6 +2819,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+[[package]]
+name = "pathdiff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+
[[package]]
name = "percent-encoding"
version = "2.3.1"
@@ -2404,6 +2879,26 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
+[[package]]
+name = "pin-project"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
[[package]]
name = "pin-project-lite"
version = "0.2.14"
@@ -2418,12 +2913,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "piper"
-version = "0.2.1"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
+checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
"atomic-waker",
- "fastrand 2.0.2",
+ "fastrand",
"futures-io",
]
@@ -2448,33 +2943,17 @@ dependencies = [
[[package]]
name = "polling"
-version = "2.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
-dependencies = [
- "autocfg",
- "bitflags 1.3.2",
- "cfg-if",
- "concurrent-queue",
- "libc",
- "log",
- "pin-project-lite",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "polling"
-version = "3.6.0"
+version = "3.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6"
+checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
dependencies = [
"cfg-if",
"concurrent-queue",
- "hermit-abi 0.3.9",
+ "hermit-abi 0.4.0",
"pin-project-lite",
- "rustix 0.38.32",
+ "rustix",
"tracing",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -2483,12 +2962,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
-[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -2556,6 +3029,25 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "profiling"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
+dependencies = [
+ "profiling-procmacros",
+]
+
+[[package]]
+name = "profiling-procmacros"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
+dependencies = [
+ "quote",
+ "syn 2.0.58",
+]
+
[[package]]
name = "qoi"
version = "0.4.1"
@@ -2565,6 +3057,21 @@ dependencies = [
"bytemuck",
]
+[[package]]
+name = "quick-error"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+
+[[package]]
+name = "quick-xml"
+version = "0.36.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "quote"
version = "1.0.35"
@@ -2604,12 +3111,68 @@ dependencies = [
"getrandom",
]
+[[package]]
+name = "rav1e"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9"
+dependencies = [
+ "arbitrary",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "av1-grain",
+ "bitstream-io",
+ "built",
+ "cfg-if",
+ "interpolate_name",
+ "itertools",
+ "libc",
+ "libfuzzer-sys",
+ "log",
+ "maybe-rayon",
+ "new_debug_unreachable",
+ "noop_proc_macro",
+ "num-derive",
+ "num-traits",
+ "once_cell",
+ "paste",
+ "profiling",
+ "rand",
+ "rand_chacha",
+ "simd_helpers",
+ "system-deps",
+ "thiserror",
+ "v_frame",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ravif"
+version = "0.11.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67376f469e7e7840d0040bbf4b9b3334005bb167f814621326e4c7ab8cd6e944"
+dependencies = [
+ "avif-serialize",
+ "imgref",
+ "loop9",
+ "quick-error",
+ "rav1e",
+ "rayon",
+ "rgb",
+]
+
[[package]]
name = "raw-window-handle"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
+[[package]]
+name = "raw-window-handle"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
+
[[package]]
name = "rayon"
version = "1.10.0"
@@ -2734,29 +3297,40 @@ dependencies = [
"log",
"pico-args",
"rgb",
- "svgtypes",
- "tiny-skia",
- "usvg",
+ "svgtypes 0.11.0",
+ "tiny-skia 0.8.4",
+ "usvg 0.31.0",
+]
+
+[[package]]
+name = "resvg"
+version = "0.37.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4"
+dependencies = [
+ "log",
+ "pico-args",
+ "rgb",
+ "svgtypes 0.13.0",
+ "tiny-skia 0.11.4",
+ "usvg 0.37.0",
]
[[package]]
name = "rfd"
-version = "0.12.1"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c9e7b57df6e8472152674607f6cc68aa14a748a3157a857a94f516e11aeacc2"
+checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e"
dependencies = [
"ashpd",
- "async-io 1.13.0",
- "block",
- "dispatch",
- "futures-util",
+ "block2 0.5.1",
"js-sys",
"log",
- "objc",
- "objc-foundation",
- "objc_id",
+ "objc2 0.5.2",
+ "objc2-app-kit",
+ "objc2-foundation",
"pollster",
- "raw-window-handle",
+ "raw-window-handle 0.6.2",
"urlencoding",
"wasm-bindgen",
"wasm-bindgen-futures",
@@ -2789,7 +3363,7 @@ dependencies = [
"roxmltree 0.18.1",
"simplecss",
"siphasher",
- "svgtypes",
+ "svgtypes 0.11.0",
]
[[package]]
@@ -2810,6 +3384,12 @@ dependencies = [
"xmlparser",
]
+[[package]]
+name = "roxmltree"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
+
[[package]]
name = "rubato"
version = "0.15.0"
@@ -2828,6 +3408,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+[[package]]
+name = "rustc-hash"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
+
[[package]]
name = "rustfft"
version = "6.2.0"
@@ -2843,20 +3429,6 @@ dependencies = [
"version_check",
]
-[[package]]
-name = "rustix"
-version = "0.37.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
-dependencies = [
- "bitflags 1.3.2",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys 0.3.8",
- "windows-sys 0.48.0",
-]
-
[[package]]
name = "rustix"
version = "0.38.32"
@@ -2866,7 +3438,7 @@ dependencies = [
"bitflags 2.5.0",
"errno",
"libc",
- "linux-raw-sys 0.4.13",
+ "linux-raw-sys",
"windows-sys 0.52.0",
]
@@ -2905,25 +3477,38 @@ checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09"
dependencies = [
"ab_glyph",
"log",
- "memmap2",
- "smithay-client-toolkit",
- "tiny-skia",
+ "memmap2 0.5.10",
+ "smithay-client-toolkit 0.16.1",
+ "tiny-skia 0.8.4",
+]
+
+[[package]]
+name = "sctk-adwaita"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
+dependencies = [
+ "ab_glyph",
+ "log",
+ "memmap2 0.9.5",
+ "smithay-client-toolkit 0.19.2",
+ "tiny-skia 0.11.4",
]
[[package]]
name = "serde"
-version = "1.0.197"
+version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.197"
+version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
@@ -2943,9 +3528,9 @@ dependencies = [
[[package]]
name = "serde_repr"
-version = "0.1.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
+checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
@@ -2954,9 +3539,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
-version = "0.6.5"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
+checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
dependencies = [
"serde",
]
@@ -3001,9 +3586,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
-version = "1.4.1"
+version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
@@ -3014,6 +3599,15 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+[[package]]
+name = "simd_helpers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
+dependencies = [
+ "quote",
+]
+
[[package]]
name = "simdeez"
version = "2.0.0-dev3"
@@ -3070,36 +3664,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9"
dependencies = [
"bitflags 1.3.2",
- "calloop",
+ "calloop 0.10.6",
"dlib",
"lazy_static",
"log",
- "memmap2",
+ "memmap2 0.5.10",
"nix 0.24.3",
"pkg-config",
- "wayland-client",
- "wayland-cursor",
- "wayland-protocols",
+ "wayland-client 0.29.5",
+ "wayland-cursor 0.29.5",
+ "wayland-protocols 0.29.5",
]
[[package]]
-name = "smithay-clipboard"
-version = "0.6.6"
+name = "smithay-client-toolkit"
+version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8"
+checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
dependencies = [
- "smithay-client-toolkit",
- "wayland-client",
+ "bitflags 2.5.0",
+ "calloop 0.13.0",
+ "calloop-wayland-source",
+ "cursor-icon",
+ "libc",
+ "log",
+ "memmap2 0.9.5",
+ "rustix",
+ "thiserror",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+ "wayland-csd-frame",
+ "wayland-cursor 0.31.6",
+ "wayland-protocols 0.32.4",
+ "wayland-protocols-wlr",
+ "wayland-scanner 0.31.5",
+ "xkeysym",
]
[[package]]
-name = "socket2"
-version = "0.4.10"
+name = "smithay-clipboard"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
+checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846"
dependencies = [
"libc",
- "winapi",
+ "smithay-client-toolkit 0.19.2",
+ "wayland-backend",
+]
+
+[[package]]
+name = "smol_str"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
+dependencies = [
+ "serde",
]
[[package]]
@@ -3157,16 +3776,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
-name = "strsim"
-version = "0.11.1"
+name = "svgtypes"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+checksum = "ed4b0611e7f3277f68c0fa18e385d9e2d26923691379690039548f867cef02a7"
+dependencies = [
+ "kurbo",
+ "siphasher",
+]
[[package]]
name = "svgtypes"
-version = "0.11.0"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed4b0611e7f3277f68c0fa18e385d9e2d26923691379690039548f867cef02a7"
+checksum = "6e44e288cd960318917cbd540340968b90becc8bc81f171345d706e7a89d9d70"
dependencies = [
"kurbo",
"siphasher",
@@ -3327,6 +3950,25 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "system-deps"
+version = "6.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
+dependencies = [
+ "cfg-expr",
+ "heck 0.5.0",
+ "pkg-config",
+ "toml 0.8.19",
+ "version-compare",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+
[[package]]
name = "tempfile"
version = "3.10.1"
@@ -3334,8 +3976,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if",
- "fastrand 2.0.2",
- "rustix 0.38.32",
+ "fastrand",
+ "rustix",
"windows-sys 0.52.0",
]
@@ -3396,36 +4038,32 @@ dependencies = [
]
[[package]]
-name = "time"
-version = "0.3.36"
+name = "tiny-skia"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67"
dependencies = [
- "deranged",
- "num-conv",
- "powerfmt",
- "serde",
- "time-core",
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "png",
+ "tiny-skia-path 0.8.4",
]
-[[package]]
-name = "time-core"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
-
[[package]]
name = "tiny-skia"
-version = "0.8.4"
+version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
dependencies = [
"arrayref",
"arrayvec",
"bytemuck",
"cfg-if",
+ "log",
"png",
- "tiny-skia-path",
+ "tiny-skia-path 0.11.4",
]
[[package]]
@@ -3439,6 +4077,17 @@ dependencies = [
"strict-num",
]
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
[[package]]
name = "tinyvec"
version = "1.6.0"
@@ -3471,21 +4120,21 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.8.12"
+version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.22.9",
+ "toml_edit 0.22.21",
]
[[package]]
name = "toml_datetime"
-version = "0.6.5"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
@@ -3496,7 +4145,7 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
- "indexmap 2.2.6",
+ "indexmap 2.5.0",
"toml_datetime",
"winnow 0.5.40",
]
@@ -3507,22 +4156,22 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [
- "indexmap 2.2.6",
+ "indexmap 2.5.0",
"toml_datetime",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.22.9"
+version = "0.22.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
+checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
dependencies = [
- "indexmap 2.2.6",
+ "indexmap 2.5.0",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow 0.6.5",
+ "winnow 0.6.18",
]
[[package]]
@@ -3582,11 +4231,20 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
name = "uds_windows"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
+checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
+dependencies = [
+ "memoffset 0.9.1",
+ "tempfile",
+ "winapi",
+]
+
+[[package]]
+name = "unicase"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
- "memoffset 0.9.1",
- "tempfile",
- "winapi",
+ "version_check",
]
[[package]]
@@ -3610,6 +4268,12 @@ dependencies = [
"tinyvec",
]
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
[[package]]
name = "url"
version = "2.5.0"
@@ -3637,8 +4301,22 @@ dependencies = [
"base64",
"log",
"pico-args",
- "usvg-parser",
- "usvg-tree",
+ "usvg-parser 0.31.0",
+ "usvg-tree 0.31.0",
+ "xmlwriter",
+]
+
+[[package]]
+name = "usvg"
+version = "0.37.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756"
+dependencies = [
+ "base64",
+ "log",
+ "pico-args",
+ "usvg-parser 0.37.0",
+ "usvg-tree 0.37.0",
"xmlwriter",
]
@@ -3648,15 +4326,33 @@ version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2352a2c05655a7e4d3dca76cf65764efce35527472668bae5c6fc876b4c996d"
dependencies = [
- "data-url",
+ "data-url 0.2.0",
"flate2",
- "imagesize",
+ "imagesize 0.11.0",
"kurbo",
"log",
"rosvgtree",
"strict-num",
- "svgtypes",
- "usvg-tree",
+ "svgtypes 0.11.0",
+ "usvg-tree 0.31.0",
+]
+
+[[package]]
+name = "usvg-parser"
+version = "0.37.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bd4e3c291f45d152929a31f0f6c819245e2921bfd01e7bd91201a9af39a2bdc"
+dependencies = [
+ "data-url 0.3.1",
+ "flate2",
+ "imagesize 0.12.0",
+ "kurbo",
+ "log",
+ "roxmltree 0.19.0",
+ "simplecss",
+ "siphasher",
+ "svgtypes 0.13.0",
+ "usvg-tree 0.37.0",
]
[[package]]
@@ -3668,14 +4364,31 @@ dependencies = [
"kurbo",
"rctree",
"strict-num",
- "svgtypes",
+ "svgtypes 0.11.0",
]
[[package]]
-name = "utf8parse"
-version = "0.2.1"
+name = "usvg-tree"
+version = "0.37.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3"
+dependencies = [
+ "rctree",
+ "strict-num",
+ "svgtypes 0.13.0",
+ "tiny-skia-path 0.11.4",
+]
+
+[[package]]
+name = "v_frame"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b"
+dependencies = [
+ "aligned-vec",
+ "num-traits",
+ "wasm-bindgen",
+]
[[package]]
name = "vec_map"
@@ -3683,6 +4396,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+[[package]]
+name = "version-compare"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
+
[[package]]
name = "version_check"
version = "0.9.4"
@@ -3691,18 +4410,17 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vk-parse"
-version = "0.8.0"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c6a0bda9bbe6b9e50e6456c80aa8fe4cca3b21e4311a1130c41e4915ec2e32a"
+checksum = "81086c28be67a8759cd80cbb3c8f7b520e0874605fc5eb74d5a1c9c2d1878e79"
dependencies = [
"xml-rs",
]
[[package]]
name = "vulkano"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e1f15eeb9d93a05eb3c237332a10806eac1eb82444e54485bfcc1859c483c23"
+version = "0.34.0"
+source = "git+https://github.com/vulkano-rs/vulkano.git?rev=4a77d39#4a77d39b8562c9b8a337ee643c58f4f01ba6079b"
dependencies = [
"ahash",
"ash",
@@ -3710,14 +4428,15 @@ dependencies = [
"core-graphics-types",
"crossbeam-queue",
"half",
- "heck",
- "indexmap 1.9.3",
- "libloading 0.7.4",
+ "heck 0.4.1",
+ "indexmap 2.5.0",
+ "libloading 0.8.3",
"objc",
"once_cell",
"parking_lot",
"proc-macro2",
"quote",
+ "raw-window-handle 0.6.2",
"regex",
"serde",
"serde_json",
@@ -3729,62 +4448,41 @@ dependencies = [
[[package]]
name = "vulkano-macros"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "895b8a2cac1e7650d2d0552f2392da0970a358515ac11a34adaf19bfdc771b98"
+version = "0.34.0"
+source = "git+https://github.com/vulkano-rs/vulkano.git?rev=4a77d39#4a77d39b8562c9b8a337ee643c58f4f01ba6079b"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.58",
]
[[package]]
name = "vulkano-shaders"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f8cf18e9becbc6d39f1c39e26bcf69546c93989553eb5748cd734a8a697a6e5"
+version = "0.34.0"
+source = "git+https://github.com/vulkano-rs/vulkano.git?rev=4a77d39#4a77d39b8562c9b8a337ee643c58f4f01ba6079b"
dependencies = [
"ahash",
- "heck",
+ "heck 0.4.1",
"proc-macro2",
"quote",
"shaderc",
- "syn 1.0.109",
- "vulkano",
-]
-
-[[package]]
-name = "vulkano-util"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a71b6df05a391161c1baec645a918437c2949d3494bf74c8358fde291d37f5f4"
-dependencies = [
- "ahash",
+ "syn 2.0.58",
"vulkano",
- "vulkano-win",
- "winit",
]
[[package]]
name = "vulkano-win"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "666c77efe5ea82837781961a6bcd957ee2e926777e8de0005f580335d6eaefe7"
+version = "0.34.0"
+source = "git+https://github.com/vulkano-rs/vulkano.git?rev=4a77d39#4a77d39b8562c9b8a337ee643c58f4f01ba6079b"
dependencies = [
"core-graphics-types",
"objc",
- "raw-window-handle",
+ "raw-window-handle 0.5.2",
"vulkano",
- "winit",
+ "winit 0.28.7",
]
-[[package]]
-name = "waker-fn"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
-
[[package]]
name = "walkdir"
version = "2.5.0"
@@ -3797,39 +4495,40 @@ dependencies = [
[[package]]
name = "wasabi"
-version = "0.1.4"
+version = "1.0.0"
dependencies = [
"atomic_float",
"bytemuck",
- "clap 4.5.4",
"colors-transform",
- "confy",
"crossbeam-channel",
- "directories 5.0.1",
+ "directories",
"egui",
"egui-winit",
+ "egui_extras",
"egui_winit_vulkano",
"enum_dispatch",
"gen-iter",
"ico",
"kdmapi",
"midi-toolkit-rs",
- "num_enum 0.7.2",
+ "midir",
+ "num_enum 0.7.3",
+ "open",
"palette",
"rand",
+ "raw-window-handle 0.6.2",
"rayon",
- "resvg",
+ "resvg 0.31.1",
"rfd",
- "rustc-hash",
+ "rustc-hash 2.0.0",
"serde",
"serde_derive",
- "time",
- "toml 0.8.12",
+ "serde_json",
+ "toml 0.8.19",
"vulkano",
"vulkano-shaders",
- "vulkano-util",
"vulkano-win",
- "winit",
+ "winit 0.30.5",
"winres",
"xsynth-core",
"xsynth-realtime",
@@ -3916,6 +4615,20 @@ dependencies = [
"riff",
]
+[[package]]
+name = "wayland-backend"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys 0.31.5",
+]
+
[[package]]
name = "wayland-client"
version = "0.29.5"
@@ -3928,8 +4641,20 @@ dependencies = [
"nix 0.24.3",
"scoped-tls",
"wayland-commons",
- "wayland-scanner",
- "wayland-sys",
+ "wayland-scanner 0.29.5",
+ "wayland-sys 0.29.5",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d"
+dependencies = [
+ "bitflags 2.5.0",
+ "rustix",
+ "wayland-backend",
+ "wayland-scanner 0.31.5",
]
[[package]]
@@ -3941,7 +4666,18 @@ dependencies = [
"nix 0.24.3",
"once_cell",
"smallvec",
- "wayland-sys",
+ "wayland-sys 0.29.5",
+]
+
+[[package]]
+name = "wayland-csd-frame"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
+dependencies = [
+ "bitflags 2.5.0",
+ "cursor-icon",
+ "wayland-backend",
]
[[package]]
@@ -3951,7 +4687,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
dependencies = [
"nix 0.24.3",
- "wayland-client",
+ "wayland-client 0.29.5",
+ "xcursor",
+]
+
+[[package]]
+name = "wayland-cursor"
+version = "0.31.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a94697e66e76c85923b0d28a0c251e8f0666f58fc47d316c0f4da6da75d37cb"
+dependencies = [
+ "rustix",
+ "wayland-client 0.31.6",
"xcursor",
]
@@ -3962,9 +4709,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
dependencies = [
"bitflags 1.3.2",
- "wayland-client",
+ "wayland-client 0.29.5",
"wayland-commons",
- "wayland-scanner",
+ "wayland-scanner 0.29.5",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.32.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b5755d77ae9040bb872a25026555ce4cb0ae75fd923e90d25fba07d81057de0"
+dependencies = [
+ "bitflags 2.5.0",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+ "wayland-scanner 0.31.5",
+]
+
+[[package]]
+name = "wayland-protocols-plasma"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a0a41a6875e585172495f7a96dfa42ca7e0213868f4f15c313f7c33221a7eff"
+dependencies = [
+ "bitflags 2.5.0",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+ "wayland-protocols 0.32.4",
+ "wayland-scanner 0.31.5",
+]
+
+[[package]]
+name = "wayland-protocols-wlr"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dad87b5fd1b1d3ca2f792df8f686a2a11e3fe1077b71096f7a175ab699f89109"
+dependencies = [
+ "bitflags 2.5.0",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+ "wayland-protocols 0.32.4",
+ "wayland-scanner 0.31.5",
]
[[package]]
@@ -3978,6 +4763,17 @@ dependencies = [
"xml-rs",
]
+[[package]]
+name = "wayland-scanner"
+version = "0.31.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3"
+dependencies = [
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+]
+
[[package]]
name = "wayland-sys"
version = "0.29.5"
@@ -3989,6 +4785,18 @@ dependencies = [
"pkg-config",
]
+[[package]]
+name = "wayland-sys"
+version = "0.31.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09"
+dependencies = [
+ "dlib",
+ "log",
+ "once_cell",
+ "pkg-config",
+]
+
[[package]]
name = "web-sys"
version = "0.3.69"
@@ -3999,19 +4807,30 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
[[package]]
name = "webbrowser"
-version = "0.8.13"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1b04c569c83a9bb971dd47ec6fd48753315f4bf989b9b04a2e7ca4d7f0dc950"
+checksum = "425ba64c1e13b1c6e8c5d2541c8fac10022ca584f33da781db01b5756aef1f4e"
dependencies = [
+ "block2 0.5.1",
"core-foundation",
"home",
"jni",
"log",
"ndk-context",
- "objc",
- "raw-window-handle",
+ "objc2 0.5.2",
+ "objc2-foundation",
"url",
"web-sys",
]
@@ -4059,7 +4878,17 @@ version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
- "windows-core",
+ "windows-core 0.54.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
+dependencies = [
+ "windows-core 0.56.0",
"windows-targets 0.52.6",
]
@@ -4073,11 +4902,45 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-core"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.58",
+]
+
[[package]]
name = "windows-result"
-version = "0.1.0"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
@@ -4302,35 +5165,87 @@ version = "0.28.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94"
dependencies = [
- "android-activity",
+ "android-activity 0.4.3",
"bitflags 1.3.2",
- "cfg_aliases",
+ "cfg_aliases 0.1.1",
"core-foundation",
- "core-graphics",
+ "core-graphics 0.22.3",
"dispatch",
"instant",
"libc",
"log",
"mio",
"ndk 0.7.0",
- "objc2",
+ "objc2 0.3.0-beta.3.patch-leaks.3",
"once_cell",
"orbclient",
"percent-encoding",
- "raw-window-handle",
+ "raw-window-handle 0.5.2",
"redox_syscall 0.3.5",
- "sctk-adwaita",
- "smithay-client-toolkit",
+ "sctk-adwaita 0.5.4",
+ "smithay-client-toolkit 0.16.1",
"wasm-bindgen",
- "wayland-client",
+ "wayland-client 0.29.5",
"wayland-commons",
- "wayland-protocols",
- "wayland-scanner",
+ "wayland-protocols 0.29.5",
+ "wayland-scanner 0.29.5",
"web-sys",
"windows-sys 0.45.0",
"x11-dl",
]
+[[package]]
+name = "winit"
+version = "0.30.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67"
+dependencies = [
+ "ahash",
+ "android-activity 0.6.0",
+ "atomic-waker",
+ "bitflags 2.5.0",
+ "block2 0.5.1",
+ "bytemuck",
+ "calloop 0.13.0",
+ "cfg_aliases 0.2.1",
+ "concurrent-queue",
+ "core-foundation",
+ "core-graphics 0.23.2",
+ "cursor-icon",
+ "dpi",
+ "js-sys",
+ "libc",
+ "memmap2 0.9.5",
+ "ndk 0.9.0",
+ "objc2 0.5.2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "objc2-ui-kit",
+ "orbclient",
+ "percent-encoding",
+ "pin-project",
+ "raw-window-handle 0.6.2",
+ "redox_syscall 0.4.1",
+ "rustix",
+ "sctk-adwaita 0.10.1",
+ "smithay-client-toolkit 0.19.2",
+ "smol_str",
+ "tracing",
+ "unicode-segmentation",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wayland-backend",
+ "wayland-client 0.31.6",
+ "wayland-protocols 0.32.4",
+ "wayland-protocols-plasma",
+ "web-sys",
+ "web-time",
+ "windows-sys 0.52.0",
+ "x11-dl",
+ "x11rb",
+ "xkbcommon-dl",
+]
+
[[package]]
name = "winnow"
version = "0.5.40"
@@ -4342,9 +5257,9 @@ dependencies = [
[[package]]
name = "winnow"
-version = "0.6.5"
+version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
+checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
dependencies = [
"memchr",
]
@@ -4375,8 +5290,12 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
dependencies = [
+ "as-raw-xcb-connection",
"gethostname",
- "rustix 0.38.32",
+ "libc",
+ "libloading 0.8.3",
+ "once_cell",
+ "rustix",
"x11rb-protocol",
]
@@ -4394,14 +5313,33 @@ checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911"
[[package]]
name = "xdg-home"
-version = "1.1.0"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e"
+checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
dependencies = [
"libc",
- "winapi",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "xkbcommon-dl"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
+dependencies = [
+ "bitflags 2.5.0",
+ "dlib",
+ "log",
+ "once_cell",
+ "xkeysym",
]
+[[package]]
+name = "xkeysym"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
+
[[package]]
name = "xml-rs"
version = "0.8.20"
@@ -4433,6 +5371,7 @@ dependencies = [
"lazy_static",
"proc-macro2",
"rayon",
+ "serde",
"simdeez",
"spin_sleep",
"symphonia",
@@ -4454,6 +5393,7 @@ dependencies = [
"crossbeam-channel",
"lazy_static",
"rayon",
+ "serde",
"spin_sleep",
"to_vec",
"wav",
@@ -4478,30 +5418,28 @@ dependencies = [
[[package]]
name = "zbus"
-version = "3.15.2"
+version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6"
+checksum = "c9ff46f2a25abd690ed072054733e0bc3157e3d4c45f41bd183dce09c2ff8ab9"
dependencies = [
"async-broadcast",
"async-executor",
- "async-fs 1.6.0",
- "async-io 1.13.0",
- "async-lock 2.8.0",
+ "async-fs",
+ "async-io",
+ "async-lock",
"async-process",
"async-recursion",
"async-task",
"async-trait",
"blocking",
- "byteorder",
"derivative",
"enumflags2",
- "event-listener 2.5.3",
+ "event-listener",
"futures-core",
"futures-sink",
"futures-util",
"hex",
- "nix 0.26.4",
- "once_cell",
+ "nix 0.28.0",
"ordered-stream",
"rand",
"serde",
@@ -4510,7 +5448,7 @@ dependencies = [
"static_assertions",
"tracing",
"uds_windows",
- "winapi",
+ "windows-sys 0.52.0",
"xdg-home",
"zbus_macros",
"zbus_names",
@@ -4519,11 +5457,11 @@ dependencies = [
[[package]]
name = "zbus_macros"
-version = "3.15.2"
+version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5"
+checksum = "4e0e3852c93dcdb49c9462afe67a2a468f7bd464150d866e861eaf06208633e0"
dependencies = [
- "proc-macro-crate 1.3.1",
+ "proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"regex",
@@ -4533,9 +5471,9 @@ dependencies = [
[[package]]
name = "zbus_names"
-version = "2.6.1"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d"
+checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
dependencies = [
"serde",
"static_assertions",
@@ -4562,6 +5500,12 @@ dependencies = [
"syn 2.0.58",
]
+[[package]]
+name = "zune-core"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
+
[[package]]
name = "zune-inflate"
version = "0.2.54"
@@ -4571,15 +5515,23 @@ dependencies = [
"simd-adler32",
]
+[[package]]
+name = "zune-jpeg"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768"
+dependencies = [
+ "zune-core",
+]
+
[[package]]
name = "zvariant"
-version = "3.15.2"
+version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db"
+checksum = "2c1b3ca6db667bfada0f1ebfc94b2b1759ba25472ee5373d4551bb892616389a"
dependencies = [
- "byteorder",
+ "endi",
"enumflags2",
- "libc",
"serde",
"static_assertions",
"url",
@@ -4588,11 +5540,11 @@ dependencies = [
[[package]]
name = "zvariant_derive"
-version = "3.15.2"
+version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9"
+checksum = "b7a4b236063316163b69039f77ce3117accb41a09567fd24c168e43491e521bc"
dependencies = [
- "proc-macro-crate 1.3.1",
+ "proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 1.0.109",
@@ -4601,9 +5553,9 @@ dependencies = [
[[package]]
name = "zvariant_utils"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200"
+checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 580b9c1..acb15b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,55 +1,56 @@
[package]
name = "wasabi"
-version = "0.1.4"
+version = "1.0.0"
edition = "2021"
[dependencies]
-egui_winit_vulkano = "0.24.0"
-vulkano-shaders = "0.33.0"
-vulkano-win = "0.33.0"
-vulkano-util = "0.33.0"
-egui-winit = "0.21.1"
-bytemuck = "1.13.1"
-vulkano = "0.33.0"
-kdmapi = { git = "https://github.com/arduano/kdmapi.git", rev = "4116b00" }
-egui = "0.21.0"
-winit = "0.28.3"
-rayon = "1.7.0"
+egui = { version = "0.29", features = ["serde"] }
+egui_extras = { version = "0.29", features = ["svg"] }
+egui-winit = "0.29"
+egui_winit_vulkano = { git = "https://github.com/MyBlackMIDIScore/egui_winit_vulkano.git", rev = "aa24f97" }
+winit = { version = "0.30", default-features = false }
+raw-window-handle = "0.6"
+vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", rev = "4a77d39" }
+vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", rev = "4a77d39" }
+vulkano-win = { git = "https://github.com/vulkano-rs/vulkano.git", rev = "4a77d39" }
midi-toolkit-rs = "0.1.0"
-xsynth-core = "0.3.1"
-xsynth-realtime = "0.3.1"
+xsynth-core = { version = "0.3.1", features = ["serde"] }
+xsynth-realtime = { version = "0.3.1", features = ["serde"] }
+kdmapi-rs = { package = "kdmapi", git = "https://github.com/arduano/kdmapi.git", rev = "4116b00" }
+serde = "1.0.210"
+serde_derive = "1.0.210"
+serde_json = "1.0"
+toml = "0.8.19"
+bytemuck = "1.18.0"
+rayon = "1.10"
+enum_dispatch = "0.3.13"
gen-iter = { git = "https://github.com/arduano/gen-iter.git", rev = "64e28bc" }
-enum_dispatch = "0.3.11"
-palette = "0.7.1"
-crossbeam-channel = "0.5.8"
+crossbeam-channel = "0.5.13"
+rustc-hash = "2.0.0"
rand = "0.8.5"
-confy = "0.5.1"
-serde_derive = "1.0.160"
-serde = "1.0.160"
-toml = "0.8.0"
-colors-transform = "0.2.11"
-directories = "5.0.0"
-rustc-hash = "1.1.0"
-atomic_float = "0.1.0"
-ico = { git = "https://github.com/StratusFearMe21/rust-ico", branch = "patch-1" }
-clap = "4.2.4"
-num_enum = "0.7.0"
-rfd = { version = "0.12.0", default-features = false, features = [
- 'xdg-portal',
-] }
-time = "0.3.36"
+directories = "5.0.1"
+atomic_float = "1.1.0"
+ico = "0.3.0"
+rfd = "0.15.0"
+open = "5.3.0"
-[profile.dev]
-opt-level = 2
+num_enum = "0.7.3"
+palette = "0.7.6"
+colors-transform = "0.2"
+midir = "0.10.0"
-[profile.release]
-opt-level = 3
-codegen-units = 1
-lto = true
[build-dependencies]
resvg = { version = "0.31.0", default-features = false }
-ico = { git = "https://github.com/StratusFearMe21/rust-ico", branch = "patch-1" }
+ico = "0.3.0"
[target.'cfg(windows)'.build-dependencies]
winres = "0.1.12"
+
+[profile.dev]
+opt-level = 2
+
+[profile.release]
+opt-level = 3
+codegen-units = 1
+lto = true
diff --git a/assets/Poppins-Bold.ttf b/assets/Poppins-Bold.ttf
new file mode 100644
index 0000000..00559ee
Binary files /dev/null and b/assets/Poppins-Bold.ttf differ
diff --git a/assets/Poppins-Medium.ttf b/assets/Poppins-Medium.ttf
new file mode 100644
index 0000000..6bcdcc2
Binary files /dev/null and b/assets/Poppins-Medium.ttf differ
diff --git a/assets/UbuntuSansMono-Medium.ttf b/assets/UbuntuSansMono-Medium.ttf
new file mode 100644
index 0000000..147bc5a
Binary files /dev/null and b/assets/UbuntuSansMono-Medium.ttf differ
diff --git a/assets/folder.svg b/assets/folder.svg
new file mode 100644
index 0000000..4bf65d8
--- /dev/null
+++ b/assets/folder.svg
@@ -0,0 +1,41 @@
+
+
+
+
diff --git a/assets/logo.svg b/assets/logo.svg
new file mode 100644
index 0000000..e4a6e4f
--- /dev/null
+++ b/assets/logo.svg
@@ -0,0 +1,493 @@
+
+
+
+
diff --git a/assets/logo_16.svg b/assets/logo_16.svg
new file mode 100644
index 0000000..47fcd9f
--- /dev/null
+++ b/assets/logo_16.svg
@@ -0,0 +1,493 @@
+
+
+
+
diff --git a/assets/options.svg b/assets/options.svg
new file mode 100644
index 0000000..2721548
--- /dev/null
+++ b/assets/options.svg
@@ -0,0 +1,53 @@
+
+
+
+
diff --git a/assets/pause.svg b/assets/pause.svg
new file mode 100644
index 0000000..88b8442
--- /dev/null
+++ b/assets/pause.svg
@@ -0,0 +1,54 @@
+
+
+
+
diff --git a/assets/pin.svg b/assets/pin.svg
new file mode 100644
index 0000000..d50933b
--- /dev/null
+++ b/assets/pin.svg
@@ -0,0 +1,44 @@
+
+
+
+
diff --git a/assets/play.svg b/assets/play.svg
new file mode 100644
index 0000000..d253bd0
--- /dev/null
+++ b/assets/play.svg
@@ -0,0 +1,45 @@
+
+
+
+
diff --git a/assets/stop.svg b/assets/stop.svg
new file mode 100644
index 0000000..bb2d1dc
--- /dev/null
+++ b/assets/stop.svg
@@ -0,0 +1,48 @@
+
+
+
+
diff --git a/src/audio_playback/empty.rs b/src/audio_playback/empty.rs
new file mode 100644
index 0000000..add11c7
--- /dev/null
+++ b/src/audio_playback/empty.rs
@@ -0,0 +1,23 @@
+use super::*;
+
+pub struct EmptyPlayer {}
+
+impl EmptyPlayer {
+ pub fn new() -> Self {
+ Self {}
+ }
+}
+
+impl MidiAudioPlayer for EmptyPlayer {
+ fn reset(&mut self) {}
+
+ fn push_event(&mut self, _data: u32) {}
+
+ fn voice_count(&self) -> u64 {
+ 0
+ }
+
+ fn configure(&mut self, _settings: &SynthSettings) {}
+
+ fn set_soundfonts(&mut self, _soundfonts: &Vec) {}
+}
diff --git a/src/audio_playback/kdmapi.rs b/src/audio_playback/kdmapi.rs
new file mode 100644
index 0000000..672407b
--- /dev/null
+++ b/src/audio_playback/kdmapi.rs
@@ -0,0 +1,40 @@
+use super::*;
+use kdmapi_rs::{KDMAPIStream, KDMAPI};
+
+pub struct KdmapiPlayer {
+ stream: KDMAPIStream,
+ use_om_list: bool,
+}
+
+impl KdmapiPlayer {
+ pub fn new() -> Self {
+ Self {
+ stream: KDMAPI.open_stream(),
+ use_om_list: false,
+ }
+ }
+}
+
+impl MidiAudioPlayer for KdmapiPlayer {
+ fn reset(&mut self) {
+ self.stream.reset();
+ }
+
+ fn push_event(&mut self, data: u32) {
+ self.stream.send_direct_data(data);
+ }
+
+ fn voice_count(&self) -> u64 {
+ 0
+ }
+
+ fn configure(&mut self, settings: &SynthSettings) {
+ self.use_om_list = settings.kdmapi.use_om_sflist;
+ }
+
+ fn set_soundfonts(&mut self, _soundfonts: &Vec) {
+ if !self.use_om_list {
+ // TODO: Create OM compatible SF list to be sent through "LoadCustomSoundFontsList"
+ }
+ }
+}
diff --git a/src/audio_playback/midiout.rs b/src/audio_playback/midiout.rs
new file mode 100644
index 0000000..2312390
--- /dev/null
+++ b/src/audio_playback/midiout.rs
@@ -0,0 +1,60 @@
+use std::thread;
+
+use super::*;
+use crossbeam_channel::Sender;
+use midir::MidiOutput;
+
+pub struct MidiDevicePlayer {
+ sender: Sender,
+}
+
+impl MidiDevicePlayer {
+ pub fn new(device: String) -> Result {
+ let out = MidiOutput::new("wasabi").map_err(|e| format!("{:?}", e))?;
+ let ports = out.ports();
+ if ports.is_empty() {
+ return Err("No MIDI devices available.".into());
+ }
+
+ let find = ports.iter().find(|d| {
+ if let Ok(name) = out.port_name(d) {
+ name == device
+ } else {
+ false
+ }
+ });
+ let found = find.unwrap_or(&ports[0]);
+ let mut connection = out
+ .connect(found, "wasabi")
+ .map_err(|e| format!("{:?}", e))?;
+
+ let (sender, receiver) = crossbeam_channel::bounded::(1000);
+
+ thread::spawn(move || {
+ for data in receiver {
+ let message = data.to_le_bytes();
+ connection.send(&message).unwrap_or_default();
+ }
+ });
+
+ Ok(Self { sender })
+ }
+}
+
+impl MidiAudioPlayer for MidiDevicePlayer {
+ fn reset(&mut self) {
+ // TODO: With CC maybe?
+ }
+
+ fn push_event(&mut self, data: u32) {
+ self.sender.send(data).unwrap();
+ }
+
+ fn voice_count(&self) -> u64 {
+ 0
+ }
+
+ fn configure(&mut self, _settings: &SynthSettings) {}
+
+ fn set_soundfonts(&mut self, _soundfonts: &Vec) {}
+}
diff --git a/src/audio_playback/mod.rs b/src/audio_playback/mod.rs
index dceb4c5..1d46af5 100644
--- a/src/audio_playback/mod.rs
+++ b/src/audio_playback/mod.rs
@@ -1,123 +1,54 @@
-use kdmapi::{KDMAPIStream, KDMAPI};
-use std::ops::RangeInclusive;
-use xsynth_core::{channel::ChannelInitOptions, soundfont::SoundfontInitOptions};
-pub mod xsynth;
-
-#[derive(Clone)]
-pub enum AudioPlayerType {
- XSynth {
- buffer: f64,
- use_threadpool: bool,
- ignore_range: RangeInclusive,
- options: ChannelInitOptions,
- },
- Kdmapi,
+use crate::settings::{SynthSettings, WasabiSoundfont};
+
+mod xsynth;
+pub use xsynth::*;
+mod kdmapi;
+pub use kdmapi::*;
+mod midiout;
+pub use midiout::*;
+mod empty;
+pub use empty::*;
+
+pub trait MidiAudioPlayer: Send + Sync {
+ fn voice_count(&self) -> u64;
+ fn push_event(&mut self, data: u32);
+ fn configure(&mut self, settings: &SynthSettings);
+ fn set_soundfonts(&mut self, soundfonts: &Vec);
+ fn reset(&mut self);
}
-pub struct SimpleTemporaryPlayer {
- player_type: AudioPlayerType,
- xsynth: Option,
- kdmapi: Option,
+pub struct WasabiAudioPlayer {
+ player: Box,
}
-impl SimpleTemporaryPlayer {
- pub fn new(player_type: AudioPlayerType) -> Self {
- let (xsynth, kdmapi) = match player_type.clone() {
- AudioPlayerType::XSynth {
- buffer,
- use_threadpool,
- ignore_range,
- options,
- } => {
- let xsynth =
- xsynth::XSynthPlayer::new(buffer, use_threadpool, ignore_range, options);
- (Some(xsynth), None)
- }
- AudioPlayerType::Kdmapi => {
- let kdmapi = KDMAPI.open_stream();
- (None, Some(kdmapi))
- }
- };
- Self {
- player_type,
- xsynth,
- kdmapi,
- }
+impl WasabiAudioPlayer {
+ pub fn new(player: Box) -> Self {
+ Self { player: player }
}
- pub fn switch_player(&mut self, player_type: AudioPlayerType) {
- self.reset();
- self.xsynth = None;
- self.kdmapi = None;
- let new_player = Self::new(player_type);
-
- self.player_type = new_player.player_type;
- self.xsynth = new_player.xsynth;
- self.kdmapi = new_player.kdmapi;
+ pub fn switch(&mut self, new_player: Box) {
+ self.player = new_player;
}
- pub fn get_voice_count(&self) -> u64 {
- match self.player_type {
- AudioPlayerType::XSynth { .. } => {
- if let Some(xsynth) = &self.xsynth {
- xsynth.get_voice_count()
- } else {
- 0
- }
- }
- AudioPlayerType::Kdmapi => 0,
- }
+ pub fn voice_count(&self) -> u64 {
+ self.player.voice_count()
}
pub fn push_events(&mut self, data: impl Iterator- ) {
- for e in data {
- self.push_event(e);
- }
- }
-
- pub fn push_event(&mut self, data: u32) {
- match self.player_type {
- AudioPlayerType::XSynth { .. } => {
- if let Some(xsynth) = self.xsynth.as_mut() {
- xsynth.push_event(data);
- }
- }
- AudioPlayerType::Kdmapi => {
- if let Some(kdmapi) = self.kdmapi.as_mut() {
- kdmapi.send_direct_data(data);
- }
- }
+ for ev in data {
+ self.player.push_event(ev);
}
}
- pub fn reset(&mut self) {
- match self.player_type {
- AudioPlayerType::XSynth { .. } => {
- if let Some(xsynth) = self.xsynth.as_mut() {
- xsynth.reset();
- }
- }
- AudioPlayerType::Kdmapi => {
- if let Some(kdmapi) = self.kdmapi.as_mut() {
- kdmapi.reset();
- }
- }
- }
+ pub fn configure(&mut self, settings: &SynthSettings) {
+ self.player.configure(settings);
}
- pub fn set_layer_count(&mut self, layers: Option) {
- if let AudioPlayerType::XSynth { .. } = self.player_type {
- if let Some(xsynth) = self.xsynth.as_mut() {
- xsynth.set_layer_count(layers);
- }
- }
+ pub fn set_soundfonts(&mut self, soundfonts: &Vec) {
+ self.player.set_soundfonts(soundfonts);
}
- pub fn set_soundfont(&mut self, path: &str, options: SoundfontInitOptions) {
- if let AudioPlayerType::XSynth { .. } = self.player_type {
- if let Some(xsynth) = self.xsynth.as_mut() {
- xsynth.set_soundfont(path, options);
- }
- }
+ pub fn reset(&mut self) {
+ self.player.reset();
}
}
diff --git a/src/audio_playback/xsynth.rs b/src/audio_playback/xsynth.rs
index fda330d..8e9e982 100644
--- a/src/audio_playback/xsynth.rs
+++ b/src/audio_playback/xsynth.rs
@@ -1,21 +1,21 @@
use std::{
- ops::{Deref, DerefMut, RangeInclusive},
- path::Path,
+ ops::{Deref, DerefMut},
sync::Arc,
};
-use crate::WasabiSettings;
+use crate::settings::WasabiSoundfont;
use xsynth_core::{
- channel::{ChannelConfigEvent, ChannelEvent, ChannelInitOptions},
- soundfont::{EnvelopeOptions, SampleSoundfont, SoundfontBase, SoundfontInitOptions},
+ channel::{ChannelConfigEvent, ChannelEvent},
+ soundfont::{SampleSoundfont, SoundfontBase},
AudioStreamParams,
};
use xsynth_realtime::{
- RealtimeEventSender, RealtimeSynth, RealtimeSynthStatsReader, SynthEvent, ThreadCount,
- XSynthRealtimeConfig,
+ RealtimeEventSender, RealtimeSynth, RealtimeSynthStatsReader, SynthEvent, XSynthRealtimeConfig,
};
+use super::*;
+
#[repr(transparent)]
struct FuckYouImSend(T);
@@ -38,30 +38,13 @@ impl DerefMut for FuckYouImSend {
pub struct XSynthPlayer {
sender: RealtimeEventSender,
- pub stats: RealtimeSynthStatsReader,
+ stats: RealtimeSynthStatsReader,
stream_params: AudioStreamParams,
_synth: FuckYouImSend,
}
impl XSynthPlayer {
- pub fn new(
- buffer: f64,
- use_threadpool: bool,
- ignore_range: RangeInclusive,
- options: ChannelInitOptions,
- ) -> Self {
- let config = XSynthRealtimeConfig {
- render_window_ms: buffer,
- channel_init_options: options,
- ignore_range,
- multithreading: if use_threadpool {
- ThreadCount::Auto
- } else {
- ThreadCount::None
- },
- ..Default::default()
- };
-
+ pub fn new(config: XSynthRealtimeConfig) -> Self {
let synth = FuckYouImSend(RealtimeSynth::open_with_default_output(config));
let sender = synth.get_senders();
let stream_params = synth.stream_params();
@@ -74,50 +57,51 @@ impl XSynthPlayer {
_synth: synth,
}
}
+}
- pub fn get_voice_count(&self) -> u64 {
+impl MidiAudioPlayer for XSynthPlayer {
+ fn voice_count(&self) -> u64 {
self.stats.voice_count()
}
- pub fn push_event(&mut self, data: u32) {
+ fn push_event(&mut self, data: u32) {
self.sender.send_event_u32(data);
}
- pub fn reset(&mut self) {
+ fn reset(&mut self) {
self.sender.reset_synth();
}
- pub fn set_layer_count(&mut self, layers: Option) {
+ fn configure(&mut self, settings: &SynthSettings) {
+ let layers = if settings.xsynth.limit_layers {
+ Some(settings.xsynth.layers)
+ } else {
+ None
+ };
+
self.sender
.send_event(SynthEvent::AllChannels(ChannelEvent::Config(
ChannelConfigEvent::SetLayerCount(layers),
)));
}
- pub fn set_soundfont(&mut self, path: &str, options: SoundfontInitOptions) {
- if !path.is_empty() && Path::new(path).exists() {
- let samplesf = SampleSoundfont::new(path, self.stream_params, options);
- if let Ok(sf) = samplesf {
- let soundfont: Arc = Arc::new(sf);
- self.sender
- .send_event(SynthEvent::AllChannels(ChannelEvent::Config(
- ChannelConfigEvent::SetSoundfonts(vec![soundfont]),
- )));
+ fn set_soundfonts(&mut self, soundfonts: &Vec) {
+ // TODO: Load in thread
+ let mut out: Vec> = Vec::new();
+
+ for sf in soundfonts {
+ if sf.enabled {
+ if let Ok(sf) =
+ SampleSoundfont::new(sf.path.clone(), self.stream_params, sf.options)
+ {
+ out.push(Arc::new(sf));
+ }
}
}
- }
-}
-
-pub fn convert_to_sf_init(settings: &WasabiSettings) -> SoundfontInitOptions {
- SoundfontInitOptions {
- vol_envelope_options: EnvelopeOptions::default(),
- use_effects: settings.synth.use_effects,
- ..Default::default()
- }
-}
-pub fn convert_to_channel_init(settings: &WasabiSettings) -> ChannelInitOptions {
- ChannelInitOptions {
- fade_out_killing: settings.synth.fade_out_kill,
+ self.sender
+ .send_event(SynthEvent::AllChannels(ChannelEvent::Config(
+ ChannelConfigEvent::SetSoundfonts(out),
+ )));
}
}
diff --git a/src/gui/window.rs b/src/gui/window.rs
index 7f8bceb..3501d65 100644
--- a/src/gui/window.rs
+++ b/src/gui/window.rs
@@ -4,68 +4,57 @@ mod keyboard_layout;
mod scene;
mod stats;
-mod settings_window;
-mod top_panel;
-mod xsynth_settings;
+mod about;
+mod playback_panel;
+mod settings;
+mod shortcuts;
-use std::{
- path::PathBuf,
- sync::{Arc, RwLock},
-};
-use time::Duration;
+use std::path::Path;
+use std::sync::{Arc, RwLock};
+use std::thread;
+use std::{path::PathBuf, time::Duration};
-use egui::{style::Margin, Frame, Visuals};
+use crossbeam_channel::{Receiver, Sender};
+use egui::FontFamily::{Monospace, Proportional};
+use egui::FontId;
+use egui::Frame;
+use settings::SettingsWindow;
+use crate::audio_playback::{EmptyPlayer, MidiDevicePlayer};
use crate::{
- audio_playback::{
- xsynth::{convert_to_channel_init, convert_to_sf_init},
- AudioPlayerType, SimpleTemporaryPlayer,
- },
+ audio_playback::{KdmapiPlayer, MidiAudioPlayer, WasabiAudioPlayer, XSynthPlayer},
gui::window::{keyboard::GuiKeyboard, scene::GuiRenderScene},
midi::{CakeMIDIFile, InRamMIDIFile, LiveLoadMIDIFile, MIDIFileBase, MIDIFileUnion},
- settings::{MidiLoading, Synth, WasabiSettings},
+ settings::{MidiParsing, Synth, WasabiSettings},
state::WasabiState,
GuiRenderer, GuiState,
};
+const WIN_MARGIN: egui::Margin = egui::Margin::same(12.0);
+const SPACE: f32 = 12.0;
+
pub struct GuiWasabiWindow {
render_scene: GuiRenderScene,
keyboard_layout: keyboard_layout::KeyboardLayout,
keyboard: GuiKeyboard,
midi_file: Option,
- synth: Arc>,
+ synth: Arc>,
fps: fps::Fps,
+
+ settings_win: SettingsWindow,
+ midi_picker: (Sender, Receiver),
}
impl GuiWasabiWindow {
pub fn new(renderer: &mut GuiRenderer, settings: &mut WasabiSettings) -> GuiWasabiWindow {
- let synth = match settings.synth.synth {
- Synth::Kdmapi => Arc::new(RwLock::new(SimpleTemporaryPlayer::new(
- AudioPlayerType::Kdmapi,
- ))),
- Synth::XSynth => {
- let synth = Arc::new(RwLock::new(SimpleTemporaryPlayer::new(
- AudioPlayerType::XSynth {
- buffer: settings.synth.buffer_ms,
- use_threadpool: settings.synth.use_threadpool,
- ignore_range: settings.synth.vel_ignore.clone(),
- options: convert_to_channel_init(settings),
- },
- )));
- synth
- .write()
- .unwrap()
- .set_soundfont(&settings.synth.sfz_path, convert_to_sf_init(settings));
- synth
- .write()
- .unwrap()
- .set_layer_count(match settings.synth.layer_count {
- 0 => None,
- _ => Some(settings.synth.layer_count),
- });
- synth
- }
- };
+ let synth = Self::create_synth(settings);
+ let synth = Arc::new(RwLock::new(WasabiAudioPlayer::new(synth)));
+
+ let mut settings_win = SettingsWindow::new(settings);
+ settings_win.load_palettes();
+ settings_win.load_midi_devices(settings);
+
+ let midi_picker = crossbeam_channel::unbounded();
GuiWasabiWindow {
render_scene: GuiRenderScene::new(renderer),
@@ -74,32 +63,143 @@ impl GuiWasabiWindow {
midi_file: None,
synth,
fps: fps::Fps::new(),
+
+ settings_win,
+ midi_picker,
}
}
+ #[inline(always)]
+ fn set_style(ctx: &egui::Context, _settings: &WasabiSettings) {
+ // Set theme
+ ctx.style_mut(|style| {
+ style.visuals.panel_fill = egui::Color32::from_rgb(18, 18, 18);
+ style.visuals.window_fill = style.visuals.panel_fill;
+ style.visuals.widgets.inactive.weak_bg_fill = style.visuals.panel_fill;
+ style.visuals.widgets.hovered.bg_stroke = egui::Stroke::NONE;
+ style.visuals.widgets.active.bg_stroke = egui::Stroke::NONE;
+
+ style.visuals.selection.bg_fill = style.visuals.widgets.active.weak_bg_fill;
+ style.visuals.selection.stroke.color = egui::Color32::TRANSPARENT;
+
+ style.visuals.override_text_color = Some(egui::Color32::from_rgb(210, 210, 210));
+
+ style.spacing.menu_margin = egui::Margin::same(8.0);
+ style.spacing.interact_size.y = 26.0;
+ });
+
+ // Set fonts
+ let mut fonts = egui::FontDefinitions::default();
+
+ fonts.font_data.insert(
+ "poppins".to_owned(),
+ egui::FontData::from_static(include_bytes!("../../assets/Poppins-Medium.ttf")),
+ );
+ fonts
+ .families
+ .get_mut(&egui::FontFamily::Proportional)
+ .unwrap()
+ .insert(0, "poppins".to_owned());
+
+ fonts.font_data.insert(
+ "ubuntu".to_owned(),
+ egui::FontData::from_static(include_bytes!("../../assets/UbuntuSansMono-Medium.ttf")),
+ );
+ fonts
+ .families
+ .get_mut(&egui::FontFamily::Monospace)
+ .unwrap()
+ .insert(0, "ubuntu".to_owned());
+
+ ctx.set_fonts(fonts);
+
+ // Set font size
+ let mut style = (*ctx.style()).clone();
+ style.text_styles = [
+ (egui::TextStyle::Heading, FontId::new(26.0, Proportional)),
+ (egui::TextStyle::Body, FontId::new(16.0, Proportional)),
+ (egui::TextStyle::Monospace, FontId::new(12.0, Monospace)),
+ (egui::TextStyle::Button, FontId::new(16.0, Proportional)),
+ (egui::TextStyle::Small, FontId::new(12.0, Proportional)),
+ (
+ egui::TextStyle::Name("monospace big".into()),
+ FontId::new(22.0, Monospace),
+ ),
+ ]
+ .into();
+ ctx.set_style(style);
+ }
+
/// Defines the layout of our UI
pub fn layout(
&mut self,
- state: &mut GuiState,
+ gui_state: &mut GuiState,
settings: &mut WasabiSettings,
- wasabi_state: &mut WasabiState,
+ state: &mut WasabiState,
) {
- let ctx = state.renderer.gui.context();
- self.fps.update();
- ctx.set_visuals(Visuals::dark());
+ let ctx = gui_state.renderer.gui.context();
+
+ let fps_limit = match settings.gui.fps_limit {
+ 0 => None,
+ f => Some(f),
+ };
+ self.fps.update(fps_limit);
+ Self::set_style(&ctx, settings);
- if wasabi_state.settings_visible {
- settings_window::draw_settings(self, settings, wasabi_state, &ctx);
+ {
+ let recv = self.midi_picker.1.clone();
+ if !recv.is_empty() {
+ for midi in recv {
+ state.last_location = midi.clone();
+ self.load_midi(settings, midi);
+ break;
+ }
+ }
}
- if wasabi_state.xsynth_settings_visible {
- xsynth_settings::draw_xsynth_settings(self, settings, wasabi_state, &ctx);
+
+ // Other windows
+ if state.show_settings {
+ self.settings_win
+ .show(&ctx, settings, state, self.synth.clone());
}
- let height_prev = ctx.available_rect().height();
- if settings.visual.show_top_pannel {
- top_panel::draw_panel(self, settings, wasabi_state, &ctx);
+ if state.show_about {
+ self.show_about(&ctx, state);
+ }
+
+ if state.show_shortcuts {
+ self.show_shortcuts(&ctx, state);
}
+ // Set global keyboard shortcuts
+ ctx.input(|events| {
+ for event in &events.events {
+ if let egui::Event::Key {
+ key,
+ pressed,
+ modifiers,
+ ..
+ } = event
+ {
+ if *pressed && modifiers.ctrl {
+ match key {
+ egui::Key::F => state.panel_pinned = !state.panel_pinned,
+ egui::Key::G => state.stats_visible = !state.stats_visible,
+ egui::Key::O => self.open_midi_dialog(state),
+ _ => {}
+ }
+ }
+ if *pressed && modifiers.alt && key == &egui::Key::Enter {
+ state.fullscreen = !state.fullscreen
+ }
+ }
+ }
+ });
+
+ // Render the panel
+ let height_prev = ctx.available_rect().height();
+ self.show_playback_panel(&ctx, state);
+
// Calculate available space left for keyboard and notes
// We must render notes before keyboard because the notes
// renderer tells us the key colors
@@ -107,21 +207,21 @@ impl GuiWasabiWindow {
let height = available.height();
let panel_height = height_prev - height;
let keyboard_height =
- (11.6 / settings.midi.key_range.len() as f32 * available.width()).min(height / 2.0);
+ (11.6 / settings.scene.key_range.len() as f32 * available.width()).min(height / 2.0);
let notes_height = height - keyboard_height;
let key_view = self.keyboard_layout.get_view_for_keys(
- *settings.midi.key_range.start() as usize,
- *settings.midi.key_range.end() as usize,
+ *settings.scene.key_range.start() as usize,
+ *settings.scene.key_range.end() as usize,
);
let no_frame = Frame::default()
- .inner_margin(Margin::same(0.0))
- .fill(settings.visual.bg_color);
+ .inner_margin(egui::Margin::same(0.0))
+ .fill(settings.scene.bg_color);
let mut stats = stats::GuiMidiStats::empty();
- let mut render_result_data = None;
+ let mut render_result_data: Option = None;
// Render the notes
egui::TopBottomPanel::top("Note panel")
@@ -130,31 +230,45 @@ impl GuiWasabiWindow {
.show_separator_line(false)
.show(&ctx, |ui| {
if let Some(midi_file) = self.midi_file.as_mut() {
- let one_sec = Duration::seconds(1);
+ let skip_dur = Duration::from_secs_f64(settings.gui.skip_control);
let time = midi_file.timer().get_time();
+ // Set playback keyboard shortcuts
ui.input(|events| {
for event in &events.events {
- if let egui::Event::Key { key, pressed, .. } = event {
+ if let egui::Event::Key {
+ key,
+ pressed,
+ modifiers,
+ ..
+ } = event
+ {
if pressed == &true {
match key {
egui::Key::ArrowRight => {
- midi_file.timer_mut().seek(time + one_sec)
+ midi_file.timer_mut().seek(time + skip_dur)
}
egui::Key::ArrowLeft => {
if midi_file.allows_seeking_backward() {
- midi_file.timer_mut().seek(if time <= one_sec {
- Duration::seconds(0)
+ midi_file.timer_mut().seek(if time <= skip_dur {
+ // FIXME: Start deplay
+ Duration::from_secs(0)
} else {
- time - one_sec
+ time - skip_dur
})
}
}
egui::Key::ArrowUp => {
- settings.midi.note_speed += 0.05;
+ if modifiers.ctrl {
+ settings.scene.note_speed +=
+ settings.gui.speed_control;
+ }
}
egui::Key::ArrowDown => {
- settings.midi.note_speed -= 0.05;
+ if modifiers.ctrl {
+ settings.scene.note_speed -=
+ settings.gui.speed_control;
+ }
}
egui::Key::Space => midi_file.timer_mut().toggle_pause(),
_ => {}
@@ -165,11 +279,11 @@ impl GuiWasabiWindow {
});
let result = self.render_scene.draw(
- state,
+ gui_state,
ui,
&key_view,
midi_file,
- settings.midi.note_speed,
+ settings.scene.note_speed,
);
stats.set_rendered_note_count(result.notes_rendered);
render_result_data = Some(result);
@@ -182,36 +296,6 @@ impl GuiWasabiWindow {
.frame(no_frame)
.show_separator_line(false)
.show(&ctx, |ui| {
- ui.input(|events| {
- for event in &events.events {
- if let egui::Event::Key {
- key,
- pressed,
- modifiers,
- ..
- } = event
- {
- if *pressed && modifiers.ctrl {
- match key {
- egui::Key::F => {
- settings.visual.show_top_pannel =
- !settings.visual.show_top_pannel
- }
- egui::Key::G => {
- settings.visual.show_statistics =
- !settings.visual.show_statistics
- }
- //egui::Key::O => self.open_midi_dialog(wasabi_state),
- _ => {}
- }
- }
- if *pressed && modifiers.alt && key == &egui::Key::Enter {
- wasabi_state.fullscreen = !wasabi_state.fullscreen
- }
- }
- }
- });
-
let colors = if let Some(data) = render_result_data {
data.key_colors
} else {
@@ -219,33 +303,42 @@ impl GuiWasabiWindow {
};
self.keyboard
- .draw(ui, &key_view, &colors, &settings.visual.bar_color);
+ .draw(ui, &key_view, &colors, &settings.scene.bar_color);
});
// Render the stats
- if settings.visual.show_statistics {
- let voice_count = self.synth.read().unwrap().get_voice_count();
+ if state.stats_visible {
+ let voice_count = self.synth.read().unwrap().voice_count();
stats.set_voice_count(voice_count);
- let pos = egui::Pos2::new(10.0, panel_height + 10.0);
- stats::draw_stats(self, &ctx, pos, stats);
+ let pad = if settings.scene.statistics.floating {
+ 12.0
+ } else {
+ 0.0
+ };
+ let pos = egui::Pos2::new(pad, panel_height + pad);
+ stats::draw_stats(self, &ctx, pos, stats, settings);
}
}
- #[allow(unused_variables)]
- pub fn open_midi_dialog(&mut self, settings: &mut WasabiSettings, state: &mut WasabiState) {
- // If windows, just use the native dialog
- let midi_path = rfd::FileDialog::new()
- .add_filter("mid", &["mid"])
- .pick_file();
+ pub fn open_midi_dialog(&mut self, state: &mut WasabiState) {
+ let sender = self.midi_picker.0.clone();
+ let last_location = state.last_location.clone();
- if let Some(midi_path) = midi_path {
- state.last_midi_file = Some(midi_path.clone());
- self.load_midi(settings, midi_path);
- }
+ thread::spawn(move || {
+ let midi_path = rfd::FileDialog::new()
+ .add_filter("mid", &["mid", "MID"])
+ .set_directory(last_location.parent().unwrap_or(Path::new("./")))
+ .pick_file();
+
+ if let Some(midi_path) = midi_path {
+ sender.send(midi_path).unwrap_or_default();
+ }
+ });
}
pub fn load_midi(&mut self, settings: &mut WasabiSettings, midi_path: PathBuf) {
+ // TODO: Load in thread
if let Some(midi_file) = self.midi_file.as_mut() {
midi_file.timer_mut().pause();
}
@@ -253,30 +346,30 @@ impl GuiWasabiWindow {
self.midi_file = None;
if let Some(midi_path) = midi_path.to_str() {
- match settings.midi.midi_loading {
- MidiLoading::Ram => {
+ match settings.midi.parsing {
+ MidiParsing::Ram => {
let mut midi_file = MIDIFileUnion::InRam(InRamMIDIFile::load_from_file(
midi_path,
self.synth.clone(),
- settings.midi.random_colors,
+ settings,
));
midi_file.timer_mut().play();
self.midi_file = Some(midi_file);
}
- MidiLoading::Live => {
+ MidiParsing::Live => {
let mut midi_file = MIDIFileUnion::Live(LiveLoadMIDIFile::load_from_file(
midi_path,
self.synth.clone(),
- settings.midi.random_colors,
+ settings,
));
midi_file.timer_mut().play();
self.midi_file = Some(midi_file);
}
- MidiLoading::Cake => {
+ MidiParsing::Cake => {
let mut midi_file = MIDIFileUnion::Cake(CakeMIDIFile::load_from_file(
midi_path,
self.synth.clone(),
- settings.midi.random_colors,
+ settings,
));
midi_file.timer_mut().play();
self.midi_file = Some(midi_file);
@@ -284,4 +377,23 @@ impl GuiWasabiWindow {
}
}
}
+
+ pub fn create_synth(settings: &WasabiSettings) -> Box {
+ let mut synth: Box = match settings.synth.synth {
+ Synth::XSynth => Box::new(XSynthPlayer::new(settings.synth.xsynth.config.clone())),
+ Synth::Kdmapi => Box::new(KdmapiPlayer::new()),
+ Synth::MidiDevice => {
+ if let Ok(midiout) = MidiDevicePlayer::new(settings.synth.midi_device.clone()) {
+ Box::new(midiout)
+ } else {
+ Box::new(EmptyPlayer::new())
+ }
+ }
+ Synth::None => Box::new(EmptyPlayer::new()),
+ };
+ synth.set_soundfonts(&settings.synth.soundfonts);
+ synth.configure(&settings.synth);
+
+ synth
+ }
}
diff --git a/src/gui/window/about.rs b/src/gui/window/about.rs
new file mode 100644
index 0000000..0f724cb
--- /dev/null
+++ b/src/gui/window/about.rs
@@ -0,0 +1,152 @@
+use crate::state::WasabiState;
+use std::env::consts::{ARCH, OS};
+
+use super::GuiWasabiWindow;
+
+impl GuiWasabiWindow {
+ pub fn show_about(&mut self, ctx: &egui::Context, state: &mut WasabiState) {
+ let frame =
+ egui::Frame::inner_margin(egui::Frame::window(ctx.style().as_ref()), super::WIN_MARGIN);
+ let size = [600.0, 450.0];
+
+ egui::Window::new("About Wasabi")
+ .resizable(true)
+ .collapsible(false)
+ .title_bar(true)
+ .scroll([false, true])
+ .enabled(true)
+ .frame(frame)
+ .fixed_size(size)
+ .open(&mut state.show_about)
+ .show(ctx, |ui| {
+ ui.add_space(4.0);
+ ui.horizontal(|ui| {
+ let image_size = 100.0;
+
+ let title_size = 46.0;
+ let titleid = egui::FontId {
+ size: title_size,
+ ..Default::default()
+ };
+
+ let title_text = format!("Wasabi");
+ let title_galley = ui.painter().layout_no_wrap(
+ title_text.to_owned(),
+ titleid,
+ egui::Color32::WHITE,
+ );
+
+ let logo_width =
+ image_size + ui.spacing().item_spacing.x + title_galley.size().x;
+ let space = ui.available_width() / 2.0 - (logo_width + 4.0) / 2.0;
+
+ ui.add_space(space);
+ ui.add(
+ egui::Image::new(egui::include_image!("../../../assets/logo.svg"))
+ .fit_to_exact_size(egui::Vec2::new(image_size, image_size)),
+ );
+ ui.add_space(4.0);
+
+ ui.vertical(|ui| {
+ let text_height = title_galley.size().y;
+ let space = (image_size - text_height) / 2.0;
+ ui.add_space(space);
+
+ ui.label(egui::RichText::new(title_text).size(title_size));
+ })
+ });
+
+ ui.add_space(10.0);
+ ui.separator();
+ ui.add_space(10.0);
+
+ let col_width = size[0] / 2.0;
+ ui.heading("Build Information");
+ egui::Grid::new("buildinfo_grid")
+ .num_columns(2)
+ .min_col_width(col_width)
+ .striped(true)
+ .show(ui, |ui| {
+ ui.label("Version:");
+ ui.label(env!("CARGO_PKG_VERSION"));
+ ui.end_row();
+
+ ui.label("Operating System:");
+ ui.label(OS.to_string());
+ ui.end_row();
+
+ ui.label("Architecture:");
+ ui.label(ARCH.to_string());
+ ui.end_row();
+ });
+
+ ui.add_space(20.0);
+
+ ui.heading("Libraries");
+ egui::Grid::new("libraries_grid")
+ .num_columns(2)
+ .min_col_width(col_width)
+ .striped(true)
+ .show(ui, |ui| {
+ ui.label("Egui Version:");
+ ui.label("0.29");
+ ui.end_row();
+
+ ui.label("XSynth Version:");
+ ui.label("0.3.1");
+ ui.end_row();
+
+ ui.label("MIDI Toolkit Version:");
+ ui.label("0.1.0");
+ ui.end_row();
+ });
+
+ let gh_text = "\u{1F310} GitHub";
+ let gh_galley = ui.painter().layout_no_wrap(
+ gh_text.to_owned(),
+ ctx.style()
+ .text_styles
+ .iter()
+ .find(|v| v.0 == &egui::TextStyle::Button)
+ .unwrap()
+ .1
+ .clone(),
+ egui::Color32::WHITE,
+ );
+
+ let upd_text = "\u{1F310} Check for updates";
+ let upd_galley = ui.painter().layout_no_wrap(
+ upd_text.to_owned(),
+ ctx.style()
+ .text_styles
+ .iter()
+ .find(|v| v.0 == &egui::TextStyle::Button)
+ .unwrap()
+ .1
+ .clone(),
+ egui::Color32::WHITE,
+ );
+
+ let mut h = ui.available_height();
+
+ let button_height = ui.spacing().button_padding.y * 2.0 + gh_galley.size().y;
+ h -= button_height;
+ ui.add_space(h);
+
+ ui.horizontal(|ui| {
+ let w = ui.available_width();
+
+ let button_width = gh_galley.size().x
+ + upd_galley.size().x
+ + ui.spacing().button_padding.x * 4.0;
+ let w = w / 2.0 - button_width / 2.0;
+ ui.add_space(w);
+
+ if ui.button(gh_text).clicked() {
+ open::that("https://github.com/BlackMIDIDevs/wasabi").unwrap();
+ }
+ if ui.button(upd_text).clicked() {}
+ });
+ });
+ }
+}
diff --git a/src/gui/window/fps.rs b/src/gui/window/fps.rs
index 380db49..8b19a5a 100644
--- a/src/gui/window/fps.rs
+++ b/src/gui/window/fps.rs
@@ -9,9 +9,10 @@ impl Fps {
Self(VecDeque::new())
}
- pub fn update(&mut self) {
+ pub fn update(&mut self, _limit: Option) {
self.0.push_back(Instant::now());
while let Some(front) = self.0.front() {
+ // TODO: FPS limit
if front.elapsed().as_secs_f64() > FPS_WINDOW {
self.0.pop_front();
} else {
diff --git a/src/gui/window/playback_panel.rs b/src/gui/window/playback_panel.rs
new file mode 100644
index 0000000..53741ce
--- /dev/null
+++ b/src/gui/window/playback_panel.rs
@@ -0,0 +1,220 @@
+use std::time::Duration;
+
+use egui::{popup_below_widget, PopupCloseBehavior};
+
+use super::{GuiWasabiWindow, SPACE, WIN_MARGIN};
+use crate::{midi::MIDIFileBase, state::WasabiState, utils::convert_seconds_to_time_string};
+
+impl GuiWasabiWindow {
+ pub fn show_playback_panel(&mut self, ctx: &egui::Context, state: &mut WasabiState) {
+ let mut mouse_over_panel = false;
+ if let Some(mouse) = ctx.pointer_latest_pos() {
+ if mouse.y < 60.0 {
+ mouse_over_panel = true;
+ }
+ }
+ let button_size = egui::Vec2::new(26.0, 26.0);
+ let icon_color = ctx.style().visuals.strong_text_color();
+ let button_rounding = 8.0;
+
+ let is_popup_open = ctx.memory(|mem| mem.is_popup_open(state.panel_popup_id));
+
+ let frame = egui::Frame::side_top_panel(&ctx.style()).inner_margin(WIN_MARGIN);
+ egui::TopBottomPanel::top("panel")
+ .frame(frame)
+ .show_separator_line(false)
+ .show_animated(
+ ctx,
+ state.panel_pinned || mouse_over_panel || is_popup_open,
+ |ui| {
+ ui.horizontal(|ui| {
+ let folder_img =
+ egui::Image::new(egui::include_image!("../../../assets/folder.svg"))
+ .fit_to_exact_size(button_size)
+ .tint(icon_color)
+ .rounding(button_rounding);
+
+ if ui
+ .add(egui::ImageButton::new(folder_img))
+ .on_hover_text("Open MIDI")
+ .clicked()
+ {
+ self.open_midi_dialog(state);
+ }
+
+ let stop_img =
+ egui::Image::new(egui::include_image!("../../../assets/stop.svg"))
+ .fit_to_exact_size(button_size)
+ .tint(icon_color)
+ .rounding(button_rounding);
+
+ if ui
+ .add(egui::ImageButton::new(stop_img))
+ .on_hover_text("Unload")
+ .clicked()
+ {
+ if let Some(midi) = self.midi_file.take().as_mut() {
+ midi.timer_mut().pause();
+ self.synth.write().unwrap().reset();
+ }
+ }
+
+ let playing = if let Some(midi) = self.midi_file.as_ref() {
+ !midi.timer().is_paused()
+ } else {
+ false
+ };
+
+ // FIXME
+ if playing {
+ let pause_img =
+ egui::Image::new(egui::include_image!("../../../assets/pause.svg"))
+ .fit_to_exact_size(button_size)
+ .tint(icon_color)
+ .rounding(button_rounding);
+
+ if ui
+ .add(egui::ImageButton::new(pause_img))
+ .on_hover_text("Pause")
+ .clicked()
+ {
+ if let Some(midi_file) = self.midi_file.as_mut() {
+ midi_file.timer_mut().pause();
+ }
+ }
+ } else {
+ let play_img =
+ egui::Image::new(egui::include_image!("../../../assets/play.svg"))
+ .fit_to_exact_size(button_size)
+ .tint(icon_color)
+ .rounding(button_rounding);
+
+ if ui
+ .add(egui::ImageButton::new(play_img))
+ .on_hover_text("Play")
+ .clicked()
+ {
+ if let Some(midi_file) = self.midi_file.as_mut() {
+ midi_file.timer_mut().play();
+ }
+ }
+ }
+
+ ui.add_space(SPACE);
+ ui.separator();
+ ui.add_space(SPACE);
+
+ let mut time_passed = 0.0;
+ let mut time_total = 0.0;
+
+ if let Some(midi) = self.midi_file.as_ref() {
+ time_total = midi.midi_length().unwrap_or(0.0);
+ time_passed = midi.timer().get_time().as_secs_f64();
+ }
+
+ let mut timeid = ui
+ .style()
+ .text_styles
+ .get(&egui::TextStyle::Monospace)
+ .unwrap()
+ .clone();
+ timeid.size = 16.0;
+ let time_text = convert_seconds_to_time_string(time_passed);
+ let time_galley = ui.painter().layout_no_wrap(
+ time_text.clone(),
+ timeid.clone(),
+ egui::Color32::WHITE,
+ );
+
+ let length_text = convert_seconds_to_time_string(time_total);
+ let length_galley = ui.painter().layout_no_wrap(
+ length_text.clone(),
+ timeid.clone(),
+ egui::Color32::WHITE,
+ );
+
+ ui.spacing_mut().slider_width = ui.available_width()
+ - time_galley.size().x
+ - length_galley.size().x
+ - ui.spacing().item_spacing.x * 8.0
+ - button_size.x * 2.0
+ - ui.spacing().button_padding.x * 2.0
+ - SPACE;
+
+ ui.label(egui::RichText::new(time_text).font(timeid.clone()));
+ let mut empty_slider =
+ || ui.add(egui::Slider::new(&mut 0.0, 0.0..=1.0).show_value(false));
+ if let Some(midi_file) = self.midi_file.as_mut() {
+ if let Some(length) = midi_file.midi_length() {
+ let mut time = midi_file.timer().get_time().as_secs_f64();
+ let time_prev = time;
+
+ ui.add(
+ egui::Slider::new(&mut time, 0.0..=length).show_value(false),
+ );
+ if (time_prev != time)
+ && (midi_file.allows_seeking_backward() || time_prev < time)
+ {
+ midi_file.timer_mut().seek(Duration::from_secs_f64(time));
+ }
+ } else {
+ empty_slider();
+ }
+ } else {
+ empty_slider();
+ }
+ ui.label(egui::RichText::new(length_text).font(timeid.clone()));
+
+ ui.add_space(SPACE);
+ ui.separator();
+ ui.add_space(SPACE);
+
+ let options_img =
+ egui::Image::new(egui::include_image!("../../../assets/options.svg"))
+ .fit_to_exact_size(button_size)
+ .tint(icon_color)
+ .rounding(button_rounding);
+
+ let options = ui.add(egui::ImageButton::new(options_img));
+
+ if options.clicked() {
+ ui.memory_mut(|mem| mem.toggle_popup(state.panel_popup_id));
+ }
+ popup_below_widget(
+ ui,
+ state.panel_popup_id,
+ &options,
+ PopupCloseBehavior::CloseOnClick,
+ |ui| {
+ ui.set_min_width(130.0);
+
+ if ui.button("Settings").clicked() {
+ state.show_settings = true;
+ }
+ if ui.button("Shortcuts").clicked() {
+ state.show_shortcuts = true;
+ }
+ if ui.button("About").clicked() {
+ state.show_about = true;
+ }
+ },
+ );
+
+ let arrow_img =
+ egui::Image::new(egui::include_image!("../../../assets/pin.svg"))
+ .fit_to_exact_size(button_size)
+ .tint(icon_color)
+ .rounding(button_rounding);
+
+ if ui
+ .add(egui::ImageButton::new(arrow_img).selected(state.panel_pinned))
+ .on_hover_text("Pin Panel")
+ .clicked()
+ {
+ state.panel_pinned = !state.panel_pinned;
+ }
+ });
+ },
+ );
+ }
+}
diff --git a/src/gui/window/scene.rs b/src/gui/window/scene.rs
index c78fb28..9a35c4a 100644
--- a/src/gui/window/scene.rs
+++ b/src/gui/window/scene.rs
@@ -1,7 +1,7 @@
mod cake_system;
mod note_list_system;
-use egui::Ui;
+use egui::{Image, Ui};
use crate::{
midi::{MIDIColor, MIDIFileUnion},
@@ -97,7 +97,8 @@ impl GuiRenderScene {
.draw(key_view, frame, file, view_range),
};
- ui.image(scene_image.id, [size[0] as f32, size[1] as f32]);
+ let img = Image::new((scene_image.id, [size[0] as f32, size[1] as f32].into()));
+ ui.add(img);
result
}
diff --git a/src/gui/window/scene/cake_system/mod.rs b/src/gui/window/scene/cake_system/mod.rs
index d6779ab..6c54300 100644
--- a/src/gui/window/scene/cake_system/mod.rs
+++ b/src/gui/window/scene/cake_system/mod.rs
@@ -5,23 +5,29 @@ use vulkano::{
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
command_buffer::{
allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
- RenderPassBeginInfo, SubpassContents,
+ RenderPassBeginInfo, SubpassBeginInfo, SubpassContents,
},
descriptor_set::{
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
},
device::{Device, Queue},
format::Format,
- image::{view::ImageView, AttachmentImage, ImageAccess, ImageViewAbstract},
- memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
+ image::{view::ImageView, Image, ImageCreateInfo, ImageUsage},
+ memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
pipeline::{
graphics::{
+ color_blend::{ColorBlendAttachmentState, ColorBlendState},
depth_stencil::DepthStencilState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
- vertex_input::Vertex,
+ multisample::MultisampleState,
+ rasterization::RasterizationState,
+ vertex_input::{Vertex, VertexDefinition},
viewport::{Viewport, ViewportState},
+ GraphicsPipelineCreateInfo,
},
- GraphicsPipeline, Pipeline, PipelineBindPoint,
+ layout::PipelineDescriptorSetLayoutCreateInfo,
+ GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
+ PipelineShaderStageCreateInfo,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sync::{self, GpuFuture},
@@ -73,18 +79,18 @@ impl BufferSet {
fn add_buffer(
&mut self,
- allocator: &StandardMemoryAllocator,
+ allocator: Arc,
block: &CakeBlock,
_key: &KeyPosition,
) {
let data = Buffer::from_iter(
- allocator,
+ allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::STORAGE_BUFFER,
..Default::default()
},
AllocationCreateInfo {
- usage: MemoryUsage::Upload,
+ memory_type_filter: MemoryTypeFilter::PREFER_HOST,
..Default::default()
},
block.tree.iter().copied(),
@@ -110,8 +116,8 @@ pub struct CakeRenderer {
buffers: BufferSet,
pipeline_clear: Arc,
render_pass_clear: Arc,
- allocator: StandardMemoryAllocator,
- depth_buffer: Arc>,
+ allocator: Arc,
+ depth_buffer: Arc,
cb_allocator: StandardCommandBufferAllocator,
sd_allocator: StandardDescriptorSetAllocator,
buffers_init: Subbuffer<[CakeNoteColumn]>,
@@ -120,23 +126,25 @@ pub struct CakeRenderer {
impl CakeRenderer {
pub fn new(renderer: &GuiRenderer) -> CakeRenderer {
- let allocator = StandardMemoryAllocator::new_default(renderer.device.clone());
+ let allocator = Arc::new(StandardMemoryAllocator::new_default(
+ renderer.device.clone(),
+ ));
let gfx_queue = renderer.queue.clone();
let render_pass_clear = vulkano::ordered_passes_renderpass!(gfx_queue.device().clone(),
attachments: {
final_color: {
- load: Clear,
- store: Store,
format: renderer.format,
samples: 1,
+ load_op: Clear,
+ store_op: Store,
},
depth: {
- load: Clear,
- store: Store,
format: Format::D16_UNORM,
samples: 1,
+ load_op: Clear,
+ store_op: Store,
}
},
passes: [
@@ -150,38 +158,93 @@ impl CakeRenderer {
.unwrap();
let depth_buffer = ImageView::new_default(
- AttachmentImage::transient_input_attachment(&allocator, [1, 1], Format::D16_UNORM)
- .unwrap(),
+ Image::new(
+ allocator.clone(),
+ ImageCreateInfo {
+ extent: [1, 1, 1],
+ format: Format::D16_UNORM,
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
+ },
+ Default::default(),
+ )
+ .unwrap(),
)
.unwrap();
- let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
- let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
- let gs = gs::load(gfx_queue.device().clone()).expect("failed to create shader module");
-
- let pipeline_base = GraphicsPipeline::start()
- .input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::PointList))
- .vertex_input_state(CakeNoteColumn::per_vertex())
- .vertex_shader(vs.entry_point("main").unwrap(), ())
- .fragment_shader(fs.entry_point("main").unwrap(), ())
- .geometry_shader(gs.entry_point("main").unwrap(), ())
- .viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
- .depth_stencil_state(DepthStencilState::simple_depth_test());
-
- let pipeline_clear = pipeline_base
- .clone()
- .render_pass(Subpass::from(render_pass_clear.clone(), 0).unwrap())
- .build(gfx_queue.device().clone())
+ let vs = vs::load(gfx_queue.device().clone())
+ .expect("failed to create shader module")
+ .entry_point("main")
+ .unwrap();
+ let fs = fs::load(gfx_queue.device().clone())
+ .expect("failed to create shader module")
+ .entry_point("main")
+ .unwrap();
+ let gs = gs::load(gfx_queue.device().clone())
+ .expect("failed to create shader module")
+ .entry_point("main")
.unwrap();
+ let vertex_input_state = CakeNoteColumn::per_vertex()
+ .definition(&vs.info().input_interface)
+ .unwrap();
+ let stages = [
+ PipelineShaderStageCreateInfo::new(vs),
+ PipelineShaderStageCreateInfo::new(fs),
+ PipelineShaderStageCreateInfo::new(gs),
+ ];
+ let layout = PipelineLayout::new(
+ renderer.device.clone(),
+ PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
+ .into_pipeline_layout_create_info(renderer.device.clone())
+ .unwrap(),
+ )
+ .unwrap();
+ let subpass = Subpass::from(render_pass_clear.clone(), 0).unwrap();
+
+ let pipeline_clear = GraphicsPipeline::new(
+ renderer.device.clone(),
+ None,
+ GraphicsPipelineCreateInfo {
+ stages: stages.into_iter().collect(),
+ vertex_input_state: Some(vertex_input_state),
+ input_assembly_state: Some(InputAssemblyState {
+ topology: PrimitiveTopology::PointList,
+ ..Default::default()
+ }),
+ viewport_state: Some(ViewportState {
+ viewports: [Viewport {
+ offset: [0.0, 0.0],
+ extent: [1280.0, 720.0],
+ depth_range: 0.0..=1.0,
+ }]
+ .into_iter()
+ .collect(),
+ ..Default::default()
+ }),
+ rasterization_state: Some(RasterizationState::default()),
+ multisample_state: Some(MultisampleState::default()),
+ color_blend_state: Some(ColorBlendState::with_attachment_states(
+ subpass.num_color_attachments(),
+ ColorBlendAttachmentState::default(),
+ )),
+ depth_stencil_state: Some(DepthStencilState::default()),
+ subpass: Some(subpass.into()),
+ ..GraphicsPipelineCreateInfo::layout(layout)
+ },
+ )
+ .unwrap();
+
let buffers = Buffer::new_slice(
- &allocator,
+ allocator.clone(),
BufferCreateInfo {
- usage: BufferUsage::VERTEX_BUFFER,
+ usage: BufferUsage::STORAGE_BUFFER
+ | BufferUsage::TRANSFER_DST
+ | BufferUsage::VERTEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
- usage: MemoryUsage::Upload,
+ memory_type_filter: MemoryTypeFilter::PREFER_DEVICE,
..Default::default()
},
BUFFER_ARRAY_LEN,
@@ -199,7 +262,10 @@ impl CakeRenderer {
renderer.device.clone(),
Default::default(),
),
- sd_allocator: StandardDescriptorSetAllocator::new(renderer.device.clone()),
+ sd_allocator: StandardDescriptorSetAllocator::new(
+ renderer.device.clone(),
+ Default::default(),
+ ),
buffers_init: buffers,
current_file_signature: None,
}
@@ -208,19 +274,19 @@ impl CakeRenderer {
pub fn draw(
&mut self,
key_view: &KeyboardView,
- final_image: Arc,
+ final_image: Arc,
midi_file: &mut CakeMIDIFile,
view_range: f64,
) -> RenderResultData {
- let img_dims = final_image.image().dimensions().width_height();
- if self.depth_buffer.image().dimensions().width_height() != img_dims {
+ let img_dims = final_image.image().extent();
+ if self.depth_buffer.image().extent() != img_dims {
+ let mut create_info: ImageCreateInfo = Default::default();
+ create_info.extent = [img_dims[0], img_dims[1], 1];
+ create_info.format = Format::D16_UNORM;
+ create_info.usage = ImageUsage::SAMPLED;
+
self.depth_buffer = ImageView::new_default(
- AttachmentImage::transient_input_attachment(
- &self.allocator,
- img_dims,
- Format::D16_UNORM,
- )
- .unwrap(),
+ Image::new(self.allocator.clone(), create_info, Default::default()).unwrap(),
)
.unwrap();
}
@@ -231,7 +297,7 @@ impl CakeRenderer {
self.buffers.clear();
for (i, block) in midi_file.key_blocks().iter().enumerate() {
let key = key_view.key(i);
- self.buffers.add_buffer(&self.allocator, block, &key);
+ self.buffers.add_buffer(self.allocator.clone(), block, &key);
}
}
@@ -247,7 +313,7 @@ impl CakeRenderer {
};
let border_width = crate::utils::calculate_border_width(
- final_image.image().dimensions().width() as f32,
+ final_image.image().extent()[0] as f32,
key_view.visible_range.len() as f32,
) as i32;
@@ -318,41 +384,53 @@ impl CakeRenderer {
0,
self.buffers.buffers.iter().map(|b| b.data.clone()),
)],
+ [],
)
.unwrap();
+ let mut subpassbegininfo = SubpassBeginInfo::default();
+ subpassbegininfo.contents = SubpassContents::Inline;
+
command_buffer_builder
.begin_render_pass(
RenderPassBeginInfo {
clear_values: clears,
..RenderPassBeginInfo::framebuffer(framebuffer)
},
- SubpassContents::Inline,
+ subpassbegininfo,
)
.unwrap();
command_buffer_builder
.bind_pipeline_graphics(pipeline.clone())
+ .unwrap()
.set_viewport(
0,
- [Viewport {
- origin: [0.0, 0.0],
- dimensions: [img_dims[0] as f32, img_dims[1] as f32],
- depth_range: 0.0..1.0,
- }],
+ vec![Viewport {
+ offset: [0.0, 0.0],
+ extent: [img_dims[0] as f32, img_dims[1] as f32],
+ depth_range: 0.0..=1.0,
+ }]
+ .into(),
)
+ .unwrap()
.push_constants(pipeline_layout.clone(), 0, push_constants)
+ .unwrap()
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline_layout.clone(),
0,
data_descriptor,
)
+ .unwrap()
.bind_vertex_buffers(0, self.buffers_init.clone())
+ .unwrap()
.draw(written_instances as u32, 1, 0, 0)
.unwrap();
- command_buffer_builder.end_render_pass().unwrap();
+ command_buffer_builder
+ .end_render_pass(Default::default())
+ .unwrap();
let command_buffer = command_buffer_builder.build().unwrap();
let now = sync::now(self.gfx_queue.device().clone()).boxed();
diff --git a/src/gui/window/scene/note_list_system/mod.rs b/src/gui/window/scene/note_list_system/mod.rs
index 29a270e..f5cceaf 100644
--- a/src/gui/window/scene/note_list_system/mod.rs
+++ b/src/gui/window/scene/note_list_system/mod.rs
@@ -3,7 +3,7 @@ mod notes_render_pass;
use std::{cell::UnsafeCell, sync::Arc};
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
-use vulkano::image::ImageViewAbstract;
+use vulkano::image::view::ImageView;
use crate::{
gui::{window::keyboard_layout::KeyboardView, GuiRenderer},
@@ -47,7 +47,7 @@ impl NoteRenderer {
pub fn draw(
&mut self,
key_view: &KeyboardView,
- final_image: Arc,
+ final_image: Arc,
midi_file: &mut impl MIDIFile,
view_range: f64,
) -> RenderResultData {
@@ -69,7 +69,7 @@ impl NoteRenderer {
let mut columns_view_info = Vec::new();
let border_width = utils::calculate_border_width(
- final_image.dimensions().width() as f32,
+ final_image.image().extent()[0] as f32,
key_view.visible_range.len() as f32,
);
diff --git a/src/gui/window/scene/note_list_system/notes_render_pass.rs b/src/gui/window/scene/note_list_system/notes_render_pass.rs
index 9d8ff72..38f7778 100644
--- a/src/gui/window/scene/note_list_system/notes_render_pass.rs
+++ b/src/gui/window/scene/note_list_system/notes_render_pass.rs
@@ -5,23 +5,30 @@ use vulkano::{
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
command_buffer::{
allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
- RenderPassBeginInfo, SubpassContents,
+ RenderPassBeginInfo, SubpassBeginInfo, SubpassContents,
},
descriptor_set::{
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
},
device::{Device, Queue},
format::Format,
- image::{view::ImageView, AttachmentImage, ImageAccess, ImageViewAbstract},
- memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
+ image::{view::ImageView, Image, ImageCreateInfo, ImageUsage},
+ memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
pipeline::{
graphics::{
+ color_blend::{ColorBlendAttachmentState, ColorBlendState},
depth_stencil::DepthStencilState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
- vertex_input::Vertex,
+ multisample::MultisampleState,
+ rasterization::RasterizationState,
+ subpass::PipelineSubpassType,
+ vertex_input::{Vertex, VertexDefinition},
viewport::{Viewport, ViewportState},
+ GraphicsPipelineCreateInfo,
},
- GraphicsPipeline, Pipeline, PipelineBindPoint,
+ layout::PipelineDescriptorSetLayoutCreateInfo,
+ GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout,
+ PipelineShaderStageCreateInfo,
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sync::{self, future::FenceSignalFuture, GpuFuture},
@@ -58,16 +65,16 @@ struct BufferSet {
}
fn get_buffer(device: &Arc) -> (Subbuffer<[NoteVertex]>, Subbuffer<[NoteVertex]>) {
- let allocator = StandardMemoryAllocator::new_default(device.clone());
+ let allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
Buffer::new_slice(
- &allocator,
+ allocator.clone(),
BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
- usage: MemoryUsage::Upload,
+ memory_type_filter: MemoryTypeFilter::PREFER_HOST,
..Default::default()
},
NOTE_BUFFER_SIZE * 2,
@@ -113,31 +120,33 @@ pub struct NoteRenderPass {
render_pass_clear: Arc,
render_pass_draw_over: Arc,
key_locations: Subbuffer<[[KeyPosition; 256]]>,
- depth_buffer: Arc>,
- allocator: StandardMemoryAllocator,
+ depth_buffer: Arc,
+ allocator: Arc,
cb_allocator: StandardCommandBufferAllocator,
sd_allocator: StandardDescriptorSetAllocator,
}
impl NoteRenderPass {
pub fn new(renderer: &GuiRenderer) -> NoteRenderPass {
- let allocator = StandardMemoryAllocator::new_default(renderer.device.clone());
+ let allocator = Arc::new(StandardMemoryAllocator::new_default(
+ renderer.device.clone(),
+ ));
let gfx_queue = renderer.queue.clone();
let render_pass_clear = vulkano::ordered_passes_renderpass!(gfx_queue.device().clone(),
attachments: {
final_color: {
- load: Clear,
- store: Store,
format: renderer.format,
samples: 1,
+ load_op: Clear,
+ store_op: Store,
},
depth: {
- load: Clear,
- store: Store,
format: Format::D16_UNORM,
samples: 1,
+ load_op: Clear,
+ store_op: Store,
}
},
passes: [
@@ -153,16 +162,16 @@ impl NoteRenderPass {
let render_pass_draw_over = vulkano::ordered_passes_renderpass!(gfx_queue.device().clone(),
attachments: {
final_color: {
- load: DontCare,
- store: Store,
format: renderer.format,
samples: 1,
+ load_op: DontCare,
+ store_op: Store,
},
depth: {
- load: DontCare,
- store: Store,
format: Format::D16_UNORM,
samples: 1,
+ load_op: DontCare,
+ store_op: Store,
}
},
passes: [
@@ -176,48 +185,102 @@ impl NoteRenderPass {
.unwrap();
let depth_buffer = ImageView::new_default(
- AttachmentImage::transient_input_attachment(&allocator, [1, 1], Format::D16_UNORM)
- .unwrap(),
+ Image::new(
+ allocator.clone(),
+ ImageCreateInfo {
+ extent: [1, 1, 1],
+ format: Format::D16_UNORM,
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
+ },
+ Default::default(),
+ )
+ .unwrap(),
)
.unwrap();
let key_locations = Buffer::from_iter(
- &allocator,
+ allocator.clone(),
BufferCreateInfo {
- usage: BufferUsage::UNIFORM_BUFFER,
+ usage: BufferUsage::STORAGE_BUFFER
+ | BufferUsage::TRANSFER_DST
+ | BufferUsage::VERTEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
- usage: MemoryUsage::Upload,
+ memory_type_filter: MemoryTypeFilter::PREFER_HOST,
..Default::default()
},
[[Default::default(); 256]],
)
.unwrap();
- let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
- let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
- let gs = gs::load(gfx_queue.device().clone()).expect("failed to create shader module");
-
- let pipeline_base = GraphicsPipeline::start()
- .input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::PointList))
- .vertex_input_state(NoteVertex::per_vertex())
- .vertex_shader(vs.entry_point("main").unwrap(), ())
- .geometry_shader(gs.entry_point("main").unwrap(), ())
- .fragment_shader(fs.entry_point("main").unwrap(), ())
- .viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
- .depth_stencil_state(DepthStencilState::simple_depth_test());
-
- let pipeline_clear = pipeline_base
- .clone()
- .render_pass(Subpass::from(render_pass_clear.clone(), 0).unwrap())
- .build(gfx_queue.device().clone())
+ let vs = vs::load(gfx_queue.device().clone())
+ .expect("failed to create shader module")
+ .entry_point("main")
+ .unwrap();
+ let fs = fs::load(gfx_queue.device().clone())
+ .expect("failed to create shader module")
+ .entry_point("main")
+ .unwrap();
+ let gs = gs::load(gfx_queue.device().clone())
+ .expect("failed to create shader module")
+ .entry_point("main")
.unwrap();
- let pipeline_draw_over = pipeline_base
- .render_pass(Subpass::from(render_pass_draw_over.clone(), 0).unwrap())
- .build(gfx_queue.device().clone())
+ let vertex_input_state = NoteVertex::per_vertex()
+ .definition(&vs.info().input_interface)
.unwrap();
+ let stages = [
+ PipelineShaderStageCreateInfo::new(vs),
+ PipelineShaderStageCreateInfo::new(fs),
+ PipelineShaderStageCreateInfo::new(gs),
+ ];
+ let layout = PipelineLayout::new(
+ renderer.device.clone(),
+ PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages)
+ .into_pipeline_layout_create_info(renderer.device.clone())
+ .unwrap(),
+ )
+ .unwrap();
+ let subpass = Subpass::from(render_pass_clear.clone(), 0).unwrap();
+
+ let mut create_info = GraphicsPipelineCreateInfo {
+ stages: stages.into_iter().collect(),
+ vertex_input_state: Some(vertex_input_state),
+ input_assembly_state: Some(InputAssemblyState {
+ topology: PrimitiveTopology::PointList,
+ ..Default::default()
+ }),
+ viewport_state: Some(ViewportState {
+ viewports: [Viewport {
+ offset: [0.0, 0.0],
+ extent: [1280.0, 720.0],
+ depth_range: 0.0..=1.0,
+ }]
+ .into_iter()
+ .collect(),
+ ..Default::default()
+ }),
+ rasterization_state: Some(RasterizationState::default()),
+ multisample_state: Some(MultisampleState::default()),
+ color_blend_state: Some(ColorBlendState::with_attachment_states(
+ subpass.num_color_attachments(),
+ ColorBlendAttachmentState::default(),
+ )),
+ depth_stencil_state: Some(DepthStencilState::default()),
+ subpass: Some(subpass.into()),
+ ..GraphicsPipelineCreateInfo::layout(layout)
+ };
+
+ let pipeline_clear =
+ GraphicsPipeline::new(renderer.device.clone(), None, create_info.clone()).unwrap();
+
+ create_info.subpass = Some(PipelineSubpassType::BeginRenderPass(
+ Subpass::from(render_pass_draw_over.clone(), 0).unwrap(),
+ ));
+ let pipeline_draw_over =
+ GraphicsPipeline::new(renderer.device.clone(), None, create_info).unwrap();
NoteRenderPass {
gfx_queue,
@@ -233,24 +296,32 @@ impl NoteRenderPass {
renderer.device.clone(),
Default::default(),
),
- sd_allocator: StandardDescriptorSetAllocator::new(renderer.device.clone()),
+ sd_allocator: StandardDescriptorSetAllocator::new(
+ renderer.device.clone(),
+ Default::default(),
+ ),
}
}
pub fn draw(
&mut self,
- final_image: Arc,
+ final_image: Arc,
key_view: &KeyboardView,
view_range: f32,
mut fill_buffer: impl FnMut(&Subbuffer<[NoteVertex]>) -> NotePassStatus,
) {
- let img_dims = final_image.image().dimensions().width_height();
- if self.depth_buffer.image().dimensions().width_height() != img_dims {
+ let img_dims = final_image.image().extent();
+ if self.depth_buffer.image().extent() != img_dims {
self.depth_buffer = ImageView::new_default(
- AttachmentImage::transient_input_attachment(
- &self.allocator,
- img_dims,
- Format::D16_UNORM,
+ Image::new(
+ self.allocator.clone(),
+ ImageCreateInfo {
+ extent: [img_dims[0], img_dims[1], 1],
+ format: Format::D16_UNORM,
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
+ },
+ Default::default(),
)
.unwrap(),
)
@@ -321,20 +392,25 @@ impl NoteRenderPass {
let pipeline_layout = pipeline.layout();
let desc_layout = pipeline_layout.set_layouts().first().unwrap();
+ let write_descriptor_set = WriteDescriptorSet::buffer(0, self.key_locations.clone());
let set = PersistentDescriptorSet::new(
&self.sd_allocator,
desc_layout.clone(),
- [WriteDescriptorSet::buffer(0, self.key_locations.clone())],
+ [write_descriptor_set],
+ [],
)
.unwrap();
+ let mut subpassbegininfo = SubpassBeginInfo::default();
+ subpassbegininfo.contents = SubpassContents::Inline;
+
command_buffer_builder
.begin_render_pass(
RenderPassBeginInfo {
clear_values: clears,
..RenderPassBeginInfo::framebuffer(framebuffer)
},
- SubpassContents::Inline,
+ subpassbegininfo,
)
.unwrap();
@@ -346,26 +422,34 @@ impl NoteRenderPass {
command_buffer_builder
.bind_pipeline_graphics(pipeline.clone())
+ .unwrap()
.set_viewport(
0,
- [Viewport {
- origin: [0.0, 0.0],
- dimensions: [img_dims[0] as f32, img_dims[1] as f32],
- depth_range: 0.0..1.0,
- }],
+ vec![Viewport {
+ offset: [0.0, 0.0],
+ extent: [img_dims[0] as f32, img_dims[1] as f32],
+ depth_range: 0.0..=1.0,
+ }]
+ .into(),
)
+ .unwrap()
.push_constants(pipeline_layout.clone().clone(), 0, push_constants)
+ .unwrap()
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline_layout.clone(),
0,
set.clone(),
)
+ .unwrap()
.bind_vertex_buffers(0, buffer.clone())
+ .unwrap()
.draw(items_to_render, 1, 0, 0)
.unwrap();
- command_buffer_builder.end_render_pass().unwrap();
+ command_buffer_builder
+ .end_render_pass(Default::default())
+ .unwrap();
let command_buffer = command_buffer_builder.build().unwrap();
if let Some(prev_future) = prev_future.take() {
diff --git a/src/gui/window/settings.rs b/src/gui/window/settings.rs
new file mode 100644
index 0000000..a651360
--- /dev/null
+++ b/src/gui/window/settings.rs
@@ -0,0 +1,181 @@
+use std::{
+ path::PathBuf,
+ sync::{Arc, RwLock},
+};
+
+use soundfonts::EguiSFList;
+
+use crate::{
+ audio_playback::WasabiAudioPlayer,
+ settings::WasabiSettings,
+ state::{SettingsTab, WasabiState},
+};
+
+mod midi;
+mod soundfonts;
+mod synth;
+mod visual;
+
+const CATEG_SPACE: f32 = 12.0;
+const SPACING: [f32; 2] = [40.0, 12.0];
+
+#[derive(Clone)]
+struct FilePalette {
+ pub path: PathBuf,
+ pub selected: bool,
+}
+
+#[derive(Clone)]
+struct MidiDevice {
+ pub name: String,
+ pub selected: bool,
+}
+
+pub struct SettingsWindow {
+ palettes: Vec,
+ midi_devices: Vec,
+ sf_list: EguiSFList,
+}
+
+impl SettingsWindow {
+ pub fn new(settings: &WasabiSettings) -> Self {
+ let mut sf_list = EguiSFList::new();
+ for sf in settings.synth.soundfonts.iter() {
+ sf_list.add_item(sf.clone()).unwrap_or_default();
+ }
+
+ Self {
+ palettes: Vec::new(),
+ midi_devices: Vec::new(),
+ sf_list,
+ }
+ }
+
+ pub fn show(
+ &mut self,
+ ctx: &egui::Context,
+ settings: &mut WasabiSettings,
+ state: &mut WasabiState,
+ synth: Arc>,
+ ) {
+ let frame =
+ egui::Frame::inner_margin(egui::Frame::window(ctx.style().as_ref()), super::WIN_MARGIN);
+
+ egui::Window::new("Settings")
+ .resizable(true)
+ .collapsible(false)
+ .title_bar(true)
+ .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
+ .movable(false)
+ .enabled(true)
+ .frame(frame)
+ .default_size([600.0, 400.0])
+ .min_size([500.0, 200.0])
+ .open(&mut state.show_settings)
+ .show(ctx, |ui| {
+ egui::TopBottomPanel::top("settings_tab_selector")
+ .resizable(false)
+ .show_inside(ui, |ui| {
+ ui.style_mut()
+ .text_styles
+ .get_mut(&egui::TextStyle::Button)
+ .unwrap()
+ .size = 20.0;
+
+ ui.horizontal(|ui| {
+ ui.selectable_value(
+ &mut state.settings_tab,
+ SettingsTab::Visual,
+ "\u{1f4bb} Visual",
+ );
+ ui.selectable_value(
+ &mut state.settings_tab,
+ SettingsTab::Midi,
+ "\u{1f3b5} MIDI",
+ );
+ ui.selectable_value(
+ &mut state.settings_tab,
+ SettingsTab::Synth,
+ "\u{1f3b9} Synth",
+ );
+ ui.selectable_value(
+ &mut state.settings_tab,
+ SettingsTab::SoundFonts,
+ "\u{1f50a} SoundFonts",
+ );
+ });
+ ui.add_space(4.0);
+ });
+
+ egui::TopBottomPanel::bottom("settings_save_panel")
+ .resizable(false)
+ .show_inside(ui, |ui| {
+ ui.add_space(4.0);
+ ui.centered_and_justified(|ui| {
+ if ui.button("Save").clicked() {
+ settings.save_to_file();
+ }
+ });
+ });
+
+ let width = ui.available_width() - 40.0;
+ egui::CentralPanel::default().show_inside(ui, |ui| {
+ egui::ScrollArea::vertical().animated(true).show(ui, |ui| {
+ match state.settings_tab {
+ SettingsTab::Visual => self.show_visual_settings(ui, settings, width),
+ SettingsTab::Midi => self.show_midi_settings(ui, settings, width),
+ SettingsTab::Synth => {
+ self.show_synth_settings(ui, settings, width, synth)
+ }
+ SettingsTab::SoundFonts => {
+ self.show_soundfont_settings(ui, settings, width, synth)
+ }
+ }
+ })
+ });
+ });
+ }
+
+ pub fn load_palettes(&mut self) {
+ self.palettes.clear();
+
+ let files = std::fs::read_dir(WasabiSettings::get_palettes_dir()).unwrap();
+
+ for file in files.filter_map(|i| i.ok()) {
+ if let Ok(ftype) = file.file_type() {
+ if ftype.is_file() {
+ self.palettes.push(FilePalette {
+ path: file.path(),
+ selected: false,
+ });
+ }
+ }
+ }
+ }
+
+ pub fn load_midi_devices(&mut self, settings: &mut WasabiSettings) {
+ self.midi_devices.clear();
+ if let Ok(con) = midir::MidiOutput::new("wasabi") {
+ let ports = con.ports();
+ for port in ports.iter() {
+ if let Ok(name) = con.port_name(&port) {
+ self.midi_devices.push(MidiDevice {
+ name,
+ selected: false,
+ });
+ }
+ }
+ }
+
+ let saved = settings.synth.midi_device.clone();
+ if let Some(found) = self.midi_devices.iter_mut().find(|d| d.name == saved) {
+ found.selected = true;
+ return;
+ }
+
+ if !self.midi_devices.is_empty() {
+ self.midi_devices[0].selected = true;
+ settings.synth.midi_device = self.midi_devices[0].name.clone();
+ }
+ }
+}
diff --git a/src/gui/window/settings/midi.rs b/src/gui/window/settings/midi.rs
new file mode 100644
index 0000000..5eeea9c
--- /dev/null
+++ b/src/gui/window/settings/midi.rs
@@ -0,0 +1,149 @@
+use egui_extras::{Column, TableBuilder};
+
+use crate::settings::{Colors, MidiParsing, WasabiSettings};
+
+use super::SettingsWindow;
+
+impl SettingsWindow {
+ pub fn show_midi_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ ) {
+ ui.heading("Settings");
+ egui::Grid::new("midi_settings_grid")
+ .num_columns(2)
+ .spacing(super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ ui.horizontal(|ui| {
+ ui.label("MIDI Parsing Algorithm:");
+ ui.monospace("\u{2139}").on_hover_text(
+ "\
+ - Cake\n\
+ \0 The most efficient loading and displaying algorithm.\n\
+ \0 The notes will be stored in binary trees and will be\n\
+ \0 displayed dynamically.\n\
+ - Standard (RAM)\n\
+ \0 The MIDI will be loaded in the RAM and all the notes\n\
+ \0 will be rendered normally by the GPU.\n\
+ - Standard (Live)\n\
+ \0 The MIDI will be streamed live from the disk and all\n\
+ \0 the notes will be rendered normally by the GPU.\
+ ",
+ );
+ });
+ egui::ComboBox::from_id_salt("midi_parsing_select")
+ .selected_text(settings.midi.parsing.as_str())
+ .show_ui(ui, |ui| {
+ ui.selectable_value(
+ &mut settings.midi.parsing,
+ MidiParsing::Cake,
+ MidiParsing::Cake.as_str(),
+ );
+ ui.selectable_value(
+ &mut settings.midi.parsing,
+ MidiParsing::Ram,
+ MidiParsing::Ram.as_str(),
+ );
+ ui.selectable_value(
+ &mut settings.midi.parsing,
+ MidiParsing::Live,
+ MidiParsing::Live.as_str(),
+ );
+ });
+ ui.end_row();
+ });
+ ui.vertical_centered(|ui| {
+ ui.small("Changes to this setting will be applied when a new MIDI is loaded.");
+ });
+
+ ui.horizontal(|ui| ui.add_space(width + 40.0));
+ ui.add_space(super::CATEG_SPACE);
+ ui.heading("Color Palette");
+ egui::Frame::default()
+ .rounding(egui::Rounding::same(8.0))
+ .stroke(ui.style().visuals.widgets.noninteractive.bg_stroke)
+ .show(ui, |ui| {
+ TableBuilder::new(ui)
+ .striped(true)
+ .cell_layout(egui::Layout::centered_and_justified(
+ egui::Direction::LeftToRight,
+ ))
+ .resizable(true)
+ .column(Column::exact(width).resizable(false))
+ .body(|mut body| {
+ let row_height = super::CATEG_SPACE * 3.0;
+ body.row(row_height, |mut row| {
+ row.col(|ui| {
+ if ui
+ .selectable_label(
+ settings.midi.colors == Colors::Rainbow,
+ Colors::Rainbow.as_str(),
+ )
+ .clicked()
+ {
+ settings.midi.colors = Colors::Rainbow;
+ }
+ });
+ });
+ body.row(row_height, |mut row| {
+ row.col(|ui| {
+ if ui
+ .selectable_label(
+ settings.midi.colors == Colors::Random,
+ Colors::Random.as_str(),
+ )
+ .clicked()
+ {
+ settings.midi.colors = Colors::Random;
+ }
+ });
+ });
+ let mut temp = self.palettes.clone();
+ for i in temp.iter_mut() {
+ i.selected = false;
+ }
+ let mut changed = false;
+ for (i, palette) in self.palettes.iter_mut().enumerate() {
+ body.row(row_height, |mut row| {
+ row.col(|ui| {
+ if ui
+ .selectable_label(
+ settings.midi.colors == Colors::Palette
+ && palette.selected,
+ palette
+ .path
+ .file_name()
+ .unwrap_or_default()
+ .to_str()
+ .unwrap_or_default(),
+ )
+ .clicked()
+ {
+ settings.midi.colors = Colors::Palette;
+ temp[i].selected = true;
+ settings.midi.palette_path = palette.path.clone();
+ changed = true;
+ }
+ });
+ });
+ }
+ if changed {
+ self.palettes = temp;
+ }
+ });
+ });
+ ui.add_space(4.0);
+ ui.horizontal(|ui| {
+ if ui.button("Refresh List").clicked() {
+ self.load_palettes();
+ }
+ if ui.button("Open Palettes Directory").clicked() {
+ open::that(WasabiSettings::get_palettes_dir()).unwrap_or_default();
+ }
+ });
+ }
+}
diff --git a/src/gui/window/settings/soundfonts.rs b/src/gui/window/settings/soundfonts.rs
new file mode 100644
index 0000000..c28f2ba
--- /dev/null
+++ b/src/gui/window/settings/soundfonts.rs
@@ -0,0 +1,22 @@
+use std::sync::{Arc, RwLock};
+
+use crate::{audio_playback::WasabiAudioPlayer, settings::WasabiSettings};
+
+use super::SettingsWindow;
+
+mod list;
+pub use list::*;
+mod cfg;
+pub use cfg::*;
+
+impl SettingsWindow {
+ pub fn show_soundfont_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ synth: Arc>,
+ ) {
+ self.sf_list.show(ui, settings, width, synth);
+ }
+}
diff --git a/src/gui/window/settings/soundfonts/cfg.rs b/src/gui/window/settings/soundfonts/cfg.rs
new file mode 100644
index 0000000..a183d62
--- /dev/null
+++ b/src/gui/window/settings/soundfonts/cfg.rs
@@ -0,0 +1,122 @@
+use crate::gui::window::WIN_MARGIN;
+
+use super::{SFFormat, SFListItem};
+use egui::{Context, Window};
+use xsynth_core::soundfont::Interpolator;
+
+#[derive(Clone)]
+pub struct SoundfontConfigWindow {
+ pub visible: bool,
+ id: usize,
+}
+
+impl SoundfontConfigWindow {
+ pub fn new(id: usize) -> Self {
+ Self { visible: true, id }
+ }
+
+ pub fn id(&self) -> usize {
+ self.id
+ }
+
+ pub fn show(&mut self, ctx: &Context, item: &mut SFListItem) {
+ let title = if let Some(path) = item.item.path.file_name() {
+ format!("Config for {path:?}")
+ } else {
+ format!("Config for {}", self.id)
+ };
+
+ let frame =
+ egui::Frame::inner_margin(egui::Frame::window(ctx.style().as_ref()), WIN_MARGIN);
+
+ Window::new(title)
+ .id(egui::Id::new(self.id))
+ .collapsible(false)
+ .title_bar(true)
+ .enabled(true)
+ .frame(frame)
+ .open(&mut self.visible)
+ .show(ctx, |ui| {
+ let col_width = 80.0;
+
+ ui.heading("Instrument");
+ ui.separator();
+ egui::Grid::new("sfconfig_window_instr")
+ .num_columns(2)
+ .min_col_width(col_width)
+ .show(ui, |ui| {
+ let mut modify = item.item.options.bank.is_some();
+
+ ui.label("Override Instrument: ");
+ let allow_override = !(item.format == SFFormat::Sfz);
+ ui.add_enabled(allow_override, egui::Checkbox::without_text(&mut modify));
+ ui.end_row();
+
+ if modify && item.item.options.bank.is_none() {
+ item.item.options.bank = Some(0);
+ item.item.options.preset = Some(0);
+ } else if !modify {
+ item.item.options.bank = None;
+ item.item.options.preset = None;
+ }
+
+ let mut bank = item.item.options.bank.unwrap_or(0);
+
+ ui.label("Bank: ");
+ ui.add_enabled(
+ modify,
+ egui::DragValue::new(&mut bank).speed(1).range(0..=128),
+ );
+ ui.end_row();
+
+ if bank != item.item.options.bank.unwrap_or(0) {
+ item.item.options.bank = Some(bank)
+ }
+
+ let mut preset = item.item.options.preset.unwrap_or(0);
+
+ ui.label("Preset: ");
+ ui.add_enabled(
+ modify,
+ egui::DragValue::new(&mut preset).speed(1).range(0..=127),
+ );
+ ui.end_row();
+
+ if preset != item.item.options.preset.unwrap_or(0) {
+ item.item.options.preset = Some(preset)
+ }
+ });
+
+ ui.heading("Settings");
+ ui.separator();
+ egui::Grid::new("sfconfig_window_settings")
+ .num_columns(2)
+ .min_col_width(col_width)
+ .show(ui, |ui| {
+ // ui.label("Linear Release Envelope: ");
+ // ui.checkbox(&mut item.init.linear_release, "");
+ // ui.end_row();
+
+ let interp = ["Nearest Neighbor", "Linear"];
+ let mut interp_idx = item.item.options.interpolator as usize;
+
+ ui.label("Interpolation:");
+ egui::ComboBox::from_id_salt("interpolation").show_index(
+ ui,
+ &mut interp_idx,
+ interp.len(),
+ |i| interp[i].to_owned(),
+ );
+ ui.end_row();
+
+ if interp_idx != item.item.options.interpolator as usize {
+ match interp_idx {
+ 0 => item.item.options.interpolator = Interpolator::Nearest,
+ 1 => item.item.options.interpolator = Interpolator::Linear,
+ _ => item.item.options.interpolator = Interpolator::Nearest,
+ };
+ }
+ });
+ });
+ }
+}
diff --git a/src/gui/window/settings/soundfonts/list.rs b/src/gui/window/settings/soundfonts/list.rs
new file mode 100644
index 0000000..6d0b943
--- /dev/null
+++ b/src/gui/window/settings/soundfonts/list.rs
@@ -0,0 +1,391 @@
+use std::{
+ path::PathBuf,
+ sync::{Arc, RwLock},
+ thread,
+};
+
+use crossbeam_channel::{Receiver, Sender};
+use egui::WidgetText;
+use egui_extras::{Column, TableBuilder};
+use serde::{Deserialize, Serialize};
+
+use crate::{
+ audio_playback::WasabiAudioPlayer,
+ settings::{WasabiSettings, WasabiSoundfont},
+};
+
+use super::SoundfontConfigWindow;
+
+#[derive(Default, Clone, PartialEq, Serialize, Deserialize)]
+pub enum SFFormat {
+ #[default]
+ Sfz,
+ Sf2,
+}
+
+#[derive(Default, Clone, Serialize, Deserialize)]
+#[serde(default)]
+pub struct SFListItem {
+ pub item: WasabiSoundfont,
+ pub id: usize,
+ pub selected: bool,
+ pub format: SFFormat,
+}
+
+pub struct EguiSFList {
+ list: Vec,
+ id_count: usize,
+
+ sf_picker: (Sender, Receiver),
+ sf_cfg_win: Vec,
+}
+
+impl EguiSFList {
+ pub fn new() -> Self {
+ let sf_picker = crossbeam_channel::unbounded();
+
+ Self {
+ list: Vec::new(),
+ id_count: 0,
+ sf_picker,
+ sf_cfg_win: Vec::new(),
+ }
+ }
+
+ pub fn add_item(&mut self, sf: WasabiSoundfont) -> Result<(), String> {
+ let err = Err(format!(
+ "The selected soundfont does not have the correct format: {:?}",
+ sf.path
+ ));
+
+ if let Some(ext) = sf.path.extension() {
+ let format = match ext.to_str().unwrap().to_lowercase().as_str() {
+ "sfz" => SFFormat::Sfz,
+ "sf2" => SFFormat::Sf2,
+ _ => return err,
+ };
+
+ let item = SFListItem {
+ item: sf,
+ id: self.id_count,
+ selected: false,
+ format,
+ };
+ self.list.push(item);
+ self.id_count += 1;
+ return Ok(());
+ }
+
+ err
+ }
+
+ pub fn add_path(&mut self, path: PathBuf) -> Result<(), String> {
+ if !path.exists() {
+ return Err(format!("File not found: {:?}", path));
+ }
+
+ let item = WasabiSoundfont {
+ path,
+ enabled: true,
+ options: Default::default(),
+ };
+
+ self.add_item(item)
+ }
+
+ pub fn select_all(&mut self) {
+ self.list = self
+ .list
+ .clone()
+ .into_iter()
+ .map(|mut item| {
+ item.selected = true;
+ item
+ })
+ .collect();
+ }
+
+ pub fn remove_selected_items(&mut self) {
+ self.list = self
+ .list
+ .clone()
+ .into_iter()
+ .filter(|item| !item.selected)
+ .collect();
+
+ // I'm bored to make it close only the windows needed, so instead I'll close all of them
+ self.sf_cfg_win.clear();
+ }
+
+ pub fn clear(&mut self) {
+ self.list.clear();
+ self.sf_cfg_win.clear();
+ }
+
+ pub fn as_vec(&self) -> Vec {
+ self.list.iter().map(|sf| sf.item.clone()).collect()
+ }
+
+ pub fn show(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ synth: Arc>,
+ ) {
+ let events = ui.input(|i| i.events.clone());
+ for event in &events {
+ if let egui::Event::Key {
+ key,
+ modifiers,
+ pressed,
+ ..
+ } = event
+ {
+ match *key {
+ egui::Key::A => {
+ if *pressed && modifiers.ctrl {
+ self.select_all();
+ }
+ }
+ egui::Key::Delete => {
+ self.remove_selected_items();
+ }
+ _ => {}
+ }
+ }
+ }
+
+ {
+ let recv = self.sf_picker.1.clone();
+ if !recv.is_empty() {
+ for path in recv {
+ //state.last_location = path.clone();
+ if path.is_file() {
+ if let Err(error) = self.add_path(path.clone()) {
+ let title = if let Some(filen) = path.file_name() {
+ format!(
+ "There was an error adding \"{}\" to the list.",
+ filen.to_str().unwrap()
+ )
+ } else {
+ "There was an error adding the selected soundfont to the list."
+ .to_string()
+ };
+ // TODO: errors
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // if !ui.input(|i| i.raw.dropped_files.is_empty()) {
+ // let dropped_files = ui.input(|i| {
+ // i.raw
+ // .dropped_files
+ // .clone()
+ // .iter()
+ // .map(|file| file.path.as_ref().unwrap().clone())
+ // .collect::>()
+ // });
+
+ // for file in dropped_files {
+ // if let Err(error) = self.add_item(file.clone()) {
+ // let title = if let Some(filen) = file.file_name() {
+ // // Not a safe unwrap but things must be very wrong for it to panic so idc
+ // format!(
+ // "There was an error adding \"{}\" to the list.",
+ // filen.to_str().unwrap()
+ // )
+ // } else {
+ // "There was an error adding the selected soundfont to the list.".to_string()
+ // };
+ // // TODO: errors
+ // }
+ // }
+ // }
+
+ self.sf_cfg_win = self
+ .sf_cfg_win
+ .clone()
+ .into_iter()
+ .filter(|item| item.visible)
+ .collect();
+
+ for cfg in self.sf_cfg_win.iter_mut() {
+ let index = self.list.iter().position(|item| item.id == cfg.id());
+ if let Some(index) = index {
+ cfg.show(ui.ctx(), &mut self.list[index]);
+ }
+ }
+
+ egui::TopBottomPanel::bottom("bottom_panel")
+ .resizable(false)
+ .show_inside(ui, |ui| {
+ ui.add_space(5.0);
+ ui.horizontal(|ui| {
+ if ui
+ .button(
+ WidgetText::from(" \u{2795} ")
+ .text_style(egui::TextStyle::Name("monospace big".into())),
+ )
+ .on_hover_text("Add SoundFont(s)")
+ .clicked()
+ {
+ let sender = self.sf_picker.0.clone();
+ //let last_location = state.last_location.clone();
+
+ thread::spawn(move || {
+ let midi_path = rfd::FileDialog::new()
+ .add_filter("Supported SoundFonts", &["sfz", "SFZ", "sf2", "SF2"])
+ //.set_directory(last_location.parent().unwrap_or(Path::new("./")))
+ .pick_file();
+
+ if let Some(midi_path) = midi_path {
+ sender.send(midi_path).unwrap_or_default();
+ }
+ });
+ }
+ if ui
+ .button(
+ WidgetText::from(" \u{2796} ")
+ .text_style(egui::TextStyle::Name("monospace big".into())),
+ )
+ .on_hover_text("Remove Selected")
+ .clicked()
+ {
+ self.remove_selected_items();
+ }
+ if ui
+ .button(
+ WidgetText::from(" \u{2716} ")
+ .text_style(egui::TextStyle::Name("monospace big".into())),
+ )
+ .on_hover_text("Clear List")
+ .clicked()
+ {
+ self.clear();
+ }
+ if ui
+ .button(
+ WidgetText::from(" \u{1F503} ")
+ .text_style(egui::TextStyle::Name("monospace big".into())),
+ )
+ .on_hover_text("Apply SoundFont List")
+ .clicked()
+ {
+ synth
+ .write()
+ .unwrap()
+ .set_soundfonts(&settings.synth.soundfonts);
+ }
+ });
+ ui.small("Loading order is top to bottom. Supported formats: SFZ, SF2");
+ });
+
+ egui::ScrollArea::both().show(ui, |ui| {
+ let events = ui.input(|i| i.events.clone());
+ for event in &events {
+ if let egui::Event::Key {
+ key,
+ modifiers,
+ pressed,
+ ..
+ } = event
+ {
+ match *key {
+ egui::Key::A => {
+ if *pressed && modifiers.ctrl {
+ self.select_all();
+ }
+ }
+ egui::Key::Delete => {
+ self.remove_selected_items();
+ }
+ _ => {}
+ }
+ }
+ }
+
+ TableBuilder::new(ui)
+ .striped(true)
+ .cell_layout(egui::Layout::centered_and_justified(
+ egui::Direction::LeftToRight,
+ ))
+ .resizable(true)
+ .column(Column::exact(20.0).resizable(false))
+ .column(Column::initial(width - 200.0).at_least(50.0).clip(true))
+ .columns(Column::auto().at_least(40.0).clip(true), 2)
+ .column(Column::auto().at_least(40.0).clip(true).resizable(false))
+ .header(20.0, |mut header| {
+ header.col(|_ui| {});
+ header.col(|ui| {
+ ui.strong("Filename");
+ });
+ header.col(|ui| {
+ ui.strong("Format");
+ });
+ header.col(|ui| {
+ ui.strong("Bank");
+ });
+ header.col(|ui| {
+ ui.strong("Preset");
+ });
+ })
+ .body(|mut body| {
+ let row_height = super::super::CATEG_SPACE * 3.0;
+ for item in self.list.iter_mut() {
+ body.row(row_height, |mut row| {
+ row.col(|ui| {
+ ui.checkbox(&mut item.item.enabled, "");
+ });
+ row.col(|ui| {
+ let selectable = if let Some(path) = item.item.path.to_str() {
+ ui.selectable_label(item.selected, path)
+ } else {
+ ui.selectable_label(item.selected, "error")
+ };
+
+ if selectable.clicked() {
+ item.selected = !item.selected;
+ }
+ if selectable.double_clicked()
+ && !self.sf_cfg_win.iter().any(|cfg| cfg.id() == item.id)
+ {
+ self.sf_cfg_win.push(SoundfontConfigWindow::new(item.id))
+ }
+ });
+ row.col(|ui| {
+ ui.label(match item.format {
+ SFFormat::Sfz => "SFZ",
+ SFFormat::Sf2 => "SF2",
+ });
+ });
+
+ let bank_txt = if let Some(bank) = item.item.options.bank {
+ format!("{}", bank)
+ } else {
+ "None".to_owned()
+ };
+ row.col(|ui| {
+ ui.label(bank_txt.to_string());
+ });
+
+ let preset_txt = if let Some(preset) = item.item.options.preset {
+ format!("{}", preset)
+ } else {
+ "None".to_owned()
+ };
+ row.col(|ui| {
+ ui.label(preset_txt.to_string());
+ });
+ });
+ }
+ });
+ ui.allocate_space(ui.available_size());
+ });
+
+ settings.synth.soundfonts = self.as_vec();
+ }
+}
diff --git a/src/gui/window/settings/synth.rs b/src/gui/window/settings/synth.rs
new file mode 100644
index 0000000..1cc8c09
--- /dev/null
+++ b/src/gui/window/settings/synth.rs
@@ -0,0 +1,96 @@
+use std::sync::{Arc, RwLock};
+
+use crate::{
+ audio_playback::WasabiAudioPlayer,
+ gui::window::GuiWasabiWindow,
+ settings::{Synth, WasabiSettings},
+};
+
+use super::SettingsWindow;
+
+mod kdmapi;
+mod mididevice;
+mod xsynth;
+
+impl SettingsWindow {
+ pub fn show_synth_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ synth: Arc>,
+ ) {
+ egui::Grid::new("synth_settings_grid")
+ .num_columns(2)
+ .spacing(super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ let synth_prev = settings.synth.synth;
+ ui.label("Synthesizer:");
+ ui.horizontal(|ui| {
+ egui::ComboBox::from_id_salt("synth_select")
+ .selected_text(settings.synth.synth.as_str())
+ .show_ui(ui, |ui| {
+ ui.selectable_value(
+ &mut settings.synth.synth,
+ Synth::XSynth,
+ Synth::XSynth.as_str(),
+ );
+ ui.selectable_value(
+ &mut settings.synth.synth,
+ Synth::Kdmapi,
+ Synth::Kdmapi.as_str(),
+ );
+ ui.selectable_value(
+ &mut settings.synth.synth,
+ Synth::MidiDevice,
+ Synth::MidiDevice.as_str(),
+ );
+ ui.selectable_value(
+ &mut settings.synth.synth,
+ Synth::None,
+ Synth::None.as_str(),
+ );
+ });
+
+ if ui
+ .button(
+ egui::WidgetText::from(" \u{1F503} ")
+ .text_style(egui::TextStyle::Name("monospace big".into())),
+ )
+ .on_hover_text("Reload Synth")
+ .clicked()
+ {
+ synth
+ .write()
+ .unwrap()
+ .switch(GuiWasabiWindow::create_synth(settings));
+ }
+ });
+ ui.end_row();
+
+ if settings.synth.synth != synth_prev {
+ let new_player = GuiWasabiWindow::create_synth(settings);
+ synth.write().unwrap().switch(new_player);
+ }
+ });
+
+ ui.add_space(8.0);
+ ui.vertical_centered(|ui| {
+ ui.small("Options marked with (*) will apply when the synth is reloaded.");
+ });
+
+ ui.add_space(super::CATEG_SPACE);
+ ui.heading("Synth Settings");
+
+ match settings.synth.synth {
+ Synth::XSynth => self.show_xsynth_settings(ui, settings, width, synth),
+ Synth::Kdmapi => self.show_kdmapi_settings(ui, settings, width),
+ Synth::MidiDevice => self.show_mididevice_settings(ui, settings, width, synth),
+ Synth::None => {
+ ui.label("No Settings");
+ }
+ }
+ }
+}
diff --git a/src/gui/window/settings/synth/kdmapi.rs b/src/gui/window/settings/synth/kdmapi.rs
new file mode 100644
index 0000000..0a95268
--- /dev/null
+++ b/src/gui/window/settings/synth/kdmapi.rs
@@ -0,0 +1,23 @@
+use crate::settings::WasabiSettings;
+
+use super::SettingsWindow;
+
+impl SettingsWindow {
+ pub fn show_kdmapi_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ ) {
+ egui::Grid::new("kdmapi_settings_grid")
+ .num_columns(2)
+ .spacing(super::super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ ui.label("Use the driver's soundfont list*:");
+ ui.checkbox(&mut settings.synth.kdmapi.use_om_sflist, "");
+ ui.end_row();
+ });
+ }
+}
diff --git a/src/gui/window/settings/synth/mididevice.rs b/src/gui/window/settings/synth/mididevice.rs
new file mode 100644
index 0000000..4f2a0fa
--- /dev/null
+++ b/src/gui/window/settings/synth/mididevice.rs
@@ -0,0 +1,66 @@
+use std::sync::{Arc, RwLock};
+
+use egui_extras::{Column, TableBuilder};
+
+use crate::{
+ audio_playback::WasabiAudioPlayer, gui::window::GuiWasabiWindow, settings::WasabiSettings,
+};
+
+use super::SettingsWindow;
+
+impl SettingsWindow {
+ pub fn show_mididevice_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ synth: Arc>,
+ ) {
+ egui::Frame::default()
+ .rounding(egui::Rounding::same(8.0))
+ .stroke(ui.style().visuals.widgets.noninteractive.bg_stroke)
+ .show(ui, |ui| {
+ TableBuilder::new(ui)
+ .striped(true)
+ .cell_layout(egui::Layout::centered_and_justified(
+ egui::Direction::LeftToRight,
+ ))
+ .resizable(true)
+ .column(Column::exact(width).resizable(false))
+ .body(|mut body| {
+ let row_height = super::super::CATEG_SPACE * 3.0;
+
+ let mut temp = self.midi_devices.clone();
+ for i in temp.iter_mut() {
+ i.selected = false;
+ }
+ let mut changed = false;
+ for (i, device) in self.midi_devices.iter_mut().enumerate() {
+ body.row(row_height, |mut row| {
+ row.col(|ui| {
+ if ui
+ .selectable_label(device.selected, device.name.clone())
+ .clicked()
+ {
+ temp[i].selected = true;
+ settings.synth.midi_device = device.name.clone();
+ changed = true;
+ }
+ });
+ });
+ }
+ if changed {
+ self.midi_devices = temp;
+ synth
+ .write()
+ .unwrap()
+ .switch(GuiWasabiWindow::create_synth(settings));
+ }
+ });
+ });
+ ui.add_space(4.0);
+ if ui.button("Refresh List").clicked() {
+ self.load_midi_devices(settings);
+ }
+ }
+}
diff --git a/src/gui/window/settings/synth/xsynth.rs b/src/gui/window/settings/synth/xsynth.rs
new file mode 100644
index 0000000..05fc5c6
--- /dev/null
+++ b/src/gui/window/settings/synth/xsynth.rs
@@ -0,0 +1,102 @@
+use std::sync::{Arc, RwLock};
+
+use xsynth_realtime::ThreadCount;
+
+use crate::{audio_playback::WasabiAudioPlayer, settings::WasabiSettings};
+
+use super::SettingsWindow;
+
+impl SettingsWindow {
+ pub fn show_xsynth_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ synth: Arc>,
+ ) {
+ egui::Grid::new("xsynth_settings_grid")
+ .num_columns(2)
+ .spacing(super::super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ let layer_limit_prev = settings.synth.xsynth.limit_layers;
+
+ ui.label("Enable Layer Limiting: ");
+ ui.checkbox(&mut settings.synth.xsynth.limit_layers, "");
+ ui.end_row();
+
+ let layer_count_prev = settings.synth.xsynth.layers;
+
+ ui.horizontal(|ui| {
+ ui.label("Layer Limit:");
+ ui.monospace("\u{2139}")
+ .on_hover_text("One layer is one voice per key per channel.");
+ });
+ ui.add_enabled(
+ settings.synth.xsynth.limit_layers,
+ egui::DragValue::new(&mut settings.synth.xsynth.layers)
+ .speed(1)
+ .range(1..=usize::MAX),
+ );
+ ui.end_row();
+
+ if settings.synth.xsynth.layers != layer_count_prev
+ || layer_limit_prev != settings.synth.xsynth.limit_layers
+ {
+ synth.write().unwrap().configure(&settings.synth);
+ }
+
+ let buffer_prev = settings.synth.xsynth.config.render_window_ms;
+ ui.label("Render Buffer (ms):");
+ ui.add(
+ egui::DragValue::new(&mut settings.synth.xsynth.config.render_window_ms)
+ .speed(0.1)
+ .range(0.0001..=1000.0),
+ );
+ ui.end_row();
+ if settings.synth.xsynth.config.render_window_ms != buffer_prev {
+ synth.write().unwrap().configure(&settings.synth);
+ }
+
+ ui.label("Ignore velocities between:");
+ let mut lovel = *settings.synth.xsynth.config.ignore_range.start();
+ let mut hivel = *settings.synth.xsynth.config.ignore_range.end();
+ ui.horizontal(|ui| {
+ ui.add(egui::DragValue::new(&mut lovel).speed(1).range(0..=127));
+ ui.label("and");
+ ui.add(egui::DragValue::new(&mut hivel).speed(1).range(lovel..=127));
+ });
+ ui.end_row();
+ if lovel != *settings.synth.xsynth.config.ignore_range.start()
+ || hivel != *settings.synth.xsynth.config.ignore_range.end()
+ {
+ settings.synth.xsynth.config.ignore_range = lovel..=hivel;
+ synth.write().unwrap().configure(&settings.synth);
+ }
+
+ ui.label("Fade out voice when killing it*: ");
+ ui.checkbox(
+ &mut settings
+ .synth
+ .xsynth
+ .config
+ .channel_init_options
+ .fade_out_killing,
+ "",
+ );
+ ui.end_row();
+
+ let mut threading =
+ settings.synth.xsynth.config.multithreading == ThreadCount::Auto;
+ ui.label("Enable multithreading*: ");
+ ui.checkbox(&mut threading, "");
+ ui.end_row();
+ if threading {
+ settings.synth.xsynth.config.multithreading = ThreadCount::Auto;
+ } else {
+ settings.synth.xsynth.config.multithreading = ThreadCount::None;
+ }
+ });
+ }
+}
diff --git a/src/gui/window/settings/visual.rs b/src/gui/window/settings/visual.rs
new file mode 100644
index 0000000..6ba4e00
--- /dev/null
+++ b/src/gui/window/settings/visual.rs
@@ -0,0 +1,175 @@
+use egui::WidgetText;
+use egui_extras::{Column, TableBuilder};
+
+use crate::settings::WasabiSettings;
+
+use super::SettingsWindow;
+
+impl SettingsWindow {
+ pub fn show_visual_settings(
+ &mut self,
+ ui: &mut egui::Ui,
+ settings: &mut WasabiSettings,
+ width: f32,
+ ) {
+ ui.heading("General");
+ egui::Grid::new("general_visual_settings_grid")
+ .num_columns(2)
+ .spacing(super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ ui.label("Check for updates on launch:");
+ ui.checkbox(&mut settings.gui.check_for_updates, "");
+ ui.end_row();
+
+ ui.label("FPS Limit:");
+ ui.add(
+ egui::DragValue::new(&mut settings.gui.fps_limit)
+ .speed(1)
+ .range(0..=usize::MAX),
+ );
+ ui.end_row();
+
+ ui.label("Skip Control:");
+ ui.add(
+ egui::DragValue::new(&mut settings.gui.skip_control)
+ .speed(0.5)
+ .range(0.0..=f64::MAX),
+ );
+ ui.end_row();
+
+ ui.label("Speed Control:");
+ ui.add(
+ egui::DragValue::new(&mut settings.gui.speed_control)
+ .speed(0.5)
+ .range(0.0..=f64::MAX),
+ );
+ ui.end_row();
+ });
+
+ ui.add_space(super::CATEG_SPACE);
+ ui.heading("Scene");
+
+ egui::Grid::new("scene_visual_settings_grid")
+ .num_columns(2)
+ .spacing(super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ ui.label("Background Color: ");
+ ui.color_edit_button_srgba(&mut settings.scene.bg_color);
+ ui.end_row();
+
+ ui.label("Bar Color: ");
+ ui.color_edit_button_srgba(&mut settings.scene.bar_color);
+ ui.end_row();
+
+ ui.label("Keyboard Range: ");
+ let mut firstkey = *settings.scene.key_range.start();
+ let mut lastkey = *settings.scene.key_range.end();
+ ui.horizontal(|ui| {
+ ui.add(egui::DragValue::new(&mut firstkey).speed(1).range(0..=253));
+ ui.add(
+ egui::DragValue::new(&mut lastkey)
+ .speed(1)
+ .range(firstkey + 1..=254),
+ );
+ });
+ ui.end_row();
+ if firstkey != *settings.scene.key_range.start()
+ || lastkey != *settings.scene.key_range.end()
+ {
+ settings.scene.key_range = firstkey..=lastkey;
+ }
+
+ ui.label("Note Speed: ");
+ ui.spacing_mut().slider_width = width / 2.0 - 100.0;
+ ui.add(
+ egui::Slider::new(&mut settings.scene.note_speed, 20.0..=0.0001)
+ .logarithmic(true),
+ );
+ ui.end_row();
+ });
+
+ ui.add_space(super::CATEG_SPACE);
+ ui.heading("Statistics");
+
+ egui::Grid::new("stats_visual_settings_grid")
+ .num_columns(2)
+ .spacing(super::SPACING)
+ .striped(true)
+ .min_col_width(width / 2.0)
+ .show(ui, |ui| {
+ ui.label("Floating:");
+ ui.checkbox(&mut settings.scene.statistics.floating, "");
+ ui.end_row();
+
+ ui.label("Border:");
+ ui.checkbox(&mut settings.scene.statistics.border, "");
+ ui.end_row();
+
+ ui.label("Background Opacity: ");
+ ui.spacing_mut().slider_width = width / 2.0 - 100.0;
+ ui.add(egui::Slider::new(
+ &mut settings.scene.statistics.opacity,
+ 0.0..=1.0,
+ ));
+ ui.end_row();
+ });
+
+ ui.add_space(4.0);
+ egui::Frame::default()
+ .rounding(egui::Rounding::same(8.0))
+ .stroke(ui.style().visuals.widgets.noninteractive.bg_stroke)
+ .show(ui, |ui| {
+ TableBuilder::new(ui)
+ .striped(true)
+ .cell_layout(egui::Layout::centered_and_justified(
+ egui::Direction::LeftToRight,
+ ))
+ .resizable(true)
+ .column(Column::exact(40.0).resizable(false))
+ .column(Column::exact(width - 100.0).resizable(false))
+ .column(Column::exact(60.0).resizable(false))
+ .body(|mut body| {
+ let row_height = super::CATEG_SPACE * 3.0;
+ let mut temp = settings.scene.statistics.order.clone();
+ for (i, item) in settings.scene.statistics.order.iter_mut().enumerate() {
+ body.row(row_height, |mut row| {
+ row.col(|ui| {
+ ui.checkbox(&mut temp[i].1, "");
+ });
+ row.col(|ui| {
+ ui.label(item.0.as_str());
+ });
+ row.col(|ui| {
+ ui.horizontal(|ui| {
+ if ui
+ .button(WidgetText::from("\u{2191}").text_style(
+ egui::TextStyle::Name("monospace big".into()),
+ ))
+ .clicked()
+ && i > 0
+ {
+ temp.swap(i, i - 1);
+ }
+
+ if ui
+ .button(WidgetText::from("\u{2193}").text_style(
+ egui::TextStyle::Name("monospace big".into()),
+ ))
+ .clicked()
+ && i < temp.len() - 1
+ {
+ temp.swap(i, i + 1);
+ }
+ });
+ });
+ });
+ }
+ settings.scene.statistics.order = temp;
+ });
+ });
+ }
+}
diff --git a/src/gui/window/settings_window.rs b/src/gui/window/settings_window.rs
deleted file mode 100644
index f345483..0000000
--- a/src/gui/window/settings_window.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-use egui::Context;
-
-use std::ops::RangeInclusive;
-
-use crate::{
- audio_playback::{
- xsynth::{convert_to_channel_init, convert_to_sf_init},
- AudioPlayerType,
- },
- gui::window::GuiWasabiWindow,
- settings::{MidiLoading, Synth, WasabiSettings},
- state::WasabiState,
-};
-
-pub fn draw_settings(
- win: &mut GuiWasabiWindow,
- settings: &mut WasabiSettings,
- state: &mut WasabiState,
- ctx: &Context,
-) {
- egui::Window::new("Settings")
- .resizable(true)
- .collapsible(true)
- .title_bar(true)
- .scroll2([false, true])
- .enabled(true)
- .open(&mut state.settings_visible)
- .show(ctx, |ui| {
- let col_width = 160.0;
-
- // Synth settings section
- ui.heading("Synth");
- ui.separator();
-
- egui::Grid::new("synth_settings_grid")
- .num_columns(2)
- .spacing([40.0, 4.0])
- .min_col_width(col_width)
- .show(ui, |ui| {
- ui.label("Synth: ");
- let synth_prev = settings.synth.synth;
- egui::ComboBox::from_id_source("synth_select")
- .selected_text(settings.synth.synth.as_str())
- .show_ui(ui, |ui| {
- ui.selectable_value(&mut settings.synth.synth, Synth::XSynth, "XSynth");
- ui.selectable_value(&mut settings.synth.synth, Synth::Kdmapi, "KDMAPI");
- });
- if settings.synth.synth != synth_prev {
- match settings.synth.synth {
- Synth::Kdmapi => {
- win.synth
- .write()
- .unwrap()
- .switch_player(AudioPlayerType::Kdmapi);
- }
- Synth::XSynth => {
- win.synth
- .write()
- .unwrap()
- .switch_player(AudioPlayerType::XSynth {
- buffer: settings.synth.buffer_ms,
- use_threadpool: settings.synth.use_threadpool,
- ignore_range: settings.synth.vel_ignore.clone(),
- options: convert_to_channel_init(settings),
- });
- win.synth.write().unwrap().set_soundfont(
- &settings.synth.sfz_path,
- convert_to_sf_init(settings),
- );
- win.synth.write().unwrap().set_layer_count(
- match settings.synth.layer_count {
- 0 => None,
- _ => Some(settings.synth.layer_count),
- },
- );
- }
- }
- }
- ui.end_row();
-
- ui.label("Configure:");
- if ui.button("Open Synth Settings").clicked() {
- state.xsynth_settings_visible = true;
- }
- ui.end_row();
- });
-
- // MIDI settings section
- ui.add_space(6.0);
- ui.heading("MIDI");
- ui.separator();
-
- egui::Grid::new("midi_settings_grid")
- .num_columns(2)
- .spacing([40.0, 4.0])
- .min_col_width(col_width)
- .show(ui, |ui| {
- ui.label("Note speed: ");
- ui.spacing_mut().slider_width = 150.0;
- ui.add(egui::Slider::new(
- &mut settings.midi.note_speed,
- 2.0..=0.001,
- ));
- ui.end_row();
-
- ui.label("Random Track Colors*: ");
- ui.checkbox(&mut settings.midi.random_colors, "");
- ui.end_row();
-
- ui.label("Keyboard Range: ");
- let mut firstkey = *settings.midi.key_range.start();
- let mut lastkey = *settings.midi.key_range.end();
- ui.horizontal(|ui| {
- ui.add(
- egui::DragValue::new(&mut firstkey)
- .speed(1)
- .clamp_range(RangeInclusive::new(0, 253)),
- );
- ui.add(
- egui::DragValue::new(&mut lastkey)
- .speed(1)
- .clamp_range(RangeInclusive::new(firstkey + 1, 254)),
- );
- });
- ui.end_row();
- if firstkey != *settings.midi.key_range.start()
- || lastkey != *settings.midi.key_range.end()
- {
- settings.midi.key_range = firstkey..=lastkey;
- }
-
- ui.label("MIDI Loading*: ");
- egui::ComboBox::from_id_source("midiload_select")
- .selected_text(settings.midi.midi_loading.as_str())
- .show_ui(ui, |ui| {
- ui.selectable_value(
- &mut settings.midi.midi_loading,
- MidiLoading::Ram,
- "In RAM",
- );
- ui.selectable_value(
- &mut settings.midi.midi_loading,
- MidiLoading::Live,
- "Live",
- );
- ui.selectable_value(
- &mut settings.midi.midi_loading,
- MidiLoading::Cake,
- "Cake",
- );
- });
- });
-
- // Visual settings section
- ui.add_space(6.0);
- ui.heading("Visual");
- ui.separator();
-
- egui::Grid::new("visual_settings_grid")
- .num_columns(2)
- .spacing([40.0, 4.0])
- .min_col_width(col_width)
- .show(ui, |ui| {
- if ui.button("Toggle Fullscreen").clicked() {
- state.fullscreen = true;
- }
- ui.end_row();
-
- ui.label("Background Color: ");
- ui.color_edit_button_srgba(&mut settings.visual.bg_color);
- ui.end_row();
-
- ui.label("Bar Color: ");
- ui.color_edit_button_srgba(&mut settings.visual.bar_color);
- ui.end_row();
- });
-
- ui.separator();
- ui.vertical_centered(|ui| {
- ui.label("Options marked with (*) will apply when a new MIDI is loaded.");
- if ui.button("Save").clicked() {
- settings.save_to_file();
- }
- });
- });
-}
diff --git a/src/gui/window/shortcuts.rs b/src/gui/window/shortcuts.rs
new file mode 100644
index 0000000..0d08cd7
--- /dev/null
+++ b/src/gui/window/shortcuts.rs
@@ -0,0 +1,60 @@
+use crate::state::WasabiState;
+
+use super::GuiWasabiWindow;
+
+impl GuiWasabiWindow {
+ pub fn show_shortcuts(&mut self, ctx: &egui::Context, state: &mut WasabiState) {
+ let frame =
+ egui::Frame::inner_margin(egui::Frame::window(ctx.style().as_ref()), super::WIN_MARGIN);
+ let size = [400.0, 210.0];
+
+ egui::Window::new("Keyboard Shortcuts")
+ .collapsible(false)
+ .title_bar(true)
+ .scroll([false, true])
+ .enabled(true)
+ .frame(frame)
+ .fixed_size(size)
+ .open(&mut state.show_shortcuts)
+ .show(ctx, |ui| {
+ let col_width = size[0] / 2.0;
+ egui::Grid::new("shortcuts_grid")
+ .num_columns(2)
+ .min_col_width(col_width)
+ .striped(true)
+ .show(ui, |ui| {
+ ui.label("Play / Pause Playback");
+ ui.label("Space");
+ ui.end_row();
+
+ ui.label("Skip Forward");
+ ui.label("Right Arrow");
+ ui.end_row();
+
+ ui.label("Go Back");
+ ui.label("Left Arrow");
+ ui.end_row();
+
+ ui.label("Slower Note Speed");
+ ui.label("Ctrl + Up Arrow");
+ ui.end_row();
+
+ ui.label("Faster Note Speed");
+ ui.label("Ctrl + Down Arrow");
+ ui.end_row();
+
+ ui.label("Toggle Fullscreen");
+ ui.label("Alt + Enter");
+ ui.end_row();
+
+ ui.label("Toggle Panel");
+ ui.label("Ctrl + F");
+ ui.end_row();
+
+ ui.label("Toggle Statistics");
+ ui.label("Ctrl + G");
+ ui.end_row();
+ });
+ });
+ }
+}
diff --git a/src/gui/window/stats.rs b/src/gui/window/stats.rs
index 75c9ba9..2ac93d9 100644
--- a/src/gui/window/stats.rs
+++ b/src/gui/window/stats.rs
@@ -1,6 +1,11 @@
use egui::{Context, Frame, Pos2};
-use crate::{gui::window::GuiWasabiWindow, midi::MIDIFileBase};
+use crate::{
+ gui::window::GuiWasabiWindow,
+ midi::{MIDIFileBase, MIDIFileStats},
+ settings::{Statistics, WasabiSettings},
+ utils::convert_seconds_to_time_string,
+};
pub struct GuiMidiStats {
time_passed: f64,
@@ -28,37 +33,63 @@ impl GuiMidiStats {
}
}
-pub fn draw_stats(win: &mut GuiWasabiWindow, ctx: &Context, pos: Pos2, mut stats: GuiMidiStats) {
+fn num_or_q(num: Option) -> String {
+ if let Some(num) = num {
+ num.to_string()
+ } else {
+ "?".to_string()
+ }
+}
+
+pub fn draw_stats(
+ win: &mut GuiWasabiWindow,
+ ctx: &Context,
+ pos: Pos2,
+ mut stats: GuiMidiStats,
+ settings: &WasabiSettings,
+) {
let onepx = ctx.pixels_per_point();
- let stats_frame = Frame::default()
- .inner_margin(egui::style::Margin::same(7.0))
- .fill(egui::Color32::from_rgba_unmultiplied(7, 7, 7, 200))
- .stroke(egui::Stroke::new(
+ let opacity = settings.scene.statistics.opacity.clamp(0.0, 1.0);
+ let alpha = (u8::MAX as f32 * opacity).round() as u8;
+
+ let round = 8.0;
+
+ let mut stats_frame = Frame::default()
+ .inner_margin(egui::Margin::same(7.0))
+ .fill(egui::Color32::from_rgba_unmultiplied(7, 7, 7, alpha));
+
+ if settings.scene.statistics.floating {
+ stats_frame = stats_frame.rounding(egui::Rounding::same(round));
+ } else {
+ stats_frame = stats_frame.rounding(egui::Rounding {
+ ne: 0.0,
+ nw: 0.0,
+ sw: 0.0,
+ se: round,
+ });
+ }
+
+ if settings.scene.statistics.border {
+ stats_frame = stats_frame.stroke(egui::Stroke::new(
onepx,
egui::Color32::from_rgb(50, 50, 50),
- ))
- .rounding(egui::Rounding::same(6.0));
+ ));
+ }
egui::Window::new("Stats")
.resizable(false)
.collapsible(false)
.title_bar(false)
- .scroll2([false, false])
+ .scroll([false, false])
.enabled(true)
.frame(stats_frame)
.fixed_pos(pos)
.fixed_size(egui::Vec2::new(200.0, 128.0))
.show(ctx, |ui| {
- let mut time_millis: i64 = 0;
- let mut time_sec: i64 = 0;
- let mut time_min: i64 = 0;
- let mut length_millis: u64 = 0;
- let mut length_sec: u64 = 0;
- let mut length_min: u64 = 0;
-
- let mut note_stats = Default::default();
+ ui.spacing_mut().interact_size.y = 16.0;
+ let mut note_stats = MIDIFileStats::default();
if let Some(midi_file) = win.midi_file.as_mut() {
stats.time_total = midi_file.midi_length().unwrap_or(0.0);
let time = midi_file.timer().get_time().as_seconds_f64();
@@ -73,69 +104,49 @@ pub fn draw_stats(win: &mut GuiWasabiWindow, ctx: &Context, pos: Pos2, mut stats
stats.time_passed = time;
}
- time_millis = (stats.time_passed * 10.0) as i64 % 10;
- time_sec = stats.time_passed as i64 % 60;
- time_min = stats.time_passed as i64 / 60;
-
note_stats = midi_file.stats();
}
- ui.horizontal(|ui| {
- ui.monospace("Time:");
- ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
- ui.monospace(format!(
- "{}{:0width$}:{:0width$}.{} / {:0width$}:{:0width$}.{}",
- if time_sec + time_millis < 0 {
- '-'
- } else {
- '\0'
- },
- time_min.abs(),
- time_sec.abs(),
- time_millis.abs(),
- length_min,
- length_sec,
- length_millis,
- width = 2
- ));
- });
- });
-
- ui.horizontal(|ui| {
- ui.monospace("FPS:");
- ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
- ui.monospace(format!("{}", win.fps.get_fps().round()));
- });
- });
-
- ui.horizontal(|ui| {
- ui.monospace("Voice Count:");
- ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
- ui.monospace(format!("{}", stats.voice_count));
- });
- });
-
- ui.horizontal(|ui| {
- ui.monospace("Rendered:");
- ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
- ui.monospace(format!("{}", stats.notes_on_screen));
- });
- });
-
- fn num_or_q(num: Option) -> String {
- if let Some(num) = num {
- num.to_string()
- } else {
- "?".to_string()
- }
+ for i in settings.scene.statistics.order.iter().filter(|i| i.1) {
+ match i.0 {
+ Statistics::Time => ui.horizontal(|ui| {
+ ui.monospace("Time:");
+ ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
+ ui.monospace(format!(
+ "{} / {}",
+ convert_seconds_to_time_string(stats.time_passed),
+ convert_seconds_to_time_string(stats.time_total)
+ ));
+ });
+ }),
+ Statistics::Fps => ui.horizontal(|ui| {
+ ui.monospace("FPS:");
+ ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
+ ui.monospace(format!("{}", win.fps.get_fps().round()));
+ });
+ }),
+ Statistics::VoiceCount => ui.horizontal(|ui| {
+ ui.monospace("Voice Count:");
+ ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
+ ui.monospace(format!("{}", stats.voice_count));
+ });
+ }),
+ Statistics::Rendered => ui.horizontal(|ui| {
+ ui.monospace("Rendered:");
+ ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
+ ui.monospace(format!("{}", stats.notes_on_screen));
+ });
+ }),
+ Statistics::NoteCount => {
+ ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
+ ui.monospace(format!(
+ "{} / {}",
+ num_or_q(note_stats.passed_notes),
+ num_or_q(note_stats.total_notes)
+ ));
+ })
+ }
+ };
}
-
- ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
- ui.monospace(format!(
- "{} / {}",
- num_or_q(note_stats.passed_notes),
- num_or_q(note_stats.total_notes)
- ));
- });
});
}
diff --git a/src/gui/window/top_panel.rs b/src/gui/window/top_panel.rs
deleted file mode 100644
index 2a42a51..0000000
--- a/src/gui/window/top_panel.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-use egui::{Context, Frame};
-
-use time::Duration;
-
-use crate::{
- gui::window::GuiWasabiWindow, midi::MIDIFileBase, settings::WasabiSettings, state::WasabiState,
-};
-
-pub fn draw_panel(
- win: &mut GuiWasabiWindow,
- settings: &mut WasabiSettings,
- state: &mut WasabiState,
- ctx: &Context,
-) {
- let panel_frame = Frame::default()
- .inner_margin(egui::style::Margin::same(10.0))
- .fill(egui::Color32::from_rgb(42, 42, 42));
-
- egui::TopBottomPanel::top("Top panel")
- .frame(panel_frame)
- .show_separator_line(false)
- .show(ctx, |ui| {
- ui.horizontal(|ui| {
- if ui.button("Open").clicked() {
- win.open_midi_dialog(settings, state);
- }
-
- if let Some(midi_file) = win.midi_file.as_mut() {
- if ui.button("Unload").clicked() {
- midi_file.timer_mut().pause();
- win.synth.write().unwrap().reset();
- win.midi_file = None;
- }
- }
-
- ui.add_space(10.0);
-
- if ui.button("Settings").clicked() {
- match state.settings_visible {
- true => state.settings_visible = false,
- false => state.settings_visible = true,
- }
- }
-
- ui.add_space(10.0);
-
- if ui.button("Play").clicked() {
- if let Some(midi_file) = win.midi_file.as_mut() {
- midi_file.timer_mut().play();
- }
- }
- if ui.button("Pause").clicked() {
- if let Some(midi_file) = win.midi_file.as_mut() {
- midi_file.timer_mut().pause();
- }
- }
-
- ui.add_space(10.0);
-
- ui.horizontal(|ui| {
- ui.label("Note speed: ");
- ui.add(
- egui::Slider::new(&mut settings.midi.note_speed, 2.0..=0.001)
- .show_value(false),
- );
- })
- });
-
- ui.spacing_mut().slider_width = ctx.available_rect().width() - 20.0;
- let mut empty_slider =
- || ui.add(egui::Slider::new(&mut 0.0, 0.0..=1.0).show_value(false));
- if let Some(midi_file) = win.midi_file.as_mut() {
- if let Some(length) = midi_file.midi_length() {
- let mut time = midi_file.timer().get_time().as_seconds_f64();
- let time_prev = time;
-
- let start_delay = crate::midi::START_DELAY.as_seconds_f64();
- ui.add(egui::Slider::new(&mut time, -start_delay..=length).show_value(false));
- if (time_prev != time)
- && (midi_file.allows_seeking_backward() || time_prev < time)
- {
- midi_file.timer_mut().seek(Duration::seconds_f64(time));
- }
- } else {
- empty_slider();
- }
- } else {
- empty_slider();
- }
- });
-}
diff --git a/src/gui/window/xsynth_settings.rs b/src/gui/window/xsynth_settings.rs
deleted file mode 100644
index 7a12399..0000000
--- a/src/gui/window/xsynth_settings.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-use egui::Context;
-
-use std::ops::RangeInclusive;
-
-use crate::{
- audio_playback::{
- xsynth::{convert_to_channel_init, convert_to_sf_init},
- AudioPlayerType,
- },
- gui::window::GuiWasabiWindow,
- settings::WasabiSettings,
- state::WasabiState,
-};
-
-pub fn draw_xsynth_settings(
- win: &mut GuiWasabiWindow,
- settings: &mut WasabiSettings,
- state: &mut WasabiState,
- ctx: &Context,
-) {
- egui::Window::new("XSynth Settings")
- .resizable(true)
- .collapsible(true)
- .title_bar(true)
- .scroll2([false, true])
- .enabled(true)
- .open(&mut state.xsynth_settings_visible)
- .show(ctx, |ui| {
- let col_width = 240.0;
-
- ui.heading("Synth");
- ui.separator();
-
- egui::Grid::new("synth_settings_grid")
- .num_columns(2)
- .spacing([40.0, 4.0])
- .min_col_width(col_width)
- .show(ui, |ui| {
- ui.label("Synth Render Buffer (ms)*: ");
- ui.add(
- egui::DragValue::new(&mut settings.synth.buffer_ms)
- .speed(0.1)
- .clamp_range(RangeInclusive::new(0.001, 1000.0)),
- );
- ui.end_row();
-
- ui.label("SoundFont Path: ");
- ui.horizontal(|ui| {
- ui.add(egui::TextEdit::singleline(&mut settings.synth.sfz_path));
-
- if ui.button("Browse...").clicked() {
- // If windows, just use the native dialog
- let sfz_path = rfd::FileDialog::new()
- .add_filter("Supported SoundFonts", &["sfz", "sf2", "SF2"])
- .pick_file();
-
- if let Some(sfz_path) = sfz_path {
- if let Ok(path) = sfz_path.into_os_string().into_string() {
- settings.synth.sfz_path = path;
- }
- }
- }
-
- if ui.button("Load").clicked() {
- win.synth.write().unwrap().set_soundfont(
- &settings.synth.sfz_path,
- convert_to_sf_init(settings),
- );
- }
- });
- ui.end_row();
-
- ui.label("Limit Layers: ");
- let layer_limit_prev = settings.synth.limit_layers;
- ui.checkbox(&mut settings.synth.limit_layers, "");
- ui.end_row();
-
- ui.label("Synth Layer Count: ");
- let layer_count_prev = settings.synth.layer_count;
- ui.add_enabled_ui(settings.synth.limit_layers, |ui| {
- ui.add(
- egui::DragValue::new(&mut settings.synth.layer_count)
- .speed(1)
- .clamp_range(RangeInclusive::new(1, 200)),
- );
- });
- if settings.synth.layer_count != layer_count_prev
- || layer_limit_prev != settings.synth.limit_layers
- {
- win.synth.write().unwrap().set_layer_count(
- if settings.synth.limit_layers {
- Some(settings.synth.layer_count)
- } else {
- None
- },
- );
- }
- ui.end_row();
-
- ui.label("Ignore notes with velocities between*: ");
- let mut lovel = *settings.synth.vel_ignore.start();
- let mut hivel = *settings.synth.vel_ignore.end();
- ui.horizontal(|ui| {
- ui.add(
- egui::DragValue::new(&mut lovel)
- .speed(1)
- .clamp_range(RangeInclusive::new(0, 127)),
- );
- ui.label("and");
- ui.add(
- egui::DragValue::new(&mut hivel)
- .speed(1)
- .clamp_range(RangeInclusive::new(lovel, 127)),
- );
- });
- ui.end_row();
- if lovel != *settings.synth.vel_ignore.start()
- || hivel != *settings.synth.vel_ignore.end()
- {
- settings.synth.vel_ignore = lovel..=hivel;
- }
- });
-
- ui.add_space(6.0);
- ui.heading("Engine");
- ui.separator();
-
- egui::Grid::new("engine_settings_grid")
- .num_columns(2)
- .spacing([40.0, 4.0])
- .min_col_width(col_width)
- .show(ui, |ui| {
- ui.label("Fade out voice when killing it*: ");
- ui.checkbox(&mut settings.synth.fade_out_kill, "");
- ui.end_row();
-
- ui.label("Use Effects*: ");
- ui.checkbox(&mut settings.synth.use_effects, "");
- ui.end_row();
-
- ui.label("Use Threadpool*: ");
- ui.checkbox(&mut settings.synth.use_threadpool, "");
- ui.end_row();
- });
-
- ui.separator();
- ui.vertical_centered(|ui| {
- ui.label("Options marked with (*) will apply when the synth is reloaded.");
- if ui.button("Reload XSynth").clicked() {
- win.synth
- .write()
- .unwrap()
- .switch_player(AudioPlayerType::XSynth {
- buffer: settings.synth.buffer_ms,
- use_threadpool: settings.synth.use_threadpool,
- ignore_range: settings.synth.vel_ignore.clone(),
- options: convert_to_channel_init(settings),
- });
- win.synth
- .write()
- .unwrap()
- .set_soundfont(&settings.synth.sfz_path, convert_to_sf_init(settings));
- win.synth
- .write()
- .unwrap()
- .set_layer_count(if settings.synth.limit_layers {
- Some(settings.synth.layer_count)
- } else {
- None
- });
- }
- });
- });
-}
diff --git a/src/main.rs b/src/main.rs
index 4f0e8ea..a3c27b2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,13 +16,14 @@ use gui::{window::GuiWasabiWindow, GuiRenderer, GuiState};
use renderer::Renderer;
use vulkano::swapchain::PresentMode;
-use settings::WasabiSettings;
-use state::WasabiState;
-use winit::{
+use egui_winit::winit::{
dpi::{LogicalSize, Size},
event::{Event, WindowEvent},
- event_loop::{ControlFlow, EventLoop},
+ event_loop::EventLoop,
};
+use settings::WasabiSettings;
+use state::WasabiState;
+use winit::event_loop::ControlFlow;
pub const WINDOW_SIZE: Size = Size::Logical(LogicalSize {
width: 1280.0,
@@ -34,34 +35,25 @@ pub const WAYLAND_PRESENT_MODE: PresentMode = PresentMode::Mailbox;
pub fn main() {
// Winit event loop
- let event_loop = EventLoop::new();
- let monitor = event_loop
- .available_monitors()
- .next()
- .expect("no monitor found!");
-
- let mode = monitor.video_modes().next().expect("no mode found");
+ let event_loop = EventLoop::new().unwrap();
+ event_loop.set_control_flow(ControlFlow::Poll);
// Load the settings values
let mut settings = WasabiSettings::new_or_load();
+ settings.save_to_file();
let mut wasabi_state = WasabiState::default();
// Create renderer for our scene & ui
- let mut renderer = Renderer::new(
- &event_loop,
- "Wasabi",
- settings.visual.fullscreen,
- mode.clone(),
- );
+ let mut renderer = Renderer::new(&event_loop, "Wasabi");
// Vulkano & Winit & egui integration
let mut gui = Gui::new(
&event_loop,
renderer.surface(),
renderer.queue(),
+ renderer.format(),
GuiConfig {
is_overlay: true,
- preferred_format: Some(renderer.format()),
..Default::default()
},
);
@@ -75,62 +67,75 @@ pub fn main() {
let mut gui_state = GuiWasabiWindow::new(&mut gui_render_data, &mut settings);
- event_loop.run(move |event, _, control_flow| {
- let device = renderer.device();
- let queue = renderer.queue();
- let format = renderer.format();
-
- // Update Egui integration so the UI works!
- match event {
- Event::WindowEvent { event, window_id } if window_id == renderer.window().id() => {
- let _pass_events_to_game = !gui.update(&event);
- match event {
- WindowEvent::Resized(size) => {
- renderer.resize(Some(size));
+ event_loop
+ .run(move |event, target| {
+ let device = renderer.device();
+ let queue = renderer.queue();
+ let format = renderer.format();
+
+ // Update Egui integration so the UI works!
+ match event {
+ Event::WindowEvent { event, window_id } if window_id == renderer.window().id() => {
+ let _pass_events_to_game = !gui.update(&event);
+ match event {
+ WindowEvent::Resized(size) => {
+ renderer.resize(Some(size));
+ }
+ WindowEvent::ScaleFactorChanged { .. } => {
+ renderer.resize(None);
+ }
+ WindowEvent::CloseRequested => {
+ target.exit();
+ }
+ WindowEvent::DroppedFile(path) => {
+ gui_state.load_midi(&mut settings, path);
+ }
+ WindowEvent::RedrawRequested => {
+ renderer.render(|frame, future| {
+ // Generate egui layouts
+ gui.immediate_ui(|gui| {
+ let mut gui_render_data = GuiRenderer {
+ gui,
+ device,
+ queue,
+ format,
+ };
+
+ let mut state = GuiState {
+ renderer: &mut gui_render_data,
+ frame,
+ };
+ egui_extras::install_image_loaders(
+ &state.renderer.gui.context(),
+ );
+ gui_state.layout(&mut state, &mut settings, &mut wasabi_state);
+ });
+
+ // Render the layouts
+ gui.draw_on_image(future, frame.image.clone())
+ });
+ }
+ _ => (),
}
- WindowEvent::ScaleFactorChanged { .. } => {
- renderer.resize(None);
- }
- WindowEvent::CloseRequested => {
- *control_flow = ControlFlow::Exit;
- }
- WindowEvent::DroppedFile(path) => {
- gui_state.load_midi(&mut settings, path);
- }
- _ => (),
}
+ Event::NewEvents(..) => {
+ renderer.window().request_redraw();
+ }
+ _ => (),
}
- Event::RedrawRequested(_) => {
- renderer.render(|frame, future| {
- // Generate egui layouts
- gui.immediate_ui(|gui| {
- let mut gui_render_data = GuiRenderer {
- gui,
- device,
- queue,
- format,
- };
-
- let mut state = GuiState {
- renderer: &mut gui_render_data,
- frame,
- };
- gui_state.layout(&mut state, &mut settings, &mut wasabi_state);
- });
-
- // Render the layouts
- gui.draw_on_image(future, frame.image.clone())
- });
- }
- Event::MainEventsCleared => {
- renderer.window().request_redraw();
+
+ let mode = target
+ .available_monitors()
+ .next()
+ .unwrap()
+ .video_modes()
+ .next()
+ .unwrap();
+
+ if wasabi_state.fullscreen {
+ renderer.set_fullscreen(mode);
+ wasabi_state.fullscreen = false;
}
- _ => (),
- }
-
- if wasabi_state.fullscreen {
- renderer.set_fullscreen(mode.clone());
- wasabi_state.fullscreen = false;
- }
- });
+ })
+ .unwrap();
}
diff --git a/src/midi/audio/live.rs b/src/midi/audio/live.rs
index 7812d84..1b2c655 100644
--- a/src/midi/audio/live.rs
+++ b/src/midi/audio/live.rs
@@ -7,7 +7,7 @@ use time::Duration;
use crossbeam_channel::Receiver;
use crate::{
- audio_playback::SimpleTemporaryPlayer,
+ audio_playback::WasabiAudioPlayer,
midi::shared::{
audio::CompressedAudio,
timer::{TimeListener, UnpauseWaitResult, WaitResult},
@@ -17,14 +17,14 @@ use crate::{
pub struct LiveAudioPlayer {
events: Receiver,
timer: TimeListener,
- player: Arc>,
+ player: Arc>,
}
impl LiveAudioPlayer {
pub fn new(
events: Receiver,
timer: TimeListener,
- player: Arc>,
+ player: Arc>,
) -> Self {
LiveAudioPlayer {
events,
diff --git a/src/midi/audio/ram.rs b/src/midi/audio/ram.rs
index 1228eb9..5c6632f 100644
--- a/src/midi/audio/ram.rs
+++ b/src/midi/audio/ram.rs
@@ -5,7 +5,7 @@ use std::{
use time::Duration;
use crate::{
- audio_playback::SimpleTemporaryPlayer,
+ audio_playback::WasabiAudioPlayer,
midi::shared::{
audio::CompressedAudio,
timer::{SeekWaitResult, TimeListener, UnpauseWaitResult, WaitResult},
@@ -15,7 +15,7 @@ use crate::{
pub struct InRamAudioPlayer {
events: Vec,
timer: TimeListener,
- player: Arc>,
+ player: Arc>,
index: usize,
}
@@ -23,7 +23,7 @@ impl InRamAudioPlayer {
pub fn new(
events: Vec,
timer: TimeListener,
- player: Arc>,
+ player: Arc>,
) -> Self {
InRamAudioPlayer {
events,
diff --git a/src/midi/cake/mod.rs b/src/midi/cake/mod.rs
index 0effc44..ef5c07d 100644
--- a/src/midi/cake/mod.rs
+++ b/src/midi/cake/mod.rs
@@ -15,7 +15,7 @@ use midi_toolkit::{
};
use crate::{
- audio_playback::SimpleTemporaryPlayer,
+ audio_playback::WasabiAudioPlayer,
midi::{
audio::ram::InRamAudioPlayer,
cake::tree_threader::{NoteEvent, ThreadedTreeSerializers},
@@ -23,6 +23,7 @@ use crate::{
shared::{audio::CompressedAudio, timer::TimeKeeper},
MIDIColor,
},
+ settings::WasabiSettings,
};
use self::blocks::CakeBlock;
@@ -47,8 +48,8 @@ pub struct CakeMIDIFile {
impl CakeMIDIFile {
pub fn load_from_file(
path: &str,
- player: Arc>,
- random_colors: bool,
+ player: Arc>,
+ settings: &WasabiSettings,
) -> Self {
let ticks_per_second = 10000;
@@ -64,12 +65,7 @@ impl CakeMIDIFile {
|>unwrap_items()
);
- let track_count = midi.track_count();
- let colors = if random_colors {
- MIDIColor::new_random_vec_for_tracks(track_count)
- } else {
- MIDIColor::new_vec_for_tracks(track_count)
- };
+ let colors = MIDIColor::new_vec_from_settings(midi.track_count(), settings);
type Ev = Delta>>;
let (key_snd, key_rcv) = crossbeam_channel::bounded::>(1000);
diff --git a/src/midi/live/mod.rs b/src/midi/live/mod.rs
index 8c46ce8..406c0cc 100644
--- a/src/midi/live/mod.rs
+++ b/src/midi/live/mod.rs
@@ -5,7 +5,7 @@ use std::{
use midi_toolkit::{io::MIDIFile as TKMIDIFile, sequence::event::get_channels_array_statistics};
-use crate::audio_playback::SimpleTemporaryPlayer;
+use crate::{audio_playback::WasabiAudioPlayer, settings::WasabiSettings};
use self::{
parse::LiveMidiParser,
@@ -13,8 +13,8 @@ use self::{
};
use super::{
- open_file_and_signature, shared::timer::TimeKeeper, MIDIFile, MIDIFileBase, MIDIFileStats,
- MIDIFileUniqueSignature, MIDIViewRange,
+ open_file_and_signature, shared::timer::TimeKeeper, MIDIColor, MIDIFile, MIDIFileBase,
+ MIDIFileStats, MIDIFileUniqueSignature, MIDIViewRange,
};
pub mod block;
@@ -37,8 +37,8 @@ pub struct LiveLoadMIDIFile {
impl LiveLoadMIDIFile {
pub fn load_from_file(
path: &str,
- player: Arc>,
- random_colors: bool,
+ player: Arc>,
+ settings: &WasabiSettings,
) -> Self {
let (file, signature) = open_file_and_signature(path);
@@ -62,8 +62,10 @@ impl LiveLoadMIDIFile {
let mut timer = TimeKeeper::new();
- let parer = LiveMidiParser::init(&midi, player, &mut timer);
- let file = LiveNoteViewData::new(parer, midi.track_count(), random_colors);
+ let colors = MIDIColor::new_vec_from_settings(midi.track_count(), settings);
+
+ let parser = LiveMidiParser::init(&midi, player, &mut timer);
+ let file = LiveNoteViewData::new(parser, colors);
LiveLoadMIDIFile {
view_data: file,
diff --git a/src/midi/live/parse.rs b/src/midi/live/parse.rs
index f378413..c0dbde0 100644
--- a/src/midi/live/parse.rs
+++ b/src/midi/live/parse.rs
@@ -17,7 +17,7 @@ use midi_toolkit::{
};
use crate::{
- audio_playback::SimpleTemporaryPlayer,
+ audio_playback::WasabiAudioPlayer,
midi::{
audio::live::LiveAudioPlayer,
shared::timer::{TimeKeeper, WaitResult},
@@ -46,7 +46,7 @@ pub struct LiveMidiParser {
impl LiveMidiParser {
pub fn init(
midi: &TKMIDIFile,
- player: Arc>,
+ player: Arc>,
timer: &mut TimeKeeper,
) -> Self {
let ppq = midi.ppq();
diff --git a/src/midi/live/view.rs b/src/midi/live/view.rs
index f720a9c..ff5885f 100644
--- a/src/midi/live/view.rs
+++ b/src/midi/live/view.rs
@@ -25,7 +25,7 @@ impl<'a> LiveCurrentNoteViews<'a> {
}
impl LiveNoteViewData {
- pub fn new(parser: LiveMidiParser, track_count: usize, random_colors: bool) -> Self {
+ pub fn new(parser: LiveMidiParser, colors: Vec) -> Self {
let mut columns = Vec::with_capacity(256);
columns.resize_with(256, LiveNoteColumn::new);
LiveNoteViewData {
@@ -35,11 +35,7 @@ impl LiveNoteViewData {
start: f64::NEG_INFINITY,
end: f64::NEG_INFINITY,
},
- default_track_colors: if random_colors {
- MIDIColor::new_random_vec_for_tracks(track_count)
- } else {
- MIDIColor::new_vec_for_tracks(track_count)
- },
+ default_track_colors: colors,
}
}
diff --git a/src/midi/mod.rs b/src/midi/mod.rs
index ebe98d6..4df0360 100644
--- a/src/midi/mod.rs
+++ b/src/midi/mod.rs
@@ -8,7 +8,7 @@ mod ram;
mod audio;
mod shared;
-use std::{fs::File, time::UNIX_EPOCH};
+use std::{fs::File, path::PathBuf, time::UNIX_EPOCH};
use enum_dispatch::enum_dispatch;
use palette::{convert::FromColorUnclamped, Hsv, Srgb};
@@ -19,6 +19,8 @@ pub use live::LiveLoadMIDIFile;
pub use ram::InRamMIDIFile;
pub use shared::timer::START_DELAY;
+use crate::settings::{Colors, WasabiSettings};
+
use self::shared::timer::TimeKeeper;
#[derive(Debug, Clone, Copy, Default)]
@@ -91,7 +93,7 @@ impl MIDIColor {
)
}
- pub fn new_vec_for_tracks(tracks: usize) -> Vec {
+ pub fn new_vec(tracks: usize) -> Vec {
let count = tracks * 16;
let mut vec = Vec::with_capacity(count);
@@ -105,7 +107,7 @@ impl MIDIColor {
vec
}
- pub fn new_random_vec_for_tracks(tracks: usize) -> Vec {
+ pub fn new_random_vec(tracks: usize) -> Vec {
let count = tracks * 16;
let mut vec = Vec::with_capacity(count);
@@ -119,6 +121,25 @@ impl MIDIColor {
vec
}
+ pub fn new_vec_from_palette(tracks: usize, path: impl Into) -> Vec {
+ let path: PathBuf = path.into();
+ if path.exists() {
+ return Vec::new();
+ }
+
+ Self::new_vec(tracks)
+ }
+
+ pub fn new_vec_from_settings(tracks: usize, settings: &WasabiSettings) -> Vec {
+ match settings.midi.colors {
+ Colors::Rainbow => MIDIColor::new_vec(tracks),
+ Colors::Random => MIDIColor::new_random_vec(tracks),
+ Colors::Palette => {
+ MIDIColor::new_vec_from_palette(tracks, settings.midi.palette_path.clone())
+ }
+ }
+ }
+
pub fn as_u32(&self) -> u32 {
self.0
}
diff --git a/src/midi/ram/parse.rs b/src/midi/ram/parse.rs
index e318334..9f86b54 100644
--- a/src/midi/ram/parse.rs
+++ b/src/midi/ram/parse.rs
@@ -16,13 +16,15 @@ use midi_toolkit::{
use rustc_hash::FxHashMap;
use crate::{
- audio_playback::SimpleTemporaryPlayer,
+ audio_playback::WasabiAudioPlayer,
midi::{
audio::ram::InRamAudioPlayer,
open_file_and_signature,
ram::{column::InRamNoteColumn, view::InRamNoteViewData},
shared::{audio::CompressedAudio, timer::TimeKeeper, track_channel::TrackAndChannel},
+ MIDIColor,
},
+ settings::WasabiSettings,
};
use super::{block::InRamNoteBlock, InRamMIDIFile};
@@ -98,8 +100,8 @@ impl Key {
impl InRamMIDIFile {
pub fn load_from_file(
path: &str,
- player: Arc>,
- random_colors: bool,
+ player: Arc>,
+ settings: &WasabiSettings,
) -> Self {
let (file, signature) = open_file_and_signature(path);
let midi = TKMIDIFile::open_from_stream(file, None).unwrap();
@@ -192,8 +194,10 @@ impl InRamMIDIFile {
.map(|key| InRamNoteColumn::new(key.column))
.collect();
+ let colors = MIDIColor::new_vec_from_settings(midi.track_count(), settings);
+
InRamMIDIFile {
- view_data: InRamNoteViewData::new(columns, midi.track_count(), random_colors),
+ view_data: InRamNoteViewData::new(columns, colors),
timer,
length,
note_count,
diff --git a/src/midi/ram/view.rs b/src/midi/ram/view.rs
index dbbeaa4..fce8085 100644
--- a/src/midi/ram/view.rs
+++ b/src/midi/ram/view.rs
@@ -22,18 +22,14 @@ impl<'a> InRamCurrentNoteViews<'a> {
}
impl InRamNoteViewData {
- pub fn new(columns: Vec, track_count: usize, random_colors: bool) -> Self {
+ pub fn new(columns: Vec, colors: Vec) -> Self {
InRamNoteViewData {
columns,
view_range: MIDIViewRange {
start: 0.0,
end: 0.0,
},
- default_track_colors: if random_colors {
- MIDIColor::new_random_vec_for_tracks(track_count)
- } else {
- MIDIColor::new_vec_for_tracks(track_count)
- },
+ default_track_colors: colors,
}
}
diff --git a/src/renderer.rs b/src/renderer.rs
index 8e54a55..b18ae72 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -2,6 +2,7 @@ pub mod swapchain;
use std::sync::Arc;
+use raw_window_handle::RawDisplayHandle;
use vulkano::{
device::{
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, Features, Queue,
@@ -14,16 +15,12 @@ use vulkano::{
Version, VulkanLibrary,
};
-use vulkano_win::create_surface_from_winit;
-#[cfg(target_os = "linux")]
-use winit::platform::wayland::EventLoopWindowTargetExtWayland;
-#[cfg(target_os = "linux")]
-use winit::platform::wayland::WindowExtWayland;
+use raw_window_handle::HasDisplayHandle;
use winit::{
dpi::PhysicalSize,
event_loop::EventLoop,
- monitor::VideoMode,
- window::{Fullscreen, Icon, Window, WindowBuilder},
+ monitor::VideoModeHandle,
+ window::{Fullscreen, Icon, Window, WindowAttributes},
};
use self::swapchain::{ManagedSwapchain, SwapchainFrame};
@@ -40,13 +37,13 @@ pub struct Renderer {
}
impl Renderer {
- pub fn new(event_loop: &EventLoop<()>, name: &str, fullscreen: bool, mode: VideoMode) -> Self {
+ pub fn new(event_loop: &EventLoop<()>, name: &str) -> Self {
// Why
let library = VulkanLibrary::new().unwrap();
// Add instance extensions based on needs
let instance_extensions = InstanceExtensions {
- ..vulkano_win::required_extensions(&library)
+ ..Surface::required_extensions(event_loop).unwrap()
};
// Create instance
@@ -61,30 +58,17 @@ impl Renderer {
.expect("Failed to create instance");
// Create rendering surface along with window
- let window = WindowBuilder::new()
+ let win_attr = WindowAttributes::default()
.with_window_icon(Some(Icon::from_rgba(ICON.to_vec(), 16, 16).unwrap()))
- .with_fullscreen({
- if fullscreen {
- #[cfg(target_os = "linux")]
- let fullscreen = if event_loop.is_wayland() {
- Some(Fullscreen::Borderless(None))
- } else {
- Some(Fullscreen::Exclusive(mode))
- };
- #[cfg(not(target_os = "linux"))]
- let fullscreen = Some(Fullscreen::Exclusive(mode));
- fullscreen
- } else {
- None
- }
- })
.with_inner_size(crate::WINDOW_SIZE)
- .with_title(name)
- .build(event_loop)
+ .with_title(name);
+ let window = event_loop
+ .create_window(win_attr)
.expect("Failed to create vulkan surface & window");
+
let window = Arc::new(window);
- let surface = create_surface_from_winit(window.clone(), instance.clone())
+ let surface = Surface::from_window(instance.clone(), window.clone())
.expect("Failed to create surface");
// Get most performant physical device (device with most memory)
@@ -149,7 +133,10 @@ impl Renderer {
physical_device,
device.clone(),
#[cfg(target_os = "linux")]
- if event_loop.is_wayland() {
+ if matches!(
+ event_loop.display_handle().unwrap().as_raw(),
+ RawDisplayHandle::Wayland(..)
+ ) {
println!("Present Mode: {:?}", crate::WAYLAND_PRESENT_MODE);
crate::WAYLAND_PRESENT_MODE
} else {
@@ -196,17 +183,16 @@ impl Renderer {
self.swap_chain.resize(size);
}
- pub fn set_fullscreen(&self, mode: VideoMode) {
+ pub fn set_fullscreen(&self, mode: VideoModeHandle) {
if self.window.fullscreen().is_none() {
- #[cfg(target_os = "linux")]
- let fullscreen = if self.window.wayland_display().is_some() {
+ let fullscreen = if matches!(
+ self.window.display_handle().unwrap().as_raw(),
+ RawDisplayHandle::Wayland(..)
+ ) {
Some(Fullscreen::Borderless(None))
} else {
Some(Fullscreen::Exclusive(mode))
};
- #[cfg(not(target_os = "linux"))]
- let fullscreen = Some(Fullscreen::Exclusive(mode));
-
self.window.set_fullscreen(fullscreen);
} else {
self.window.set_fullscreen(None);
diff --git a/src/renderer/swapchain.rs b/src/renderer/swapchain.rs
index 9aea4a2..b28b8db 100644
--- a/src/renderer/swapchain.rs
+++ b/src/renderer/swapchain.rs
@@ -1,16 +1,17 @@
use std::sync::Arc;
+use egui_winit::winit::{dpi::PhysicalSize, window::Window};
use vulkano::{
device::{physical::PhysicalDevice, Device, Queue},
format::Format,
- image::{view::ImageView, ImageUsage, SwapchainImage},
+ image::{view::ImageView, ImageUsage},
swapchain::{
- AcquireError, PresentMode, Surface, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo,
- SwapchainCreationError, SwapchainPresentInfo,
+ PresentMode, Surface, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo,
+ SwapchainPresentInfo,
},
- sync::{self, FlushError, GpuFuture},
+ sync::{self, GpuFuture},
+ Validated, VulkanError,
};
-use winit::{dpi::PhysicalSize, window::Window};
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ImagesState {
@@ -26,7 +27,7 @@ pub struct SwapchainState {
pub struct ManagedSwapchain {
state: SwapchainState,
swap_chain: Arc,
- image_views: Vec>>,
+ image_views: Vec>,
previous_frame_end: Option>,
device: Arc,
recreate_on_next_frame: bool,
@@ -49,8 +50,9 @@ impl ManagedSwapchain {
.unwrap();
let image_format = formats
.iter()
- .find(|v| v.0 == Format::B8G8R8A8_SRGB)
- .map(|v| v.0);
+ .find(|v| v.0 == Format::B8G8R8A8_UNORM)
+ .map(|v| v.0)
+ .unwrap_or(Format::B8G8R8A8_UNORM);
let image_extent = window.inner_size().into();
let (swapchain, images) = Swapchain::new(
@@ -110,7 +112,7 @@ impl ManagedSwapchain {
..self.swap_chain.create_info()
}) {
Ok(r) => r,
- Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
+ Err(Validated::Error { .. }) => return,
Err(e) => panic!("Failed to recreate swapchain: {e:?}"),
};
self.swap_chain = new_swapchain;
@@ -144,11 +146,15 @@ impl ManagedSwapchain {
let (image_num, suboptimal, acquire_future) = match next {
Ok(r) => r,
// TODO: Handle more errors, e.g. DeviceLost, by re-creating the entire graphics chain
- Err(AcquireError::OutOfDate) => {
- self.recreate();
- continue;
+ Err(Validated::Error(e)) => {
+ if e == VulkanError::OutOfDate {
+ self.recreate();
+ continue;
+ } else {
+ panic!("Failed to acquire next image: {e:?}");
+ }
}
- Err(e) => panic!("Failed to acquire next image: {e:?}"),
+ Err(e) => panic!("Unknown error: {e:?}"),
};
if suboptimal {
@@ -172,7 +178,7 @@ pub struct SwapchainFrame<'a> {
presented: bool,
pub image_num: u32,
- pub image: Arc>,
+ pub image: Arc,
managed_swap_chain: &'a mut ManagedSwapchain,
}
@@ -200,12 +206,17 @@ impl<'a> SwapchainFrame<'a> {
}
sc.previous_frame_end = Some(future.boxed());
}
- Err(FlushError::OutOfDate) => {
- sc.recreate_on_next_frame = true;
- sc.previous_frame_end = Some(sync::now(sc.device.clone()).boxed());
+ Err(Validated::Error(e)) => {
+ if e == VulkanError::OutOfDate {
+ sc.recreate_on_next_frame = true;
+ sc.previous_frame_end = Some(sync::now(sc.device.clone()).boxed());
+ } else {
+ println!("Failed to flush future: {e:?}");
+ sc.previous_frame_end = Some(sync::now(sc.device.clone()).boxed());
+ }
}
Err(e) => {
- println!("Failed to flush future: {e:?}");
+ println!("Unknown error: {e:?}");
sc.previous_frame_end = Some(sync::now(sc.device.clone()).boxed());
}
}
diff --git a/src/scenes.rs b/src/scenes.rs
index 283b238..4d348b5 100644
--- a/src/scenes.rs
+++ b/src/scenes.rs
@@ -2,14 +2,14 @@ use std::sync::Arc;
use vulkano::{
device::Device,
- image::{view::ImageView, AttachmentImage},
+ image::{view::ImageView, Image, ImageCreateInfo, ImageUsage},
memory::allocator::StandardMemoryAllocator,
};
use crate::{gui::GuiState, renderer::swapchain::ImagesState};
pub struct SceneImage {
- pub image: Arc>,
+ pub image: Arc,
pub id: egui::TextureId,
}
@@ -39,17 +39,24 @@ impl SceneSwapchain {
state.renderer.gui.unregister_user_image(image.id);
}
- let allocator = StandardMemoryAllocator::new_default(self.device.clone());
+ let allocator = Arc::new(StandardMemoryAllocator::new_default(self.device.clone()));
+ let mut create_info: ImageCreateInfo = Default::default();
+ create_info.format = image_state.format;
+ create_info.extent = [size[0], size[1], 1];
+ create_info.usage = ImageUsage::SAMPLED;
// Create new images
for _ in 0..image_state.count {
let image = ImageView::new_default(
- AttachmentImage::sampled_input_attachment(&allocator, size, image_state.format)
+ Image::new(allocator.clone(), create_info.clone(), Default::default())
.expect("Failed to create scene image"),
)
.expect("Failed to create scene image view");
- let id = state.renderer.gui.register_user_image_view(image.clone());
+ let id = state
+ .renderer
+ .gui
+ .register_user_image_view(image.clone(), Default::default());
self.scene_images.push(SceneImage { image, id });
}
diff --git a/src/settings/enums.rs b/src/settings/enums.rs
new file mode 100644
index 0000000..f741d4d
--- /dev/null
+++ b/src/settings/enums.rs
@@ -0,0 +1,167 @@
+use num_enum::FromPrimitive;
+use serde_derive::{Deserialize, Serialize};
+use std::{fmt::Debug, slice::Iter, str::FromStr};
+
+#[repr(usize)]
+#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, FromPrimitive)]
+#[serde(rename_all = "lowercase")]
+pub enum MidiParsing {
+ #[default]
+ Ram = 0,
+ Live = 1,
+ Cake = 2,
+}
+
+impl MidiParsing {
+ pub const fn as_str(self) -> &'static str {
+ match self {
+ MidiParsing::Ram => "Standard (RAM)",
+ MidiParsing::Live => "Standard (Live)",
+ MidiParsing::Cake => "Cake",
+ }
+ }
+}
+
+impl FromStr for MidiParsing {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.to_lowercase().as_str() {
+ "ram" => Ok(MidiParsing::Ram),
+ "live" => Ok(MidiParsing::Live),
+ "cake" => Ok(MidiParsing::Cake),
+ s => Err(format!(
+ "{} was not expected. Expected one of `ram`, `live` or `cake`",
+ s
+ )),
+ }
+ }
+}
+
+#[repr(usize)]
+#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, FromPrimitive)]
+#[serde(rename_all = "lowercase")]
+pub enum Synth {
+ #[default]
+ XSynth = 0,
+ Kdmapi = 1,
+ MidiDevice = 2,
+ None = 3,
+}
+
+impl Synth {
+ #[inline]
+ pub const fn as_str(self) -> &'static str {
+ match self {
+ Synth::XSynth => "Built-In (XSynth)",
+ Synth::Kdmapi => "KDMAPI",
+ Synth::MidiDevice => "MIDI Device",
+ Synth::None => "None",
+ }
+ }
+}
+
+impl FromStr for Synth {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.to_lowercase().as_str() {
+ "xsynth" => Ok(Synth::XSynth),
+ "kdmapi" => Ok(Synth::Kdmapi),
+ "mididevice" => Ok(Synth::MidiDevice),
+ "none" => Ok(Synth::None),
+ s => Err(format!(
+ "{} was not expected. Expected one of `xsynth`, `kdmapi`, `mididevice` or `none`",
+ s
+ )),
+ }
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, FromPrimitive)]
+#[repr(usize)]
+#[serde(rename_all = "lowercase")]
+pub enum Statistics {
+ #[default]
+ Time = 0,
+ Fps = 1,
+ VoiceCount = 2,
+ Rendered = 3,
+ NoteCount = 4,
+}
+
+impl Statistics {
+ #[inline]
+ pub const fn as_str(self) -> &'static str {
+ match self {
+ Statistics::Time => "Time",
+ Statistics::Fps => "FPS",
+ Statistics::VoiceCount => "Voice Count",
+ Statistics::Rendered => "Rendered",
+ Statistics::NoteCount => "Note Count",
+ }
+ }
+
+ pub fn iter() -> Iter<'static, Statistics> {
+ static STATISTICS: [Statistics; 5] = [
+ Statistics::Time,
+ Statistics::Fps,
+ Statistics::VoiceCount,
+ Statistics::Rendered,
+ Statistics::NoteCount,
+ ];
+ STATISTICS.iter()
+ }
+}
+
+impl FromStr for Statistics {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.to_lowercase().as_str() {
+ "time" => Ok(Statistics::Time),
+ "fps" => Ok(Statistics::Fps),
+ "voicecount" => Ok(Statistics::VoiceCount),
+ "rendered" => Ok(Statistics::Rendered),
+ "notecount" => Ok(Statistics::NoteCount),
+ s => Err(format!("{} was not expected.", s)),
+ }
+ }
+}
+
+#[repr(usize)]
+#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, FromPrimitive)]
+#[serde(rename_all = "lowercase")]
+pub enum Colors {
+ #[default]
+ Rainbow = 0,
+ Random = 1,
+ Palette = 2,
+}
+
+impl Colors {
+ #[inline]
+ pub const fn as_str(self) -> &'static str {
+ match self {
+ Colors::Rainbow => "Rainbow",
+ Colors::Random => "Random",
+ Colors::Palette => "Palette",
+ }
+ }
+}
+
+impl FromStr for Colors {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.to_lowercase().as_str() {
+ "rainbow" => Ok(Colors::Rainbow),
+ "random" => Ok(Colors::Random),
+ "palette" => Ok(Colors::Palette),
+ s => Err(format!(
+ "{} was not expected. Expected one of `ranbow`, `random` or `palette`",
+ s
+ )),
+ }
+ }
+}
diff --git a/src/settings/migrations.rs b/src/settings/migrations.rs
index ea63efb..7d667d7 100644
--- a/src/settings/migrations.rs
+++ b/src/settings/migrations.rs
@@ -1,77 +1,6 @@
-use colors_transform::{Color, Rgb};
-use egui::Color32;
-use serde_derive::Deserialize;
-use std::fs;
+mod serializers;
+mod v0;
+mod v1;
-use super::{MidiLoading, MidiSettings, Synth, SynthSettings, VisualSettings, WasabiSettings};
-
-#[derive(Deserialize)]
-pub struct WasabiConfigFileV0 {
- note_speed: f64,
- bg_color: String,
- bar_color: String,
- random_colors: bool,
- sfz_path: String,
- first_key: u8,
- last_key: u8,
- midi_loading: usize,
- buffer_ms: f64,
- use_threadpool: bool,
- limit_layers: bool,
- layer_count: usize,
- fade_out_kill: bool,
- use_effects: bool,
- vel_ignore_lo: u8,
- vel_ignore_hi: u8,
- synth: usize,
-}
-
-impl WasabiConfigFileV0 {
- pub fn migrate() -> Result {
- let config_path = WasabiSettings::get_config_path();
- let content = fs::read_to_string(config_path).unwrap_or_default();
- let cfg = toml::from_str::(&content)?;
- if let (Ok(bg), Ok(bar)) = (
- Rgb::from_hex_str(&cfg.bg_color),
- Rgb::from_hex_str(&cfg.bar_color),
- ) {
- Ok(WasabiSettings {
- synth: SynthSettings {
- synth: Synth::from(cfg.synth),
- buffer_ms: cfg.buffer_ms,
- use_threadpool: cfg.use_threadpool,
- limit_layers: cfg.limit_layers,
- layer_count: cfg.layer_count,
- fade_out_kill: cfg.fade_out_kill,
- use_effects: cfg.use_effects,
- sfz_path: cfg.sfz_path,
- vel_ignore: cfg.vel_ignore_lo..=cfg.vel_ignore_hi,
- },
- midi: MidiSettings {
- note_speed: cfg.note_speed,
- random_colors: cfg.random_colors,
- key_range: cfg.first_key..=cfg.last_key,
- midi_loading: MidiLoading::from(cfg.midi_loading),
- },
- visual: VisualSettings {
- bg_color: Color32::from_rgb(
- bg.get_red() as u8,
- bg.get_green() as u8,
- bg.get_blue() as u8,
- ),
- bar_color: Color32::from_rgb(
- bar.get_red() as u8,
- bar.get_green() as u8,
- bar.get_blue() as u8,
- ),
- show_top_pannel: true,
- show_statistics: true,
- fullscreen: false,
- },
- load_midi_file: None,
- })
- } else {
- Ok(WasabiSettings::default())
- }
- }
-}
+pub use v0::*;
+pub use v1::*;
diff --git a/src/settings/migrations/serializers.rs b/src/settings/migrations/serializers.rs
new file mode 100644
index 0000000..9339616
--- /dev/null
+++ b/src/settings/migrations/serializers.rs
@@ -0,0 +1,104 @@
+pub mod color32_serde {
+ use colors_transform::{Color, Rgb};
+ use egui::Color32;
+ use serde::{de::Visitor, Deserializer};
+
+ #[inline(always)]
+ pub fn color_parser(s: &str) -> Result {
+ let rgb = Rgb::from_hex_str(s).map_err(|e| e.message)?;
+ Ok(Color32::from_rgb(
+ rgb.get_red() as u8,
+ rgb.get_green() as u8,
+ rgb.get_blue() as u8,
+ ))
+ }
+
+ pub struct ColorVisitor;
+
+ impl<'de> Visitor<'de> for ColorVisitor {
+ type Value = Color32;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ formatter.write_str("A color encoded as a hex string")
+ }
+
+ fn visit_str(self, v: &str) -> Result
+ where
+ E: serde::de::Error,
+ {
+ color_parser(v)
+ .map_err(|e| E::invalid_value(serde::de::Unexpected::Str(v), &e.as_str()))
+ }
+ }
+
+ pub fn deserialize<'de, D>(de: D) -> Result
+ where
+ D: Deserializer<'de>,
+ {
+ de.deserialize_str(ColorVisitor)
+ }
+}
+
+pub mod range_serde {
+ use std::ops::RangeInclusive;
+
+ use serde::{
+ de::{self, Visitor},
+ Deserializer,
+ };
+
+ use serde_derive::Deserialize;
+
+ #[derive(Deserialize)]
+ #[serde(field_identifier, rename_all = "lowercase")]
+ enum Field {
+ Hi,
+ Lo,
+ }
+
+ pub struct RangeVisitor;
+
+ impl<'de> Visitor<'de> for RangeVisitor {
+ type Value = RangeInclusive;
+
+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ formatter.write_str("A color encoded as a hex string")
+ }
+
+ fn visit_map(self, mut map: A) -> Result
+ where
+ A: serde::de::MapAccess<'de>,
+ {
+ let mut hi = None;
+ let mut lo = None;
+ while let Some(key) = map.next_key::()? {
+ match key {
+ Field::Hi => {
+ if hi.is_some() {
+ return Err(de::Error::duplicate_field("hi"));
+ }
+ hi = Some(map.next_value::()?);
+ }
+ Field::Lo => {
+ if lo.is_some() {
+ return Err(de::Error::duplicate_field("lo"));
+ }
+ lo = Some(map.next_value::()?);
+ }
+ }
+ }
+
+ let hi = hi.ok_or_else(|| de::Error::missing_field("hi"))?;
+ let lo = lo.ok_or_else(|| de::Error::missing_field("lo"))?;
+
+ Ok(hi..=lo)
+ }
+ }
+
+ pub fn deserialize<'de, D>(de: D) -> Result, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ de.deserialize_struct("range", &["hi", "lo"], RangeVisitor)
+ }
+}
diff --git a/src/settings/migrations/v0.rs b/src/settings/migrations/v0.rs
new file mode 100644
index 0000000..0a796e2
--- /dev/null
+++ b/src/settings/migrations/v0.rs
@@ -0,0 +1,71 @@
+use colors_transform::{Color, Rgb};
+use egui::Color32;
+use serde_derive::Deserialize;
+
+use super::v1::{MidiSettingsV1, SynthSettingsV1, VisualSettingsV1};
+use super::WasabiConfigFileV1;
+use crate::settings::enums::{MidiParsing, Synth};
+
+#[allow(dead_code)]
+#[derive(Deserialize)]
+pub struct WasabiConfigFileV0 {
+ note_speed: f64,
+ bg_color: String,
+ bar_color: String,
+ random_colors: bool,
+ sfz_path: String,
+ first_key: u8,
+ last_key: u8,
+ midi_loading: usize,
+ buffer_ms: f64,
+ limit_layers: bool,
+ layer_count: usize,
+ fade_out_kill: bool,
+ linear_envelope: bool,
+ use_effects: bool,
+ vel_ignore_lo: u8,
+ vel_ignore_hi: u8,
+ synth: usize,
+}
+
+impl WasabiConfigFileV0 {
+ pub fn migrate_to_v1(content: String) -> Result {
+ let cfg = toml::from_str::(&content)?;
+ let bg = Rgb::from_hex_str(&cfg.bg_color).unwrap_or(Rgb::from(0.1, 0.1, 0.1));
+ let bar = Rgb::from_hex_str(&cfg.bar_color).unwrap_or(Rgb::from(0.56, 0.0, 0.0));
+ Ok(WasabiConfigFileV1 {
+ synth: SynthSettingsV1 {
+ synth: Synth::from(cfg.synth),
+ buffer_ms: cfg.buffer_ms,
+ limit_layers: cfg.limit_layers,
+ layer_count: cfg.layer_count,
+ fade_out_kill: cfg.fade_out_kill,
+ use_effects: cfg.use_effects,
+ sfz_path: cfg.sfz_path,
+ vel_ignore: cfg.vel_ignore_lo..=cfg.vel_ignore_hi,
+ },
+ midi: MidiSettingsV1 {
+ note_speed: cfg.note_speed,
+ random_colors: cfg.random_colors,
+ key_range: cfg.first_key..=cfg.last_key,
+ midi_loading: MidiParsing::from(cfg.midi_loading),
+ },
+ visual: VisualSettingsV1 {
+ bg_color: Color32::from_rgb(
+ bg.get_red() as u8,
+ bg.get_green() as u8,
+ bg.get_blue() as u8,
+ ),
+ bar_color: Color32::from_rgb(
+ bar.get_red() as u8,
+ bar.get_green() as u8,
+ bar.get_blue() as u8,
+ ),
+ show_top_pannel: true,
+ show_statistics: true,
+ fullscreen: false,
+ },
+ load_midi_file: None,
+ })
+ }
+}
diff --git a/src/settings/migrations/v1.rs b/src/settings/migrations/v1.rs
new file mode 100644
index 0000000..f209e63
--- /dev/null
+++ b/src/settings/migrations/v1.rs
@@ -0,0 +1,101 @@
+use egui::Color32;
+use serde_derive::Deserialize;
+use std::ops::RangeInclusive;
+use xsynth_realtime::{ChannelInitOptions, XSynthRealtimeConfig};
+
+use super::serializers::{color32_serde, range_serde};
+use crate::settings::{
+ MidiParsing, MidiSettings, SceneSettings, Synth, SynthSettings, WasabiSettings,
+ WasabiSoundfont, XSynthSettings,
+};
+
+#[allow(dead_code)]
+#[derive(Deserialize)]
+pub struct VisualSettingsV1 {
+ #[serde(with = "color32_serde")]
+ pub bg_color: Color32,
+ #[serde(with = "color32_serde")]
+ pub bar_color: Color32,
+ pub show_top_pannel: bool,
+ pub show_statistics: bool,
+ pub fullscreen: bool,
+}
+
+#[allow(dead_code)]
+#[derive(Deserialize)]
+pub struct MidiSettingsV1 {
+ pub note_speed: f64,
+ pub random_colors: bool,
+ #[serde(with = "range_serde")]
+ pub key_range: RangeInclusive,
+ pub midi_loading: MidiParsing,
+}
+
+#[allow(dead_code)]
+#[derive(Deserialize)]
+pub struct SynthSettingsV1 {
+ pub synth: Synth,
+ pub buffer_ms: f64,
+ pub sfz_path: String,
+ pub limit_layers: bool,
+ pub layer_count: usize,
+ #[serde(with = "range_serde")]
+ pub vel_ignore: RangeInclusive,
+ pub fade_out_kill: bool,
+ pub use_effects: bool,
+}
+
+#[allow(dead_code)]
+#[derive(Deserialize)]
+pub struct WasabiConfigFileV1 {
+ pub synth: SynthSettingsV1,
+ pub midi: MidiSettingsV1,
+ pub visual: VisualSettingsV1,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub load_midi_file: Option,
+}
+
+impl WasabiConfigFileV1 {
+ pub fn migrate_to_v2(content: String) -> Result {
+ let cfg = toml::from_str::(&content)?;
+ Ok(Self::migrate_to_v2_raw(cfg))
+ }
+
+ pub fn migrate_to_v2_raw(cfg: Self) -> WasabiSettings {
+ WasabiSettings {
+ scene: SceneSettings {
+ bg_color: cfg.visual.bg_color,
+ bar_color: cfg.visual.bar_color,
+ statistics: Default::default(),
+ note_speed: cfg.midi.note_speed,
+ key_range: cfg.midi.key_range,
+ },
+ midi: MidiSettings {
+ parsing: cfg.midi.midi_loading,
+ ..Default::default()
+ },
+ synth: SynthSettings {
+ synth: cfg.synth.synth,
+ soundfonts: vec![WasabiSoundfont {
+ path: cfg.synth.sfz_path.into(),
+ enabled: true,
+ options: Default::default(),
+ }],
+ xsynth: XSynthSettings {
+ layers: cfg.synth.layer_count,
+ limit_layers: cfg.synth.limit_layers,
+ config: XSynthRealtimeConfig {
+ render_window_ms: cfg.synth.buffer_ms,
+ channel_init_options: ChannelInitOptions {
+ fade_out_killing: cfg.synth.fade_out_kill,
+ },
+ ignore_range: cfg.synth.vel_ignore,
+ ..Default::default()
+ },
+ },
+ ..Default::default()
+ },
+ ..Default::default()
+ }
+ }
+}
diff --git a/src/settings/mod.rs b/src/settings/mod.rs
index 58f8923..1429424 100644
--- a/src/settings/mod.rs
+++ b/src/settings/mod.rs
@@ -1,8 +1,5 @@
-use clap::{parser::ValueSource, value_parser, Arg, ArgAction, Command, ValueHint};
-use colors_transform::{Color, Rgb};
use directories::BaseDirs;
use egui::Color32;
-use num_enum::FromPrimitive;
use serde_derive::{Deserialize, Serialize};
use std::{
fmt::Debug,
@@ -10,639 +7,247 @@ use std::{
io::Write,
ops::RangeInclusive,
path::{Path, PathBuf},
- str::FromStr,
};
-use xsynth_core::{channel::ChannelInitOptions, soundfont::SoundfontInitOptions};
+use xsynth_core::soundfont::SoundfontInitOptions;
use xsynth_realtime::XSynthRealtimeConfig;
+mod enums;
mod migrations;
-#[inline(always)]
-fn f64_parser(s: &str) -> Result {
- s.parse().map_err(|e| format!("{}", e))
-}
+pub use enums::*;
-#[inline(always)]
-fn note_speed(s: &str) -> Result {
- let num: f64 = f64_parser(s)?;
- if (0.0001..=2.0).contains(&num) {
- Ok(2.0001 - num)
- } else {
- Err(String::from("Number must be between >0 and 2.0"))
- }
-}
+// region: gui
-#[inline(always)]
-fn color_parser(s: &str) -> Result {
- let rgb = Rgb::from_hex_str(s).map_err(|e| e.message)?;
- Ok(Color32::from_rgb(
- rgb.get_red() as u8,
- rgb.get_green() as u8,
- rgb.get_blue() as u8,
- ))
-}
-
-#[inline(always)]
-fn range_parser(s: &str) -> Result, String> {
- let range = s
- .split_once(',')
- .ok_or_else(|| String::from("This argument requires 2 numbers, comma seperated"))?;
-
- Ok(range.0.parse().map_err(|e| format!("{}", e))?
- ..=range.1.parse().map_err(|e| format!("{}", e))?)
+#[derive(Debug, Serialize, Deserialize, Clone)]
+#[serde(default)]
+pub struct GuiSettings {
+ pub check_for_updates: bool,
+ pub fps_limit: usize,
+ pub skip_control: f64,
+ pub speed_control: f64,
}
-mod color32_serde {
- use colors_transform::Rgb;
- use egui::Color32;
- use serde::{de::Visitor, Deserializer, Serializer};
-
- use super::color_parser;
-
- pub fn serialize
(color: &Color32, ser: S) -> Result
- where
- S: Serializer,
- {
- let hex_color =
- Rgb::from(color.r() as f32, color.g() as f32, color.b() as f32).to_css_hex_string();
-
- ser.serialize_str(&hex_color)
- }
-
- pub struct ColorVisitor;
-
- impl<'de> Visitor<'de> for ColorVisitor {
- type Value = Color32;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- formatter.write_str("A color encoded as a hex string")
- }
-
- fn visit_str(self, v: &str) -> Result
- where
- E: serde::de::Error,
- {
- color_parser(v)
- .map_err(|e| E::invalid_value(serde::de::Unexpected::Str(v), &e.as_str()))
+impl Default for GuiSettings {
+ fn default() -> Self {
+ Self {
+ check_for_updates: true,
+ fps_limit: 0,
+ skip_control: 1.0,
+ speed_control: 0.05,
}
}
-
- pub fn deserialize<'de, D>(de: D) -> Result
- where
- D: Deserializer<'de>,
- {
- de.deserialize_str(ColorVisitor)
- }
}
-mod range_serde {
- use std::ops::RangeInclusive;
-
- use serde::{
- de::{self, Visitor},
- ser::SerializeStruct,
- Deserializer, Serializer,
- };
-
- use serde_derive::Deserialize;
-
- pub fn serialize(range: &RangeInclusive, ser: S) -> Result
- where
- S: Serializer,
- {
- let mut ser_struct = ser.serialize_struct("range", 2)?;
- ser_struct.serialize_field("hi", range.start())?;
- ser_struct.serialize_field("lo", range.end())?;
- ser_struct.end()
- }
-
- #[derive(Deserialize)]
- #[serde(field_identifier, rename_all = "lowercase")]
- enum Field {
- Hi,
- Lo,
- }
-
- pub struct RangeVisitor;
-
- impl<'de> Visitor<'de> for RangeVisitor {
- type Value = RangeInclusive;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- formatter.write_str("A color encoded as a hex string")
- }
-
- fn visit_map(self, mut map: A) -> Result
- where
- A: serde::de::MapAccess<'de>,
- {
- let mut hi = None;
- let mut lo = None;
- while let Some(key) = map.next_key::()? {
- match key {
- Field::Hi => {
- if hi.is_some() {
- return Err(de::Error::duplicate_field("hi"));
- }
- hi = Some(map.next_value::()?);
- }
- Field::Lo => {
- if lo.is_some() {
- return Err(de::Error::duplicate_field("lo"));
- }
- lo = Some(map.next_value::()?);
- }
- }
- }
-
- let hi = hi.ok_or_else(|| de::Error::missing_field("hi"))?;
- let lo = lo.ok_or_else(|| de::Error::missing_field("lo"))?;
+#[derive(Debug, Serialize, Deserialize, Clone)]
+#[serde(default)]
+pub struct StatisticsSettings {
+ pub border: bool,
+ pub floating: bool,
+ pub opacity: f32,
+ pub order: Vec<(Statistics, bool)>,
+}
- Ok(hi..=lo)
+impl Default for StatisticsSettings {
+ fn default() -> Self {
+ Self {
+ border: true,
+ floating: true,
+ opacity: 0.5,
+ order: Statistics::iter().map(|i| (*i, true)).collect(),
}
}
-
- pub fn deserialize<'de, D>(de: D) -> Result, D::Error>
- where
- D: Deserializer<'de>,
- {
- de.deserialize_struct("range", &["hi", "lo"], RangeVisitor)
- }
}
-#[repr(usize)]
-#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, FromPrimitive)]
-#[serde(rename_all = "lowercase")]
-pub enum MidiLoading {
- #[default]
- Ram = 0,
- Live = 1,
- Cake = 2,
+#[derive(Debug, Serialize, Deserialize, Clone)]
+#[serde(default)]
+pub struct SceneSettings {
+ pub bg_color: Color32,
+ pub bar_color: Color32,
+ pub statistics: StatisticsSettings,
+ pub note_speed: f64,
+ pub key_range: RangeInclusive,
}
-impl MidiLoading {
- pub const fn as_str(self) -> &'static str {
- match self {
- MidiLoading::Ram => "In RAM",
- MidiLoading::Live => "Live",
- MidiLoading::Cake => "Cake",
+impl Default for SceneSettings {
+ fn default() -> Self {
+ Self {
+ bg_color: Color32::from_rgb(30, 30, 30),
+ bar_color: Color32::from_rgb(145, 0, 0),
+ statistics: Default::default(),
+ note_speed: 0.25,
+ key_range: 0..=127,
}
}
}
-impl FromStr for MidiLoading {
- type Err = String;
-
- fn from_str(s: &str) -> Result {
- match s.to_lowercase().as_str() {
- "ram" => Ok(MidiLoading::Ram),
- "live" => Ok(MidiLoading::Live),
- "cake" => Ok(MidiLoading::Cake),
- s => Err(format!(
- "{} was not expected. Expected one of `ram`, `live` or `cake`",
- s
- )),
- }
- }
-}
+// endregion
-#[repr(usize)]
-#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, FromPrimitive)]
-#[serde(rename_all = "lowercase")]
-pub enum Synth {
- #[default]
- XSynth = 0,
- Kdmapi = 1,
-}
+// region: midi
-impl Synth {
- #[inline]
- pub const fn as_str(self) -> &'static str {
- match self {
- Synth::XSynth => "XSynth",
- Synth::Kdmapi => "KDMAPI",
- }
- }
+#[derive(Debug, Serialize, Deserialize, Clone)]
+#[serde(default)]
+pub struct MidiSettings {
+ pub parsing: MidiParsing,
+ pub colors: Colors,
+ pub palette_path: PathBuf,
}
-impl FromStr for Synth {
- type Err = String;
-
- fn from_str(s: &str) -> Result {
- match s.to_lowercase().as_str() {
- "xsynth" => Ok(Synth::XSynth),
- "kdmapi" => Ok(Synth::Kdmapi),
- s => Err(format!(
- "{} was not expected. Expected one of `xsynth`, or `kdmapi`",
- s
- )),
+impl Default for MidiSettings {
+ fn default() -> Self {
+ Self {
+ parsing: MidiParsing::Cake,
+ colors: Colors::Rainbow,
+ palette_path: PathBuf::new(),
}
}
}
-#[derive(Debug, Deserialize, Serialize)]
+// endregion
+
+// region: synth
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(default)]
-pub struct VisualSettings {
- #[serde(with = "color32_serde")]
- pub bg_color: Color32,
- #[serde(with = "color32_serde")]
- pub bar_color: Color32,
- pub show_top_pannel: bool,
- pub show_statistics: bool,
- pub fullscreen: bool,
+pub struct XSynthSettings {
+ pub config: XSynthRealtimeConfig,
+ pub limit_layers: bool,
+ pub layers: usize,
}
-impl Default for VisualSettings {
+impl Default for XSynthSettings {
fn default() -> Self {
- VisualSettings {
- bg_color: Color32::from_rgb(30, 30, 30),
- bar_color: Color32::from_rgb(145, 0, 0),
- show_top_pannel: true,
- show_statistics: true,
- fullscreen: false,
+ Self {
+ config: Default::default(),
+ limit_layers: true,
+ layers: 4,
}
}
}
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[serde(default)]
-pub struct MidiSettings {
- pub note_speed: f64,
- pub random_colors: bool,
- #[serde(with = "range_serde")]
- pub key_range: RangeInclusive,
- pub midi_loading: MidiLoading,
+pub struct KdmapiSettings {
+ pub use_om_sflist: bool,
}
-impl Default for MidiSettings {
- fn default() -> Self {
- MidiSettings {
- note_speed: 0.25,
- random_colors: false,
- key_range: 0..=127,
- midi_loading: MidiLoading::Cake,
- }
- }
+#[derive(Debug, Serialize, Deserialize, Clone, Default)]
+#[serde(default)]
+pub struct WasabiSoundfont {
+ pub path: PathBuf,
+ pub enabled: bool,
+ pub options: SoundfontInitOptions,
}
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(default)]
pub struct SynthSettings {
pub synth: Synth,
- pub buffer_ms: f64,
- pub use_threadpool: bool,
- pub sfz_path: String,
- pub limit_layers: bool,
- pub layer_count: usize,
- #[serde(with = "range_serde")]
- pub vel_ignore: RangeInclusive,
- pub fade_out_kill: bool,
- pub use_effects: bool,
+ pub soundfonts: Vec,
+
+ pub xsynth: XSynthSettings,
+ pub kdmapi: KdmapiSettings,
+ pub midi_device: String,
}
impl Default for SynthSettings {
fn default() -> Self {
- SynthSettings {
+ Self {
synth: Synth::XSynth,
- buffer_ms: XSynthRealtimeConfig::default().render_window_ms,
- use_threadpool: false,
- sfz_path: String::new(),
- limit_layers: true,
- layer_count: 4,
- vel_ignore: 0..=0,
- fade_out_kill: ChannelInitOptions::default().fade_out_killing,
- use_effects: SoundfontInitOptions::default().use_effects,
+ soundfonts: Vec::new(),
+ xsynth: Default::default(),
+ kdmapi: Default::default(),
+ midi_device: String::new(),
}
}
}
-#[derive(Debug, Deserialize, Serialize, Default)]
+// endregion
+
+// region: general
+
+#[derive(Default, Debug, Serialize, Deserialize, Clone)]
#[serde(default)]
pub struct WasabiSettings {
- pub synth: SynthSettings,
+ pub gui: GuiSettings,
+ pub scene: SceneSettings,
pub midi: MidiSettings,
- pub visual: VisualSettings,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub load_midi_file: Option,
+ pub synth: SynthSettings,
}
-static CONFIG_PATH: &str = "wasabi-config.toml";
-
impl WasabiSettings {
+ const VERSION_TEXT: &str = "# DON'T EDIT THIS LINE; Version: 2\n";
+
pub fn new_or_load() -> Self {
let config_path = Self::get_config_path();
- let mut config = if !Path::new(&config_path).exists() {
- Self::load_and_save_defaults()
- } else {
- let config = fs::read_to_string(&config_path).unwrap();
- if config.starts_with('#') {
- if let Ok(config) = toml::from_str(&config) {
- config
- } else {
- Self::load_and_save_defaults()
+ if !Path::new(&config_path).exists() {
+ return Self::load_and_save_defaults();
+ } else if let Ok(config) = fs::read_to_string(&config_path) {
+ if config.starts_with(Self::VERSION_TEXT) {
+ let offset = Self::VERSION_TEXT.len();
+ if let Ok(config) = serde_json::from_str(&config[offset..]) {
+ return config;
+ }
+ } else if config.starts_with("# DON'T EDIT THIS LINE; Version: 1") {
+ if let Ok(cfg) = migrations::WasabiConfigFileV1::migrate_to_v2(config) {
+ cfg.save_to_file();
+ return cfg;
}
} else {
- let config = migrations::WasabiConfigFileV0::migrate().unwrap_or_default();
- config.save_to_file();
- config
+ if let Ok(v1) = migrations::WasabiConfigFileV0::migrate_to_v1(config) {
+ let cfg = migrations::WasabiConfigFileV1::migrate_to_v2_raw(v1);
+ cfg.save_to_file();
+ return cfg;
+ }
}
- };
+ }
- config.augment_from_args();
- config
+ println!("Error loading config. Resetting.");
+ Self::load_and_save_defaults()
}
pub fn save_to_file(&self) {
let config_path = Self::get_config_path();
- let toml: String = toml::to_string(&self).unwrap();
- if Path::new(&config_path).exists() {
- fs::remove_file(&config_path).expect("Error deleting old config");
- }
- let mut file = fs::File::create(&config_path).unwrap();
- file.write_all(b"# DON'T EDIT THIS LINE; Version: 1\n\n")
- .unwrap();
- file.write_all(toml.as_bytes())
- .expect("Error creating config");
- }
-
- fn augment_from_args(&mut self) {
- let matches = Command::new("wasabi")
- .version(env!("CARGO_PKG_VERSION"))
- .author(env!("CARGO_PKG_AUTHORS"))
- .about(env!("CARGO_PKG_DESCRIPTION"))
- .arg(
- Arg::new("synth")
- .help("The synthesizer to use")
- .long_help(
- "The synthesizer that is used to play the MIDI. \
- This can either be XSynth (recommended) or KDMAPI. KDMAPI \
- only works if you have OmniMIDI installed, and are using Windows",
- )
- .short('S')
- .long("synth")
- .value_parser(Synth::from_str),
- )
- .arg(
- Arg::new("buffer-ms")
- .help("The amount of time events are held in the buffer")
- .long_help(
- "The amount of time that events are held in the \
- buffer before being played. Higher numbers may increase \
- performance but also increase latency.",
- )
- .short('b')
- .long("buffer-ms")
- .value_parser(f64_parser),
- )
- .arg(
- Arg::new("sfz-path")
- .help("The path to an SFZ SoundFont")
- .long_help(
- "The path to any SFZ soundfont. In audio only mode \
- a soundfont must be passed either via the config file, or
- this command line option. In the GUI you can set this under \
- `Open Synth Settings > SFZ Path`",
- )
- .short('s')
- .long("sfz-path")
- .value_hint(ValueHint::FilePath),
- )
- .arg(
- Arg::new("dont-limit-layers")
- .help("Do not apply the layer limit to the synth")
- .long_help(
- "This allows the synth to create as many layers as it \
- needs to play the MIDI file faithfully. Only turn this on if your \
- MIDI sounds bad, or your computer is running on GFuel",
- )
- .long("dont-limit-layers")
- .action(ArgAction::SetFalse),
- )
- .arg(
- Arg::new("layer-count")
- .help("The amount of layers that the synthesizer can create")
- .long_help(
- "The maximum amount of voices the synth is \
- allowed to create per key per channel",
- )
- .short('l')
- .long("layer-count")
- .value_parser(value_parser!(usize)),
- )
- .arg(
- Arg::new("vel-ignore")
- .help("The range of note velocities that the synth will discard")
- .long_help(
- "Two numbers, comma seperated, that represent a range of velocities \
- that the synth will discard, making notes in the range inaudible.",
- )
- .short('v')
- .long("vel-ignore")
- .value_parser(range_parser),
- )
- .arg(
- Arg::new("fade-out-kill")
- .help("Once a voice is killed, fade it out")
- .long_help(
- "Once the synthesizer kills one of it's voices, it will fade it \
- out as opposed to simply cutting it off",
- )
- .short('F')
- .long("fade-out-kill")
- .action(ArgAction::SetTrue),
- )
- .arg(
- Arg::new("no-effects")
- .help("Disables the soundfont's effects")
- .long_help(
- "Disables soundfont audio effects. \
- This may improve the performance.",
- )
- .short('N')
- .long("no-effects")
- .action(ArgAction::SetFalse),
- )
- .arg(
- Arg::new("note-speed")
- .help("The speed that the notes travel on-screen")
- .long_help(
- "The speed at which the notes will move across the screen. This makes \
- the notes physically longer, causing them to move faster on-screen",
- )
- .short('n')
- .long("note-speed")
- .value_parser(note_speed),
- )
- .arg(
- Arg::new("random-colors")
- .help("Make each channel a random color")
- .long_help("This causes each of the note channels to become a random color")
- .short('r')
- .long("random-colors")
- .action(ArgAction::SetTrue),
- )
- .arg(
- Arg::new("key-range")
- .help("The key range of the on-screen piano keyboard")
- .long_help(
- "Two numbers, comma seperated, that describe the range \
- of keys to be shown on the on-screen piano keyboard, the range must \
- be less than 255 and more than 0",
- )
- .short('k')
- .long("key-range")
- .value_parser(range_parser),
- )
- .arg(
- Arg::new("midi-loading")
- .help("How the MIDI is loaded into `wasabi`")
- .long_help(
- "The method in which the MIDI file is loaded into `wasabi`, the \
- two possible options are `ram`, which loads the MIDI file entirely into \
- RAM before beginning playback; and `live` which will read the MIDI file \
- as it's being played back. The latter method is for using with systems \
- with low memory",
- )
- .short('m')
- .long("midi-loading")
- .value_parser(MidiLoading::from_str),
- )
- .arg(
- Arg::new("bg-color")
- .help("The window background")
- .long_help("A hex color string describing the background color of the window")
- .long("bg-color")
- .value_parser(color_parser),
- )
- .arg(
- Arg::new("bar-color")
- .help("The color of the bar just above the piano")
- .long_help(
- "A hex color string describing the color of the bar just above \
- the on-screen piano keyboard",
- )
- .long("bar-color")
- .value_parser(color_parser),
- )
- .arg(
- Arg::new("hide-top-pannel")
- .long_help(
- "Hides the top panel from view when the app opens. It can be un-hidden \
- with Ctrl+F",
- )
- .help("Hide the top panel")
- .long("hide-top-pannel")
- .action(ArgAction::SetFalse),
- )
- .arg(
- Arg::new("hide-statistics")
- .help("Hide the statistics window")
- .long_help(
- "Hides the statistics window from view when the app opens. It can be \
- un-hidden with Ctrl+G",
- )
- .long("hide-statistics")
- .action(ArgAction::SetFalse),
- )
- .arg(
- Arg::new("fullscreen")
- .help("Start `wasabi` in fullscreen")
- .long_help(
- "Starts `wasabi` in fullscreen mode. `wasabi` will use \
- borderless fullscreen mode on Linux systems running Wayland, \
- and exclusive fullscreen mode for everyone else",
- )
- .short('f')
- .long("fullscreen")
- .action(ArgAction::SetTrue),
- )
- .arg(
- Arg::new("midi-file")
- .value_hint(ValueHint::FilePath)
- .help("The MIDI file to immediately begin playing")
- .long_help(
- "This MIDI file is played immediately after the app's launch. \
- This argument is required to use the `--audio-only` option",
- ),
- )
- .get_matches();
-
- macro_rules! set {
- ($one:ident.$two:ident,$value:expr) => {
- if let Some(value) = matches.get_one($value) {
- self.$one.$two = *value;
- }
- };
- }
-
- macro_rules! set_flag {
- ($one:ident.$two:ident,$value:expr) => {
- if matches!(matches.value_source($value), Some(ValueSource::CommandLine)) {
- if let Some(value) = matches.get_one($value) {
- self.$one.$two = *value;
- }
- }
- };
- }
-
- macro_rules! set_owned {
- ($one:ident.$two:ident,$value:expr,$type:ty) => {
- if let Some(value) = matches.get_one::<$type>($value) {
- self.$one.$two = value.to_owned();
- }
- };
+ let cfg: String = serde_json::to_string_pretty(&self).unwrap();
+ if let Ok(mut file) = fs::File::create(&config_path) {
+ file.write_all(Self::VERSION_TEXT.as_bytes()).unwrap();
+ file.write_all(cfg.as_bytes())
+ .expect("Error creating config");
}
-
- self.load_midi_file = matches.get_one::("midi-file").map(|f| f.to_owned());
-
- // Synth settings
- set!(synth.synth, "synth");
- set!(synth.buffer_ms, "buffer-ms");
- set_owned!(synth.sfz_path, "sfz-path", String);
- set_flag!(synth.limit_layers, "dont-limit-layers");
- set!(synth.layer_count, "layer-count");
- set_owned!(synth.vel_ignore, "vel-ignore", RangeInclusive);
- set_flag!(synth.fade_out_kill, "fade-out-kill");
- set_flag!(synth.use_effects, "no-effects");
-
- // MIDI settings
- set!(midi.note_speed, "note-speed");
- set_flag!(midi.random_colors, "random-colors");
- set_owned!(midi.key_range, "key-range", RangeInclusive);
- set!(midi.midi_loading, "midi-loading");
-
- // Visual settings
- set!(visual.bg_color, "bg-color");
- set!(visual.bar_color, "bar-color");
- set_flag!(visual.show_top_pannel, "hide-top-pannel");
- set_flag!(visual.show_statistics, "hide-statistics");
- set_flag!(visual.fullscreen, "fullscreen");
}
fn load_and_save_defaults() -> Self {
- let _ = fs::remove_file(Self::get_config_path());
let cfg = Self::default();
Self::save_to_file(&cfg);
cfg
}
- fn get_config_path() -> String {
+ fn get_config_dir() -> PathBuf {
if let Some(base_dirs) = BaseDirs::new() {
let mut path: PathBuf = base_dirs.config_dir().to_path_buf();
path.push("wasabi");
- path.push(CONFIG_PATH);
- if std::fs::create_dir_all(path.parent().unwrap()).is_ok() {
- if let Some(path) = path.to_str() {
- path.to_string()
- } else {
- CONFIG_PATH.to_string()
- }
- } else {
- CONFIG_PATH.to_string()
+ if std::fs::create_dir_all(&path).is_ok() {
+ return path;
}
- } else {
- CONFIG_PATH.to_string()
}
+
+ PathBuf::from("./")
+ }
+
+ fn get_config_path() -> PathBuf {
+ let mut path = Self::get_config_dir();
+ path.push("wasabi-config.toml");
+
+ path
+ }
+
+ pub fn get_palettes_dir() -> PathBuf {
+ let mut path = Self::get_config_dir();
+ path.push("palettes");
+ std::fs::create_dir_all(&path).unwrap_or_default();
+
+ path
}
}
+
+// endregion
diff --git a/src/state.rs b/src/state.rs
index c652a76..d9c5dbe 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -1,10 +1,46 @@
use std::path::PathBuf;
-#[derive(Clone, Default)]
+#[derive(Default, PartialEq)]
+pub enum SettingsTab {
+ #[default]
+ Visual,
+ Midi,
+ Synth,
+ SoundFonts,
+}
+
pub struct WasabiState {
pub fullscreen: bool,
- pub settings_visible: bool,
- pub xsynth_settings_visible: bool,
- pub last_midi_file: Option,
- // pub last_sfz_file: Option,
+
+ pub panel_pinned: bool,
+ pub panel_popup_id: egui::Id,
+ pub stats_visible: bool,
+
+ pub show_settings: bool,
+ pub show_shortcuts: bool,
+ pub show_about: bool,
+
+ pub settings_tab: SettingsTab,
+
+ pub last_location: PathBuf,
+}
+
+impl Default for WasabiState {
+ fn default() -> Self {
+ Self {
+ fullscreen: false,
+
+ panel_pinned: true,
+ panel_popup_id: egui::Id::new("options_popup"),
+ stats_visible: true,
+
+ show_settings: false,
+ show_shortcuts: false,
+ show_about: false,
+
+ settings_tab: SettingsTab::default(),
+
+ last_location: PathBuf::default(),
+ }
+ }
}
diff --git a/src/utils.rs b/src/utils.rs
index a441e8e..81b564e 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,3 +1,22 @@
pub fn calculate_border_width(width_pixels: f32, keys_len: f32) -> f32 {
((width_pixels / keys_len) / 12.0).clamp(1.0, 5.0).round() * 2.0
}
+
+pub fn convert_seconds_to_time_string(sec: f64) -> String {
+ let time_millis = (sec * 10.0) as i64 % 10;
+ let time_sec = sec as i64 % 60;
+ let time_min = sec as i64 / 60;
+
+ format!(
+ "{}{:0width$}:{:0width$}.{}",
+ if time_sec + time_millis < 0 {
+ '-'
+ } else {
+ '\0'
+ },
+ time_min.abs(),
+ time_sec.abs(),
+ time_millis.abs(),
+ width = 2
+ )
+}