nice_plug/wrapper/
clap.rs1#[macro_use]
2mod util;
3
4mod context;
5mod descriptor;
6pub mod features;
7mod wrapper;
8
9use crate::wrapper::clap::features::ClapFeature;
10
11pub use self::descriptor::PluginDescriptor;
13pub use self::wrapper::Wrapper;
14pub use clap_sys::entry::clap_plugin_entry;
15pub use clap_sys::factory::plugin_factory::{CLAP_PLUGIN_FACTORY_ID, clap_plugin_factory};
16pub use clap_sys::host::clap_host;
17pub use clap_sys::plugin::{clap_plugin, clap_plugin_descriptor};
18pub use clap_sys::version::CLAP_VERSION;
19use nice_plug_core::context::remote_controls::RemoteControlsContext;
20use nice_plug_core::plugin::Plugin;
21
22#[allow(unused_variables)]
24pub trait ClapPlugin: Plugin {
25 const CLAP_ID: &'static str;
28 const CLAP_DESCRIPTION: Option<&'static str>;
30 const CLAP_MANUAL_URL: Option<&'static str>;
32 const CLAP_SUPPORT_URL: Option<&'static str>;
34 const CLAP_FEATURES: &'static [ClapFeature];
37
38 const CLAP_POLY_MODULATION_CONFIG: Option<PolyModulationConfig> = None;
40
41 fn remote_controls(&self, context: &mut impl RemoteControlsContext) {}
46}
47
48pub struct PolyModulationConfig {
50 pub max_voice_capacity: u32,
54 pub supports_overlapping_voices: bool,
58}
59
60#[macro_export]
62macro_rules! nice_export_clap {
63 ($($plugin_ty:ty),+) => {
64 #[doc(hidden)]
68 mod clap {
69 use $crate::prelude::nice_debug_assert_eq;
70 use $crate::wrapper::setup_logger;
71 use $crate::wrapper::clap::{PluginDescriptor, Wrapper};
72 use $crate::wrapper::clap::{CLAP_PLUGIN_FACTORY_ID, clap_host, clap_plugin, clap_plugin_descriptor, clap_plugin_factory};
73 use ::std::collections::HashSet;
74 use ::std::ffi::{CStr, c_void};
75 use ::std::os::raw::c_char;
76 use ::std::sync::{Arc, OnceLock};
77
78 use super::*;
81
82 const CLAP_PLUGIN_FACTORY: clap_plugin_factory = clap_plugin_factory {
83 get_plugin_count: Some(get_plugin_count),
84 get_plugin_descriptor: Some(get_plugin_descriptor),
85 create_plugin: Some(create_plugin),
86 };
87
88 const PLUGIN_COUNT: usize = [$(stringify!($plugin_ty)),+].len();
90
91 static PLUGIN_DESCRIPTORS: OnceLock<[PluginDescriptor; PLUGIN_COUNT]> = OnceLock::new();
93
94 fn plugin_descriptors() -> &'static [PluginDescriptor; PLUGIN_COUNT] {
95 PLUGIN_DESCRIPTORS.get_or_init(|| {
96 let descriptors = [$(PluginDescriptor::for_plugin::<$plugin_ty>()),+];
97
98 if cfg!(debug_assertions) {
99 let unique_plugin_ids: HashSet<_> = descriptors.iter().map(|d| d.clap_id()).collect();
100 nice_debug_assert_eq!(
101 unique_plugin_ids.len(),
102 descriptors.len(),
103 "Duplicate plugin IDs found in `nice_export_clap!()` call"
104 );
105 }
106
107 descriptors
108 })
109 }
110
111 unsafe extern "C" fn get_plugin_count(_factory: *const clap_plugin_factory) -> u32 {
112 plugin_descriptors().len() as u32
113 }
114
115 unsafe extern "C" fn get_plugin_descriptor (
116 _factory: *const clap_plugin_factory,
117 index: u32,
118 ) -> *const clap_plugin_descriptor {
119 match plugin_descriptors().get(index as usize) {
120 Some(descriptor) => descriptor.clap_plugin_descriptor(),
121 None => ::std::ptr::null()
122 }
123 }
124
125 unsafe extern "C" fn create_plugin (
126 _factory: *const clap_plugin_factory,
127 host: *const clap_host,
128 plugin_id: *const c_char,
129 ) -> *const clap_plugin {
130 if plugin_id.is_null() {
131 return ::std::ptr::null();
132 }
133 let plugin_id_cstr = unsafe { CStr::from_ptr(plugin_id) };
134
135 let descriptors = plugin_descriptors();
140 let mut descriptor_idx = 0;
141 $({
142 let descriptor = &descriptors[descriptor_idx];
143 if plugin_id_cstr == descriptor.clap_id() {
144 return unsafe {(*Arc::into_raw(Wrapper::<$plugin_ty>::new(host)))
148 .clap_plugin
149 .as_ptr()};
150 }
151
152 descriptor_idx += 1;
153 })+
154
155 ::std::ptr::null()
156 }
157
158 pub extern "C" fn init(_plugin_path: *const c_char) -> bool {
159 setup_logger();
160 true
161 }
162
163 pub extern "C" fn deinit() {}
164
165 pub extern "C" fn get_factory(factory_id: *const c_char) -> *const c_void {
166 if !factory_id.is_null() && unsafe { CStr::from_ptr(factory_id) } == CLAP_PLUGIN_FACTORY_ID {
167 &CLAP_PLUGIN_FACTORY as *const _ as *const c_void
168 } else {
169 ::std::ptr::null()
170 }
171 }
172 }
173
174 #[unsafe(no_mangle)]
176 #[used]
177 pub static clap_entry: $crate::wrapper::clap::clap_plugin_entry =
178 $crate::wrapper::clap::clap_plugin_entry {
179 clap_version: $crate::wrapper::clap::CLAP_VERSION,
180 init: Some(self::clap::init),
181 deinit: Some(self::clap::deinit),
182 get_factory: Some(self::clap::get_factory),
183 };
184 };
185}