Skip to main content

sim_lib_plugin_clap/
adapter.rs

1use sim_kernel::Result;
2use sim_lib_audio_dsp::Gain;
3use sim_lib_audio_graph_core::{PrepareConfig, ProcessBlock, Processor};
4use sim_lib_plugin_core::{
5    HostedPluginProcessor, PluginDescriptor, PluginInstance, PluginState, ProcessorPlugin,
6};
7
8use crate::{ClapParamMap, clap_gain_descriptor};
9
10/// Audio-graph [`Processor`] that hosts a CLAP plugin instance.
11///
12/// Wraps the shared `HostedPluginProcessor` from `sim-lib-plugin-core` and
13/// pairs it with a [`ClapParamMap`] so CLAP parameter ids can be translated to
14/// SIM parameter ids. The [`Processor`] implementation forwards every call
15/// straight to the hosted instance.
16#[derive(Clone, Debug)]
17pub struct ClapHostProcessor<I> {
18    hosted: HostedPluginProcessor<I>,
19    param_map: ClapParamMap,
20}
21
22impl<I> ClapHostProcessor<I> {
23    /// Hosts `instance` with an empty (identity) parameter map.
24    pub fn new(instance: I) -> Self {
25        Self {
26            hosted: HostedPluginProcessor::new(instance),
27            param_map: ClapParamMap::new(),
28        }
29    }
30
31    /// Returns this processor with `param_map` installed as the CLAP-to-SIM
32    /// parameter id translation table.
33    pub fn with_param_map(mut self, param_map: ClapParamMap) -> Self {
34        self.param_map = param_map;
35        self
36    }
37
38    /// Returns the CLAP-to-SIM parameter id map in effect.
39    pub fn param_map(&self) -> &ClapParamMap {
40        &self.param_map
41    }
42
43    /// Returns a reference to the hosted plugin instance.
44    pub fn instance(&self) -> &I {
45        self.hosted.instance()
46    }
47}
48
49impl<I: PluginInstance> Processor for ClapHostProcessor<I> {
50    fn prepare(&mut self, cfg: PrepareConfig) {
51        self.hosted.prepare(cfg);
52    }
53
54    fn reset(&mut self) {
55        self.hosted.reset();
56    }
57
58    fn process(&mut self, block: &mut ProcessBlock<'_>) {
59        self.hosted.process(block);
60    }
61
62    fn tail_frames(&self) -> u64 {
63        self.hosted.tail_frames()
64    }
65}
66
67impl<I: PluginInstance> PluginInstance for ClapHostProcessor<I> {
68    fn descriptor(&self) -> &PluginDescriptor {
69        self.hosted.instance().descriptor()
70    }
71
72    fn state(&self) -> PluginState {
73        self.hosted.instance().state()
74    }
75
76    fn set_state(&mut self, state: PluginState) {
77        self.hosted.instance_mut().set_state(state);
78    }
79
80    fn prepare(&mut self, cfg: PrepareConfig) {
81        self.hosted.prepare(cfg);
82    }
83
84    fn reset(&mut self) {
85        self.hosted.reset();
86    }
87
88    fn process(&mut self, block: &mut ProcessBlock<'_>) {
89        self.hosted.process(block);
90    }
91}
92
93/// A native SIM [`Processor`] presented to the host as a CLAP plugin instance.
94///
95/// Wraps the shared `ProcessorPlugin` from `sim-lib-plugin-core` together with
96/// a [`ClapParamMap`]; the `PluginInstance` implementation delegates descriptor,
97/// state, and processing to the inner plugin so a SIM processor can be exported
98/// through the CLAP surface.
99#[derive(Clone, Debug)]
100pub struct ClapExportedProcessor<P> {
101    inner: ProcessorPlugin<P>,
102    param_map: ClapParamMap,
103}
104
105impl<P> ClapExportedProcessor<P> {
106    /// Builds an exported instance from a `descriptor`, the wrapped `processor`,
107    /// and its CLAP-to-SIM `param_map`.
108    pub fn new(descriptor: PluginDescriptor, processor: P, param_map: ClapParamMap) -> Self {
109        Self {
110            inner: ProcessorPlugin::new(descriptor, processor),
111            param_map,
112        }
113    }
114
115    /// Returns the CLAP-to-SIM parameter id map for this exported instance.
116    pub fn param_map(&self) -> &ClapParamMap {
117        &self.param_map
118    }
119}
120
121sim_lib_plugin_core::forward_plugin_instance!(ClapExportedProcessor);
122
123/// Exports any SIM [`Processor`] as a [`ClapExportedProcessor`].
124///
125/// Builds an identity [`ClapParamMap`] over the descriptor's parameter ids, so
126/// each CLAP parameter id maps to the matching SIM parameter id.
127pub fn export_processor_as_clap<P: Processor>(
128    descriptor: PluginDescriptor,
129    processor: P,
130) -> ClapExportedProcessor<P> {
131    let param_map = ClapParamMap::identity(descriptor.parameters.iter().map(|param| param.id));
132    ClapExportedProcessor::new(descriptor, processor, param_map)
133}
134
135/// Exports a `Gain` DSP node as a CLAP gain plugin at the given `gain` value.
136///
137/// Uses [`clap_gain_descriptor`] for the descriptor and fails closed if that
138/// descriptor cannot be built.
139pub fn export_gain_as_clap(gain: f32) -> Result<ClapExportedProcessor<Gain>> {
140    Ok(export_processor_as_clap(
141        clap_gain_descriptor()?,
142        Gain::new(gain),
143    ))
144}