strip MIDI/BLE transport, make UDP the sole connection method
Remove ble.rs, midir dependency, TransportMode enum, and all MIDI-related Message variants (OpenMidiSetup, RefreshMidi, ToggleTransport). Simplify subscription to UDP-only path. Rename BleReady/BleStatus/BleData to DeviceReady/DeviceStatus/DeviceData. Replace transport toggle UI with always-visible UDP address field and Reconnect button.
This commit is contained in:
parent
06f4fa8e71
commit
fc0ff900f1
|
|
@ -54,28 +54,6 @@ version = "0.2.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "alsa"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags 2.11.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alsa-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.6.0"
|
||||
|
|
@ -639,27 +617,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coremidi"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "964eb3e10ea8b0d29c797086aab3ca730f75e06dced0cb980642fd274a5cca30"
|
||||
dependencies = [
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"coremidi-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coremidi-sys"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9504310988d938e49fff1b5f1e56e3dafe39bb1bae580c19660b58b83a191e"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmic-text"
|
||||
version = "0.12.1"
|
||||
|
|
@ -764,7 +721,6 @@ dependencies = [
|
|||
"dirs-next",
|
||||
"futures",
|
||||
"iced",
|
||||
"midir",
|
||||
"muda",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
|
|
@ -1393,7 +1349,7 @@ dependencies = [
|
|||
"presser",
|
||||
"thiserror 1.0.69",
|
||||
"winapi",
|
||||
"windows 0.52.0",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2013,23 +1969,6 @@ dependencies = [
|
|||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "midir"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b73f8737248ad37b88291a2108d9df5f991dc8555103597d586b5a29d4d703c0"
|
||||
dependencies = [
|
||||
"alsa",
|
||||
"bitflags 1.3.2",
|
||||
"coremidi",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"parking_lot 0.12.5",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"windows 0.56.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
|
|
@ -4222,17 +4161,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
|
||||
dependencies = [
|
||||
"windows-core 0.56.0",
|
||||
"windows-core",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
|
|
@ -4245,55 +4174,12 @@ dependencies = [
|
|||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[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.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
iced = { version = "0.13", features = ["canvas", "tokio"] }
|
||||
midir = "0.10"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures = "0.3"
|
||||
muda = { version = "0.17", default-features = false }
|
||||
|
|
|
|||
193
cue/src/app.rs
193
cue/src/app.rs
|
|
@ -9,7 +9,6 @@ use std::fmt::Write;
|
|||
use std::time::Duration;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::ble::BleEvent;
|
||||
use crate::native_menu::{MenuAction, NativeMenu};
|
||||
use crate::protocol::{
|
||||
self, AmpPoint, ClPoint, ClResult, Electrode, EisMessage, EisPoint, LpRtia, LsvPoint,
|
||||
|
|
@ -18,12 +17,6 @@ use crate::protocol::{
|
|||
use crate::storage::{self, Session, Storage};
|
||||
use crate::udp::UdpEvent;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum TransportMode {
|
||||
Midi,
|
||||
Udp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Tab {
|
||||
Eis,
|
||||
|
|
@ -58,9 +51,9 @@ impl std::fmt::Display for SessionItem {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
BleReady(mpsc::UnboundedSender<Vec<u8>>),
|
||||
BleStatus(String),
|
||||
BleData(EisMessage),
|
||||
DeviceReady(mpsc::UnboundedSender<Vec<u8>>),
|
||||
DeviceStatus(String),
|
||||
DeviceData(EisMessage),
|
||||
TabSelected(Tab),
|
||||
PaneResized(pane_grid::ResizeEvent),
|
||||
DataAction(text_editor::Action),
|
||||
|
|
@ -132,9 +125,7 @@ pub enum Message {
|
|||
BrowseDeleteMeasurement(i64),
|
||||
BrowseBack,
|
||||
/* Misc */
|
||||
OpenMidiSetup,
|
||||
RefreshMidi,
|
||||
ToggleTransport,
|
||||
Reconnect,
|
||||
UdpAddrChanged(String),
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +133,7 @@ pub struct App {
|
|||
tab: Tab,
|
||||
status: String,
|
||||
cmd_tx: Option<mpsc::UnboundedSender<Vec<u8>>>,
|
||||
ble_connected: bool,
|
||||
connected: bool,
|
||||
panes: pane_grid::State<PaneId>,
|
||||
native_menu: NativeMenu,
|
||||
show_sysinfo: bool,
|
||||
|
|
@ -239,8 +230,7 @@ pub struct App {
|
|||
|
||||
/* Global */
|
||||
temp_c: f32,
|
||||
midi_gen: u64,
|
||||
transport: TransportMode,
|
||||
conn_gen: u64,
|
||||
udp_addr: String,
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +369,7 @@ impl App {
|
|||
tab: Tab::Eis,
|
||||
status: "Starting...".into(),
|
||||
cmd_tx: None,
|
||||
ble_connected: false,
|
||||
connected: false,
|
||||
panes: pane_grid::State::with_configuration(pane_grid::Configuration::Split {
|
||||
axis: pane_grid::Axis::Horizontal,
|
||||
ratio: 0.55,
|
||||
|
|
@ -469,8 +459,7 @@ impl App {
|
|||
cal_cell_constant: None,
|
||||
|
||||
temp_c: 25.0,
|
||||
midi_gen: 0,
|
||||
transport: TransportMode::Midi,
|
||||
conn_gen: 0,
|
||||
udp_addr: crate::udp::load_addr(),
|
||||
}, Task::none())
|
||||
}
|
||||
|
|
@ -567,20 +556,20 @@ impl App {
|
|||
|
||||
pub fn update(&mut self, message: Message) -> Task<Message> {
|
||||
match message {
|
||||
Message::BleReady(tx) => {
|
||||
Message::DeviceReady(tx) => {
|
||||
self.cmd_tx = Some(tx);
|
||||
self.ble_connected = true;
|
||||
self.connected = true;
|
||||
self.send_cmd(&protocol::build_sysex_get_config());
|
||||
self.send_cmd(&protocol::build_sysex_get_cell_k());
|
||||
}
|
||||
Message::BleStatus(s) => {
|
||||
if s.contains("Reconnecting") || s.contains("Looking") {
|
||||
self.ble_connected = false;
|
||||
Message::DeviceStatus(s) => {
|
||||
if s.contains("Reconnecting") || s.contains("Connecting") {
|
||||
self.connected = false;
|
||||
self.cmd_tx = None;
|
||||
}
|
||||
self.status = s;
|
||||
}
|
||||
Message::BleData(msg) => match msg {
|
||||
Message::DeviceData(msg) => match msg {
|
||||
EisMessage::SweepStart { num_points, freq_start, freq_stop } => {
|
||||
if self.collecting_refs {
|
||||
/* ref collection: clear temp buffer */
|
||||
|
|
@ -1079,30 +1068,11 @@ impl App {
|
|||
self.browse_measurements.clear();
|
||||
}
|
||||
}
|
||||
Message::OpenMidiSetup => {
|
||||
let _ = std::process::Command::new("open")
|
||||
.arg("-a")
|
||||
.arg("Audio MIDI Setup")
|
||||
.spawn();
|
||||
}
|
||||
Message::RefreshMidi => {
|
||||
self.midi_gen += 1;
|
||||
Message::Reconnect => {
|
||||
self.conn_gen += 1;
|
||||
self.cmd_tx = None;
|
||||
self.ble_connected = false;
|
||||
self.status = "Looking for MIDI device...".into();
|
||||
}
|
||||
Message::ToggleTransport => {
|
||||
self.transport = match self.transport {
|
||||
TransportMode::Midi => TransportMode::Udp,
|
||||
TransportMode::Udp => TransportMode::Midi,
|
||||
};
|
||||
self.midi_gen += 1;
|
||||
self.cmd_tx = None;
|
||||
self.ble_connected = false;
|
||||
self.status = match self.transport {
|
||||
TransportMode::Midi => "Looking for MIDI device...".into(),
|
||||
TransportMode::Udp => format!("Connecting UDP to {}...", self.udp_addr),
|
||||
};
|
||||
self.connected = false;
|
||||
self.status = format!("Connecting to {}...", self.udp_addr);
|
||||
}
|
||||
Message::UdpAddrChanged(s) => {
|
||||
self.udp_addr = s;
|
||||
|
|
@ -1112,71 +1082,39 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn subscription(&self) -> Subscription<Message> {
|
||||
let use_udp = self.transport == TransportMode::Udp;
|
||||
let udp_addr = self.udp_addr.clone();
|
||||
let transport = Subscription::run_with_id(
|
||||
self.midi_gen,
|
||||
self.conn_gen,
|
||||
iced::stream::channel(100, move |mut output| async move {
|
||||
if use_udp {
|
||||
let addr = udp_addr.clone();
|
||||
loop {
|
||||
let (udp_tx, mut udp_rx) = mpsc::unbounded_channel::<UdpEvent>();
|
||||
let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::<Vec<u8>>();
|
||||
let addr = udp_addr.clone();
|
||||
loop {
|
||||
let (udp_tx, mut udp_rx) = mpsc::unbounded_channel::<UdpEvent>();
|
||||
let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::<Vec<u8>>();
|
||||
|
||||
let tx = udp_tx.clone();
|
||||
let a = addr.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = crate::udp::connect_and_run(tx, cmd_rx, a).await {
|
||||
eprintln!("UDP: {e}");
|
||||
}
|
||||
});
|
||||
|
||||
let mut ready_sent = false;
|
||||
while let Some(ev) = udp_rx.recv().await {
|
||||
let msg = match ev {
|
||||
UdpEvent::Status(ref s) if s == "Connected" && !ready_sent => {
|
||||
ready_sent = true;
|
||||
let _ = output.send(Message::BleReady(cmd_tx.clone())).await;
|
||||
Message::BleStatus(s.clone())
|
||||
}
|
||||
UdpEvent::Status(s) => Message::BleStatus(s),
|
||||
UdpEvent::Data(m) => Message::BleData(m),
|
||||
};
|
||||
let _ = output.send(msg).await;
|
||||
let tx = udp_tx.clone();
|
||||
let a = addr.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = crate::udp::connect_and_run(tx, cmd_rx, a).await {
|
||||
eprintln!("UDP: {e}");
|
||||
}
|
||||
});
|
||||
|
||||
let _ = output.send(Message::BleStatus("Reconnecting UDP...".into())).await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
} else {
|
||||
loop {
|
||||
let (ble_tx, mut ble_rx) = mpsc::unbounded_channel::<BleEvent>();
|
||||
let (cmd_tx, cmd_rx) = mpsc::unbounded_channel::<Vec<u8>>();
|
||||
|
||||
let tx = ble_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = crate::ble::connect_and_run(tx, cmd_rx).await {
|
||||
eprintln!("BLE: {e}");
|
||||
let mut ready_sent = false;
|
||||
while let Some(ev) = udp_rx.recv().await {
|
||||
let msg = match ev {
|
||||
UdpEvent::Status(ref s) if s == "Connected" && !ready_sent => {
|
||||
ready_sent = true;
|
||||
let _ = output.send(Message::DeviceReady(cmd_tx.clone())).await;
|
||||
Message::DeviceStatus(s.clone())
|
||||
}
|
||||
});
|
||||
|
||||
let mut ready_sent = false;
|
||||
while let Some(ev) = ble_rx.recv().await {
|
||||
let msg = match ev {
|
||||
BleEvent::Status(ref s) if s == "Connected" && !ready_sent => {
|
||||
ready_sent = true;
|
||||
let _ = output.send(Message::BleReady(cmd_tx.clone())).await;
|
||||
Message::BleStatus(s.clone())
|
||||
}
|
||||
BleEvent::Status(s) => Message::BleStatus(s),
|
||||
BleEvent::Data(m) => Message::BleData(m),
|
||||
};
|
||||
let _ = output.send(msg).await;
|
||||
}
|
||||
|
||||
let _ = output.send(Message::BleStatus("Reconnecting...".into())).await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
UdpEvent::Status(s) => Message::DeviceStatus(s),
|
||||
UdpEvent::Data(m) => Message::DeviceData(m),
|
||||
};
|
||||
let _ = output.send(msg).await;
|
||||
}
|
||||
|
||||
let _ = output.send(Message::DeviceStatus("Reconnecting...".into())).await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
|
@ -1208,14 +1146,6 @@ impl App {
|
|||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Alignment::Center);
|
||||
if self.transport == TransportMode::Midi {
|
||||
tabs = tabs.push(
|
||||
button(text("MIDI Setup").size(13))
|
||||
.style(style_neutral())
|
||||
.padding([6, 14])
|
||||
.on_press(Message::OpenMidiSetup),
|
||||
);
|
||||
}
|
||||
tabs = tabs
|
||||
.push(iced::widget::horizontal_space())
|
||||
.push(text("Clean").size(12))
|
||||
|
|
@ -1295,36 +1225,21 @@ impl App {
|
|||
ref_row = ref_row.push(text("REF").size(11));
|
||||
}
|
||||
|
||||
let connected = self.ble_connected;
|
||||
let transport_label = match self.transport {
|
||||
TransportMode::Midi => "MIDI",
|
||||
TransportMode::Udp => "UDP",
|
||||
};
|
||||
let mut status_row = row![text(&self.status).size(16)].spacing(6)
|
||||
.align_y(iced::Alignment::Center);
|
||||
status_row = status_row.push(
|
||||
button(text(transport_label).size(11))
|
||||
.style(style_neutral())
|
||||
.padding([4, 10])
|
||||
.on_press(Message::ToggleTransport),
|
||||
text_input("IP:port", &self.udp_addr)
|
||||
.size(12)
|
||||
.width(160)
|
||||
.on_input(Message::UdpAddrChanged)
|
||||
.on_submit(Message::Reconnect),
|
||||
);
|
||||
status_row = status_row.push(
|
||||
button(text("Reconnect").size(11))
|
||||
.style(style_apply())
|
||||
.padding([4, 10])
|
||||
.on_press(Message::Reconnect),
|
||||
);
|
||||
if self.transport == TransportMode::Udp {
|
||||
status_row = status_row.push(
|
||||
text_input("IP:port", &self.udp_addr)
|
||||
.size(12)
|
||||
.width(160)
|
||||
.on_input(Message::UdpAddrChanged)
|
||||
.on_submit(Message::ToggleTransport), // reconnect on enter
|
||||
);
|
||||
}
|
||||
if !connected && self.transport == TransportMode::Midi {
|
||||
status_row = status_row.push(
|
||||
button(text("Refresh MIDI").size(11))
|
||||
.style(style_apply())
|
||||
.padding([4, 10])
|
||||
.on_press(Message::RefreshMidi),
|
||||
);
|
||||
}
|
||||
status_row = status_row
|
||||
.push(iced::widget::horizontal_space())
|
||||
.push(ref_row)
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
use midir::{MidiInput, MidiOutput, MidiInputConnection, MidiOutputConnection};
|
||||
use std::sync::mpsc as std_mpsc;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::protocol::{self, EisMessage};
|
||||
|
||||
const DEVICE_NAME: &str = "EIS4";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BleEvent {
|
||||
Status(String),
|
||||
Data(EisMessage),
|
||||
}
|
||||
|
||||
pub async fn connect_and_run(
|
||||
tx: mpsc::UnboundedSender<BleEvent>,
|
||||
mut cmd_rx: mpsc::UnboundedReceiver<Vec<u8>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let _ = tx.send(BleEvent::Status("Looking for MIDI device...".into()));
|
||||
|
||||
let (midi_in, in_port, midi_out, out_port) = loop {
|
||||
if let Some(found) = find_midi_ports() {
|
||||
break found;
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
|
||||
};
|
||||
|
||||
let _ = tx.send(BleEvent::Status("Connecting MIDI...".into()));
|
||||
|
||||
let (sysex_tx, sysex_rx) = std_mpsc::channel::<Vec<u8>>();
|
||||
|
||||
let _in_conn: MidiInputConnection<()> = midi_in.connect(
|
||||
&in_port, "cue-in",
|
||||
move |_ts, data, _| {
|
||||
if let Some(sysex) = extract_sysex(data) {
|
||||
let _ = sysex_tx.send(sysex);
|
||||
}
|
||||
},
|
||||
(),
|
||||
).map_err(|e| format!("MIDI input connect: {e}"))?;
|
||||
|
||||
let mut out_conn: MidiOutputConnection = midi_out.connect(
|
||||
&out_port, "cue-out",
|
||||
).map_err(|e| format!("MIDI output connect: {e}"))?;
|
||||
|
||||
let _ = tx.send(BleEvent::Status("Connected".into()));
|
||||
|
||||
loop {
|
||||
while let Ok(sysex) = sysex_rx.try_recv() {
|
||||
if let Some(msg) = protocol::parse_sysex(&sysex) {
|
||||
let _ = tx.send(BleEvent::Data(msg));
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match cmd_rx.try_recv() {
|
||||
Ok(pkt) => {
|
||||
if let Err(e) = out_conn.send(&pkt) {
|
||||
eprintln!("MIDI send error: {e}");
|
||||
}
|
||||
}
|
||||
Err(mpsc::error::TryRecvError::Disconnected) => return Ok(()),
|
||||
Err(mpsc::error::TryRecvError::Empty) => break,
|
||||
}
|
||||
}
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(5)).await;
|
||||
}
|
||||
}
|
||||
|
||||
fn find_midi_ports() -> Option<(
|
||||
MidiInput, midir::MidiInputPort,
|
||||
MidiOutput, midir::MidiOutputPort,
|
||||
)> {
|
||||
let midi_in = MidiInput::new("cue-in").ok()?;
|
||||
let midi_out = MidiOutput::new("cue-out").ok()?;
|
||||
|
||||
let in_port = midi_in.ports().into_iter().find(|p| {
|
||||
midi_in.port_name(p).map_or(false, |n| n.contains(DEVICE_NAME))
|
||||
})?;
|
||||
|
||||
let out_port = midi_out.ports().into_iter().find(|p| {
|
||||
midi_out.port_name(p).map_or(false, |n| n.contains(DEVICE_NAME))
|
||||
})?;
|
||||
|
||||
Some((midi_in, in_port, midi_out, out_port))
|
||||
}
|
||||
|
||||
fn extract_sysex(data: &[u8]) -> Option<Vec<u8>> {
|
||||
if data.first() != Some(&0xF0) { return None; }
|
||||
let end = data.iter().position(|&b| b == 0xF7)?;
|
||||
Some(data[1..end].to_vec())
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
mod app;
|
||||
mod ble;
|
||||
mod native_menu;
|
||||
mod plot;
|
||||
mod protocol;
|
||||
|
|
|
|||
Loading…
Reference in New Issue