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}