Compare commits

..

No commits in common. "df014a15b45b0cd7b89828208a9d57109c183ef0" and "ca040e96eca780eb934d2390ec7dab6e711e6589" have entirely different histories.

8 changed files with 95 additions and 743 deletions

449
Cargo.lock generated
View file

@ -28,9 +28,9 @@ dependencies = [
"accesskit", "accesskit",
"accesskit_consumer", "accesskit_consumer",
"hashbrown", "hashbrown",
"objc2 0.5.2", "objc2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -275,17 +275,6 @@ dependencies = [
"portable-atomic-util", "portable-atomic-util",
] ]
[[package]]
name = "audioshader"
version = "0.1.0"
dependencies = [
"bevy",
"cpal 0.16.0",
"crossbeam-channel",
"rodio 0.21.1",
"rustfft",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.5.0" version = "1.5.0"
@ -449,8 +438,8 @@ dependencies = [
"bevy_math", "bevy_math",
"bevy_reflect", "bevy_reflect",
"bevy_transform", "bevy_transform",
"cpal 0.15.3", "cpal",
"rodio 0.20.1", "rodio",
"tracing", "tracing",
] ]
@ -1145,6 +1134,13 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
] ]
[[package]]
name = "bevy_test"
version = "0.1.0"
dependencies = [
"bevy",
]
[[package]] [[package]]
name = "bevy_text" name = "bevy_text"
version = "0.16.1" version = "0.16.1"
@ -1416,7 +1412,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
dependencies = [ dependencies = [
"objc2 0.5.2", "objc2",
] ]
[[package]] [[package]]
@ -1676,20 +1672,6 @@ dependencies = [
"coreaudio-sys", "coreaudio-sys",
] ]
[[package]]
name = "coreaudio-rs"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17"
dependencies = [
"bitflags 1.3.2",
"libc",
"objc2-audio-toolbox",
"objc2-core-audio",
"objc2-core-audio-types",
"objc2-core-foundation",
]
[[package]] [[package]]
name = "coreaudio-sys" name = "coreaudio-sys"
version = "0.2.17" version = "0.2.17"
@ -1730,7 +1712,7 @@ checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
dependencies = [ dependencies = [
"alsa", "alsa",
"core-foundation-sys", "core-foundation-sys",
"coreaudio-rs 0.11.3", "coreaudio-rs",
"dasp_sample", "dasp_sample",
"jni", "jni",
"js-sys", "js-sys",
@ -1745,32 +1727,6 @@ dependencies = [
"windows 0.54.0", "windows 0.54.0",
] ]
[[package]]
name = "cpal"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd307f43cc2a697e2d1f8bc7a1d824b5269e052209e28883e5bc04d095aaa3f"
dependencies = [
"alsa",
"coreaudio-rs 0.13.0",
"dasp_sample",
"jni",
"js-sys",
"libc",
"mach2",
"ndk 0.9.0",
"ndk-context",
"num-derive",
"num-traits",
"objc2-audio-toolbox",
"objc2-core-audio",
"objc2-core-audio-types",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.54.0",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.5.0" version = "1.5.0"
@ -1871,16 +1827,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dispatch2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
"bitflags 2.9.3",
"objc2 0.6.2",
]
[[package]] [[package]]
name = "disqualified" name = "disqualified"
version = "1.0.0" version = "1.0.0"
@ -1955,15 +1901,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "encoding_rs"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@ -2020,12 +1957,6 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "extended"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.3.0" version = "2.3.0"
@ -3022,25 +2953,6 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "num-derive" name = "num-derive"
version = "0.4.2" version = "0.4.2"
@ -3052,26 +2964,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.19" version = "0.2.19"
@ -3129,15 +3021,6 @@ dependencies = [
"objc2-encode", "objc2-encode",
] ]
[[package]]
name = "objc2"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc"
dependencies = [
"objc2-encode",
]
[[package]] [[package]]
name = "objc2-app-kit" name = "objc2-app-kit"
version = "0.2.2" version = "0.2.2"
@ -3147,28 +3030,13 @@ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"libc", "libc",
"objc2 0.5.2", "objc2",
"objc2-core-data", "objc2-core-data",
"objc2-core-image", "objc2-core-image",
"objc2-foundation 0.2.2", "objc2-foundation",
"objc2-quartz-core", "objc2-quartz-core",
] ]
[[package]]
name = "objc2-audio-toolbox"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07"
dependencies = [
"bitflags 2.9.3",
"libc",
"objc2 0.6.2",
"objc2-core-audio",
"objc2-core-audio-types",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
]
[[package]] [[package]]
name = "objc2-cloud-kit" name = "objc2-cloud-kit"
version = "0.2.2" version = "0.2.2"
@ -3177,9 +3045,9 @@ checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-core-location", "objc2-core-location",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3189,30 +3057,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
dependencies = [ dependencies = [
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
]
[[package]]
name = "objc2-core-audio"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82"
dependencies = [
"dispatch2",
"objc2 0.6.2",
"objc2-core-audio-types",
"objc2-core-foundation",
]
[[package]]
name = "objc2-core-audio-types"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1"
dependencies = [
"bitflags 2.9.3",
"objc2 0.6.2",
] ]
[[package]] [[package]]
@ -3223,8 +3069,8 @@ checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3234,8 +3080,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"dispatch2",
"objc2 0.6.2",
] ]
[[package]] [[package]]
@ -3245,8 +3089,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
dependencies = [ dependencies = [
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
"objc2-metal", "objc2-metal",
] ]
@ -3257,9 +3101,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
dependencies = [ dependencies = [
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-contacts", "objc2-contacts",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3278,16 +3122,7 @@ dependencies = [
"block2", "block2",
"dispatch", "dispatch",
"libc", "libc",
"objc2 0.5.2", "objc2",
]
[[package]]
name = "objc2-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
dependencies = [
"objc2 0.6.2",
] ]
[[package]] [[package]]
@ -3297,9 +3132,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
dependencies = [ dependencies = [
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3310,8 +3145,8 @@ checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3322,8 +3157,8 @@ checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
"objc2-metal", "objc2-metal",
] ]
@ -3333,8 +3168,8 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
dependencies = [ dependencies = [
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3345,12 +3180,12 @@ checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-cloud-kit", "objc2-cloud-kit",
"objc2-core-data", "objc2-core-data",
"objc2-core-image", "objc2-core-image",
"objc2-core-location", "objc2-core-location",
"objc2-foundation 0.2.2", "objc2-foundation",
"objc2-link-presentation", "objc2-link-presentation",
"objc2-quartz-core", "objc2-quartz-core",
"objc2-symbols", "objc2-symbols",
@ -3365,8 +3200,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
dependencies = [ dependencies = [
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3377,9 +3212,9 @@ checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [ dependencies = [
"bitflags 2.9.3", "bitflags 2.9.3",
"block2", "block2",
"objc2 0.5.2", "objc2",
"objc2-core-location", "objc2-core-location",
"objc2-foundation 0.2.2", "objc2-foundation",
] ]
[[package]] [[package]]
@ -3620,15 +3455,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "primal-check"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08"
dependencies = [
"num-integer",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "3.3.0" version = "3.3.0"
@ -3807,22 +3633,10 @@ version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1" checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1"
dependencies = [ dependencies = [
"cpal 0.15.3", "cpal",
"lewton", "lewton",
] ]
[[package]]
name = "rodio"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e40ecf59e742e03336be6a3d53755e789fd05a059fa22dfa0ed624722319e183"
dependencies = [
"cpal 0.16.0",
"dasp_sample",
"num-rational",
"symphonia",
]
[[package]] [[package]]
name = "ron" name = "ron"
version = "0.8.1" version = "0.8.1"
@ -3853,20 +3667,6 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustfft"
version = "6.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f140db74548f7c9d7cce60912c9ac414e74df5e718dc947d514b051b42f3f4"
dependencies = [
"num-complex",
"num-integer",
"num-traits",
"primal-check",
"strength_reduce",
"transpose",
]
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.44" version = "0.38.44"
@ -4087,12 +3887,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strength_reduce"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82"
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.26.3" version = "0.26.3"
@ -4132,153 +3926,6 @@ dependencies = [
"zeno", "zeno",
] ]
[[package]]
name = "symphonia"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9"
dependencies = [
"lazy_static",
"symphonia-bundle-flac",
"symphonia-bundle-mp3",
"symphonia-codec-aac",
"symphonia-codec-pcm",
"symphonia-codec-vorbis",
"symphonia-core",
"symphonia-format-isomp4",
"symphonia-format-ogg",
"symphonia-format-riff",
"symphonia-metadata",
]
[[package]]
name = "symphonia-bundle-flac"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e34f34298a7308d4397a6c7fbf5b84c5d491231ce3dd379707ba673ab3bd97"
dependencies = [
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-bundle-mp3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4"
dependencies = [
"lazy_static",
"log",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-codec-aac"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdbf25b545ad0d3ee3e891ea643ad115aff4ca92f6aec472086b957a58522f70"
dependencies = [
"lazy_static",
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-codec-pcm"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b"
dependencies = [
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-codec-vorbis"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30"
dependencies = [
"log",
"symphonia-core",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-core"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3"
dependencies = [
"arrayvec",
"bitflags 1.3.2",
"bytemuck",
"lazy_static",
"log",
]
[[package]]
name = "symphonia-format-isomp4"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abfdf178d697e50ce1e5d9b982ba1b94c47218e03ec35022d9f0e071a16dc844"
dependencies = [
"encoding_rs",
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-format-ogg"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ada3505789516bcf00fc1157c67729eded428b455c27ca370e41f4d785bfa931"
dependencies = [
"log",
"symphonia-core",
"symphonia-metadata",
"symphonia-utils-xiph",
]
[[package]]
name = "symphonia-format-riff"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50"
dependencies = [
"extended",
"log",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-metadata"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c"
dependencies = [
"encoding_rs",
"lazy_static",
"log",
"symphonia-core",
]
[[package]]
name = "symphonia-utils-xiph"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe"
dependencies = [
"symphonia-core",
"symphonia-metadata",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.106" version = "2.0.106"
@ -4501,16 +4148,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "transpose"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e"
dependencies = [
"num-integer",
"strength_reduce",
]
[[package]] [[package]]
name = "ttf-parser" name = "ttf-parser"
version = "0.20.0" version = "0.20.0"
@ -5390,9 +5027,9 @@ dependencies = [
"js-sys", "js-sys",
"libc", "libc",
"ndk 0.9.0", "ndk 0.9.0",
"objc2 0.5.2", "objc2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation 0.2.2", "objc2-foundation",
"objc2-ui-kit", "objc2-ui-kit",
"orbclient", "orbclient",
"percent-encoding", "percent-encoding",

View file

@ -1,15 +1,11 @@
[package] [package]
edition = "2024" edition = "2024"
name = "audioshader" name = "bevy_test"
version = "0.1.0" version = "0.1.0"
[dependencies] [dependencies]
bevy = { version = "0.16", features = ["file_watcher"] } bevy = { version = "0.16", features = ["file_watcher"] }
cpal = "0.16"
crossbeam-channel = "0.5"
rodio = "0.21"
rustfft = "6"
# Enable a small amount of optimization in the dev profile. # Enable a small amount of optimization in the dev profile.
[profile.dev] [profile.dev]

View file

@ -1,107 +1,13 @@
#import bevy_sprite::mesh2d_vertex_output::VertexOutput #import bevy_sprite::mesh2d_vertex_output::VertexOutput
@group(2) @binding(0) var<uniform> u_time: f32; @group(2) @binding(0) var<uniform> u_time: f32;
@group(2) @binding(1) var<uniform> u_resolution: vec2f; @group(2) @binding(1) var<uniform> u_resolution: vec2<f32>;
@group(2) @binding(2) var<uniform> u_mouse_position: vec2f;
@group(2) @binding(3) var fft_texture: texture_2d<f32>;
@group(2) @binding(4) var fft_texture_sampler: sampler;
fn lerp(v0: f32, v1: f32, t: f32) -> f32 {
return v0 + t * (v1 - v0);
}
// Utility: clamp to 0..1 range
fn saturate(x: f32) -> f32 { return clamp(x, 0.0, 1.0); }
// Cosine palette (like IQ's)
fn palette(t: f32, a: vec3f, b: vec3f, c: vec3f, d: vec3f) -> vec3f {
return a + b * cos(6.2831853 * (c * t + d));
}
// Sample the FFT texture at normalized x in [0,1]
fn sample_fft(x: f32) -> f32 {
// 5-tap Gaussian blur in texture space using actual texel width
let size = textureDimensions(fft_texture);
let tex_w = max(f32(size.x), 1.0);
let one_texel = 1.0 / tex_w;
let u = saturate(x);
let v = 0.5;
let w0 = 0.0625; // gaussian-ish weights: 1,4,6,4,1 normalized
let w1 = 0.25;
let w2 = 0.375;
let s0 = textureSample(fft_texture, fft_texture_sampler, vec2f(u - 2.0 * one_texel, v)).r;
let s1 = textureSample(fft_texture, fft_texture_sampler, vec2f(u - 1.0 * one_texel, v)).r;
let s2 = textureSample(fft_texture, fft_texture_sampler, vec2f(u, v)).r;
let s3 = textureSample(fft_texture, fft_texture_sampler, vec2f(u + 1.0 * one_texel, v)).r;
let s4 = textureSample(fft_texture, fft_texture_sampler, vec2f(u + 2.0 * one_texel, v)).r;
return w0 * s0 + w1 * s1 + w2 * s2 + w1 * s3 + w0 * s4;
}
@fragment @fragment
fn fragment(mesh: VertexOutput) -> @location(0) vec4f { fn fragment(mesh: VertexOutput) -> @location(0) vec4<f32> {
// Normalize UV to -1..1 with aspect correction let bottom = vec3<f32>(1.0, 0.8, 0.2); // warm
let aspect = u_resolution.x / max(u_resolution.y, 1.0); let top = vec3<f32>(0.2, 0.6, 1.0); // cool
let p = (mesh.uv * 2.0 - vec2f(1.0, 1.0)) * vec2f(aspect, 1.0);
// Polar coords let color = mix(bottom, top, mesh.uv.y);
let r = length(p); return vec4<f32>(color, 1.0);
let ang = atan2(p.y, p.x); // [-pi, pi]
var a01 = ang / 6.2831853 + 0.5; // [0,1]
// Scroll the angle slowly for motion
a01 = fract(a01 + 0.05 * u_time);
// Log-like frequency remap for better distribution of low freqs
let freq = pow(a01, 0.8);
// Smooth FFT sample with a few taps
let amp0 = sample_fft(freq);
let amp1 = sample_fft(saturate(freq + 1.0 / 512.0));
let amp2 = sample_fft(saturate(freq - 1.0 / 512.0));
var amp = (amp0 + amp1 + amp2) / 3.0;
// Optional shaping
amp = pow(amp, 0.6);
// Target ring radius driven by amplitude
let base_r = 0.35;
let ring_r = base_r + amp * 0.45;
// Ring intensity with derivative-based anti-aliasing
let band_w = mix(0.02, 0.06, 1.0 - amp);
let aa = fwidth(r);
let dist = abs(r - ring_r);
let ring = 1.0 - smoothstep(band_w - aa, band_w + aa, dist);
// Radial spokes modulated by FFT at harmonics
let spokes = 0.5 + 0.5 * cos(ang * (8.0 + 24.0 * amp) + u_time * (1.0 + 2.0 * amp));
let spokes_mask = pow(spokes, 3.0);
// Glow falloff
let glow = 0.015 / (r * r + 0.03);
// Background subtle gradient with slow drift
let bg = 0.08 + 0.06 * cos(6.28318 * (p.x * 0.15 + p.y * 0.12 + 0.03 * u_time));
// Color palette over angle
let col = palette(
a01,
vec3f(0.35, 0.3, 0.35), // a
vec3f(0.35, 0.35, 0.35), // b
vec3f(1.0, 1.0, 1.0), // c
vec3f(0.0, 0.33, 0.67) // d
);
// Combine layers
var color = vec3f(bg) * 0.6;
color += col * ring * (0.6 + 0.6 * spokes_mask);
color += vec3f(0.9, 0.95, 1.0) * glow * (0.3 + 1.5 * amp);
// Subtle vignette
let vig = smoothstep(1.2, 0.3, r);
color *= vig;
// Final boost
color = clamp(color, vec3f(0.0), vec3f(1.0));
return vec4f(color, 1.0);
} }

View file

@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1767313136, "lastModified": 1756469547,
"narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", "narHash": "sha256-YvtD2E7MYsQ3r7K9K2G7nCslCKMPShoSEAtbjHLtH0k=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", "rev": "41d292bfc37309790f70f4c120b79280ce40af16",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -62,11 +62,11 @@
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1770520253, "lastModified": 1756521112,
"narHash": "sha256-6rWuHgSENXKnC6HGGAdRolQrnp/8IzscDn7FQEo1uEQ=", "narHash": "sha256-/YW9DI+vZ2lbTvYAek6BsudUXdpWr0FybTDod4P42L4=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "ebb8a141f60bb0ec33836333e0ca7928a072217f", "rev": "2243e3f251ea18486f83133cf8e325d2b9b71e89",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -1,165 +0,0 @@
use {
bevy::prelude::*,
cpal::{
FromSample, Sample, SizedSample,
traits::{DeviceTrait, HostTrait, StreamTrait},
},
crossbeam_channel::{Receiver, Sender},
rustfft::{Fft, FftPlanner, num_complex::Complex},
std::sync::Arc,
};
/// Resource holding the latest FFT result (magnitude spectrum)
#[derive(Resource, Clone, Debug)]
pub struct AudioFft {
pub spectrum: Vec<f32>,
pub sample_rate: u32,
pub channels: u16,
}
impl Default for AudioFft {
fn default() -> Self {
Self {
spectrum: vec![0.0; 1024],
sample_rate: 44100,
channels: 1,
}
}
}
/// Holds the CPAL stream alive and a channel for transferring audio to Bevy world.
#[derive(Resource)]
struct AudioCaptureStream {
rx: Receiver<Vec<f32>>,
#[allow(dead_code)]
stream: cpal::Stream, // kept to prevent drop
sample_rate: u32,
channels: u16,
}
pub struct AudioCapturePlugin;
impl Plugin for AudioCapturePlugin {
fn build(&self, app: &mut App) {
app.init_resource::<AudioFft>()
.add_systems(Startup, init_audio_input_stream)
.add_systems(Update, dispatch_audio_events);
}
}
fn init_audio_input_stream(mut commands: Commands) {
let default_host = cpal::default_host();
let default_device = default_host
.default_input_device()
.expect("Failed to get default input device");
let default_input_config = default_device
.default_input_config()
.expect("Failed to get default input config");
let sample_rate = default_input_config.sample_rate().0;
let channels = default_input_config.channels();
let config = default_input_config.config();
let (tx, rx) = crossbeam_channel::unbounded::<Vec<f32>>();
let stream = match default_input_config.sample_format() {
cpal::SampleFormat::F32 => build_input_stream::<f32>(&default_device, &config, tx),
cpal::SampleFormat::I16 => build_input_stream::<i16>(&default_device, &config, tx),
cpal::SampleFormat::U16 => build_input_stream::<u16>(&default_device, &config, tx),
other => panic!("Unsupported sample format: {other:?}"),
}
.expect("Failed to build input stream");
stream.play().expect("Failed to play input stream");
info!(
"Audio capture stream started: {} ch @ {} Hz (default OS input)",
channels, sample_rate
);
commands.insert_resource(AudioCaptureStream {
rx,
stream,
sample_rate,
channels,
});
}
/// Helper to build a typed CPAL input stream and forward f32 samples via channel.
fn build_input_stream<T>(
device: &cpal::Device,
config: &cpal::StreamConfig,
tx: Sender<Vec<f32>>,
) -> Result<cpal::Stream, cpal::BuildStreamError>
where
T: SizedSample + Sample,
f32: FromSample<T>,
{
device.build_input_stream(
config,
move |data: &[T], _| {
// Convert to f32 and ship to the main thread.
// NOTE: allocate-per-callback is simple; use a ring buffer for lower GC/latency if needed.
let mut out = Vec::with_capacity(data.len());
for &s in data {
out.push(f32::from_sample(s));
}
// Ignore send errors if receiver was dropped.
let _ = tx.send(out);
},
move |err| {
if let cpal::StreamError::BackendSpecific {
err: cpal::BackendSpecificError { ref description },
} = err
&& description != "`alsa::poll()` spuriously returned"
{
error!("CPAL stream error: {err}");
}
},
Some(std::time::Duration::from_millis(10)), // latency
)
}
fn dispatch_audio_events(stream: Res<AudioCaptureStream>, mut fft_res: ResMut<AudioFft>) {
// FFT parameters
const FFT_SIZE: usize = 1024;
// Drain any available audio buffers without blocking the frame.
while let Ok(samples) = stream.rx.try_recv() {
// Compute FFT on the first channel (mono mix)
let mut mono: Vec<f32> = if stream.channels > 1 {
samples
.chunks(stream.channels as usize)
.map(|frame| frame[0])
.collect()
} else {
samples.clone()
};
// Pad or truncate to FFT_SIZE
if mono.len() < FFT_SIZE {
mono.resize(FFT_SIZE, 0.0);
} else if mono.len() > FFT_SIZE {
mono.truncate(FFT_SIZE);
}
// Prepare input for FFT
let mut buffer: Vec<Complex<f32>> = mono
.into_iter()
.map(|x| Complex { re: x, im: 0.0 })
.collect();
// Compute FFT
let mut planner = FftPlanner::<f32>::new();
let fft: Arc<dyn Fft<f32>> = planner.plan_fft_forward(FFT_SIZE);
fft.process(&mut buffer);
// Compute magnitude spectrum
let spectrum: Vec<f32> = buffer.iter().map(|c| c.norm()).collect();
// Update AudioFft resource
fft_res.spectrum = spectrum;
fft_res.sample_rate = stream.sample_rate;
fft_res.channels = stream.channels;
}
}

View file

@ -1,5 +1,4 @@
//! A shader that uses the WGSL shading language. //! A shader that uses the WGSL shading language.
mod audio_input;
mod material; mod material;
mod systems; mod systems;
@ -12,16 +11,14 @@ fn main() {
.add_plugins(( .add_plugins((
DefaultPlugins, DefaultPlugins,
Material2dPlugin::<CustomMaterial>::default(), Material2dPlugin::<CustomMaterial>::default(),
audio_input::AudioCapturePlugin,
)) ))
.add_systems(Startup, systems::setup) .add_systems(Startup, systems::setup)
.add_systems( .add_systems(
Update, Update,
( (
material::update_material_time, material::update_material_time,
material::update_material_audio_fft, material::shader_hot_reload,
systems::screen_resized, systems::resize_fullscreen_quad,
systems::mouse_moved,
systems::exit_app.run_if(input_just_pressed(KeyCode::Escape)), systems::exit_app.run_if(input_just_pressed(KeyCode::Escape)),
systems::toggle_fullscreen.run_if(input_just_pressed(KeyCode::F11)), systems::toggle_fullscreen.run_if(input_just_pressed(KeyCode::F11)),
), ),

View file

@ -1,24 +1,20 @@
use bevy::{ use bevy::{
asset::Assets, asset::AssetEvent,
prelude::*, prelude::*,
reflect::TypePath, reflect::TypePath,
render::render_resource::{AsBindGroup, Extent3d, ShaderRef}, render::render_resource::{AsBindGroup, Shader, ShaderRef},
sprite::{AlphaMode2d, Material2d}, sprite::{AlphaMode2d, Material2d},
}; };
const DEFAULT_SHADER_PATH: &str = "shaders/default.wgsl"; const DEFAULT_SHADER_PATH: &str = "shaders/default.wgsl";
// This is the struct that will be passed to your shader
#[derive(Asset, TypePath, AsBindGroup, Clone)] #[derive(Asset, TypePath, AsBindGroup, Clone)]
pub struct CustomMaterial { pub struct CustomMaterial {
#[uniform(0)] #[uniform(0)]
pub time: f32, pub time: f32,
#[uniform(1)] #[uniform(1)]
pub resolution: Vec2, pub resolution: Vec2,
#[uniform(2)]
pub mouse_position: Vec2,
#[texture(3)]
#[sampler(4)]
pub audio_fft_tex: Handle<Image>,
} }
pub fn update_material_time(mut materials: ResMut<Assets<CustomMaterial>>, time: Res<Time>) { pub fn update_material_time(mut materials: ResMut<Assets<CustomMaterial>>, time: Res<Time>) {
@ -28,32 +24,28 @@ pub fn update_material_time(mut materials: ResMut<Assets<CustomMaterial>>, time:
} }
} }
pub fn update_material_audio_fft( /// Listen for shader asset changes and force materials to update so the new shader is used.
pub fn shader_hot_reload(
mut shader_events: EventReader<AssetEvent<Shader>>,
mut materials: ResMut<Assets<CustomMaterial>>, mut materials: ResMut<Assets<CustomMaterial>>,
mut images: ResMut<Assets<Image>>,
audio_fft: Res<crate::audio_input::AudioFft>,
) { ) {
let spectrum = &audio_fft.spectrum; let mut reload_needed = false;
if spectrum.is_empty() { for event in shader_events.read() {
return; match event {
AssetEvent::Modified { .. } => {
reload_needed = true;
} }
let image = Image::new( _ => {}
Extent3d { }
width: spectrum.len() as u32, }
height: 1,
depth_or_array_layers: 1, if reload_needed {
}, // iterate all materials and 'touch' them so Bevy updates bindings using the recompiled shader
bevy::render::render_resource::TextureDimension::D2,
spectrum
.iter()
.map(|&v| (v * 255.0).clamp(0.0, 255.0) as u8)
.collect(),
bevy::render::render_resource::TextureFormat::R8Unorm,
bevy::asset::RenderAssetUsages::RENDER_WORLD,
);
let handle = images.add(image);
for (_handle, material) in materials.iter_mut() { for (_handle, material) in materials.iter_mut() {
material.audio_fft_tex = handle.clone(); // assign to itself to mark changed
let cloned = material.clone();
*material = cloned;
}
} }
} }

View file

@ -1,19 +1,23 @@
use bevy::{ use bevy::{
prelude::*, prelude::*,
window::{PrimaryWindow, WindowMode, WindowResized}, window::{PrimaryWindow, WindowMode},
}; };
use crate::material::CustomMaterial; use crate::material::CustomMaterial;
/// Marker component for the fullscreen quad so we can update it on window resize
#[derive(Component)] #[derive(Component)]
pub struct FullscreenQuad; pub struct FullscreenQuad;
/// set up a simple 2D-screen-like surface
pub fn setup( pub fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<CustomMaterial>>, mut materials: ResMut<Assets<CustomMaterial>>,
primary_window: Single<&Window, With<PrimaryWindow>>, mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
mut commands: Commands, mut commands: Commands,
) { ) {
primary_window.decorations = false;
commands.spawn(Camera2d); commands.spawn(Camera2d);
// quad that fills the whole window // quad that fills the whole window
@ -25,8 +29,6 @@ pub fn setup(
let material_handle = materials.add(CustomMaterial { let material_handle = materials.add(CustomMaterial {
time: 0.0, time: 0.0,
resolution: screen_size, resolution: screen_size,
mouse_position: Vec2::ZERO,
audio_fft_tex: Default::default(),
}); });
commands.spawn(( commands.spawn((
@ -37,29 +39,16 @@ pub fn setup(
)); ));
} }
pub fn mouse_moved( /// Update fullscreen quad transforms when the primary window is resized.
mut events: EventReader<CursorMoved>, pub fn resize_fullscreen_quad(
shader_material: Single<&MeshMaterial2d<CustomMaterial>, With<FullscreenQuad>>, primary_window: Single<&Window, With<PrimaryWindow>>,
mut materials: ResMut<Assets<CustomMaterial>>, mut transform: Single<&mut Transform, With<FullscreenQuad>>,
) { ) {
if let Some(event) = events.read().last() { let size = Vec2::new(
materials primary_window.resolution.width(),
.get_mut(&shader_material.0) primary_window.resolution.height(),
.unwrap() );
.mouse_position = Vec2::new(event.position.x, event.position.y); transform.scale = Vec3::new(size.x, size.y, 1.0);
}
}
pub fn screen_resized(
mut events: EventReader<WindowResized>,
shader_data: Single<(&mut Transform, &MeshMaterial2d<CustomMaterial>), With<FullscreenQuad>>,
mut materials: ResMut<Assets<CustomMaterial>>,
) {
let (mut transform, material) = shader_data.into_inner();
if let Some(event) = events.read().last() {
transform.scale = Vec3::new(event.width, event.height, 1.0);
materials.get_mut(&material.0).unwrap().resolution = Vec2::new(event.width, event.height);
}
} }
pub fn exit_app(mut exit: EventWriter<AppExit>) { pub fn exit_app(mut exit: EventWriter<AppExit>) {