1use core::any::Any;
2
3#[cfg(not(feature = "std"))]
4use bevy_platform::prelude::{Box, Vec};
5
6use crate::{
7 clock::{DurationSamples, DurationSeconds, InstantSamples, InstantSeconds},
8 collector::{ArcGc, OwnedGc},
9 diff::{Notify, ParamPath},
10 dsp::volume::Volume,
11 node::NodeID,
12 vector::{Vec2, Vec3},
13};
14
15#[cfg(feature = "midi_events")]
16pub use wmidi;
17#[cfg(feature = "midi_events")]
18use wmidi::MidiMessage;
19
20#[cfg(feature = "scheduled_events")]
21use crate::clock::EventInstant;
22
23#[cfg(feature = "musical_transport")]
24use crate::clock::{DurationMusical, InstantMusical};
25
26pub struct NodeEvent {
28 pub node_id: NodeID,
30 #[cfg(feature = "scheduled_events")]
33 pub time: Option<EventInstant>,
34 pub event: NodeEventType,
36}
37
38impl NodeEvent {
39 pub const fn new(node_id: NodeID, event: NodeEventType) -> Self {
44 Self {
45 node_id,
46 #[cfg(feature = "scheduled_events")]
47 time: None,
48 event,
49 }
50 }
51
52 #[cfg(feature = "scheduled_events")]
59 pub const fn scheduled(node_id: NodeID, time: EventInstant, event: NodeEventType) -> Self {
60 Self {
61 node_id,
62 time: Some(time),
63 event,
64 }
65 }
66}
67
68#[non_exhaustive]
70pub enum NodeEventType {
71 Param {
72 data: ParamData,
74 path: ParamPath,
76 },
77 Custom(OwnedGc<Box<dyn Any + Send + 'static>>),
79 CustomBytes([u8; 36]),
81 #[cfg(feature = "midi_events")]
82 MIDI(MidiMessage<'static>),
83}
84
85impl NodeEventType {
86 pub fn custom<T: Send + 'static>(value: T) -> Self {
87 Self::Custom(OwnedGc::new(Box::new(value)))
88 }
89
90 pub fn downcast_ref<T: Send + 'static>(&self) -> Option<&T> {
95 if let Self::Custom(owned) = self {
96 owned.downcast_ref()
97 } else {
98 None
99 }
100 }
101
102 pub fn downcast_mut<T: Send + 'static>(&mut self) -> Option<&mut T> {
107 if let Self::Custom(owned) = self {
108 owned.downcast_mut()
109 } else {
110 None
111 }
112 }
113}
114
115#[derive(Clone, Debug)]
117#[non_exhaustive]
118pub enum ParamData {
119 F32(f32),
120 F64(f64),
121 I32(i32),
122 U32(u32),
123 I64(i64),
124 U64(u64),
125 Bool(bool),
126 Volume(Volume),
127 Vector2D(Vec2),
128 Vector3D(Vec3),
129
130 #[cfg(feature = "scheduled_events")]
131 EventInstant(EventInstant),
132 InstantSeconds(InstantSeconds),
133 DurationSeconds(DurationSeconds),
134 InstantSamples(InstantSamples),
135 DurationSamples(DurationSamples),
136 #[cfg(feature = "musical_transport")]
137 InstantMusical(InstantMusical),
138 #[cfg(feature = "musical_transport")]
139 DurationMusical(DurationMusical),
140
141 Any(ArcGc<dyn Any + Send + Sync>),
143
144 CustomBytes([u8; 20]),
146
147 None,
149}
150
151impl ParamData {
152 pub fn any<T: Send + Sync + 'static>(value: T) -> Self {
154 Self::Any(ArcGc::new_any(value))
155 }
156
157 pub fn opt_any<T: Any + Send + Sync + 'static>(value: Option<T>) -> Self {
159 if let Some(value) = value {
160 Self::any(value)
161 } else {
162 Self::None
163 }
164 }
165
166 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
171 match self {
172 Self::Any(any) => any.downcast_ref(),
173 _ => None,
174 }
175 }
176}
177
178macro_rules! param_data_from {
179 ($ty:ty, $variant:ident) => {
180 impl From<$ty> for ParamData {
181 fn from(value: $ty) -> Self {
182 Self::$variant(value.into())
183 }
184 }
185
186 impl TryInto<$ty> for &ParamData {
187 type Error = crate::diff::PatchError;
188
189 fn try_into(self) -> Result<$ty, crate::diff::PatchError> {
190 match self {
191 ParamData::$variant(value) => Ok((*value).into()),
192 _ => Err(crate::diff::PatchError::InvalidData),
193 }
194 }
195 }
196
197 impl From<Option<$ty>> for ParamData {
198 fn from(value: Option<$ty>) -> Self {
199 if let Some(value) = value {
200 Self::$variant(value.into())
201 } else {
202 Self::None
203 }
204 }
205 }
206
207 impl TryInto<Option<$ty>> for &ParamData {
208 type Error = crate::diff::PatchError;
209
210 fn try_into(self) -> Result<Option<$ty>, crate::diff::PatchError> {
211 match self {
212 ParamData::$variant(value) => Ok(Some((*value).into())),
213 ParamData::None => Ok(None),
214 _ => Err(crate::diff::PatchError::InvalidData),
215 }
216 }
217 }
218
219 impl From<Notify<$ty>> for ParamData {
220 fn from(value: Notify<$ty>) -> Self {
221 Self::$variant((*value).into())
222 }
223 }
224
225 impl TryInto<Notify<$ty>> for &ParamData {
226 type Error = crate::diff::PatchError;
227
228 fn try_into(self) -> Result<Notify<$ty>, crate::diff::PatchError> {
229 match self {
230 ParamData::$variant(value) => Ok(Notify::new((*value).into())),
231 _ => Err(crate::diff::PatchError::InvalidData),
232 }
233 }
234 }
235 };
236}
237
238param_data_from!(Volume, Volume);
239param_data_from!(f32, F32);
240param_data_from!(f64, F64);
241param_data_from!(i32, I32);
242param_data_from!(u32, U32);
243param_data_from!(i64, I64);
244param_data_from!(u64, U64);
245param_data_from!(bool, Bool);
246param_data_from!(Vec2, Vector2D);
247param_data_from!(Vec3, Vector3D);
248#[cfg(feature = "scheduled_events")]
249param_data_from!(EventInstant, EventInstant);
250param_data_from!(InstantSeconds, InstantSeconds);
251param_data_from!(DurationSeconds, DurationSeconds);
252param_data_from!(InstantSamples, InstantSamples);
253param_data_from!(DurationSamples, DurationSamples);
254#[cfg(feature = "musical_transport")]
255param_data_from!(InstantMusical, InstantMusical);
256#[cfg(feature = "musical_transport")]
257param_data_from!(DurationMusical, DurationMusical);
258
259#[cfg(feature = "glam-29")]
260param_data_from!(glam::Vec2, Vector2D);
261#[cfg(feature = "glam-29")]
262param_data_from!(glam::Vec3, Vector3D);
263
264impl From<()> for ParamData {
265 fn from(_value: ()) -> Self {
266 Self::None
267 }
268}
269
270impl TryInto<()> for &ParamData {
271 type Error = crate::diff::PatchError;
272
273 fn try_into(self) -> Result<(), crate::diff::PatchError> {
274 match self {
275 ParamData::None => Ok(()),
276 _ => Err(crate::diff::PatchError::InvalidData),
277 }
278 }
279}
280
281impl From<Notify<()>> for ParamData {
282 fn from(_value: Notify<()>) -> Self {
283 Self::None
284 }
285}
286
287impl TryInto<Notify<()>> for &ParamData {
288 type Error = crate::diff::PatchError;
289
290 fn try_into(self) -> Result<Notify<()>, crate::diff::PatchError> {
291 match self {
292 ParamData::None => Ok(Notify::new(())),
293 _ => Err(crate::diff::PatchError::InvalidData),
294 }
295 }
296}
297
298pub struct ProcEvents<'a> {
300 immediate_event_buffer: &'a mut [Option<NodeEvent>],
301 #[cfg(feature = "scheduled_events")]
302 scheduled_event_arena: &'a mut [Option<NodeEvent>],
303 indices: &'a mut Vec<ProcEventsIndex>,
304}
305
306impl<'a> ProcEvents<'a> {
307 pub fn new(
308 immediate_event_buffer: &'a mut [Option<NodeEvent>],
309 #[cfg(feature = "scheduled_events")] scheduled_event_arena: &'a mut [Option<NodeEvent>],
310 indices: &'a mut Vec<ProcEventsIndex>,
311 ) -> Self {
312 Self {
313 immediate_event_buffer,
314 #[cfg(feature = "scheduled_events")]
315 scheduled_event_arena,
316 indices,
317 }
318 }
319
320 pub fn num_events(&self) -> usize {
321 self.indices.len()
322 }
323
324 pub fn drain<'b>(&'b mut self) -> impl IntoIterator<Item = NodeEventType> + use<'b> {
326 self.indices.drain(..).map(|index_type| match index_type {
327 ProcEventsIndex::Immediate(i) => {
328 self.immediate_event_buffer[i as usize]
329 .take()
330 .unwrap()
331 .event
332 }
333 #[cfg(feature = "scheduled_events")]
334 ProcEventsIndex::Scheduled(i) => {
335 self.scheduled_event_arena[i as usize].take().unwrap().event
336 }
337 })
338 }
339
340 #[cfg(feature = "scheduled_events")]
348 pub fn drain_with_timestamps<'b>(
349 &'b mut self,
350 ) -> impl IntoIterator<Item = (NodeEventType, Option<EventInstant>)> + use<'b> {
351 self.indices.drain(..).map(|index_type| match index_type {
352 ProcEventsIndex::Immediate(i) => {
353 let event = self.immediate_event_buffer[i as usize].take().unwrap();
354
355 (event.event, event.time)
356 }
357 ProcEventsIndex::Scheduled(i) => {
358 let event = self.scheduled_event_arena[i as usize].take().unwrap();
359
360 (event.event, event.time)
361 }
362 })
363 }
364
365 pub fn drain_patches<'b, T: crate::diff::Patch>(
397 &'b mut self,
398 ) -> impl IntoIterator<Item = <T as crate::diff::Patch>::Patch> + use<'b, T> {
399 self.drain().into_iter().filter_map(|e| T::patch_event(&e))
403 }
404
405 #[cfg(feature = "scheduled_events")]
442 pub fn drain_patches_with_timestamps<'b, T: crate::diff::Patch>(
443 &'b mut self,
444 ) -> impl IntoIterator<Item = (<T as crate::diff::Patch>::Patch, Option<EventInstant>)> + use<'b, T>
445 {
446 self.drain_with_timestamps()
450 .into_iter()
451 .filter_map(|(e, timestamp)| T::patch_event(&e).map(|patch| (patch, timestamp)))
452 }
453}
454
455#[derive(Debug, Clone, Copy, PartialEq, Eq)]
457pub enum ProcEventsIndex {
458 Immediate(u32),
459 #[cfg(feature = "scheduled_events")]
460 Scheduled(u32),
461}