Merge branch 'desttinghim/sound-effects' into 'master'

Sound Effects

Closes #163 and #97

See merge request veloren/veloren!473
This commit is contained in:
Joshua Barretto 2019-09-06 11:19:32 +00:00
commit 8ef13f72b7
36 changed files with 692 additions and 557 deletions

106
Cargo.lock generated
View File

@ -21,10 +21,21 @@ dependencies = [
"memchr 2.2.1 (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.62 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
@ -311,16 +322,6 @@ dependencies = [
"libc 0.2.62 (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 = "chashmap"
version = "2.2.2"
@ -378,7 +379,7 @@ dependencies = [
[[package]]
name = "claxon"
version = "0.3.3"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -535,9 +536,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.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1023,6 +1024,14 @@ dependencies = [
"pkg-config 0.3.15 (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.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getrandom"
version = "0.1.11"
@ -1512,6 +1521,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"
@ -1596,6 +1610,14 @@ dependencies = [
"libc 0.2.62 (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 = "maybe-uninit"
version = "2.0.0"
@ -1722,6 +1744,22 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nalgebra"
version = "0.18.1"
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-rational 0.2.2 (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.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.33"
@ -2439,6 +2477,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"
@ -2524,16 +2567,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[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.4.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.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -3000,6 +3043,11 @@ name = "tuple_utils"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "typenum"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ucd-util"
version = "0.1.5"
@ -3181,7 +3229,7 @@ dependencies = [
"parking_lot 0.9.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.7.0 (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.99 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3419,7 +3467,8 @@ dependencies = [
"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.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum alsa-sys 0.1.1 (git+https://github.com/desttinghim/cpal?rev=e7c086d0afc368a888ad133c3b1d928b16986130)" = "<none>"
"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"
@ -3455,13 +3504,12 @@ dependencies = [
"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 chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45"
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
"checksum clang-sys 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "611ec2e3a7623afd8a8c0d027887b6b55759d894abbf5fe11b9dc11b50d5b49a"
"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 cmake 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "3c84c596dcf125d6781f58e3f4254677ec2a6d8aa56e8501ac277100990b3229"
"checksum cocoa 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0c23085dde1ef4429df6e5896b89356d35cdd321fb43afe3e378d010bb5adc6"
@ -3479,7 +3527,7 @@ dependencies = [
"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)" = "<none>"
"checksum cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58ae1ed6536b1b233f5e3aeb6997a046ddb4d05e3f61701b58a92eb254a829e"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650"
"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
@ -3532,6 +3580,7 @@ dependencies = [
"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 getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872"
"checksum gfx 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "619e38a31e275efaf92c6a94f977db8aac396e3cb6998c176cfde32ce3239b69"
"checksum gfx_core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e1127b02a9d4fcc880091d8a0f4419efd598de4f1649edcd005c76e5792176f"
@ -3583,6 +3632,7 @@ dependencies = [
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9"
"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
"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"
@ -3594,6 +3644,7 @@ dependencies = [
"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 maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
@ -3608,6 +3659,7 @@ dependencies = [
"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)" = "<none>"
"checksum nalgebra 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2"
"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"
@ -3685,6 +3737,7 @@ dependencies = [
"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"
@ -3694,7 +3747,7 @@ dependencies = [
"checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
"checksum rodio 0.8.1 (git+https://github.com/desttinghim/rodio.git?rev=dd93f905c1afefaac03c496a666ecab27d3e391b)" = "<none>"
"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 rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
@ -3749,6 +3802,7 @@ dependencies = [
"checksum tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b7c2cfc4742bd8a32f2e614339dd8ce30dbcf676bb262bd63a2327bc5df57d"
"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.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -54,7 +54,7 @@ num = "0.2.0"
backtrace = "0.3.33"
rand = "0.7.0"
frustum_query = "0.1.2"
rodio = { git = "https://github.com/desttinghim/rodio.git", rev = "dd93f905c1afefaac03c496a666ecab27d3e391b" }
rodio = "0.9.0"
crossbeam = "0.7.2"
heaptrack = "0.3.0"
hashbrown = { version = "0.5.0", features = ["serde", "nightly"] }

View File

@ -1,424 +0,0 @@
use crate::settings::{AudioSettings, Settings};
use common::assets::read_dir;
use crossbeam::{
atomic::AtomicCell,
channel::{unbounded, Sender},
queue::SegQueue,
sync::ShardedLock,
};
use parking_lot::{Condvar, Mutex};
use rodio::{Decoder, Device, Sink};
use std::fs::File;
use std::io::BufReader;
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<AudioPlayerMsg>) -> Self;
}
trait StereoMode {
fn set_stereo(tx: Sender<AudioPlayerMsg>) -> Self;
}
trait DebugMode {
fn set_no_audio(tx: Sender<AudioPlayerMsg>) -> 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 {
condvar: Arc<(Mutex<bool>, Condvar)>,
queue: Arc<SegQueue<Action>>,
playing: Arc<ShardedLock<bool>>,
}
impl EventLoop {
fn new() -> Self {
Self {
condvar: Arc::new((Mutex::new(false), Condvar::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<bool>,
tx: Sender<AudioPlayerMsg>,
}
impl AudioPlayer {
pub(crate) fn new(genre: Genre, tx: Sender<AudioPlayerMsg>) -> 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()));
self.set_playing(true);
}
// 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 stop(&mut self) {
// self.paused.store(false);
// self.send(AudioPlayerMsg::AudioStop);
// self.emit(Action::Stop);
// self.set_playing(false);
// }
pub(crate) fn is_paused(&self) -> bool {
self.paused.load()
}
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()));
}
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 condvar) = &*self.event_loop.condvar;
let mut started = lock.lock();
*started = playing;
if playing {
condvar.notify_one();
}
}
}
impl MonoMode for AudioPlayer {
/// Playing audio until a receive operation appears on the other side.
fn set_mono(tx: Sender<AudioPlayerMsg>) -> Self {
let event_loop = EventLoop::new();
{
//let mut tx = tx.clone();
let event_loop = event_loop.clone();
let condition = event_loop.condvar.clone();
thread::spawn(move || {
let block = || {
let (ref lock, ref condvar) = *condition;
let mut started = lock.lock();
*started = false;
while !*started {
condvar.wait(&mut started);
}
};
let mut playback = MonoEmitter::new(&Settings::load().audio);
// Start the thread if set_playing(true).
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<AudioPlayerMsg>) -> 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<Genre>,
pub(crate) player: AudioPlayer,
}
impl Jukebox {
pub(crate) fn new(genre: Genre) -> Self {
let (tx, _rx) = unbounded();
Self {
genre: AtomicCell::new(genre),
player: AudioPlayer::new(genre, tx),
}
}
// 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()
}
}
struct MonoEmitter {
device: Device,
stream: Sink,
}
// struct StereoEmitter {
// device: Device,
// stream: SpatialSink,
// }
impl MonoEmitter {
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 = Sink::new(&device);
sink.set_volume(settings.music_volume);
Self {
device,
stream: sink,
}
}
// /// Returns the name of the current audio device.
// /// Does not return rodio Device struct in case our audio backend changes.
// fn get_device(&self) -> String {
// self.device.name()
// }
fn play_from(&mut self, path: &str) {
let bufreader = BufReader::new(File::open(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 = dev;
self.stream = Sink::new(&self.device);
}
}
}
// impl StereoEmitter {
// 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 = 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 = dev;
// self.stream = SpatialSink::new(
// &self.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<String> {
match *genre {
Genre::Bgm => {
let assets = read_dir("voxygen.audio.soundtrack").unwrap();
let soundtracks = assets
.filter_map(|entry| {
entry.ok().map(|f| {
let path = f.path();
path.to_string_lossy().into_owned()
})
})
.collect::<Vec<String>>();
soundtracks
}
Genre::Sfx => {
let assets = read_dir("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::<Vec<String>>();
.filter_map(|entry| {
entry.ok().map(|f| {
let path = f.path();
(*path.into_os_string().to_string_lossy()).to_owned()
})
})
.collect::<Vec<String>>();
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::<usize>() % soundtracks.len();
soundtracks[index].clone()
}
/// 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() -> Vec<String> {
list_devices_raw().iter().map(|x| x.name()).collect()
}
/// Returns vec of devices
fn list_devices_raw() -> Vec<Device> {
rodio::output_devices().collect()
}
fn send_msg(tx: &mut Sender<AudioPlayerMsg>, msg: AudioPlayerMsg) {
tx.send(msg)
.expect("Failed on attempting to send a message into audio channel.");
}
#[test]
fn test_load_soundtracks() {
use crate::audio::base::{load_soundtracks, Genre};
for entry in load_soundtracks(&Genre::Bgm).iter() {
println!("{}", entry)
}
}

View File

@ -0,0 +1,137 @@
use crate::audio::fader::Fader;
use rodio::{Decoder, Device, Sample, Source, SpatialSink};
use std::fs::File;
use std::io::BufReader;
use vek::*;
#[derive(PartialEq, Clone, Copy)]
pub enum AudioType {
Sfx,
Music,
None,
}
#[derive(PartialEq, Clone, Copy)]
enum ChannelState {
// Init,
// ToPlay,
// Loading,
Playing,
Stopping,
Stopped,
}
pub struct Channel {
id: usize,
sink: SpatialSink,
audio_type: AudioType,
state: ChannelState,
fader: Fader,
pub pos: Vec3<f32>,
}
// TODO: Implement asynchronous loading
impl Channel {
/// Create an empty channel for future use
pub fn new(device: &Device) -> Self {
Self {
id: 0,
sink: SpatialSink::new(device, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]),
audio_type: AudioType::None,
state: ChannelState::Stopped,
fader: Fader::fade_in(0.0),
pos: Vec3::zero(),
}
}
pub fn music(id: usize, device: &Device, bufr: BufReader<File>) -> Self {
let sink = SpatialSink::new(device, [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [-1.0, 0.0, 0.0]);
let sound = Decoder::new(bufr).unwrap();
sink.append(sound);
Self {
id,
sink,
audio_type: AudioType::Music,
state: ChannelState::Playing,
fader: Fader::fade_in(0.0),
pos: Vec3::zero(),
}
}
pub fn sfx(id: usize, sink: SpatialSink, pos: Vec3<f32>) -> Self {
Self {
id,
sink,
audio_type: AudioType::Sfx,
state: ChannelState::Playing,
fader: Fader::fade_in(0.0),
pos,
}
}
pub fn play<S>(&mut self, source: S)
where
S: Source + Send + 'static,
S::Item: Sample,
S::Item: Send,
<S as std::iter::Iterator>::Item: std::fmt::Debug,
{
self.state = ChannelState::Playing;
self.sink.append(source);
}
pub fn is_done(&self) -> bool {
self.sink.empty() || self.state == ChannelState::Stopped
}
pub fn stop(&mut self, fader: Fader) {
self.state = ChannelState::Stopping;
self.fader = fader;
}
pub fn get_id(&self) -> usize {
self.id
}
pub fn set_id(&mut self, new_id: usize) {
self.id = new_id;
}
pub fn get_audio_type(&self) -> AudioType {
self.audio_type
}
pub fn set_volume(&mut self, volume: f32) {
self.sink.set_volume(volume);
}
pub fn set_emitter_position(&mut self, pos: [f32; 3]) {
self.sink.set_emitter_position(pos);
}
pub fn set_left_ear_position(&mut self, pos: [f32; 3]) {
self.sink.set_left_ear_position(pos);
}
pub fn set_right_ear_position(&mut self, pos: [f32; 3]) {
self.sink.set_right_ear_position(pos);
}
pub fn update(&mut self, dt: f32) {
match self.state {
// ChannelState::Init | ChannelState::ToPlay | ChannelState::Loading => {}
ChannelState::Playing => {}
ChannelState::Stopping => {
self.fader.update(dt);
self.sink.set_volume(self.fader.get_volume());
if self.fader.is_finished() {
self.state = ChannelState::Stopped;
}
}
ChannelState::Stopped => {}
}
}
}

View File

@ -0,0 +1,66 @@
#[derive(PartialEq, Clone, Copy)]
pub struct Fader {
length: f32,
running_time: f32,
volume_from: f32,
volume_to: f32,
is_running: bool,
}
fn lerp(t: f32, a: f32, b: f32) -> f32 {
(1.0 - t) * a + t * b
}
impl Fader {
pub fn fade(time: f32, volume_from: f32, volume_to: f32) -> Self {
Self {
length: time,
running_time: 0.0,
volume_from,
volume_to,
is_running: true,
}
}
pub fn fade_in(time: f32) -> Self {
Self {
length: time,
running_time: 0.0,
volume_from: 0.0,
volume_to: 1.0,
is_running: true,
}
}
pub fn fade_out(time: f32) -> Self {
Self {
length: time,
running_time: 0.0,
volume_from: 1.0,
volume_to: 0.0,
is_running: true,
}
}
pub fn update(&mut self, dt: f32) {
if self.is_running {
self.running_time = self.running_time + dt;
if self.running_time >= self.length {
self.running_time = self.length;
self.is_running = false;
}
}
}
pub fn get_volume(&self) -> f32 {
lerp(
self.running_time / self.length,
self.volume_from,
self.volume_to,
)
}
pub fn is_finished(&self) -> bool {
self.running_time >= self.length || !self.is_running
}
}

View File

@ -1,41 +1,242 @@
pub mod base;
use base::{Genre, Jukebox};
pub mod channel;
pub mod fader;
pub mod soundcache;
use channel::{AudioType, Channel};
use fader::Fader;
use soundcache::SoundCache;
use common::assets;
use rodio::{Decoder, Device};
use vek::*;
const FALLOFF: f32 = 0.13;
pub struct AudioFrontend {
pub(crate) model: Jukebox,
pub(crate) default_device: String,
pub(crate) device_list: Vec<String>,
pub device: String,
pub device_list: Vec<String>,
audio_device: Option<Device>,
sound_cache: SoundCache,
channels: Vec<Channel>,
next_channel_id: usize,
sfx_volume: f32,
music_volume: f32,
listener_pos: Vec3<f32>,
listener_ori: Vec3<f32>,
listener_ear_left: Vec3<f32>,
listener_ear_right: Vec3<f32>,
}
impl AudioFrontend {
pub(crate) fn new() -> Self {
/// Construct with given device
pub fn new(device: String, channel_num: usize) -> Self {
let mut channels = Vec::with_capacity(channel_num);
let audio_device = get_device_raw(&device);
if let Some(audio_device) = &audio_device {
for _i in 0..channel_num {
channels.push(Channel::new(&audio_device));
}
}
Self {
model: Jukebox::new(Genre::Bgm),
default_device: base::get_default_device(),
device_list: base::list_devices(),
device: device.clone(),
device_list: list_devices(),
audio_device,
sound_cache: SoundCache::new(),
channels: channels,
next_channel_id: 1,
sfx_volume: 1.0,
music_volume: 1.0,
listener_pos: Vec3::zero(),
listener_ori: Vec3::zero(),
listener_ear_left: Vec3::zero(),
listener_ear_right: Vec3::zero(),
}
}
/// Play audio.
pub(crate) fn play(&mut self) {
let path = base::select_random_music(&Genre::Bgm);
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),
/// Construct in `no-audio` mode for debugging
pub fn no_audio() -> Self {
Self {
device: "none".to_string(),
device_list: list_devices(),
audio_device: None,
sound_cache: SoundCache::new(),
channels: Vec::new(),
next_channel_id: 1,
sfx_volume: 1.0,
music_volume: 1.0,
listener_pos: Vec3::zero(),
listener_ori: Vec3::zero(),
listener_ear_left: Vec3::zero(),
listener_ear_right: Vec3::zero(),
}
}
/// Construct in `no-audio` mode for debugging.
pub(crate) fn no_audio() -> Self {
Self {
model: Jukebox::new(Genre::None),
default_device: "None".to_owned(),
device_list: Vec::new(),
/// Maintain audio
pub fn maintain(&mut self, dt: f32) {
for channel in self.channels.iter_mut() {
channel.update(dt);
}
}
pub fn get_channel(&mut self) -> Option<&mut Channel> {
self.channels.iter_mut().find(|c| c.is_done())
}
/// Play specfied sound file.
///```ignore
///audio.play_sound("voxygen.audio.sfx.step");
///```
pub fn play_sound(&mut self, sound: &str, pos: Vec3<f32>) -> usize {
let id = self.next_channel_id;
self.next_channel_id += 1;
if let Some(_) = &self.audio_device {
let calc_pos = ((pos - self.listener_pos) * FALLOFF).into_array();
let sound = self.sound_cache.load_sound(sound);
let left_ear = self.listener_ear_left.into_array();
let right_ear = self.listener_ear_right.into_array();
if let Some(channel) = self.get_channel() {
channel.set_id(id);
channel.set_emitter_position(calc_pos);
channel.set_left_ear_position(left_ear);
channel.set_right_ear_position(right_ear);
channel.play(sound);
} else {
log::warn!("No available channels!");
}
}
id
}
pub fn set_listener_pos(&mut self, pos: &Vec3<f32>, ori: &Vec3<f32>) {
self.listener_pos = pos.clone();
self.listener_ori = ori.normalized();
let up = Vec3::new(0.0, 0.0, 1.0);
let pos_left = up.cross(self.listener_ori.clone()).normalized();
let pos_right = self.listener_ori.cross(up.clone()).normalized();
self.listener_ear_left = pos_left;
self.listener_ear_right = pos_right;
for channel in self.channels.iter_mut() {
if channel.get_audio_type() == AudioType::Sfx {
channel.set_emitter_position(
((channel.pos - self.listener_pos) * FALLOFF).into_array(),
);
channel.set_left_ear_position(pos_left.into_array());
channel.set_right_ear_position(pos_right.into_array());
}
}
}
pub fn play_music(&mut self, sound: &str) -> usize {
let id = self.next_channel_id;
self.next_channel_id += 1;
if let Some(_) = &self.audio_device {
let file = assets::load_file(&sound, &["ogg"]).unwrap();
let sound = Decoder::new(file).unwrap();
if let Some(channel) = self.get_channel() {
channel.set_id(id);
channel.play(sound);
}
}
id
}
pub fn stop_channel(&mut self, channel_id: usize, fader: Fader) {
let index = self.channels.iter().position(|c| c.get_id() == channel_id);
if let Some(index) = index {
self.channels[index].stop(fader);
}
}
pub fn get_sfx_volume(&self) -> f32 {
self.sfx_volume
}
pub fn get_music_volume(&self) -> f32 {
self.music_volume
}
pub fn set_sfx_volume(&mut self, volume: f32) {
self.sfx_volume = volume;
for channel in self.channels.iter_mut() {
if channel.get_audio_type() == AudioType::Sfx {
channel.set_volume(volume);
}
}
}
pub fn set_music_volume(&mut self, volume: f32) {
self.music_volume = volume;
for channel in self.channels.iter_mut() {
if channel.get_audio_type() == AudioType::Music {
channel.set_volume(volume);
}
}
}
// TODO: figure out how badly this will break things when it is called
pub fn set_device(&mut self, name: String) {
self.device = name.clone();
self.audio_device = get_device_raw(&name);
}
}
pub fn select_random_music() -> String {
let soundtracks = load_soundtracks();
let index = rand::random::<usize>() % soundtracks.len();
soundtracks[index].clone()
}
/// 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()
}
/// Load the audio file directory selected by genre.
pub fn load_soundtracks() -> Vec<String> {
let assets = assets::read_dir("voxygen.audio.soundtrack").unwrap();
let soundtracks = assets
.filter_map(|entry| {
entry.ok().map(|f| {
let path = f.path();
path.to_string_lossy().into_owned()
})
})
.collect::<Vec<String>>();
soundtracks
}
/// Returns a vec of the audio devices available.
/// Does not return rodio Device struct in case our audio backend changes.
pub fn list_devices() -> Vec<String> {
list_devices_raw().iter().map(|x| x.name()).collect()
}
/// Returns vec of devices
fn list_devices_raw() -> Vec<Device> {
rodio::output_devices().collect()
}
fn get_device_raw(device: &str) -> Option<Device> {
rodio::output_devices().find(|d| d.name() == device)
}

View File

@ -0,0 +1,53 @@
use common::assets;
use hashbrown::HashMap;
use rodio;
use std::convert::AsRef;
use std::io;
use std::io::Read;
use std::sync::Arc;
// Implementation of sound taken from this github issue:
// https://github.com/RustAudio/rodio/issues/141
pub struct Sound(Arc<Vec<u8>>);
impl AsRef<[u8]> for Sound {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Sound {
pub fn load(filename: &str) -> Result<Sound, assets::Error> {
let mut file = assets::load_file(filename, &["wav"])?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
Ok(Sound(Arc::new(buf)))
}
pub fn cursor(&self) -> io::Cursor<Sound> {
io::Cursor::new(Sound(self.0.clone()))
}
pub fn decoder(&self) -> rodio::Decoder<io::Cursor<Sound>> {
rodio::Decoder::new(self.cursor()).unwrap()
}
}
pub struct SoundCache {
sounds: HashMap<String, Sound>,
}
impl SoundCache {
pub fn new() -> Self {
Self {
sounds: HashMap::new(),
}
}
pub fn load_sound(&mut self, name: &str) -> rodio::Decoder<io::Cursor<Sound>> {
self.sounds
.entry(name.to_string())
.or_insert(Sound::load(name).unwrap())
.decoder()
}
}

View File

@ -2,7 +2,6 @@ use super::{
img_ids::Imgs, BarNumbers, CrosshairType, Fonts, ShortcutNumbers, Show, XpBar, TEXT_COLOR,
};
use crate::{
audio::base::Genre,
ui::{ImageSlider, ScaleMode, ToggleButton},
GlobalState,
};
@ -1251,39 +1250,26 @@ impl<'a> Widget for SettingsWindow<'a> {
}
// Audio Device Selector --------------------------------------------
match self.global_state.audio.model.get_genre() {
Genre::Bgm => {
let device = &self.global_state.audio.default_device;
let device_list = &self.global_state.audio.device_list;
Text::new("Volume")
.down_from(state.ids.audio_volume_slider, 10.0)
.font_size(14)
.font_id(self.fonts.opensans)
.color(TEXT_COLOR)
.set(state.ids.audio_device_text, ui);
let device = &self.global_state.audio.device;
let device_list = &self.global_state.audio.device_list;
Text::new("Volume")
.down_from(state.ids.audio_volume_slider, 10.0)
.font_size(14)
.font_id(self.fonts.opensans)
.color(TEXT_COLOR)
.set(state.ids.audio_device_text, ui);
// Get which device is currently selected
let selected = device_list.iter().position(|x| x.contains(device));
// Get which device is currently selected
let selected = device_list.iter().position(|x| x.contains(device));
if let Some(clicked) = DropDownList::new(&device_list, selected)
.w_h(400.0, 22.0)
.down_from(state.ids.audio_device_text, 10.0)
.label_font_id(self.fonts.opensans)
.set(state.ids.audio_device_list, ui)
{
let new_val = device_list[clicked].clone();
events.push(Event::ChangeAudioDevice(new_val));
}
}
Genre::Sfx => unimplemented!(),
Genre::None => {
Text::new("Volume")
.down_from(state.ids.audio_volume_slider, 10.0)
.font_size(14)
.font_id(self.fonts.opensans)
.color(TEXT_COLOR)
.set(state.ids.audio_device_text, ui);
}
if let Some(clicked) = DropDownList::new(&device_list, selected)
.w_h(400.0, 22.0)
.down_from(state.ids.audio_device_text, 10.0)
.label_font_id(self.fonts.opensans)
.set(state.ids.audio_device_list, ui)
{
let new_val = device_list[clicked].clone();
events.push(Event::ChangeAudioDevice(new_val));
}
}

View File

@ -31,10 +31,7 @@ pub mod window;
// Reexports
pub use crate::error::Error;
use crate::{
audio::base::Genre, audio::AudioFrontend, menu::main::MainMenuState, settings::Settings,
window::Window,
};
use crate::{audio::AudioFrontend, menu::main::MainMenuState, settings::Settings, window::Window};
use heaptrack::track_mem;
use log::{self, debug, error, info};
@ -58,9 +55,8 @@ impl GlobalState {
self.window.needs_refresh_resize();
}
pub fn maintain(&mut self) {
// TODO: Maintain both `Bgm` and `Sfx` audio threads.
self.audio.play();
pub fn maintain(&mut self, dt: f32) {
self.audio.maintain(dt);
}
}
@ -108,6 +104,22 @@ fn main() {
if let Err(err) = settings.save_to_file() {
panic!("Failed to save settings: {:?}", err);
}
let audio_device = match &settings.audio.audio_device {
Some(d) => d.to_string(),
None => audio::get_default_device(),
};
let audio = if settings.audio.audio_on {
AudioFrontend::new(audio_device, 16)
} else {
AudioFrontend::no_audio()
};
let mut global_state = GlobalState {
audio,
window: Window::new(&settings).expect("Failed to create window!"),
settings,
};
let settings = &global_state.settings;
// Initialize logging.
let term_log_level = std::env::var_os("VOXYGEN_LOG")
@ -186,39 +198,6 @@ fn main() {
default_hook(panic_info);
}));
// Set up the global state.
let audio = if settings.audio.audio_on {
AudioFrontend::new()
} else {
AudioFrontend::no_audio()
};
let mut global_state = GlobalState {
audio,
window: Window::new(&settings).expect("Failed to create window!"),
settings,
};
// Initialize discord. (lazy_static initalise lazily...)
#[cfg(feature = "discord")]
{
match DISCORD_INSTANCE.lock() {
Ok(_disc) => {
//great
}
Err(e) => log::error!("Couldn't init discord: {}", e),
}
}
match global_state.audio.model.get_genre() {
Genre::Bgm => {
global_state.settings.audio.audio_device =
Some(crate::audio::base::get_default_device())
}
Genre::Sfx => unimplemented!(),
Genre::None => global_state.settings.audio.audio_device = None,
}
// Set up the initial play state.
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
states

View File

@ -78,7 +78,7 @@ impl PlayState for CharSelectionState {
}
// Maintain global state.
global_state.maintain();
global_state.maintain(clock.get_last_delta().as_secs_f32());
// Maintain the scene.
self.scene.maintain(

View File

@ -76,7 +76,7 @@ impl PlayState for MainMenuState {
}
// Maintain global_state
global_state.maintain();
global_state.maintain(clock.get_last_delta().as_secs_f32());
// Maintain the UI.
for event in self.main_menu_ui.maintain(global_state) {

View File

@ -1,13 +1,16 @@
pub mod camera;
pub mod figure;
pub mod sound;
pub mod terrain;
use self::{
camera::{Camera, CameraMode},
figure::FigureMgr,
sound::SoundMgr,
terrain::Terrain,
};
use crate::{
audio::AudioFrontend,
render::{
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
PostProcessPipeline, Renderer, SkyboxLocals, SkyboxPipeline,
@ -46,6 +49,7 @@ pub struct Scene {
loaded_distance: f32,
figure_mgr: FigureMgr,
sound_mgr: SoundMgr,
}
impl Scene {
@ -71,6 +75,7 @@ impl Scene {
terrain: Terrain::new(renderer),
loaded_distance: 0.0,
figure_mgr: FigureMgr::new(),
sound_mgr: SoundMgr::new(),
}
}
@ -115,7 +120,12 @@ impl Scene {
}
/// Maintain data such as GPU constant buffers, models, etc. To be called once per tick.
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) {
pub fn maintain(
&mut self,
renderer: &mut Renderer,
audio: &mut AudioFrontend,
client: &Client,
) {
// Get player position.
let player_pos = client
.state()
@ -219,6 +229,9 @@ impl Scene {
// Remove unused figures.
self.figure_mgr.clean(client.get_tick());
// Maintain audio
self.sound_mgr.maintain(audio, client);
}
/// Render the scene using the provided `Renderer`.

View File

@ -0,0 +1,67 @@
use crate::audio::AudioFrontend;
use client::Client;
use common::comp::{Body, CharacterState, MovementState::*, Ori, Pos};
use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join};
use std::time::Instant;
use vek::*;
pub struct AnimState {
last_step_sound: Instant,
}
pub struct SoundMgr {
character_states: HashMap<EcsEntity, AnimState>,
}
impl SoundMgr {
pub fn new() -> Self {
Self {
character_states: HashMap::new(),
}
}
pub fn maintain(&mut self, audio: &mut AudioFrontend, client: &Client) {
let ecs = client.state().ecs();
// Get player position.
let player_pos = ecs
.read_storage::<Pos>()
.get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
let player_ori = ecs
.read_storage::<Ori>()
.get(client.entity())
.map_or(Vec3::zero(), |pos| pos.0);
audio.set_listener_pos(&player_pos, &player_ori);
for (entity, pos, body, character) in (
&ecs.entities(),
&ecs.read_storage::<Pos>(),
&ecs.read_storage::<Body>(),
ecs.read_storage::<CharacterState>().maybe(),
)
.join()
{
if let (Body::Humanoid(_), Some(character)) = (body, character) {
let state = self
.character_states
.entry(entity)
.or_insert_with(|| AnimState {
last_step_sound: Instant::now(),
});
if character.movement == Run && state.last_step_sound.elapsed().as_secs_f64() > 0.25
{
let rand_step = (rand::random::<usize>() % 7) + 1;
audio.play_sound(
&format!("voxygen.audio.footsteps.stepdirt_{}", rand_step),
pos.0,
);
state.last_step_sound = Instant::now();
}
}
}
}
}

View File

@ -271,7 +271,7 @@ impl PlayState for SessionState {
}
// Maintain global state.
global_state.maintain();
global_state.maintain(clock.get_last_delta().as_secs_f32());
// Extract HUD events ensuring the client borrow gets dropped.
let hud_events = self.hud.maintain(
@ -357,13 +357,13 @@ impl PlayState for SessionState {
}
HudEvent::AdjustVolume(volume) => {
global_state.audio.model.player.set_volume(volume);
global_state.audio.set_music_volume(volume);
global_state.settings.audio.music_volume = volume;
global_state.settings.save_to_file_warn();
}
HudEvent::ChangeAudioDevice(name) => {
global_state.audio.model.player.set_device(&name.clone());
global_state.audio.set_device(name.clone());
global_state.settings.audio.audio_device = Some(name);
global_state.settings.save_to_file_warn();
@ -388,8 +388,11 @@ impl PlayState for SessionState {
}
// Maintain the scene.
self.scene
.maintain(global_state.window.renderer_mut(), &self.client.borrow());
self.scene.maintain(
global_state.window.renderer_mut(),
&mut global_state.audio,
&self.client.borrow(),
);
// Render the session.
self.render(global_state.window.renderer_mut());