Skip to main content

truce_core/
process.rs

1use crate::config::ProcessMode;
2use crate::events::{EventList, TransportInfo};
3
4/// Per-block context handed to `process()`. Construct via
5/// [`Self::new`] + the `with_*` builders. Marked `#[non_exhaustive]`
6/// so adding host-populated fields in future (e.g. `host_latency`,
7/// `bus_routing`) isn't a `SemVer` break for downstream pre-1.0 callers.
8#[non_exhaustive]
9pub struct ProcessContext<'a> {
10    pub transport: &'a TransportInfo,
11    /// How the host is driving audio this block. Tracks host toggles
12    /// that don't force a re-prepare (VST3 `kRealtime` <-> `kPrefetch`,
13    /// an LV2 freewheel port). A plugin that reallocates for offline
14    /// keys off `AudioConfig::process_mode` at `reset` instead; this
15    /// field is for "may I relax realtime discipline right now?".
16    pub process_mode: ProcessMode,
17    pub sample_rate: f64,
18    pub block_size: usize,
19    pub output_events: &'a mut EventList,
20    params_fn: Option<&'a dyn Fn(u32) -> f64>,
21    meters_fn: Option<&'a dyn Fn(u32, f32)>,
22}
23
24impl<'a> ProcessContext<'a> {
25    pub fn new(
26        transport: &'a TransportInfo,
27        sample_rate: f64,
28        block_size: usize,
29        output_events: &'a mut EventList,
30    ) -> Self {
31        Self {
32            transport,
33            process_mode: ProcessMode::Realtime,
34            sample_rate,
35            block_size,
36            output_events,
37            params_fn: None,
38            meters_fn: None,
39        }
40    }
41
42    /// Set the processing mode for this block. Defaults to
43    /// [`ProcessMode::Realtime`]; wrappers stamp the live host mode.
44    #[must_use]
45    pub fn with_process_mode(mut self, mode: ProcessMode) -> Self {
46        self.process_mode = mode;
47        self
48    }
49
50    /// Set the parameter lookup callback.
51    #[must_use]
52    pub fn with_params(mut self, f: &'a dyn Fn(u32) -> f64) -> Self {
53        self.params_fn = Some(f);
54        self
55    }
56
57    /// Set the meter reporting callback.
58    #[must_use]
59    pub fn with_meters(mut self, f: &'a dyn Fn(u32, f32)) -> Self {
60        self.meters_fn = Some(f);
61        self
62    }
63
64    /// Read a parameter's plain value by ID.
65    ///
66    /// Returns `None` when no params callback is wired up (e.g. when a
67    /// plugin runs under the bare test driver without a `with_params`
68    /// closure). Callers that always run inside a real format wrapper
69    /// can `.unwrap_or_default()`. Distinguishing "no callback" from
70    /// "value is zero" lets test harnesses notice when they forgot to
71    /// wire up params rather than masking the misconfiguration as
72    /// "host set the value to zero".
73    #[must_use]
74    pub fn param(&self, id: u32) -> Option<f64> {
75        self.params_fn.map(|f| f(id))
76    }
77
78    /// Report a meter value (0.0 to 1.0).
79    pub fn set_meter(&self, id: impl Into<u32>, value: f32) {
80        let id = id.into();
81        if let Some(f) = self.meters_fn {
82            f(id, value);
83        }
84    }
85}
86
87#[derive(Clone, Copy, Debug, PartialEq)]
88pub enum ProcessStatus {
89    /// Plugin produced meaningful output.
90    Normal,
91    /// Plugin is producing tail. Value = remaining tail samples.
92    Tail(u32),
93    /// Keep alive even if input is silent.
94    KeepAlive,
95}