1use rosc::{OscMessage, OscPacket, OscType};
4
5use crate::{
6 address::{AddressPath, NodeId},
7 error::Result,
8 message::NetMessage,
9};
10
11pub struct ParsedOscMessage {
13 pub address: AddressPath,
14 pub value: f32,
15}
16
17pub fn parse_osc_packet(packet: &OscPacket) -> Vec<ParsedOscMessage> {
21 let mut messages = Vec::new();
22 collect_messages(packet, &mut messages);
23 messages
24}
25
26fn collect_messages(packet: &OscPacket, out: &mut Vec<ParsedOscMessage>) {
27 match packet {
28 OscPacket::Message(msg) => {
29 if let Some(parsed) = parse_single_message(msg) {
30 out.push(parsed);
31 }
32 }
33 OscPacket::Bundle(bundle) => {
34 for content in &bundle.content {
35 collect_messages(content, out);
36 }
37 }
38 }
39}
40
41fn parse_single_message(msg: &OscMessage) -> Option<ParsedOscMessage> {
42 let address = AddressPath::parse(&msg.addr).ok()?;
43
44 let value = msg.args.first().and_then(|arg| match arg {
45 OscType::Float(f) => Some(*f),
46 OscType::Int(i) => Some(*i as f32),
47 OscType::Double(d) => Some(*d as f32),
48 OscType::Bool(b) => Some(if *b { 1.0 } else { 0.0 }),
49 _ => None,
50 })?;
51
52 Some(ParsedOscMessage { address, value })
53}
54
55pub fn parse_osc_message(data: &[u8], source_node_id: NodeId) -> Result<Vec<NetMessage>> {
66 let packet = rosc::decoder::decode_udp(data)
67 .map_err(|_| crate::error::NetError::ParseError)?
68 .1;
69
70 let parsed = parse_osc_packet(&packet);
71
72 Ok(parsed
73 .into_iter()
74 .map(|p| NetMessage::param_change(&p.address.param_name, p.value, source_node_id))
75 .collect())
76}
77
78#[cfg(test)]
79mod tests {
80 use rosc::encoder;
81
82 use super::*;
83
84 #[test]
85 fn test_parse_float_message() {
86 let msg = OscMessage {
87 addr: "/blocks/param/gain".to_string(),
88 args: vec![OscType::Float(0.75)],
89 };
90 let packet = OscPacket::Message(msg);
91 let bytes = encoder::encode(&packet).unwrap();
92
93 let node_id = NodeId::default();
94 let messages = parse_osc_message(&bytes, node_id).unwrap();
95
96 assert_eq!(messages.len(), 1);
97 assert!((messages[0].payload.value().unwrap() - 0.75).abs() < f32::EPSILON);
98 }
99
100 #[test]
101 fn test_parse_int_message() {
102 let msg = OscMessage {
103 addr: "/blocks/param/level".to_string(),
104 args: vec![OscType::Int(100)],
105 };
106 let packet = OscPacket::Message(msg);
107 let bytes = encoder::encode(&packet).unwrap();
108
109 let node_id = NodeId::default();
110 let messages = parse_osc_message(&bytes, node_id).unwrap();
111
112 assert_eq!(messages.len(), 1);
113 assert!((messages[0].payload.value().unwrap() - 100.0).abs() < f32::EPSILON);
114 }
115
116 #[test]
117 fn test_parse_bool_message() {
118 let msg = OscMessage {
119 addr: "/blocks/param/enabled".to_string(),
120 args: vec![OscType::Bool(true)],
121 };
122 let packet = OscPacket::Message(msg);
123 let bytes = encoder::encode(&packet).unwrap();
124
125 let node_id = NodeId::default();
126 let messages = parse_osc_message(&bytes, node_id).unwrap();
127
128 assert_eq!(messages.len(), 1);
129 assert!((messages[0].payload.value().unwrap() - 1.0).abs() < f32::EPSILON);
130 }
131
132 #[test]
133 fn test_parse_invalid_address() {
134 let msg = OscMessage {
135 addr: "/invalid/path".to_string(),
136 args: vec![OscType::Float(0.5)],
137 };
138 let packet = OscPacket::Message(msg);
139 let bytes = encoder::encode(&packet).unwrap();
140
141 let node_id = NodeId::default();
142 let messages = parse_osc_message(&bytes, node_id).unwrap();
143
144 assert!(messages.is_empty());
145 }
146}