From 98d6e82397d8a7cfd0e05f19acf10b160695bdd6 Mon Sep 17 00:00:00 2001 From: Skyler Lehmkuhl Date: Sat, 25 Jan 2025 04:10:04 -0500 Subject: [PATCH] More work on Rust --- lightningbeam-core/Cargo.lock | 458 +++++++++++--------------------- lightningbeam-core/Cargo.toml | 7 +- lightningbeam-core/build.sh | 3 + lightningbeam-core/src/audio.rs | 191 +++++++------ lightningbeam-core/src/lib.rs | 215 ++++++++++++--- lightningbeam-core/src/time.rs | 29 ++ 6 files changed, 483 insertions(+), 420 deletions(-) create mode 100755 lightningbeam-core/build.sh diff --git a/lightningbeam-core/Cargo.lock b/lightningbeam-core/Cargo.lock index 9db978d..d3c70be 100644 --- a/lightningbeam-core/Cargo.lock +++ b/lightningbeam-core/Cargo.lock @@ -13,14 +13,14 @@ dependencies = [ [[package]] name = "alsa" -version = "0.6.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" dependencies = [ "alsa-sys", - "bitflags 1.3.2", + "bitflags 2.8.0", + "cfg-if", "libc", - "nix", ] [[package]] @@ -33,18 +33,18 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "bindgen" version = "0.70.1" @@ -60,7 +60,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.96", + "syn", ] [[package]] @@ -158,11 +158,12 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "coreaudio-rs" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" dependencies = [ "bitflags 1.3.2", + "core-foundation-sys", "coreaudio-sys", ] @@ -177,33 +178,32 @@ dependencies = [ [[package]] name = "cpal" -version = "0.14.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f342c1b63e185e9953584ff2199726bf53850d96610a310e3aca09e9405a2d0b" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" dependencies = [ "alsa", "core-foundation-sys", "coreaudio-rs", + "dasp_sample", "jni", "js-sys", "libc", - "mach", - "ndk 0.7.0", + "mach2", + "ndk", "ndk-context", "oboe", - "once_cell", - "parking_lot", - "stdweb", - "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", "windows", ] [[package]] -name = "discard" -version = "1.0.4" +name = "dasp_sample" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" [[package]] name = "either" @@ -248,24 +248,20 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - [[package]] name = "jni" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys", "log", "thiserror", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -306,30 +302,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "lightningbeam-core" version = "0.1.0" dependencies = [ + "anyhow", "console_error_panic_hook", "cpal", + "log", "serde", "wasm-bindgen", + "wasm-logger", "web-sys", ] -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.25" @@ -337,10 +326,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] -name = "mach" -version = "0.3.2" +name = "mach2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] @@ -351,15 +340,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -368,31 +348,18 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "ndk" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.8.0", "jni-sys", - "ndk-sys 0.3.0", + "log", + "ndk-sys", "num_enum", "thiserror", ] -[[package]] -name = "ndk" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" -dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys 0.4.1+23.1.7779620", - "num_enum", - "raw-window-handle", - "thiserror", -] - [[package]] name = "ndk-context" version = "0.1.1" @@ -401,35 +368,13 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.3.0" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ "jni-sys", ] -[[package]] -name = "ndk-sys" -version = "0.4.1+23.1.7779620" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "nix" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if", - "libc", - "memoffset", -] - [[package]] name = "nom" version = "7.1.3" @@ -442,13 +387,13 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -462,33 +407,33 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "oboe" -version = "0.4.6" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ "jni", - "ndk 0.6.0", + "ndk", "ndk-context", "num-derive", "num-traits", @@ -497,9 +442,9 @@ dependencies = [ [[package]] name = "oboe-sys" -version = "0.4.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" dependencies = [ "cc", ] @@ -510,29 +455,6 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - [[package]] name = "pkg-config" version = "0.3.31" @@ -567,21 +489,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "redox_syscall" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" -dependencies = [ - "bitflags 2.8.0", -] - [[package]] name = "regex" version = "1.11.1" @@ -617,27 +524,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - [[package]] name = "rustversion" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - [[package]] name = "same-file" version = "1.0.6" @@ -647,27 +539,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.217" @@ -685,108 +556,15 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn", ] -[[package]] -name = "serde_json" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.96" @@ -815,7 +593,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn", ] [[package]] @@ -873,10 +651,23 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.96", + "syn", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.100" @@ -895,7 +686,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -909,6 +700,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-logger" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" +dependencies = [ + "log", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.77" @@ -925,20 +727,45 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "windows" -version = "0.37.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" dependencies = [ - "windows_aarch64_msvc 0.37.0", - "windows_i686_gnu 0.37.0", - "windows_i686_msvc 0.37.0", - "windows_x86_64_gnu 0.37.0", - "windows_x86_64_msvc 0.37.0", + "windows-core", + "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]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", ] [[package]] @@ -947,7 +774,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -956,16 +798,22 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -974,9 +822,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.37.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" @@ -986,9 +834,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.37.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" @@ -1004,9 +852,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.37.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" @@ -1016,9 +864,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.37.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" @@ -1026,6 +874,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -1034,9 +888,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.37.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" diff --git a/lightningbeam-core/Cargo.toml b/lightningbeam-core/Cargo.toml index d34a84e..a6badae 100644 --- a/lightningbeam-core/Cargo.toml +++ b/lightningbeam-core/Cargo.toml @@ -8,8 +8,11 @@ crate-type = ["cdylib", "rlib"] [dependencies] serde = { version = "1.0", features = ["derive"] } -wasm-bindgen = "0.2" -cpal = "0.14" +wasm-bindgen = "0.2.45" +cpal = { version = "0.15", features = ["wasm-bindgen"] } +anyhow = "1.0" +wasm-logger = "0.2" +log = "0.4" [dependencies.web-sys] version = "0.3.22" diff --git a/lightningbeam-core/build.sh b/lightningbeam-core/build.sh new file mode 100755 index 0000000..efac65a --- /dev/null +++ b/lightningbeam-core/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd core +wasm-pack build --target web --out-dir ../src/pkg --features wasm diff --git a/lightningbeam-core/src/audio.rs b/lightningbeam-core/src/audio.rs index 16a7dba..4166a88 100644 --- a/lightningbeam-core/src/audio.rs +++ b/lightningbeam-core/src/audio.rs @@ -1,25 +1,93 @@ use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -use cpal::{SampleFormat, SampleRate, Stream, StreamConfig}; -use cpal::{BufferSize, SupportedBufferSize}; +use cpal::{Sample, SampleFormat, StreamConfig, SupportedBufferSize, SampleRate, BufferSize}; use std::sync::{Arc, Mutex}; -use crate::AudioOutput; +use crate::{TrackManager, Timestamp, Duration, SampleCount, AudioOutput, PlaybackState}; + +// #[cfg(feature = "wasm")] +// use wasm_bindgen::prelude::*; + +// #[cfg(feature="wasm")] +// #[wasm_bindgen] pub struct CpalAudioOutput { - stream: Option, - buffer: Arc>>, // Shared buffer for audio chunks + track_manager: Option>>, + _stream: Option, + playback_state: PlaybackState, + timestamp: Arc>, + chunk_size: usize, sample_rate: u32, - channels: u16, } +// #[cfg(feature="wasm")] +// #[wasm_bindgen] impl CpalAudioOutput { - pub fn new(sample_rate: u32, channels: u16) -> Self { + pub fn new() -> Self { Self { - stream: None, - buffer: Arc::new(Mutex::new(Vec::new())), - sample_rate, - channels, + track_manager: None, + _stream: None, + playback_state: PlaybackState::Stopped, + timestamp: Arc::new(Mutex::new(Timestamp::from_seconds(0.0))), + chunk_size: 0, + sample_rate: 44100, // Default sample rate, updated later } } + + fn build_stream( + &mut self, + device: &cpal::Device, + config: cpal::SupportedStreamConfig, +) -> Result +where + T: Sample + From + cpal::SizedSample, +{ + let supported_config = config.config(); + self.sample_rate = supported_config.sample_rate.0; + let num_channels = supported_config.channels as usize; // Get channel count + + let track_manager = self.track_manager.clone(); + let playback_state = self.playback_state.clone(); + let timestamp = self.timestamp.clone(); + let sample_rate = self.sample_rate; + + let err_fn = |err| eprintln!("Audio stream error: {:?}", err); + + let stream = device.build_output_stream( + &supported_config, + move |data: &mut [T], _: &cpal::OutputCallbackInfo| { + if let Some(track_manager) = &track_manager { + let num_frames = data.len() / num_channels; // Stereo: divide by 2 + let sample_count = SampleCount::new(num_frames); + let chunk_duration = Duration::new(num_frames as f64 / sample_rate as f64); + + let mut track_manager = track_manager.lock().unwrap(); + let playing = matches!(playback_state, PlaybackState::Playing); + + let mut timestamp_guard = timestamp.lock().unwrap(); + let timestamp = &mut *timestamp_guard; + + let chunk = track_manager.update_audio( + timestamp.clone(), + playing, + sample_count, + sample_rate, + ); + + // Write samples (interleaved stereo) + for (i, frame) in chunk.iter().enumerate() { + let sample = T::from(*frame); + data[i * num_channels] = sample; // Left channel + data[i * num_channels + 1] = sample; // Right channel (or process separately) + } + + *timestamp_guard += chunk_duration; + } + }, + err_fn, + None, + )?; + + Ok(stream) + } } impl AudioOutput for CpalAudioOutput { @@ -27,79 +95,34 @@ impl AudioOutput for CpalAudioOutput { let host = cpal::default_host(); let device = host .default_output_device() - .ok_or("No output device available")?; - let supported_config = device - .default_output_config().unwrap(); - // .with_sample_rate(SampleRate(self.sample_rate)); - let config = StreamConfig { - channels: self.channels, - sample_rate: SampleRate(self.sample_rate), - buffer_size: match supported_config.buffer_size() { - SupportedBufferSize::Range { min, max: _ } => BufferSize::Fixed(*min), - SupportedBufferSize::Unknown => BufferSize::Default, - }, - }; - - let buffer = self.buffer.clone(); - let sample_format = supported_config.sample_format(); - - let stream = match sample_format { - SampleFormat::F32 => device.build_output_stream( - &config, - move |data: &mut [f32], _| { - let mut buffer = buffer.lock().unwrap(); - for (out_sample, buffer_sample) in data.iter_mut().zip(buffer.iter()) { - *out_sample = *buffer_sample; - } - buffer.clear(); // Clear buffer after playback - }, - move |err| { - eprintln!("Audio stream error: {:?}", err); - }, - ), - SampleFormat::I16 => device.build_output_stream( - &config, - move |data: &mut [i16], _| { - let mut buffer = buffer.lock().unwrap(); - for (out_sample, buffer_sample) in data.iter_mut().zip(buffer.iter()) { - *out_sample = (*buffer_sample * i16::MAX as f32) as i16; - } - buffer.clear(); - }, - move |err| { - eprintln!("Audio stream error: {:?}", err); - }, - ), - SampleFormat::U16 => device.build_output_stream( - &config, - move |data: &mut [u16], _| { - let mut buffer = buffer.lock().unwrap(); - for (out_sample, buffer_sample) in data.iter_mut().zip(buffer.iter()) { - *out_sample = ((*buffer_sample + 1.0) * 0.5 * u16::MAX as f32) as u16; - } - buffer.clear(); - }, - move |err| { - eprintln!("Audio stream error: {:?}", err); - }, - ), - }; - - // If the stream creation failed, return the error - let stream = stream.map_err(|e| { - format!( - "Failed to build output stream for sample format {:?}: {:?}", - sample_format, e - ) - })?; - - stream.play()?; - self.stream = Some(stream); + .ok_or_else(|| "No output device available")?; + let supported_config = device.default_output_config()?; + self._stream = Some(self.build_stream::(&device, supported_config)?); + if let Some(stream) = self._stream.as_ref() { + stream.play().unwrap(); + } else { + eprintln!("Stream is not initialized!"); + } Ok(()) } - - fn play_chunk(&mut self, chunk: Vec) { - let mut buffer = self.buffer.lock().unwrap(); - buffer.extend(chunk); + + fn play(&mut self, start_timestamp: Timestamp) { + self.timestamp.lock().unwrap().set(start_timestamp); + self.playback_state = PlaybackState::Playing; } -} \ No newline at end of file + + fn stop(&mut self) { + self.playback_state = PlaybackState::Stopped; + } + + fn register_track_manager(&mut self, track_manager: Arc>) { + self.track_manager = Some(track_manager); + } + + fn get_timestamp(&mut self) -> Timestamp { + *self.timestamp.lock().unwrap() + } + fn set_chunk_size(&mut self, chunk_size: usize) { + self.chunk_size = chunk_size + } +} diff --git a/lightningbeam-core/src/lib.rs b/lightningbeam-core/src/lib.rs index a3d36e2..0912adc 100644 --- a/lightningbeam-core/src/lib.rs +++ b/lightningbeam-core/src/lib.rs @@ -1,20 +1,30 @@ mod time; -use time::{Timestamp, Duration, Frame}; +use time::{Timestamp, Duration, Frame, SampleCount}; mod audio; use audio::{CpalAudioOutput}; +use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError}; + +use std::sync::{Arc, Mutex}; #[cfg(feature = "wasm")] -use wasm_bindgen::prelude::*; +mod wasm_imports { + pub use wasm_bindgen::prelude::*; + pub use web_sys::console; + use wasm_logger; +} +#[cfg(feature = "wasm")] +use wasm_imports::*; -pub trait AudioTrack { + +pub trait AudioTrack: Send { /// Render a chunk of audio for the given timestamp and duration. - fn render_chunk(&self, timestamp: Timestamp, duration: Duration) -> Vec; + fn render_chunk(&mut self, timestamp: Timestamp, duration: SampleCount) -> Vec; /// Get the sample rate of the audio track. fn sample_rate(&self) -> u32; } -pub trait VideoTrack { +pub trait VideoTrack: Send { /// Render a frame for the given timestamp. fn render_frame(&self, timestamp: Timestamp) -> Frame; @@ -25,8 +35,10 @@ pub trait VideoTrack { pub struct TrackManager { audio_tracks: Vec>, video_tracks: Vec>, - sample_rate: u32, - frame_duration: Duration, // Duration of each frame in seconds (e.g., 1/60 for 60 FPS) + // sample_rate: u32, + // frame_duration: Duration, // Duration of each frame in seconds (e.g., 1/60 for 60 FPS) + timestamp: Timestamp, + playback_state: PlaybackState, } impl TrackManager { @@ -34,8 +46,10 @@ impl TrackManager { Self { audio_tracks: Vec::new(), video_tracks: Vec::new(), - sample_rate, - frame_duration: Duration::new(frame_duration), + // sample_rate, + // frame_duration: Duration::new(frame_duration), + playback_state: PlaybackState::Stopped, + timestamp: Timestamp::from_seconds(0.0), } } @@ -46,47 +60,180 @@ impl TrackManager { pub fn add_video_track(&mut self, track: Box) { self.video_tracks.push(track); } + + pub fn play(&mut self, start_timestamp: Timestamp) { + self.timestamp = start_timestamp; + self.playback_state = PlaybackState::Playing; + } + + pub fn stop(&mut self) { + self.playback_state = PlaybackState::Stopped; + } - pub fn play(&mut self, timestamp: Timestamp, audio_output: &mut dyn AudioOutput, video_output: &mut dyn FrameTarget) { - let mut timestamp = timestamp.clone(); + // pub fn play(&mut self, timestamp: Timestamp, audio_output: &mut dyn AudioOutput, video_output: &mut dyn FrameTarget) { + // let mut timestamp = timestamp.clone(); - // Main playback loop - loop { - // Render and play audio chunks - let mut audio_mix: Vec = vec![0.0; self.frame_duration.to_samples(self.sample_rate) as usize]; - for track in &mut self.audio_tracks { - let chunk = track.render_chunk(timestamp, self.frame_duration); - for (i, sample) in chunk.iter().enumerate() { - audio_mix[i] += sample; // Simple mixing (sum of samples) - } - } - audio_output.play_chunk(audio_mix); + // // Main playback loop + // loop { + // // Render and play audio chunks + // let mut audio_mix: Vec = vec![0.0; self.frame_duration.to_samples(self.sample_rate) as usize]; + // for track in &mut self.audio_tracks { + // let chunk = track.render_chunk(timestamp, self.frame_duration); + // for (i, sample) in chunk.iter().enumerate() { + // audio_mix[i] += sample; // Simple mixing (sum of samples) + // } + // } + // audio_output.play_chunk(audio_mix); - // Render video frames - for track in &self.video_tracks { - let track_frame = track.render_frame(timestamp); - } + // // Render video frames + // for track in &self.video_tracks { + // let track_frame = track.render_frame(timestamp); + // } - // Update timestamp - timestamp += self.frame_duration; + // // Update timestamp + // timestamp += self.frame_duration; - // Break condition (e.g., end of tracks) - if self.audio_tracks.iter().all(|t| t.render_chunk(timestamp, self.frame_duration).is_empty()) { - break; + // // Break condition (e.g., end of tracks) + // if self.audio_tracks.iter().all(|t| t.render_chunk(timestamp, self.frame_duration).is_empty()) { + // break; + // } + // } + // } + pub fn update_audio(&mut self, timestamp: Timestamp, playing: bool, chunk_size: SampleCount, sample_rate: u32) -> Vec { + let mut mixed_audio = vec![0.0; chunk_size.as_usize()]; + + // TODO: render video + for track in &mut self.audio_tracks { + let track_audio = track.render_chunk(timestamp, chunk_size); + for (i, sample) in track_audio.iter().enumerate() { + mixed_audio[i] += *sample; // Simple mixing, add samples together } } + + mixed_audio } } pub trait AudioOutput { fn start(&mut self) -> Result<(), Box>; - fn play_chunk(&mut self, chunk: Vec); + fn play(&mut self, start_timestamp: Timestamp); + fn stop(&mut self); + fn register_track_manager(&mut self, track_manager: Arc>); + fn get_timestamp(&mut self) -> Timestamp; + fn set_chunk_size(&mut self, chunk_size: usize); } pub trait FrameTarget { fn draw(&mut self, frame: &[u8], width: u32, height: u32); } +#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] +enum PlaybackState { + Playing, + Stopped, +} + +pub struct SineWaveTrack { + frequency: f32, + phase: f32, + sample_rate: u32, +} + +impl SineWaveTrack { + pub fn new(frequency: f32, sample_rate: u32) -> Self { + Self { + frequency, + phase: 0.0, + sample_rate, + } + } +} + +impl AudioTrack for SineWaveTrack { + fn render_chunk(&mut self, timestamp: Timestamp, chunk_size: SampleCount) -> Vec { + let mut chunk = Vec::with_capacity(chunk_size.as_usize()); + let phase_increment = (2.0 * std::f32::consts::PI * self.frequency) / self.sample_rate as f32; + + for _ in 0..chunk_size.as_usize() { + chunk.push((self.phase).sin()); + self.phase += phase_increment; + if self.phase > 2.0 * std::f32::consts::PI { + self.phase -= 2.0 * std::f32::consts::PI; + } + } + + chunk + } + fn sample_rate(&self) -> u32 { + self.sample_rate + } +} + + +#[cfg(feature="wasm")] +#[wasm_bindgen] +pub struct CoreInterface { + #[wasm_bindgen(skip)] + track_manager: Arc>, + #[wasm_bindgen(skip)] + cpal_audio_output: Box, +} + +#[cfg(feature="wasm")] +#[wasm_bindgen] +impl CoreInterface { + #[wasm_bindgen(constructor)] + pub fn new(sample_rate: u32, frame_duration: f64) -> Self { + Self { + track_manager: Arc::new(Mutex::new(TrackManager::new(sample_rate, frame_duration))), + cpal_audio_output: Box::new(CpalAudioOutput::new()) + } + } + pub fn init(&mut self) { + println!("Init CoreInterface"); + let track_manager_clone = self.track_manager.clone(); + self.cpal_audio_output.register_track_manager(track_manager_clone); + self.cpal_audio_output.start(); + } + pub fn play(&mut self, timestamp: f64) { + // Lock the Mutex to get access to TrackManager + let mut track_manager = self.track_manager.lock().unwrap(); + track_manager.play(Timestamp::new(timestamp)); + } + pub fn get_timestamp(&mut self) -> f64 { + self.cpal_audio_output.get_timestamp().as_seconds() + } +} + + +struct PlainTextLogger; + +impl Log for PlainTextLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Info + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + console::log_1(&format!( + "{} [{}:{}] {}", + record.level(), + record.file().unwrap_or("unknown"), + record.line().unwrap_or(0), + record.args() + ).into()); + } + } + + fn flush(&self) {} +} + +pub fn init_plain_text_logger() -> Result<(), SetLoggerError> { + log::set_boxed_logger(Box::new(PlainTextLogger))?; + log::set_max_level(LevelFilter::Info); + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -106,6 +253,10 @@ pub fn main_js() -> Result<(), JsValue> { // It's disabled in release mode so it doesn't bloat up the file size. #[cfg(debug_assertions)] console_error_panic_hook::set_once(); + init_plain_text_logger().expect("Failed to initialize plain text logger"); + + + log::info!("Logger initialized!"); Ok(()) } \ No newline at end of file diff --git a/lightningbeam-core/src/time.rs b/lightningbeam-core/src/time.rs index 4f21a13..c014ced 100644 --- a/lightningbeam-core/src/time.rs +++ b/lightningbeam-core/src/time.rs @@ -6,12 +6,21 @@ pub struct Timestamp(f64); #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] pub struct Duration(f64); +/// A strongly-typed representation of a number of samples. +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +pub struct SampleCount(usize); + impl Timestamp { /// Create a new timestamp in seconds. pub fn new(seconds: f64) -> Self { Timestamp(seconds) } + /// Create a new timestamp from seconds. (dummy method) + pub fn from_seconds(seconds: f64) -> Self { + Timestamp(seconds) + } + /// Create a new timestamp from milliseconds. pub fn from_millis(milliseconds: u64) -> Self { Timestamp(milliseconds as f64 / 1000.0) @@ -41,6 +50,10 @@ impl Timestamp { pub fn subtract_timestamp(&self, other: Timestamp) -> Duration { Duration(self.0 - other.0) } + + pub fn set(&mut self, other: Timestamp) { + self.0 = other.as_seconds(); + } } impl Duration { @@ -79,6 +92,10 @@ impl Duration { (self.0 * sample_rate as f64).round() as u64 } + pub fn to_std(&self) -> std::time::Duration { + std::time::Duration::from_nanos((self.0/1_000_000_000.0).round() as u64) + } + /// Add two durations together. pub fn add(&self, other: Duration) -> Duration { Duration(self.0 + other.0) @@ -90,6 +107,18 @@ impl Duration { } } + +impl SampleCount { + /// Create a new count of samples. + pub fn new(samples: usize) -> Self { + SampleCount(samples) + } + + pub fn as_usize(&self) -> usize { + self.0 + } +} + // Overloading operators for more natural usage use std::ops::{Add, Sub, AddAssign, SubAssign};