use std::ffi::c_void;
use std::marker::PhantomData;
use std::mem;
use vst3_sys::base::{kInvalidArgument, kResultOk, tresult};
use vst3_sys::base::{IPluginFactory, IPluginFactory2, IPluginFactory3, IUnknown};
use vst3_sys::VST3;
use vst3_sys as vst3_com;
use super::subcategories::Vst3SubCategory;
use super::util::u16strlcpy;
use super::wrapper::Wrapper;
use crate::prelude::Vst3Plugin;
use crate::wrapper::util::strlcpy;
const VST3_SDK_VERSION: &str = "VST 3.6.14";
#[doc(hidden)]
#[VST3(implements(IPluginFactory, IPluginFactory2, IPluginFactory3))]
pub struct Factory<P: Vst3Plugin> {
_phantom: PhantomData<P>,
}
impl<P: Vst3Plugin> Factory<P> {
pub fn new() -> Box<Self> {
Self::allocate(PhantomData::default())
}
}
impl<P: Vst3Plugin> IPluginFactory for Factory<P> {
unsafe fn get_factory_info(&self, info: *mut vst3_sys::base::PFactoryInfo) -> tresult {
*info = mem::zeroed();
let info = &mut *info;
strlcpy(&mut info.vendor, P::VENDOR);
strlcpy(&mut info.url, P::URL);
strlcpy(&mut info.email, P::EMAIL);
info.flags = vst3_sys::base::FactoryFlags::kUnicode as i32;
kResultOk
}
unsafe fn count_classes(&self) -> i32 {
1
}
unsafe fn get_class_info(&self, index: i32, info: *mut vst3_sys::base::PClassInfo) -> tresult {
if index != 0 {
return kInvalidArgument;
}
*info = mem::zeroed();
let info = &mut *info;
info.cid.data = P::PLATFORM_VST3_CLASS_ID;
info.cardinality = vst3_sys::base::ClassCardinality::kManyInstances as i32;
strlcpy(&mut info.category, "Audio Module Class");
strlcpy(&mut info.name, P::NAME);
kResultOk
}
unsafe fn create_instance(
&self,
cid: *const vst3_sys::IID,
iid: *const vst3_sys::IID,
obj: *mut *mut vst3_sys::c_void,
) -> tresult {
check_null_ptr!(cid, obj);
if (*cid).data != P::PLATFORM_VST3_CLASS_ID {
return kInvalidArgument;
}
let wrapper = Wrapper::<P>::new();
let result = wrapper.query_interface(iid, obj);
if result == kResultOk {
wrapper.release();
Box::leak(wrapper);
}
result
}
}
impl<P: Vst3Plugin> IPluginFactory2 for Factory<P> {
unsafe fn get_class_info2(
&self,
index: i32,
info: *mut vst3_sys::base::PClassInfo2,
) -> tresult {
if index != 0 {
return kInvalidArgument;
}
*info = mem::zeroed();
let info = &mut *info;
info.cid.data = P::PLATFORM_VST3_CLASS_ID;
info.cardinality = vst3_sys::base::ClassCardinality::kManyInstances as i32;
strlcpy(&mut info.category, "Audio Module Class");
strlcpy(&mut info.name, P::NAME);
info.class_flags = 1 << 1; strlcpy(&mut info.subcategories, &make_subcategories_string::<P>());
strlcpy(&mut info.vendor, P::VENDOR);
strlcpy(&mut info.version, P::VERSION);
strlcpy(&mut info.sdk_version, VST3_SDK_VERSION);
kResultOk
}
}
impl<P: Vst3Plugin> IPluginFactory3 for Factory<P> {
unsafe fn get_class_info_unicode(
&self,
index: i32,
info: *mut vst3_sys::base::PClassInfoW,
) -> tresult {
if index != 0 {
return kInvalidArgument;
}
*info = mem::zeroed();
let info = &mut *info;
info.cid.data = P::PLATFORM_VST3_CLASS_ID;
info.cardinality = vst3_sys::base::ClassCardinality::kManyInstances as i32;
strlcpy(&mut info.category, "Audio Module Class");
u16strlcpy(&mut info.name, P::NAME);
info.class_flags = 1 << 1; strlcpy(&mut info.subcategories, &make_subcategories_string::<P>());
u16strlcpy(&mut info.vendor, P::VENDOR);
u16strlcpy(&mut info.version, P::VERSION);
u16strlcpy(&mut info.sdk_version, VST3_SDK_VERSION);
kResultOk
}
unsafe fn set_host_context(&self, _context: *mut c_void) -> tresult {
kResultOk
}
}
fn make_subcategories_string<P: Vst3Plugin>() -> String {
nih_debug_assert!(!P::VST3_SUBCATEGORIES.contains(&Vst3SubCategory::Custom("OnlyRT")));
let subcategory_string = P::VST3_SUBCATEGORIES
.iter()
.map(Vst3SubCategory::as_str)
.collect::<Vec<&str>>()
.join("|");
let subcategory_string = if P::HARD_REALTIME_ONLY {
format!("{subcategory_string}|OnlyRT")
} else {
subcategory_string
};
nih_debug_assert!(subcategory_string.len() <= 127);
subcategory_string
}