sim_lib_audio_graph_live/
event.rs1use sim_kernel::{Error, Result, Symbol};
2use sim_lib_audio_graph_core::BlockEvent;
3use sim_lib_stream_core::{BackpressureOutcome, StreamDiagnostic, StreamPacket};
4
5pub type LiveQueuePush = BackpressureOutcome;
7
8#[derive(Clone, Copy, Debug, PartialEq)]
10pub enum LiveControlEvent {
11 Midi {
13 offset: u32,
15 bytes: [u8; 3],
17 len: u8,
19 },
20 ParamSet {
22 offset: u32,
24 param: u32,
26 value: f64,
28 },
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
33pub enum LiveAudioEvent {
34 Xrun {
36 frames: u32,
38 max_frames: u32,
40 },
41 DroppedControlEvents {
43 count: u64,
45 },
46 DroppedAudioEvents {
48 count: u64,
50 },
51 ProcessorParamSet {
53 offset: u32,
55 param: u32,
57 value: f64,
59 },
60 ProcessorMidi {
62 offset: u32,
64 bytes: [u8; 3],
66 len: u8,
68 },
69}
70
71impl LiveControlEvent {
72 pub fn midi_short(offset: u32, bytes: &[u8]) -> Result<Self> {
74 if bytes.is_empty() || bytes.len() > 3 {
75 return Err(Error::Eval(
76 "live MIDI event must contain one to three bytes".to_owned(),
77 ));
78 }
79 let mut padded = [0; 3];
80 padded[..bytes.len()].copy_from_slice(bytes);
81 Ok(Self::Midi {
82 offset,
83 bytes: padded,
84 len: bytes.len() as u8,
85 })
86 }
87
88 pub fn param_set(offset: u32, param: u32, value: f64) -> Result<Self> {
90 if !value.is_finite() {
91 return Err(Error::Eval(
92 "live parameter value must be finite".to_owned(),
93 ));
94 }
95 Ok(Self::ParamSet {
96 offset,
97 param,
98 value,
99 })
100 }
101
102 pub fn offset(self) -> u32 {
104 match self {
105 Self::Midi { offset, .. } | Self::ParamSet { offset, .. } => offset,
106 }
107 }
108
109 pub fn to_block_event(self) -> BlockEvent<'static> {
111 match self {
112 Self::Midi { offset, bytes, len } => BlockEvent::Midi { offset, bytes, len },
113 Self::ParamSet {
114 offset,
115 param,
116 value,
117 } => BlockEvent::ParamSet {
118 offset,
119 param,
120 value,
121 },
122 }
123 }
124}
125
126impl LiveAudioEvent {
127 pub fn from_processor_event(event: BlockEvent<'_>) -> Option<Self> {
132 match event {
133 BlockEvent::Midi { offset, bytes, len } => {
134 Some(Self::ProcessorMidi { offset, bytes, len })
135 }
136 BlockEvent::ParamSet {
137 offset,
138 param,
139 value,
140 } => Some(Self::ProcessorParamSet {
141 offset,
142 param,
143 value,
144 }),
145 BlockEvent::MidiLong { .. }
146 | BlockEvent::NoteOn { .. }
147 | BlockEvent::NoteOff { .. } => None,
148 }
149 }
150
151 pub fn to_diagnostic_packet(self) -> StreamPacket {
153 let (kind, message) = match self {
154 Self::Xrun { frames, max_frames } => (
155 Symbol::qualified("stream/diagnostic", "xrun"),
156 format!("live callback received {frames} frames, max block is {max_frames}"),
157 ),
158 Self::DroppedControlEvents { count } => (
159 Symbol::qualified("stream/diagnostic", "control-drop"),
160 format!("live control-to-audio queue dropped {count} events"),
161 ),
162 Self::DroppedAudioEvents { count } => (
163 Symbol::qualified("stream/diagnostic", "audio-drop"),
164 format!("live audio-to-control queue dropped {count} events"),
165 ),
166 Self::ProcessorParamSet {
167 offset,
168 param,
169 value,
170 } => (
171 Symbol::qualified("stream/diagnostic", "processor-param"),
172 format!("processor emitted param {param}={value} at frame {offset}"),
173 ),
174 Self::ProcessorMidi { offset, len, .. } => (
175 Symbol::qualified("stream/diagnostic", "processor-midi"),
176 format!("processor emitted {len}-byte MIDI event at frame {offset}"),
177 ),
178 };
179 StreamPacket::Diagnostic(StreamDiagnostic::new(kind, message))
180 }
181}