Add a missing #define to our MSVC project (portaudio_backend)
[ardour.git] / libs / ardour / mac_vst_support.cc
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2012 Paul Davis
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <pthread.h>
24 #include <signal.h>
25 #include <dlfcn.h>
26 #include <string.h>
27 #include <strings.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <pthread.h>
31
32 #include <glib.h>
33 #include "pbd/gstdio_compat.h"
34 #include <glibmm/miscutils.h>
35 #include <glibmm/fileutils.h>
36
37 #include "ardour/mac_vst_support.h"
38 #include "pbd/basename.h"
39 #include "pbd/error.h"
40
41 #include "pbd/i18n.h"
42
43 #include <Carbon/Carbon.h>
44
45 /*Simple error handler stuff for VSTFX*/
46
47 void mac_vst_error (const char *fmt, ...)
48 {
49         va_list ap;
50         char buffer[512];
51
52         va_start (ap, fmt);
53         vsnprintf (buffer, sizeof (buffer), fmt, ap);
54         mac_vst_error_callback (buffer);
55         va_end (ap);
56 }
57
58 /*default error handler callback*/
59
60 static void default_mac_vst_error_callback (const char *desc)
61 {
62         PBD::error << desc << endmsg;
63 }
64
65 void (*mac_vst_error_callback)(const char *desc) = &default_mac_vst_error_callback;
66
67 /* --- */
68
69 /*Create and return a pointer to a new VSTFX handle*/
70
71 static VSTHandle *
72 mac_vst_handle_new ()
73 {
74         VSTHandle* mac_vst = (VSTHandle *) calloc (1, sizeof (VSTHandle));
75         return mac_vst;
76 }
77
78 /*Create and return a pointer to a new mac_vst instance*/
79
80 static VSTState *
81 mac_vst_new ()
82 {
83         VSTState* mac_vst = (VSTState *) calloc (1, sizeof (VSTState));
84         vststate_init (mac_vst);
85         return mac_vst;
86 }
87
88 /*This loads up a plugin, given the path to its .vst bundle and
89  * finds its main entry point etc */
90
91 VSTHandle *
92 mac_vst_load (const char *path)
93 {
94         VSTHandle* fhandle;
95
96         /*Create a new handle we can use to reference the plugin*/
97
98         fhandle = mac_vst_handle_new ();
99
100         fhandle->dll = NULL;
101
102         CFURLRef url;
103         if (!(url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*)path, (CFIndex) strlen (path), true))) {
104                 return 0;
105         }
106
107         CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url);
108         CFRelease (url);
109
110         if (bundleRef == 0) {
111                 return 0;
112         }
113
114         if (!CFBundleLoadExecutable (bundleRef)) {
115                 CFRelease (bundleRef);
116                 return 0;
117         }
118
119         fhandle->name = strdup (path);
120         fhandle->dll = (void*) &bundleRef;
121
122         fhandle->main_entry = (main_entry_t)
123                 CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho"));
124
125         if (!fhandle->main_entry) {
126                 fhandle->main_entry = (main_entry_t)
127                         CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain"));
128         }
129
130         if (fhandle->main_entry == 0) {
131                 mac_vst_unload (fhandle);
132                 return 0;
133         }
134
135         fhandle->res_file_id = CFBundleOpenBundleResourceMap (bundleRef);
136
137         /*return the handle of the plugin*/
138         return fhandle;
139 }
140
141 /*This unloads a plugin*/
142
143 int
144 mac_vst_unload (VSTHandle* fhandle)
145 {
146         if (fhandle->plugincnt)
147         {
148                 /*Still have plugin instances - can't unload the library
149                 - actually dlclose keeps an instance count anyway*/
150
151                 return -1;
152         }
153
154         /*Valid plugin loaded?*/
155
156         if (fhandle->dll)
157         {
158                 CFBundleRef* bundleRefPtr = (CFBundleRef*) fhandle->dll;
159                 CFBundleCloseBundleResourceMap (*bundleRefPtr, (CFBundleRefNum)fhandle->res_file_id);
160                 CFRelease (*bundleRefPtr);
161                 fhandle->dll = 0;
162         }
163
164         if (fhandle->name)
165         {
166                 free (fhandle->name);
167         }
168
169         /*Don't need the plugin handle any more*/
170
171         free (fhandle);
172         return 0;
173 }
174
175 /*This instantiates a plugin*/
176
177 VSTState *
178 mac_vst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
179 {
180         VSTState* mac_vst = mac_vst_new ();
181
182         if (fhandle == 0)
183         {
184                 mac_vst_error ( "** ERROR ** VSTFX : The handle was 0\n" );
185                 free (mac_vst);
186                 return 0;
187         }
188
189         if ((mac_vst->plugin = fhandle->main_entry (amc)) == 0)
190         {
191                 mac_vst_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
192                 free (mac_vst);
193                 return 0;
194         }
195
196         mac_vst->handle = fhandle;
197         mac_vst->plugin->user = userptr;
198
199         if (mac_vst->plugin->magic != kEffectMagic)
200         {
201                 mac_vst_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
202                 free (mac_vst);
203                 return 0;
204         }
205
206         mac_vst->plugin->dispatcher (mac_vst->plugin, effOpen, 0, 0, 0, 0);
207
208         /*May or May not need to 'switch the plugin on' here - unlikely
209         since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
210
211         //mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 1, 0, 0);
212
213         /* configure plugin to use Cocoa View */
214         mac_vst->plugin->dispatcher (mac_vst->plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f);
215
216         mac_vst->vst_version = mac_vst->plugin->dispatcher (mac_vst->plugin, effGetVstVersion, 0, 0, 0, 0);
217
218         mac_vst->handle->plugincnt++;
219         mac_vst->wantIdle = 0;
220
221         return mac_vst;
222 }
223
224 /*Close a mac_vst instance*/
225
226 void mac_vst_close (VSTState* mac_vst)
227 {
228         // assert that the GUI object is destoyed
229
230         if (mac_vst->plugin)
231         {
232                 mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 0, 0, 0);
233
234                 /*Calling dispatcher with effClose will cause the plugin's destructor to
235                 be called, which will also remove the editor if it exists*/
236
237                 mac_vst->plugin->dispatcher (mac_vst->plugin, effClose, 0, 0, 0, 0);
238         }
239
240         if (mac_vst->handle->plugincnt)
241                         mac_vst->handle->plugincnt--;
242
243         /*mac_vst_unload will unload the dll if the instance count allows -
244         we need to do this because some plugins keep their own instance count
245         and (JUCE) manages the plugin UI in its own thread.  When the plugins
246         internal instance count reaches zero, JUCE stops the UI thread and won't
247         restart it until the next time the library is loaded.  If we don't unload
248         the lib JUCE will never restart*/
249
250
251         if (mac_vst->handle->plugincnt)
252         {
253                 return;
254         }
255
256         /*Valid plugin loaded - so we can unload it and 0 the pointer
257         to it.  We can't free the handle here because we don't know what else
258         might need it.  It should be / is freed when the plugin is deleted*/
259
260         if (mac_vst->handle->dll)
261         {
262                 dlclose (mac_vst->handle->dll); //dlclose keeps its own reference count
263                 mac_vst->handle->dll = 0;
264         }
265         free (mac_vst);
266 }
267
268 #if 0 // TODO wrap dispatch
269 intptr_t
270 mac_vst_dispatch (VSTState* mac_vst, int op, int idx, intptr_t val, void* ptr, float opt)
271 {
272         const ResFileRefNum old_resources = CurResFile();
273
274         if (mac_vst->handle->res_file_id) {
275                 UseResFile (mac_vst->handle->res_file_id);
276         }
277
278         mac_vst->plugin->dispatcher (mac_vst->plugin, op, idx, val, prt, opt);
279
280         const ResFileRefNum current_res = CurResFile();
281         if (current_res != old_resources) {
282                 mac_vst->handle->res_file_id = current_res;
283                 UseResFile (old_resources);
284         }
285 }
286 #endif