bbx_plugin/macros.rs
1//! FFI export macro for plugin DSP implementations.
2//!
3//! This module provides the `bbx_plugin_ffi!` macro that generates
4//! all C FFI exports for a given `PluginDsp` implementation.
5
6/// Generate C FFI exports for a `PluginDsp` implementation.
7///
8/// This macro generates the following FFI functions:
9/// - `bbx_graph_create()` - Create a new DSP graph
10/// - `bbx_graph_destroy()` - Destroy a DSP graph
11/// - `bbx_graph_prepare()` - Prepare for playback
12/// - `bbx_graph_reset()` - Reset DSP state
13/// - `bbx_graph_process()` - Process audio
14///
15/// # Example
16///
17/// ```ignore
18/// use bbx_dsp::PluginDsp;
19/// use bbx_ffi::bbx_plugin_ffi;
20///
21/// pub struct PluginGraph { /* ... */ }
22/// impl PluginDsp for PluginGraph { /* ... */ }
23///
24/// // Generate all FFI exports
25/// bbx_plugin_ffi!(PluginGraph);
26/// ```
27#[macro_export]
28macro_rules! bbx_plugin_ffi {
29 ($dsp_type:ty) => {
30 // Type alias for this plugin's graph
31 type PluginGraphInner = $crate::GraphInner<$dsp_type>;
32
33 /// Create a new DSP effects chain.
34 #[unsafe(no_mangle)]
35 pub extern "C" fn bbx_graph_create() -> *mut $crate::BbxGraph {
36 let inner = Box::new(PluginGraphInner::new());
37 $crate::handle_from_graph(inner)
38 }
39
40 /// Destroy a DSP effects chain.
41 #[unsafe(no_mangle)]
42 pub extern "C" fn bbx_graph_destroy(handle: *mut $crate::BbxGraph) {
43 if !handle.is_null() {
44 unsafe {
45 drop(Box::from_raw(handle as *mut PluginGraphInner));
46 }
47 }
48 }
49
50 /// Prepare the effects chain for playback.
51 #[unsafe(no_mangle)]
52 pub unsafe extern "C" fn bbx_graph_prepare(
53 handle: *mut $crate::BbxGraph,
54 sample_rate: f64,
55 buffer_size: u32,
56 num_channels: u32,
57 ) -> $crate::BbxError {
58 if handle.is_null() {
59 return $crate::BbxError::NullPointer;
60 }
61 if buffer_size == 0 {
62 return $crate::BbxError::InvalidBufferSize;
63 }
64 if num_channels == 0 {
65 return $crate::BbxError::InvalidParameter;
66 }
67
68 unsafe {
69 let inner = $crate::graph_from_handle::<$dsp_type>(handle);
70 inner.prepare(sample_rate, buffer_size as usize, num_channels as usize);
71 }
72
73 $crate::BbxError::Ok
74 }
75
76 /// Reset the effects chain state.
77 #[unsafe(no_mangle)]
78 pub unsafe extern "C" fn bbx_graph_reset(handle: *mut $crate::BbxGraph) -> $crate::BbxError {
79 if handle.is_null() {
80 return $crate::BbxError::NullPointer;
81 }
82
83 unsafe {
84 let inner = $crate::graph_from_handle::<$dsp_type>(handle);
85 inner.reset();
86 }
87
88 $crate::BbxError::Ok
89 }
90
91 /// Process a block of audio through the effects chain.
92 #[unsafe(no_mangle)]
93 pub unsafe extern "C" fn bbx_graph_process(
94 handle: *mut $crate::BbxGraph,
95 inputs: *const *const f32,
96 outputs: *mut *mut f32,
97 num_channels: u32,
98 num_samples: u32,
99 params: *const f32,
100 num_params: u32,
101 midi_events: *const $crate::midi::MidiEvent,
102 num_midi_events: u32,
103 ) {
104 $crate::process_audio::<$dsp_type>(
105 handle,
106 inputs,
107 outputs,
108 num_channels,
109 num_samples,
110 params,
111 num_params,
112 midi_events,
113 num_midi_events,
114 );
115 }
116 };
117}