Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
0d8a51816c |
10 changed files with 78 additions and 346 deletions
100
Cargo.lock
generated
100
Cargo.lock
generated
|
@ -81,12 +81,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -296,12 +290,6 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"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]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
@ -354,12 +342,6 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fragile"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "from_variants"
|
name = "from_variants"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -547,32 +529,6 @@ dependencies = [
|
||||||
"windows",
|
"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]]
|
[[package]]
|
||||||
name = "mpris"
|
name = "mpris"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
@ -642,11 +598,9 @@ dependencies = [
|
||||||
"libpulse-binding",
|
"libpulse-binding",
|
||||||
"log",
|
"log",
|
||||||
"midir",
|
"midir",
|
||||||
"mockall",
|
|
||||||
"mpris",
|
"mpris",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"shaku",
|
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -656,32 +610,6 @@ version = "0.3.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
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]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.78"
|
version = "1.0.78"
|
||||||
|
@ -797,28 +725,6 @@ dependencies = [
|
||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -873,12 +779,6 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termtree"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.47"
|
version = "1.0.47"
|
||||||
|
|
|
@ -13,9 +13,8 @@ itertools = "0.11.0"
|
||||||
libpulse-binding = "2.28.1"
|
libpulse-binding = "2.28.1"
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
midir = "0.9.1"
|
midir = "0.9.1"
|
||||||
mockall = "0.13.1"
|
|
||||||
mpris = "2.0.1"
|
mpris = "2.0.1"
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
serde = {version ="1.0.188", features = ["derive"]}
|
serde = {version ="1.0.188", features = ["derive"]}
|
||||||
shaku = "0.6.2"
|
|
||||||
toml = "0.7.6"
|
toml = "0.7.6"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# picoKontroller
|
# picoKontroller
|
||||||
[![ci/cd](https://git.ghoscht.com/ghoscht/picoKontroller/badges/workflows/ci.yml/badge.svg?style=for-the-badge)](https://git.ghoscht.com/ghoscht/picoKontroller/actions?workflow=ci.yml)
|
[![ci/cd](https://git.ghoscht.com/ghoscht/picoKontroller/badges/workflows/ci.yml/badge.svg?style=for-the-badge)](https://git.ghoscht.com/ghoscht/picoKontroller/actions?workflow=ci.yml)
|
||||||
|
[![ci/cd](https://git.ghoscht.com/ghoscht/picoKontroller/badges/release.svg?style=for-the-badge)](#)
|
||||||
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0)
|
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
[![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org)
|
[![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org)
|
||||||
|
|
||||||
|
|
|
@ -1,41 +1,73 @@
|
||||||
use crate::{config::NanoKeys, interaction_server::InteractionServer};
|
use crate::{config::NanoKeys, interaction_server::InteractionServer};
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use midir::MidiInput;
|
use midir::{Ignore, MidiInput};
|
||||||
|
use regex::Regex;
|
||||||
use super::midi_client::{MidiClient, MidiPort, MockMidiClient, MockMidiPort};
|
use std::thread::{self, JoinHandle};
|
||||||
use super::midi_service::MidiService;
|
use std::time;
|
||||||
use super::midi_service_impl::{MidiServiceImpl, MidiServiceImplParameters};
|
|
||||||
use super::midir_client_impl::{MidirClientImpl, MidirPortImpl};
|
|
||||||
|
|
||||||
const CLIENT_NAME: &str = "PicoKontroller";
|
const CLIENT_NAME: &str = "PicoKontroller";
|
||||||
const PORT_NAME: &str = "PicoController Input";
|
const PORT_NAME: &str = "PicoController Input";
|
||||||
|
|
||||||
//pub struct MidiClient {
|
pub struct MidiClient {
|
||||||
// pub device_name: String,
|
pub device_name: String,
|
||||||
// pub out_channel: Sender<KeyEvent>,
|
pub out_channel: Sender<KeyEvent>,
|
||||||
//}
|
}
|
||||||
|
|
||||||
pub type KeyEvent = (NanoKeys, KeyState);
|
pub type KeyEvent = (NanoKeys, KeyState);
|
||||||
pub type KeyState = u8;
|
pub type KeyState = u8;
|
||||||
|
|
||||||
|
impl InteractionServer for MidiClient {
|
||||||
|
fn start(self) -> JoinHandle<()> {
|
||||||
|
thread::spawn(move || {
|
||||||
|
self.exec();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//impl MidiClient {
|
impl MidiClient {
|
||||||
// pub fn new(device_name: String, out_channel: Sender<KeyEvent>) -> MidiClient {
|
pub fn new(device_name: String, out_channel: Sender<KeyEvent>) -> MidiClient {
|
||||||
// MidiClient {
|
MidiClient {
|
||||||
// device_name,
|
device_name,
|
||||||
// out_channel,
|
out_channel,
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// pub fn start(self) -> () {
|
fn exec(self) {
|
||||||
// }
|
let port_filter = Regex::new(&self.device_name).expect("Creating RegEx failed");
|
||||||
//}
|
|
||||||
//
|
let mut midi_in = MidiInput::new(CLIENT_NAME).expect("Creating MIDI device failed");
|
||||||
//pub fn list_ports() -> () {
|
midi_in.ignore(Ignore::None);
|
||||||
// let midi_in = MidiInput::new(CLIENT_NAME).expect("Creating MIDI device failed");
|
|
||||||
// let in_ports = midi_in.ports();
|
let in_ports = midi_in.ports();
|
||||||
// println!("All available MIDI devices:");
|
let in_port = in_ports
|
||||||
// for (_, p) in in_ports.iter().enumerate() {
|
.iter()
|
||||||
// println!("{}", midi_in.port_name(p).unwrap());
|
.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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_ports() -> () {
|
||||||
|
let midi_in = MidiInput::new(CLIENT_NAME).expect("Creating MIDI device failed");
|
||||||
|
let in_ports = midi_in.ports();
|
||||||
|
println!("All available MIDI devices:");
|
||||||
|
for (_, p) in in_ports.iter().enumerate() {
|
||||||
|
println!("{}", midi_in.port_name(p).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
use std::any::Any;
|
|
||||||
|
|
||||||
use shaku::{self, Interface};
|
|
||||||
|
|
||||||
pub type MidiConnectionCallback = Box<dyn Fn(&[u8]) + Send>;
|
|
||||||
|
|
||||||
#[mockall::automock]
|
|
||||||
pub trait MidiClient<MP: MidiPort + Interface>: Interface {
|
|
||||||
fn ports(&self) -> Vec<MP>;
|
|
||||||
fn connect(&self, port: &MP, port_name: &str, callback: MidiConnectionCallback) -> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[mockall::automock]
|
|
||||||
pub trait MidiPort: Interface + Send{
|
|
||||||
fn name(&self) -> String;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
use std::{sync::Arc, thread::JoinHandle};
|
|
||||||
|
|
||||||
use shaku::Interface;
|
|
||||||
|
|
||||||
use super::midi_client::MidiPort;
|
|
||||||
|
|
||||||
pub trait MidiService<MP: MidiPort + Interface>: Interface {
|
|
||||||
fn exec(self: Arc<Self>);
|
|
||||||
fn list_ports(&self) -> ();
|
|
||||||
fn start(self: Arc<Self>) -> JoinHandle<()>;
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
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<MP>)]
|
|
||||||
pub struct MidiServiceImpl<MP: MidiPort + Interface> {
|
|
||||||
#[shaku(default)]
|
|
||||||
device_name: String,
|
|
||||||
#[shaku(default = unimplemented!())]
|
|
||||||
out_channel: Sender<KeyEvent>,
|
|
||||||
#[shaku(inject)]
|
|
||||||
midi_client: Arc<dyn MidiClient<MP>>,
|
|
||||||
#[shaku(default = PhantomData)]
|
|
||||||
phantom: PhantomData<MP>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type KeyEvent = (NanoKeys, KeyState);
|
|
||||||
pub type KeyState = u8;
|
|
||||||
|
|
||||||
impl<MP: MidiPort + Interface> MidiService<MP> for MidiServiceImpl<MP> {
|
|
||||||
fn exec(self: Arc<Self>) {
|
|
||||||
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<Self>) -> JoinHandle<()> {
|
|
||||||
let foo = self.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
foo.exec();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
use midir::{Ignore, MidiInput, MidiInputPort};
|
|
||||||
use shaku::{self, Component};
|
|
||||||
|
|
||||||
use super::midi_client::{MidiClient, MidiConnectionCallback, MidiPort};
|
|
||||||
use std::{any::Any, time};
|
|
||||||
|
|
||||||
fn create_input(client_name: &str) -> MidiInput {
|
|
||||||
let mut input = MidiInput::new(client_name).expect("Creating MIDI device failed");
|
|
||||||
input.ignore(Ignore::None);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
#[shaku(interface = MidiClient<MidirPortImpl>)]
|
|
||||||
pub struct MidirClientImpl {
|
|
||||||
#[shaku(default)]
|
|
||||||
client_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MidiClient<MidirPortImpl> for MidirClientImpl {
|
|
||||||
fn ports(&self) -> Vec<MidirPortImpl> {
|
|
||||||
let midi_in = create_input(&self.client_name);
|
|
||||||
midi_in
|
|
||||||
.ports()
|
|
||||||
.iter()
|
|
||||||
.map(|p| MidirPortImpl::new(p.clone(), self.client_name.clone())) // Cast to Box<dyn MidiPort>
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn connect(
|
|
||||||
&self,
|
|
||||||
port: &MidirPortImpl,
|
|
||||||
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 MidirPortImpl {
|
|
||||||
port: MidiInputPort,
|
|
||||||
client_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MidiPort for MidirPortImpl {
|
|
||||||
fn name(&self) -> String {
|
|
||||||
let midi_in = create_input(&self.client_name);
|
|
||||||
midi_in.port_name(&self.port).unwrap()
|
|
||||||
}
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MidirPortImpl {
|
|
||||||
fn new(port: MidiInputPort, client_name: String) -> MidirPortImpl {
|
|
||||||
MidirPortImpl { port, client_name }
|
|
||||||
}
|
|
||||||
fn get_port(&self) -> &MidiInputPort {
|
|
||||||
&self.port
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
pub mod midi;
|
|
||||||
pub mod midi_client;
|
|
||||||
pub mod midir_client_impl;
|
|
||||||
pub mod midi_service;
|
|
||||||
pub mod midi_service_impl;
|
|
66
src/main.rs
66
src/main.rs
|
@ -1,27 +1,24 @@
|
||||||
mod config;
|
mod config;
|
||||||
mod interaction_server;
|
|
||||||
mod router;
|
mod router;
|
||||||
|
mod interaction_server;
|
||||||
|
|
||||||
mod controllers {
|
mod controllers {
|
||||||
pub mod exec;
|
|
||||||
pub mod mpris;
|
pub mod mpris;
|
||||||
pub mod pulse;
|
pub mod pulse;
|
||||||
|
pub mod exec;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod clients {
|
||||||
|
pub mod midi;
|
||||||
}
|
}
|
||||||
mod clients;
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use clients::midi::KeyEvent;
|
use crossbeam_channel::unbounded;
|
||||||
use clients::midi_client::{MidiClient, MidiPort, MockMidiClient, MockMidiPort};
|
|
||||||
use clients::midi_service::MidiService;
|
|
||||||
use clients::midi_service_impl::{MidiServiceImpl, MidiServiceImplParameters};
|
|
||||||
use clients::midir_client_impl::{MidirClientImpl, MidirPortImpl};
|
|
||||||
use crossbeam_channel::{unbounded, Sender};
|
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
|
use interaction_server::InteractionServer;
|
||||||
|
use clients::midi::MidiClient;
|
||||||
use std::{path::PathBuf, process::exit, sync::Arc};
|
use std::{path::PathBuf, process::exit, sync::Arc};
|
||||||
|
|
||||||
use shaku::{module, HasComponent, Interface, ModuleBuilder};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
@ -31,32 +28,12 @@ struct Cli {
|
||||||
list_mpris: bool,
|
list_mpris: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
module! {
|
|
||||||
MyModule<MP: MidiPort + Interface> {
|
|
||||||
components = [MidiServiceImpl<MidirPortImpl>, MidirClientImpl],
|
|
||||||
providers = [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_module(
|
|
||||||
device_name: String,
|
|
||||||
out_channel: Sender<KeyEvent>,
|
|
||||||
) -> ModuleBuilder<MyModule<MidirPortImpl>> {
|
|
||||||
MyModule::builder().with_component_parameters::<MidiServiceImpl<MidirPortImpl>>(
|
|
||||||
MidiServiceImplParameters::<MidirPortImpl> {
|
|
||||||
device_name,
|
|
||||||
out_channel,
|
|
||||||
phantom: PhantomData,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
if cli.list_midi {
|
if cli.list_midi {
|
||||||
//clients::midi::list_ports();
|
clients::midi::list_ports();
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if cli.list_mpris {
|
} else if cli.list_mpris {
|
||||||
controllers::mpris::list_players();
|
controllers::mpris::list_players();
|
||||||
|
@ -69,25 +46,10 @@ fn main() {
|
||||||
let arc_cfg = Arc::new(cfg);
|
let arc_cfg = Arc::new(cfg);
|
||||||
|
|
||||||
let (sender, receiver) = unbounded::<clients::midi::KeyEvent>();
|
let (sender, receiver) = unbounded::<clients::midi::KeyEvent>();
|
||||||
|
let midi = MidiClient::new(arc_cfg.general.midi_device.clone(), sender);
|
||||||
let mut client_mock = MockMidiClient::<MockMidiPort>::new();
|
|
||||||
let mut port_mock = MockMidiPort::new();
|
|
||||||
port_mock
|
|
||||||
.expect_name()
|
|
||||||
.times(1)
|
|
||||||
.returning(|| "nanoKONTROL2:nanoKONTROL2 nanoKONTROL2 _ CTR 28:0".to_string());
|
|
||||||
client_mock
|
|
||||||
.expect_ports()
|
|
||||||
.times(1)
|
|
||||||
.returning(|| vec![port_mock]);
|
|
||||||
|
|
||||||
let module: MyModule<MockMidiPort> = MyModule::builder()
|
|
||||||
.with_component_override::<dyn MidiClient<MockMidiPort>>(Box::new(client_mock))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let service: Arc<dyn MidiService<MidirPortImpl>> = module.resolve();
|
|
||||||
let handle = service.start();
|
|
||||||
let _ = handle.join();
|
|
||||||
|
|
||||||
router::run(receiver, Arc::clone(&arc_cfg));
|
router::run(receiver, Arc::clone(&arc_cfg));
|
||||||
|
|
||||||
|
let server = midi.start();
|
||||||
|
let _ = server.join();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue