1use std::sync::Arc;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4use rill_core::math::Transcendental;
5use rill_core::prelude::{
6 SignalNode, NodeCategory, NodeId, NodeMetadata, NodeState, ParamValue, ParameterId, Port,
7 ProcessResult,
8};
9use rill_core::queues::spsc::SpscQueue;
10use rill_core::queues::TelemetryBlock;
11use rill_core::time::ClockTick;
12use rill_core::traits::Processor;
13
14pub struct TelemetryProbe<T: Transcendental, const BUF_SIZE: usize, const QUEUE_CAP: usize> {
28 id: NodeId,
29 inputs: Vec<Port<T, BUF_SIZE>>,
30 outputs: Vec<Port<T, BUF_SIZE>>,
31 state: NodeState<T, BUF_SIZE>,
32
33 queue: Arc<SpscQueue<TelemetryBlock<T, BUF_SIZE>, QUEUE_CAP>>,
35
36 interval: u32,
38 counter: u32,
40 block_index: u64,
42 channel: u32,
44 node_name: String,
46}
47
48impl<T: Transcendental, const BUF_SIZE: usize, const QUEUE_CAP: usize>
49 TelemetryProbe<T, BUF_SIZE, QUEUE_CAP>
50{
51 pub fn new(
59 queue: Arc<SpscQueue<TelemetryBlock<T, BUF_SIZE>, QUEUE_CAP>>,
60 interval: u32,
61 channel: u32,
62 node_name: &str,
63 ) -> Self {
64 assert!(interval > 0, "interval must be positive");
65
66 let id = NodeId(0);
67 let inputs = vec![Port::input(id, 0, "signal_in")];
68
69 let outputs = vec![Port::output(id, 0, "signal_out")];
70
71 Self {
72 id,
73 inputs,
74 outputs,
75 state: NodeState::new(44100.0),
76 queue,
77 interval,
78 counter: 0,
79 block_index: 0,
80 channel,
81 node_name: node_name.to_string(),
82 }
83 }
84
85 pub fn queue(&self) -> &Arc<SpscQueue<TelemetryBlock<T, BUF_SIZE>, QUEUE_CAP>> {
87 &self.queue
88 }
89}
90
91impl<T: Transcendental, const BUF_SIZE: usize, const QUEUE_CAP: usize> SignalNode<T, BUF_SIZE>
94 for TelemetryProbe<T, BUF_SIZE, QUEUE_CAP>
95{
96 fn metadata(&self) -> NodeMetadata {
97 let mut meta = NodeMetadata::new(&self.node_name, NodeCategory::Analyzer);
98 meta.description = "Pass-through telemetry probe".to_string();
99 meta.author = "Rill".to_string();
100 meta.version = env!("CARGO_PKG_VERSION").to_string();
101 meta.signal_inputs = self.inputs.len();
102 meta.signal_outputs = self.outputs.len();
103 meta
104 }
105
106 fn init(&mut self, sample_rate: f32) {
107 self.state = NodeState::new(sample_rate);
108 }
109
110 fn reset(&mut self) {
111 self.state.reset();
112 self.counter = 0;
113 self.block_index = 0;
114 }
115
116 fn get_parameter(&self, _id: &ParameterId) -> Option<ParamValue> {
117 None
118 }
119
120 fn set_parameter(&mut self, _id: &ParameterId, _value: ParamValue) -> ProcessResult<()> {
121 Ok(())
122 }
123
124 fn id(&self) -> NodeId {
125 self.id
126 }
127
128 fn set_id(&mut self, id: NodeId) {
129 self.id = id;
130 }
131
132 fn input_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
133 self.inputs.get(index)
134 }
135
136 fn input_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
137 self.inputs.get_mut(index)
138 }
139
140 fn output_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
141 self.outputs.get(index)
142 }
143
144 fn output_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
145 self.outputs.get_mut(index)
146 }
147
148 fn control_port(&self, _index: usize) -> Option<&Port<T, BUF_SIZE>> {
149 None
150 }
151
152 fn control_port_mut(&mut self, _index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
153 None
154 }
155
156 fn num_control_inputs(&self) -> usize {
157 0
158 }
159
160 fn num_control_outputs(&self) -> usize {
161 0
162 }
163
164 fn state(&self) -> &NodeState<T, BUF_SIZE> {
165 &self.state
166 }
167
168 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
169 &mut self.state
170 }
171}
172
173impl<T: Transcendental, const BUF_SIZE: usize, const QUEUE_CAP: usize> Processor<T, BUF_SIZE>
176 for TelemetryProbe<T, BUF_SIZE, QUEUE_CAP>
177{
178 fn process(
179 &mut self,
180 _clock: &ClockTick,
181 signal_inputs: &[&[T; BUF_SIZE]],
182 _control_inputs: &[T],
183 _clock_inputs: &[ClockTick],
184 _feedback_inputs: &[&[T; BUF_SIZE]],
185 ) -> ProcessResult<()> {
186 let silence = [T::ZERO; BUF_SIZE];
188 let input = signal_inputs.first().copied().unwrap_or(&silence);
189 if let Some(port) = self.outputs.first_mut() {
190 port.buffer.as_mut_array().copy_from_slice(input);
191 }
192
193 self.counter += 1;
195 if self.counter >= self.interval {
196 self.counter = 0;
197
198 let timestamp = SystemTime::now()
199 .duration_since(UNIX_EPOCH)
200 .unwrap_or_default()
201 .as_micros() as u64;
202
203 let mut frame = TelemetryBlock {
204 node_id: self.id,
205 channel: self.channel,
206 sample_rate: self.state.sample_rate,
207 block_index: self.block_index,
208 timestamp,
209 ..Default::default()
210 };
211 frame.data.copy_from_slice(input);
212 frame.compute_metrics();
213
214 self.block_index += 1;
215
216 let _ = self.queue.push(frame);
218 }
219
220 self.state.advance();
221 Ok(())
222 }
223
224 fn latency(&self) -> usize {
225 0
226 }
227}