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 "ardour/vst_plugin.h"
39 #include "pbd/basename.h"
40 #include "pbd/error.h"
44 /***********************************************************/
45 /* VSTFX - A set of modules for managing linux VST plugins */
46 /* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc */
47 /***********************************************************/
49 /*Simple error handler stuff for VSTFX*/
51 void vstfx_error (const char *fmt, ...)
57 vsnprintf (buffer, sizeof(buffer), fmt, ap);
58 vstfx_error_callback (buffer);
62 /*default error handler callback*/
64 void default_vstfx_error_callback (const char *desc)
66 PBD::error << desc << endmsg;
69 void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
73 /*Create and return a pointer to a new VSTFX handle*/
78 VSTHandle* vstfx = (VSTHandle *) calloc (1, sizeof (VSTHandle));
82 /*Create and return a pointer to a new vstfx instance*/
87 VSTState* vstfx = (VSTState *) calloc (1, sizeof (VSTState));
91 pthread_mutex_init (&vstfx->lock, 0);
92 pthread_cond_init (&vstfx->window_status_change, 0);
93 pthread_cond_init (&vstfx->plugin_dispatcher_called, 0);
94 pthread_cond_init (&vstfx->window_created, 0);
98 vstfx->want_program = -1;
99 vstfx->want_chunk = 0;
100 vstfx->n_pending_keys = 0;
101 vstfx->has_editor = 0;
102 vstfx->program_set_without_editor = 0;
103 vstfx->linux_window = 0;
104 vstfx->linux_plugin_ui_window = 0;
105 vstfx->eventProc = 0;
106 vstfx->extra_data = 0;
107 vstfx->want_resize = 0;
112 /*This loads the plugin shared library*/
114 void* vstfx_load_vst_library(const char* path)
123 /*Try and load the shared library pointed to by the path -
124 NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
125 you get some occasional failures to load - dlerror reports
128 if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != 0) {
132 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
133 PBD::error << string_compose (_("Could not open existing LXVST plugin: %1"), dlerror()) << endmsg;
137 /*We didn't find the library so try and get the path specified in the
138 env variable LXVST_PATH*/
140 envdup = getenv ("LXVST_PATH");
142 /*Path not specified - not much more we can do*/
147 /*Copy the path into envdup*/
149 envdup = strdup (envdup);
156 /*Try all the possibilities in the path - deliminated by : */
158 lxvst_path = strtok (envdup, ":");
160 while (lxvst_path != 0)
162 vstfx_error ("\"%s\"", lxvst_path);
163 len1 = strlen(lxvst_path);
165 full_path = (char*)malloc(len1 + 1 + len2 + 1);
166 memcpy(full_path, lxvst_path, len1);
167 full_path[len1] = '/';
168 memcpy(full_path + len1 + 1, path, len2);
169 full_path[len1 + 1 + len2] = '\0';
171 /*Try and load the library*/
173 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != 0)
181 lxvst_path = strtok (0, ":");
191 /*This loads up a plugin, given the path to its .so file and
192 finds its main entry point etc*/
195 vstfx_load (const char *path)
200 /*Create a new handle we can use to reference the plugin*/
202 fhandle = vstfx_handle_new();
204 /*See if we have .so appended to the path - if not we need to make sure it is added*/
206 if (strstr (path, ".so") == 0)
209 /*Append the .so to the path - Make sure the path has enough space*/
211 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
213 sprintf (buf, "%s.so", path);
215 fhandle->nameptr = strdup (path);
220 /*We already have .so appened to the filename*/
224 fhandle->nameptr = strdup (path);
227 /* get a name for the plugin based on the path: ye old VST problem where
228 we don't know anything about its name until we load and instantiate the plugin
229 which we don't want to do at this point
232 fhandle->name = strdup (PBD::basename_nosuffix (fhandle->nameptr).c_str());
234 /*call load_vstfx_library to actually load the .so into memory*/
236 if ((fhandle->dll = vstfx_load_vst_library (buf)) == 0)
238 vstfx_unload (fhandle);
245 /*Find the main entry point into the plugin*/
247 if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == 0)
249 /*If it can't be found, unload the plugin and return a 0 handle*/
251 vstfx_unload (fhandle);
260 /*return the handle of the plugin*/
265 /*This unloads a plugin*/
268 vstfx_unload (VSTHandle* fhandle)
270 if (fhandle->plugincnt)
272 /*Still have plugin instances - can't unload the library
273 - actually dlclose keeps an instance count anyway*/
278 /*Valid plugin loaded?*/
282 dlclose(fhandle->dll);
286 if (fhandle->nameptr)
288 free (fhandle->nameptr);
289 free (fhandle->name);
292 /*Don't need the plugin handle any more*/
299 Instantiates a VST plugin and also set _state of its plugin argument
303 vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void *ptr)
305 VSTState* vstfx = vstfx_new ();
306 ARDOUR::VSTPlugin* plugin = reinterpret_cast<ARDOUR::VSTPlugin*> (ptr);
309 vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" );
313 if ((vstfx->plugin = fhandle->main_entry (amc)) == 0) {
314 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
319 vstfx->handle = fhandle;
320 vstfx->plugin->user = plugin;
322 if (vstfx->plugin->magic != kEffectMagic) {
323 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
328 /* need to set this here because some plugins make audioMaster
329 * callbacks from within effOpen, and _state must be set for
333 plugin->set_state (vstfx);
335 vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
337 /*May or May not need to 'switch the plugin on' here - unlikely
338 since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
340 //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, 0, 0);
342 vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
344 vstfx->handle->plugincnt++;
350 /*Close a vstfx instance*/
352 void vstfx_close (VSTState* vstfx)
354 vstfx_destroy_editor(vstfx);
358 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, 0, 0);
360 /*Calling dispatcher with effClose will cause the plugin's destructor to
361 be called, which will also remove the editor if it exists*/
363 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
366 if (vstfx->handle->plugincnt)
367 vstfx->handle->plugincnt--;
369 /*vstfx_unload will unload the dll if the instance count allows -
370 we need to do this because some plugins keep their own instance count
371 and (JUCE) manages the plugin UI in its own thread. When the plugins
372 internal instance count reaches zero, JUCE stops the UI thread and won't
373 restart it until the next time the library is loaded. If we don't unload
374 the lib JUCE will never restart*/
377 if (vstfx->handle->plugincnt)
382 /*Valid plugin loaded - so we can unload it and 0 the pointer
383 to it. We can't free the handle here because we don't know what else
384 might need it. It should be / is freed when the plugin is deleted*/
386 if (vstfx->handle->dll)
388 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
389 vstfx->handle->dll = 0;
395 vstfx_save_state (VSTState* vstfx, char * filename)
397 FILE* f = g_fopen (filename, "wb");
401 int numParams = vstfx->plugin->numParams;
403 char productString[64];
405 char vendorString[64];
410 fprintf(f, "<plugin_state>\n");
412 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
416 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
420 printf ("No product string\n");
423 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
427 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
428 printf ("Effect name: %s\n", effectName);
432 printf ("No effect name\n");
435 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
439 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
440 printf ("Vendor string: %s\n", vendorString);
444 printf ("No vendor string\n");
448 if(vstfx->plugin->flags & 32 )
453 for(i=0; i < numParams; i++)
457 pthread_mutex_lock( &vstfx->lock );
458 val = vstfx->plugin->getParameter(vstfx->plugin, i );
459 pthread_mutex_unlock( &vstfx->lock );
460 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
463 if(vstfx->plugin->flags & 32 )
465 printf( "getting chunk...\n" );
467 bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
468 printf( "got tha chunk..\n" );
473 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
477 //char *encoded = g_base64_encode( chunk, bytelen );
478 //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
484 fprintf( f, "</plugin_state>\n" );
489 printf ("Could not open state file\n");
495 /*Set up a call to the plugins 'dispatcher' function*/
497 int vstfx_call_dispatcher (VSTState* vstfx, int opcode, int index, int val, void *ptr, float opt)
499 pthread_mutex_lock (&vstfx->lock);
501 /*Set up the opcode and parameters*/
503 vstfx->dispatcher_opcode = opcode;
504 vstfx->dispatcher_index = index;
505 vstfx->dispatcher_val = val;
506 vstfx->dispatcher_ptr = ptr;
507 vstfx->dispatcher_opt = opt;
509 /*Signal that we want the call to happen*/
511 vstfx->dispatcher_wantcall = 1;
513 /*Wait for the call to happen*/
515 pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
516 pthread_mutex_unlock (&vstfx->lock);
518 /*Return the result*/
520 return vstfx->dispatcher_retval;