From c699801d78bed1c45f6b2323a7ae7024afb4c57f Mon Sep 17 00:00:00 2001 From: Sheldon Knuth <4120133-sheldon_knuth@users.noreply.gitlab.com> Date: Tue, 2 Jul 2019 04:10:55 +0000 Subject: [PATCH] Revamping the audio system for Voxygen from #163 --- .gitignore | 5 + Cargo.lock | 137 +++++++-- common/Cargo.toml | 1 + common/src/assets/mod.rs | 87 +++--- voxygen/Cargo.toml | 5 +- voxygen/src/audio/base.rs | 428 +++++++++++++++++++++++++++++ voxygen/src/audio/mod.rs | 144 ++-------- voxygen/src/hud/settings_window.rs | 4 +- voxygen/src/main.rs | 7 +- voxygen/src/session.rs | 4 +- voxygen/src/settings.rs | 2 + 11 files changed, 631 insertions(+), 193 deletions(-) create mode 100644 voxygen/src/audio/base.rs diff --git a/.gitignore b/.gitignore index 887cde8b21..7851bea8dc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ /target/ /*/target/ +# Vim + +**/*.vi +**/*.swp + # IntelliJ **/.idea/ diff --git a/Cargo.lock b/Cargo.lock index 7c1d8b036e..89e3069f1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,10 +21,21 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "alga" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "alsa-sys" -version = "0.1.1" -source = "git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130#e7c086d0afc368a888ad133c3b1d928b16986130" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -268,16 +279,6 @@ dependencies = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cgmath" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "chrono" version = "0.4.7" @@ -315,7 +316,7 @@ dependencies = [ [[package]] name = "claxon" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -464,9 +465,9 @@ dependencies = [ [[package]] name = "cpal" version = "0.8.2" -source = "git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130#e7c086d0afc368a888ad133c3b1d928b16986130" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "alsa-sys 0.1.1 (git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130)", + "alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -486,6 +487,19 @@ dependencies = [ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-channel" version = "0.2.6" @@ -498,6 +512,15 @@ dependencies = [ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.5.2" @@ -745,6 +768,11 @@ dependencies = [ "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "find_folder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fixedbitset" version = "0.1.9" @@ -861,6 +889,14 @@ dependencies = [ "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gfx" version = "0.17.1" @@ -1280,6 +1316,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "line_drawing" version = "0.7.0" @@ -1348,6 +1389,14 @@ dependencies = [ "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matrixmultiply" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memchr" version = "1.0.2" @@ -1461,6 +1510,21 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nalgebra" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "net2" version = "0.2.33" @@ -2007,6 +2071,11 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rawpointer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rayon" version = "1.1.0" @@ -2103,16 +2172,16 @@ dependencies = [ [[package]] name = "rodio" -version = "0.8.1" -source = "git+https://github.com/desttinghim/rodio.git?rev=dd93f905c1afefaac03c496a666ecab27d3e391b#dd93f905c1afefaac03c496a666ecab27d3e391b" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cgmath 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "claxon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cpal 0.8.2 (git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130)", + "claxon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "hound 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lewton 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "minimp3 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2507,6 +2576,11 @@ name = "tuple_utils" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.3" @@ -2581,6 +2655,7 @@ version = "0.2.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "find_folder 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2630,6 +2705,7 @@ dependencies = [ "backtrace 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", "conrod_core 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", "conrod_winit 0.63.0 (git+https://gitlab.com/veloren/conrod.git)", + "crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "dot_vox 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "euc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2649,7 +2725,7 @@ dependencies = [ "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "portpicker 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rodio 0.8.1 (git+https://github.com/desttinghim/rodio.git?rev=dd93f905c1afefaac03c496a666ecab27d3e391b)", + "rodio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2867,7 +2943,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" -"checksum alsa-sys 0.1.1 (git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130)" = "" +"checksum alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d708cb68c7106ed1844de68f50f0157a7788c2909a6926fad5a87546ef6a4ff8" +"checksum alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" "checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" @@ -2898,11 +2975,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49" -"checksum cgmath 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87f025a17ad3f30d49015c787903976d5f9cd6115ece1eb7f4d6ffe06b8c4080" "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e414af9726e1d11660801e73ccc7fb81803fb5f49e5903a25b348b2b3b480d2e" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum claxon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "35193597ff846c905e135b66b7a88876a8b684d269a24fa0f6086988fc2197c8" +"checksum claxon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f86c952727a495bda7abaf09bafdee1a939194dd793d9a8e26281df55ac43b00" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cocoa 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0c23085dde1ef4429df6e5896b89356d35cdd321fb43afe3e378d010bb5adc6" "checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b" @@ -2919,9 +2995,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" "checksum coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" "checksum coreaudio-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78fdbabf58d5b1f461e31b94a571c109284f384cec619a3d96e66ec55b4de82b" -"checksum cpal 0.8.2 (git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130)" = "" +"checksum cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58ae1ed6536b1b233f5e3aeb6997a046ddb4d05e3f61701b58a92eb254a829e" "checksum crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650" +"checksum crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b14492071ca110999a20bf90e3833406d5d66bfd93b4e52ec9539025ff43fe0d" "checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827" +"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7792c4a9b5a4222f654e3728a3dd945aacc24d2c3a1a096ed265d80e4929cb9a" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" @@ -2949,6 +3027,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum find_folder 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f6d018fb95a0b59f854aed68ecd96ce2b80af7911b92b1fed3c4b1fa516b91b" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" @@ -2962,6 +3041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gdk-pixbuf 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c2d2199eba47ebcb9977ce28179649bdd59305ef465c4e6f9b65aaa41c24e6b5" "checksum gdk-pixbuf-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df6a3b73e04fafc07f5ebc083f1096a773412e627828e1103a55e921f81187d8" "checksum gdk-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3162ff940526ddff71bf1f630facee6b5e05d282d125ba0c4c803842819b80c3" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum gfx 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7d7ce0c1f747245342a73453fdb098ea0764c430421fbc4d98cdc8ef8ede4834" "checksum gfx_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c74932837e61f20956c3da1a47471513707dde300274812bba94373ab51830ae" "checksum gfx_device_gl 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "def9cc76ab9ae3187a1ef5edb16c263fa7d713319ffa1d46e00c9d348081a982" @@ -3005,6 +3085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" "checksum libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5692f82b51823e27c4118b3e5c0d98aee9be90633ebc71ad12afef380b50219" +"checksum libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" "checksum line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" @@ -3014,6 +3095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfed72d871629daa12b25af198f110e8095d7650f5f4c61c5bac28364604f9b" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" @@ -3026,6 +3108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum mopa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a785740271256c230f57462d3b83e52f998433a7062fc18f96d5999474a9f915" "checksum msgbox 0.1.1 (git+https://github.com/bekker/msgbox-rs.git)" = "" +"checksum nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e12856109b5cb8e2934b5e45e4624839416e1c6c1f7d286711a7a66b79db29d" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" @@ -3087,6 +3170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" "checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" "checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -3097,7 +3181,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" -"checksum rodio 0.8.1 (git+https://github.com/desttinghim/rodio.git?rev=dd93f905c1afefaac03c496a666ecab27d3e391b)" = "" +"checksum rodio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d0f961b254e66d147a7b550c78b01308934c97d807a34b417fd0f5a0a0f3a2d" "checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" @@ -3144,6 +3228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbfecd7bb8f0a3e96b3b31c46af2677a55a588767c0091f484601424fcb20e7e" +"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/common/Cargo.toml b/common/Cargo.toml index 92245e75b3..bbd8b088c0 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -24,3 +24,4 @@ rayon = "1.0" lazy_static = "1.3" lz4-compress = "0.1" fxhash = "0.2" +find_folder = "0.3" diff --git a/common/src/assets/mod.rs b/common/src/assets/mod.rs index ab4717b325..aab9a74a3a 100644 --- a/common/src/assets/mod.rs +++ b/common/src/assets/mod.rs @@ -5,9 +5,11 @@ use serde_json::Value; use std::{ any::Any, collections::HashMap, - fs::File, + env, + fs::{read_dir, read_link, File, ReadDir}, io::BufReader, io::Read, + path::{Path, PathBuf}, sync::{Arc, RwLock}, }; @@ -113,41 +115,60 @@ impl Asset for Value { } // TODO: System to load file from specifiers (e.g.: "core.ui.backgrounds.city"). -fn try_open_with_path(name: &str) -> Option { - debug!("Trying to access \"{}\"", name); - let abs_path = std::env::current_dir().expect("No current directory?"); - // TODO: don't do this? - // if it's stupid and it works.., - let platform_specific = "".to_string(); - #[cfg(target_os = "linux")] - { - let platform_specific = "/usr/share/veloren/assets".to_string(); +fn assets_folder() -> PathBuf { + match std::env::current_exe() { + Ok(mut exe_path) => { + exe_path.pop(); + find_folder::Search::Parents(2) + .of(exe_path) + .for_folder("assets") + } + Err(_) => find_folder::Search::Parents(2).for_folder("assets"), } - [ - std::env::var("VELOREN_ASSETS").unwrap_or("".to_owned()), - "assets".to_string(), - "../assets".to_string(), /* optimizations */ - "../../assets".to_string(), - [env!("CARGO_MANIFEST_DIR"), "/../assets"].concat(), - [env!("CARGO_MANIFEST_DIR"), "/assets"].concat(), - [env!("CARGO_MANIFEST_DIR"), "/../../assets"].concat(), - "../../../assets".to_string(), - [env!("CARGO_MANIFEST_DIR"), "/../../../assets"].concat(), - platform_specific, - ] - .into_iter() - .map(|bp| { - let mut p = abs_path.clone(); - p.push(bp); - p.push(name); - p - }) - .find_map(|ref filename| File::open(filename).ok()) + .expect("Could not find assets folder") } +// TODO: System to load file from specifiers (e.g.: "core.ui.backgrounds.city"). pub fn load_from_path(name: &str) -> Result, Error> { - match try_open_with_path(name) { - Some(f) => Ok(BufReader::new(f)), - None => Err(Error::NotFound(name.to_owned())), + debug!("Trying to access \"{}\"", name); + + let mut path = assets_folder(); + path.push(name); + + match File::open(path) { + Ok(file) => Ok(BufReader::new(file)), + Err(_) => Err(Error::NotFound(name.to_owned())), + } +} + +/// Read directory from `veloren/assets/*` +pub fn read_from_assets(dir_name: &str) -> Result { + let mut entry = assets_folder(); + entry.push("../assets/"); + entry.push(dir_name); + match Path::new(&entry).exists() { + true => Ok(read_dir(entry).expect("`read_dir` failed.")), + false => Err(Error::NotFound(entry.to_str().unwrap().to_owned())), + } +} + +/// Returns the cargo manifest directory when running the executable with cargo +/// or the directory in which the executable resides otherwise, +/// traversing symlinks if necessary. +pub fn application_root_dir() -> String { + match env::var("PROFILE") { + Ok(_) => String::from(env!("CARGO_MANIFEST_DIR")), + Err(_) => { + let mut path = env::current_exe().expect("Failed to find executable path."); + while let Ok(target) = read_link(path.clone()) { + path = target; + } + String::from( + path.parent() + .expect("Failed to get parent directory of the executable.") + .to_str() + .unwrap(), + ) + } } } diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index d98b06017e..412322ccc3 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -27,9 +27,6 @@ conrod_core = { git = "https://gitlab.com/veloren/conrod.git" } conrod_winit = { git = "https://gitlab.com/veloren/conrod.git" } euc = "0.2" -# Audio -rodio = { git = "https://github.com/desttinghim/rodio.git", rev = "dd93f905c1afefaac03c496a666ecab27d3e391b" } - # ECS specs = "0.14" @@ -56,3 +53,5 @@ num = "0.2" backtrace = "0.3" rand = "0.5" frustum_query = "0.1.2" +rodio = "^0.9" +crossbeam = "^0.7.1" diff --git a/voxygen/src/audio/base.rs b/voxygen/src/audio/base.rs new file mode 100644 index 0000000000..648f26c2ef --- /dev/null +++ b/voxygen/src/audio/base.rs @@ -0,0 +1,428 @@ +use crate::settings::{AudioSettings, Settings}; +use common::assets::{load_from_path, read_from_assets}; +use crossbeam::{ + atomic::AtomicCell, + channel::{unbounded, Sender}, + queue::SegQueue, + sync::{ShardedLock, WaitGroup}, +}; +use rodio::{Decoder, Device, Sink, SpatialSink}; +use std::sync::Arc; +use std::thread; + +trait AudioConfig { + fn set_volume(&mut self, volume: f32); + fn set_device(&mut self, name: String); +} + +trait MonoMode { + fn set_mono(tx: Sender) -> Self; +} + +trait StereoMode { + fn set_stereo(tx: Sender) -> Self; +} + +trait DebugMode { + fn set_no_audio(tx: Sender) -> Self; +} + +#[derive(Debug)] +pub enum SinkError { + SinkNotMatch, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum Genre { + Bgm, + Sfx, + None, +} + +#[derive(Debug)] +pub enum AudioPlayerMsg { + AudioPlay, + AudioStop, + AudioTime(f64), +} + +#[derive(Debug)] +pub enum Action { + Load(String), + Stop, + AdjustVolume(f32), + ChangeDevice(String), +} + +#[derive(Clone)] +struct EventLoop { + condition: Arc<(ShardedLock, WaitGroup)>, + queue: Arc>, + playing: Arc>, +} + +impl EventLoop { + fn new() -> Self { + Self { + condition: Arc::new((ShardedLock::new(false), WaitGroup::new())), + queue: Arc::new(SegQueue::new()), + playing: Arc::new(ShardedLock::new(false)), + } + } +} + +/// The `AudioPlayer` handles exactly what player does by playing audio from emitter. +pub struct AudioPlayer { + event_loop: EventLoop, + paused: AtomicCell, + tx: Sender, +} + +impl AudioPlayer { + pub(crate) fn new(genre: Genre, tx: Sender) -> Self { + match genre { + Genre::Bgm => AudioPlayer::set_mono(tx), + Genre::Sfx => unimplemented!(), + Genre::None => AudioPlayer::set_no_audio(tx), + } + } + + pub(crate) fn load(&self, path: &str) { + self.emit(Action::Load(path.to_string())); + } + + pub(crate) fn set_volume(&self, value: f32) { + self.emit(Action::AdjustVolume(value)); + } + + pub(crate) fn set_device(&self, device: &str) { + self.emit(Action::ChangeDevice(device.to_string())); + } + + pub(crate) fn pause(&mut self) { + self.paused.store(true); + self.send(AudioPlayerMsg::AudioStop); + self.set_playing(false); + } + + pub(crate) fn resume(&mut self) { + self.paused.store(false); + self.send(AudioPlayerMsg::AudioPlay); + self.set_playing(true); + } + + pub(crate) fn is_paused(&self) -> bool { + self.paused.load() + } + + pub(crate) fn stop(&mut self) { + self.paused.store(false); + self.send(AudioPlayerMsg::AudioStop); + self.emit(Action::Stop); + self.set_playing(false); + } + + fn emit(&self, action: Action) { + self.event_loop.queue.push(action); + } + + fn send(&mut self, msg: AudioPlayerMsg) { + send_msg(&mut self.tx, msg); + } + + fn set_playing(&self, playing: bool) { + *self.event_loop.playing.write().unwrap() = playing; + let &(ref lock, ref wg) = &*self.event_loop.condition; + let mut started = lock.write().unwrap(); + *started = playing; + let wg = wg.clone(); + if playing { + wg.wait(); + } + } +} + +impl MonoMode for AudioPlayer { + /// Playing audio until a receive operation appears on the other side. + fn set_mono(tx: Sender) -> Self { + let event_loop = EventLoop::new(); + + { + let mut tx = tx.clone(); + let event_loop = event_loop.clone(); + let condition = event_loop.condition.clone(); + + thread::spawn(move || { + let block = || { + let &(ref lock, ref wg) = &*condition; + let mut started = lock.write().unwrap(); + *started = false; + drop(wg); + }; + let mut playback = MonoEmitter::new(&Settings::load().audio); + loop { + if let Ok(action) = event_loop.queue.pop() { + match action { + Action::Load(path) => { + if playback.stream.empty() { + playback.play_from(&path); + send_msg(&mut tx, AudioPlayerMsg::AudioPlay); + } + } + Action::Stop => playback.stream.stop(), + Action::AdjustVolume(value) => playback.set_volume(value), + Action::ChangeDevice(device) => playback.set_device(device), + } + } else { + block(); + } + } + }); + } + + Self { + event_loop, + paused: AtomicCell::new(false), + tx, + } + } +} + +impl DebugMode for AudioPlayer { + /// Don't load `rodio` for `no-audio` feature. + fn set_no_audio(tx: Sender) -> Self { + Self { + event_loop: EventLoop::new(), + paused: AtomicCell::new(true), + tx, + } + } +} + +/// TODO: Implement treeview and modellist widgets for GUI design. +pub struct Jukebox { + genre: AtomicCell, + pub(crate) player: AudioPlayer, + pub(crate) device: AudioDevice, +} + +impl Jukebox { + pub(crate) fn new(genre: Genre) -> Self { + let (tx, _rx) = unbounded(); + Self { + genre: AtomicCell::new(genre), + player: AudioPlayer::new(genre, tx), + device: AudioDevice::new(&AudioSettings::default()), + } + } + + // TODO: The `update` function should associate with `conrod` to visualise the audio playlist + // and settings. + pub(crate) fn update(&mut self, msg: AudioPlayerMsg) { + unimplemented!() + } + + /// Display the current genre. + pub(crate) fn get_genre(&self) -> Genre { + self.genre.load() + } +} + +pub struct AudioDevice { + device: Device, + devices: Vec, +} + +impl AudioDevice { + fn new(settings: &AudioSettings) -> Self { + let device = match &settings.audio_device { + Some(dev) => rodio::output_devices() + .find(|x| &x.name() == dev) + .or_else(rodio::default_output_device) + .expect("No Audio devices found!"), + None => rodio::default_output_device().expect("No Audio devices found!"), + }; + + Self { + device, + devices: list_devices_raw(), + } + } + + /// Returns a vec of the audio devices available. + /// Does not return rodio Device struct in case our audio backend changes. + pub(crate) fn list_devices(&self) -> Vec { + self.devices.iter().map(|x| x.name()).collect() + } + + /// Caches vec of devices for later reference + pub(crate) fn update_devices(&mut self) { + self.devices = list_devices_raw() + } + + /// Returns the name of the current audio device. + /// Does not return rodio Device struct in case our audio backend changes. + pub(crate) fn get_device(&self) -> String { + self.device.name() + } +} + +struct MonoEmitter { + device: AudioDevice, + stream: Sink, +} + +struct StereoEmitter { + device: AudioDevice, + stream: SpatialSink, +} + +impl MonoEmitter { + fn new(settings: &AudioSettings) -> Self { + let device = AudioDevice::new(settings); + + let sink = Sink::new(&device.device); + sink.set_volume(settings.master_volume); + + Self { + device, + stream: sink, + } + } + + fn play_from(&mut self, path: &str) { + let bufreader = load_from_path(path).unwrap(); + let src = Decoder::new(bufreader).unwrap(); + self.stream.append(src); + } +} + +impl AudioConfig for MonoEmitter { + fn set_volume(&mut self, volume: f32) { + self.stream.set_volume(volume.min(1.0).max(0.0)) + } + + /// Sets the current audio device from a string. + /// Does not use the rodio Device struct in case that detail changes. + /// If the string is an invalid audio device, then no change is made. + fn set_device(&mut self, name: String) { + if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) { + self.device.device = dev; + self.stream = Sink::new(&self.device.device); + } + } +} + +impl StereoEmitter { + fn new(settings: &AudioSettings) -> Self { + let device = AudioDevice::new(settings); + + let sink = SpatialSink::new( + &device.device, + [0.0, 0.0, 0.0], + [1.0, 0.0, 0.0], + [-1.0, 0.0, 0.0], + ); + sink.set_volume(settings.music_volume); + + Self { + device, + stream: sink, + } + } + + fn play_from(&mut self, path: &str) { + let bufreader = load_from_path(path).unwrap(); + let src = Decoder::new(bufreader).unwrap(); + self.stream.append(src); + } +} + +impl AudioConfig for StereoEmitter { + fn set_volume(&mut self, volume: f32) { + self.stream.set_volume(volume.min(1.0).max(0.0)) + } + + /// Sets the current audio device from a string. + /// Does not use the rodio Device struct in case that detail changes. + /// If the string is an invalid audio device, then no change is made. + fn set_device(&mut self, name: String) { + if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) { + self.device.device = dev; + self.stream = SpatialSink::new( + &self.device.device, + [0.0, 0.0, 0.0], + [1.0, 0.0, 0.0], + [-1.0, 0.0, 0.0], + ); + } + } +} + +/// Returns the default audio device. +/// Does not return rodio Device struct in case our audio backend changes. +pub(crate) fn get_default_device() -> String { + rodio::default_output_device() + .expect("No audio output devices detected.") + .name() +} + +/// Load the audio file directory selected by genre. +pub(crate) fn load_soundtracks(genre: &Genre) -> Vec { + match *genre { + Genre::Bgm => { + let assets = read_from_assets("voxygen/audio/soundtrack/").unwrap(); + let soundtracks = assets + .filter_map(|entry| { + entry.ok().map(|f| { + let path = f.path(); + (*path.into_os_string().to_string_lossy()).to_owned() + }) + }) + .collect::>(); + + soundtracks + } + Genre::Sfx => { + let assets = read_from_assets("voxygen/audio/soundtrack/").unwrap(); + let soundtracks = assets + //.filter_map(|entry| { + // entry.ok().and_then(|f| { + // f.path() + // .file_name() + // .and_then(|n| n.to_str().map(|s| String::from(s))) + // }) + //}) + //.collect::>(); + .filter_map(|entry| { + entry.ok().map(|f| { + let path = f.path(); + (*path.into_os_string().to_string_lossy()).to_owned() + }) + }) + .collect::>(); + + soundtracks + } + Genre::None => { + let empty_list = Vec::new(); + empty_list + } + } +} + +pub(crate) fn select_random_music(genre: &Genre) -> String { + let soundtracks = load_soundtracks(genre); + let index = rand::random::() % soundtracks.len(); + soundtracks[index].clone() +} + +fn send_msg(tx: &mut Sender, msg: AudioPlayerMsg) { + tx.try_send(msg) + .expect("Failed on attempting to send a message into audio channel."); +} + +/// Returns vec of devices +fn list_devices_raw() -> Vec { + rodio::output_devices().collect() +} diff --git a/voxygen/src/audio/mod.rs b/voxygen/src/audio/mod.rs index 1f08520e90..f6a8b2fe36 100644 --- a/voxygen/src/audio/mod.rs +++ b/voxygen/src/audio/mod.rs @@ -1,139 +1,35 @@ -use crate::settings::AudioSettings; -use common::assets; -use log::error; -use rodio::{Decoder, Device, SpatialSink}; -use std::iter::Iterator; -use std::panic::catch_unwind; +pub mod base; +use base::{Genre, Jukebox}; pub struct AudioFrontend { - device: Device, - // Performance optimisation, iterating through available audio devices takes time - devices: Vec, - // streams: HashMap, //always use SpatialSink even if no position is used for now - stream: Option, + pub(crate) model: Jukebox, } impl AudioFrontend { - pub fn new(settings: &AudioSettings) -> Self { - let device = match &settings.audio_device { - Some(dev) => rodio::output_devices() - .find(|x| &x.name() == dev) - .or_else(rodio::default_output_device) - .expect("No Audio devices found"), - None => rodio::default_output_device().expect("No audio devices found"), - }; - - let sink = catch_unwind(|| { - let sink = rodio::SpatialSink::new( - &device, - [0.0, 0.0, 0.0], - [1.0, 0.0, 0.0], - [-1.0, 0.0, 0.0], - ); - sink.set_volume(settings.music_volume); - Some(sink) - }) - .unwrap_or_else(|e| { - error!("Error creating a SpatialSink (audio): "); - None - }); - - AudioFrontend { - device, - // streams: HashMap::::new(), - stream: sink, - devices: AudioFrontend::list_devices_raw(), + pub(crate) fn new() -> Self { + Self { + model: Jukebox::new(Genre::Bgm), } } - pub fn play_music(&mut self, path: &str) { - let bufreader = assets::load_from_path(path).unwrap(); - let src = Decoder::new(bufreader).unwrap(); + /// Play audio. + pub(crate) fn play(&mut self) { + let path = base::select_random_music(&Genre::Bgm); - // TODO: stop previous audio from playing. Sink has this ability, but - // SpatialSink does not for some reason. This means that we will - // probably want to use sinks for music, and SpatialSink for sfx. - if let Some(s) = &self.stream { - s.append(src); + match self.model.player.is_paused() { + true => match self.model.get_genre() { + Genre::Bgm => self.model.player.resume(), + Genre::Sfx => unimplemented!(), // TODO: add support for sound effects. + Genre::None => (), + }, + false => self.model.player.load(&path), } } - pub fn maintain(&mut self) { - let music = [ - "voxygen/audio/soundtrack/Ethereal_Bonds.ogg", - "voxygen/audio/soundtrack/field_grazing.ogg", - "voxygen/audio/soundtrack/fiesta_del_pueblo.ogg", - "voxygen/audio/soundtrack/library_theme_with_harpsichord.ogg", - "voxygen/audio/soundtrack/Mineral_Deposits.ogg", - //"voxygen/audio/soundtrack/Ruination.ogg", - "voxygen/audio/soundtrack/sacred_temple.ogg", - "voxygen/audio/soundtrack/Snowtop_volume.ogg", - "voxygen/audio/soundtrack/veloren_title_tune-3.ogg", - ]; - - if let Some(s) = &self.stream { - if s.empty() { - let i = rand::random::() % music.len(); - self.play_music(music[i]); - } - } - } - - pub fn set_volume(&mut self, volume: f32) { - if let Some(s) = &self.stream { - s.set_volume(volume.min(1.0).max(0.0)); - } - } - - /// Returns a vec of the audio devices available. - /// Does not return rodio Device struct in case our audio backend changes. - pub fn list_device_names(&self) -> Vec { - self.devices.iter().map(|x| x.name()).collect() - } - - /// Returns vec of devices - fn list_devices_raw() -> Vec { - rodio::output_devices().collect() - } - - /// Caches vec of devices for later reference - fn maintain_devices(&mut self) { - self.devices = AudioFrontend::list_devices_raw() - } - - /// Returns the default audio device. - /// Does not return rodio Device struct in case our audio backend changes. - pub fn get_default_device() -> String { - rodio::default_output_device() - .expect("No audio output devices detected.") - .name() - } - - /// Returns the name of the current audio device. - /// Does not return rodio Device struct in case our audio backend changes. - pub fn get_device_name(&self) -> String { - self.device.name() - } - - /// Sets the current audio device from a string. - /// Does not use the rodio Device struct in case that detail changes. - /// If the string is an invalid audio device, then no change is made. - pub fn set_device(&mut self, name: String) { - if let Some(dev) = rodio::output_devices().find(|x| x.name() == name) { - self.device = dev; - self.stream = catch_unwind(|| { - let sink = rodio::SpatialSink::new( - &self.device, - [0.0, 0.0, 0.0], - [1.0, 0.0, 0.0], - [-1.0, 0.0, 0.0], - ); - Some(sink) - }) - .unwrap_or_else(|e| { - error!("Error creating a SpatialSink (audio): "); - None - }); + /// Construct in `no-audio` mode for debugging. + pub(crate) fn no_audio() -> Self { + Self { + model: Jukebox::new(Genre::None), } } } diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index 1f7083e04f..cfdc088c13 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -707,8 +707,8 @@ impl<'a> Widget for SettingsWindow<'a> { } // Audio Device Selector -------------------------------------------- - let device = self.global_state.audio.get_device_name(); - let device_list = self.global_state.audio.list_device_names(); + let device = self.global_state.audio.model.device.get_device(); + let device_list = self.global_state.audio.model.device.list_devices(); Text::new("Volume") .down_from(state.ids.audio_volume_slider, 10.0) .font_size(14) diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 8691113e45..8706ee88d4 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -42,7 +42,8 @@ impl GlobalState { } pub fn maintain(&mut self) { - self.audio.maintain(); + // TODO: Maintain both `Bgm` and `Sfx` audio threads. + self.audio.play(); } } @@ -79,7 +80,7 @@ fn main() { // Set up the global state. let settings = Settings::load(); let mut global_state = GlobalState { - audio: AudioFrontend::new(&settings.audio), + audio: AudioFrontend::new(), // TODO: Provide `AudioFrontend::no_audio()` feature during initialisation, the config will be stored in `ron` object list. window: Window::new(&settings).expect("Failed to create window!"), settings, }; @@ -162,7 +163,7 @@ fn main() { })); if global_state.settings.audio.audio_device == None { - global_state.settings.audio.audio_device = Some(AudioFrontend::get_default_device()); + global_state.settings.audio.audio_device = Some(crate::audio::base::get_default_device()); } // Set up the initial play state. diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 7e1b73e106..e26b4cf4c4 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -215,7 +215,7 @@ impl PlayState for SessionState { } } HudEvent::AdjustVolume(volume) => { - global_state.audio.set_volume(volume); + global_state.audio.model.player.set_volume(volume); global_state.settings.audio.music_volume = volume; if let Err(err) = global_state.settings.save_to_file() { @@ -223,7 +223,7 @@ impl PlayState for SessionState { } } HudEvent::ChangeAudioDevice(name) => { - global_state.audio.set_device(name.clone()); + global_state.audio.model.player.set_device(&name.clone()); global_state.settings.audio.audio_device = Some(name); if let Err(err) = global_state.settings.save_to_file() { diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 37a61c2140..01ab21fa8c 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -138,6 +138,7 @@ impl Default for GraphicsSettings { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(default)] pub struct AudioSettings { + pub master_volume: f32, pub music_volume: f32, pub sfx_volume: f32, @@ -148,6 +149,7 @@ pub struct AudioSettings { impl Default for AudioSettings { fn default() -> Self { Self { + master_volume: 1.0, music_volume: 0.5, sfx_volume: 0.5, audio_device: None,