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
26#[derive(Debug)]
28pub struct NodeEvent {
29 pub node_id: NodeID,
31 #[cfg(feature = "scheduled_events")]
34 pub time: Option<EventInstant>,
35 pub event: NodeEventType,
37}
38
39impl NodeEvent {
40 pub const fn new(node_id: NodeID, event: NodeEventType) -> Self {
45 Self {
46 node_id,
47 #[cfg(feature = "scheduled_events")]
48 time: None,
49 event,
50 }
51 }
52
53 #[cfg(feature = "scheduled_events")]
60 pub const fn scheduled(node_id: NodeID, time: EventInstant, event: NodeEventType) -> Self {
61 Self {
62 node_id,
63 time: Some(time),
64 event,
65 }
66 }
67}
68
69#[non_exhaustive]
71pub enum NodeEventType {
72 Param {
73 data: ParamData,
75 path: ParamPath,
77 },
78 Custom(OwnedGc<Box<dyn Any + Send + 'static>>),
80 CustomBytes([u8; 36]),
82 #[cfg(feature = "midi_events")]
83 MIDI(MidiMessage<'static>),
84}
85
86impl NodeEventType {
87 pub fn custom<T: Send + 'static>(value: T) -> Self {
88 Self::Custom(OwnedGc::new(Box::new(value)))
89 }
90
91 pub fn custom_boxed<T: Send + 'static>(value: Box<T>) -> Self {
92 Self::Custom(OwnedGc::new(value))
93 }
94
95 pub fn downcast_ref<T: Send + 'static>(&self) -> Option<&T> {
100 if let Self::Custom(owned) = self {
101 owned.as_ref().downcast_ref()
102 } else {
103 None
104 }
105 }
106
107 pub fn downcast_mut<T: Send + 'static>(&mut self) -> Option<&mut T> {
112 if let Self::Custom(owned) = self {
113 owned.as_mut().downcast_mut()
114 } else {
115 None
116 }
117 }
118
119 pub fn downcast_swap<T: Send + 'static>(&mut self, value: &mut T) -> bool {
129 if let Some(v) = self.downcast_mut::<T>() {
130 core::mem::swap(v, value);
131 true
132 } else {
133 false
134 }
135 }
136
137 pub fn downcast_into_owned<T: Send + 'static>(&mut self, value: &mut OwnedGc<T>) -> bool {
147 if let Some(v) = self.downcast_mut::<T>() {
148 value.swap(v);
149 true
150 } else {
151 false
152 }
153 }
154}
155
156impl core::fmt::Debug for NodeEventType {
157 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
158 match self {
159 NodeEventType::Param { data, path } => f
160 .debug_struct("Param")
161 .field("data", &data)
162 .field("path", &path)
163 .finish(),
164 NodeEventType::Custom(_) => f.debug_tuple("Custom").finish_non_exhaustive(),
165 NodeEventType::CustomBytes(f0) => f.debug_tuple("CustomBytes").field(&f0).finish(),
166 #[cfg(feature = "midi_events")]
167 NodeEventType::MIDI(f0) => f.debug_tuple("MIDI").field(&f0).finish(),
168 }
169 }
170}
171
172#[derive(Clone, Debug)]
174#[non_exhaustive]
175pub enum ParamData {
176 F32(f32),
177 F64(f64),
178 I32(i32),
179 U32(u32),
180 I64(i64),
181 U64(u64),
182 Bool(bool),
183 Volume(Volume),
184 Vector2D(Vec2),
185 Vector3D(Vec3),
186
187 #[cfg(feature = "scheduled_events")]
188 EventInstant(EventInstant),
189 InstantSeconds(InstantSeconds),
190 DurationSeconds(DurationSeconds),
191 InstantSamples(InstantSamples),
192 DurationSamples(DurationSamples),
193 #[cfg(feature = "musical_transport")]
194 InstantMusical(InstantMusical),
195 #[cfg(feature = "musical_transport")]
196 DurationMusical(DurationMusical),
197
198 Any(ArcGc<dyn Any + Send + Sync>),
200
201 CustomBytes([u8; 20]),
203
204 None,
206}
207
208impl ParamData {
209 pub fn any<T: Send + Sync + 'static>(value: T) -> Self {
211 Self::Any(ArcGc::new_any(value))
212 }
213
214 pub fn opt_any<T: Any + Send + Sync + 'static>(value: Option<T>) -> Self {
216 if let Some(value) = value {
217 Self::any(value)
218 } else {
219 Self::None
220 }
221 }
222
223 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
228 match self {
229 Self::Any(any) => any.downcast_ref(),
230 _ => None,
231 }
232 }
233}
234
235macro_rules! param_data_from {
236 ($ty:ty, $variant:ident) => {
237 impl From<$ty> for ParamData {
238 fn from(value: $ty) -> Self {
239 Self::$variant(value.into())
240 }
241 }
242
243 impl TryInto<$ty> for &ParamData {
244 type Error = crate::diff::PatchError;
245
246 fn try_into(self) -> Result<$ty, crate::diff::PatchError> {
247 match self {
248 ParamData::$variant(value) => Ok((*value).into()),
249 _ => Err(crate::diff::PatchError::InvalidData),
250 }
251 }
252 }
253
254 impl From<Option<$ty>> for ParamData {
255 fn from(value: Option<$ty>) -> Self {
256 if let Some(value) = value {
257 Self::$variant(value.into())
258 } else {
259 Self::None
260 }
261 }
262 }
263
264 impl TryInto<Option<$ty>> for &ParamData {
265 type Error = crate::diff::PatchError;
266
267 fn try_into(self) -> Result<Option<$ty>, crate::diff::PatchError> {
268 match self {
269 ParamData::$variant(value) => Ok(Some((*value).into())),
270 ParamData::None => Ok(None),
271 _ => Err(crate::diff::PatchError::InvalidData),
272 }
273 }
274 }
275
276 impl From<Notify<$ty>> for ParamData {
277 fn from(value: Notify<$ty>) -> Self {
278 Self::$variant((*value).into())
279 }
280 }
281
282 impl TryInto<Notify<$ty>> for &ParamData {
283 type Error = crate::diff::PatchError;
284
285 fn try_into(self) -> Result<Notify<$ty>, crate::diff::PatchError> {
286 match self {
287 ParamData::$variant(value) => Ok(Notify::new((*value).into())),
288 _ => Err(crate::diff::PatchError::InvalidData),
289 }
290 }
291 }
292 };
293}
294
295param_data_from!(Volume, Volume);
296param_data_from!(f32, F32);
297param_data_from!(f64, F64);
298param_data_from!(i32, I32);
299param_data_from!(u32, U32);
300param_data_from!(i64, I64);
301param_data_from!(u64, U64);
302param_data_from!(bool, Bool);
303param_data_from!(Vec2, Vector2D);
304param_data_from!(Vec3, Vector3D);
305#[cfg(feature = "scheduled_events")]
306param_data_from!(EventInstant, EventInstant);
307param_data_from!(InstantSeconds, InstantSeconds);
308param_data_from!(DurationSeconds, DurationSeconds);
309param_data_from!(InstantSamples, InstantSamples);
310param_data_from!(DurationSamples, DurationSamples);
311#[cfg(feature = "musical_transport")]
312param_data_from!(InstantMusical, InstantMusical);
313#[cfg(feature = "musical_transport")]
314param_data_from!(DurationMusical, DurationMusical);
315
316#[cfg(feature = "glam-29")]
317param_data_from!(glam_29::Vec2, Vector2D);
318#[cfg(feature = "glam-29")]
319param_data_from!(glam_29::Vec3, Vector3D);
320
321#[cfg(feature = "glam-30")]
322param_data_from!(glam_30::Vec2, Vector2D);
323#[cfg(feature = "glam-30")]
324param_data_from!(glam_30::Vec3, Vector3D);
325
326impl From<()> for ParamData {
327 fn from(_value: ()) -> Self {
328 Self::None
329 }
330}
331
332impl TryInto<()> for &ParamData {
333 type Error = crate::diff::PatchError;
334
335 fn try_into(self) -> Result<(), crate::diff::PatchError> {
336 match self {
337 ParamData::None => Ok(()),
338 _ => Err(crate::diff::PatchError::InvalidData),
339 }
340 }
341}
342
343impl From<Notify<()>> for ParamData {
344 fn from(_value: Notify<()>) -> Self {
345 Self::None
346 }
347}
348
349impl TryInto<Notify<()>> for &ParamData {
350 type Error = crate::diff::PatchError;
351
352 fn try_into(self) -> Result<Notify<()>, crate::diff::PatchError> {
353 match self {
354 ParamData::None => Ok(Notify::new(())),
355 _ => Err(crate::diff::PatchError::InvalidData),
356 }
357 }
358}
359
360#[cfg(feature = "scheduled_events")]
362pub struct ScheduledEventEntry {
363 pub event: NodeEvent,
364 pub is_pre_process: bool,
365}
366
367pub struct ProcEvents<'a> {
369 immediate_event_buffer: &'a mut [Option<NodeEvent>],
370 #[cfg(feature = "scheduled_events")]
371 scheduled_event_arena: &'a mut [Option<ScheduledEventEntry>],
372 indices: &'a mut Vec<ProcEventsIndex>,
373}
374
375impl<'a> ProcEvents<'a> {
376 pub fn new(
377 immediate_event_buffer: &'a mut [Option<NodeEvent>],
378 #[cfg(feature = "scheduled_events")] scheduled_event_arena: &'a mut [Option<
379 ScheduledEventEntry,
380 >],
381 indices: &'a mut Vec<ProcEventsIndex>,
382 ) -> Self {
383 Self {
384 immediate_event_buffer,
385 #[cfg(feature = "scheduled_events")]
386 scheduled_event_arena,
387 indices,
388 }
389 }
390
391 pub fn num_events(&self) -> usize {
392 self.indices.len()
393 }
394
395 pub fn drain<'b>(&'b mut self) -> impl IntoIterator<Item = NodeEventType> + use<'b> {
397 self.indices.drain(..).map(|index_type| match index_type {
398 ProcEventsIndex::Immediate(i) => {
399 self.immediate_event_buffer[i as usize]
400 .take()
401 .unwrap()
402 .event
403 }
404 #[cfg(feature = "scheduled_events")]
405 ProcEventsIndex::Scheduled(i) => {
406 self.scheduled_event_arena[i as usize]
407 .take()
408 .unwrap()
409 .event
410 .event
411 }
412 })
413 }
414
415 #[cfg(feature = "scheduled_events")]
423 pub fn drain_with_timestamps<'b>(
424 &'b mut self,
425 ) -> impl IntoIterator<Item = (NodeEventType, Option<EventInstant>)> + use<'b> {
426 self.indices.drain(..).map(|index_type| match index_type {
427 ProcEventsIndex::Immediate(i) => {
428 let event = self.immediate_event_buffer[i as usize].take().unwrap();
429
430 (event.event, event.time)
431 }
432 ProcEventsIndex::Scheduled(i) => {
433 let event = self.scheduled_event_arena[i as usize].take().unwrap();
434
435 (event.event.event, event.event.time)
436 }
437 })
438 }
439
440 pub fn drain_patches<'b, T: crate::diff::Patch>(
472 &'b mut self,
473 ) -> impl IntoIterator<Item = <T as crate::diff::Patch>::Patch> + use<'b, T> {
474 self.drain().into_iter().filter_map(|e| T::patch_event(&e))
478 }
479
480 #[cfg(feature = "scheduled_events")]
517 pub fn drain_patches_with_timestamps<'b, T: crate::diff::Patch>(
518 &'b mut self,
519 ) -> impl IntoIterator<Item = (<T as crate::diff::Patch>::Patch, Option<EventInstant>)> + use<'b, T>
520 {
521 self.drain_with_timestamps()
525 .into_iter()
526 .filter_map(|(e, timestamp)| T::patch_event(&e).map(|patch| (patch, timestamp)))
527 }
528}
529
530#[derive(Debug, Clone, Copy, PartialEq, Eq)]
532pub enum ProcEventsIndex {
533 Immediate(u32),
534 #[cfg(feature = "scheduled_events")]
535 Scheduled(u32),
536}