use std::ffi::c_void;
use std::marker::PhantomData;
use beamer_core::Config;
use vst3::com_scrape_types::MakeHeader;
use vst3::{Class, ComWrapper, Steinberg::*};
use crate::util::{copy_cstring, copy_wstring};
pub struct Factory<C> {
config: &'static Config,
component_uid: TUID,
controller_uid: Option<TUID>,
_marker: PhantomData<C>,
}
impl<C> Factory<C> {
pub fn new(config: &'static Config) -> Self {
let parts = config.vst3_uid_parts();
let component_uid = vst3::uid(parts[0], parts[1], parts[2], parts[3]);
let controller_uid = config.vst3_controller_uid_parts().map(|p| {
vst3::uid(p[0], p[1], p[2], p[3])
});
Self {
config,
component_uid,
controller_uid,
_marker: PhantomData,
}
}
fn has_controller(&self) -> bool {
self.controller_uid.is_some()
}
}
pub trait ComponentFactory: Class {
fn create(config: &'static Config) -> Self;
}
impl<C> Class for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
type Interfaces = (IPluginFactory3,);
}
impl<C> IPluginFactoryTrait for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
unsafe fn getFactoryInfo(&self, info: *mut PFactoryInfo) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
let info = unsafe { &mut *info };
copy_cstring(self.config.vendor, &mut info.vendor);
copy_cstring(self.config.url, &mut info.url);
copy_cstring(self.config.email, &mut info.email);
info.flags = PFactoryInfo_::FactoryFlags_::kUnicode as int32;
kResultOk
}
unsafe fn countClasses(&self) -> i32 {
if self.has_controller() {
2
} else {
1
}
}
unsafe fn getClassInfo(&self, index: i32, info: *mut PClassInfo) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
match index {
0 => {
let info = unsafe { &mut *info };
info.cid = self.component_uid;
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Audio Module Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
kResultOk
}
1 if self.has_controller() => {
let info = unsafe { &mut *info };
info.cid = self.controller_uid.unwrap();
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Component Controller Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
kResultOk
}
_ => kInvalidArgument,
}
}
unsafe fn createInstance(
&self,
cid: FIDString,
iid: FIDString,
obj: *mut *mut c_void,
) -> tresult {
if cid.is_null() || iid.is_null() || obj.is_null() {
return kInvalidArgument;
}
let requested_cid = unsafe { &*(cid as *const TUID) };
if *requested_cid != self.component_uid {
if let Some(controller_uid) = self.controller_uid {
if *requested_cid != controller_uid {
return kInvalidArgument;
}
} else {
return kInvalidArgument;
}
}
let component = ComWrapper::new(C::create(self.config));
let unknown = component.as_com_ref::<FUnknown>().unwrap();
let ptr = unknown.as_ptr();
unsafe { ((*(*ptr).vtbl).queryInterface)(ptr, iid as *const TUID, obj) }
}
}
impl<C> IPluginFactory2Trait for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
unsafe fn getClassInfo2(&self, index: i32, info: *mut PClassInfo2) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
match index {
0 => {
let info = unsafe { &mut *info };
info.cid = self.component_uid;
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Audio Module Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
info.classFlags = 0;
let subcategories = self.config.vst3_subcategories();
copy_cstring(&subcategories, &mut info.subCategories);
copy_cstring(self.config.vendor, &mut info.vendor);
copy_cstring(self.config.version, &mut info.version);
copy_cstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
1 if self.has_controller() => {
let info = unsafe { &mut *info };
info.cid = self.controller_uid.unwrap();
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Component Controller Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
info.classFlags = 1; copy_cstring("", &mut info.subCategories);
copy_cstring(self.config.vendor, &mut info.vendor);
copy_cstring(self.config.version, &mut info.version);
copy_cstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
_ => kInvalidArgument,
}
}
}
impl<C> IPluginFactory3Trait for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
unsafe fn getClassInfoUnicode(&self, index: i32, info: *mut PClassInfoW) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
match index {
0 => {
let info = unsafe { &mut *info };
info.cid = self.component_uid;
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Audio Module Class", &mut info.category);
copy_wstring(self.config.name, &mut info.name);
info.classFlags = 0;
let subcategories = self.config.vst3_subcategories();
copy_cstring(&subcategories, &mut info.subCategories);
copy_wstring(self.config.vendor, &mut info.vendor);
copy_wstring(self.config.version, &mut info.version);
copy_wstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
1 if self.has_controller() => {
let info = unsafe { &mut *info };
info.cid = self.controller_uid.unwrap();
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Component Controller Class", &mut info.category);
copy_wstring(self.config.name, &mut info.name);
info.classFlags = 1; copy_cstring("", &mut info.subCategories);
copy_wstring(self.config.vendor, &mut info.vendor);
copy_wstring(self.config.version, &mut info.version);
copy_wstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
_ => kInvalidArgument,
}
}
unsafe fn setHostContext(&self, _context: *mut FUnknown) -> tresult {
kResultOk
}
}