rill_core/queues/
telemetry_block.rs1use crate::math::Transcendental;
2use crate::traits::NodeId;
3
4#[repr(C)]
9#[derive(Debug, Clone, Copy)]
10pub struct TelemetryBlock<T: Transcendental, const BUF_SIZE: usize> {
11 pub node_id: NodeId,
13 pub channel: u32,
15 pub timestamp: u64,
17 pub sample_rate: f32,
19 pub block_index: u64,
21 pub peak: T,
23 pub rms: T,
25 pub dc_offset: T,
27 pub data: [T; BUF_SIZE],
29}
30
31impl<T: Transcendental, const BUF_SIZE: usize> Default for TelemetryBlock<T, BUF_SIZE> {
32 fn default() -> Self {
33 Self {
34 node_id: NodeId(0),
35 channel: 0,
36 timestamp: 0,
37 sample_rate: 44100.0,
38 block_index: 0,
39 peak: T::ZERO,
40 rms: T::ZERO,
41 dc_offset: T::ZERO,
42 data: [T::ZERO; BUF_SIZE],
43 }
44 }
45}
46
47impl<T: Transcendental, const BUF_SIZE: usize> TelemetryBlock<T, BUF_SIZE> {
48 #[inline]
50 pub fn compute_metrics(&mut self) {
51 let mut sum = T::ZERO;
52 let mut sq_sum = T::ZERO;
53 let mut peak = T::ZERO;
54
55 for &sample in self.data.iter() {
56 let abs = sample.abs();
57 if abs > peak {
58 peak = abs;
59 }
60 sum = sum + sample;
61 sq_sum = sq_sum + sample * sample;
62 }
63
64 let len = T::from_f32(BUF_SIZE as f32);
65 self.dc_offset = sum / len;
66 self.rms = (sq_sum / len).sqrt();
67 self.peak = peak;
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_telemetry_block_default() {
77 let block = TelemetryBlock::<f32, 64>::default();
78 assert_eq!(block.node_id, NodeId(0));
79 assert_eq!(block.channel, 0);
80 assert_eq!(block.timestamp, 0);
81 assert_eq!(block.block_index, 0);
82 assert_eq!(block.peak, 0.0);
83 assert_eq!(block.rms, 0.0);
84 assert_eq!(block.dc_offset, 0.0);
85 assert_eq!(block.data.len(), 64);
86 }
87
88 #[test]
89 fn test_telemetry_block_copy() {
90 let block = TelemetryBlock::<f32, 64>::default();
91 let copied = block;
92 assert_eq!(copied.node_id, block.node_id);
93 }
94
95 #[test]
96 fn test_compute_metrics_sine() {
97 let mut block = TelemetryBlock::<f32, 64>::default();
98 for (i, sample) in block.data.iter_mut().enumerate() {
99 *sample = (i as f32 * std::f32::consts::TAU / 64.0).sin();
100 }
101 block.compute_metrics();
102 assert!((block.peak - 1.0).abs() < 0.01, "peak={}", block.peak);
103 assert!((block.rms - 0.707).abs() < 0.01, "rms={}", block.rms);
104 assert!(
105 block.dc_offset.abs() < 0.01,
106 "dc_offset={}",
107 block.dc_offset
108 );
109 }
110
111 #[test]
112 fn test_compute_metrics_dc() {
113 let mut block = TelemetryBlock::<f32, 64>::default();
114 for sample in block.data.iter_mut() {
115 *sample = 0.5;
116 }
117 block.compute_metrics();
118 assert_eq!(block.dc_offset, 0.5);
119 assert_eq!(block.peak, 0.5);
120 assert_eq!(block.rms, 0.5);
121 }
122}