firewheel_core/
event.rs

1use core::any::Any;
2
3pub use glam::{Vec2, Vec3};
4
5use crate::{clock::EventDelay, diff::ParamPath, dsp::volume::Volume, node::NodeID};
6
7/// An event sent to an [`AudioNodeProcessor`][crate::node::AudioNodeProcessor].
8pub struct NodeEvent {
9    /// The ID of the node that should receive the event.
10    pub node_id: NodeID,
11    /// The type of event.
12    pub event: NodeEventType,
13}
14
15/// An event type associated with an [`AudioNodeProcessor`][crate::node::AudioNodeProcessor].
16#[non_exhaustive]
17pub enum NodeEventType {
18    Param {
19        /// Data for a specific parameter.
20        data: ParamData,
21        /// The path to the parameter.
22        path: ParamPath,
23    },
24    /// A command to control the current sequence in a node.
25    ///
26    /// This only has an effect on certain nodes.
27    SequenceCommand(SequenceCommand),
28    /// Custom event type.
29    Custom(Box<dyn Any + Send + Sync>),
30    /// Custom event type stored on the stack as raw bytes.
31    CustomBytes([u8; 16]),
32}
33
34/// Data that can be used to patch an individual parameter.
35///
36/// The [`ParamData::Any`] variant is double-boxed to keep
37/// its size small on the stack.
38#[non_exhaustive]
39pub enum ParamData {
40    Volume(Volume),
41    F32(f32),
42    F64(f64),
43    I32(i32),
44    U32(u32),
45    U64(u64),
46    Bool(bool),
47    Vector2D(Vec2),
48    Vector3D(Vec3),
49    Any(Box<Box<dyn Any + Send + Sync>>),
50}
51
52impl ParamData {
53    /// Construct a [`ParamData::Any`] variant.
54    pub fn any<T: Any + Send + Sync>(value: T) -> Self {
55        Self::Any(Box::new(Box::new(value)))
56    }
57
58    /// Try to downcast [`ParamData::Any`] into `T`.
59    ///
60    /// If this enum doesn't hold [`ParamData::Any`] or
61    /// the downcast fails, this returns `None`.
62    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
63        match self {
64            Self::Any(any) => any.downcast_ref(),
65            _ => None,
66        }
67    }
68}
69
70macro_rules! param_data_from {
71    ($ty:ty, $variant:ident) => {
72        impl From<$ty> for ParamData {
73            fn from(value: $ty) -> Self {
74                Self::$variant(value)
75            }
76        }
77
78        impl TryInto<$ty> for &ParamData {
79            type Error = crate::diff::PatchError;
80
81            fn try_into(self) -> Result<$ty, crate::diff::PatchError> {
82                match self {
83                    ParamData::$variant(value) => Ok(*value),
84                    _ => Err(crate::diff::PatchError::InvalidData),
85                }
86            }
87        }
88    };
89}
90
91param_data_from!(Volume, Volume);
92param_data_from!(f32, F32);
93param_data_from!(f64, F64);
94param_data_from!(i32, I32);
95param_data_from!(u32, U32);
96param_data_from!(u64, U64);
97param_data_from!(bool, Bool);
98param_data_from!(Vec2, Vector2D);
99param_data_from!(Vec3, Vector3D);
100
101/// A command to control the current sequence in a node.
102///
103/// This only has an effect on certain nodes.
104#[derive(Debug, Clone, Copy, PartialEq)]
105pub enum SequenceCommand {
106    /// Start/restart the current sequence.
107    StartOrRestart {
108        /// The exact moment when the sequence should start. Set to `None`
109        /// to start as soon as the event is received.
110        delay: Option<EventDelay>,
111    },
112    /// Pause the current sequence.
113    Pause,
114    /// Resume the current sequence.
115    Resume,
116    /// Stop the current sequence.
117    Stop,
118}
119
120/// A list of events for an [`AudioNodeProcessor`][crate::node::AudioNodeProcessor].
121pub struct NodeEventList<'a> {
122    event_buffer: &'a mut [NodeEvent],
123    indices: &'a [u32],
124}
125
126impl<'a> NodeEventList<'a> {
127    pub fn new(event_buffer: &'a mut [NodeEvent], indices: &'a [u32]) -> Self {
128        Self {
129            event_buffer,
130            indices,
131        }
132    }
133
134    pub fn num_events(&self) -> usize {
135        self.indices.len()
136    }
137
138    pub fn get_event(&mut self, index: usize) -> Option<&mut NodeEventType> {
139        self.indices
140            .get(index)
141            .map(|idx| &mut self.event_buffer[*idx as usize].event)
142    }
143
144    pub fn for_each(&mut self, mut f: impl FnMut(&mut NodeEventType)) {
145        for &idx in self.indices {
146            if let Some(event) = self.event_buffer.get_mut(idx as usize) {
147                (f)(&mut event.event);
148            }
149        }
150    }
151}