#![allow(dead_code)]
use murrelet_common::{print_expect, IsLivecodeSrc, LivecodeSrcUpdateInput, LivecodeValue};
use rosc::{OscPacket, OscType};
use std::collections::HashMap;
use std::net::UdpSocket;
use std::net::{SocketAddrV4, ToSocketAddrs};
use std::str::FromStr;
use std::sync::mpsc::{self, Receiver};
use std::thread::{self, JoinHandle};
use std::time::Duration;
const OSC_PREFIX: &str = "/livecode/";
impl IsLivecodeSrc for OscMng {
fn update(&mut self, _: &LivecodeSrcUpdateInput) {
for _ in 0..10 {
let r = self.cxn.check_and_maybe_update(&mut self.values);
if r.is_err() {
break;
} }
}
fn to_exec_funcs(&self) -> Vec<(String, murrelet_common::LivecodeValue)> {
self.values.to_livecode_vals()
}
}
pub struct OscMng {
cxn: OscCxn,
pub values: OscValues,
}
#[derive(Debug)]
pub struct OscValues {
last_values: HashMap<String, LivecodeValue>,
smooth_values: HashMap<String, LivecodeValue>,
}
impl OscValues {
fn to_livecode_vals(&self) -> Vec<(String, murrelet_common::LivecodeValue)> {
let last_values: Vec<(String, murrelet_common::LivecodeValue)> =
self.last_values.clone().into_iter().collect();
let smooth_values: Vec<(String, murrelet_common::LivecodeValue)> = self
.smooth_values
.clone()
.into_iter()
.map(|(key, val)| (format!("{}_smooth", key), val))
.collect();
[last_values, smooth_values].concat()
}
}
impl OscMng {
pub fn new_from_str(ip_address: &str) -> Self {
let addr = match SocketAddrV4::from_str(ip_address) {
Ok(addr) => addr,
Err(_) => panic!(
"address couldn't be parsed with SocketAddrV4 {}",
ip_address
),
};
let cxn = OscCxn::new(&addr);
Self {
cxn,
values: OscValues {
last_values: HashMap::new(),
smooth_values: HashMap::new(),
},
}
}
}
pub struct OscCxn {
_osc_cxn: JoinHandle<()>, pub osc_rx: Receiver<OSCMessage>,
}
impl OscCxn {
pub fn check_and_maybe_update(&self, r: &mut OscValues) -> Result<(), mpsc::TryRecvError> {
self.osc_rx.try_recv().map(|x| {
for (name, new_val) in x.to_livecode_vals().into_iter() {
if let Some(old_val) = r.smooth_values.get(&name) {
let actual_new_val = match (old_val, new_val) {
(LivecodeValue::Float(old), LivecodeValue::Float(new)) => {
LivecodeValue::Float(*old * 0.9 + new * 0.1)
}
_ => new_val,
};
r.smooth_values.insert(name.clone(), actual_new_val);
} else {
println!("first time seeing name {} with value {:?}", name, new_val);
r.smooth_values.insert(name.clone(), new_val);
}
r.last_values.insert(name.clone(), new_val); }
})
}
pub fn new<A: ToSocketAddrs>(addr: &A) -> Self {
let (event_tx, event_rx) = mpsc::channel::<OSCMessage>();
let sock = UdpSocket::bind(addr).unwrap();
let handle = std::thread::spawn(move || {
let mut buf = [0u8; rosc::decoder::MTU];
loop {
match sock.recv_from(&mut buf) {
Ok((size, _)) => {
let (_, packet) = rosc::decoder::decode_udp(&buf[..size]).unwrap();
if let Some(msg) = handle_packet(&packet) {
print_expect(event_tx.send(msg), "error sending osc msg");
}
}
Err(e) => {
println!("Error receiving from socket: {}", e);
break;
}
}
thread::sleep(Duration::from_micros(100));
}
});
OscCxn {
_osc_cxn: handle,
osc_rx: event_rx,
}
}
}
#[derive(Debug)]
pub struct OSCMessage {
v: Vec<LivecodeOSC>,
}
impl OSCMessage {
fn new(v: Vec<LivecodeOSC>) -> Self {
Self { v }
}
fn to_livecode_vals(&self) -> Vec<(String, murrelet_common::LivecodeValue)> {
self.v
.iter()
.map(|osc| (format!("oo_{}", osc.name), osc.v))
.collect::<Vec<_>>()
}
}
#[derive(Debug)]
pub struct LivecodeOSC {
name: String,
v: murrelet_common::LivecodeValue,
}
impl LivecodeOSC {
pub fn new_f32(name: String, v: f32) -> Self {
Self {
name,
v: LivecodeValue::float(v),
}
}
}
fn handle_packet(packet: &OscPacket) -> Option<OSCMessage> {
match packet {
OscPacket::Message(msg) => {
if let Some(osc_name) = msg.addr.as_str().strip_prefix(OSC_PREFIX) {
let mut values = vec![];
match msg.args[..] {
[OscType::Float(value)] => {
values.push(LivecodeOSC::new_f32(osc_name.to_owned(), value));
}
_ => {
println!("OSC data values funny: {:?}", msg.args);
}
}
Some(OSCMessage::new(values))
} else {
println!("unexpected name, not with {}", OSC_PREFIX);
println!("OSC address: {}", msg.addr);
println!("OSC arguments: {:?}", msg.args);
None
}
}
OscPacket::Bundle(bundle) => {
let mut values = vec![];
for c in &bundle.content {
if let OscPacket::Message(msg) = c {
if let Some(osc_name) = msg.addr.as_str().strip_prefix(OSC_PREFIX) {
match msg.args[..] {
[OscType::Float(value)] => {
values.push(LivecodeOSC::new_f32(osc_name.to_owned(), value));
}
_ => {
println!("OSC address content funny: {:?}", msg.args);
}
}
} else {
println!(
"OSC label dropped, not prefixed with {}: {}",
OSC_PREFIX, msg.addr
);
}
}
}
Some(OSCMessage::new(values))
}
}
}