Compare commits

..
19 Commits
Author SHA1 Message Date
LucasDLTG d2252fed66 fix: unlock payload
CI / Rust CI (push) Failing after 41s
2026-10-04 21:01:44 +02:00
LucasDLTG 94ca90db69 feat: remove hardware test from git hooks
CI / Rust CI (push) Successful in 3m48s
2026-10-04 12:58:28 +02:00
LucasDLTG 2bf07d0fba fix: bypass calculation 2026-10-02 22:50:39 +02:00
Lucas e661022329 feat: add random meters in demo 2026-09-30 16:09:18 +02:00
Lucas f4650ece00 fix: import 2026-09-30 12:41:32 +02:00
Lucas 01cc0feda2 fix: errors 2026-09-29 17:01:12 +02:00
LucasDLTG 234dcd08d0 unstable modification 2026-09-28 23:21:21 +02:00
LucasDLTG 9b05d32f27 feat: add reset state on change preset
CI / Rust CI (push) Successful in 45s
2026-09-25 20:35:54 +02:00
Lucas 5c79deec56 fix: round trip value before putting in state so hardware and software stay in sync
CI / Rust CI (push) Successful in 45s
2026-09-25 15:11:03 +02:00
Lucas b8e3d870cb fix: fmt
CI / Rust CI (push) Successful in 45s
2026-09-21 12:13:14 +02:00
Lucas 3ccc563c3d fix: hardware tests
CI / Rust CI (push) Failing after 45s
2026-09-21 12:11:23 +02:00
LucasDLTG 3cf7c279a8 feat: default meters + update state on link
CI / Rust CI (push) Failing after 47s
2026-09-20 21:39:47 +02:00
LucasDLTG a98be2f8e3 feat: add demo mode + rust own default state
CI / Rust CI (push) Failing after 1m0s
2026-09-13 19:10:42 +02:00
LucasDLTG af2e7dc602 feat: adapt to real usage
CI / Rust CI (push) Failing after 1m3s
2026-09-06 12:29:45 +02:00
LucasDLTG e2fee36cdb feat: rms + peak meters 2026-08-01 12:45:58 +02:00
LucasDLTG 27821c1866 fix: remove warnings 2026-07-31 14:03:52 +02:00
LucasDLTG 3d94df0b7a feat: decode meters clip indicators 2026-07-31 13:54:48 +02:00
LucasDLTG f6b6beda5e fix: prevent race condition on socket + remove panicking code 2026-07-21 23:38:35 +02:00
LucasDLTG a9a49bef89 fix: thread lock in tcp send/receive 2026-07-21 14:47:47 +02:00
19 changed files with 5107 additions and 3198 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ repos:
- id: test - id: test
name: cargo test name: cargo test
entry: cargo test --all --features hardware-tests -- --include-ignored entry: cargo test --all -- --include-ignored
language: system language: system
pass_filenames: false pass_filenames: false
stages: [pre-push] stages: [pre-push]
Generated
+765 -7
View File
@@ -2,6 +2,176 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "android_system_properties"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base64"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "cc"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005ec2760ca554fae18df7a11195552ec576cd665632a881bc011d5bb2fd4d80"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chacha20"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
dependencies = [
"cfg-if",
"cpufeatures",
"rand_core",
]
[[package]]
name = "chrono"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"iana-time-zone",
"num-traits",
"serde",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
dependencies = [
"libc",
]
[[package]]
name = "darling"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff"
dependencies = [
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 3.0.6",
]
[[package]]
name = "darling_macro"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785"
dependencies = [
"darling_core",
"quote",
"syn 3.0.6",
]
[[package]]
name = "defmt"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1"
dependencies = [
"bitflags",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8"
dependencies = [
"defmt-parser",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "defmt-parser"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
dependencies = [
"thiserror",
]
[[package]]
name = "deranged"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"serde_core",
]
[[package]] [[package]]
name = "dotenvy" name = "dotenvy"
version = "0.15.7" version = "0.15.7"
@@ -13,17 +183,283 @@ name = "dsp_thomann"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dotenvy", "dotenvy",
"rand",
"serde",
"serde_json",
"serde_with",
"strum", "strum",
"strum_macros", "strum_macros",
"thiserror", "thiserror",
] ]
[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "find-msvc-tools"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
[[package]]
name = "futures-core"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
[[package]]
name = "futures-task"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
[[package]]
name = "futures-util"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
name = "getrandom"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"rand_core",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"serde",
"serde_core",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "jiff"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb"
dependencies = [
"defmt",
"jiff-core",
"jiff-static",
"jiff-tzdb-platform",
"log",
"portable-atomic",
"portable-atomic-util",
"serde_core",
"windows-link",
]
[[package]]
name = "jiff-core"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c"
dependencies = [
"defmt",
"log",
]
[[package]]
name = "jiff-static"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212"
dependencies = [
"jiff-core",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "jiff-tzdb"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e"
[[package]]
name = "jiff-tzdb-platform"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
dependencies = [
"jiff-tzdb",
]
[[package]]
name = "js-sys"
version = "0.3.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e"
dependencies = [
"cfg-if",
"futures-util",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "log"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "num-conv"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "portable-atomic"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
[[package]]
name = "portable-atomic-util"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
dependencies = [
"portable-atomic",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@@ -42,6 +478,173 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "r-efi"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"
dependencies = [
"chacha20",
"getrandom",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "ref-cast"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
]
[[package]]
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "schemars"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "schemars"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "serde"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.6",
]
[[package]]
name = "serde_json"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "serde_with"
version = "3.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9adc193c780ef8f159aee8b61e2d5801aaa555e6eb0947fe45530ec506296f"
dependencies = [
"base64",
"bs58",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.14.2",
"jiff",
"schemars 0.9.0",
"schemars 1.2.2",
"serde_core",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e17bbc68e28663bbbb90df47e058aa7eda4fb445b89fe70457bb94fbccf6e49"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 3.0.6",
]
[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.28.0" version = "0.28.0"
@@ -73,9 +676,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "3.0.2" version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3" checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -84,26 +687,181 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.19" version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "2.0.19" version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 3.0.2", "syn 3.0.6",
] ]
[[package]]
name = "time"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"
dependencies = [
"deranged",
"num-conv",
"powerfmt",
"serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
[[package]]
name = "time-macros"
version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinyvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cf0ded5c4e56918d8f8a339e1bb67d038d3bc6d144ac407904015ba2e4cde9b"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.24" version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "wasm-bindgen"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 3.0.6",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+7 -1
View File
@@ -7,9 +7,13 @@ edition = "2024"
dotenvy = "0.15" dotenvy = "0.15"
[dependencies] [dependencies]
thiserror = "2.0.19" thiserror = "2.0.21"
strum = "0.28.0" strum = "0.28.0"
strum_macros = "0.28.0" strum_macros = "0.28.0"
serde = { version = "1", features = ["derive"], optional = true }
serde_json = { version = "1", optional = true }
serde_with = "3.24.0"
rand = "0.10.3"
[lib] [lib]
name = "dsp_thomann" name = "dsp_thomann"
@@ -17,3 +21,5 @@ path = "src/lib.rs"
[features] [features]
hardware-tests = [] hardware-tests = []
default = []
serialization = ["dep:serde", "dep:serde_json"]
+68 -13
View File
@@ -617,26 +617,81 @@ delay = delay_min + (raw / 255) × (delay_max - delay_min)
| Field | Value | | Field | Value |
|---|---| |---|---|
| **Purpose** | Per-channel level + peak metering | | **Purpose** | Per-channel RMS + peak metering, with clip flags |
| **Size** | 3 bytes per channel | | **Payload size** | 38 bytes (exactly; any other length is an error) |
| **Total** | 12 channels × 3 bytes = 36 bytes | | **Layout** | 12 channels × 3 bytes = 36 bytes, followed by 2 clip-flag bytes |
| **Channel order** | Channels 0–3 are inputs, channels 4–11 are outputs, each mapped in enum order |
#### Channel record (3 bytes, at offset `i = channel × 3`)
| Byte offset | Field | Format | | Byte offset | Field | Format |
|---|---|---| |---|---|---|
| 0–1 | Level | IEEE754 float16, little-endian | | `i + 0` | RMS low byte | Low byte of the RMS float16 |
| 2 | Peak | 1-byte peak value (format not specified in source) | | `i + 1` | Shared high byte | High byte of **both** the RMS and Peak float16s |
| `i + 2` | Peak low byte | Low byte of the Peak float16 |
Both values are IEEE 754 half-precision floats (little-endian pairs). The peak is not a separate 1-byte value: it reuses byte `i + 1` as its high byte, so its byte order is reversed relative to the offset order.
**Encoding (value → raw):**
```text ```text
level_bytes = float16_encode(level) // 2 bytes, little-endian rms_raw = float16_decode(lo = payload[i], hi = payload[i + 1])
peak_byte = peak_encode(peak) // format undefined — see note below peak_raw = float16_decode(lo = payload[i + 2], hi = payload[i + 1])
raw = level_bytes + peak_byte
``` ```
**Decoding (raw → value):** If a float16 fails to decode, the raw value defaults to `0.0`, which converts to `MIN_DB` (-60 dB).
#### Clip flags (bytes 36–37)
| Channel index | Flag location |
|---|---|
| 0–3 | `payload[36]`, bit `index` |
| 4–11 | `payload[37]`, bit `index - 4` |
```text ```text
level = float16_decode(raw[0:2]) // little-endian clip = (flags_byte & (1 << bit)) != 0
peak = peak_decode(raw[2]) // format undefined — see note below ```
#### Raw → dB conversion
Raw values are converted with a piecewise-linear curve, then clamped.
| Constant | Value | Meaning |
|---|---|---|
| `X0` | -25.0 dB | Breakpoint |
| `Y0` | 1.0 | Raw value at the breakpoint |
| `K1` | 0.0104 | Raw units per dB below the breakpoint (`raw < Y0`) |
| `K2` | 0.0208 | Raw units per dB above the breakpoint (`raw >= Y0`) |
| `MIN_DB` | -60.0 dB | Lower clamp |
| `MAX_DB` | 12.0 dB | Upper clamp |
**Decoding (raw → dB):**
```text
if raw < Y0: db = X0 + (raw - Y0) / K1
else: db = X0 + (raw - Y0) / K2
db = clamp(db, MIN_DB, MAX_DB)
```
**Encoding (dB → raw):** the inverse of the above. Values outside the clamp range are not recoverable.
```text
db = clamp(db, MIN_DB, MAX_DB)
if db < X0: raw = Y0 + (db - X0) * K1
else: raw = Y0 + (db - X0) * K2
```
#### Full decode
```text
require len(payload) == 38
for index in 0..11:
i = index * 3
rms_db = raw_to_db(float16_decode(payload[i], payload[i + 1]))
peak_db = raw_to_db(float16_decode(payload[i + 2], payload[i + 1]))
clip = index < 4 ? payload[36] bit index
: payload[37] bit (index - 4)
meter[index] = { rms: rms_db, peak: peak_db, clip }
inputs = meter[0..3] → InputChannel enum order
outputs = meter[4..11] → OutputChannel enum order
``` ```
--- ---
@@ -1868,7 +1923,7 @@ Sine Wave:
|---|---|---|---| |---|---|---|---|
| `Byte 1-36` | 12 meter channels | 3 bytes × 12 | [Enc §8.1 Meter Level](#81-meter-level) | | `Byte 1-36` | 12 meter channels | 3 bytes × 12 | [Enc §8.1 Meter Level](#81-meter-level) |
| `Byte 37` | Input clip indicator | 1 byte bitmask | Same OR bitmask pattern as [Enc §4.1](#41-matrix-input-mask) | | `Byte 37` | Input clip indicator | 1 byte bitmask | Same OR bitmask pattern as [Enc §4.1](#41-matrix-input-mask) |
| `Byte 38` | Output clip indicator | 1 byte bitmask | Same OR bitmask pattern as [Enc §4.1](#41-matrix-input-mask) | | `Byte 38` | Output limit indicator | 1 byte bitmask | Same OR bitmask pattern as [Enc §4.1](#41-matrix-input-mask) |
**Example — Query** **Example — Query**
+2
View File
@@ -13,6 +13,8 @@
- Figure out Meter level encoding - Figure out Meter level encoding
- Full test of client (Improve existing one) - Full test of client (Improve existing one)
- Write correct readme.md - Write correct readme.md
- Make client dsp408 thread safe
- Absolutely, send command to avoid tcp keep alive, that make the dsp crash
Rust library for remote LAN control of Thomann DSP408 digital signal processors. Rust library for remote LAN control of Thomann DSP408 digital signal processors.
+12
View File
@@ -122,6 +122,12 @@ pub enum DSPError {
#[error("operation failed: {0}")] #[error("operation failed: {0}")]
OperationFailed(String), OperationFailed(String),
#[error("internal error: {0}")]
InternalError(String),
#[error("mutex poisoned: {0}")]
MutexPoisoned(String),
#[error("I/O error: {0}")] #[error("I/O error: {0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
@@ -134,3 +140,9 @@ pub enum DSPError {
#[error("frame error: {0}")] #[error("frame error: {0}")]
Frame(#[from] FrameError), Frame(#[from] FrameError),
} }
impl<T> From<std::sync::PoisonError<T>> for DSPError {
fn from(err: std::sync::PoisonError<T>) -> Self {
DSPError::MutexPoisoned(err.to_string())
}
}
+333
View File
@@ -0,0 +1,333 @@
use rand::RngExt;
use std::collections::HashMap;
use strum::IntoEnumIterator;
use crate::dsp408::types::ConnectionStatus;
use crate::dsp408::types::{
Compressor, Crossover, CrossoverFilter, CrossoverFilters, DSPConfigState, DSPState, DelayUnit,
DeviceFlags, DiscreteFrequency, Gate, GraphicEQ, InputChannel, InputChannelState, InputMeters,
InputSource, InputType, Limiter, MatrixRoutes, Meter, OutputChannel, OutputChannelState,
OutputMeters, PEQ, PEQBand, PEQChain, PEQFilter, PresetBank, Ratio,
};
const FREQUENCY_MIN: f32 = 19.7;
const FREQUENCY_MAX: f32 = 20160.0;
const PRESET_COUNT: usize = 20;
pub fn default_dsp_state() -> DSPState {
DSPState {
name: "Default".to_string(),
flags: DeviceFlags { is_locked: true },
presets: default_preset_bank(),
current_config: default_config(),
connection: ConnectionStatus::Disconnected,
}
}
pub fn default_input_meters() -> InputMeters {
InputMeters {
meters: InputChannel::iter().map(|c| (c, default_meter())).collect(),
}
}
pub fn default_output_meters() -> OutputMeters {
OutputMeters {
meters: OutputChannel::iter()
.map(|c| (c, default_meter()))
.collect(),
}
}
// -----------------------------------------------------------------------------
// Presets
// -----------------------------------------------------------------------------
fn default_preset_bank() -> PresetBank {
PresetBank {
current_index: 0,
names: vec!["Default".to_string(); PRESET_COUNT],
modified: vec![false; PRESET_COUNT],
}
}
// -----------------------------------------------------------------------------
// DSP config
// -----------------------------------------------------------------------------
fn default_config() -> DSPConfigState {
DSPConfigState {
input_source: InputSource {
r#type: InputType::Analog,
frequency: DiscreteFrequency::F20000,
},
delay_unit: DelayUnit::Millisecond,
input_states: default_input_states(),
output_states: default_output_states(),
}
}
// -----------------------------------------------------------------------------
// Input channels
// -----------------------------------------------------------------------------
fn default_input_states() -> HashMap<InputChannel, InputChannelState> {
[
(
InputChannel::InA,
default_input_channel_state("In A", false),
),
(InputChannel::InB, default_input_channel_state("In B", true)),
(
InputChannel::InC,
default_input_channel_state("In C", false),
),
(
InputChannel::InD,
default_input_channel_state("In D", false),
),
]
.into_iter()
.collect()
}
fn default_input_channel_state(name: &str, a: bool) -> InputChannelState {
if a {
return InputChannelState {
name: name.to_string(),
gain: 0.0,
phase_inverted: false,
delay: 0.0,
gate: default_gate(),
geq: default_graphic_eq(),
peq_chain: default_peq_chain(),
crossover: default_crossover_filters(),
linked_channels: vec![InputChannel::InA],
// linked_channels: Vec::new(),
mute: false,
};
}
InputChannelState {
name: name.to_string(),
gain: 0.0,
phase_inverted: false,
delay: 0.0,
gate: default_gate(),
geq: default_graphic_eq(),
peq_chain: default_peq_chain(),
crossover: default_crossover_filters(),
linked_channels: Vec::new(),
mute: false,
}
}
// -----------------------------------------------------------------------------
// Output channels
// -----------------------------------------------------------------------------
fn default_output_states() -> HashMap<OutputChannel, OutputChannelState> {
[
(OutputChannel::Out1, default_output_channel_state("Out 1")),
(OutputChannel::Out2, default_output_channel_state("Out 2")),
(OutputChannel::Out3, default_output_channel_state("Out 3")),
(OutputChannel::Out4, default_output_channel_state("Out 4")),
(OutputChannel::Out5, default_output_channel_state("Out 5")),
(OutputChannel::Out6, default_output_channel_state("Out 6")),
(OutputChannel::Out7, default_output_channel_state("Out 7")),
(OutputChannel::Out8, default_output_channel_state("Out 8")),
]
.into_iter()
.collect()
}
fn default_output_channel_state(name: &str) -> OutputChannelState {
OutputChannelState {
name: name.to_string(),
matrix_routes: default_matrix_routes(),
crossover: default_crossover_filters(),
peq_chain: default_peq_chain(),
compressor: default_compressor(),
limiter: default_limiter(),
gain: 0.0,
phase_inverted: false,
delay: 0.0,
linked_channels: Vec::new(),
mute: false,
}
}
// -----------------------------------------------------------------------------
// Gate
// -----------------------------------------------------------------------------
fn default_gate() -> Gate {
Gate {
attack: 10,
release: 10,
hold: 10,
threshold: 0.0,
}
}
// -----------------------------------------------------------------------------
// Graphic EQ
// -----------------------------------------------------------------------------
fn default_graphic_eq() -> GraphicEQ {
let gains = DiscreteFrequency::iter()
.map(|frequency| (frequency, 0.0))
.collect();
GraphicEQ {
gains,
bypass: false,
}
}
// -----------------------------------------------------------------------------
// PEQ
// -----------------------------------------------------------------------------
fn default_peq() -> PEQ {
PEQ {
gain: 0.0,
frequency: 1000.0,
q: 1.0,
filter_type: PEQFilter::Peak,
bypass: false,
}
}
fn default_peq_chain() -> PEQChain {
let bands = PEQBand::iter().map(|band| (band, default_peq())).collect();
PEQChain {
bands,
bypass: false,
}
}
// -----------------------------------------------------------------------------
// Crossover
// -----------------------------------------------------------------------------
fn default_crossover(frequency: f32) -> Crossover {
Crossover {
frequency,
slope: CrossoverFilter::Bypass,
}
}
fn default_crossover_filters() -> CrossoverFilters {
CrossoverFilters {
high_pass: default_crossover(FREQUENCY_MIN),
low_pass: default_crossover(FREQUENCY_MAX),
}
}
// -----------------------------------------------------------------------------
// Matrix
// -----------------------------------------------------------------------------
fn default_matrix_routes() -> MatrixRoutes {
let gains = [
(InputChannel::InA, 0.0),
(InputChannel::InB, 0.0),
(InputChannel::InC, 0.0),
(InputChannel::InD, 0.0),
]
.into_iter()
.collect();
MatrixRoutes {
connected: vec![InputChannel::InA],
gains,
}
}
// -----------------------------------------------------------------------------
// Compressor
// -----------------------------------------------------------------------------
fn default_compressor() -> Compressor {
Compressor {
threshold: -90.0,
ratio: Ratio::Ratio1_1,
attack: 1,
release: 10,
knee: 0,
}
}
// -----------------------------------------------------------------------------
// Limiter
// -----------------------------------------------------------------------------
fn default_limiter() -> Limiter {
Limiter {
threshold: -90.0,
attack: 1,
release: 10,
}
}
// -----------------------------------------------------------------------------
// Meters
// -----------------------------------------------------------------------------
fn default_meter() -> Meter {
Meter {
rms: -60.0,
peak: -60.0,
clip: false,
}
}
fn random_meter() -> Meter {
let mut rng = rand::rng();
let rms = rng.random_range(-60.0..=0.0);
let peak = (rms + rng.random_range(0.0..=12.0) as f32).min(12.0);
Meter {
rms,
peak,
clip: peak > 0.0,
}
}
pub fn random_input_meters() -> InputMeters {
InputMeters {
meters: InputChannel::iter()
.map(|channel| (channel, random_meter()))
.collect(),
}
}
pub fn random_output_meters() -> OutputMeters {
OutputMeters {
meters: OutputChannel::iter()
.map(|channel| (channel, random_meter()))
.collect(),
}
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1,2 +1,4 @@
mod default;
mod dsp408; mod dsp408;
pub use dsp408::DSP408; pub use dsp408::DSP408;
+72 -27
View File
@@ -1,14 +1,16 @@
use std::collections::HashMap;
use strum::IntoEnumIterator;
use crate::{ use crate::{
common::errors::ProtocolError, common::errors::ProtocolError,
dsp408::{ dsp408::{
protocol::{ protocol::frame::Frame,
constants::{METERS_HIGH_STEP, METERS_LOW_STEP, METERS_SPLIT, METERS_SPLIT_LEVEL_DB},
frame::Frame,
},
types::{ types::{
Acknowledgement, AuthenticationResult, ConfigChunk, CurrentPreset, DeviceFlags, Acknowledgement, AuthenticationResult, ConfigChunk, CurrentPreset, DeviceFlags,
DeviceInfo, DeviceResponseType, HandshakeAck, Meters, ModifiedPreset, NotImplemented, DeviceInfo, DeviceResponseType, HandshakeAck, InputChannel, InputMeters, Meter,
PresetName, UnknownResponse, ModifiedPreset, NotImplemented, OutputChannel, OutputMeters, PresetName,
UnknownResponse,
}, },
}, },
}; };
@@ -88,10 +90,6 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
// Command `0x24` (Get Config Chunk) // Command `0x24` (Get Config Chunk)
if cmd == 0x24 { if cmd == 0x24 {
// Mirrors Python's `int.from_bytes(payload[:1], "little")`, which
// is `0` for an empty payload rather than an error — Python slices
// never panic. `payload.get(1..)` below mirrors the same
// forgiving-slice behavior for the remainder.
let index = payload.first().copied().unwrap_or(0); let index = payload.first().copied().unwrap_or(0);
if index > 0x1c { if index > 0x1c {
@@ -150,7 +148,7 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
return Err(ProtocolError::new("Missing authentication result")); return Err(ProtocolError::new("Missing authentication result"));
} }
if payload[1] != 0x00 && payload[1] != 0x01 { if payload[0] != 0x00 && payload[1] != 0x01 {
return Err(ProtocolError::new(format!( return Err(ProtocolError::new(format!(
"Invalid authentication flag: {:#04x}", "Invalid authentication flag: {:#04x}",
payload[1] payload[1]
@@ -166,27 +164,75 @@ pub fn map_response(frame: &Frame) -> Result<DeviceResponseType, ProtocolError>
// Command `0x40` (Get Level Meters) // Command `0x40` (Get Level Meters)
if cmd == 0x40 { if cmd == 0x40 {
const X0: f32 = -25.0; // breakpoint, in dB
const Y0: f32 = 1.0; // raw value at the breakpoint
const K1: f32 = 0.0104; // slope below breakpoint (raw < Y0)
const K2: f32 = 0.0208; // slope above breakpoint (raw >= Y0)
const MIN_DB: f32 = -60.0;
const MAX_DB: f32 = 12.0;
fn float_to_db(raw: f32) -> f32 {
let db = if raw < Y0 {
X0 + (raw - Y0) / K1
} else {
X0 + (raw - Y0) / K2
};
db.clamp(MIN_DB, MAX_DB)
}
if payload.len() != 38 { if payload.len() != 38 {
return Err(ProtocolError::new("Not enough bytes for meter levels")); return Err(ProtocolError::new("Not enough bytes for meter levels"));
} }
let floats: Vec<f32> = (0..36) let raw_meters: Vec<Meter> = (0..36)
.step_by(3) .step_by(3)
.map(|i| decode_float16(payload[i], payload[i + 1]).unwrap_or_default()) .enumerate()
.collect(); .map(|(index, i)| {
let rms = decode_float16(payload[i], payload[i + 1]).unwrap_or_default();
let peak = decode_float16(payload[i + 2], payload[i + 1]).unwrap_or_default();
let meters: Vec<f32> = floats let rms_db = float_to_db(rms);
.into_iter() let peak_db = float_to_db(peak);
.map(|f| {
if f < METERS_SPLIT { let clip = if index < 4 {
METERS_SPLIT_LEVEL_DB + (f - METERS_SPLIT) / METERS_LOW_STEP payload[36] & (1 << index) != 0
} else { } else {
METERS_SPLIT_LEVEL_DB + (f - METERS_SPLIT) / METERS_HIGH_STEP payload[37] & (1 << (index - 4)) != 0
};
Meter {
rms: rms_db,
peak: peak_db,
clip,
} }
}) })
.collect(); .collect();
return Ok(DeviceResponseType::Meters(Meters { levels: meters })); let mut input_iter = InputChannel::iter();
let mut output_iter = OutputChannel::iter();
let mut input_meters = HashMap::new();
let mut output_meters = HashMap::new();
for (index, meter) in raw_meters.into_iter().enumerate() {
if index < 4 {
if let Some(channel) = input_iter.next() {
input_meters.insert(channel, meter);
}
} else if let Some(channel) = output_iter.next() {
output_meters.insert(channel, meter);
}
}
return Ok(DeviceResponseType::Meters(
InputMeters {
meters: input_meters,
},
OutputMeters {
meters: output_meters,
},
));
} }
Ok(DeviceResponseType::UnknownResponse(UnknownResponse { Ok(DeviceResponseType::UnknownResponse(UnknownResponse {
@@ -401,8 +447,6 @@ mod tests {
#[test] #[test]
fn meters_decode() { fn meters_decode() {
// 38 bytes required.
// First 36 bytes are meter values, remaining 2 bytes ignored.
let mut payload = vec![0; 38]; let mut payload = vec![0; 38];
// half float 1.0 = 0x3c00 // half float 1.0 = 0x3c00
@@ -414,11 +458,12 @@ mod tests {
let result = map_response(&frame(0x40, payload)).unwrap(); let result = map_response(&frame(0x40, payload)).unwrap();
match result { match result {
DeviceResponseType::Meters(m) => { DeviceResponseType::Meters(inputs, outputs) => {
assert_eq!(m.levels.len(), 12); assert_eq!(inputs.meters.len(), 4);
assert_eq!(outputs.meters.len(), 8);
for level in m.levels { for meter in inputs.meters.values().chain(outputs.meters.values()) {
assert!(level.is_finite()); assert!(meter.rms.is_finite());
} }
} }
other => panic!("unexpected {:?}", other), other => panic!("unexpected {:?}", other),
+5 -1
View File
@@ -99,7 +99,11 @@ pub fn build_get_device_flags() -> Vec<u8> {
pub fn build_unlock_device(password: &[u8]) -> Result<Vec<u8>, ValidationError> { pub fn build_unlock_device(password: &[u8]) -> Result<Vec<u8>, ValidationError> {
validate_raw_password(password)?; validate_raw_password(password)?;
Ok(build_frame(0x2d, password)) let mut payload = Vec::with_capacity(1 + password.len());
payload.push(0x00);
payload.extend_from_slice(password);
Ok(build_frame(0x2d, &payload))
} }
// Command 0x2F // Command 0x2F
+63 -30
View File
@@ -35,12 +35,14 @@ fn read_gate(r: &mut BinaryReader) -> Result<types::Gate, DSPError> {
} }
fn read_geq(r: &mut BinaryReader) -> Result<types::GraphicEQ, DSPError> { fn read_geq(r: &mut BinaryReader) -> Result<types::GraphicEQ, DSPError> {
let gains = types::DiscreteFrequency::iter() let mut gains = std::collections::HashMap::new();
.map(|_| {
for frequency in types::DiscreteFrequency::iter() {
let raw = r.read_u16()?; let raw = r.read_u16()?;
Ok(mapper::raw_to_eq_gain(raw)?) let gain = mapper::raw_to_eq_gain(raw)?;
})
.collect::<Result<Vec<_>, DSPError>>()?; gains.insert(frequency, gain);
}
Ok(types::GraphicEQ { Ok(types::GraphicEQ {
gains, gains,
@@ -49,17 +51,20 @@ fn read_geq(r: &mut BinaryReader) -> Result<types::GraphicEQ, DSPError> {
} }
fn read_peq_chain(r: &mut BinaryReader, band_count: usize) -> Result<types::PEQChain, DSPError> { fn read_peq_chain(r: &mut BinaryReader, band_count: usize) -> Result<types::PEQChain, DSPError> {
let bands = (0..band_count) let bands = types::PEQBand::iter()
.map(|_| { .take(band_count)
Ok(types::PEQ { .map(|band| {
let peq = types::PEQ {
gain: mapper::raw_to_eq_gain(r.read_u16()?)?, gain: mapper::raw_to_eq_gain(r.read_u16()?)?,
frequency: mapper::raw_to_frequency_hz(r.read_u16()?)?, frequency: mapper::raw_to_frequency_hz(r.read_u16()?)?,
q: mapper::raw_to_peq_q(r.read_u8()?)?, q: mapper::raw_to_peq_q(r.read_u8()?)?,
filter_type: mapper::raw_to_peq_filter(r.read_u8()?)?, filter_type: mapper::raw_to_peq_filter(r.read_u8()?)?,
bypass: false, bypass: false,
};
Ok((band, peq))
}) })
}) .collect::<Result<HashMap<_, _>, DSPError>>()?;
.collect::<Result<Vec<_>, DSPError>>()?;
Ok(types::PEQChain { Ok(types::PEQChain {
bands, bands,
@@ -67,6 +72,21 @@ fn read_peq_chain(r: &mut BinaryReader, band_count: usize) -> Result<types::PEQC
}) })
} }
fn apply_peq_bypass(
r: &mut BinaryReader,
bands: &mut HashMap<types::PEQBand, types::PEQ>,
) -> Result<(), DSPError> {
let bitmap = r.read_u16()?;
for (index, band) in types::PEQBand::iter().enumerate() {
if let Some(peq) = bands.get_mut(&band) {
peq.bypass = bitmap & (1 << index) != 0;
}
}
Ok(())
}
fn read_crossover(r: &mut BinaryReader) -> Result<types::CrossoverFilters, DSPError> { fn read_crossover(r: &mut BinaryReader) -> Result<types::CrossoverFilters, DSPError> {
let hp_freq = r.read_u16()?; let hp_freq = r.read_u16()?;
let lp_freq = r.read_u16()?; let lp_freq = r.read_u16()?;
@@ -152,7 +172,13 @@ pub fn decode_config(payload: &[u8]) -> Result<types::DSPConfigState, DSPError>
inp.linked_channels = mapper::raw_to_link_channels( inp.linked_channels = mapper::raw_to_link_channels(
mapper::channel_to_raw(types::Channel::Input(channel))?, mapper::channel_to_raw(types::Channel::Input(channel))?,
r.read_u8()?, r.read_u8()?,
)?; )?
.into_iter()
.filter_map(|link| match link {
types::Channel::Input(input) => Some(input),
types::Channel::Output(_) => None,
})
.collect();
} }
// ============================ // ============================
@@ -162,17 +188,26 @@ pub fn decode_config(payload: &[u8]) -> Result<types::DSPConfigState, DSPError>
for (channel, out) in types::OutputChannel::iter().zip(output_channels.iter_mut()) { for (channel, out) in types::OutputChannel::iter().zip(output_channels.iter_mut()) {
out.name = mapper::raw_to_channel_name(r.pop(constants::CHANNEL_NAME_LENGTH)?)?; out.name = mapper::raw_to_channel_name(r.pop(constants::CHANNEL_NAME_LENGTH)?)?;
r.skip(1)?;
out.matrix_routes = types::MatrixRoutes { out.matrix_routes = types::MatrixRoutes {
connected: mapper::raw_to_matrix(r.read_u8()?)?, connected: mapper::raw_to_matrix(r.read_u8()?)?,
gains: (0..4) gains: {
.map(|_| { r.skip(1)?;
[
types::InputChannel::InA,
types::InputChannel::InB,
types::InputChannel::InC,
types::InputChannel::InD,
]
.into_iter()
.map(|input| {
let raw = r.read_u16()?; let raw = r.read_u16()?;
Ok::<f32, DSPError>(mapper::raw_to_matrix_gain(raw)?) let gain = mapper::raw_to_matrix_gain(raw)?;
Ok::<(types::InputChannel, f32), DSPError>((input, gain))
}) })
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<HashMap<_, _>, _>>()?
},
}; };
out.crossover = read_crossover(&mut r)?; out.crossover = read_crossover(&mut r)?;
@@ -196,7 +231,13 @@ pub fn decode_config(payload: &[u8]) -> Result<types::DSPConfigState, DSPError>
out.linked_channels = mapper::raw_to_link_channels( out.linked_channels = mapper::raw_to_link_channels(
mapper::channel_to_raw(types::Channel::Output(channel))?, mapper::channel_to_raw(types::Channel::Output(channel))?,
r.read_u8()?, r.read_u8()?,
)?; )?
.into_iter()
.filter_map(|link| match link {
types::Channel::Output(output) => Some(output),
types::Channel::Input(_) => None,
})
.collect();
} }
// ============================ // ============================
@@ -212,15 +253,11 @@ pub fn decode_config(payload: &[u8]) -> Result<types::DSPConfigState, DSPError>
// ============================ // ============================
for inp in &mut input_channels { for inp in &mut input_channels {
apply_flag(&mut r, inp.peq_chain.bands.as_mut_slice(), |band, value| { apply_peq_bypass(&mut r, &mut inp.peq_chain.bands)?;
band.bypass = value
})?;
} }
for out in &mut output_channels { for out in &mut output_channels {
apply_flag(&mut r, out.peq_chain.bands.as_mut_slice(), |band, value| { apply_peq_bypass(&mut r, &mut out.peq_chain.bands)?;
band.bypass = value
})?;
} }
// ============================ // ============================
@@ -260,9 +297,7 @@ pub fn decode_config(payload: &[u8]) -> Result<types::DSPConfigState, DSPError>
for (index, inp) in input_channels.iter_mut().enumerate() { for (index, inp) in input_channels.iter_mut().enumerate() {
let bypass = input_peq_bitmap & (1 << index) != 0; let bypass = input_peq_bitmap & (1 << index) != 0;
for peq in inp.peq_chain.bands.iter_mut() { inp.peq_chain.bypass = bypass;
peq.bypass = bypass;
}
} }
let output_peq_bitmap = r.read_u16()?; let output_peq_bitmap = r.read_u16()?;
@@ -270,9 +305,7 @@ pub fn decode_config(payload: &[u8]) -> Result<types::DSPConfigState, DSPError>
for (index, out) in output_channels.iter_mut().enumerate() { for (index, out) in output_channels.iter_mut().enumerate() {
let bypass = output_peq_bitmap & (1 << index) != 0; let bypass = output_peq_bitmap & (1 << index) != 0;
for peq in out.peq_chain.bands.iter_mut() { out.peq_chain.bypass = bypass;
peq.bypass = bypass;
}
} }
let bitmap = r.read_u16()?; let bitmap = r.read_u16()?;
-5
View File
@@ -77,8 +77,3 @@ pub fn output_link_mask(channel: u8) -> Option<u8> {
_ => None, _ => None,
} }
} }
pub const METERS_SPLIT: f32 = 1.0;
pub const METERS_SPLIT_LEVEL_DB: f32 = -18.0;
pub const METERS_LOW_STEP: f32 = 0.0104;
pub const METERS_HIGH_STEP: f32 = 0.0208;
+69 -11
View File
@@ -1,8 +1,12 @@
use std::{collections::HashMap, net::IpAddr}; use std::{collections::HashMap, net::IpAddr};
use strum_macros::{EnumCount, EnumIter}; use strum_macros::{EnumCount, EnumIter};
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
// ------ Enums ------ // ------ Enums ------
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DelayUnit { pub enum DelayUnit {
Millisecond, Millisecond,
@@ -10,6 +14,7 @@ pub enum DelayUnit {
Feet, Feet,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter, EnumCount, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter, EnumCount, PartialOrd, Ord)]
pub enum InputChannel { pub enum InputChannel {
InA, InA,
@@ -18,6 +23,7 @@ pub enum InputChannel {
InD, InD,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter, EnumCount, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter, EnumCount, PartialOrd, Ord)]
pub enum OutputChannel { pub enum OutputChannel {
Out1, Out1,
@@ -30,12 +36,14 @@ pub enum OutputChannel {
Out8, Out8,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Channel { pub enum Channel {
Input(InputChannel), Input(InputChannel),
Output(OutputChannel), Output(OutputChannel),
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Ratio { pub enum Ratio {
#[default] #[default]
@@ -57,6 +65,7 @@ pub enum Ratio {
Limit, Limit,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum CrossoverFilter { pub enum CrossoverFilter {
#[default] #[default]
@@ -83,6 +92,7 @@ pub enum CrossoverFilter {
Bl48, Bl48,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub enum PEQBand { pub enum PEQBand {
B1 = 1, B1 = 1,
@@ -96,6 +106,7 @@ pub enum PEQBand {
B9, B9,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PEQFilter { pub enum PEQFilter {
Peak, Peak,
@@ -109,6 +120,7 @@ pub enum PEQFilter {
AllPass2, AllPass2,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub enum DiscreteFrequency { pub enum DiscreteFrequency {
F20, F20,
@@ -144,6 +156,7 @@ pub enum DiscreteFrequency {
F20000, F20000,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InputType { pub enum InputType {
Analog, Analog,
@@ -152,6 +165,7 @@ pub enum InputType {
SineWave, SineWave,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct InputSource { pub struct InputSource {
pub r#type: InputType, pub r#type: InputType,
@@ -194,6 +208,7 @@ pub struct PresetName {
pub name: String, pub name: String,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DeviceFlags { pub struct DeviceFlags {
pub is_locked: bool, pub is_locked: bool,
@@ -204,9 +219,12 @@ pub struct AuthenticationResult {
pub success: bool, pub success: bool,
} }
#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Meters { #[derive(Debug, Clone, Copy, PartialEq)]
pub levels: Vec<f32>, pub struct Meter {
pub rms: f32,
pub peak: f32,
pub clip: bool,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@@ -230,7 +248,7 @@ pub enum DeviceResponseType {
PresetName(PresetName), PresetName(PresetName),
DeviceFlags(DeviceFlags), DeviceFlags(DeviceFlags),
AuthenticationResult(AuthenticationResult), AuthenticationResult(AuthenticationResult),
Meters(Meters), Meters(InputMeters, OutputMeters),
CurrentPreset(CurrentPreset), CurrentPreset(CurrentPreset),
ModifiedPreset(ModifiedPreset), ModifiedPreset(ModifiedPreset),
ConfigChunk(ConfigChunk), ConfigChunk(ConfigChunk),
@@ -238,7 +256,7 @@ pub enum DeviceResponseType {
} }
// ------ State ------ // ------ State ------
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Gate { pub struct Gate {
pub attack: u16, pub attack: u16,
@@ -247,6 +265,7 @@ pub struct Gate {
pub threshold: f32, pub threshold: f32,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Compressor { pub struct Compressor {
pub threshold: f32, pub threshold: f32,
@@ -256,6 +275,7 @@ pub struct Compressor {
pub knee: u16, pub knee: u16,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Limiter { pub struct Limiter {
pub threshold: f32, pub threshold: f32,
@@ -263,12 +283,14 @@ pub struct Limiter {
pub release: u16, pub release: u16,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct GraphicEQ { pub struct GraphicEQ {
pub gains: Vec<f32>, pub gains: HashMap<DiscreteFrequency, f32>,
pub bypass: bool, pub bypass: bool,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct PEQ { pub struct PEQ {
pub gain: f32, pub gain: f32,
@@ -278,30 +300,35 @@ pub struct PEQ {
pub bypass: bool, pub bypass: bool,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct CrossoverFilters { pub struct CrossoverFilters {
pub high_pass: Crossover, pub high_pass: Crossover,
pub low_pass: Crossover, pub low_pass: Crossover,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Crossover { pub struct Crossover {
pub frequency: f32, pub frequency: f32,
pub slope: CrossoverFilter, pub slope: CrossoverFilter,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct MatrixRoutes { pub struct MatrixRoutes {
pub connected: Vec<InputChannel>, pub connected: Vec<InputChannel>,
pub gains: Vec<f32>, pub gains: HashMap<InputChannel, f32>,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct PEQChain { pub struct PEQChain {
pub bands: Vec<PEQ>, pub bands: HashMap<PEQBand, PEQ>,
pub bypass: bool, pub bypass: bool,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct PresetBank { pub struct PresetBank {
pub current_index: usize, pub current_index: usize,
@@ -309,6 +336,7 @@ pub struct PresetBank {
pub modified: Vec<bool>, pub modified: Vec<bool>,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DeviceConnection { pub struct DeviceConnection {
pub host: IpAddr, pub host: IpAddr,
@@ -316,6 +344,7 @@ pub struct DeviceConnection {
pub device_id: u8, pub device_id: u8,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct InputChannelState { pub struct InputChannelState {
pub name: String, pub name: String,
@@ -326,10 +355,11 @@ pub struct InputChannelState {
pub geq: GraphicEQ, pub geq: GraphicEQ,
pub peq_chain: PEQChain, pub peq_chain: PEQChain,
pub crossover: CrossoverFilters, pub crossover: CrossoverFilters,
pub linked_channels: Vec<Channel>, pub linked_channels: Vec<InputChannel>,
pub mute: bool, pub mute: bool,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Default, PartialEq)] #[derive(Debug, Clone, Default, PartialEq)]
pub struct OutputChannelState { pub struct OutputChannelState {
pub name: String, pub name: String,
@@ -341,10 +371,11 @@ pub struct OutputChannelState {
pub gain: f32, pub gain: f32,
pub phase_inverted: bool, pub phase_inverted: bool,
pub delay: f32, pub delay: f32,
pub linked_channels: Vec<Channel>, pub linked_channels: Vec<OutputChannel>,
pub mute: bool, pub mute: bool,
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct DSPConfigState { pub struct DSPConfigState {
pub(crate) input_states: HashMap<InputChannel, InputChannelState>, pub(crate) input_states: HashMap<InputChannel, InputChannelState>,
@@ -367,11 +398,38 @@ impl DSPConfigState {
} }
} }
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DSPMode {
Demo,
Normal,
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectionStatus {
Connected,
Disconnected,
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct DSPState { pub struct DSPState {
pub(crate) name: String, pub(crate) name: String,
pub(crate) flags: DeviceFlags, pub(crate) flags: DeviceFlags,
pub(crate) presets: PresetBank, pub(crate) presets: PresetBank,
pub(crate) current_config: DSPConfigState, pub(crate) current_config: DSPConfigState,
pub(crate) connection: ConnectionStatus,
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct InputMeters {
pub meters: HashMap<InputChannel, Meter>,
}
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct OutputMeters {
pub meters: HashMap<OutputChannel, Meter>,
} }
+19 -4
View File
@@ -2,7 +2,6 @@ use std::net::IpAddr;
use std::str::FromStr; use std::str::FromStr;
use dsp_thomann::dsp408::DSP408; use dsp_thomann::dsp408::DSP408;
use dsp_thomann::dsp408::types;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let host = IpAddr::from_str("192.168.49.30")?; let host = IpAddr::from_str("192.168.49.30")?;
@@ -22,13 +21,29 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
println!("DSP connected."); println!("DSP connected.");
dsp.set_mute(types::Channel::Input(types::InputChannel::InA), true)?; // dsp.set_mute(types::Channel::Input(types::InputChannel::InA), true)?;
dbg!(dsp.state()?); // let r = dsp.set_peq_band(
// types::Channel::Input(InA),
// types::PEQBand::B1,
// 3.0,
// 1400.0,
// 2.1,
// types::PEQFilter::LowShelf,
// false,
// )?;
// dbg!(r);
dbg!(&dsp.state());
// let s = &dsp.state()?.current_config.input_states[&InputChannel::InA].peq_chain;
// dbg!(s)
println!("Disconnecting..."); println!("Disconnecting...");
dsp.disconnect(); dsp.disconnect()?;
println!("Disconnected"); println!("Disconnected");
Ok(()) Ok(())
} }
// 10020100 27 40 263df7 263dfd 263dfd 263dfd 063d8d 063d63 263dcf 263dfd 263df6 263dcf 263dcf 263dcf 0300 10038b