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