caw_viz_udp_app_lib/
lib.rs1pub mod blink;
9mod common;
10pub mod oscilloscope;
11use std::{collections::HashMap, sync::Mutex};
12
13pub use common::SendStatus;
14
15use caw_core::{Channel, Sig, SigT};
16use lazy_static::lazy_static;
17
18struct StereoOscilloscopeState {
19 server: oscilloscope::Server,
20 last_batch_index: u64,
21 buf: Vec<f32>,
22}
23
24lazy_static! {
25 static ref STEREO_OSCILLOSCOPE_STATES_BY_TITLE: Mutex<HashMap<String, StereoOscilloscopeState>> =
26 Mutex::new(HashMap::new());
27}
28
29pub trait VizSigBool {
30 fn viz_blink(
31 self,
32 title: impl AsRef<str>,
33 config: blink::Config,
34 ) -> Sig<impl SigT<Item = bool>>;
35}
36
37impl<S> VizSigBool for Sig<S>
38where
39 S: SigT<Item = bool>,
40{
41 fn viz_blink(
42 self,
43 title: impl AsRef<str>,
44 config: blink::Config,
45 ) -> Sig<impl SigT<Item = bool>> {
46 let make_viz =
47 move || blink::Server::new(title.as_ref(), config.clone()).unwrap();
48 let mut viz = make_viz();
49 let sig = self.shared();
50 let delay_s = 0.05;
51 let env =
52 caw_modules::adsr_linear_01(sig.clone().trig_to_gate(delay_s))
53 .release_s(delay_s)
54 .build()
55 .with_buf(move |buf| {
56 match viz.send_samples(buf) {
57 Ok(SendStatus::Success) => (),
58 Ok(SendStatus::Disconnected) => {
59 viz = make_viz();
61 }
62 Err(e) => eprintln!("{}", e),
63 }
64 });
65 Sig(sig).force(env)
66 }
67}
68
69pub trait VizSigF32 {
70 fn viz_blink(
71 self,
72 title: impl AsRef<str>,
73 config: blink::Config,
74 ) -> Sig<impl SigT<Item = f32>>;
75
76 fn viz_oscilloscope(
77 self,
78 title: impl AsRef<str>,
79 config: oscilloscope::Config,
80 ) -> Sig<impl SigT<Item = f32>>;
81
82 fn viz_oscilloscope_stereo(
86 self,
87 title: impl AsRef<str>,
88 channel: Channel,
89 config: oscilloscope::Config,
90 ) -> Sig<impl SigT<Item = f32>>;
91}
92
93impl<S> VizSigF32 for Sig<S>
94where
95 S: SigT<Item = f32>,
96{
97 fn viz_blink(
98 self,
99 title: impl AsRef<str>,
100 config: blink::Config,
101 ) -> Sig<impl SigT<Item = f32>> {
102 let make_viz =
103 move || blink::Server::new(title.as_ref(), config.clone()).unwrap();
104 let mut viz = make_viz();
105 Sig(self).with_buf(move |buf| {
106 match viz.send_samples(buf) {
107 Ok(SendStatus::Success) => (),
108 Ok(SendStatus::Disconnected) => {
109 viz = make_viz();
111 }
112 Err(e) => eprintln!("{}", e),
113 }
114 })
115 }
116
117 fn viz_oscilloscope(
118 self,
119 title: impl AsRef<str>,
120 config: oscilloscope::Config,
121 ) -> Sig<impl SigT<Item = f32>> {
122 let make_viz = move || {
123 oscilloscope::Server::new(title.as_ref(), config.clone()).unwrap()
124 };
125 let mut viz = make_viz();
126 Sig(self).with_buf(move |buf| {
127 match viz.send_samples(buf) {
128 Ok(SendStatus::Success) => (),
129 Ok(SendStatus::Disconnected) => {
130 viz = make_viz();
132 }
133 Err(e) => eprintln!("{}", e),
134 }
135 })
136 }
137
138 fn viz_oscilloscope_stereo(
139 self,
140 title: impl AsRef<str>,
141 channel: Channel,
142 config: oscilloscope::Config,
143 ) -> Sig<impl SigT<Item = f32>> {
144 let title = title.as_ref().to_string();
145 let make_server = {
146 let title = title.clone();
147 move || {
148 oscilloscope::Server::new(title.as_str(), config.clone())
149 .unwrap()
150 }
151 };
152 {
153 let mut states =
155 STEREO_OSCILLOSCOPE_STATES_BY_TITLE.lock().unwrap();
156 states.entry(title.clone()).or_insert_with(|| {
157 StereoOscilloscopeState {
158 server: make_server(),
159 last_batch_index: 0,
160 buf: Vec::new(),
161 }
162 });
163 }
164 Sig(self).with_buf_ctx(move |buf, ctx| {
165 let mut states =
166 STEREO_OSCILLOSCOPE_STATES_BY_TITLE.lock().unwrap();
167 let this_state = states.get_mut(&title).unwrap();
168 if this_state.last_batch_index == ctx.batch_index {
169 let mut i = match channel {
172 Channel::Left => 0,
173 Channel::Right => 1,
174 };
175 for &sample in buf {
176 this_state.buf[i] = sample;
177 i += 2;
178 }
179 match this_state.server.send_samples(&this_state.buf) {
180 Ok(SendStatus::Success) => (),
181 Ok(SendStatus::Disconnected) => {
182 this_state.server = make_server();
184 }
185 Err(e) => eprintln!("{}", e),
186 }
187 } else {
188 this_state.last_batch_index = ctx.batch_index;
192 this_state.buf.clear();
193 for &sample in buf {
194 this_state.buf.push(sample);
199 this_state.buf.push(sample);
200 }
201 }
202 })
203 }
204}