1 //----------------------------------------------------------------------------- 2 // LICENSE 3 // (c) 2018, Steinberg Media Technologies GmbH, All Rights Reserved 4 // (c) 2018, Guillaume Piolat (contact@auburnsounds.com) 5 //----------------------------------------------------------------------------- 6 // 7 // This Software Development Kit is licensed under the terms of the General 8 // Public License (GPL) Version 3. 9 // 10 // This source is part of the "Auburn Sounds (Guillaume Piolat) extension to the 11 // Steinberg VST 3 Plug-in SDK". 12 // 13 // Details of that license can be found at: www.gnu.org/licenses/gpl-3.0.html 14 // 15 // Dual-licence: 16 // 17 // The "Auburn Sounds (Guillaume Piolat) extension to the Steinberg VST 3 Plug-in 18 // SDK", hereby referred to as DPLUG:VST3, is a language translation of the VST3 19 // SDK suitable for usage in Dplug. Any Licensee of a currently valid Steinberg 20 // VST 3 Plug-In SDK Licensing Agreement (version 2.2.4 or ulterior, hereby referred 21 // to as the AGREEMENT), is granted by Auburn Sounds (Guillaume Piolat) a non-exclusive, 22 // worldwide, nontransferable license during the term the AGREEMENT to use parts 23 // of DPLUG:VST3 not covered by the AGREEMENT, as if they were originally 24 // inside the Licensed Software Developer Kit mentionned in the AGREEMENT. 25 // Under this licence all conditions that apply to the Licensed Software Developer 26 // Kit also apply to DPLUG:VST3. 27 // 28 //----------------------------------------------------------------------------- 29 module dplug.vst3.vst3main; 30 31 version(VST3): 32 33 nothrow @nogc: 34 35 import core.stdc.stdio: snprintf; 36 37 import dplug.core.runtime; 38 import dplug.core.nogc; 39 40 import dplug.client.client; 41 import dplug.client.daw; 42 43 import dplug.vst3.ipluginbase; 44 import dplug.vst3.ftypes; 45 import dplug.vst3.ivstaudioprocessor; 46 import dplug.vst3.client; 47 48 template VST3EntryPoint(alias ClientClass) 49 { 50 // Those exports are optional, but could be useful in the future 51 enum entry_InitDll = `export extern(C) bool InitDll() nothrow @nogc { return true; }`; 52 enum entry_ExitDll = `export extern(C) bool ExitDll() nothrow @nogc { return true; }`; 53 54 enum entry_GetPluginFactory = 55 "export extern(C) void* GetPluginFactory() nothrow @nogc" ~ 56 "{" ~ 57 " return cast(void*)(GetPluginFactoryInternal!" ~ ClientClass.stringof ~ ");" ~ 58 "}"; 59 60 // macOS has different "shared libraries" and "bundle" 61 // For Cubase, VST3 validator and Nuendo, the VST3 binary must be a macOS "bundle". 62 // Other hosts don't seem to care. 63 // This fake a macOS bundle with special entry points. 64 enum entry_bundleEntry = `export extern(C) bool bundleEntry(void*) nothrow @nogc { return true; }`; 65 enum entry_bundleExit = `export extern(C) bool bundleExit() nothrow @nogc { return true; }`; 66 67 // Issue #433: on Linux, VST3 need entry points ModuleEntry and ModuleExit 68 version(linux) 69 { 70 enum entry_ModuleEntry = `export extern(C) bool ModuleEntry(void*) nothrow @nogc { return true; }`; 71 enum entry_ModuleExit = `export extern(C) bool ModuleExit(void*) nothrow @nogc { return true; }`; 72 } 73 else 74 { 75 enum entry_ModuleEntry = ``; 76 enum entry_ModuleExit = ``; 77 } 78 79 const char[] VST3EntryPoint = entry_InitDll ~ entry_ExitDll 80 ~ entry_GetPluginFactory 81 ~ entry_bundleEntry ~ entry_bundleExit 82 ~ entry_ModuleEntry ~ entry_ModuleExit; 83 } 84 85 IPluginFactory GetPluginFactoryInternal(ClientClass)() 86 { 87 ScopedForeignCallback!(false, true) scopedCallback; 88 scopedCallback.enter(); 89 90 if (!gPluginFactory) 91 { 92 // Create a client just for the purpose of creating the factory 93 ClientClass client = mallocNew!ClientClass(); 94 scope(exit) client.destroyFree(); 95 96 auto vendorNameZ = CString(client.vendorName); 97 98 string vendorEmail = client.getVendorSupportEmail(); 99 if (!vendorEmail) vendorEmail = "support@example.com"; 100 101 string pluginHomepage = client.pluginHomepage(); 102 if (!pluginHomepage) pluginHomepage = "https://google.com"; 103 104 auto pluginHomepageZ = CString(pluginHomepage); 105 auto vendorEmailZ = CString(vendorEmail); 106 107 PFactoryInfo factoryInfo = PFactoryInfo(vendorNameZ, 108 pluginHomepageZ, 109 vendorEmailZ, 110 PFactoryInfo.kUnicode); 111 112 auto pluginFactory = mallocNew!CPluginFactory(factoryInfo); 113 gPluginFactory = pluginFactory; 114 115 enum uint DPLUG_MAGIC = 0xB20BA92; 116 enum uint DPLUG_MAGIC2 = 0xCE0B145; 117 char[4] vid = client.getVendorUniqueID(); 118 char[4] pid = client.getPluginUniqueID(); 119 TUID classId = INLINE_UID(DPLUG_MAGIC, DPLUG_MAGIC2, *cast(uint*)(vid.ptr), *cast(uint*)(pid.ptr)); 120 121 auto pluginNameZ = CString(client.pluginName()); 122 char[64] versionString; 123 client.getPublicVersion().toVST3VersionString(versionString.ptr, 64); 124 125 string vst3Category; 126 final switch(client.pluginCategory()) with (PluginCategory) 127 { 128 case effectAnalysisAndMetering: vst3Category = PlugType.kFxAnalyzer; break; 129 case effectDelay: vst3Category = PlugType.kFxDelay; break; 130 case effectDistortion: vst3Category = PlugType.kFxDistortion; break; 131 case effectDynamics: vst3Category = PlugType.kFxDynamics; break; 132 case effectEQ: vst3Category = PlugType.kFxEQ; break; 133 case effectImaging: vst3Category = PlugType.kFxSpatial; break; 134 case effectModulation: vst3Category = PlugType.kFxModulation; break; 135 case effectPitch: vst3Category = PlugType.kFxPitchShift; break; 136 case effectReverb: vst3Category = PlugType.kFxReverb; break; 137 case effectOther: vst3Category = PlugType.kFx; break; 138 case instrumentDrums: vst3Category = PlugType.kInstrumentDrum; break; 139 case instrumentSampler: vst3Category = PlugType.kInstrumentSampler; break; 140 case instrumentSynthesizer: vst3Category = PlugType.kInstrumentSynth; break; 141 case instrumentOther: vst3Category = PlugType.kInstrumentSynth; break; 142 case invalid: assert(false); 143 } 144 145 PClassInfo2 componentClass = PClassInfo2(classId, 146 PClassInfo.kManyInstances, // cardinality 147 kVstAudioEffectClass.ptr, 148 pluginNameZ, 149 kSimpleModeSupported, 150 vst3Category.ptr, 151 vendorNameZ, 152 versionString.ptr, 153 kVstVersionString.ptr); 154 pluginFactory.registerClass(&componentClass, &(createVST3Client!ClientClass)); 155 } 156 else 157 gPluginFactory.addRef(); 158 159 return gPluginFactory; 160 } 161 162 // must return a IAudioProcessor 163 extern(C) FUnknown createVST3Client(ClientClass)(void* useless) nothrow @nogc 164 { 165 ScopedForeignCallback!(false, true) scopedCallback; 166 scopedCallback.enter(); 167 ClientClass client = mallocNew!ClientClass(); 168 VST3Client plugin = mallocNew!VST3Client(client); 169 return plugin; 170 }