This commit is contained in:
Jade Rowland 2023-09-09 01:20:08 -04:00
parent 133a1d2e8f
commit e75ac7b3c0
6 changed files with 84 additions and 12 deletions

View File

@ -0,0 +1,11 @@
import { listen } from '@tauri-apps/api/event';
import { logger } from '../core/logger.mjs';
// listen for log events from the Tauri backend and log in the UI
await listen('log-event', (e) => {
if (e.payload == null) {
return;
}
const { message, message_type } = e.payload;
logger(message, message_type);
});

View File

@ -0,0 +1,20 @@
use std::sync::Arc;
use tauri::Window;
#[derive(Clone, serde::Serialize)]
pub struct LoggerPayload {
pub message: String,
pub message_type: String,
}
#[derive(Clone)]
pub struct Logger {
pub window: Arc<Window>,
}
impl Logger {
pub fn log(&self, message: String, message_type: String) {
println!("{}", message);
let _ = self.window.emit("log-event", LoggerPayload { message, message_type });
}
}

View File

@ -3,9 +3,21 @@
mod midibridge; mod midibridge;
mod oscbridge; mod oscbridge;
mod loggerbridge;
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
use loggerbridge::Logger;
use tauri::Manager;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
// the payload type must implement `Serialize` and `Clone`.
#[derive(Clone, serde::Serialize)]
struct Payload {
message: String,
message_type: String,
}
fn main() { fn main() {
let (async_input_transmitter_midi, async_input_receiver_midi) = mpsc::channel(1); let (async_input_transmitter_midi, async_input_receiver_midi) = mpsc::channel(1);
let (async_output_transmitter_midi, async_output_receiver_midi) = mpsc::channel(1); let (async_output_transmitter_midi, async_output_receiver_midi) = mpsc::channel(1);
@ -20,9 +32,16 @@ fn main() {
inner: Mutex::new(async_input_transmitter_osc), inner: Mutex::new(async_input_transmitter_osc),
}) })
.invoke_handler(tauri::generate_handler![midibridge::sendmidi, oscbridge::sendosc]) .invoke_handler(tauri::generate_handler![midibridge::sendmidi, oscbridge::sendosc])
.setup(|_app| { .setup(|app| {
midibridge::init(async_input_receiver_midi, async_output_receiver_midi, async_output_transmitter_midi); let window = Arc::new(app.get_window("main").unwrap());
oscbridge::init(async_input_receiver_osc, async_output_receiver_osc, async_output_transmitter_osc); let logger = Logger { window };
midibridge::init(
logger.clone(),
async_input_receiver_midi,
async_output_receiver_midi,
async_output_transmitter_midi
);
oscbridge::init(logger, async_input_receiver_osc, async_output_receiver_osc, async_output_transmitter_osc);
Ok(()) Ok(())
}) })
.run(tauri::generate_context!()) .run(tauri::generate_context!())

View File

@ -2,10 +2,13 @@ use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use midir::MidiOutput; use midir::MidiOutput;
use tokio::sync::{ mpsc, Mutex }; use tokio::sync::{ mpsc, Mutex };
use tokio::time::Instant; use tokio::time::Instant;
use serde::Deserialize; use serde::Deserialize;
use std::thread::sleep; use std::thread::sleep;
use crate::loggerbridge::Logger;
pub struct MidiMessage { pub struct MidiMessage {
pub message: Vec<u8>, pub message: Vec<u8>,
pub instant: Instant, pub instant: Instant,
@ -18,6 +21,7 @@ pub struct AsyncInputTransmit {
} }
pub fn init( pub fn init(
logger: Logger,
async_input_receiver: mpsc::Receiver<Vec<MidiMessage>>, async_input_receiver: mpsc::Receiver<Vec<MidiMessage>>,
mut async_output_receiver: mpsc::Receiver<Vec<MidiMessage>>, mut async_output_receiver: mpsc::Receiver<Vec<MidiMessage>>,
async_output_transmitter: mpsc::Sender<Vec<MidiMessage>> async_output_transmitter: mpsc::Sender<Vec<MidiMessage>>
@ -50,10 +54,13 @@ pub fn init(
let mut port_names = Vec::new(); let mut port_names = Vec::new();
//TODO: Send these print messages to the UI logger instead of the rust console so the user can see them //TODO: Send these print messages to the UI logger instead of the rust console so the user can see them
if out_ports.len() == 0 { if out_ports.len() == 0 {
println!(" No MIDI devices found. Connect a device or enable IAC Driver."); logger.log(" No MIDI devices found. Connect a device or enable IAC Driver.".to_string(), "".to_string());
// logger(window, " No MIDI devices found. Connect a device or enable IAC Driver.".to_string(), None);
return; return;
} }
println!("Found {} midi devices!", out_ports.len()); // give the frontend couple seconds to load on start, or the log messages will get lost
sleep(Duration::from_secs(3));
logger.log(format!("Found {} midi devices!", out_ports.len()), "".to_string());
// the user could reference any port at anytime during runtime, // the user could reference any port at anytime during runtime,
// so let's go ahead and open them all (same behavior as web app) // so let's go ahead and open them all (same behavior as web app)
@ -63,7 +70,7 @@ pub fn init(
let ports = midiout.ports(); let ports = midiout.ports();
let port = ports.get(i).unwrap(); let port = ports.get(i).unwrap();
let port_name = midiout.port_name(port).unwrap(); let port_name = midiout.port_name(port).unwrap();
println!("{}", port_name); logger.log(port_name.clone(), "".to_string());
let out_con = midiout.connect(port, &port_name).unwrap(); let out_con = midiout.connect(port, &port_name).unwrap();
port_names.insert(i, port_name.clone()); port_names.insert(i, port_name.clone());
output_connections.insert(port_name, out_con); output_connections.insert(port_name, out_con);
@ -96,10 +103,10 @@ pub fn init(
if out_con.is_some() { if out_con.is_some() {
// process the message // process the message
if let Err(err) = (&mut out_con.unwrap()).send(&message.message) { if let Err(err) = (&mut out_con.unwrap()).send(&message.message) {
println!("Midi message send error: {}", err); logger.log(format!("Midi message send error: {}", err), "warning".to_string());
} }
} else { } else {
println!("failed to find midi device: {}", message.requestedport); logger.log(format!("failed to find midi device: {}", message.requestedport), "warning".to_string());
} }
return false; return false;
}); });

View File

@ -1,5 +1,6 @@
use rosc::{ encoder, OscTime }; use rosc::{ encoder, OscTime };
use rosc::{ OscMessage, OscPacket, OscType, OscBundle }; use rosc::{ OscMessage, OscPacket, OscType, OscBundle };
use std::net::UdpSocket; use std::net::UdpSocket;
use std::time::Duration; use std::time::Duration;
@ -7,6 +8,8 @@ use std::sync::Arc;
use tokio::sync::{ mpsc, Mutex }; use tokio::sync::{ mpsc, Mutex };
use serde::Deserialize; use serde::Deserialize;
use std::thread::sleep; use std::thread::sleep;
use crate::loggerbridge::Logger;
pub struct OscMsg { pub struct OscMsg {
pub msg_buf: Vec<u8>, pub msg_buf: Vec<u8>,
pub timestamp: u64, pub timestamp: u64,
@ -22,6 +25,7 @@ const NANOS_PER_SECOND: f64 = 1.0e9;
const SECONDS_PER_NANO: f64 = 1.0 / NANOS_PER_SECOND; const SECONDS_PER_NANO: f64 = 1.0 / NANOS_PER_SECOND;
pub fn init( pub fn init(
logger: Logger,
async_input_receiver: mpsc::Receiver<Vec<OscMsg>>, async_input_receiver: mpsc::Receiver<Vec<OscMsg>>,
mut async_output_receiver: mpsc::Receiver<Vec<OscMsg>>, mut async_output_receiver: mpsc::Receiver<Vec<OscMsg>>,
async_output_transmitter: mpsc::Sender<Vec<OscMsg>> async_output_transmitter: mpsc::Sender<Vec<OscMsg>>
@ -64,7 +68,10 @@ pub fn init(
message_queue.retain(|message| { message_queue.retain(|message| {
let result = sock.send(&message.msg_buf); let result = sock.send(&message.msg_buf);
if result.is_err() { if result.is_err() {
println!("OSC Message failed to send, the server might no longer be available"); logger.log(
format!("OSC Message failed to send, the server might no longer be available"),
"warning".to_string()
);
} }
return false; return false;
}); });

View File

@ -37,14 +37,22 @@ const modules = [
import('@strudel.cycles/core'), import('@strudel.cycles/core'),
import('@strudel.cycles/tonal'), import('@strudel.cycles/tonal'),
import('@strudel.cycles/mini'), import('@strudel.cycles/mini'),
isTauri() ? import('@strudel/desktopbridge/midibridge.mjs') : import('@strudel.cycles/midi'),
import('@strudel.cycles/xen'), import('@strudel.cycles/xen'),
import('@strudel.cycles/webaudio'), import('@strudel.cycles/webaudio'),
isTauri() ? import('@strudel/desktopbridge/oscbridge.mjs') : import('@strudel.cycles/osc'),
import('@strudel.cycles/serial'), import('@strudel.cycles/serial'),
import('@strudel.cycles/soundfonts'), import('@strudel.cycles/soundfonts'),
import('@strudel.cycles/csound'), import('@strudel.cycles/csound'),
]; ];
if (isTauri()) {
modules.concat([
import('@strudel/desktopbridge/loggerbridge.mjs'),
import('@strudel/desktopbridge/midibridge.mjs'),
import('@strudel/desktopbridge/oscbridge.mjs'),
]);
} else {
modules.concat([import('@strudel.cycles/midi'), import('@strudel.cycles/osc')]);
}
const modulesLoading = evalScope( const modulesLoading = evalScope(
controls, // sadly, this cannot be exported from core direclty controls, // sadly, this cannot be exported from core direclty