diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..ee0584d --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.x86_64-unknown-linux-gnu] +rustflags = ["-C", "target-cpu=native"] diff --git a/.gitignore b/.gitignore index 088ba6b..676c9ca 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock +# Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..dec4330 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2685 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5110f1c78cf582855d895ecd0746b653db010cec6d9f5575293f27934d980a39" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +dependencies = [ + "android-properties", + "bitflags 1.3.2", + "cc", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum 0.6.1", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "anstream" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arboard" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac57f2b058a76363e357c056e4f74f1945bf734d37b8b3ef49066c4787dde0fc" +dependencies = [ + "clipboard-win", + "log", + "objc", + "objc-foundation", + "objc_id", + "parking_lot", + "thiserror", + "winapi", + "x11rb", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix 0.37.23", + "slab", + "socket2 0.4.9", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + +[[package]] +name = "atomic_refcell" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112ef6b3f6cb3cb6fc5b6b494ef7a848492cff1ab0ef4de10b0f7d572861c905" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-sys" +version = "0.1.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" +dependencies = [ + "block-sys", + "objc2-encode", +] + +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "log", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "calloop" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" +dependencies = [ + "bitflags 1.3.2", + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "clap" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "clap_lex" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" + +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.0", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "ecolor" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e479a7fa3f23d4e794f8b2f8b3568dd4e47886ad1b12c9c095e141cb591eb63" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "eframe" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4596583a2c680c55b6feaa748f74890c4f9cb9c7cb69d6117110444cb65b2f" +dependencies = [ + "bytemuck", + "cocoa", + "egui", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "glutin-winit", + "image", + "js-sys", + "log", + "objc", + "percent-encoding", + "raw-window-handle", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winapi", + "winit", +] + +[[package]] +name = "egui" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3aef8ec3ae1b772f340170c65bf27d5b8c28f543a0116c844d2ac08d01123e7" +dependencies = [ + "ahash", + "epaint", + "log", + "nohash-hasher", +] + +[[package]] +name = "egui-winit" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a49155fd4a0a4fb21224407a91de0030847972ef90fc64edb63621caea61cb2" +dependencies = [ + "arboard", + "egui", + "instant", + "log", + "raw-window-handle", + "smithay-clipboard", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_glow" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8c2752cdf1b0ef5fcda59a898cacabad974d4f5880e92a420b2c917022da64" +dependencies = [ + "bytemuck", + "egui", + "glow", + "log", + "memoffset", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "emath" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3857d743a6e0741cdd60b622a74c7a36ea75f5f8f11b793b41d905d2c9721a4b" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "epaint" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09333964d4d57f40a85338ba3ca5ed4716070ab184dcfed966b35491c5c64f3b" +dependencies = [ + "ab_glyph", + "ahash", + "atomic_refcell", + "bytemuck", + "ecolor", + "emath", + "log", + "nohash-hasher", + "parking_lot", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "glow" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc93b03242719b8ad39fb26ed2b01737144ce7bd4bfc7adadcef806596760fe" +dependencies = [ + "bitflags 1.3.2", + "cfg_aliases", + "cgl", + "core-foundation", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading 0.7.4", + "objc2", + "once_cell", + "raw-window-handle", + "wayland-sys 0.30.1", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629a873fc04062830bfe8f97c03773bcd7b371e23bcc465d0a61448cd1588fa4" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af784eb26c5a68ec85391268e074f0aa618c096eadb5d6330b0911cf34fe57c5" +dependencies = [ + "gl_generator", + "windows-sys 0.45.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b53cb5fe568964aa066a3ba91eac5ecbac869fb0842cd0dc9e412434f1a1494" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef89398e90033fc6bc65e9bd42fd29bbbfd483bda5b56dc5562f455550618165" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idsp" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43632fb78a5a307efb78ae8c3c11961ec1528de34bc034d94801b1ec3465e9e5" +dependencies = [ + "num-complex", + "num-traits", + "serde", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-rational", + "num-traits", + "png", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.11", + "windows-sys 0.48.0", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", +] + +[[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", + "num_enum 0.5.11", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[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.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc-sys" +version = "0.2.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" + +[[package]] +name = "objc2" +version = "0.3.0-beta.3.patch-leaks.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +dependencies = [ + "block2", + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "orbclient" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8378ac0dfbd4e7895f2d2c1f1345cab3836910baf3a300b000d04250f0c8428f" +dependencies = [ + "redox_syscall", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primal-check" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0" +dependencies = [ + "num-integer", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rustfft" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d4f6cbdb180c9f4b2a26bbf01c4e647f1e1dea22fe8eb9db54198b32f9434" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", + "version_check", +] + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.5", + "windows-sys 0.48.0", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.24.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "stabilizer-streaming" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-std", + "bytemuck", + "clap", + "derive_builder", + "eframe", + "env_logger", + "idsp", + "log", + "ndarray", + "num_enum 0.5.11", + "rand", + "rustfft", + "serde", + "socket2 0.5.3", + "thiserror", +] + +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[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.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "tiny-skia" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "transpose" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "ttf-parser" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a464a4b34948a5f67fddd2b823c62d9d92e44be75058b99939eae6c5b6960b33" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "value-bag" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.29", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags 1.3.2", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags 1.3.2", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "wayland-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +dependencies = [ + "dlib", + "lazy_static", + "log", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2c79b77f525a2d670cb40619d7d9c673d09e0666f72c591ebd7861f84a87e57" +dependencies = [ + "core-foundation", + "home", + "jni", + "log", + "ndk-context", + "objc", + "raw-window-handle", + "url", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[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]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[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]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winit" +version = "0.28.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "866db3f712fffba75d31bf0cdecf357c8aeafd158c5b7ab51dba2a2b2d47f196" +dependencies = [ + "android-activity", + "bitflags 1.3.2", + "cfg_aliases", + "core-foundation", + "core-graphics", + "dispatch", + "instant", + "libc", + "log", + "mio", + "ndk", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall", + "sctk-adwaita", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-commons", + "wayland-protocols", + "wayland-scanner", + "web-sys", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "winnow" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507" +dependencies = [ + "gethostname", + "nix 0.24.3", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67" +dependencies = [ + "nix 0.24.3", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xml-rs" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47430998a7b5d499ccee752b41567bc3afc57e1327dc855b1a2aa44ce29b5fa1" diff --git a/Cargo.toml b/Cargo.toml index 5b4f78b..80e6f5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,35 @@ [package] name = "stabilizer-streaming" version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +authors = [ + "Robert Jördens ", + "Ryan Summers ", +] +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.67" [dependencies] -clap = "3.0.0-beta.5" +clap = { version = "4.3", features = ["derive"] } num_enum = "0.5" log = "0.4" -env_logger = "0.9" async-std = { version = "1", features = ["attributes"] } +#tide = "0.16" +serde = { version = "1", features = ["derive"] } +eframe = { version = "0.22", default-features = false, features = ["glow", "default_fonts"] } +# egui = "0.22" +# image = { version = "0.24", default-features = false, features = ["png"] } +# rfd = "0.11.0" +env_logger = "0.10" +ndarray = "0.15.6" +bytemuck = "1.13.1" +thiserror = "1.0.47" +anyhow = "1.0.75" +socket2 = "0.5.3" +idsp = "0.11.0" +rustfft = "6.1.0" +rand = "0.8.5" +derive_builder = "0.12.0" + +#[build-dependencies] +#npm_rs = "0.2.1" diff --git a/src/bin/main.rs b/src/bin/main.rs new file mode 100644 index 0000000..0874da0 --- /dev/null +++ b/src/bin/main.rs @@ -0,0 +1,202 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use anyhow::Result; +use clap::Parser; +use eframe::egui; +use eframe::egui::plot::{Legend, Line, Plot, PlotPoints}; +use std::sync::mpsc; +use std::time::Duration; + +use stabilizer_streaming::{ + source::{Source, SourceOpts}, + Break, Detrend, PsdCascade, +}; + +#[derive(Clone, Copy, Debug)] +enum Cmd { + Exit, + Reset, +} + +struct Trace { + breaks: Vec, + psd: Vec<[f64; 2]>, +} + +#[derive(Parser, Debug)] +pub struct Opts { + #[command(flatten)] + source: SourceOpts, + + #[arg(short, long, default_value_t = 4)] + min_avg: usize, +} + +fn main() -> Result<()> { + env_logger::init(); + let Opts { source, min_avg } = Opts::parse(); + + let (cmd_send, cmd_recv) = mpsc::channel(); + let (trace_send, trace_recv) = mpsc::sync_channel(1); + let receiver = std::thread::spawn(move || { + let mut source = Source::new(source)?; + let mut dec = Vec::with_capacity(4); + + let mut i = 0usize; + loop { + match cmd_recv.try_recv() { + Err(mpsc::TryRecvError::Disconnected) | Ok(Cmd::Exit) => break, + Ok(Cmd::Reset) => dec.clear(), + Err(mpsc::TryRecvError::Empty) => {} + }; + + if dec.is_empty() { + dec.extend((0..4).map(|_| { + let mut c = PsdCascade::<{ 1 << 9 }>::default(); + c.set_stage_depth(3); + c.set_detrend(Detrend::Mid); + c + })); + i = 0; + } + + match source.get() { + Ok(traces) => { + for (dec, x) in dec.iter_mut().zip(traces) { + dec.process(&x); + } + } + Err(e) => log::warn!("source: {}", e), + } + i += 1; + + if i > 200 { + i = 0; + let trace = dec + .iter() + .map_while(|dec| { + let (p, b) = dec.psd(min_avg); + if p.is_empty() { + None + } else { + let f = Break::frequencies(&b); + Some(Trace { + breaks: b, + psd: f[..f.len() - 1] // DC + .iter() + .zip(p.iter()) + .map(|(f, p)| [f.log10() as f64, 10.0 * p.log10() as f64]) + .collect(), + }) + } + }) + .collect(); + match trace_send.try_send(trace) { + Ok(()) => {} + Err(mpsc::TrySendError::Full(_)) => { + // log::warn!("full"); + } + Err(e) => { + log::error!("{:?}", e); + } + } + } + } + + source.finish(); + + Result::<()>::Ok(()) + }); + + let options = eframe::NativeOptions { + initial_window_size: Some(egui::vec2(640.0, 500.0)), + ..Default::default() + }; + eframe::run_native( + "FLS", + options, + Box::new(|cc| Box::new(FLS::new(cc, trace_recv, cmd_send))), + ) + .unwrap(); + + receiver.join().unwrap()?; + + Ok(()) +} + +pub struct FLS { + trace_recv: mpsc::Receiver>, + cmd_send: mpsc::Sender, + current: Option>, +} + +impl FLS { + fn new( + cc: &eframe::CreationContext<'_>, + trace_recv: mpsc::Receiver>, + cmd_send: mpsc::Sender, + ) -> Self { + cc.egui_ctx.set_visuals(egui::Visuals::light()); + + Self { + trace_recv, + cmd_send, + current: None, + } + } +} + +impl eframe::App for FLS { + fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) { + self.cmd_send.send(Cmd::Exit).ok(); + } + + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + match self.trace_recv.try_recv() { + Err(mpsc::TryRecvError::Empty) => {} + Ok(new) => { + self.current = Some(new); + ctx.request_repaint_after(Duration::from_millis(100)); + } + Err(mpsc::TryRecvError::Disconnected) => { + panic!("lost data processing thread") + } + }; + ui.heading("FLS"); + ui.add_space(20.0); + ui.horizontal(|ui| { + ui.add_space(20.0); + let plot = Plot::new("") + .width(600.0) + .height(400.0) + // .x_grid_spacer(log_grid_spacer(10)) + .legend(Legend::default()); + plot.show(ui, |plot_ui| { + if let Some(traces) = &mut self.current { + for (trace, name) in traces.iter().zip("ABCD".chars()) { + plot_ui.line(Line::new(PlotPoints::from(trace.psd.clone())).name(name)); + } + } + }); + }); + ui.add_space(20.0); + ui.horizontal(|ui| { + ui.add_space(20.0); + if ui.button("Reset").clicked() { + self.cmd_send.send(Cmd::Reset).unwrap(); + } + self.current + .as_ref() + .and_then(|ts| ts.get(0)) + .and_then(|t| t.breaks.get(0)) + .map(|bi| { + ui.label(format!( + "{:.2e} samples", // includes overlap + (bi.count * bi.effective_fft_size) as f32 + )) + }); + }); + }); + } +} diff --git a/src/bin/stream_test.rs b/src/bin/stream_test.rs index 15aba7c..f87bb6c 100644 --- a/src/bin/stream_test.rs +++ b/src/bin/stream_test.rs @@ -1,74 +1,82 @@ +use anyhow::Result; use clap::Parser; -use stabilizer_streaming::StreamReceiver; -use std::time::{Duration, Instant}; - -const MAX_LOSS: f32 = 0.05; +use stabilizer_streaming::{ + source::{Source, SourceOpts}, + Break, Detrend, PsdCascade, VarBuilder, +}; +use std::sync::mpsc; +use std::time::Duration; /// Execute stabilizer stream throughput testing. /// Use `RUST_LOG=info cargo run` to increase logging verbosity. -#[derive(Parser)] -struct Opts { - /// The local IP to receive streaming data on. - #[clap(short, long, default_value = "0.0.0.0")] - ip: String, - - /// The UDP port to receive streaming data on. - #[clap(long, default_value = "9293")] - port: u16, +#[derive(Parser, Debug)] +pub struct Opts { + #[command(flatten)] + source: SourceOpts, - /// The test duration in seconds. - #[clap(long, default_value = "5")] + #[arg(short, long, default_value_t = 10.0)] duration: f32, + + #[arg(short, long, default_value_t = 0)] + trace: usize, } -#[async_std::main] -async fn main() { +fn main() -> Result<()> { env_logger::init(); + let Opts { + source, + duration, + trace, + } = Opts::parse(); + + let (cmd_send, cmd_recv) = mpsc::channel(); + let receiver = std::thread::spawn(move || { + let mut source = Source::new(source)?; + + let mut dec: Vec<_> = (0..4) + .map(|_| { + let mut c = PsdCascade::<{ 1 << 9 }>::default(); + c.set_stage_depth(3); + c.set_detrend(Detrend::Mid); + c + }) + .collect(); + + while cmd_recv.try_recv() == Err(mpsc::TryRecvError::Empty) { + match source.get() { + Ok(traces) => { + for (dec, x) in dec.iter_mut().zip(traces) { + dec.process(&x); + } + } + Err(e) => log::warn!("{e}"), + }; + } - let opts = Opts::parse(); - let ip: std::net::Ipv4Addr = opts.ip.parse().unwrap(); - - log::info!("Binding to socket"); - let mut stream_receiver = StreamReceiver::new(ip, opts.port).await; - - let mut total_batches = 0u64; - let mut dropped_batches = 0u64; - let mut expect_sequence = None; - - let stop = Instant::now() + Duration::from_millis((opts.duration * 1000.) as _); - - log::info!("Reading frames"); - while Instant::now() < stop { - let frame = stream_receiver.next_frame().await.unwrap(); - total_batches += frame.batch_count() as u64; - - if let Some(expect) = expect_sequence { - let num_dropped = frame.sequence_number.wrapping_sub(expect) as u64; - dropped_batches += num_dropped; - total_batches += num_dropped; - - if num_dropped > 0 { - log::warn!( - "Lost {} batches: {:#08X} -> {:#08X}", - num_dropped, - expect, - frame.sequence_number, - ); + let (y, b) = dec[trace].psd(1); + log::info!("breaks: {:?}", b); + log::info!("psd: {:?}", y); + + if let Some(b0) = b.last() { + let var = VarBuilder::default().dc_cut(1).clip(1.0).build().unwrap(); + let mut fdev = vec![]; + let mut tau = 1.0; + let f = Break::frequencies(&b); + while tau <= (b0.effective_fft_size / 2) as f32 { + fdev.push((tau, var.eval(&y, &f, tau).sqrt())); + tau *= 2.0; } + log::info!("fdev: {:?}", fdev); } - expect_sequence = Some(frame.sequence_number.wrapping_add(frame.batch_count() as _)); - } + source.finish(); - assert!(total_batches > 0); - let loss = dropped_batches as f32 / total_batches as f32; + Result::<()>::Ok(()) + }); - log::info!( - "Loss: {} % ({}/{} batches)", - loss * 100.0, - dropped_batches, - total_batches - ); + std::thread::sleep(Duration::from_millis((duration * 1000.) as _)); + cmd_send.send(())?; + receiver.join().unwrap()?; - assert!(loss < MAX_LOSS); + Ok(()) } diff --git a/src/bin/stream_to_raw.rs b/src/bin/stream_to_raw.rs new file mode 100644 index 0000000..3b790fb --- /dev/null +++ b/src/bin/stream_to_raw.rs @@ -0,0 +1,28 @@ +use anyhow::Result; +use clap::Parser; +use stabilizer_streaming::source::{Source, SourceOpts}; +use std::io::Write; + +#[derive(Parser, Debug)] +pub struct Opts { + #[command(flatten)] + source: SourceOpts, + + #[arg(short, long, default_value_t = 0)] + trace: usize, +} + +fn main() -> Result<()> { + env_logger::init(); + let Opts { trace, source } = Opts::parse(); + + let mut source = Source::new(source)?; + let mut stdout = std::io::BufWriter::new(std::io::stdout()); + + loop { + let t = &source.get()?[trace]; + stdout.write_all(bytemuck::cast_slice(&t[..]))?; + } + + // source.finish(); +} diff --git a/src/de/data.rs b/src/de/data.rs new file mode 100644 index 0000000..b743054 --- /dev/null +++ b/src/de/data.rs @@ -0,0 +1,125 @@ +use ndarray::{ArrayView, Axis, ShapeError}; +use thiserror::Error; + +#[derive(Error, Debug, Clone)] +pub enum FormatError { + #[error("Invalid frame payload size")] + InvalidSize(#[from] ShapeError), +} + +pub trait Payload { + fn new(batches: usize, data: &[u8]) -> Result + where + Self: Sized; + fn traces(&self) -> &[Vec]; + fn traces_mut(&mut self) -> &mut [Vec]; + fn labels(&self) -> &[&str]; +} + +pub struct AdcDac { + traces: [Vec; 4], +} + +impl Payload for AdcDac { + /// Extract AdcDacData from a binary data block in the stream. + /// + /// # Args + /// * `batch_size` - The size of each batch in samples. + /// * `data` - The binary data composing the stream frame. + fn new(batches: usize, data: &[u8]) -> Result { + let channels = 4; + let samples = data.len() / batches / channels / core::mem::size_of::(); + let mut data = ArrayView::from_shape( + (batches, channels, samples, core::mem::size_of::()), + data, + )?; + data.swap_axes(0, 1); // FIXME: non-contig + let data = data.into_shape((channels, samples * batches, core::mem::size_of::()))?; + + // The DAC output range in bipolar mode (including the external output op-amp) is +/- 4.096 + // V with 16-bit resolution. The anti-aliasing filter has an additional gain of 2.5. + const DAC_VOLT_PER_LSB: f32 = 4.096 * 2.5 / (1u16 << 15) as f32; + // The ADC has a differential input with a range of +/- 4.096 V and 16-bit resolution. + // The gain into the two inputs is 1/5. + const ADC_VOLT_PER_LSB: f32 = 5.0 / 2.0 * 4.096 / (1u16 << 15) as f32; + assert_eq!(DAC_VOLT_PER_LSB, ADC_VOLT_PER_LSB); + + let traces: [Vec; 4] = [ + data.index_axis(Axis(0), 0) + .axis_iter(Axis(0)) + .map(|x| { + i16::from_le_bytes([x[0], x[1]]).wrapping_add(i16::MIN) as f32 + * DAC_VOLT_PER_LSB + }) + .collect(), + data.index_axis(Axis(0), 1) + .axis_iter(Axis(0)) + .map(|x| { + i16::from_le_bytes([x[0], x[1]]).wrapping_add(i16::MIN) as f32 + * DAC_VOLT_PER_LSB + }) + .collect(), + data.index_axis(Axis(0), 2) + .axis_iter(Axis(0)) + .map(|x| i16::from_le_bytes([x[0], x[1]]) as f32 * ADC_VOLT_PER_LSB) + .collect(), + data.index_axis(Axis(0), 3) + .axis_iter(Axis(0)) + .map(|x| i16::from_le_bytes([x[0], x[1]]) as f32 * ADC_VOLT_PER_LSB) + .collect(), + ]; + + Ok(Self { traces }) + } + + fn traces(&self) -> &[Vec] { + &self.traces[..] + } + + fn traces_mut(&mut self) -> &mut [Vec] { + &mut self.traces + } + fn labels(&self) -> &[&str] { + &["ADC0", "ADC1", "DAC0", "DAC1"] + } +} + +pub struct Fls { + traces: [Vec; 4], +} + +impl Payload for Fls { + fn new(batches: usize, data: &[u8]) -> Result { + let data: &[[[i32; 6]; 2]] = bytemuck::cast_slice(data); + // demod_re, demod_im, wraps, ftw, pow_amp, pll + assert_eq!(batches, data.len()); + let traces: [Vec; 4] = [ + data.iter() + .map(|b| { + ((b[0][0] as f32).powi(2) + (b[0][1] as f32).powi(2)).sqrt() / (i32::MAX as f32) + }) + .collect(), + data.iter() + .map(|b| (b[0][1] as f32).atan2(b[0][0] as f32)) + .collect(), + data.iter() + .map(|b| b[1][0] as f32 / i32::MAX as f32) + .collect(), + data.iter() + .map(|b| b[1][1] as f32 / i32::MAX as f32) + .collect(), + ]; + Ok(Self { traces }) + } + + fn labels(&self) -> &[&str] { + &["AR", "AP", "BI", "BQ"] + } + + fn traces(&self) -> &[Vec] { + &self.traces + } + fn traces_mut(&mut self) -> &mut [Vec] { + &mut self.traces + } +} diff --git a/src/de/deserializer.rs b/src/de/deserializer.rs deleted file mode 100644 index 71b19c5..0000000 --- a/src/de/deserializer.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::{AdcDacData, Error, FormatError, StreamData, StreamFormat}; - -use std::convert::TryFrom; - -// The magic word at the start of each stream frame. -const MAGIC_WORD: u16 = 0x057B; - -// The size of the frame header in bytes. -const HEADER_SIZE: usize = 8; - -/// A single stream frame contains multiple batches of data. -pub struct StreamFrame<'a> { - pub sequence_number: u32, - pub data: StreamData<'a>, -} - -struct FrameHeader { - // The format code associated with the stream binary data. - pub format_code: StreamFormat, - - // The size of each batch contained within the binary data. - pub batch_size: u8, - - // The sequence number of the first batch in the binary data. The sequence number increments - // monotonically for each batch. All batches the binary data are sequential. - pub sequence_number: u32, -} - -impl FrameHeader { - /// Parse the header of a stream frame. - pub fn parse(header: &[u8]) -> Result { - assert_eq!(header.len(), HEADER_SIZE); - - let magic_word = u16::from_le_bytes([header[0], header[1]]); - - if magic_word != MAGIC_WORD { - return Err(Error::InvalidHeader); - } - - let format_code = StreamFormat::try_from(header[2]).map_err(|_| Error::UnknownFormat)?; - let batch_size = header[3]; - let sequence_number = u32::from_le_bytes([header[4], header[5], header[6], header[7]]); - log::debug!( - "Header: {:?}, {}, {:X}", - format_code, - batch_size, - sequence_number - ); - - Ok(Self { - format_code, - batch_size, - sequence_number, - }) - } -} - -impl<'a> StreamFrame<'a> { - /// Parse a stream frame from a single UDP packet. - pub fn from_bytes(input: &'a [u8]) -> Result, Error> { - let (header, data) = input.split_at(HEADER_SIZE); - - let header = FrameHeader::parse(header)?; - - if data.len() % header.batch_size as usize != 0 { - return Err(FormatError::InvalidSize.into()); - } - - let data = match header.format_code { - StreamFormat::AdcDacData => { - let data = AdcDacData::new(header.batch_size, data)?; - StreamData::AdcDacData(data) - } - }; - - Ok(StreamFrame { - sequence_number: header.sequence_number, - data, - }) - } - - /// Get the number of batches contained within the frame. - pub fn batch_count(&self) -> usize { - match &self.data { - StreamData::AdcDacData(data) => data.batch_count(), - } - } -} - -impl<'a> AdcDacData<'a> { - /// Extract AdcDacData from a binary data block in the stream. - /// - /// # Args - /// * `batch_size` - The size of each batch in samples. - /// * `data` - The binary data composing the stream frame. - fn new(batch_size: u8, data: &'a [u8]) -> Result, FormatError> { - // Each element of the batch is 4 samples, each of which are u16s. - let batch_size_bytes: usize = (batch_size * 8) as usize; - if data.len() % batch_size_bytes != 0 { - return Err(FormatError::InvalidSize); - } - - Ok(Self { batch_size, data }) - } - - fn batch_count(&self) -> usize { - self.data.len() / (self.batch_size * 8) as usize - } -} diff --git a/src/de/frame.rs b/src/de/frame.rs new file mode 100644 index 0000000..2c0718e --- /dev/null +++ b/src/de/frame.rs @@ -0,0 +1,60 @@ +use super::data::{self, Payload}; +use super::{Error, Format}; + +use std::convert::TryFrom; + +// The magic word at the start of each stream frame. +const MAGIC_WORD: [u8; 2] = [0x7b, 0x05]; + +// The size of the frame header in bytes. +const HEADER_SIZE: usize = 8; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Header { + // The format code associated with the stream binary data. + pub format: Format, + + // The number of batches in the payload. + pub batches: u8, + + // The sequence number of the first batch in the binary data. The sequence number increments + // monotonically for each batch. All batches the binary data are sequential. + pub seq: u32, +} + +impl Header { + /// Parse the header of a stream frame. + fn parse(header: &[u8; HEADER_SIZE]) -> Result { + if header[..2] != MAGIC_WORD { + return Err(Error::InvalidHeader); + } + let format = Format::try_from(header[2]).or(Err(Error::UnknownFormat))?; + let batches = header[3]; + let seq = u32::from_le_bytes(header[4..8].try_into().unwrap()); + Ok(Self { + format, + batches, + seq, + }) + } +} + +/// A single stream frame contains multiple batches of data. +// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Frame { + pub header: Header, + pub data: Box, +} + +impl Frame { + /// Parse a stream frame from a single UDP packet. + pub fn from_bytes(input: &[u8]) -> Result { + let header = Header::parse(&input[..HEADER_SIZE].try_into().unwrap())?; + let data = &input[HEADER_SIZE..]; + let data: Box = match header.format { + Format::AdcDac => Box::new(data::AdcDac::new(header.batches as _, data)?), + Format::Fls => Box::new(data::Fls::new(header.batches as _, data)?), + }; + Ok(Self { header, data }) + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 6916e06..d36a52e 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1,36 +1,25 @@ use num_enum::TryFromPrimitive; +use thiserror::Error; -pub mod deserializer; +mod data; +pub use data::*; +mod frame; +pub use frame::*; -pub struct AdcDacData<'a> { - data: &'a [u8], - batch_size: u8, -} - -pub enum StreamData<'a> { - AdcDacData(AdcDacData<'a>), -} - -#[derive(TryFromPrimitive, Debug)] +#[derive(TryFromPrimitive, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] -enum StreamFormat { - AdcDacData = 1, +#[non_exhaustive] +pub enum Format { + AdcDac = 1, + Fls = 2, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone, Error)] pub enum Error { - DataFormat(FormatError), + #[error("Could not parse the frame payload")] + DataFormat(#[from] data::FormatError), + #[error("Invalid frame header")] InvalidHeader, + #[error("Unknown format ID")] UnknownFormat, } - -#[derive(Debug, Copy, Clone)] -pub enum FormatError { - InvalidSize, -} - -impl From for Error { - fn from(e: FormatError) -> Error { - Error::DataFormat(e) - } -} diff --git a/src/lib.rs b/src/lib.rs index 1c99274..3c81fc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,44 +1,20 @@ -pub mod de; +use thiserror::Error; -use async_std::net::UdpSocket; -use de::deserializer::StreamFrame; -use std::time::Duration; +mod de; +pub use de::*; +mod psd; +pub use psd::*; +mod loss; +pub use loss::*; +mod var; +pub use var::*; -/// Receives stream frames from Stabilizer over UDP. -pub struct StreamReceiver { - socket: UdpSocket, - buf: [u8; 2048], -} - -impl StreamReceiver { - /// Construct a new receiver. - /// - /// # Args - /// * `ip` - The IP address to bind to. Should be associated with the interface that is used to - /// communciate with Stabilizer. - /// * `port` - The port that livestream data is being sent to. - pub async fn new(ip: std::net::Ipv4Addr, port: u16) -> Self { - let socket = UdpSocket::bind((ip, port)).await.unwrap(); - - Self { - socket, - buf: [0; 2048], - } - } - - /// Receive a stream frame from Stabilizer. - pub async fn next_frame(&mut self) -> Option> { - // Read a single UDP packet. - let len = async_std::io::timeout(Duration::from_secs(1), self.socket.recv(&mut self.buf)) - .await - .unwrap(); +pub mod source; - // Deserialize the stream frame. - StreamFrame::from_bytes(&self.buf[..len]) - .map_err(|err| { - log::warn!("Frame deserialization error: {:?}", err); - err - }) - .ok() - } +#[derive(Debug, Error)] +pub enum Error { + #[error("Frame deserialization error")] + Frame(#[from] de::Error), + #[error("IO/Networt error")] + Network(#[from] std::io::Error), } diff --git a/src/loss.rs b/src/loss.rs new file mode 100644 index 0000000..e8638f8 --- /dev/null +++ b/src/loss.rs @@ -0,0 +1,39 @@ +use crate::Frame; + +#[derive(Clone, Copy, Default)] +pub struct Loss { + received: u64, + dropped: u64, + seq: Option, +} + +impl Loss { + pub fn update(&mut self, frame: &Frame) { + self.received += frame.header.batches as u64; + if let Some(seq) = self.seq { + let missing = frame.header.seq.wrapping_sub(seq) as u64; + self.dropped += missing; + if missing > 0 { + log::warn!( + "Lost {} batches: {:#08X} -> {:#08X}", + missing, + seq, + frame.header.seq, + ); + } + } + self.seq = Some(frame.header.seq.wrapping_add(frame.header.batches as _)); + } + + pub fn analyze(&self) { + if self.received > 0 { + let loss = self.dropped as f32 / (self.received + self.dropped) as f32; + log::info!( + "Loss: {} % ({} of {})", + loss * 100.0, + self.dropped, + self.received + self.dropped + ); + } + } +} diff --git a/src/psd.rs b/src/psd.rs new file mode 100644 index 0000000..af155c7 --- /dev/null +++ b/src/psd.rs @@ -0,0 +1,541 @@ +use idsp::hbf::{Filter, HbfDecCascade}; +use rustfft::{num_complex::Complex, Fft, FftPlanner}; +use std::sync::Arc; + +/// Window kernel +/// +/// +/// +/// +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Window { + pub win: [f32; N], + /// Mean squared + pub power: f32, + /// Normalized effective noise bandwidth (in bins) + pub nenbw: f32, +} + +impl Window { + /// Rectangular window + pub fn rectangular() -> Self { + assert!(N > 0); + Self { + win: [1.0; N], + power: 1.0, + nenbw: 1.0, + } + } + + /// Hann window + /// + /// This is the "numerical" version of the window with period `N`, `win[0] = win[N]` + /// (conceptually), specifically `win[0] != win[win.len() - 1]`. + /// Matplotlib's `matplotlib.mlab.window_hanning()` (but not scipy.signal.get_window()) + /// uses the symetric one of period `N-1`, with `win[0] = win[N - 1] = 0` + /// which looses a lot of useful properties (exact nenbw() and power() independent of `N`, + /// exact optimal overlap etc) + pub fn hann() -> Self { + assert!(N > 0); + let df = core::f32::consts::PI / N as f32; + let mut win = [0.0; N]; + for (i, w) in win.iter_mut().enumerate() { + *w = (df * i as f32).sin().powi(2); + } + Self { + win, + power: 0.25, + nenbw: 1.5, + } + } +} + +/// Detrend method +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Detrend { + /// No detrending + None, + /// Subtract the midpoint of each segment + Mid, + /// Remove linear interpolation between first and last item for each segment + Span, + // TODO: mean + // TODO: linear +} + +/// Power spectral density accumulator and decimator +/// +/// Note: Don't feed more than N*1e7 items without expecting loss of accuracy +/// +/// One stage in [PsdCascade]. +#[derive(Clone)] +pub struct Psd { + hbf: HbfDecCascade, + buf: [f32; N], + idx: usize, + spectrum: [f32; N], // using only the positive half N/2 + 1 + count: usize, + fft: Arc>, + win: Arc>, + overlap: usize, + detrend: Detrend, + drain: usize, +} + +impl Psd { + pub fn new(fft: Arc>, win: Arc>) -> Self { + let hbf = HbfDecCascade::default(); + assert_eq!(N, fft.len()); + // check fft and decimation block size compatibility + assert!(N >= 2); // Nyquist and DC distinction + let mut s = Self { + hbf, + buf: [0.0; N], + idx: 0, + spectrum: [0.0; N], + count: 0, + fft, + win, + overlap: 0, + detrend: Detrend::None, + drain: 0, + }; + s.set_overlap(N / 2); + s.set_stage_depth(0); + s + } + + pub fn set_overlap(&mut self, o: usize) { + assert_eq!(o % self.hbf.block_size().0, 0); + assert!(self.hbf.block_size().1 >= o); + assert!(o <= N / 2); + // TODO assert w.r.t. decimation workspace + self.overlap = o; + } + + pub fn set_detrend(&mut self, d: Detrend) { + self.detrend = d; + } + + pub fn set_stage_depth(&mut self, n: usize) { + self.hbf.set_depth(n); + self.drain = self.hbf.response_length(); + } + + fn apply_window(&self) -> [Complex; N] { + // apply detrending, window, make complex + let mut c = [Complex::default(); N]; + + match self.detrend { + Detrend::None => { + for ((c, x), w) in c.iter_mut().zip(&self.buf).zip(&self.win.win) { + c.re = x * w; + c.im = 0.0; + } + } + Detrend::Mid => { + let offset = self.buf[N / 2]; + for ((c, x), w) in c.iter_mut().zip(&self.buf).zip(&self.win.win) { + c.re = (x - offset) * w; + c.im = 0.0; + } + } + Detrend::Span => { + let mut offset = self.buf[0]; + let slope = (self.buf[N - 1] - self.buf[0]) / (N - 1) as f32; + for ((c, x), w) in c.iter_mut().zip(&self.buf).zip(&self.win.win) { + c.re = (x - offset) * w; + c.im = 0.0; + offset += slope; + } + } + }; + c + } +} + +pub trait PsdStage { + /// Process items + /// + /// Unused items are buffered. + /// Full FFT blocks are processed. + /// Overlap is kept. + /// Decimation is performed on fully processed input items. + /// + /// # Args + /// * `x`: input items + /// * `y`: output items + /// + /// # Returns + /// number if items written to `y` + fn process<'a>(&mut self, x: &[f32], y: &'a mut [f32]) -> &'a mut [f32]; + /// Return the positive frequency half of the spectrum + fn spectrum(&self) -> &[f32]; + /// PSD normalization factor + /// + /// one-sided + fn gain(&self) -> f32; + /// Number of averages + fn count(&self) -> usize; + /// Currently buffered items + fn buf(&self) -> &[f32]; +} + +impl PsdStage for Psd { + fn process<'a>(&mut self, mut x: &[f32], y: &'a mut [f32]) -> &'a mut [f32] { + let mut n = 0; + while !x.is_empty() { + // load + let take = x.len().min(self.buf.len() - self.idx); + let chunk; + (chunk, x) = x.split_at(take); + self.buf[self.idx..][..take].copy_from_slice(chunk); + self.idx += take; + if self.idx < N { + break; + } + + let mut c = self.apply_window(); + // fft in-place + self.fft.process(&mut c); + // convert positive frequency spectrum to power + // and accumulate + // TODO: accuracy for large counts + for (c, p) in c[..N / 2 + 1] + .iter() + .zip(self.spectrum[..N / 2 + 1].iter_mut()) + { + *p += c.norm_sqr(); + } + + let start = if self.count == 0 { + // decimate all, keep overlap later + 0 + } else { + // keep overlap + self.buf.copy_within(N - self.overlap..N, 0); + // decimate only new + self.overlap + }; + + // decimate overlap + let mut yi = self.hbf.process_block(None, &mut self.buf[start..]); + // drain decimator impulse response to initial state (zeros) + let skip = self.drain.min(yi.len()); + self.drain -= skip; + yi = &mut yi[skip..]; + // yield l + y[n..][..yi.len()].copy_from_slice(yi); + n += yi.len(); + + if self.count == 0 { + self.buf.copy_within(N - self.overlap..N, 0); + } + + self.count += 1; + self.idx = self.overlap; + } + &mut y[..n] + } + + fn spectrum(&self) -> &[f32] { + &self.spectrum[..N / 2 + 1] + } + + fn count(&self) -> usize { + self.count + } + + fn gain(&self) -> f32 { + // 2 for one-sided + // overlap is compensated by counting + 1.0 / ((self.count * N / 2) as f32 * self.win.nenbw * self.win.power) + } + + fn buf(&self) -> &[f32] { + &self.buf[..self.idx] + } +} + +/// Stage break information +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Break { + /// Start index in PSD and frequencies + pub start: usize, + /// Number of averages + pub count: usize, + /// Highes FFT bin (at `start`) + pub highest_bin: usize, + /// The effective FFT size + pub effective_fft_size: usize, +} + +impl Break { + /// Compute PSD bin center frequencies from stage breaks. + pub fn frequencies(b: &[Break]) -> Vec { + let Some(bi) = b.last() else { return vec![] }; + let mut f = Vec::with_capacity(bi.start + bi.highest_bin); + for bi in b.iter() { + f.truncate(bi.start); + let df = 1.0 / bi.effective_fft_size as f32; + f.extend((0..bi.highest_bin).rev().map(|f| f as f32 * df)); + } + assert_eq!(f.len(), bi.start + bi.highest_bin); + debug_assert_eq!(f.first(), Some(&0.5)); + debug_assert_eq!(f.last(), Some(&0.0)); + f + } +} + +/// Online power spectral density estimation +/// +/// This performs efficient long term power spectral density monitoring in real time. +/// The idea is to perform FFTs over relatively short windows and simultaneously decimate +/// the time domain data, everything in multiple stages, then +/// stitch together the FFT bins from the different stages. +/// This allows arbitrarily large effective FFTs sizes in practice with only +/// logarithmically increasing memory and cpu consumption. And it makes available PSD data +/// from higher frequency stages early to get rid of the delay in +/// recording and computing the large FFTs. The effective full FFT size grows in real-time +/// and does not need to be fixed. +/// This is well defined with the caveat that spur power depends on the changing bin width. +/// It's also typically what some modern signal analyzers or noise metrology instruments do. +/// +/// See also [`csdl`](https://github.com/jordens/csdl) or +/// [LPSD](https://doi.org/10.1016/j.measurement.2005.10.010). +/// +/// Infinite averaging +/// Incremental updates +/// Automatic FFT stage extension +#[derive(Clone)] +pub struct PsdCascade { + stages: Vec>, + fft: Arc>, + stage_length: usize, + detrend: Detrend, + overlap: usize, + win: Arc>, +} + +impl Default for PsdCascade { + /// Create a new Psd instance + /// + /// fft_size: size of the FFT blocks and the window + /// stage_length: number of decimation stages. rate change per stage is 1 << stage_length + /// detrend: [Detrend] method + fn default() -> Self { + let fft = FftPlanner::::new().plan_fft_forward(N); + let win = Arc::new(Window::hann()); + Self { + stages: Vec::with_capacity(4), + fft, + stage_length: 1, + detrend: Detrend::None, + overlap: N / 2, + win, + } + } +} + +impl PsdCascade { + pub fn set_window(&mut self, win: Window) { + self.win = Arc::new(win); + } + + pub fn set_stage_depth(&mut self, n: usize) { + assert!(n > 0); + self.stage_length = n; + for stage in self.stages.iter_mut() { + stage.set_stage_depth(n); + } + } + + pub fn set_detrend(&mut self, d: Detrend) { + self.detrend = d; + } + + fn get_or_add(&mut self, i: usize) -> &mut Psd { + while i >= self.stages.len() { + let mut stage = Psd::new(self.fft.clone(), self.win.clone()); + stage.set_stage_depth(self.stage_length); + stage.set_detrend(self.detrend); + stage.set_overlap(self.overlap); + self.stages.push(stage); + } + &mut self.stages[i] + } + + /// Process input items + pub fn process(&mut self, x: &[f32]) { + let mut a = ([0f32; N], [0f32; N]); + let (mut y, mut z) = (&mut a.0[..], &mut a.1[..]); + for mut x in x.chunks(N << self.stage_length) { + let mut i = 0; + while !x.is_empty() { + let n = self.get_or_add(i).process(x, y).len(); + core::mem::swap(&mut z, &mut y); + x = &z[..n]; + i += 1; + } + } + } + + /// Return the PSD and a Vec of segement break information + /// + /// # Args + /// * `min_count`: minimum number of averages to include in output + /// + /// # Returns + /// * `psd`: `Vec` normalized reversed (Nyquist first, DC last) + /// * `breaks`: `Vec` of stage breaks + pub fn psd(&self, min_count: usize) -> (Vec, Vec) { + let mut p = Vec::with_capacity(self.stages.len() * (N / 2 + 1)); + let mut b = Vec::with_capacity(self.stages.len()); + let mut n = 0; + for stage in self.stages.iter().take_while(|s| s.count >= min_count) { + let mut pi = stage.spectrum(); + // a stage yields frequency bins 0..N/2 ty its nyquist + // 0..floor(0.4*N) is its passband if it was preceeded by a decimator + // 0..floor(0.4*N/R) is next lower stage + // hence take bins ceil(0.4*N/R)..floor(0.4*N) from a stage + if !p.is_empty() { + // not the first stage + // remove transition band of previous stage's decimator, floor + let f_pass = 4 * N / 10; + pi = &pi[..f_pass]; + // remove low f bins from previous stage, ceil + let f_low = (4 * N + (10 << stage.hbf.depth()) - 1) / (10 << stage.hbf.depth()); + p.truncate(p.len() - f_low); + } + let g = stage.gain() * (1 << n) as f32; + b.push(Break { + start: p.len(), + count: stage.count(), + highest_bin: pi.len(), + effective_fft_size: N << n, + }); + p.extend(pi.iter().rev().map(|pi| pi * g)); + n += stage.hbf.depth(); + } + // correct DC and Nyquist bins as both only contribute once to the one-sided spectrum + // this matches matplotlib and matlab but is certainly a questionable step + // need special care when interpreting and integrating the PSD: DC and nyquist bins + // must be counted as only half the width as the "usual" bins 0 < i < N/2 + if let Some(p) = p.first_mut() { + *p *= 0.5; + } + if let Some(p) = p.last_mut() { + *p *= 0.5; + } + (p, b) + } +} + +#[cfg(test)] +mod test { + use super::*; + + /// 36 insns per input sample: > 190 MS/s per skylake core + #[test] + #[ignore] + fn insn() { + let mut s = PsdCascade::<{ 1 << 9 }>::default(); + s.set_stage_depth(3); + s.set_detrend(Detrend::Mid); + let x: Vec<_> = (0..1 << 16) + .map(|_| rand::random::() * 2.0 - 1.0) + .collect(); + for _ in 0..1 << 11 { + s.process(&x); + } + } + + /// full accuracy tests + #[test] + fn exact() { + const N: usize = 4; + let mut s = Psd::::new( + FftPlanner::new().plan_fft_forward(N), + Arc::new(Window::rectangular()), + ); + let x = vec![1.0; N]; + let mut y = vec![0.0; N]; + let y = s.process(&x, &mut y); + assert_eq!(y, &x[..N]); + println!("{:?}, {}", s.spectrum(), s.gain()); + + let mut s = PsdCascade::::default(); + s.set_window(Window::hann()); + s.process(&x); + let (p, b) = s.psd(0); + let f = Break::frequencies(&b); + println!("{:?}, {:?}", p, f); + assert!(p + .iter() + .zip([0.0, 4.0 / 3.0, 8.0 / 3.0].iter()) + .all(|(p, p0)| (p - p0).abs() < 1e-7)); + assert!(f + .iter() + .zip([0.5, 0.25, 0.0].iter()) + .all(|(p, p0)| (p - p0).abs() < 1e-7)); + } + + #[test] + fn test() { + assert_eq!(idsp::hbf::HBF_PASSBAND, 0.4); + + // make uniform noise [-1, 1), ignore the epsilon. + let x: Vec<_> = (0..1 << 16) + .map(|_| rand::random::() * 2.0 - 1.0) + .collect(); + let xm = x.iter().map(|x| *x as f64).sum::() as f32 / x.len() as f32; + // mean is 0, take 10 sigma here and elsewhere + assert!(xm.abs() < 10.0 / (x.len() as f32).sqrt()); + let xv = x.iter().map(|x| (x * x) as f64).sum::() as f32 / x.len() as f32; + // variance is 1/3 + assert!((xv * 3.0 - 1.0).abs() < 10.0 / (x.len() as f32).sqrt()); + + const N: usize = 1 << 9; + let n = 3; + let mut s = Psd::::new( + FftPlanner::new().plan_fft_forward(N), + Arc::new(Window::hann()), + ); + s.set_stage_depth(n); + let mut y = vec![0.0; x.len() >> n]; + let y = s.process(&x, &mut y[..]); + + let mut hbf = HbfDecCascade::default(); + hbf.set_depth(n); + assert_eq!(y.len(), (x.len() >> n) - hbf.response_length()); + let p: Vec<_> = s.spectrum().iter().map(|p| p * s.gain()).collect(); + // psd of a stage + assert!( + p.iter() + // 0.5 for one-sided spectrum + .all(|p| (p * 0.5 * 3.0 - 1.0).abs() < 10.0 / (s.count() as f32).sqrt()), + "{:?}", + &p[..] + ); + + let mut d = PsdCascade::::default(); + d.set_stage_depth(n); + d.set_detrend(Detrend::None); + d.process(&x); + let (mut p, b) = d.psd(1); + // tweak DC and Nyquist to make checks less code + let n = p.len(); + p[0] *= 2.0; + p[n - 1] *= 2.0; + for (i, bi) in b.iter().enumerate() { + // let (start, count, high, size) = bi.into(); + let end = b.get(i + 1).map(|bi| bi.start).unwrap_or(n); + let pi = &p[bi.start..end]; + // psd of the cascade + assert!(pi + .iter() + // 0.5 for one-sided spectrum + .all(|p| (p * 0.5 * 3.0 - 1.0).abs() < 10.0 / (bi.count as f32).sqrt())); + } + } +} diff --git a/src/source.rs b/src/source.rs new file mode 100644 index 0000000..a8c6f2a --- /dev/null +++ b/src/source.rs @@ -0,0 +1,113 @@ +use crate::{Frame, Loss}; +use anyhow::Result; +use clap::Parser; +use std::io::ErrorKind; +use std::time::Duration; +use std::{ + fs::File, + io::{BufReader, Read, Seek}, +}; + +/// Stabilizer stream source options +#[derive(Parser, Debug, Clone)] +pub struct SourceOpts { + /// The local IP to receive streaming data on. + #[arg(short, long, default_value = "0.0.0.0")] + ip: std::net::Ipv4Addr, + + /// The UDP port to receive streaming data on. + #[arg(short, long, default_value_t = 9293)] + port: u16, + + /// Use frames from the given file + #[arg(short, long)] + file: Option, + + /// Frame size in file (8 + n_batches*n_channel*batch_size) + #[arg(short, long, default_value_t = 8 + 30 * 2 * 6 * 4)] + frame_size: usize, + + /// On a file, wrap around and repeat + #[arg(short, long)] + repeat: bool, + + /// Single f32 raw trace in file, architecture dependent + #[arg(short, long)] + single: Option, +} + +#[derive(Debug)] +enum Data { + Udp(std::net::UdpSocket), + File(BufReader), + Single(BufReader), +} + +pub struct Source { + opts: SourceOpts, + data: Data, + loss: Loss, +} + +impl Source { + pub fn new(opts: SourceOpts) -> Result { + let data = if let Some(file) = &opts.file { + Data::File(BufReader::with_capacity(1 << 20, File::open(file)?)) + } else if let Some(single) = &opts.single { + Data::Single(BufReader::with_capacity(1 << 20, File::open(single)?)) + } else { + log::info!("Binding to {}:{}", opts.ip, opts.port); + let socket = std::net::UdpSocket::bind((opts.ip, opts.port))?; + socket2::SockRef::from(&socket).set_recv_buffer_size(1 << 20)?; + socket.set_read_timeout(Some(Duration::from_millis(1000)))?; + Data::Udp(socket) + }; + Ok(Self { + opts, + data, + loss: Loss::default(), + }) + } + + pub fn get(&mut self) -> Result>> { + let mut buf = [0u8; 2048]; + Ok(match &mut self.data { + Data::File(fil) => loop { + match fil.read_exact(&mut buf[..self.opts.frame_size]) { + Ok(()) => { + let frame = Frame::from_bytes(&buf[..self.opts.frame_size])?; + self.loss.update(&frame); + break frame.data.traces().into(); + } + Err(e) if e.kind() == ErrorKind::UnexpectedEof && self.opts.repeat => { + fil.seek(std::io::SeekFrom::Start(0))?; + } + Err(e) => Err(e)?, + } + }, + Data::Single(fil) => loop { + match fil.read(&mut buf[..]) { + Ok(len) => { + if len == 0 && self.opts.repeat { + fil.seek(std::io::SeekFrom::Start(0))?; + continue; + } + let v: &[[u8; 4]] = bytemuck::cast_slice(&buf[..len / 4 * 4]); + break vec![v.iter().map(|b| f32::from_le_bytes(*b)).collect()]; + } + Err(e) => Err(e)?, + } + }, + Data::Udp(socket) => { + let len = socket.recv(&mut buf[..])?; + let frame = Frame::from_bytes(&buf[..len])?; + self.loss.update(&frame); + frame.data.traces().into() + } + }) + } + + pub fn finish(&self) { + self.loss.analyze() + } +} diff --git a/src/var.rs b/src/var.rs new file mode 100644 index 0000000..4cf7bcc --- /dev/null +++ b/src/var.rs @@ -0,0 +1,68 @@ +use core::f32::consts::PI; +use derive_builder::Builder; + +#[derive(Debug, Builder, Clone, Copy, PartialEq)] +pub struct Var { + /// exponent of `pi*f*tau` in the variance frequency response (-2 for AVAR, -4 for MVAR) + #[builder(default = "-2")] + x_exp: i32, + /// Exponent of `sin(pi*f*tau)` in the variance frequency response (4 for AVAR, 6 for MVAR) + #[builder(default = "4")] + sinx_exp: i32, + /// Response clip (infinite for AVAR and MVAR, 1 for the main lobe: FVAR) + #[builder(default = "f32::MAX")] + clip: f32, + /// skip the fix `dc_cut` bins to suppress DC window leakage + #[builder(default = "2")] + dc_cut: usize, +} + +impl Var { + /// Compute statistical variance estimator (AVAR, MVAR, FVAR...) from Phase PSD + /// + /// # Args + /// * `phase_psd`: Phase noise PSD vector from Nyquist down + /// * `frequencies`: PSD bin frequencies, Nyquist first + pub fn eval(&self, phase_psd: &[f32], frequencies: &[f32], tau: f32) -> f32 { + phase_psd + .iter() + .rev() + .zip( + frequencies + .iter() + .rev() + .take_while(|&f| f * tau <= self.clip), + ) + .skip(self.dc_cut) + // force DC bin to 0 + .fold((0.0, (0.0, 0.0)), |(accu, (a0, f0)), (&sp, &f)| { + // frequency PSD + let sy = sp * f * f; + let pft = PI * (f * tau); + // Allan variance transfer function (rectangular window: sinc**2 and differencing: 2*sin**2) + // Cancel the 2 here with the 0.5 in the trapezoidal rule + let hahd = pft.sin().powi(self.sinx_exp) * pft.powi(self.x_exp); + let a = sy * hahd; + // trapezoidal integration + (accu + (a + a0) * (f - f0), (a, f)) + }) + .0 + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn basic() { + let mut p = [1000.0, 100.0, 1.2, 3.4, 5.6]; + let mut f = [0.0, 1.0, 3.0, 6.0, 9.0]; + p.reverse(); + f.reverse(); + let var = VarBuilder::default().build().unwrap(); + let v = var.eval(&p, &f, 2.7); + println!("{}", v); + assert!((0.13478442 - v).abs() < 1e-6); + } +}