// vst_entry.cpp — the VST3 module class factory (Phase S1). Enumerates the one class // this module offers (the ReaSampler instrument) via the SDK's factory macros. The // Windows module exports — GetPluginFactory (here, via BEGIN_FACTORY) and // InitDll/ExitDll (from the SDK's dllmain.cpp) — are how REAPER discovers and loads a // VST3. // // VERIFIED (corrects §1a's "experienced estimate" flags on export names + macros, // against vendor/vst3sdk/public.sdk/source/main/): // * Windows exports: InitDll / ExitDll (SMTG_EXPORT_SYMBOL, in dllmain.cpp) + // GetPluginFactory (SMTG_EXPORT_SYMBOL IPluginFactory* PLUGIN_API, emitted by the // BEGIN_FACTORY macro). The plug-in must provide InitModule/DeinitModule — supplied // here by linking moduleinit.cpp (the SDK's default one-time init/term). // * Factory macros: BEGIN_FACTORY(vendor,url,email,flags) / DEF_CLASS2(...) / // END_FACTORY — exact spellings from pluginfactory.h. // * Instrument subcategory string: "Instrument|Synth|Sampler" // (PlugType::kInstrumentSynthSampler, ivstaudioprocessor.h). // * classFlags = 0 for a SingleComponentEffect (non-distributable), matching the // AGain example. #include "public.sdk/source/main/pluginfactory.h" #include "pluginterfaces/vst/ivstaudioprocessor.h" // kVstAudioEffectClass, PlugType #include "app_version.h" // vstPluginName / appVersion — the channel-derived identity #include "ext_keys.h" // kProjExtNamespace — the pairing-surface assertion target #include "reasampler_processor.h" #include "reasampler_vst.h" // channel-selected class UID (REASAMPLER_ACTIVE_UID_*) // CHANNEL PAIRING INVARIANT (S18). The instrument's PLUGIN identity forks by the ONE channel // bit (REASAMPLER_CHANNEL_IS_BETA — the class UID selected in reasampler_vst.h, the filename // + display name in app_version). Its DATA identity forks by the SAME bit, one layer down: // ext_keys.h's kProjExtNamespace() delegates to app_version::extStateNamespace(), so a beta // binary reads "reasampler_beta". Both derive from that one bit, so a beta VST can only ever // talk to the beta extension. // // The guard below pins the two forks together so a refactor cannot split them. It asserts // that the CLASS UID this factory registers (REASAMPLER_ACTIVE_UID_1, selected by the #if in // reasampler_vst.h) is the UID that matches THIS binary's channel bit. If someone edited that // #if to pick the wrong branch — registering the stable UID in a beta build, or vice versa — // the instrument's identity would diverge from the namespace ext_keys reads (a beta-named // plugin presenting the stable UID, or reading the stable banks under a beta identity). That // is exactly the silent split the invariant forbids, and it breaks the build here instead. // (The namespace itself is a runtime accessor — .c_str() on a channel-selected string — so // the couplable compile-time fact is the UID selection, not the namespace value; the // app_version_tests pin the namespace string per channel.) #if REASAMPLER_CHANNEL_IS_BETA static_assert(REASAMPLER_ACTIVE_UID_1 == REASAMPLER_PROC_UID_BETA_1 && REASAMPLER_ACTIVE_UID_2 == REASAMPLER_PROC_UID_BETA_2 && REASAMPLER_ACTIVE_UID_3 == REASAMPLER_PROC_UID_BETA_3 && REASAMPLER_ACTIVE_UID_4 == REASAMPLER_PROC_UID_BETA_4, "S18: a beta build must register the BETA class UID that pairs with the beta " "extension's ext-state namespace — the UID selection and the channel bit split"); #else static_assert(REASAMPLER_ACTIVE_UID_1 == REASAMPLER_PROC_UID_1 && REASAMPLER_ACTIVE_UID_2 == REASAMPLER_PROC_UID_2 && REASAMPLER_ACTIVE_UID_3 == REASAMPLER_PROC_UID_3 && REASAMPLER_ACTIVE_UID_4 == REASAMPLER_PROC_UID_4, "S18: a stable build must register the STABLE class UID that pairs with the " "stable ext-state namespace — the UID selection and the channel bit split"); #endif BEGIN_FACTORY(reasampler::vst::kVendorName, reasampler::vst::kVendorUrl, reasampler::vst::kVendorEmail, Steinberg::PFactoryInfo::kNoFlags) // The display name and version are channel-derived from app_version — sourced here, not // as literals. DEF_CLASS2 expands inside GetPluginFactory() and PClassInfo2's constructor // copies the char* into its own fixed buffer at that runtime call, so .c_str() on the // accessors' static-storage strings is valid (no dangling — the refs outlive the copy). // vstPluginName(): "ReaSampler 9000" / "ReaSampler 9000 beta" (live literals in // app_version.cpp). appVersion(): the configured version string / that string plus // "-beta" (the -beta render V4 already yields on beta). DEF_CLASS2(INLINE_UID(REASAMPLER_ACTIVE_UID_1, REASAMPLER_ACTIVE_UID_2, REASAMPLER_ACTIVE_UID_3, REASAMPLER_ACTIVE_UID_4), Steinberg::PClassInfo::kManyInstances, // cardinality kVstAudioEffectClass, // component category (fixed) reasampler::vstPluginName().c_str(), // plug-in display name (channel-derived) 0, // single-component => 0 Steinberg::Vst::PlugType::kInstrumentSynthSampler, // subcategory reasampler::appVersion().c_str(), // plug-in version (channel: -beta render) kVstVersionString, // VST3 SDK version (fixed) reasampler::vst::ReaSamplerProcessor::createInstance) END_FACTORY