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.