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