2 Copyright (C) 2012 Paul Davis
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.
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.
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.
32 #include "pbd/gstdio_compat.h"
33 #include <glibmm/miscutils.h>
34 #include <glibmm/fileutils.h>
36 #include "ardour/linux_vst_support.h"
37 #include "pbd/basename.h"
38 #include "pbd/error.h"
42 /***********************************************************/
43 /* VSTFX - A set of modules for managing linux VST plugins */
44 /* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc */
45 /***********************************************************/
47 /*Simple error handler stuff for VSTFX*/
49 void vstfx_error (const char *fmt, ...)
55 vsnprintf (buffer, sizeof(buffer), fmt, ap);
56 vstfx_error_callback (buffer);
60 /*default error handler callback*/
62 static void default_vstfx_error_callback (const char *desc)
64 PBD::error << desc << endmsg;
67 void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
71 /*Create and return a pointer to a new VSTFX handle*/
76 VSTHandle* vstfx = (VSTHandle *) calloc (1, sizeof (VSTHandle));
80 /*Create and return a pointer to a new vstfx instance*/
85 VSTState* vstfx = (VSTState *) calloc (1, sizeof (VSTState));
86 vststate_init (vstfx);
90 /*This loads the plugin shared library*/
92 static void* vstfx_load_vst_library(const char* path)
95 char* full_path = NULL;
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
106 if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != 0) {
110 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
111 PBD::error << string_compose (_("Could not open existing LXVST plugin: %1"), dlerror()) << endmsg;
115 /*We didn't find the library so try and get the path specified in the
116 env variable LXVST_PATH*/
118 envdup = getenv ("LXVST_PATH");
120 /*Path not specified - not much more we can do*/
125 /*Copy the path into envdup*/
127 envdup = strdup (envdup);
134 /*Try all the possibilities in the path - deliminated by : */
136 lxvst_path = strtok_r (envdup, ":", &saveptr);
138 while (lxvst_path != 0)
140 vstfx_error ("\"%s\"", lxvst_path);
141 len1 = strlen(lxvst_path);
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';
150 /*Try and load the library*/
152 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != 0)
160 lxvst_path = strtok_r (0, ":", &saveptr);
164 if (full_path) free(full_path);
170 /*This loads up a plugin, given the path to its .so file and
171 finds its main entry point etc*/
174 vstfx_load (const char *path)
179 /*Create a new handle we can use to reference the plugin*/
181 fhandle = vstfx_handle_new();
183 /*See if we have .so appended to the path - if not we need to make sure it is added*/
185 if (strstr (path, ".so") == 0)
188 /*Append the .so to the path - Make sure the path has enough space*/
190 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
192 sprintf (buf, "%s.so", path);
197 /*We already have .so appened to the filename*/
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
207 fhandle->name = strdup (PBD::basename_nosuffix (path).c_str());
209 /*call load_vstfx_library to actually load the .so into memory*/
211 if ((fhandle->dll = vstfx_load_vst_library (buf)) == 0)
213 vstfx_unload (fhandle);
220 /*Find the main entry point into the plugin*/
222 fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "VSTPluginMain");
224 if (fhandle->main_entry == 0) {
225 fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main");
228 if (fhandle->main_entry == 0)
230 /*If it can't be found, unload the plugin and return a 0 handle*/
232 vstfx_unload (fhandle);
241 /*return the handle of the plugin*/
246 /*This unloads a plugin*/
249 vstfx_unload (VSTHandle* fhandle)
251 if (fhandle->plugincnt)
253 /*Still have plugin instances - can't unload the library
254 - actually dlclose keeps an instance count anyway*/
259 /*Valid plugin loaded?*/
263 dlclose(fhandle->dll);
269 free (fhandle->name);
272 /*Don't need the plugin handle any more*/
278 /*This instantiates a plugin*/
281 vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
283 VSTState* vstfx = vstfx_new ();
287 vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" );
292 if ((vstfx->plugin = fhandle->main_entry (amc)) == 0)
294 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
299 vstfx->handle = fhandle;
300 vstfx->plugin->ptr1 = userptr;
302 if (vstfx->plugin->magic != kEffectMagic)
304 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
310 /* scanning.. or w/o master-callback userptr == 0, open now.
312 * Session::vst_callback needs a pointer to the AEffect
313 * ((VSTPlugin*)userptr)->_plugin = vstfx->plugin
314 * before calling effOpen, because effOpen may call back
316 vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
317 vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
320 vstfx->handle->plugincnt++;
326 /*Close a vstfx instance*/
328 void vstfx_close (VSTState* vstfx)
330 vstfx_destroy_editor(vstfx);
334 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, 0, 0);
336 /*Calling dispatcher with effClose will cause the plugin's destructor to
337 be called, which will also remove the editor if it exists*/
339 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
342 if (vstfx->handle->plugincnt)
343 vstfx->handle->plugincnt--;
345 /*vstfx_unload will unload the dll if the instance count allows -
346 we need to do this because some plugins keep their own instance count
347 and (JUCE) manages the plugin UI in its own thread. When the plugins
348 internal instance count reaches zero, JUCE stops the UI thread and won't
349 restart it until the next time the library is loaded. If we don't unload
350 the lib JUCE will never restart*/
353 if (vstfx->handle->plugincnt)
358 /*Valid plugin loaded - so we can unload it and 0 the pointer
359 to it. We can't free the handle here because we don't know what else
360 might need it. It should be / is freed when the plugin is deleted*/
362 if (vstfx->handle->dll)
364 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
365 vstfx->handle->dll = 0;