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 <glib/gstdio.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 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));
89 pthread_mutex_init (&vstfx->lock, 0);
90 pthread_cond_init (&vstfx->window_status_change, 0);
91 pthread_cond_init (&vstfx->plugin_dispatcher_called, 0);
92 pthread_cond_init (&vstfx->window_created, 0);
96 vstfx->want_program = -1;
97 vstfx->want_chunk = 0;
98 vstfx->n_pending_keys = 0;
99 vstfx->has_editor = 0;
100 vstfx->program_set_without_editor = 0;
101 vstfx->linux_window = 0;
102 vstfx->linux_plugin_ui_window = 0;
103 vstfx->eventProc = 0;
104 vstfx->extra_data = 0;
105 vstfx->want_resize = 0;
110 /*This loads the plugin shared library*/
112 void* vstfx_load_vst_library(const char* path)
115 char* full_path = NULL;
121 /*Try and load the shared library pointed to by the path -
122 NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
123 you get some occasional failures to load - dlerror reports
126 if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != 0) {
130 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
131 PBD::error << string_compose (_("Could not open existing LXVST plugin: %1"), dlerror()) << endmsg;
135 /*We didn't find the library so try and get the path specified in the
136 env variable LXVST_PATH*/
138 envdup = getenv ("LXVST_PATH");
140 /*Path not specified - not much more we can do*/
145 /*Copy the path into envdup*/
147 envdup = strdup (envdup);
154 /*Try all the possibilities in the path - deliminated by : */
156 lxvst_path = strtok (envdup, ":");
158 while (lxvst_path != 0)
160 vstfx_error ("\"%s\"", lxvst_path);
161 len1 = strlen(lxvst_path);
163 if (full_path) free(full_path);
164 full_path = (char*)malloc(len1 + 1 + len2 + 1);
165 memcpy(full_path, lxvst_path, len1);
166 full_path[len1] = '/';
167 memcpy(full_path + len1 + 1, path, len2);
168 full_path[len1 + 1 + len2] = '\0';
170 /*Try and load the library*/
172 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != 0)
180 lxvst_path = strtok (0, ":");
184 if (full_path) free(full_path);
190 /*This loads up a plugin, given the path to its .so file and
191 finds its main entry point etc*/
194 vstfx_load (const char *path)
199 /*Create a new handle we can use to reference the plugin*/
201 fhandle = vstfx_handle_new();
203 /*See if we have .so appended to the path - if not we need to make sure it is added*/
205 if (strstr (path, ".so") == 0)
208 /*Append the .so to the path - Make sure the path has enough space*/
210 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
212 sprintf (buf, "%s.so", path);
214 fhandle->nameptr = strdup (path);
219 /*We already have .so appened to the filename*/
223 fhandle->nameptr = strdup (path);
226 /* get a name for the plugin based on the path: ye old VST problem where
227 we don't know anything about its name until we load and instantiate the plugin
228 which we don't want to do at this point
231 fhandle->name = strdup (PBD::basename_nosuffix (fhandle->nameptr).c_str());
233 /*call load_vstfx_library to actually load the .so into memory*/
235 if ((fhandle->dll = vstfx_load_vst_library (buf)) == 0)
237 vstfx_unload (fhandle);
244 /*Find the main entry point into the plugin*/
246 fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main");
248 if (fhandle->main_entry == 0) {
249 if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "VSTPluginMain")) != 0) {
250 PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
254 if (fhandle->main_entry == 0)
256 /*If it can't be found, unload the plugin and return a 0 handle*/
258 vstfx_unload (fhandle);
267 /*return the handle of the plugin*/
272 /*This unloads a plugin*/
275 vstfx_unload (VSTHandle* fhandle)
277 if (fhandle->plugincnt)
279 /*Still have plugin instances - can't unload the library
280 - actually dlclose keeps an instance count anyway*/
285 /*Valid plugin loaded?*/
289 dlclose(fhandle->dll);
293 if (fhandle->nameptr)
295 free (fhandle->nameptr);
296 free (fhandle->name);
299 /*Don't need the plugin handle any more*/
305 /*This instantiates a plugin*/
308 vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
310 VSTState* vstfx = vstfx_new ();
314 vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" );
319 if ((vstfx->plugin = fhandle->main_entry (amc)) == 0)
321 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
326 vstfx->handle = fhandle;
327 vstfx->plugin->user = userptr;
329 if (vstfx->plugin->magic != kEffectMagic)
331 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
336 vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
338 /*May or May not need to 'switch the plugin on' here - unlikely
339 since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
341 //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, 0, 0);
343 vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
345 vstfx->handle->plugincnt++;
351 /*Close a vstfx instance*/
353 void vstfx_close (VSTState* vstfx)
355 vstfx_destroy_editor(vstfx);
359 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, 0, 0);
361 /*Calling dispatcher with effClose will cause the plugin's destructor to
362 be called, which will also remove the editor if it exists*/
364 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
367 if (vstfx->handle->plugincnt)
368 vstfx->handle->plugincnt--;
370 /*vstfx_unload will unload the dll if the instance count allows -
371 we need to do this because some plugins keep their own instance count
372 and (JUCE) manages the plugin UI in its own thread. When the plugins
373 internal instance count reaches zero, JUCE stops the UI thread and won't
374 restart it until the next time the library is loaded. If we don't unload
375 the lib JUCE will never restart*/
378 if (vstfx->handle->plugincnt)
383 /*Valid plugin loaded - so we can unload it and 0 the pointer
384 to it. We can't free the handle here because we don't know what else
385 might need it. It should be / is freed when the plugin is deleted*/
387 if (vstfx->handle->dll)
389 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
390 vstfx->handle->dll = 0;
397 vstfx_save_state (VSTState* vstfx, char * filename)
399 FILE* f = g_fopen (filename, "wb");
403 int numParams = vstfx->plugin->numParams;
405 char productString[64];
407 char vendorString[64];
412 fprintf(f, "<plugin_state>\n");
414 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
418 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
422 printf ("No product string\n");
425 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
429 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
430 printf ("Effect name: %s\n", effectName);
434 printf ("No effect name\n");
437 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
441 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
442 printf ("Vendor string: %s\n", vendorString);
446 printf ("No vendor string\n");
450 if(vstfx->plugin->flags & 32 )
455 for(i=0; i < numParams; i++)
459 pthread_mutex_lock( &vstfx->lock );
460 val = vstfx->plugin->getParameter(vstfx->plugin, i );
461 pthread_mutex_unlock( &vstfx->lock );
462 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
465 if(vstfx->plugin->flags & 32 )
467 printf( "getting chunk...\n" );
469 bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
470 printf( "got tha chunk..\n" );
475 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
479 //char *encoded = g_base64_encode( chunk, bytelen );
480 //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
486 fprintf( f, "</plugin_state>\n" );
491 printf ("Could not open state file\n");
497 /*Set up a call to the plugins 'dispatcher' function*/
499 int vstfx_call_dispatcher (VSTState* vstfx, int opcode, int index, int val, void *ptr, float opt)
501 pthread_mutex_lock (&vstfx->lock);
503 /*Set up the opcode and parameters*/
505 vstfx->dispatcher_opcode = opcode;
506 vstfx->dispatcher_index = index;
507 vstfx->dispatcher_val = val;
508 vstfx->dispatcher_ptr = ptr;
509 vstfx->dispatcher_opt = opt;
511 /*Signal that we want the call to happen*/
513 vstfx->dispatcher_wantcall = 1;
515 /*Wait for the call to happen*/
517 pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
518 pthread_mutex_unlock (&vstfx->lock);
520 /*Return the result*/
522 return vstfx->dispatcher_retval;