Remove ambiguous API implementation
[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->ptr1 = 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         if (!userptr) {
207                 /* scanning.. or w/o master-callback userptr == 0, open now.
208                  *
209                  * Session::vst_callback needs a pointer to the AEffect
210                  *     ((VSTPlugin*)userptr)->_plugin = vstfx->plugin
211                  * before calling effOpen, because effOpen may call back
212                  */
213                 mac_vst->plugin->dispatcher (mac_vst->plugin, effOpen, 0, 0, 0, 0);
214                 mac_vst->vst_version = mac_vst->plugin->dispatcher (mac_vst->plugin, effGetVstVersion, 0, 0, 0, 0);
215
216                 /* configure plugin to use Cocoa View */
217                 mac_vst->plugin->dispatcher (mac_vst->plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f);
218         }
219
220         mac_vst->handle->plugincnt++;
221         mac_vst->wantIdle = 0;
222
223         return mac_vst;
224 }
225
226 /*Close a mac_vst instance*/
227
228 void mac_vst_close (VSTState* mac_vst)
229 {
230         // assert that the GUI object is destoyed
231
232         if (mac_vst->plugin)
233         {
234                 mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 0, 0, 0);
235
236                 /*Calling dispatcher with effClose will cause the plugin's destructor to
237                 be called, which will also remove the editor if it exists*/
238
239                 mac_vst->plugin->dispatcher (mac_vst->plugin, effClose, 0, 0, 0, 0);
240         }
241
242         if (mac_vst->handle->plugincnt)
243                         mac_vst->handle->plugincnt--;
244
245         /*mac_vst_unload will unload the dll if the instance count allows -
246         we need to do this because some plugins keep their own instance count
247         and (JUCE) manages the plugin UI in its own thread.  When the plugins
248         internal instance count reaches zero, JUCE stops the UI thread and won't
249         restart it until the next time the library is loaded.  If we don't unload
250         the lib JUCE will never restart*/
251
252
253         if (mac_vst->handle->plugincnt)
254         {
255                 return;
256         }
257
258         /*Valid plugin loaded - so we can unload it and 0 the pointer
259         to it.  We can't free the handle here because we don't know what else
260         might need it.  It should be / is freed when the plugin is deleted*/
261
262         if (mac_vst->handle->dll)
263         {
264                 dlclose (mac_vst->handle->dll); //dlclose keeps its own reference count
265                 mac_vst->handle->dll = 0;
266         }
267         free (mac_vst);
268 }
269
270 #if 0 // TODO wrap dispatch
271 intptr_t
272 mac_vst_dispatch (VSTState* mac_vst, int op, int idx, intptr_t val, void* ptr, float opt)
273 {
274         const ResFileRefNum old_resources = CurResFile();
275
276         if (mac_vst->handle->res_file_id) {
277                 UseResFile (mac_vst->handle->res_file_id);
278         }
279
280         mac_vst->plugin->dispatcher (mac_vst->plugin, op, idx, val, prt, opt);
281
282         const ResFileRefNum current_res = CurResFile();
283         if (current_res != old_resources) {
284                 mac_vst->handle->res_file_id = current_res;
285                 UseResFile (old_resources);
286         }
287 }
288 #endif