diff --git a/src/clients/midi.rs b/src/clients/midi.rs index 0fad423..01a6d0e 100644 --- a/src/clients/midi.rs +++ b/src/clients/midi.rs @@ -1,9 +1,14 @@ use crate::{config::NanoKeys, interaction_server::InteractionServer}; use crossbeam_channel::Sender; -use midir::{Ignore, MidiInput}; -use regex::Regex; -use std::thread::{self, JoinHandle}; -use std::time; +use midir::MidiInput; +use shaku::{module, HasComponent, Interface}; +use std::marker::PhantomData; +use std::sync::Arc; + +use super::midi_client::MidiPort; +use super::midi_service::MidiService; +use super::midi_service_impl::{MidiServiceImpl, MidiServiceImplParameters}; +use super::midir_client_impl::{MidirClientImpl, MidirPortImpl}; const CLIENT_NAME: &str = "PicoKontroller"; const PORT_NAME: &str = "PicoController Input"; @@ -16,11 +21,10 @@ pub struct MidiClient { pub type KeyEvent = (NanoKeys, KeyState); pub type KeyState = u8; -impl InteractionServer for MidiClient { - fn start(self) -> JoinHandle<()> { - thread::spawn(move || { - self.exec(); - }) +module! { + MyModule { + components = [MidiServiceImpl, MidirClientImpl], + providers = [], } } @@ -32,34 +36,20 @@ impl MidiClient { } } - fn exec(self) { - let port_filter = Regex::new(&self.device_name).expect("Creating RegEx failed"); + pub fn start(self) -> () { + let module: MyModule = MyModule::builder() + .with_component_parameters::>( + MidiServiceImplParameters:: { + device_name: "nanoKONTROL2".to_string(), + out_channel: self.out_channel, + phantom: PhantomData, + }, + ) + .build(); - let mut midi_in = MidiInput::new(CLIENT_NAME).expect("Creating MIDI device failed"); - midi_in.ignore(Ignore::None); - - let in_ports = midi_in.ports(); - let in_port = in_ports - .iter() - .find(|p| port_filter.is_match(&midi_in.port_name(p).unwrap())) - .expect("Couldn't find a port matching the supplied RegEx"); - - // _conn_in needs to be a named parameter, because it needs to be kept alive until the end of the scope - let _conn_in = midi_in.connect( - in_port, - PORT_NAME, - move |_, message, _| { - let key = NanoKeys::try_from(message[1]).unwrap(); - let state = message[2]; - let _ = self.out_channel.send((key, state)); - }, - (), - ); - 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)); - } + let service: Arc> = module.resolve(); + let handle = service.start(); + let _ = handle.join(); } } diff --git a/src/clients/midi_client.rs b/src/clients/midi_client.rs index a89d61b..6205651 100644 --- a/src/clients/midi_client.rs +++ b/src/clients/midi_client.rs @@ -1,14 +1,14 @@ use shaku::{self, Interface}; -pub type MidiConnectionCallback = Box; +pub type MidiConnectionCallback = Box; #[cfg_attr(test, mockall::automock)] -pub trait MidiClient: Interface { +pub trait MidiClient: Interface { fn ports(&self) -> Vec; - fn connect(&self, port: MP, port_name: &str, callback: MidiConnectionCallback) -> (); + fn connect(&self, port: &MP, port_name: &str, callback: MidiConnectionCallback) -> (); } #[cfg_attr(test, mockall::automock)] -pub trait MidiPort : Interface{ +pub trait MidiPort: Interface { fn name(&self) -> String; } diff --git a/src/clients/midi_service.rs b/src/clients/midi_service.rs new file mode 100644 index 0000000..5533211 --- /dev/null +++ b/src/clients/midi_service.rs @@ -0,0 +1,11 @@ +use std::{sync::Arc, thread::JoinHandle}; + +use shaku::Interface; + +use super::midi_client::MidiPort; + +pub trait MidiService: Interface { + fn exec(self: Arc); + fn list_ports(&self) -> (); + fn start(self: Arc) -> JoinHandle<()>; +} diff --git a/src/clients/midi_service_impl.rs b/src/clients/midi_service_impl.rs new file mode 100644 index 0000000..25ead51 --- /dev/null +++ b/src/clients/midi_service_impl.rs @@ -0,0 +1,59 @@ +use super::midi_client::{MidiClient, MidiPort}; +use super::midi_service::MidiService; +use crate::config::NanoKeys; +use crossbeam_channel::Sender; +use regex::Regex; +use shaku::{self, Component, Interface}; +use std::marker::PhantomData; +use std::sync::Arc; +use std::thread::{self, JoinHandle}; + +const CLIENT_NAME: &str = "PicoKontroller"; +const PORT_NAME: &str = "PicoController Input"; + +#[derive(Component)] +#[shaku(interface = MidiService)] +pub struct MidiServiceImpl { + #[shaku(default)] + device_name: String, + #[shaku(default = unimplemented!())] + out_channel: Sender, + #[shaku(inject)] + midi_client: Arc>, + #[shaku(default = PhantomData)] + phantom: PhantomData, +} + +pub type KeyEvent = (NanoKeys, KeyState); +pub type KeyState = u8; + +impl MidiService for MidiServiceImpl { + fn exec(self: Arc) { + let port_filter = Regex::new(&self.device_name).expect("Creating RegEx failed"); + let ports = self.midi_client.ports(); + + let port = ports + .iter() + .find(|p| port_filter.is_match(&p.name())) + .expect("Couldn't find a port matching the supplied RegEx"); + + let channel = self.out_channel.clone(); + + let callback = Box::new(move |message: &[u8]| { + let key = NanoKeys::try_from(message[1]).unwrap(); + let state = message[2]; + let _ = channel.send((key, state)); + }); + + self.midi_client.connect(&port, PORT_NAME, callback); + } + + fn list_ports(&self) -> () {} + + fn start(self: Arc) -> JoinHandle<()> { + let foo = self.clone(); + thread::spawn(move || { + foo.exec(); + }) + } +} diff --git a/src/clients/midir_client_impl.rs b/src/clients/midir_client_impl.rs index 1e7dc86..53f2a63 100644 --- a/src/clients/midir_client_impl.rs +++ b/src/clients/midir_client_impl.rs @@ -1,4 +1,4 @@ -use midir::{MidiInput, MidiInputPort, Ignore}; +use midir::{Ignore, MidiInput, MidiInputPort}; use shaku::{self, Component}; use super::midi_client::{MidiClient, MidiConnectionCallback, MidiPort}; @@ -13,6 +13,7 @@ fn create_input(client_name: &str) -> MidiInput { #[derive(Component)] #[shaku(interface = MidiClient)] pub struct MidirClientImpl { + #[shaku(default)] client_name: String, } @@ -25,9 +26,10 @@ impl MidiClient for MidirClientImpl { .map(|p| MidirPortImpl::new(p.clone(), self.client_name.clone())) // Cast to Box .collect() } + fn connect( &self, - port: MidirPortImpl, + port: &MidirPortImpl, port_name: &str, callback: MidiConnectionCallback, ) -> () { diff --git a/src/main.rs b/src/main.rs index c9e339a..158eb3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,18 @@ mod config; -mod router; mod interaction_server; +mod router; mod controllers { + pub mod exec; pub mod mpris; pub mod pulse; - pub mod exec; } mod clients; use clap::Parser; +use clients::midi::MidiClient; use crossbeam_channel::unbounded; use directories::ProjectDirs; -use interaction_server::InteractionServer; -use clients::midi::MidiClient; use std::{path::PathBuf, process::exit, sync::Arc}; #[derive(Parser)] @@ -47,6 +46,6 @@ fn main() { router::run(receiver, Arc::clone(&arc_cfg)); - let server = midi.start(); - let _ = server.join(); + midi.start(); + println!("fooo"); }