1 /** 2 * VST host implentation. 3 * 4 * Copyright: Copyright Auburn Sounds 2015-2016 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 * Authors: Guillaume Piolat 7 */ 8 module dplug.host.vst; 9 10 import std..string; 11 12 import dplug.core.sharedlib; 13 import dplug.core.nogc; 14 import dplug.host.host; 15 import dplug.vst; 16 17 18 alias VSTPluginMain_t = extern(C) AEffect* function(HostCallbackFunction fun); 19 20 VSTPluginMain_t getVSTEntryPoint(SharedLib lib) 21 { 22 void* result = null; 23 24 void tryEntryPoint(string name) 25 { 26 if (result != null) 27 return; 28 29 if (lib.hasSymbol(name)) 30 result = lib.loadSymbol(name); 31 else 32 result = null; 33 } 34 tryEntryPoint("VSTPluginMain"); 35 tryEntryPoint("main_macho"); 36 tryEntryPoint("main"); 37 38 if (result == null) 39 throw new Exception("Did not find a VST entry point"); 40 else 41 return cast(VSTPluginMain_t)result; 42 } 43 44 private __gshared VSTPluginHost[AEffect*] reverseMapping; 45 46 final class VSTPluginHost : IPluginHost 47 { 48 this(SharedLib lib) 49 { 50 _lib = lib; 51 52 VSTPluginMain_t VSTPluginMain = getVSTEntryPoint(lib); 53 54 _aeffect = VSTPluginMain(&hostCallback); 55 56 reverseMapping[_aeffect] = this; 57 58 // various checks 59 if (_aeffect.magic != kEffectMagic) 60 throw new Exception("Wrong VST magic number"); 61 if (_aeffect.dispatcher == null) 62 throw new Exception("aeffect.dispatcher is null"); 63 if (_aeffect.setParameter == null) 64 throw new Exception("aeffect.setParameter is null"); 65 if (_aeffect.getParameter == null) 66 throw new Exception("aeffect.getParameter is null"); 67 68 _dispatcher = _aeffect.dispatcher; 69 70 // open plugin 71 _dispatcher(_aeffect, effOpen, 0, 0, null, 0.0f); 72 } 73 74 override void setParameter(int paramIndex, float normalizedValue) 75 { 76 _aeffect.setParameter(_aeffect, paramIndex, normalizedValue); 77 } 78 79 override float getParameter(int paramIndex) 80 { 81 return _aeffect.getParameter(_aeffect, paramIndex); 82 } 83 84 override void close() 85 { 86 if (!_suspended) 87 throw new Exception("Cannot close VST plugin while not suspended"); 88 89 // close plugin 90 _dispatcher(_aeffect, effClose, 0, 0, null, 0.0f); 91 92 // TODO: disabled because this breaks the second time the DLL is unloaded on Windows 93 // unload dynlib 94 // Note: probably fixed now 95 // _lib.unload(); 96 } 97 98 override string getVendorString() 99 { 100 char[65] buf; 101 _dispatcher(_aeffect, effGetVendorString, 0, 0, buf.ptr, 0.0f); 102 return fromStringz(buf.ptr).idup; 103 } 104 105 override string getEffectName() 106 { 107 char[65] buf; 108 _dispatcher(_aeffect, effGetEffectName, 0, 0, buf.ptr, 0.0f); 109 return fromStringz(buf.ptr).idup; 110 } 111 112 override string getProductString() 113 { 114 char[65] buf; 115 _dispatcher(_aeffect, effGetProductString, 0, 0, buf.ptr, 0.0f); 116 return fromStringz(buf.ptr).idup; 117 } 118 119 override void processAudioFloat(float** inputs, float** outputs, int samples) 120 { 121 if (_suspended) 122 throw new Exception("Cannot process audio with VST plugin while suspended"); 123 _aeffect.processReplacing(_aeffect, inputs, outputs, samples); 124 _processedSamples += samples; 125 } 126 127 override void beginAudioProcessing() 128 { 129 _dispatcher(_aeffect, effMainsChanged, 0, 1, null, 0.0f); 130 _suspended = false; 131 } 132 133 override void endAudioProcessing() 134 { 135 _dispatcher(_aeffect, effMainsChanged, 0, 0, null, 0.0f); 136 _suspended = true; 137 } 138 139 override void setSampleRate(float sampleRate) 140 { 141 if (!_suspended) 142 throw new Exception("Cannot set sample rate of VST plugin while not suspended"); 143 _dispatcher(_aeffect, effSetSampleRate, 0, 0, null, sampleRate); 144 } 145 146 override void setMaxBufferSize(int samples) 147 { 148 if (!_suspended) 149 throw new Exception("Cannot set block sizeof VST plugin while not suspended"); 150 _dispatcher(_aeffect, effSetBlockSize, 0, cast(VstIntPtr)samples, null, 0.0f); 151 } 152 153 override void loadPreset(int presetIndex) 154 { 155 _dispatcher(_aeffect, effSetProgram, 0, cast(ptrdiff_t)(presetIndex), null, 0.0f); 156 } 157 158 override void openUI(void* windowHandle) 159 { 160 _dispatcher(_aeffect, effEditOpen, 0, 0, windowHandle, 0.0f); 161 } 162 163 override void closeUI() 164 { 165 _dispatcher(_aeffect, effEditClose, 0, 0, null, 0.0f); 166 } 167 168 override int[2] getUISize() 169 { 170 ERect* rect; 171 _dispatcher(_aeffect, effEditGetRect, 0, 0, &rect, 0.0f); 172 int[2] size; 173 size[0] = rect.right - rect.left; 174 size[1] = rect.bottom - rect.top; 175 return size; 176 } 177 178 override ubyte[] saveState() 179 { 180 if (_aeffect.flags && effFlagsProgramChunks) 181 { 182 ubyte* pChunk = null; 183 VstIntPtr size = _dispatcher(_aeffect, effGetChunk, 0 /* want a bank */, 0, &pChunk, 0.0f); 184 185 if (size == 0 || pChunk == null) 186 throw new Exception("effGetChunk returned an empty chunk"); 187 188 return pChunk[0..size].dup; 189 } 190 else 191 throw new Exception("This VST doesn't support chunks"); 192 193 } 194 195 override void restoreState(ubyte[] chunk) 196 { 197 VstIntPtr result = _dispatcher(_aeffect, effSetChunk, 0 /* want a bank */, chunk.length, chunk.ptr, 0.0f); 198 if (result != 1) 199 throw new Exception("effSetChunk failed"); 200 } 201 202 override int getCurrentProgram() 203 { 204 return cast(int)( _dispatcher(_aeffect, effGetProgram, 0, 0, null, 0.0f) ); 205 } 206 207 private: 208 SharedLib _lib; 209 AEffect* _aeffect; 210 AEffectDispatcherProc _dispatcher; 211 long _processedSamples; 212 VstTimeInfo timeInfo; 213 bool _suspended = true; 214 } 215 216 extern(C) nothrow @nogc VstIntPtr hostCallback(AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) 217 { 218 import core.stdc.stdio; 219 220 // unimplemented stuff will printf 221 222 switch(opcode) 223 { 224 case audioMasterAutomate: printf("audioMasterAutomate\n"); return 0; 225 case audioMasterVersion: return 2400; 226 case audioMasterCurrentId: printf("audioMasterCurrentId\n"); return 0; 227 case audioMasterIdle: printf("audioMasterIdle\n"); return 0; 228 case DEPRECATED_audioMasterPinConnected: printf("DEPRECATED_audioMasterPinConnected\n"); return 0; 229 case DEPRECATED_audioMasterWantMidi: return 0; 230 case audioMasterGetTime: 231 { 232 VSTPluginHost* phost = effect in reverseMapping; 233 if (!phost) 234 return 0; 235 236 VSTPluginHost host = *phost; 237 host.timeInfo.samplePos = host._processedSamples; 238 host.timeInfo.flags = 0; 239 240 return cast(VstIntPtr)(&host.timeInfo); 241 } 242 case audioMasterProcessEvents: printf("audioMasterProcessEvents\n"); return 0; 243 case DEPRECATED_audioMasterSetTime: printf("DEPRECATED_audioMasterSetTime\n"); return 0; 244 case DEPRECATED_audioMasterTempoAt: printf("DEPRECATED_audioMasterTempoAt\n"); return 0; 245 case DEPRECATED_audioMasterGetNumAutomatableParameters: printf("DEPRECATED_audioMasterGetNumAutomatableParameters\n"); return 0; 246 case DEPRECATED_audioMasterGetParameterQuantization: printf("DEPRECATED_audioMasterGetParameterQuantization\n"); return 0; 247 case audioMasterIOChanged: printf("audioMasterIOChanged\n"); return 0; 248 case DEPRECATED_audioMasterNeedIdle: printf("DEPRECATED_audioMasterNeedIdle\n"); return 0; 249 case audioMasterSizeWindow: printf("audioMasterSizeWindow\n"); return 0; 250 case audioMasterGetSampleRate: printf("audioMasterGetSampleRate\n"); return 0; 251 case audioMasterGetBlockSize: printf("audioMasterGetBlockSize\n"); return 0; 252 case audioMasterGetInputLatency: printf("audioMasterGetInputLatency\n"); return 0; 253 case audioMasterGetOutputLatency: printf("audioMasterGetOutputLatency\n"); return 0; 254 case DEPRECATED_audioMasterGetPreviousPlug: printf("DEPRECATED_audioMasterGetPreviousPlug\n"); return 0; 255 case DEPRECATED_audioMasterGetNextPlug: printf("DEPRECATED_audioMasterGetNextPlug\n"); return 0; 256 case DEPRECATED_audioMasterWillReplaceOrAccumulate: printf("DEPRECATED_audioMasterWillReplaceOrAccumulate\n"); return 0; 257 258 case audioMasterGetCurrentProcessLevel: 259 return 2; /* kVstProcessLevelRealtime */ 260 261 case audioMasterGetAutomationState: printf("audioMasterGetAutomationState\n"); return 0; 262 case audioMasterOfflineStart: printf("audioMasterOfflineStart\n"); return 0; 263 case audioMasterOfflineRead: printf("audioMasterOfflineRead\n"); return 0; 264 case audioMasterOfflineWrite: printf("audioMasterOfflineWrite\n"); return 0; 265 case audioMasterOfflineGetCurrentPass: printf("audioMasterOfflineGetCurrentPass\n"); return 0; 266 case audioMasterOfflineGetCurrentMetaPass: printf("audioMasterOfflineGetCurrentMetaPass\n"); return 0; 267 case DEPRECATED_audioMasterSetOutputSampleRate: printf("DEPRECATED_audioMasterSetOutputSampleRate\n"); return 0; 268 case DEPRECATED_audioMasterGetOutputSpeakerArrangement: printf("DEPRECATED_audioMasterGetOutputSpeakerArrangement\n"); return 0; 269 270 case audioMasterGetVendorString: 271 case audioMasterGetProductString: 272 { 273 char* p = cast(char*)ptr; 274 if (p !is null) 275 stringNCopy(p, 64, "Dplug host"); 276 return 0; 277 } 278 279 case audioMasterGetVendorVersion: return 0x200; // 2.0 280 281 case audioMasterVendorSpecific: printf("audioMasterVendorSpecific\n"); return 0; 282 case DEPRECATED_audioMasterSetIcon: printf("DEPRECATED_audioMasterSetIcon\n"); return 0; 283 case audioMasterCanDo: printf("audioMasterCanDo\n"); return 0; 284 case audioMasterGetLanguage: printf("audioMasterGetLanguage\n"); return 0; 285 case DEPRECATED_audioMasterOpenWindow: printf("DEPRECATED_audioMasterOpenWindow\n"); return 0; 286 case DEPRECATED_audioMasterCloseWindow: printf("DEPRECATED_audioMasterCloseWindow\n"); return 0; 287 case audioMasterGetDirectory: printf("audioMasterGetDirectory\n"); return 0; 288 case audioMasterUpdateDisplay: printf("audioMasterUpdateDisplay\n"); return 0; 289 case audioMasterBeginEdit: printf("audioMasterBeginEdit\n"); return 0; 290 case audioMasterEndEdit: printf("audioMasterEndEdit\n"); return 0; 291 case audioMasterOpenFileSelector: printf("audioMasterOpenFileSelector\n"); return 0; 292 case audioMasterCloseFileSelector: printf("audioMasterCloseFileSelector\n"); return 0; 293 case DEPRECATED_audioMasterEditFile: printf("DEPRECATED_audioMasterEditFile\n"); return 0; 294 case DEPRECATED_audioMasterGetChunkFile: printf("DEPRECATED_audioMasterGetChunkFile\n"); return 0; 295 case DEPRECATED_audioMasterGetInputSpeakerArrangement: printf("DEPRECATED_audioMasterGetInputSpeakerArrangement\n"); return 0; 296 default: printf(" unknown opcode %d\n", opcode); return 0; 297 } 298 }