Add audio, fix timing
This commit is contained in:
		
							parent
							
								
									8bba7b9e1b
								
							
						
					
					
						commit
						70373647fb
					
				| 
						 | 
					@ -31,12 +31,43 @@ dependencies = [
 | 
				
			||||||
 "zerocopy",
 | 
					 "zerocopy",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "aho-corasick"
 | 
				
			||||||
 | 
					version = "1.1.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "allocator-api2"
 | 
					name = "allocator-api2"
 | 
				
			||||||
version = "0.2.18"
 | 
					version = "0.2.18"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
 | 
					checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "alsa"
 | 
				
			||||||
 | 
					version = "0.9.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "alsa-sys",
 | 
				
			||||||
 | 
					 "bitflags 2.6.0",
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "alsa-sys"
 | 
				
			||||||
 | 
					version = "0.3.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "pkg-config",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "android-activity"
 | 
					name = "android-activity"
 | 
				
			||||||
version = "0.6.0"
 | 
					version = "0.6.0"
 | 
				
			||||||
| 
						 | 
					@ -51,7 +82,7 @@ dependencies = [
 | 
				
			||||||
 "jni-sys",
 | 
					 "jni-sys",
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "ndk",
 | 
					 "ndk 0.9.0",
 | 
				
			||||||
 "ndk-context",
 | 
					 "ndk-context",
 | 
				
			||||||
 "ndk-sys 0.6.0+11769913",
 | 
					 "ndk-sys 0.6.0+11769913",
 | 
				
			||||||
 "num_enum",
 | 
					 "num_enum",
 | 
				
			||||||
| 
						 | 
					@ -167,6 +198,24 @@ version = "1.4.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 | 
					checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bindgen"
 | 
				
			||||||
 | 
					version = "0.70.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bitflags 2.6.0",
 | 
				
			||||||
 | 
					 "cexpr",
 | 
				
			||||||
 | 
					 "clang-sys",
 | 
				
			||||||
 | 
					 "itertools",
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "regex",
 | 
				
			||||||
 | 
					 "rustc-hash",
 | 
				
			||||||
 | 
					 "shlex",
 | 
				
			||||||
 | 
					 "syn 2.0.87",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "bit-set"
 | 
					name = "bit-set"
 | 
				
			||||||
version = "0.6.0"
 | 
					version = "0.6.0"
 | 
				
			||||||
| 
						 | 
					@ -284,6 +333,15 @@ 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 = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
 | 
					checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cexpr"
 | 
				
			||||||
 | 
					version = "0.6.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "nom",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "cfg-if"
 | 
					name = "cfg-if"
 | 
				
			||||||
version = "1.0.0"
 | 
					version = "1.0.0"
 | 
				
			||||||
| 
						 | 
					@ -308,6 +366,17 @@ version = "1.0.12"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "1e10e7569f6ca78ef7664d7d651115172d4875c4410c050306bccde856a99a49"
 | 
					checksum = "1e10e7569f6ca78ef7664d7d651115172d4875c4410c050306bccde856a99a49"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "clang-sys"
 | 
				
			||||||
 | 
					version = "1.8.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "glob",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "libloading",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "clap"
 | 
					name = "clap"
 | 
				
			||||||
version = "4.5.20"
 | 
					version = "4.5.20"
 | 
				
			||||||
| 
						 | 
					@ -454,6 +523,49 @@ dependencies = [
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "coreaudio-rs"
 | 
				
			||||||
 | 
					version = "0.11.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bitflags 1.3.2",
 | 
				
			||||||
 | 
					 "core-foundation-sys",
 | 
				
			||||||
 | 
					 "coreaudio-sys",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "coreaudio-sys"
 | 
				
			||||||
 | 
					version = "0.2.16"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bindgen",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cpal"
 | 
				
			||||||
 | 
					version = "0.15.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "alsa",
 | 
				
			||||||
 | 
					 "core-foundation-sys",
 | 
				
			||||||
 | 
					 "coreaudio-rs",
 | 
				
			||||||
 | 
					 "dasp_sample",
 | 
				
			||||||
 | 
					 "jni",
 | 
				
			||||||
 | 
					 "js-sys",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "mach2",
 | 
				
			||||||
 | 
					 "ndk 0.8.0",
 | 
				
			||||||
 | 
					 "ndk-context",
 | 
				
			||||||
 | 
					 "oboe",
 | 
				
			||||||
 | 
					 "wasm-bindgen",
 | 
				
			||||||
 | 
					 "wasm-bindgen-futures",
 | 
				
			||||||
 | 
					 "web-sys",
 | 
				
			||||||
 | 
					 "windows 0.54.0",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "crossbeam-utils"
 | 
					name = "crossbeam-utils"
 | 
				
			||||||
version = "0.8.20"
 | 
					version = "0.8.20"
 | 
				
			||||||
| 
						 | 
					@ -477,6 +589,12 @@ dependencies = [
 | 
				
			||||||
 "winapi",
 | 
					 "winapi",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "dasp_sample"
 | 
				
			||||||
 | 
					version = "0.11.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "dispatch"
 | 
					name = "dispatch"
 | 
				
			||||||
version = "0.2.0"
 | 
					version = "0.2.0"
 | 
				
			||||||
| 
						 | 
					@ -513,6 +631,12 @@ version = "0.1.1"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
 | 
					checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "either"
 | 
				
			||||||
 | 
					version = "1.13.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "equivalent"
 | 
					name = "equivalent"
 | 
				
			||||||
version = "1.0.1"
 | 
					version = "1.0.1"
 | 
				
			||||||
| 
						 | 
					@ -588,6 +712,12 @@ dependencies = [
 | 
				
			||||||
 "xml-rs",
 | 
					 "xml-rs",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "glob"
 | 
				
			||||||
 | 
					version = "0.3.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "glow"
 | 
					name = "glow"
 | 
				
			||||||
version = "0.13.1"
 | 
					version = "0.13.1"
 | 
				
			||||||
| 
						 | 
					@ -638,7 +768,7 @@ dependencies = [
 | 
				
			||||||
 "presser",
 | 
					 "presser",
 | 
				
			||||||
 "thiserror",
 | 
					 "thiserror",
 | 
				
			||||||
 "winapi",
 | 
					 "winapi",
 | 
				
			||||||
 "windows",
 | 
					 "windows 0.52.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -773,6 +903,15 @@ version = "1.70.1"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
 | 
					checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "itertools"
 | 
				
			||||||
 | 
					version = "0.13.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "either",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "jni"
 | 
					name = "jni"
 | 
				
			||||||
version = "0.21.1"
 | 
					version = "0.21.1"
 | 
				
			||||||
| 
						 | 
					@ -885,6 +1024,15 @@ version = "0.4.22"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 | 
					checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "mach2"
 | 
				
			||||||
 | 
					version = "0.4.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "malloc_buf"
 | 
					name = "malloc_buf"
 | 
				
			||||||
version = "0.0.6"
 | 
					version = "0.0.6"
 | 
				
			||||||
| 
						 | 
					@ -924,6 +1072,12 @@ dependencies = [
 | 
				
			||||||
 "paste",
 | 
					 "paste",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "minimal-lexical"
 | 
				
			||||||
 | 
					version = "0.2.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "mint"
 | 
					name = "mint"
 | 
				
			||||||
version = "0.5.9"
 | 
					version = "0.5.9"
 | 
				
			||||||
| 
						 | 
					@ -951,6 +1105,20 @@ dependencies = [
 | 
				
			||||||
 "unicode-xid",
 | 
					 "unicode-xid",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "ndk"
 | 
				
			||||||
 | 
					version = "0.8.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "bitflags 2.6.0",
 | 
				
			||||||
 | 
					 "jni-sys",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
 | 
					 "ndk-sys 0.5.0+25.2.9519653",
 | 
				
			||||||
 | 
					 "num_enum",
 | 
				
			||||||
 | 
					 "thiserror",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "ndk"
 | 
					name = "ndk"
 | 
				
			||||||
version = "0.9.0"
 | 
					version = "0.9.0"
 | 
				
			||||||
| 
						 | 
					@ -990,6 +1158,54 @@ dependencies = [
 | 
				
			||||||
 "jni-sys",
 | 
					 "jni-sys",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "nom"
 | 
				
			||||||
 | 
					version = "7.1.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					 "minimal-lexical",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-complex"
 | 
				
			||||||
 | 
					version = "0.4.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-derive"
 | 
				
			||||||
 | 
					version = "0.4.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn 2.0.87",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[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-traits"
 | 
				
			||||||
 | 
					version = "0.2.19"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "num_enum"
 | 
					name = "num_enum"
 | 
				
			||||||
version = "0.7.3"
 | 
					version = "0.7.3"
 | 
				
			||||||
| 
						 | 
					@ -1223,6 +1439,29 @@ dependencies = [
 | 
				
			||||||
 "objc2-foundation",
 | 
					 "objc2-foundation",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "oboe"
 | 
				
			||||||
 | 
					version = "0.6.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "jni",
 | 
				
			||||||
 | 
					 "ndk 0.8.0",
 | 
				
			||||||
 | 
					 "ndk-context",
 | 
				
			||||||
 | 
					 "num-derive",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					 "oboe-sys",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "oboe-sys"
 | 
				
			||||||
 | 
					version = "0.6.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "once_cell"
 | 
					name = "once_cell"
 | 
				
			||||||
version = "1.20.2"
 | 
					version = "1.20.2"
 | 
				
			||||||
| 
						 | 
					@ -1341,6 +1580,15 @@ version = "0.3.1"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
 | 
					checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[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.2.0"
 | 
					version = "3.2.0"
 | 
				
			||||||
| 
						 | 
					@ -1395,6 +1643,15 @@ version = "0.6.2"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
 | 
					checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "realfft"
 | 
				
			||||||
 | 
					version = "3.4.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "390252372b7f2aac8360fc5e72eba10136b166d6faeed97e6d0c8324eb99b2b1"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "rustfft",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "redox_syscall"
 | 
					name = "redox_syscall"
 | 
				
			||||||
version = "0.4.1"
 | 
					version = "0.4.1"
 | 
				
			||||||
| 
						 | 
					@ -1413,18 +1670,80 @@ dependencies = [
 | 
				
			||||||
 "bitflags 2.6.0",
 | 
					 "bitflags 2.6.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "regex"
 | 
				
			||||||
 | 
					version = "1.11.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "aho-corasick",
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					 "regex-automata",
 | 
				
			||||||
 | 
					 "regex-syntax",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "regex-automata"
 | 
				
			||||||
 | 
					version = "0.4.8"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "aho-corasick",
 | 
				
			||||||
 | 
					 "memchr",
 | 
				
			||||||
 | 
					 "regex-syntax",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "regex-syntax"
 | 
				
			||||||
 | 
					version = "0.8.5"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "renderdoc-sys"
 | 
					name = "renderdoc-sys"
 | 
				
			||||||
version = "1.1.0"
 | 
					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 = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
 | 
					checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rtrb"
 | 
				
			||||||
 | 
					version = "0.3.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "f3f94e84c073f3b85d4012b44722fa8842b9986d741590d4f2636ad0a5b14143"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rubato"
 | 
				
			||||||
 | 
					version = "0.16.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "cdd96992d7e24b3d7f35fdfe02af037a356ac90d41b466945cf3333525a86eea"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "num-complex",
 | 
				
			||||||
 | 
					 "num-integer",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					 "realfft",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "rustc-hash"
 | 
					name = "rustc-hash"
 | 
				
			||||||
version = "1.1.0"
 | 
					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 = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 | 
					checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rustfft"
 | 
				
			||||||
 | 
					version = "6.2.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "43806561bc506d0c5d160643ad742e3161049ac01027b5e6d7524091fd401d86"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "num-complex",
 | 
				
			||||||
 | 
					 "num-integer",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					 "primal-check",
 | 
				
			||||||
 | 
					 "strength_reduce",
 | 
				
			||||||
 | 
					 "transpose",
 | 
				
			||||||
 | 
					 "version_check",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "rustix"
 | 
					name = "rustix"
 | 
				
			||||||
version = "0.38.38"
 | 
					version = "0.38.38"
 | 
				
			||||||
| 
						 | 
					@ -1506,10 +1825,16 @@ dependencies = [
 | 
				
			||||||
 "bytemuck",
 | 
					 "bytemuck",
 | 
				
			||||||
 "cc",
 | 
					 "cc",
 | 
				
			||||||
 "clap",
 | 
					 "clap",
 | 
				
			||||||
 | 
					 "cpal",
 | 
				
			||||||
 "imgui",
 | 
					 "imgui",
 | 
				
			||||||
 "imgui-wgpu",
 | 
					 "imgui-wgpu",
 | 
				
			||||||
 "imgui-winit-support",
 | 
					 "imgui-winit-support",
 | 
				
			||||||
 | 
					 "itertools",
 | 
				
			||||||
 | 
					 "num-derive",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 "pollster",
 | 
					 "pollster",
 | 
				
			||||||
 | 
					 "rtrb",
 | 
				
			||||||
 | 
					 "rubato",
 | 
				
			||||||
 "wgpu",
 | 
					 "wgpu",
 | 
				
			||||||
 "winit",
 | 
					 "winit",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -1587,6 +1912,12 @@ 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 = "strict-num"
 | 
					name = "strict-num"
 | 
				
			||||||
version = "0.1.1"
 | 
					version = "0.1.1"
 | 
				
			||||||
| 
						 | 
					@ -1708,6 +2039,16 @@ version = "0.1.32"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
 | 
					checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[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.25.0"
 | 
					version = "0.25.0"
 | 
				
			||||||
| 
						 | 
					@ -2111,7 +2452,17 @@ version = "0.52.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 | 
					checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "windows-core",
 | 
					 "windows-core 0.52.0",
 | 
				
			||||||
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows"
 | 
				
			||||||
 | 
					version = "0.54.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows-core 0.54.0",
 | 
				
			||||||
 "windows-targets 0.52.6",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2124,6 +2475,25 @@ dependencies = [
 | 
				
			||||||
 "windows-targets 0.52.6",
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows-core"
 | 
				
			||||||
 | 
					version = "0.54.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows-result",
 | 
				
			||||||
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "windows-result"
 | 
				
			||||||
 | 
					version = "0.1.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "windows-targets 0.52.6",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "windows-sys"
 | 
					name = "windows-sys"
 | 
				
			||||||
version = "0.45.0"
 | 
					version = "0.45.0"
 | 
				
			||||||
| 
						 | 
					@ -2351,7 +2721,7 @@ dependencies = [
 | 
				
			||||||
 "js-sys",
 | 
					 "js-sys",
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 "memmap2",
 | 
					 "memmap2",
 | 
				
			||||||
 "ndk",
 | 
					 "ndk 0.9.0",
 | 
				
			||||||
 "objc2",
 | 
					 "objc2",
 | 
				
			||||||
 "objc2-app-kit",
 | 
					 "objc2-app-kit",
 | 
				
			||||||
 "objc2-foundation",
 | 
					 "objc2-foundation",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +7,16 @@ edition = "2021"
 | 
				
			||||||
anyhow = "1"
 | 
					anyhow = "1"
 | 
				
			||||||
bytemuck = { version = "1", features = ["derive"] }
 | 
					bytemuck = { version = "1", features = ["derive"] }
 | 
				
			||||||
clap = { version = "4", features = ["derive"] }
 | 
					clap = { version = "4", features = ["derive"] }
 | 
				
			||||||
 | 
					cpal = "0.15"
 | 
				
			||||||
imgui = "0.12"
 | 
					imgui = "0.12"
 | 
				
			||||||
imgui-wgpu = { git = "https://github.com/Yatekii/imgui-wgpu-rs", rev = "2edd348" }
 | 
					imgui-wgpu = { git = "https://github.com/Yatekii/imgui-wgpu-rs", rev = "2edd348" }
 | 
				
			||||||
imgui-winit-support = "0.13"
 | 
					imgui-winit-support = "0.13"
 | 
				
			||||||
 | 
					itertools = "0.13"
 | 
				
			||||||
 | 
					num-derive = "0.4"
 | 
				
			||||||
 | 
					num-traits = "0.2"
 | 
				
			||||||
pollster = "0.4"
 | 
					pollster = "0.4"
 | 
				
			||||||
 | 
					rtrb = "0.3"
 | 
				
			||||||
 | 
					rubato = "0.16"
 | 
				
			||||||
wgpu = "22.1"
 | 
					wgpu = "22.1"
 | 
				
			||||||
winit = "0.30"
 | 
					winit = "0.30"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					use anyhow::{bail, Result};
 | 
				
			||||||
 | 
					use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
 | 
				
			||||||
 | 
					use itertools::Itertools;
 | 
				
			||||||
 | 
					use rubato::{FftFixedInOut, Resampler};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Audio {
 | 
				
			||||||
 | 
					    #[allow(unused)]
 | 
				
			||||||
 | 
					    stream: cpal::Stream,
 | 
				
			||||||
 | 
					    sampler: FftFixedInOut<f32>,
 | 
				
			||||||
 | 
					    input_buffer: Vec<Vec<f32>>,
 | 
				
			||||||
 | 
					    output_buffer: Vec<Vec<f32>>,
 | 
				
			||||||
 | 
					    sample_sink: rtrb::Producer<f32>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Audio {
 | 
				
			||||||
 | 
					    pub fn init() -> Result<Self> {
 | 
				
			||||||
 | 
					        let host = cpal::default_host();
 | 
				
			||||||
 | 
					        let Some(device) = host.default_output_device() else {
 | 
				
			||||||
 | 
					            bail!("No output device available");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let Some(config) = device
 | 
				
			||||||
 | 
					            .supported_output_configs()?
 | 
				
			||||||
 | 
					            .find(|c| c.channels() == 2 && c.sample_format().is_float())
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            bail!("No suitable output config available");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let mut config = config.with_max_sample_rate().config();
 | 
				
			||||||
 | 
					        let sampler = FftFixedInOut::new(41700, config.sample_rate.0 as usize, 834, 2)?;
 | 
				
			||||||
 | 
					        config.buffer_size = cpal::BufferSize::Fixed(sampler.output_frames_max() as u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let input_buffer = sampler.input_buffer_allocate(true);
 | 
				
			||||||
 | 
					        let output_buffer = sampler.output_buffer_allocate(true);
 | 
				
			||||||
 | 
					        let (sample_sink, mut sample_source) =
 | 
				
			||||||
 | 
					            rtrb::RingBuffer::new(sampler.output_frames_max() * 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let stream = device.build_output_stream(
 | 
				
			||||||
 | 
					            &config,
 | 
				
			||||||
 | 
					            move |data: &mut [f32], _| {
 | 
				
			||||||
 | 
					                let requested = data.len();
 | 
				
			||||||
 | 
					                let chunk = match sample_source.read_chunk(data.len()) {
 | 
				
			||||||
 | 
					                    Ok(c) => c,
 | 
				
			||||||
 | 
					                    Err(rtrb::chunks::ChunkError::TooFewSlots(n)) => {
 | 
				
			||||||
 | 
					                        sample_source.read_chunk(n).unwrap()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let len = chunk.len();
 | 
				
			||||||
 | 
					                let (first, second) = chunk.as_slices();
 | 
				
			||||||
 | 
					                data[0..first.len()].copy_from_slice(first);
 | 
				
			||||||
 | 
					                data[first.len()..len].copy_from_slice(second);
 | 
				
			||||||
 | 
					                for rest in &mut data[len..requested] {
 | 
				
			||||||
 | 
					                    *rest = 0.0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                chunk.commit_all();
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            move |err| eprintln!("stream error: {err}"),
 | 
				
			||||||
 | 
					            None,
 | 
				
			||||||
 | 
					        )?;
 | 
				
			||||||
 | 
					        stream.play()?;
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            stream,
 | 
				
			||||||
 | 
					            sampler,
 | 
				
			||||||
 | 
					            input_buffer,
 | 
				
			||||||
 | 
					            output_buffer,
 | 
				
			||||||
 | 
					            sample_sink,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn update(&mut self, samples: &[f32]) {
 | 
				
			||||||
 | 
					        for sample in samples.chunks_exact(2) {
 | 
				
			||||||
 | 
					            for (channel, value) in self.input_buffer.iter_mut().zip(sample) {
 | 
				
			||||||
 | 
					                channel.push(*value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if self.input_buffer[0].len() >= self.sampler.input_frames_next() {
 | 
				
			||||||
 | 
					                let (_, output_samples) = self
 | 
				
			||||||
 | 
					                    .sampler
 | 
				
			||||||
 | 
					                    .process_into_buffer(&self.input_buffer, &mut self.output_buffer, None)
 | 
				
			||||||
 | 
					                    .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let chunk = match self.sample_sink.write_chunk_uninit(output_samples * 2) {
 | 
				
			||||||
 | 
					                    Ok(c) => c,
 | 
				
			||||||
 | 
					                    Err(rtrb::chunks::ChunkError::TooFewSlots(n)) => {
 | 
				
			||||||
 | 
					                        self.sample_sink.write_chunk_uninit(n).unwrap()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let interleaved = self.output_buffer[0]
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .interleave(self.output_buffer[1].iter())
 | 
				
			||||||
 | 
					                    .cloned();
 | 
				
			||||||
 | 
					                chunk.fill_from_iter(interleaved);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for channel in &mut self.input_buffer {
 | 
				
			||||||
 | 
					                    channel.clear();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while self.sample_sink.slots() < self.sampler.output_frames_max() * 2 {
 | 
				
			||||||
 | 
					            std::hint::spin_loop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,29 +1,60 @@
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    fs,
 | 
					    fs,
 | 
				
			||||||
    path::Path,
 | 
					    path::{Path, PathBuf},
 | 
				
			||||||
    sync::mpsc::{self, TryRecvError},
 | 
					    sync::mpsc::{self, TryRecvError},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{renderer::GameRenderer, shrooms_vb_core::CoreVB};
 | 
					use crate::{audio::Audio, renderer::GameRenderer, shrooms_vb_core::CoreVB};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct EmulatorBuilder {
 | 
				
			||||||
 | 
					    rom: Option<PathBuf>,
 | 
				
			||||||
 | 
					    commands: mpsc::Receiver<EmulatorCommand>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl EmulatorBuilder {
 | 
				
			||||||
 | 
					    pub fn new() -> (Self, EmulatorClient) {
 | 
				
			||||||
 | 
					        let (queue, commands) = mpsc::channel();
 | 
				
			||||||
 | 
					        let builder = Self {
 | 
				
			||||||
 | 
					            rom: None,
 | 
				
			||||||
 | 
					            commands,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let client = EmulatorClient { queue };
 | 
				
			||||||
 | 
					        (builder, client)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn with_rom(self, path: &Path) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            rom: Some(path.into()),
 | 
				
			||||||
 | 
					            ..self
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn build(self) -> Result<Emulator> {
 | 
				
			||||||
 | 
					        let mut emulator = Emulator::new(self.commands)?;
 | 
				
			||||||
 | 
					        if let Some(path) = self.rom {
 | 
				
			||||||
 | 
					            emulator.load_rom(&path)?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(emulator)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Emulator {
 | 
					pub struct Emulator {
 | 
				
			||||||
    sim: CoreVB,
 | 
					    sim: CoreVB,
 | 
				
			||||||
 | 
					    audio: Audio,
 | 
				
			||||||
    commands: mpsc::Receiver<EmulatorCommand>,
 | 
					    commands: mpsc::Receiver<EmulatorCommand>,
 | 
				
			||||||
    renderer: Option<GameRenderer>,
 | 
					    renderer: Option<GameRenderer>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Emulator {
 | 
					impl Emulator {
 | 
				
			||||||
    pub fn new() -> (Self, EmulatorClient) {
 | 
					    fn new(commands: mpsc::Receiver<EmulatorCommand>) -> Result<Self> {
 | 
				
			||||||
        let (sink, source) = mpsc::channel();
 | 
					        Ok(Self {
 | 
				
			||||||
        let emu = Emulator {
 | 
					 | 
				
			||||||
            sim: CoreVB::new(),
 | 
					            sim: CoreVB::new(),
 | 
				
			||||||
            commands: source,
 | 
					            audio: Audio::init()?,
 | 
				
			||||||
 | 
					            commands,
 | 
				
			||||||
            renderer: None,
 | 
					            renderer: None,
 | 
				
			||||||
        };
 | 
					        })
 | 
				
			||||||
        let queue = EmulatorClient { queue: sink };
 | 
					 | 
				
			||||||
        (emu, queue)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn load_rom(&mut self, path: &Path) -> Result<()> {
 | 
					    pub fn load_rom(&mut self, path: &Path) -> Result<()> {
 | 
				
			||||||
| 
						 | 
					@ -34,6 +65,7 @@ impl Emulator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn run(&mut self) {
 | 
					    pub fn run(&mut self) {
 | 
				
			||||||
        let mut eye_contents = vec![0u8; 384 * 224 * 2];
 | 
					        let mut eye_contents = vec![0u8; 384 * 224 * 2];
 | 
				
			||||||
 | 
					        let mut audio_samples = vec![];
 | 
				
			||||||
        loop {
 | 
					        loop {
 | 
				
			||||||
            self.sim.emulate_frame();
 | 
					            self.sim.emulate_frame();
 | 
				
			||||||
            if let Some(renderer) = &mut self.renderer {
 | 
					            if let Some(renderer) = &mut self.renderer {
 | 
				
			||||||
| 
						 | 
					@ -41,6 +73,11 @@ impl Emulator {
 | 
				
			||||||
                    renderer.render(&eye_contents);
 | 
					                    renderer.render(&eye_contents);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            self.sim.read_samples(&mut audio_samples);
 | 
				
			||||||
 | 
					            if !audio_samples.is_empty() {
 | 
				
			||||||
 | 
					                self.audio.update(&audio_samples);
 | 
				
			||||||
 | 
					                audio_samples.clear();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            loop {
 | 
					            loop {
 | 
				
			||||||
                match self.commands.try_recv() {
 | 
					                match self.commands.try_recv() {
 | 
				
			||||||
                    Ok(command) => self.handle_command(command),
 | 
					                    Ok(command) => self.handle_command(command),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,11 @@ use std::{path::PathBuf, thread};
 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
use app::App;
 | 
					use app::App;
 | 
				
			||||||
use clap::Parser;
 | 
					use clap::Parser;
 | 
				
			||||||
use emulator::Emulator;
 | 
					use emulator::EmulatorBuilder;
 | 
				
			||||||
use winit::event_loop::{ControlFlow, EventLoop};
 | 
					use winit::event_loop::{ControlFlow, EventLoop};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod app;
 | 
					mod app;
 | 
				
			||||||
 | 
					mod audio;
 | 
				
			||||||
mod emulator;
 | 
					mod emulator;
 | 
				
			||||||
mod renderer;
 | 
					mod renderer;
 | 
				
			||||||
mod shrooms_vb_core;
 | 
					mod shrooms_vb_core;
 | 
				
			||||||
| 
						 | 
					@ -19,9 +20,10 @@ struct Args {
 | 
				
			||||||
fn main() -> Result<()> {
 | 
					fn main() -> Result<()> {
 | 
				
			||||||
    let args = Args::parse();
 | 
					    let args = Args::parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (mut emulator, client) = Emulator::new();
 | 
					    let (builder, client) = EmulatorBuilder::new();
 | 
				
			||||||
    emulator.load_rom(&args.rom)?;
 | 
					    let builder = builder.with_rom(&args.rom);
 | 
				
			||||||
    thread::spawn(move || {
 | 
					    thread::spawn(move || {
 | 
				
			||||||
 | 
					        let mut emulator = builder.build().unwrap();
 | 
				
			||||||
        emulator.run();
 | 
					        emulator.run();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
use std::{ffi::c_void, ptr};
 | 
					use std::{ffi::c_void, ptr, slice};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use anyhow::{anyhow, Result};
 | 
					use anyhow::{anyhow, Result};
 | 
				
			||||||
 | 
					use num_derive::{FromPrimitive, ToPrimitive};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[repr(C)]
 | 
					#[repr(C)]
 | 
				
			||||||
struct VB {
 | 
					struct VB {
 | 
				
			||||||
| 
						 | 
					@ -9,6 +10,20 @@ struct VB {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(non_camel_case_types)]
 | 
					#[allow(non_camel_case_types)]
 | 
				
			||||||
type c_int = i32;
 | 
					type c_int = i32;
 | 
				
			||||||
 | 
					#[allow(non_camel_case_types)]
 | 
				
			||||||
 | 
					type c_uint = u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[repr(u32)]
 | 
				
			||||||
 | 
					#[derive(FromPrimitive, ToPrimitive)]
 | 
				
			||||||
 | 
					enum VBDataType {
 | 
				
			||||||
 | 
					    S8 = 0,
 | 
				
			||||||
 | 
					    U8 = 1,
 | 
				
			||||||
 | 
					    S16 = 2,
 | 
				
			||||||
 | 
					    U16 = 3,
 | 
				
			||||||
 | 
					    S32 = 4,
 | 
				
			||||||
 | 
					    F32 = 5,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type OnFrame = extern "C" fn(sim: *mut VB) -> c_int;
 | 
					type OnFrame = extern "C" fn(sim: *mut VB) -> c_int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[link(name = "vb")]
 | 
					#[link(name = "vb")]
 | 
				
			||||||
| 
						 | 
					@ -27,6 +42,13 @@ extern "C" {
 | 
				
			||||||
        right_stride_x: c_int,
 | 
					        right_stride_x: c_int,
 | 
				
			||||||
        right_stride_y: c_int,
 | 
					        right_stride_y: c_int,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    #[link_name = "vbGetSamples"]
 | 
				
			||||||
 | 
					    fn vb_get_samples(
 | 
				
			||||||
 | 
					        sim: *mut VB,
 | 
				
			||||||
 | 
					        typ_: *mut VBDataType,
 | 
				
			||||||
 | 
					        capacity: *mut c_uint,
 | 
				
			||||||
 | 
					        position: *mut c_uint,
 | 
				
			||||||
 | 
					    ) -> *mut c_void;
 | 
				
			||||||
    #[link_name = "vbGetUserData"]
 | 
					    #[link_name = "vbGetUserData"]
 | 
				
			||||||
    fn vb_get_user_data(sim: *mut VB) -> *mut c_void;
 | 
					    fn vb_get_user_data(sim: *mut VB) -> *mut c_void;
 | 
				
			||||||
    #[link_name = "vbInit"]
 | 
					    #[link_name = "vbInit"]
 | 
				
			||||||
| 
						 | 
					@ -39,6 +61,13 @@ extern "C" {
 | 
				
			||||||
    fn vb_set_keys(sim: *mut VB, keys: u16) -> u16;
 | 
					    fn vb_set_keys(sim: *mut VB, keys: u16) -> u16;
 | 
				
			||||||
    #[link_name = "vbSetFrameCallback"]
 | 
					    #[link_name = "vbSetFrameCallback"]
 | 
				
			||||||
    fn vb_set_frame_callback(sim: *mut VB, on_frame: OnFrame);
 | 
					    fn vb_set_frame_callback(sim: *mut VB, on_frame: OnFrame);
 | 
				
			||||||
 | 
					    #[link_name = "vbSetSamples"]
 | 
				
			||||||
 | 
					    fn vb_set_samples(
 | 
				
			||||||
 | 
					        sim: *mut VB,
 | 
				
			||||||
 | 
					        samples: *mut c_void,
 | 
				
			||||||
 | 
					        typ_: VBDataType,
 | 
				
			||||||
 | 
					        capacity: c_uint,
 | 
				
			||||||
 | 
					    ) -> c_int;
 | 
				
			||||||
    #[link_name = "vbSetUserData"]
 | 
					    #[link_name = "vbSetUserData"]
 | 
				
			||||||
    fn vb_set_user_data(sim: *mut VB, tag: *mut c_void);
 | 
					    fn vb_set_user_data(sim: *mut VB, tag: *mut c_void);
 | 
				
			||||||
    #[link_name = "vbSizeOf"]
 | 
					    #[link_name = "vbSizeOf"]
 | 
				
			||||||
| 
						 | 
					@ -53,6 +82,9 @@ extern "C" fn on_frame(sim: *mut VB) -> i32 {
 | 
				
			||||||
    1
 | 
					    1
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AUDIO_CAPACITY_SAMPLES: usize = 834 * 4;
 | 
				
			||||||
 | 
					const AUDIO_CAPACITY_FLOATS: usize = AUDIO_CAPACITY_SAMPLES * 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct VBState {
 | 
					struct VBState {
 | 
				
			||||||
    frame_seen: bool,
 | 
					    frame_seen: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -79,6 +111,11 @@ impl CoreVB {
 | 
				
			||||||
        unsafe { vb_set_user_data(sim, Box::into_raw(Box::new(state)).cast()) };
 | 
					        unsafe { vb_set_user_data(sim, Box::into_raw(Box::new(state)).cast()) };
 | 
				
			||||||
        unsafe { vb_set_frame_callback(sim, on_frame) };
 | 
					        unsafe { vb_set_frame_callback(sim, on_frame) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // set up audio buffer
 | 
				
			||||||
 | 
					        let audio_buffer = vec![0.0f32; AUDIO_CAPACITY_FLOATS];
 | 
				
			||||||
 | 
					        let samples: *mut c_void = Box::into_raw(audio_buffer.into_boxed_slice()).cast();
 | 
				
			||||||
 | 
					        unsafe { vb_set_samples(sim, samples, VBDataType::F32, AUDIO_CAPACITY_SAMPLES as u32) };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CoreVB { sim }
 | 
					        CoreVB { sim }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,6 +175,25 @@ impl CoreVB {
 | 
				
			||||||
        true
 | 
					        true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn read_samples(&mut self, samples: &mut Vec<f32>) {
 | 
				
			||||||
 | 
					        let mut position = 0;
 | 
				
			||||||
 | 
					        let ptr =
 | 
				
			||||||
 | 
					            unsafe { vb_get_samples(self.sim, ptr::null_mut(), ptr::null_mut(), &mut position) };
 | 
				
			||||||
 | 
					        // SAFETY: position is an offset in a buffer of (f32, f32). so, position * 2 is an offset in a buffer of f32.
 | 
				
			||||||
 | 
					        let read_samples: &mut [f32] =
 | 
				
			||||||
 | 
					            unsafe { slice::from_raw_parts_mut(ptr.cast(), position as usize * 2) };
 | 
				
			||||||
 | 
					        samples.extend_from_slice(read_samples);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsafe {
 | 
				
			||||||
 | 
					            vb_set_samples(
 | 
				
			||||||
 | 
					                self.sim,
 | 
				
			||||||
 | 
					                ptr,
 | 
				
			||||||
 | 
					                VBDataType::F32,
 | 
				
			||||||
 | 
					                AUDIO_CAPACITY_SAMPLES as u32,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn set_keys(&mut self, keys: u16) {
 | 
					    pub fn set_keys(&mut self, keys: u16) {
 | 
				
			||||||
        unsafe { vb_set_keys(self.sim, keys) };
 | 
					        unsafe { vb_set_keys(self.sim, keys) };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -145,6 +201,14 @@ impl CoreVB {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Drop for CoreVB {
 | 
					impl Drop for CoreVB {
 | 
				
			||||||
    fn drop(&mut self) {
 | 
					    fn drop(&mut self) {
 | 
				
			||||||
 | 
					        let ptr =
 | 
				
			||||||
 | 
					            unsafe { vb_get_samples(self.sim, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()) };
 | 
				
			||||||
 | 
					        // SAFETY: the audio buffer originally came from a Vec<u32>
 | 
				
			||||||
 | 
					        let floats: Vec<f32> = unsafe {
 | 
				
			||||||
 | 
					            Vec::from_raw_parts(ptr.cast(), AUDIO_CAPACITY_FLOATS, AUDIO_CAPACITY_FLOATS)
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        drop(floats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // SAFETY: the *mut VB owns its userdata.
 | 
					        // SAFETY: the *mut VB owns its userdata.
 | 
				
			||||||
        // There is no way for the userdata to be null or otherwise invalid.
 | 
					        // There is no way for the userdata to be null or otherwise invalid.
 | 
				
			||||||
        let ptr: *mut VBState = unsafe { vb_get_user_data(self.sim).cast() };
 | 
					        let ptr: *mut VBState = unsafe { vb_get_user_data(self.sim).cast() };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue