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 let cid = &*(cid as *const [u8; 16]);
157
158 let mut plugin_idx = 0;
162 $({
163 let plugin_info = &self.plugin_infos[plugin_idx];
164 if cid == plugin_info.cid {
165 let wrapper = ComWrapper::new(Wrapper::<$plugin_ty>::new());
166 let unknown = wrapper.as_com_ref::<FUnknown>().unwrap();
167 let ptr = unknown.as_ptr();
168 return ((*(*ptr).vtbl).queryInterface)(ptr, iid as *const TUID, obj);
169 }
170
171 plugin_idx += 1;
172 })+
173
174 kInvalidArgument
175 }
176 }
177
178 impl IPluginFactory2Trait for Factory {
179 unsafe fn getClassInfo2(&self, index: int32, info: *mut PClassInfo2) -> tresult {
180 if index < 0 || index >= self.plugin_infos.len() as i32 {
181 return kInvalidArgument;
182 }
183
184 unsafe { *info = self.plugin_infos[index as usize].create_class_info_2(); }
185
186 kResultOk
187 }
188 }
189
190 impl IPluginFactory3Trait for Factory {
191 unsafe fn getClassInfoUnicode(
192 &self,
193 index: int32,
194 info: *mut PClassInfoW,
195 ) -> tresult {
196 if index < 0 || index >= self.plugin_infos.len() as i32 {
197 return kInvalidArgument;
198 }
199
200 unsafe { *info = self.plugin_infos[index as usize].create_class_info_unicode(); }
201
202 kResultOk
203 }
204
205 unsafe fn setHostContext(&self, _context: *mut FUnknown) -> tresult {
206 kResultOk
208 }
209 }
210 }
211
212 #[unsafe(no_mangle)]
214 pub extern "system" fn GetPluginFactory() -> *mut ::std::ffi::c_void {
215 use $crate::wrapper::vst3::vst3::{ComWrapper, Steinberg::IPluginFactory};
216
217 ComWrapper::new(self::vst3::Factory::new())
218 .to_com_ptr::<IPluginFactory>()
219 .unwrap()
220 .into_raw() as *mut ::std::ffi::c_void
221 }
222
223 #[allow(missing_docs)]
227 #[unsafe(no_mangle)]
228 #[cfg(all(target_family = "unix", not(target_os = "macos")))]
229 pub extern "C" fn ModuleEntry(_lib_handle: *mut ::std::ffi::c_void) -> bool {
230 $crate::wrapper::setup_logger();
231 true
232 }
233
234 #[allow(missing_docs)]
235 #[unsafe(no_mangle)]
236 #[cfg(all(target_family = "unix", not(target_os = "macos")))]
237 pub extern "C" fn ModuleExit() -> bool {
238 true
239 }
240
241 #[allow(missing_docs)]
244 #[unsafe(no_mangle)]
245 #[cfg(target_os = "macos")]
246 pub extern "C" fn bundleEntry(_lib_handle: *mut ::std::ffi::c_void) -> bool {
247 $crate::wrapper::setup_logger();
248 true
249 }
250
251 #[allow(missing_docs)]
252 #[unsafe(no_mangle)]
253 #[cfg(target_os = "macos")]
254 pub extern "C" fn bundleExit() -> bool {
255 true
256 }
257
258 #[allow(missing_docs)]
261 #[unsafe(no_mangle)]
262 #[cfg(target_os = "windows")]
263 pub extern "system" fn InitDll() -> bool {
264 $crate::wrapper::setup_logger();
265 true
266 }
267
268 #[allow(missing_docs)]
269 #[unsafe(no_mangle)]
270 #[cfg(target_os = "windows")]
271 pub extern "system" fn ExitDll() -> bool {
272 true
273 }
274 };
275}