try VST2.4's VSTPluginMain first
[ardour.git] / libs / ardour / linux_vst_support.cc
1 /*
2     Copyright (C) 2012 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
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 <time.h>
28 #include <unistd.h>
29 #include <pthread.h>
30
31 #include <glib.h>
32 #include "pbd/gstdio_compat.h"
33 #include <glibmm/miscutils.h>
34 #include <glibmm/fileutils.h>
35
36 #include "ardour/linux_vst_support.h"
37 #include "pbd/basename.h"
38 #include "pbd/error.h"
39
40 #include "pbd/i18n.h"
41
42 /***********************************************************/
43 /* VSTFX - A set of modules for managing linux VST plugins */
44 /* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc              */
45 /***********************************************************/
46
47 /*Simple error handler stuff for VSTFX*/
48
49 void vstfx_error (const char *fmt, ...)
50 {
51         va_list ap;
52         char buffer[512];
53
54         va_start (ap, fmt);
55         vsnprintf (buffer, sizeof(buffer), fmt, ap);
56         vstfx_error_callback (buffer);
57         va_end (ap);
58 }
59
60 /*default error handler callback*/
61
62 static void default_vstfx_error_callback (const char *desc)
63 {
64         PBD::error << desc << endmsg;
65 }
66
67 void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
68
69 /* --- */
70
71 /*Create and return a pointer to a new VSTFX handle*/
72
73 static VSTHandle *
74 vstfx_handle_new ()
75 {
76         VSTHandle* vstfx = (VSTHandle *) calloc (1, sizeof (VSTHandle));
77         return vstfx;
78 }
79
80 /*Create and return a pointer to a new vstfx instance*/
81
82 static VSTState *
83 vstfx_new ()
84 {
85         VSTState* vstfx = (VSTState *) calloc (1, sizeof (VSTState));
86         vststate_init (vstfx);
87         return vstfx;
88 }
89
90 /*This loads the plugin shared library*/
91
92 static void* vstfx_load_vst_library(const char* path)
93 {
94         void* dll;
95         char* full_path = NULL;
96         char* envdup;
97         char* lxvst_path;
98         size_t len1;
99         size_t len2;
100
101         /*Try and load the shared library pointed to by the path -
102         NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
103         you get some occasional failures to load - dlerror reports
104         invalid arguments*/
105
106         if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != 0) {
107                 return dll;
108         }
109
110         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
111                 PBD::error << string_compose (_("Could not open existing LXVST plugin: %1"), dlerror()) << endmsg;
112                 return 0;
113         }
114
115         /*We didn't find the library so try and get the path specified in the
116         env variable LXVST_PATH*/
117
118         envdup = getenv ("LXVST_PATH");
119
120         /*Path not specified - not much more we can do*/
121
122         if (envdup == 0)
123                 return 0;
124
125         /*Copy the path into envdup*/
126
127         envdup = strdup (envdup);
128
129         if (envdup == 0)
130                 return 0;
131
132         len2 = strlen(path);
133
134         /*Try all the possibilities in the path - deliminated by : */
135         char *saveptr;
136         lxvst_path = strtok_r (envdup, ":", &saveptr);
137
138         while (lxvst_path != 0)
139         {
140                 vstfx_error ("\"%s\"", lxvst_path);
141                 len1 = strlen(lxvst_path);
142
143                 if (full_path) free(full_path);
144                 full_path = (char*)malloc(len1 + 1 + len2 + 1);
145                 memcpy(full_path, lxvst_path, len1);
146                 full_path[len1] = '/';
147                 memcpy(full_path + len1 + 1, path, len2);
148                 full_path[len1 + 1 + len2] = '\0';
149
150                 /*Try and load the library*/
151
152                 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != 0)
153                 {
154                         /*Succeeded */
155                         break;
156                 }
157
158                 /*Try again*/
159
160                 lxvst_path = strtok_r (0, ":", &saveptr);
161         }
162
163         /*Free the path*/
164         if (full_path) free(full_path);
165         free(envdup);
166
167         return dll;
168 }
169
170 /*This loads up a plugin, given the path to its .so file and
171  finds its main entry point etc*/
172
173 VSTHandle *
174 vstfx_load (const char *path)
175 {
176         char* buf = 0;
177         VSTHandle* fhandle;
178
179         /*Create a new handle we can use to reference the plugin*/
180
181         fhandle = vstfx_handle_new();
182
183         /*See if we have .so appended to the path - if not we need to make sure it is added*/
184
185         if (strstr (path, ".so") == 0)
186         {
187
188                 /*Append the .so to the path - Make sure the path has enough space*/
189
190                 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
191
192                 sprintf (buf, "%s.so", path);
193
194         }
195         else
196         {
197                 /*We already have .so appened to the filename*/
198
199                 buf = strdup(path);
200         }
201
202         /* get a name for the plugin based on the path: ye old VST problem where
203            we don't know anything about its name until we load and instantiate the plugin
204            which we don't want to do at this point
205         */
206
207         fhandle->name = strdup (PBD::basename_nosuffix (path).c_str());
208
209         /*call load_vstfx_library to actually load the .so into memory*/
210
211         if ((fhandle->dll = vstfx_load_vst_library (buf)) == 0)
212         {
213                 vstfx_unload (fhandle);
214
215                 free(buf);
216
217                 return 0;
218         }
219
220         /*Find the main entry point into the plugin*/
221
222         fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "VSTPluginMain");
223
224         if (fhandle->main_entry == 0) {
225                 fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main");
226         }
227
228         if (fhandle->main_entry == 0)
229         {
230                 /*If it can't be found, unload the plugin and return a 0 handle*/
231
232                 vstfx_unload (fhandle);
233
234                 free(buf);
235
236                 return 0;
237         }
238
239         free(buf);
240
241         /*return the handle of the plugin*/
242
243         return fhandle;
244 }
245
246 /*This unloads a plugin*/
247
248 int
249 vstfx_unload (VSTHandle* fhandle)
250 {
251         if (fhandle->plugincnt)
252         {
253                 /*Still have plugin instances - can't unload the library
254                 - actually dlclose keeps an instance count anyway*/
255
256                 return -1;
257         }
258
259         /*Valid plugin loaded?*/
260
261         if (fhandle->dll)
262         {
263                 dlclose(fhandle->dll);
264                 fhandle->dll = 0;
265         }
266
267         if (fhandle->name)
268         {
269                 free (fhandle->name);
270         }
271
272         /*Don't need the plugin handle any more*/
273
274         free (fhandle);
275         return 0;
276 }
277
278 /*This instantiates a plugin*/
279
280 VSTState *
281 vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
282 {
283         VSTState* vstfx = vstfx_new ();
284
285         if(fhandle == 0)
286         {
287                 vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" );
288                 free (vstfx);
289                 return 0;
290         }
291
292         if ((vstfx->plugin = fhandle->main_entry (amc)) == 0)
293         {
294                 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
295                 free (vstfx);
296                 return 0;
297         }
298
299         vstfx->handle = fhandle;
300         vstfx->plugin->user = userptr;
301
302         if (vstfx->plugin->magic != kEffectMagic)
303         {
304                 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
305                 free (vstfx);
306                 return 0;
307         }
308
309         vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
310
311         /*May or May not need to 'switch the plugin on' here - unlikely
312         since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
313
314         //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, 0, 0);
315
316         vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
317
318         vstfx->handle->plugincnt++;
319         vstfx->wantIdle = 0;
320
321         return vstfx;
322 }
323
324 /*Close a vstfx instance*/
325
326 void vstfx_close (VSTState* vstfx)
327 {
328         vstfx_destroy_editor(vstfx);
329
330         if(vstfx->plugin)
331         {
332                 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, 0, 0);
333
334                 /*Calling dispatcher with effClose will cause the plugin's destructor to
335                 be called, which will also remove the editor if it exists*/
336
337                 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
338         }
339
340         if (vstfx->handle->plugincnt)
341                         vstfx->handle->plugincnt--;
342
343         /*vstfx_unload will unload the dll if the instance count allows -
344         we need to do this because some plugins keep their own instance count
345         and (JUCE) manages the plugin UI in its own thread.  When the plugins
346         internal instance count reaches zero, JUCE stops the UI thread and won't
347         restart it until the next time the library is loaded.  If we don't unload
348         the lib JUCE will never restart*/
349
350
351         if (vstfx->handle->plugincnt)
352         {
353                 return;
354         }
355
356         /*Valid plugin loaded - so we can unload it and 0 the pointer
357         to it.  We can't free the handle here because we don't know what else
358         might need it.  It should be / is freed when the plugin is deleted*/
359
360         if (vstfx->handle->dll)
361         {
362                 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
363                 vstfx->handle->dll = 0;
364         }
365         free(vstfx);
366 }