pub trait Patch {
type Patch;
// Required methods
fn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError>;
fn apply(&mut self, patch: Self::Patch);
// Provided method
fn patch_event(event: &NodeEventType) -> Option<Self::Patch> { ... }
}Expand description
Fine-grained parameter patching.
This trait allows a type to perform patching on itself, applying changes generated from another instance.
For more information, see the module docs.
§Examples
Like with Diff, the typical Patch usage is simple.
use firewheel_core::{diff::Patch, event::*, node::*, log::*};
#[derive(Patch)]
struct MyParams {
a: f32,
b: f32,
}
struct MyProcessor {
params: MyParams,
}
impl AudioNodeProcessor for MyProcessor {
fn process(
&mut self,
buffers: ProcBuffers,
proc_info: &ProcInfo,
events: &mut ProcEvents,
_logger: &mut RealtimeLogger,
) -> ProcessStatus {
// Synchronize `params` from the event list.
for patch in events.drain_patches::<MyParams>() {
self.params.apply(patch);
}
// ...
ProcessStatus::outputs_not_silent()
}
}If you need fine access to each patch, you can match on the patch type.
impl AudioNodeProcessor for MyProcessor {
fn process(
&mut self,
buffers: ProcBuffers,
proc_info: &ProcInfo,
events: &mut ProcEvents,
_logger: &mut RealtimeLogger,
) -> ProcessStatus {
for mut patch in events.drain_patches::<MyParams>() {
// When you derive `Patch`, it creates an enum with variants
// for each field.
match &mut patch {
MyParamsPatch::A(a) => {
// You can mutate the patch itself if you want
// to constrain or modify values.
*a = a.clamp(0.0, 1.0);
}
MyParamsPatch::B(b) => {}
}
// And / or apply it directly.
self.params.apply(patch);
}
// ...
ProcessStatus::outputs_not_silent()
}
}§Manual implementation
Like with Diff, types like parameters should prefer the Patch derive macro.
Nonetheless, Firewheel provides a few tools to make manual implementations straightforward.
use firewheel_core::{diff::{Patch, PatchError}, event::ParamData};
struct MyParams {
a: f32,
b: bool,
}
// To follow the derive macro convention, create an
// enum with variants for each field.
enum MyParamsPatch {
A(f32),
B(bool),
}
impl Patch for MyParams {
type Patch = MyParamsPatch;
fn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError> {
match path {
[0] => {
// Types that exist in `ParamData`'s variants can use
// `try_into`.
let a = data.try_into()?;
Ok(MyParamsPatch::A(a))
}
[1] => {
let b = data.try_into()?;
Ok(MyParamsPatch::B(b))
}
_ => Err(PatchError::InvalidPath)
}
}
fn apply(&mut self, patch: Self::Patch) {
match patch {
MyParamsPatch::A(a) => self.a = a,
MyParamsPatch::B(b) => self.b = b,
}
}
}Required Associated Types§
Sourcetype Patch
type Patch
A type’s patch.
This is a value that enumerates all the ways a type can be changed.
For leaf types (values that represent the smallest diffable unit) like f32,
this is just the type itself. For aggregate types like structs, this should
be an enum over each field.
struct FilterParams {
frequency: f32,
quality: f32,
}
enum FilterParamsPatch {
Frequency(f32),
Quality(f32),
}This type is converted from NodeEventType::Param in the patch
method.
Required Methods§
Sourcefn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError>
fn patch(data: &ParamData, path: &[u32]) -> Result<Self::Patch, PatchError>
Construct a patch from a parameter event.
This converts the intermediate representation in NodeEventType::Param into
a concrete value, making it easy to manipulate the event in audio processors.
#[derive(Patch, Default)]
struct FilterParams {
frequency: f32,
quality: f32,
}
let mut filter_params = FilterParams::default();
for event in event_list.drain() {
match event {
NodeEventType::Param { data, path } => {
let Ok(patch) = FilterParams::patch(&data, &path) else {
return;
};
// You can match on the patch directly
match &patch {
FilterParamsPatch::Frequency(f) => {
// Handle frequency event...
}
FilterParamsPatch::Quality(q) => {
// Handle quality event...
}
}
// And/or apply it.
filter_params.apply(patch);
}
_ => {}
}
}Sourcefn apply(&mut self, patch: Self::Patch)
fn apply(&mut self, patch: Self::Patch)
Apply a patch.
This will generally be called from within the audio thread, so real-time constraints should be respected.
Typically, you’ll call this within drain_patches.
#[derive(Patch, Default)]
struct FilterParams {
frequency: f32,
quality: f32,
}
let mut filter_params = FilterParams::default();
for patch in event_list.drain_patches::<FilterParams>() { filter_params.apply(patch); }Provided Methods§
Sourcefn patch_event(event: &NodeEventType) -> Option<Self::Patch>
fn patch_event(event: &NodeEventType) -> Option<Self::Patch>
Construct a patch from a node event.
This is a convenience wrapper around patch, discarding
errors and node events besides NodeEventType::Param.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.