This repository has no description
1use super::{Probe, beacon::connect_to_beacon, probe::Datapoint};
2use anyhow::Result;
3use nih_plug::params::FloatParam;
4use std::{fmt::Display, net::TcpStream};
5use tungstenite::{WebSocket, stream::MaybeTlsStream};
6
7pub struct RemoteProbe {
8 pub id: u32,
9 pub out: WebSocket<MaybeTlsStream<TcpStream>>,
10 pub pointsbuffer: Vec<Datapoint>,
11}
12
13impl RemoteProbe {
14 pub fn new(id: u32) -> Self {
15 Self {
16 id,
17 out: connect_to_beacon().unwrap(),
18 pointsbuffer: Vec::new(),
19 }
20 }
21
22 pub fn register(&mut self) -> Result<()> {
23 let probe = Probe {
24 id: self.id,
25 ..Default::default()
26 };
27
28 self.out
29 .send(
30 format!(
31 "? hi {}",
32 serde_json::to_string(&probe)
33 .expect("Failed to serialize probe")
34 )
35 .into(),
36 )
37 .expect("Failed to send register probe message");
38
39 Ok(())
40 }
41
42 pub fn update(&mut self, probe: Probe) -> Result<()> {
43 self.out
44 .send(
45 format!(
46 "{} hi {}",
47 self.id,
48 serde_json::to_string(&probe)
49 .expect("Failed to serialize probe")
50 )
51 .into(),
52 )
53 .expect("Failed to send update probe message");
54 Ok(())
55 }
56
57 pub fn timestamp() -> usize {
58 std::time::SystemTime::now()
59 .duration_since(std::time::UNIX_EPOCH)
60 .unwrap()
61 .as_millis() as usize
62 }
63
64 /// Store a automation data point.
65 pub fn store_automation(
66 &mut self,
67 timestamp: usize,
68 param_id: usize,
69 param: &FloatParam,
70 ) -> Result<()> {
71 self.store(Datapoint::Automation(timestamp, param_id, param.value()))
72 }
73
74 /// Store a audio data point.
75 pub fn store_audio(
76 &mut self,
77 timestamp: usize,
78 samples: Vec<f32>,
79 ) -> Result<()> {
80 self.store(Datapoint::Audio(timestamp, samples))
81 }
82
83 /// Store a midi data point.
84 pub fn store_midi(&mut self, timestamp: usize, data: &[u8]) -> Result<()> {
85 self.store(Datapoint::Midi(timestamp, data.to_vec()))
86 }
87
88 /// Store a data point.
89 pub fn say(&mut self, msg: impl Display) -> Result<()> {
90 self.out
91 .write(format!("{} say {}", self.id, msg).into())
92 .expect("Failed to send say message");
93 Ok(())
94 }
95
96 pub fn store(&mut self, datapoint: Datapoint) -> Result<()> {
97 self.pointsbuffer.push(datapoint);
98 if self.pointsbuffer.len() >= 100 {
99 self.say("flushing buffer of datapoints")?;
100 for datapoint in self.pointsbuffer.drain(..) {
101 self.out
102 .write(
103 format!(
104 "{} {}",
105 self.id,
106 match &datapoint {
107 Datapoint::Automation(ts, param_id, value) => {
108 format!("{ts} % {} {}", param_id, value)
109 }
110 Datapoint::Midi(ts, data) => {
111 format!(
112 "{ts} # 0 {}",
113 data.iter()
114 .map(|b| b.to_string())
115 .collect::<Vec<String>>()
116 .join(" ")
117 )
118 }
119 Datapoint::Audio(ts, data) => {
120 format!(
121 "{ts} ~ {}",
122 data.iter()
123 .map(|f| f.to_string())
124 .collect::<Vec<String>>()
125 .join(" ")
126 )
127 }
128 }
129 )
130 .into(),
131 )
132 .expect("Failed to send store datapoint message");
133 }
134 self.out.flush().expect("Failed to flush probe connection");
135 }
136
137 Ok(())
138 }
139}
140
141impl Drop for RemoteProbe {
142 fn drop(&mut self) {
143 self.out
144 .close(None)
145 .expect("Failed to close probe connection");
146 }
147}