setting up
This commit is contained in:
parent
192adccb10
commit
60e600c381
4 changed files with 183 additions and 5 deletions
27
src-tauri/Cargo.lock
generated
27
src-tauri/Cargo.lock
generated
|
|
@ -98,6 +98,7 @@ name = "app"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"midir",
|
"midir",
|
||||||
|
"rosc",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
|
|
@ -1557,6 +1558,12 @@ dependencies = [
|
||||||
"windows 0.43.0",
|
"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]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
|
@ -1629,6 +1636,16 @@ version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
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]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
|
@ -2173,6 +2190,16 @@ version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
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]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.4.0", features = ["fs-all"] }
|
tauri = { version = "1.4.0", features = ["fs-all"] }
|
||||||
midir = "0.9.1"
|
midir = "0.9.1"
|
||||||
tokio = { version = "1.29.0", features = ["full"] }
|
tokio = { version = "1.29.0", features = ["full"] }
|
||||||
|
rosc = "0.10.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,27 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
mod midibridge;
|
mod midibridge;
|
||||||
|
mod oscbridge;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (async_input_transmitter, async_input_receiver) = mpsc::channel(1);
|
let (async_input_transmitter_midi, async_input_receiver_midi) = mpsc::channel(1);
|
||||||
let (async_output_transmitter, async_output_receiver) = 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
|
tauri::Builder
|
||||||
::default()
|
::default()
|
||||||
.manage(midibridge::AsyncInputTransmit {
|
.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| {
|
.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(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
|
|
|
||||||
143
src-tauri/src/oscbridge.rs
Normal file
143
src-tauri/src/oscbridge.rs
Normal 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())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue