firewheel_core/
event.rs

1use core::any::Any;
2
3pub use glam::{Vec2, Vec3};
4
5use crate::{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    /// Custom event type.
25    Custom(Box<dyn Any + Send + Sync>),
26    /// Custom event type stored on the stack as raw bytes.
27    CustomBytes([u8; 16]),
28}
29
30/// Data that can be used to patch an individual parameter.
31///
32/// The [`ParamData::Any`] variant is double-boxed to keep
33/// its size small on the stack.
34#[non_exhaustive]
35pub enum ParamData {
36    Volume(Volume),
37    F32(f32),
38    F64(f64),
39    I32(i32),
40    U32(u32),
41    U64(u64),
42    Bool(bool),
43    Vector2D(Vec2),
44    Vector3D(Vec3),
45    Any(Box<Box<dyn Any + Send + Sync>>),
46}
47
48impl ParamData {
49    /// Construct a [`ParamData::Any`] variant.
50    pub fn any<T: Any + Send + Sync>(value: T) -> Self {
51        Self::Any(Box::new(Box::new(value)))
52    }
53
54    /// Try to downcast [`ParamData::Any`] into `T`.
55    ///
56    /// If this enum doesn't hold [`ParamData::Any`] or
57    /// the downcast fails, this returns `None`.
58    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
59        match self {
60            Self::Any(any) => any.downcast_ref(),
61            _ => None,
62        }
63    }
64}
65
66macro_rules! param_data_from {
67    ($ty:ty, $variant:ident) => {
68        impl From<$ty> for ParamData {
69            fn from(value: $ty) -> Self {
70                Self::$variant(value)
71            }
72        }
73
74        impl TryInto<$ty> for &ParamData {
75            type Error = crate::diff::PatchError;
76
77            fn try_into(self) -> Result<$ty, crate::diff::PatchError> {
78                match self {
79                    ParamData::$variant(value) => Ok(*value),
80                    _ => Err(crate::diff::PatchError::InvalidData),
81                }
82            }
83        }
84    };
85}
86
87param_data_from!(Volume, Volume);
88param_data_from!(f32, F32);
89param_data_from!(f64, F64);
90param_data_from!(i32, I32);
91param_data_from!(u32, U32);
92param_data_from!(u64, U64);
93param_data_from!(bool, Bool);
94param_data_from!(Vec2, Vector2D);
95param_data_from!(Vec3, Vector3D);
96
97/// A list of events for an [`AudioNodeProcessor`][crate::node::AudioNodeProcessor].
98pub struct NodeEventList<'a> {
99    event_buffer: &'a mut [NodeEvent],
100    indices: &'a [u32],
101}
102
103impl<'a> NodeEventList<'a> {
104    pub fn new(event_buffer: &'a mut [NodeEvent], indices: &'a [u32]) -> Self {
105        Self {
106            event_buffer,
107            indices,
108        }
109    }
110
111    pub fn num_events(&self) -> usize {
112        self.indices.len()
113    }
114
115    pub fn get_event(&mut self, index: usize) -> Option<&mut NodeEventType> {
116        self.indices
117            .get(index)
118            .map(|idx| &mut self.event_buffer[*idx as usize].event)
119    }
120
121    pub fn for_each(&mut self, mut f: impl FnMut(&mut NodeEventType)) {
122        for &idx in self.indices {
123            if let Some(event) = self.event_buffer.get_mut(idx as usize) {
124                (f)(&mut event.event);
125            }
126        }
127    }
128
129    /// Iterate over patches for `T`.
130    ///
131    /// ```
132    /// # use firewheel_core::{diff::*, event::NodeEventList};
133    /// # fn for_each_example(mut event_list: NodeEventList) {
134    /// #[derive(Patch, Default)]
135    /// struct FilterNode {
136    ///     frequency: f32,
137    ///     quality: f32,
138    /// }
139    ///
140    /// // You can match on individual patch variants.
141    /// event_list.for_each_patch::<FilterNode>(|patch| match patch {
142    ///     FilterNodePatch::Frequency(frequency) => {}
143    ///     FilterNodePatch::Quality(quality) => {}
144    /// });
145    ///
146    /// // Or simply apply all of them.
147    /// let mut node = FilterNode::default();
148    /// event_list.for_each_patch::<FilterNode>(|patch| node.apply(patch));
149    /// # }
150    /// ```
151    ///
152    /// Errors produced while constructing patches are simply skipped.
153    pub fn for_each_patch<T: crate::diff::Patch>(&mut self, mut f: impl FnMut(T::Patch)) {
154        for &idx in self.indices {
155            if let Some(patch) = self
156                .event_buffer
157                .get_mut(idx as usize)
158                .and_then(|e| T::patch_event(&e.event))
159            {
160                (f)(patch);
161            }
162        }
163    }
164}