From 44cc3f4bdf01963a7426a0de80fa0c0525b403ee Mon Sep 17 00:00:00 2001 From: GHOSCHT <31184695+GHOSCHT@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:19:03 +0100 Subject: [PATCH] Implement basic control flow basic mpris control now works via supplied config.toml --- .envrc | 1 + Cargo.lock | 395 +++++++++++++++++++------------------------- Cargo.toml | 3 +- src/config.rs | 14 +- src/controller.rs | 96 +++++++++++ src/main.rs | 17 +- src/midi_client.rs | 23 +-- src/mpris_client.rs | 78 ++++++++- 8 files changed, 377 insertions(+), 250 deletions(-) create mode 100644 src/controller.rs diff --git a/.envrc b/.envrc index 3550a30..ba6561f 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,2 @@ +export RUST_LOG=info use flake diff --git a/Cargo.lock b/Cargo.lock index 7af0a90..0f727ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" version = "1.1.2" @@ -48,27 +33,60 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -81,27 +99,18 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "core-foundation" version = "0.9.3" @@ -203,16 +212,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "delay_map" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4355c25cbf99edcb6b4a0e906f6bdc6956eda149e84455bea49696429b2f8e8" -dependencies = [ - "futures", - "tokio-util", -] - [[package]] name = "derive_is_enum_variant" version = "0.1.1" @@ -241,6 +240,29 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -274,101 +296,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote 1.0.35", - "syn 2.0.52", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - [[package]] name = "hashbrown" version = "0.14.0" @@ -384,6 +311,12 @@ dependencies = [ "unicode-segmentation", ] +[[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" @@ -475,9 +408,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" @@ -501,15 +434,6 @@ dependencies = [ "windows", ] -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - [[package]] name = "mpris" version = "2.0.1" @@ -554,15 +478,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "object" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.18.0" @@ -574,10 +489,11 @@ name = "pico_kontroller" version = "0.1.0" dependencies = [ "crossbeam-channel", - "delay_map", + "env_logger", "int-enum", "itertools", "libpulse-binding", + "log", "midir", "mpris", "regex", @@ -585,18 +501,6 @@ dependencies = [ "toml", ] -[[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" @@ -669,12 +573,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - [[package]] name = "serde" version = "1.0.188" @@ -704,15 +602,6 @@ dependencies = [ "serde", ] -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "strsim" version = "0.10.0" @@ -781,30 +670,6 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "tokio" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "tokio-util" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "slab", - "tokio", -] - [[package]] name = "toml" version = "0.7.6" @@ -857,6 +722,12 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.9.4" @@ -955,13 +826,37 @@ version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "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-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -970,42 +865,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[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.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[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.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[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.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[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.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[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.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "winnow" version = "0.5.15" diff --git a/Cargo.toml b/Cargo.toml index d477077..c01a088 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,11 @@ edition = "2021" [dependencies] crossbeam-channel = "0.5.8" -delay_map = "0.3.0" +env_logger = "0.11.3" int-enum = "1.0.1" itertools = "0.11.0" libpulse-binding = "2.28.1" +log = "0.4.21" midir = "0.9.1" mpris = "2.0.1" regex = "1.10.3" diff --git a/src/config.rs b/src/config.rs index 8b19b60..d1ecdb6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,5 @@ use int_enum::IntEnum; +use log::{error, info, warn}; use serde::{Deserialize, Serialize}; use std::path::Path; use std::process; @@ -58,7 +59,7 @@ pub fn load(path: &str) -> Config { match cfg { Ok(expr) => expr, Err(expr) => { - eprintln!("Failed loading config at {path}: {expr}"); + error!("Failed loading config at {path}: {expr}"); process::exit(1); } } @@ -71,7 +72,7 @@ pub fn write_default(path: &str) -> () { let _ = fs::write(path, &cfg_toml_text); } Err(expr) => { - eprintln!("Failed serializing default config: {expr}"); + error!("Failed serializing default config: {expr}"); process::exit(1); } } @@ -85,7 +86,7 @@ pub enum MprisAction { Stop, Next, Previous, - VOLUME, + Volume, } #[derive(Debug, Serialize, Deserialize)] @@ -98,15 +99,20 @@ pub enum KeyMapVariant { PipeWire { ids: Vec, }, + Key { + keycode: u8, //TODO: add real keycodes + }, Exec { command: String, }, } +pub type KeyMap = BTreeMap>; + #[derive(Debug, Serialize, Deserialize)] pub struct Config { pub general: General, - pub keymap: BTreeMap>, + pub keymap: KeyMap, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/controller.rs b/src/controller.rs new file mode 100644 index 0000000..30a7e2f --- /dev/null +++ b/src/controller.rs @@ -0,0 +1,96 @@ +use crate::config::NanoKeys; +use crate::config::{Config, KeyMapVariant, MprisAction}; +use crate::midi_client::KeyEvent; +use crate::mpris_client; +use crossbeam_channel::Receiver; +use log::{error, info, warn}; +use std::sync::Arc; +use std::thread; + +pub fn run(in_channel: Receiver, config: Arc) { + thread::spawn(move || { + exec(in_channel, config); + }); +} + +fn exec(in_channel: Receiver, config: Arc) { + loop { + let event_in = in_channel.recv(); + match event_in { + Ok((key, state)) => { + eval(key, state, &config); + } + Err(err) => { + error!("Failed receiving event in controller thread: {err}"); + } + } + } +} + +fn eval(key: NanoKeys, state: u8, config: &Arc) { + match config.keymap.get(&key) { + Some(actions) => { + info!( + "Registered actions for [{:?} | {}]: {:?}", + key, state, actions + ); + for action in actions { + match action { + KeyMapVariant::Mpris { ids, action } => match action { + MprisAction::Play => { + if is_logical_true(state) { + continue; + } + ids.iter().for_each(|id| mpris_client::play(id)); + } + MprisAction::Pause => { + if is_logical_true(state) { + continue; + } + ids.iter().for_each(|id| mpris_client::pause(id)); + } + MprisAction::PlayPause => { + if is_logical_true(state) { + continue; + } + ids.iter().for_each(|id| mpris_client::play_pause(id)); + } + MprisAction::Stop => { + if is_logical_true(state) { + continue; + } + ids.iter().for_each(|id| mpris_client::stop(id)); + } + MprisAction::Next => { + if is_logical_true(state) { + continue; + } + ids.iter().for_each(|id| mpris_client::next(id)); + } + MprisAction::Previous => { + if is_logical_true(state) { + continue; + } + ids.iter().for_each(|id| mpris_client::previous(id)); + } + MprisAction::Volume => { + let volume = state as f64 / 100.0; + ids.iter() + .for_each(|id| mpris_client::set_volume(id, volume)); + } + }, + KeyMapVariant::PipeWire { ids } => {} + KeyMapVariant::Key { keycode } => {} + KeyMapVariant::Exec { command } => {} + } + } + } + None => { + warn!("Midi input {:?} not mapped", key); + } + } +} + +fn is_logical_true(state: u8) -> bool { + return state == 127; +} diff --git a/src/main.rs b/src/main.rs index baf136a..b992a5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,20 @@ -//use itertools::Itertools; -//use mpris::{Player, PlayerFinder}; mod config; +mod controller; mod midi_client; +mod mpris_client; mod pulse_client; +use crossbeam_channel::unbounded; +use std::sync::Arc; fn main() { - midi_client::run().unwrap(); + env_logger::init(); + let path: &str = "./config.toml"; + let cfg: config::Config = config::init(path); + let arc_cfg = Arc::new(cfg); + // midi_client::list_ports(); + // mpris_client::list_clients(); + + let (sender, receiver) = unbounded::(); + controller::run(receiver, Arc::clone(&arc_cfg)); + midi_client::run(&arc_cfg.general.midi_device, sender).unwrap(); } diff --git a/src/midi_client.rs b/src/midi_client.rs index 35dde73..3a0525d 100644 --- a/src/midi_client.rs +++ b/src/midi_client.rs @@ -1,7 +1,9 @@ use crate::config::NanoKeys; +use crossbeam_channel::Sender; use midir::{Ignore, MidiInput}; use regex::Regex; use std::error::Error; +use std::time; pub fn list_ports() -> () { let midi_in = MidiInput::new("PicoKontroller").expect("Creating Midi device failed"); @@ -12,7 +14,7 @@ pub fn list_ports() -> () { } } -pub fn run(port_name: &str) -> Result<(), Box> { +pub fn run(port_name: &str, out_channel: Sender) -> Result<(), Box> { let port_filter = Regex::new(port_name).expect("Creating RegEx failed"); let mut midi_in = MidiInput::new("PicoKontroller").expect("Creating Midi device failed"); @@ -29,16 +31,17 @@ pub fn run(port_name: &str) -> Result<(), Box> { in_port, "PicoController Input", move |_, message, _| { - let key = message[1]; - let volume = message[2] as f64 / 127.0; - println!( - "Key: {:?} | State: {:.2}", - NanoKeys::try_from(key).unwrap(), - volume - ); + let key = NanoKeys::try_from(message[1]).unwrap(); + let state = message[2]; + let _ = out_channel.send((key, state)); }, (), )?; - - loop {} + loop { + // sleep forever, callback functions happen on separate thread + // couldn't reuse this thread, since _conn_in needs to be alive in this scope + std::thread::sleep(time::Duration::from_secs(u64::MAX)); + } } + +pub type KeyEvent = (NanoKeys, u8); diff --git a/src/mpris_client.rs b/src/mpris_client.rs index 38a8d64..47e1b02 100644 --- a/src/mpris_client.rs +++ b/src/mpris_client.rs @@ -1,13 +1,85 @@ +use mpris::Player; use mpris::PlayerFinder; +use regex::Regex; -pub fn set_volume(player_id: &str, volume: f64) { +pub fn list_clients() -> () { PlayerFinder::new() .expect("Could not connect to D-Bus") .find_all() .unwrap_or_else(|_| Vec::new()) .into_iter() - .filter(|player| player.identity() == player_id) .for_each(|player| { - let _ = player.set_volume(volume); + println!("{}", player.identity()); }); } + +fn for_all_players(player_id: &str, function: F) +where + F: Fn(&Player) -> (), +{ + let player_filter = Regex::new(player_id).expect("Creating RegEx failed"); + PlayerFinder::new() + .expect("Could not connect to D-Bus") + .find_all() + .unwrap_or_else(|_| Vec::new()) + .into_iter() + .filter(|player| player_filter.is_match(player.identity())) + .into_iter() + .for_each(|player| { + function(&player); + }); +} + +fn for_active_player(function: F) +where + F: Fn(&Player) -> (), +{ + let player = PlayerFinder::new() + .expect("Could not connect to D-Bus") + .find_active() + .expect("Could not find any player"); + + function(&player); +} + +pub fn play(player_id: &str) -> () { + for_all_players(player_id, |player| { + let _ = player.play(); + }); +} + +pub fn pause(player_id: &str) -> () { + for_all_players(player_id, |player| { + let _ = player.pause(); + }); +} + +pub fn play_pause(player_id: &str) -> () { + for_all_players(player_id, |player| { + let _ = player.play_pause(); + }); +} + +pub fn stop(player_id: &str) -> () { + for_all_players(player_id, |player| { + let _ = player.stop(); + }); +} + +pub fn next(player_id: &str) -> () { + for_all_players(player_id, |player| { + let _ = player.next(); + }); +} + +pub fn previous(player_id: &str) -> () { + for_all_players(player_id, |player| { + let _ = player.previous(); + }); +} + +pub fn set_volume(player_id: &str, volume: f64) -> () { + for_all_players(player_id, |player| { + let _ = player.set_volume(volume); + }); +}