conformal_vst_wrapper/
factory.rs1use super::edit_controller;
2use crate::{ClassCategory, enum_to_i32, enum_to_u32};
3use crate::{ClassID, Info};
4use vst3::Class;
5use vst3::ComWrapper;
6use vst3::Steinberg::IPluginFactoryTrait;
7use vst3::Steinberg::{FIDString, IPluginFactory2};
8use vst3::Steinberg::{IPluginBase, tresult};
9use vst3::Steinberg::{IPluginFactory, IPluginFactory2Trait};
10use vst3::com_scrape_types::Unknown;
11
12pub struct Factory {
13 classes: &'static [&'static dyn ClassCategory],
14 info: Info<'static>,
15}
16
17#[cfg(test)]
18#[path = "factory.tests.rs"]
19mod tests;
20
21const EC_TAG: &str = "EC";
22
23impl Factory {
24 pub fn new(classes: &'static [&'static dyn ClassCategory], info: Info<'static>) -> Factory {
25 assert!(info.vendor.len() < vst3::Steinberg::PFactoryInfo_::kNameSize as usize);
26 assert!(info.url.len() < vst3::Steinberg::PFactoryInfo_::kURLSize as usize);
27 assert!(info.email.len() < vst3::Steinberg::PFactoryInfo_::kEmailSize as usize);
28 assert!(info.version.len() < vst3::Steinberg::PClassInfo2_::kVersionSize as usize);
29
30 for class in classes {
31 assert!(
32 class.info().name.len()
33 < vst3::Steinberg::PClassInfo_::kNameSize as usize - EC_TAG.len()
34 );
35 }
36 Factory { classes, info }
37 }
38}
39
40fn to_cstr<'a, T: Iterator<Item = &'a mut i8>>(s: &str, it: T) {
41 let s = s.as_bytes();
42 for (i, c) in it.enumerate() {
43 if i < s.len() {
44 *c = s[i] as i8;
45 } else {
46 *c = 0;
47 }
48 }
49}
50
51unsafe fn compare_fid(a: FIDString, b: ClassID) -> bool {
52 unsafe {
53 for i in 0..16 {
54 if *a.offset(i) != b[i as usize] as i8 {
55 return false;
56 }
57 }
58 true
59 }
60}
61
62unsafe fn to_iid(iid: FIDString) -> [u8; 16] {
63 unsafe {
64 let mut ret = [0; 16];
65 for i in 0isize..16 {
66 ret[i as usize] = *iid.offset(i) as u8;
67 }
68 ret
69 }
70}
71
72impl IPluginFactoryTrait for Factory {
73 unsafe fn countClasses(&self) -> vst3::Steinberg::int32 {
74 (self.classes.len() * 2).try_into().unwrap()
75 }
76
77 unsafe fn createInstance(
78 &self,
79 class_id: FIDString,
80 interface_id: FIDString,
81 obj: *mut *mut ::std::ffi::c_void,
82 ) -> tresult {
83 unsafe {
84 if obj.is_null() {
85 return vst3::Steinberg::kInvalidArgument;
86 }
87 for class in self.classes {
88 if compare_fid(class_id, class.info().edit_controller_cid) {
89 let com_ptr = ComWrapper::new(edit_controller::create(
90 class.create_parameter_model(),
91 class.info().ui_initial_size,
92 class.info().resizability,
93 class.get_kind(),
94 ))
95 .to_com_ptr::<IPluginBase>()
96 .unwrap();
97
98 if let Some(i) =
99 IPluginBase::query_interface(com_ptr.as_ptr(), &to_iid(interface_id))
100 {
101 std::ptr::write_unaligned(obj, i);
102 return vst3::Steinberg::kResultOk;
103 }
104 return vst3::Steinberg::kNoInterface;
105 }
106 if compare_fid(class_id, class.info().cid) {
107 let com_ptr = class.create_processor(class.info().edit_controller_cid);
108
109 if let Some(i) =
110 IPluginBase::query_interface(com_ptr.as_ptr(), &to_iid(interface_id))
111 {
112 std::ptr::write_unaligned(obj, i);
113 return vst3::Steinberg::kResultOk;
114 }
115 return vst3::Steinberg::kNoInterface;
116 }
117 }
118 vst3::Steinberg::kInvalidArgument
119 }
120 }
121
122 unsafe fn getClassInfo(
123 &self,
124 index: vst3::Steinberg::int32,
125 info: *mut vst3::Steinberg::PClassInfo,
126 ) -> tresult {
127 unsafe {
128 if let Some(class) = &self.classes.get(index as usize / 2) {
129 let is_ec = index % 2 == 1;
130
131 (*info).cardinality =
132 enum_to_i32(vst3::Steinberg::PClassInfo_::ClassCardinality_::kManyInstances)
133 .unwrap();
134
135 if is_ec {
136 (*info)
137 .cid
138 .iter_mut()
139 .zip(class.info().edit_controller_cid.iter())
140 .for_each(|(a, b)| *a = *b as i8);
141 to_cstr("Component Controller Class", (*info).category.iter_mut());
142 to_cstr(class.info().name, (*info).name.iter_mut());
143 to_cstr(
144 EC_TAG,
145 (*info).name.iter_mut().skip(class.info().name.len()),
146 );
147 } else {
148 (*info)
149 .cid
150 .iter_mut()
151 .zip(class.info().cid.iter())
152 .for_each(|(a, b)| *a = *b as i8);
153 to_cstr("Audio Module Class", (*info).category.iter_mut());
154 to_cstr(class.info().name, (*info).name.iter_mut());
155 }
156 vst3::Steinberg::kResultOk
157 } else {
158 vst3::Steinberg::kInvalidArgument
159 }
160 }
161 }
162
163 unsafe fn getFactoryInfo(&self, info: *mut vst3::Steinberg::PFactoryInfo) -> tresult {
164 unsafe {
165 to_cstr(self.info.vendor, (*info).vendor.iter_mut());
166 to_cstr(self.info.url, (*info).url.iter_mut());
167 to_cstr(self.info.email, (*info).email.iter_mut());
168 (*info).flags =
169 enum_to_i32(vst3::Steinberg::PFactoryInfo_::FactoryFlags_::kUnicode).unwrap();
170 vst3::Steinberg::kResultOk
171 }
172 }
173}
174
175impl IPluginFactory2Trait for Factory {
176 unsafe fn getClassInfo2(
177 &self,
178 index: vst3::Steinberg::int32,
179 info: *mut vst3::Steinberg::PClassInfo2,
180 ) -> tresult {
181 unsafe {
182 if let Some(class) = &self.classes.get(index as usize / 2) {
183 let is_ec = index % 2 == 1;
184 (*info).cardinality =
185 enum_to_i32(vst3::Steinberg::PClassInfo_::ClassCardinality_::kManyInstances)
186 .unwrap();
187
188 if is_ec {
189 (*info)
190 .cid
191 .iter_mut()
192 .zip(class.info().edit_controller_cid.iter())
193 .for_each(|(a, b)| *a = *b as i8);
194 to_cstr("Component Controller Class", (*info).category.iter_mut());
195 to_cstr(class.info().name, (*info).name.iter_mut());
196 to_cstr(
197 EC_TAG,
198 (*info).name.iter_mut().skip(class.info().name.len()),
199 );
200 } else {
201 (*info)
202 .cid
203 .iter_mut()
204 .zip(class.info().cid.iter())
205 .for_each(|(a, b)| *a = *b as i8);
206 to_cstr("Audio Module Class", (*info).category.iter_mut());
207 to_cstr(class.info().name, (*info).name.iter_mut());
208 }
209 to_cstr(class.category_str(), (*info).subCategories.iter_mut());
210 (*info).classFlags =
211 enum_to_u32(vst3::Steinberg::Vst::ComponentFlags_::kDistributable).unwrap();
212 to_cstr(
213 std::ffi::CStr::from_ptr(vst3::Steinberg::Vst::SDKVersionString)
214 .to_str()
215 .unwrap(),
216 (*info).sdkVersion.iter_mut(),
217 );
218 to_cstr(self.info.version, (*info).version.iter_mut());
219 to_cstr(self.info.vendor, (*info).vendor.iter_mut());
220 vst3::Steinberg::kResultOk
221 } else {
222 vst3::Steinberg::kInvalidArgument
223 }
224 }
225 }
226}
227
228impl Class for Factory {
229 type Interfaces = (IPluginFactory, IPluginFactory2);
230}