diff --git a/Cargo.lock b/Cargo.lock index be7b1b8..d724e7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + [[package]] name = "autocfg" version = "1.1.0" @@ -290,6 +296,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "either" version = "1.9.0" @@ -342,6 +354,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "from_variants" version = "1.0.2" @@ -529,6 +547,32 @@ dependencies = [ "windows", ] +[[package]] +name = "mockall" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote 1.0.35", + "syn 2.0.52", +] + [[package]] name = "mpris" version = "2.0.1" @@ -598,9 +642,11 @@ dependencies = [ "libpulse-binding", "log", "midir", + "mockall", "mpris", "regex", "serde", + "shaku", "toml", ] @@ -610,6 +656,32 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "predicates" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" + +[[package]] +name = "predicates-tree" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -725,6 +797,28 @@ dependencies = [ "serde", ] +[[package]] +name = "shaku" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d599314a26c92706bde1c984391b1eeb77ebf46e23142216a58eacb6e12f858b" +dependencies = [ + "anymap2", + "once_cell", + "shaku_derive", +] + +[[package]] +name = "shaku_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524f791f1f958b9c1825c1e48657d3bc485ee9ac4a1c7c226ab7fc7010afa7dc" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 1.0.109", +] + [[package]] name = "strsim" version = "0.10.0" @@ -779,6 +873,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + [[package]] name = "thiserror" version = "1.0.47" diff --git a/Cargo.toml b/Cargo.toml index b70d99e..a1dab3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,9 @@ itertools = "0.11.0" libpulse-binding = "2.28.1" log = "0.4.21" midir = "0.9.1" +mockall = "0.13.1" mpris = "2.0.1" regex = "1.10.3" serde = {version ="1.0.188", features = ["derive"]} +shaku = "0.6.2" toml = "0.7.6" - diff --git a/src/clients/mod.rs b/src/clients/mod.rs new file mode 100644 index 0000000..2e1bc3e --- /dev/null +++ b/src/clients/mod.rs @@ -0,0 +1,5 @@ +pub mod midi; +mod services { + pub mod midi_service; + pub mod midir_service; +} diff --git a/src/clients/services/midi_service.rs b/src/clients/services/midi_service.rs new file mode 100644 index 0000000..1329d10 --- /dev/null +++ b/src/clients/services/midi_service.rs @@ -0,0 +1,14 @@ +use shaku::{self, Interface}; + +pub type MidiConnectionCallback = Box; + +#[cfg_attr(test, mockall::automock)] +pub trait MidiService: Interface { + fn ports(&self) -> Vec; + fn connect(&self, port: MP, port_name: &str, callback: MidiConnectionCallback) -> (); +} + +#[cfg_attr(test, mockall::automock)] +pub trait MidiPort : Interface{ + fn name(&self) -> String; +} diff --git a/src/clients/services/midir_service.rs b/src/clients/services/midir_service.rs new file mode 100644 index 0000000..33cfaef --- /dev/null +++ b/src/clients/services/midir_service.rs @@ -0,0 +1,59 @@ +use midir::{MidiInput, MidiInputPort}; +use shaku::{self, Component}; + +use super::midi_service::{MidiConnectionCallback, MidiPort, MidiService}; +use std::time; + +fn create_input(client_name: &str) -> MidiInput { + MidiInput::new(client_name).expect("Creating MIDI device failed") +} + +#[derive(Component)] +#[shaku(interface = MidiService)] +pub struct MidirService { + client_name: String, +} + +impl MidiService for MidirService { + fn ports(&self) -> Vec { + let midi_in = create_input(&self.client_name); + midi_in + .ports() + .iter() + .map(|p| MidirPort::new(p.clone(), self.client_name.clone())) // Cast to Box + .collect() + } + fn connect(&self, port: MidirPort, port_name: &str, callback: MidiConnectionCallback) -> () { + let midi_in = MidiInput::new(&self.client_name).expect("Creating MIDI device failed"); + let connection = midi_in.connect( + port.get_port(), + port_name, + move |_, message, _| callback(message), + (), + ); + loop { + std::thread::sleep(time::Duration::from_secs(u64::MAX)); + } + } +} + +pub struct MidirPort { + port: MidiInputPort, + client_name: String, +} + +impl MidiPort for MidirPort { + fn name(&self) -> String { + let midi_in = create_input(&self.client_name); + midi_in.port_name(&self.port).unwrap() + } +} + +impl MidirPort { + fn new(port: MidiInputPort, client_name: String) -> MidirPort { + MidirPort { port, client_name } + } + fn get_port(&self) -> &MidiInputPort { + &self.port + } +} diff --git a/src/main.rs b/src/main.rs index a3a48f6..c9e339a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,7 @@ mod controllers { pub mod pulse; pub mod exec; } - -mod clients { - pub mod midi; -} +mod clients; use clap::Parser; use crossbeam_channel::unbounded;