nice_plug/wrapper/
vst3.rs1#[macro_use]
2mod util;
3
4mod context;
5mod factory;
6mod inner;
7mod note_expressions;
8mod param_units;
9pub mod subcategories;
10mod view;
11mod wrapper;
12
13pub use factory::PluginInfo;
15use nice_plug_core::plugin::Plugin;
16pub use vst3;
17pub use wrapper::Wrapper;
18
19use crate::wrapper::vst3::subcategories::Vst3SubCategory;
20
21pub trait Vst3Plugin: Plugin {
23 const VST3_CLASS_ID: [u8; 16];
28 const VST3_SUBCATEGORIES: &'static [Vst3SubCategory];
33
34 const PLATFORM_VST3_CLASS_ID: [u8; 16] = swap_vst3_uid_byte_order(Self::VST3_CLASS_ID);
37}
38
39#[cfg(not(target_os = "windows"))]
40const fn swap_vst3_uid_byte_order(uid: [u8; 16]) -> [u8; 16] {
41 uid
42}
43
44#[cfg(target_os = "windows")]
45const fn swap_vst3_uid_byte_order(mut uid: [u8; 16]) -> [u8; 16] {
46 let original_uid = uid;
48
49 uid[0] = original_uid[3];
50 uid[1] = original_uid[2];
51 uid[2] = original_uid[1];
52 uid[3] = original_uid[0];
53
54 uid[4] = original_uid[5];
55 uid[5] = original_uid[4];
56 uid[6] = original_uid[7];
57 uid[7] = original_uid[6];
58
59 uid
60}
61
62#[macro_export]
65macro_rules! nice_export_vst3 {
66 ($($plugin_ty:ty),+) => {
67 #[doc(hidden)]
71 mod vst3 {
72 use ::std::collections::HashSet;
73 use ::std::ffi::c_void;
74
75 use $crate::wrapper::vst3::{PluginInfo, Wrapper};
77 use $crate::wrapper::vst3::vst3::Steinberg::{kInvalidArgument, kResultOk, tresult, int32, FIDString, TUID};
78 use $crate::wrapper::vst3::vst3::Steinberg::{
79 PFactoryInfo_::FactoryFlags_, IPluginFactory, IPluginFactory2, IPluginFactory3, FUnknown,
80 PClassInfo, PClassInfo2, PClassInfoW, PFactoryInfo, IPluginFactoryTrait, IPluginFactory2Trait, IPluginFactory3Trait,
81 };
82 use $crate::wrapper::vst3::vst3::{Class, ComWrapper};
83
84 use super::*;
87
88 const PLUGIN_COUNT: usize = [$(stringify!($plugin_ty)),+].len();
90
91 #[doc(hidden)]
92 pub struct Factory {
93 plugin_infos: [PluginInfo; PLUGIN_COUNT],
95 }
96
97 impl Class for Factory {
98 type Interfaces = (IPluginFactory, IPluginFactory2, IPluginFactory3);
99 }
100
101 impl Factory {
102 pub fn new() -> Self {
103 let plugin_infos = [$(PluginInfo::for_plugin::<$plugin_ty>()),+];
104
105 if cfg!(debug_assertions) {
106 let unique_cids: HashSet<[u8; 16]> = plugin_infos.iter().map(|d| *d.cid).collect();
107 $crate::nice_debug_assert_eq!(
108 unique_cids.len(),
109 plugin_infos.len(),
110 "Duplicate VST3 class IDs found in `nice_export_vst3!()` call"
111 );
112 }
113
114 Factory { plugin_infos }
115 }
116 }
117
118 impl IPluginFactoryTrait for Factory {
119 unsafe fn getFactoryInfo(&self, info: *mut PFactoryInfo) -> tresult {
120 if info.is_null() {
121 return kInvalidArgument;
122 }
123
124 unsafe { *info = self.plugin_infos[0].create_factory_info(); }
126
127 kResultOk
128 }
129
130 unsafe fn countClasses(&self) -> int32 {
131 self.plugin_infos.len() as i32
132 }
133
134 unsafe fn getClassInfo(&self, index: int32, info: *mut PClassInfo) -> tresult {
135 if index < 0 || index >= self.plugin_infos.len() as i32 {
136 return kInvalidArgument;
137 }
138
139 unsafe { *info = self.plugin_infos[index as usize].create_class_info(); }
140
141 kResultOk
142 }
143
144 unsafe fn createInstance(
145 &self,
146 cid: FIDString,
147 iid: FIDString,
148 obj: *mut *mut c_void,
149 ) -> tresult {
150 if cid.is_null() || obj.is_null() {
153 return kInvalidArgument;
154 }
155
156 unsafe {
157 let cid = &*(cid as *const [u8; 16]);
158
159 let mut plugin_idx = 0;
163 $({
164 let plugin_info = &self.plugin_infos[plugin_idx];
165 if cid == plugin_info.cid {
166 let wrapper = ComWrapper::new(Wrapper::<$plugin_ty>::new());
167 let unknown = wrapper.as_com_ref::<FUnknown>().unwrap();
168 let ptr = unknown.as_ptr();
169 return ((*(*ptr).vtbl).queryInterface)(ptr, iid as *const TUID, obj);
170 }
171
172 plugin_idx += 1;
173 })+
174 }
175
176 kInvalidArgument
177 }
178 }
179
180 impl IPluginFactory2Trait for Factory {
181 unsafe fn getClassInfo2(&self, index: int32, info: *mut PClassInfo2) -> tresult {
182 if index < 0 || index >= self.plugin_infos.len() as i32 {
183 return kInvalidArgument;
184 }
185
186 unsafe { *info = self.plugin_infos[index as usize].create_class_info_2(); }
187
188 kResultOk
189 }
190 }
191
192 impl IPluginFactory3Trait for Factory {
193 unsafe fn getClassInfoUnicode(
194 &self,
195 index: int32,
196 info: *mut PClassInfoW,
197 ) -> tresult {
198 if index < 0 || index >= self.plugin_infos.len() as i32 {
199 return kInvalidArgument;
200 }
201
202 unsafe { *info = self.plugin_infos[index as usize].create_class_info_unicode(); }
203
204 kResultOk
205 }
206
207 unsafe fn setHostContext(&self, _context: *mut FUnknown) -> tresult {
208 kResultOk
210 }
211 }
212 }
213
214 #[unsafe(no_mangle)]
216 pub extern "system" fn GetPluginFactory() -> *mut ::std::ffi::c_void {
217 use $crate::wrapper::vst3::vst3::{ComWrapper, Steinberg::IPluginFactory};
218
219 ComWrapper::new(self::vst3::Factory::new())
220 .to_com_ptr::<IPluginFactory>()
221 .unwrap()
222 .into_raw() as *mut ::std::ffi::c_void
223 }
224
225 #[allow(missing_docs)]
229 #[unsafe(no_mangle)]
230 #[cfg(all(target_family = "unix", not(target_os = "macos")))]
231 pub extern "C" fn ModuleEntry(_lib_handle: *mut ::std::ffi::c_void) -> bool {
232 $crate::wrapper::setup_logger();
233 true
234 }
235
236 #[allow(missing_docs)]
237 #[unsafe(no_mangle)]
238 #[cfg(all(target_family = "unix", not(target_os = "macos")))]
239 pub extern "C" fn ModuleExit() -> bool {
240 true
241 }
242
243 #[allow(missing_docs)]
246 #[unsafe(no_mangle)]
247 #[cfg(target_os = "macos")]
248 pub extern "C" fn bundleEntry(_lib_handle: *mut ::std::ffi::c_void) -> bool {
249 $crate::wrapper::setup_logger();
250 true
251 }
252
253 #[allow(missing_docs)]
254 #[unsafe(no_mangle)]
255 #[cfg(target_os = "macos")]
256 pub extern "C" fn bundleExit() -> bool {
257 true
258 }
259
260 #[allow(missing_docs)]
263 #[unsafe(no_mangle)]
264 #[cfg(target_os = "windows")]
265 pub extern "system" fn InitDll() -> bool {
266 $crate::wrapper::setup_logger();
267 true
268 }
269
270 #[allow(missing_docs)]
271 #[unsafe(no_mangle)]
272 #[cfg(target_os = "windows")]
273 pub extern "system" fn ExitDll() -> bool {
274 true
275 }
276 };
277}