truce_loader/
static_shell.rs1use std::sync::Arc;
7use std::sync::atomic::{AtomicU32, Ordering};
8
9use truce_core::buffer::AudioBuffer;
10use truce_core::bus::BusLayout;
11use truce_core::editor::Editor;
12use truce_core::events::{EventBody, EventList};
13use truce_core::info::PluginInfo;
14use truce_core::plugin::PluginRuntime;
15use truce_core::process::{ProcessContext, ProcessStatus};
16use truce_params::Params;
17use truce_params::sample::Sample;
18use truce_plugin::PluginLogicCore;
19
20pub struct StaticShell<P: Params, L: PluginLogicCore<S>, S: Sample = f32> {
30 pub params: Arc<P>,
31 logic: L,
32 meters: Arc<[AtomicU32; 256]>,
33 sample_rate: f64,
34 _sample: std::marker::PhantomData<fn() -> S>,
35}
36
37unsafe impl<P: Params, L: PluginLogicCore<S>, S: Sample> Send for StaticShell<P, L, S> {}
47
48impl<P: Params + Default + 'static, L: PluginLogicCore<S> + 'static, S: Sample>
49 StaticShell<P, L, S>
50{
51 pub fn from_parts(params: Arc<P>, logic: L) -> Self {
54 Self {
55 params,
56 logic,
57 meters: Arc::new(std::array::from_fn(|_| AtomicU32::new(0))),
58 sample_rate: 44100.0,
59 _sample: std::marker::PhantomData,
60 }
61 }
62
63 pub fn logic_ref(&self) -> &L {
65 &self.logic
66 }
67
68 pub fn logic_ref_mut(&mut self) -> &mut L {
70 &mut self.logic
71 }
72}
73
74impl<P: Params + Default + 'static, L: PluginLogicCore<S> + 'static, S: Sample> PluginRuntime
75 for StaticShell<P, L, S>
76{
77 type Sample = S;
78
79 fn info() -> PluginInfo
80 where
81 Self: Sized,
82 {
83 unreachable!("StaticShell::info() should not be called statically")
84 }
85
86 fn bus_layouts() -> Vec<BusLayout>
87 where
88 Self: Sized,
89 {
90 unreachable!("StaticShell::bus_layouts() should not be called statically")
91 }
92
93 fn init(&mut self) {}
94
95 fn reset(&mut self, sample_rate: f64, max_block_size: usize) {
96 self.sample_rate = sample_rate;
97 self.params.set_sample_rate(sample_rate);
98 self.logic.reset(sample_rate, max_block_size);
99 }
100
101 fn process(
102 &mut self,
103 buffer: &mut AudioBuffer<S>,
104 events: &EventList,
105 context: &mut ProcessContext,
106 ) -> ProcessStatus {
107 for e in events.iter() {
111 if let EventBody::ParamChange { id, value } = &e.body {
112 self.params.set_plain(*id, *value);
113 }
114 }
115
116 let params = &self.params;
120 let meters = &self.meters;
121 let param_fn = |id: u32| -> f64 { params.get_plain(id).unwrap_or(0.0) };
122 let meter_fn = |id: u32, v: f32| {
123 let idx = id.wrapping_sub(truce_params::METER_ID_BASE) as usize;
126 if let Some(slot) = meters.get(idx) {
127 slot.store(v.to_bits(), Ordering::Relaxed);
128 }
129 };
130 let mut ctx = ProcessContext::new(
131 context.transport,
132 context.sample_rate,
133 buffer.num_samples(),
134 &mut *context.output_events,
135 )
136 .with_params(¶m_fn)
137 .with_meters(&meter_fn);
138
139 self.logic.process(buffer, events, &mut ctx)
140 }
141
142 fn save_state(&self) -> Vec<u8> {
143 self.logic.save_state()
144 }
145
146 fn load_state(&mut self, data: &[u8]) -> Result<(), truce_core::state::StateLoadError> {
147 let result = self.logic.load_state(data);
148 PluginLogicCore::state_changed(&mut self.logic);
153 result
154 }
155
156 fn editor(&mut self) -> Option<Box<dyn Editor>> {
157 Some(PluginLogicCore::editor(&self.logic))
158 }
159
160 fn latency(&self) -> u32 {
161 self.logic.latency()
162 }
163 fn tail(&self) -> u32 {
164 self.logic.tail()
165 }
166
167 fn get_meter(&self, meter_id: u32) -> f32 {
168 let idx = meter_id.wrapping_sub(truce_params::METER_ID_BASE) as usize;
173 if let Some(slot) = self.meters.get(idx) {
174 f32::from_bits(slot.load(Ordering::Relaxed))
175 } else {
176 0.0
177 }
178 }
179}
180
181#[macro_export]
204macro_rules! export_static {
205 (
206 params: $params:ty,
207 info: $info:expr,
208 logic: $logic:ty,
209 ) => {
210 pub struct __HotShellWrapper {
211 inner: $crate::static_shell::StaticShell<$params, $logic, Sample>,
218 }
219
220 impl $crate::__macro_deps::truce_core::plugin::PluginRuntime for __HotShellWrapper {
221 type Sample = Sample;
222
223 fn supports_in_place() -> bool
224 where
225 Self: Sized,
226 {
227 <$logic as $crate::__macro_deps::truce_plugin::PluginLogicCore<Sample>>::supports_in_place()
236 }
237
238 fn info() -> $crate::__macro_deps::truce_core::info::PluginInfo
239 where
240 Self: Sized,
241 {
242 $info
243 }
244
245 fn bus_layouts() -> Vec<$crate::__macro_deps::truce_core::bus::BusLayout>
246 where
247 Self: Sized,
248 {
249 <$logic as $crate::__macro_deps::truce_plugin::PluginLogicCore<Sample>>::bus_layouts()
250 }
251
252 fn init(&mut self) {
253 self.inner.init();
254 }
255
256 fn reset(&mut self, sample_rate: f64, max_block_size: usize) {
257 self.inner.reset(sample_rate, max_block_size);
258 }
259
260 fn process(
261 &mut self,
262 buffer: &mut $crate::__macro_deps::truce_core::buffer::AudioBuffer<Sample>,
263 events: &$crate::__macro_deps::truce_core::events::EventList,
264 context: &mut $crate::__macro_deps::truce_core::process::ProcessContext,
265 ) -> $crate::__macro_deps::truce_core::process::ProcessStatus {
266 self.inner.process(buffer, events, context)
267 }
268
269 fn save_state(&self) -> Vec<u8> {
270 self.inner.save_state()
271 }
272
273 fn load_state(
274 &mut self,
275 data: &[u8],
276 ) -> Result<(), $crate::__macro_deps::truce_core::state::StateLoadError> {
277 self.inner.load_state(data)
278 }
279
280 fn editor(
281 &mut self,
282 ) -> Option<Box<dyn $crate::__macro_deps::truce_core::editor::Editor>> {
283 self.inner.editor()
284 }
285
286 fn latency(&self) -> u32 {
287 self.inner.latency()
288 }
289 fn tail(&self) -> u32 {
290 self.inner.tail()
291 }
292 fn get_meter(&self, meter_id: u32) -> f32 {
293 self.inner.get_meter(meter_id)
294 }
295 }
296
297 impl $crate::__macro_deps::truce_core::export::PluginExport for __HotShellWrapper {
298 type Params = $params;
299
300 fn create() -> Self {
301 let params = std::sync::Arc::new(<$params>::new());
302 let logic = <$logic>::new(std::sync::Arc::clone(¶ms));
303 Self {
304 inner: $crate::static_shell::StaticShell::from_parts(params, logic),
305 }
306 }
307
308 fn params(&self) -> &$params {
309 &self.inner.params
310 }
311
312 fn params_arc(&self) -> std::sync::Arc<$params> {
313 std::sync::Arc::clone(&self.inner.params)
314 }
315 }
316 };
317}