1 /// This test shows how to use the runtime in a plug-in which 2 /// would have an otherwise disabled runtime 3 /// 4 /// ============================================================================ 5 /// 6 /// VERY IMPORTANT MESSAGE 7 /// This is a bit of an experimental feature! 8 /// 9 /// 1. You can't use it with DMD + macOS. Because DMD doesn't support 10 /// shared library initialization on macOS. 11 /// 12 /// 2. It is yet unknown how far Mac compatibility is broken by using 13 /// the runtime. It is known to work since macOS 10.12 with LDC >= 1.3 14 /// but we don't have the data for previous macOS versions. 15 /// 16 /// 3. The behaviour on POSIX in presence of multiple instances is yet unknown. 17 /// Please let us know. 18 /// 19 /// ============================================================================ 20 module main; 21 22 import core.memory; 23 import std.stdio; 24 import dplug.core, dplug.client, dplug.vst; 25 26 // This create the DLL entry point 27 mixin(DLLEntryPoint!()); 28 29 // This create the VST entry point 30 mixin(VSTEntryPoint!RuntimeTestPlugin); 31 32 final class RuntimeTestPlugin : dplug.client.Client 33 { 34 35 public: 36 nothrow: 37 @nogc: 38 39 // <needed for runtime> This is required so that the rest of the plug-in can make runtime calls. 40 ScopedRuntime _runtime; 41 this() 42 { 43 _runtime.initialize(); 44 } 45 // </needed for runtime> 46 47 // Needed for the removal of _heapObject which was added as root. 48 // So this has to be mirrored. 49 // 50 // Note: You are subjected to the classical D limitation with regards 51 // to the order of finalization of GC objects. 52 ~this() 53 { 54 runtimeSection(&cleanupObject)(_heapObject); 55 } 56 57 override PluginInfo buildPluginInfo() 58 { 59 static immutable PluginInfo pluginInfo = parsePluginInfo(import("plugin.json")); 60 return pluginInfo; 61 } 62 63 override LegalIO[] buildLegalIO() 64 { 65 auto io = makeVec!LegalIO(); 66 io.pushBack(LegalIO(2, 2)); 67 return io.releaseData(); 68 } 69 70 override void reset(double sampleRate, int maxFrames, int numInputs, int numOutputs) 71 { 72 // Note: this doesn't need to be `@nogc`. 73 // This can be a delegate, or a raw function pointer,. 74 int functionThatUseRuntime(ref HeapObject obj) nothrow 75 { 76 // Note: here you can call runtime functions and stuff, however 77 // keep in mind nothing GC-allocated must escape that function. 78 // That limits applicability 79 80 // Here you can create garbage 81 float[] invalidMemory = new float[13]; 82 assert(invalidMemory.capacity != 0); 83 84 if (obj is null) 85 { 86 // Allocate an object on the GC heap 87 obj = new HeapObject; 88 89 // Make it survive the end of the Runtime Section by being referenced elsewhere 90 // (than the stack of this thread) 91 GC.addRoot(cast(void*)obj); 92 } 93 94 return 1984; 95 } 96 97 // Note: this returns a callable Voldemort from a GC-using delegate 98 // However this delegate should not have a GC closure, so you can't refer to _members. 99 // This is a stark limitation, sorry. 100 auto runtimeUsingFunction = runtimeSection(&functionThatUseRuntime); 101 int result = runtimeUsingFunction(_heapObject); 102 assert(result == 1984); 103 104 // You can call stand-alone functions or methods 105 // but they have to be `nothrow`. 106 size_t len = runtimeSection(&myCarelessFunction)(); 107 assert(len == 4000); 108 } 109 110 override void processAudio(const(float*)[] inputs, float*[]outputs, int frames, TimeInfo info) 111 { 112 outputs[0][0..frames] = 0; 113 outputs[1][0..frames] = 0; 114 } 115 116 HeapObject _heapObject; 117 } 118 119 class HeapObject 120 { 121 this() nothrow 122 { 123 try 124 { 125 writeln("Creating a GC object"); 126 } 127 catch(Exception e) 128 { 129 } 130 } 131 132 ~this() nothrow 133 { 134 try 135 { 136 writeln("Destroying a GC object"); 137 } 138 catch(Exception e) 139 { 140 } 141 } 142 } 143 144 static void cleanupObject(ref HeapObject obj) nothrow 145 { 146 if (obj !is null) 147 { 148 GC.removeRoot(cast(void*)obj); 149 obj = null; 150 } 151 } 152 153 size_t myCarelessFunction() nothrow 154 { 155 auto A = new ubyte[4000]; 156 return A.length; 157 } 158