ardour
linux_vst_support.cc
Go to the documentation of this file.
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 <glib/gstdio.h>
33 #include <glibmm/miscutils.h>
34 #include <glibmm/fileutils.h>
35 
37 #include "pbd/basename.h"
38 #include "pbd/error.h"
39 
40 #include "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 void default_vstfx_error_callback (const char *desc)
63 {
64  PBD::error << desc << endmsg;
65 }
66 
68 
69 /* --- */
70 
71 /*Create and return a pointer to a new VSTFX handle*/
72 
73 VSTHandle *
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 VSTState *
84 {
85  VSTState* vstfx = (VSTState *) calloc (1, sizeof (VSTState));
86 
87  /*Mutexes*/
88 
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);
93 
94  /*Safe values*/
95 
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;
106 
107  return vstfx;
108 }
109 
110 /*This loads the plugin shared library*/
111 
112 void* vstfx_load_vst_library(const char* path)
113 {
114  void* dll;
115  char* full_path = NULL;
116  char* envdup;
117  char* lxvst_path;
118  size_t len1;
119  size_t len2;
120 
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
124  invalid arguments*/
125 
126  if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != 0) {
127  return dll;
128  }
129 
130  if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
131  PBD::error << string_compose (_("Could not open existing LXVST plugin: %1"), dlerror()) << endmsg;
132  return 0;
133  }
134 
135  /*We didn't find the library so try and get the path specified in the
136  env variable LXVST_PATH*/
137 
138  envdup = getenv ("LXVST_PATH");
139 
140  /*Path not specified - not much more we can do*/
141 
142  if (envdup == 0)
143  return 0;
144 
145  /*Copy the path into envdup*/
146 
147  envdup = strdup (envdup);
148 
149  if (envdup == 0)
150  return 0;
151 
152  len2 = strlen(path);
153 
154  /*Try all the possibilities in the path - deliminated by : */
155  char *saveptr;
156  lxvst_path = strtok_r (envdup, ":", &saveptr);
157 
158  while (lxvst_path != 0)
159  {
160  vstfx_error ("\"%s\"", lxvst_path);
161  len1 = strlen(lxvst_path);
162 
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';
169 
170  /*Try and load the library*/
171 
172  if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != 0)
173  {
174  /*Succeeded */
175  break;
176  }
177 
178  /*Try again*/
179 
180  lxvst_path = strtok_r (0, ":", &saveptr);
181  }
182 
183  /*Free the path*/
184  if (full_path) free(full_path);
185  free(envdup);
186 
187  return dll;
188 }
189 
190 /*This loads up a plugin, given the path to its .so file and
191  finds its main entry point etc*/
192 
193 VSTHandle *
194 vstfx_load (const char *path)
195 {
196  char* buf = 0;
197  VSTHandle* fhandle;
198 
199  /*Create a new handle we can use to reference the plugin*/
200 
201  fhandle = vstfx_handle_new();
202 
203  /*See if we have .so appended to the path - if not we need to make sure it is added*/
204 
205  if (strstr (path, ".so") == 0)
206  {
207 
208  /*Append the .so to the path - Make sure the path has enough space*/
209 
210  buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
211 
212  sprintf (buf, "%s.so", path);
213 
214  }
215  else
216  {
217  /*We already have .so appened to the filename*/
218 
219  buf = strdup(path);
220  }
221 
222  /* get a name for the plugin based on the path: ye old VST problem where
223  we don't know anything about its name until we load and instantiate the plugin
224  which we don't want to do at this point
225  */
226 
227  fhandle->name = strdup (PBD::basename_nosuffix (path).c_str());
228 
229  /*call load_vstfx_library to actually load the .so into memory*/
230 
231  if ((fhandle->dll = vstfx_load_vst_library (buf)) == 0)
232  {
233  vstfx_unload (fhandle);
234 
235  free(buf);
236 
237  return 0;
238  }
239 
240  /*Find the main entry point into the plugin*/
241 
242  fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main");
243 
244  if (fhandle->main_entry == 0) {
245  if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "VSTPluginMain")) != 0) {
246  PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
247  }
248  }
249 
250  if (fhandle->main_entry == 0)
251  {
252  /*If it can't be found, unload the plugin and return a 0 handle*/
253 
254  vstfx_unload (fhandle);
255 
256  free(buf);
257 
258  return 0;
259  }
260 
261  free(buf);
262 
263  /*return the handle of the plugin*/
264 
265  return fhandle;
266 }
267 
268 /*This unloads a plugin*/
269 
270 int
272 {
273  if (fhandle->plugincnt)
274  {
275  /*Still have plugin instances - can't unload the library
276  - actually dlclose keeps an instance count anyway*/
277 
278  return -1;
279  }
280 
281  /*Valid plugin loaded?*/
282 
283  if (fhandle->dll)
284  {
285  dlclose(fhandle->dll);
286  fhandle->dll = 0;
287  }
288 
289  if (fhandle->name)
290  {
291  free (fhandle->name);
292  }
293 
294  /*Don't need the plugin handle any more*/
295 
296  free (fhandle);
297  return 0;
298 }
299 
300 /*This instantiates a plugin*/
301 
302 VSTState *
303 vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
304 {
305  VSTState* vstfx = vstfx_new ();
306 
307  if(fhandle == 0)
308  {
309  vstfx_error( "** ERROR ** VSTFX : The handle was 0\n" );
310  free (vstfx);
311  return 0;
312  }
313 
314  if ((vstfx->plugin = fhandle->main_entry (amc)) == 0)
315  {
316  vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
317  free (vstfx);
318  return 0;
319  }
320 
321  vstfx->handle = fhandle;
322  vstfx->plugin->user = userptr;
323 
324  if (vstfx->plugin->magic != kEffectMagic)
325  {
326  vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
327  free (vstfx);
328  return 0;
329  }
330 
331  vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
332 
333  /*May or May not need to 'switch the plugin on' here - unlikely
334  since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
335 
336  //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, 0, 0);
337 
338  vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
339 
340  vstfx->handle->plugincnt++;
341  vstfx->wantIdle = 0;
342 
343  return vstfx;
344 }
345 
346 /*Close a vstfx instance*/
347 
348 void vstfx_close (VSTState* vstfx)
349 {
350  vstfx_destroy_editor(vstfx);
351 
352  if(vstfx->plugin)
353  {
354  vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, 0, 0);
355 
356  /*Calling dispatcher with effClose will cause the plugin's destructor to
357  be called, which will also remove the editor if it exists*/
358 
359  vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
360  }
361 
362  if (vstfx->handle->plugincnt)
363  vstfx->handle->plugincnt--;
364 
365  /*vstfx_unload will unload the dll if the instance count allows -
366  we need to do this because some plugins keep their own instance count
367  and (JUCE) manages the plugin UI in its own thread. When the plugins
368  internal instance count reaches zero, JUCE stops the UI thread and won't
369  restart it until the next time the library is loaded. If we don't unload
370  the lib JUCE will never restart*/
371 
372 
373  if (vstfx->handle->plugincnt)
374  {
375  return;
376  }
377 
378  /*Valid plugin loaded - so we can unload it and 0 the pointer
379  to it. We can't free the handle here because we don't know what else
380  might need it. It should be / is freed when the plugin is deleted*/
381 
382  if (vstfx->handle->dll)
383  {
384  dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
385  vstfx->handle->dll = 0;
386  }
387  free(vstfx);
388 }
389 
390 
391 bool
392 vstfx_save_state (VSTState* vstfx, char * filename)
393 {
394  FILE* f = g_fopen (filename, "wb");
395  if (f)
396  {
397  int bytelen;
398  int numParams = vstfx->plugin->numParams;
399  int i;
400  char productString[64];
401  char effectName[64];
402  char vendorString[64];
403  int success;
404 
405  /* write header */
406 
407  fprintf(f, "<plugin_state>\n");
408 
409  success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
410 
411  if(success == 1)
412  {
413  fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
414  }
415  else
416  {
417  printf ("No product string\n");
418  }
419 
420  success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
421 
422  if(success == 1)
423  {
424  fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
425  printf ("Effect name: %s\n", effectName);
426  }
427  else
428  {
429  printf ("No effect name\n");
430  }
431 
432  success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
433 
434  if( success == 1 )
435  {
436  fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
437  printf ("Vendor string: %s\n", vendorString);
438  }
439  else
440  {
441  printf ("No vendor string\n");
442  }
443 
444 
445  if(vstfx->plugin->flags & 32 )
446  {
447  numParams = 0;
448  }
449 
450  for(i=0; i < numParams; i++)
451  {
452  float val;
453 
454  pthread_mutex_lock( &vstfx->lock );
455  val = vstfx->plugin->getParameter(vstfx->plugin, i );
456  pthread_mutex_unlock( &vstfx->lock );
457  fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
458  }
459 
460  if(vstfx->plugin->flags & 32 )
461  {
462  printf( "getting chunk...\n" );
463  void * chunk;
464  bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
465  printf( "got tha chunk..\n" );
466  if( bytelen )
467  {
468  if( bytelen < 0 )
469  {
470  printf( "Chunke len < 0 !!! Not saving chunk.\n" );
471  }
472  else
473  {
474  //char *encoded = g_base64_encode( chunk, bytelen );
475  //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
476  //g_free( encoded );
477  }
478  }
479  }
480 
481  fprintf( f, "</plugin_state>\n" );
482  fclose( f );
483  }
484  else
485  {
486  printf ("Could not open state file\n");
487  return false;
488  }
489  return true;
490 }
491 
492 /*Set up a call to the plugins 'dispatcher' function*/
493 
494 int vstfx_call_dispatcher (VSTState* vstfx, int opcode, int index, int val, void *ptr, float opt)
495 {
496  pthread_mutex_lock (&vstfx->lock);
497 
498  /*Set up the opcode and parameters*/
499 
500  vstfx->dispatcher_opcode = opcode;
501  vstfx->dispatcher_index = index;
502  vstfx->dispatcher_val = val;
503  vstfx->dispatcher_ptr = ptr;
504  vstfx->dispatcher_opt = opt;
505 
506  /*Signal that we want the call to happen*/
507 
508  vstfx->dispatcher_wantcall = 1;
509 
510  /*Wait for the call to happen*/
511 
512  pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
513  pthread_mutex_unlock (&vstfx->lock);
514 
515  /*Return the result*/
516 
517  return vstfx->dispatcher_retval;
518 }
int vst_version
Definition: vst_types.h:103
void * dispatcher_ptr
Definition: vst_types.h:122
pthread_cond_t window_status_change
Definition: vst_types.h:128
VSTState * vstfx_instantiate(VSTHandle *fhandle, audioMasterCallback amc, void *userptr)
intptr_t(* audioMasterCallback)(AEffect *, int32_t, int32_t, intptr_t, void *, float)
Definition: aeffectx.h:329
int numParams
Definition: aeffectx.h:280
#define effGetProductString
Definition: aeffectx.h:108
int want_resize
Set to signal the plugin resized its UI.
Definition: vst_types.h:87
VSTHandle * vstfx_handle_new()
void vstfx_close(VSTState *vstfx)
float(* getParameter)(struct _AEffect *, int)
Definition: aeffectx.h:276
void default_vstfx_error_callback(const char *desc)
tuple f
Definition: signals.py:35
intptr_t(* dispatcher)(struct _AEffect *, int, int, intptr_t, void *, float)
Definition: aeffectx.h:270
int vstfx_unload(VSTHandle *fhandle)
LIBPBD_API Transmitter error
int plugincnt
Definition: vst_types.h:69
LIBPBD_API Transmitter warning
void(* vstfx_error_callback)(const char *desc)
#define effMainsChanged
Definition: aeffectx.h:97
int linux_plugin_ui_window
The ID of the plugin UI window created by the plugin.
Definition: vst_types.h:80
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
pthread_cond_t plugin_dispatcher_called
Definition: vst_types.h:129
int want_chunk
Definition: vst_types.h:109
int dispatcher_wantcall
Definition: vst_types.h:118
#define effClose
Definition: aeffectx.h:90
AEffect *(* main_entry_t)(audioMasterCallback)
Definition: vst_types.h:59
LIBARDOUR_API void vstfx_destroy_editor(VSTState *)
Definition: dummy_lxvst.cc:36
int program_set_without_editor
Definition: vst_types.h:106
void vstfx_error(const char *fmt,...)
int wantIdle
Definition: vst_types.h:97
int has_editor
Definition: vst_types.h:104
VSTState * vstfx_new()
#define _(Text)
Definition: i18n.h:11
int magic
Definition: aeffectx.h:268
pthread_cond_t window_created
Definition: vst_types.h:130
pthread_mutex_t lock
Definition: vst_types.h:127
int dispatcher_opcode
Definition: vst_types.h:119
main_entry_t main_entry
Definition: vst_types.h:67
void * dll
Definition: vst_types.h:63
bool vstfx_save_state(VSTState *vstfx, char *filename)
int dispatcher_val
Definition: vst_types.h:121
#define effGetVendorString
Definition: aeffectx.h:107
#define kEffectMagic
Definition: aeffectx.h:130
int dispatcher_index
Definition: vst_types.h:120
VSTHandle * vstfx_load(const char *path)
#define effGetVstVersion
Definition: aeffectx.h:115
void * vstfx_load_vst_library(const char *path)
int vstfx_call_dispatcher(VSTState *vstfx, int opcode, int index, int val, void *ptr, float opt)
VSTHandle * handle
Definition: vst_types.h:93
LIBPBD_API Glib::ustring basename_nosuffix(Glib::ustring)
int n_pending_keys
Definition: vst_types.h:110
int want_program
Definition: vst_types.h:108
AEffect * plugin
Definition: vst_types.h:76
void * extra_data
Pointer to any extra data.
Definition: vst_types.h:88
int flags
Definition: aeffectx.h:286
void(* eventProc)(void *event)
Definition: vst_types.h:91
int dispatcher_retval
Definition: vst_types.h:124
#define effOpen
Definition: aeffectx.h:89
char * name
Definition: vst_types.h:64
#define effGetEffectName
Definition: aeffectx.h:106
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void * user
Definition: aeffectx.h:297
float dispatcher_opt
Definition: vst_types.h:123
int linux_window
The plugin's parent X11 XWindow.
Definition: vst_types.h:79