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 }