setting up

This commit is contained in:
Jade Rowland 2023-09-03 13:23:13 -04:00
parent 192adccb10
commit 60e600c381
4 changed files with 183 additions and 5 deletions

27
src-tauri/Cargo.lock generated
View File

@ -98,6 +98,7 @@ name = "app"
version = "0.1.0"
dependencies = [
"midir",
"rosc",
"serde",
"serde_json",
"tauri",
@ -1557,6 +1558,12 @@ dependencies = [
"windows 0.43.0",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
@ -1629,6 +1636,16 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@ -2173,6 +2190,16 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]]
name = "rosc"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e63d9e6b0d090be1485cf159b1e04c3973d2d3e1614963544ea2ff47a4a981"
dependencies = [
"byteorder",
"nom",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"

View File

@ -20,6 +20,7 @@ serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.4.0", features = ["fs-all"] }
midir = "0.9.1"
tokio = { version = "1.29.0", features = ["full"] }
rosc = "0.10.1"
[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.

View File

@ -2,20 +2,27 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod midibridge;
mod oscbridge;
use tokio::sync::mpsc;
use tokio::sync::Mutex;
fn main() {
let (async_input_transmitter, async_input_receiver) = mpsc::channel(1);
let (async_output_transmitter, async_output_receiver) = 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_input_transmitter_osc, async_input_receiver_osc) = mpsc::channel(1);
let (async_output_transmitter_osc, async_output_receiver_osc) = mpsc::channel(1);
tauri::Builder
::default()
.manage(midibridge::AsyncInputTransmit {
inner: Mutex::new(async_input_transmitter),
inner: Mutex::new(async_input_transmitter_midi),
})
.invoke_handler(tauri::generate_handler![midibridge::sendmidi])
.manage(oscbridge::AsyncInputTransmit {
inner: Mutex::new(async_input_transmitter_osc),
})
.invoke_handler(tauri::generate_handler![midibridge::sendmidi, oscbridge::sendosc])
.setup(|_app| {
midibridge::init(async_input_receiver, async_output_receiver, async_output_transmitter);
midibridge::init(async_input_receiver_midi, async_output_receiver_midi, async_output_transmitter_midi);
oscbridge::init(async_input_receiver_osc, async_output_receiver_osc, async_output_transmitter_osc);
Ok(())
})
.run(tauri::generate_context!())

143
src-tauri/src/oscbridge.rs Normal file
View File

@ -0,0 +1,143 @@
use rosc::encoder;
use rosc::{ OscMessage, OscPacket, OscType };
use std::net::{ SocketAddrV4, UdpSocket };
use std::str::FromStr;
use std::time::Duration;
use std::{ env, f32 };
use std::sync::Arc;
use tokio::sync::{ mpsc, Mutex };
use tokio::time::Instant;
use serde::Deserialize;
use std::thread::sleep;
pub struct OscMsg {
pub msg_buf: Vec<u8>,
pub instant: Instant,
pub offset: u64,
}
pub struct AsyncInputTransmit {
pub inner: Mutex<mpsc::Sender<Vec<OscMsg>>>,
}
fn get_addr_from_arg(arg: &str) -> SocketAddrV4 {
SocketAddrV4::from_str(arg).unwrap()
}
pub fn init(
async_input_receiver: mpsc::Receiver<Vec<OscMsg>>,
mut async_output_receiver: mpsc::Receiver<Vec<OscMsg>>,
async_output_transmitter: mpsc::Sender<Vec<OscMsg>>
) {
tauri::async_runtime::spawn(async move { async_process_model(async_input_receiver, async_output_transmitter).await });
let message_queue: Arc<Mutex<Vec<OscMsg>>> = Arc::new(Mutex::new(Vec::new()));
/* ...........................................................
Listen For incoming messages and add to queue
............................................................*/
let message_queue_clone = Arc::clone(&message_queue);
tauri::async_runtime::spawn(async move {
loop {
if let Some(package) = async_output_receiver.recv().await {
let mut message_queue = message_queue_clone.lock().await;
let messages = package;
//println!("received message");
for message in messages {
(*message_queue).push(message);
}
}
}
});
println!("cloning message queue");
let message_queue_clone = Arc::clone(&message_queue);
tauri::async_runtime::spawn(async move {
println!("opening osc port");
/* ...........................................................
Open OSC Ports
............................................................*/
let sock = UdpSocket::bind("localhost:57121").unwrap();
let to_addr = String::from("localhost:57120");
/* ...........................................................
Process queued messages
............................................................*/
loop {
let mut message_queue = message_queue_clone.lock().await;
println!("num messages {}", message_queue.len());
//iterate over each message, play and remove messages when they are ready
message_queue.retain(|message| {
if message.instant.elapsed().as_millis() < message.offset.into() {
return true;
}
sock.send_to(&message.msg_buf, to_addr.clone()).unwrap();
return false;
});
sleep(Duration::from_millis(1));
}
});
}
pub async fn async_process_model(
mut input_reciever: mpsc::Receiver<Vec<OscMsg>>,
output_transmitter: mpsc::Sender<Vec<OscMsg>>
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
while let Some(input) = input_reciever.recv().await {
let output = input;
output_transmitter.send(output).await?;
}
Ok(())
}
#[derive(Deserialize)]
pub struct Param {
name: String,
value: String,
valueisnumber: bool,
}
#[derive(Deserialize)]
pub struct MessageFromJS {
params: Vec<Param>,
offset: u64,
target: String,
}
// Called from JS
#[tauri::command]
pub async fn sendosc(
messagesfromjs: Vec<MessageFromJS>,
state: tauri::State<'_, AsyncInputTransmit>
) -> Result<(), String> {
let async_proc_input_tx = state.inner.lock().await;
let mut messages_to_process: Vec<OscMsg> = Vec::new();
for m in messagesfromjs {
let mut args = Vec::new();
for p in m.params {
args.push(OscType::String(p.name));
if p.valueisnumber {
args.push(OscType::Float(p.value.parse().unwrap()));
} else {
args.push(OscType::String(p.value));
}
}
let msg_buf = encoder
::encode(
&OscPacket::Message(OscMessage {
addr: m.target,
args,
})
)
.unwrap();
let message_to_process = OscMsg {
instant: Instant::now(),
msg_buf,
offset: m.offset,
};
messages_to_process.push(message_to_process);
}
async_proc_input_tx.send(messages_to_process).await.map_err(|e| e.to_string())
}