Sort session routes before trying to do the group tabs
[ardour.git] / libs / ardour / vstfx.cc
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <stdlib.h>
4 #include <libgen.h>
5 #include <pthread.h>
6 #include <signal.h>
7 #include <dlfcn.h>
8 #include <string.h>
9 #include <time.h>
10 #include <unistd.h>
11 #include <pthread.h>
12
13 #include "ardour/vstfx.h"
14 #include "pbd/error.h"
15
16 /***********************************************************/
17 /* VSTFX - A set of modules for managing linux VST plugins */
18 /* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc              */
19 /***********************************************************/
20
21 /*Simple error handler stuff for VSTFX*/
22
23 void vstfx_error (const char *fmt, ...)
24 {
25         va_list ap;
26         char buffer[512];
27
28         va_start (ap, fmt);
29         vsnprintf (buffer, sizeof(buffer), fmt, ap);
30         vstfx_error_callback (buffer);
31         va_end (ap);
32 }
33
34 /*default error handler callback*/
35
36 void default_vstfx_error_callback (const char *desc)
37 {
38         PBD::error << desc << endmsg;
39 }
40
41 void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
42
43 /* --- */
44
45 /*Create and return a pointer to a new VSTFX handle*/
46
47 VSTFXHandle* vstfx_handle_new()
48 {
49         VSTFXHandle* vstfx = (VSTFXHandle*)calloc(1, sizeof (VSTFXHandle));
50         return vstfx;
51 }
52
53 /*Create and return a pointer to a new vstfx instance*/
54
55 VSTFX* vstfx_new ()
56 {
57         VSTFX* vstfx = (VSTFX*) calloc (1, sizeof (VSTFX));
58         
59         /*Mutexes*/
60         
61         pthread_mutex_init (&vstfx->lock, NULL);
62         pthread_cond_init (&vstfx->window_status_change, NULL);
63         pthread_cond_init (&vstfx->plugin_dispatcher_called, NULL);
64         pthread_cond_init (&vstfx->window_created, NULL);
65
66         /*Safe values*/
67         
68         vstfx->want_program = -1;
69         vstfx->want_chunk = 0;
70         vstfx->current_program = -1;
71         vstfx->n_pending_keys = 0;
72         vstfx->has_editor = 0;
73         vstfx->program_set_without_editor = 0;
74         vstfx->window = 0;
75         vstfx->plugin_ui_window = 0;
76         vstfx->eventProc = NULL;
77         vstfx->extra_data = NULL;
78         vstfx->want_resize = 0;
79         
80         return vstfx;
81 }
82
83 /*This loads the plugin shared library*/
84
85 void* vstfx_load_vst_library(const char* path)
86 {
87         void* dll;
88         char* full_path;
89         char* envdup;
90         char* lxvst_path;
91         size_t len1;
92         size_t len2;
93
94         /*Try and load the shared library pointed to by the path - 
95         NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
96         you get some occasional failures to load - dlerror reports
97         invalid arguments*/
98
99         if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
100                 return dll;
101                 
102         /*We didn't find the library so try and get the path specified in the
103         env variable LXVST_PATH*/
104
105         envdup = getenv ("LXVST_PATH");
106         
107         /*Path not specified - not much more we can do*/
108         
109         if (envdup == NULL)
110                 return NULL;
111         
112         /*Copy the path into envdup*/
113                 
114         envdup = strdup (envdup);
115         
116         if (envdup == NULL)
117                 return NULL;
118                 
119         len2 = strlen(path);
120
121         /*Try all the possibilities in the path - deliminated by : */
122
123         lxvst_path = strtok (envdup, ":");
124         
125         while (lxvst_path != NULL)
126         {
127                 vstfx_error ("\"%s\"", lxvst_path);
128                 len1 = strlen(lxvst_path);
129                 
130                 full_path = (char*)malloc(len1 + 1 + len2 + 1);
131                 memcpy(full_path, lxvst_path, len1);
132                 full_path[len1] = '/';
133                 memcpy(full_path + len1 + 1, path, len2);
134                 full_path[len1 + 1 + len2] = '\0';
135
136                 /*Try and load the library*/
137
138                 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
139                 {
140                         /*Succeeded */
141                         break;
142                 }
143         
144                 /*Try again*/
145
146                 lxvst_path = strtok (NULL, ":");
147         }
148
149         /*Free the path*/
150
151         free(envdup);
152
153         return dll;
154 }
155
156 /*This loads up a plugin, given the path to its .so file and
157  finds its main entry point etc*/
158
159 VSTFXHandle* vstfx_load (const char *path)
160 {
161         char* buf = NULL;
162         VSTFXHandle* fhandle;
163         int i;
164         
165         /*Create a new handle we can use to reference the plugin*/
166
167         fhandle = vstfx_handle_new();
168         
169         /*See if we have .so appended to the path - if not we need to make sure it is added*/
170         
171         if (strstr (path, ".so") == NULL)
172         {
173
174                 /*Append the .so to the path - Make sure the path has enough space*/
175                 
176                 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
177
178                 sprintf (buf, "%s.so", path);
179                 
180                 fhandle->nameptr = strdup (path);
181
182         }
183         else
184         {
185                 /*We already have .so appened to the filename*/
186                 
187                 buf = strdup(path);
188                 
189                 fhandle->nameptr = strdup (path);
190         }
191         
192         /*Use basename to shorten the path and then strip off the .so - the old VST problem,
193         we don't know anything about its name until we load and instantiate the plugin
194         which we don't want to do at this point*/
195         
196         for(i=0; i < (int)strlen(fhandle->nameptr); i++)
197         {
198                 if(fhandle->nameptr[i] == '.')
199                         fhandle->nameptr[i] = 0;
200         }
201                         
202         
203         fhandle->name = basename (fhandle->nameptr);
204
205         /*call load_vstfx_library to actually load the .so into memory*/
206
207         if ((fhandle->dll = vstfx_load_vst_library (buf)) == NULL)
208         {
209                 vstfx_unload (fhandle);
210                 
211                 free(buf);
212                 
213                 return NULL;
214         }
215
216         /*Find the main entry point into the plugin*/
217
218         if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == NULL)
219         {
220                 /*If it can't be found, unload the plugin and return a NULL handle*/
221                 
222                 vstfx_unload (fhandle);
223                 
224                 free(buf);
225                 
226                 return NULL;
227         }
228
229         free(buf);
230
231         /*return the handle of the plugin*/
232
233         return fhandle;
234 }
235
236 /*This unloads a plugin*/
237
238 int vstfx_unload (VSTFXHandle* fhandle)
239 {
240         if (fhandle->plugincnt)
241         {
242                 /*Still have plugin instances - can't unload the library
243                 - actually dlclose keeps an instance count anyway*/
244                 
245                 return -1;
246         }
247
248         /*Valid plugin loaded?*/
249
250         if (fhandle->dll)
251         {
252                 dlclose(fhandle->dll);
253                 fhandle->dll = NULL;
254         }
255
256         if (fhandle->nameptr)
257         {
258                 free (fhandle->nameptr);
259                 fhandle->name = NULL;
260         }
261         
262         /*Don't need the plugin handle any more*/
263         
264         free (fhandle);
265         return 0;
266 }
267
268 /*This instantiates a plugin*/
269
270 VSTFX* vstfx_instantiate (VSTFXHandle* fhandle, audioMasterCallback amc, void* userptr)
271 {
272         VSTFX* vstfx = vstfx_new ();
273
274         if(fhandle == NULL)
275         {
276             vstfx_error( "** ERROR ** VSTFX : The handle was NULL\n" );
277             return NULL;
278         }
279
280         if ((vstfx->plugin = fhandle->main_entry (amc)) == NULL) 
281         {
282                 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
283                 free (vstfx);
284                 return NULL;
285         }
286         
287         vstfx->handle = fhandle;
288         vstfx->plugin->user = userptr;
289                 
290         if (vstfx->plugin->magic != kEffectMagic)
291         {
292                 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
293                 free (vstfx);
294                 return NULL;
295         }
296         
297         vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
298         
299         /*May or May not need to 'switch the plugin on' here - unlikely
300         since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
301         
302         //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, NULL, 0);
303         
304         vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
305         
306         vstfx->handle->plugincnt++;
307         vstfx->wantIdle = 0;
308         
309         return vstfx;
310 }
311
312 /*Close a vstfx instance*/
313
314 void vstfx_close (VSTFX* vstfx)
315 {
316         vstfx_destroy_editor(vstfx);
317         
318         if(vstfx->plugin)
319         {
320                 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, NULL, 0);
321                 
322                 /*Calling dispatcher with effClose will cause the plugin's destructor to
323                 be called, which will also remove the editor if it exists*/
324                 
325                 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
326         }
327
328         if (vstfx->handle->plugincnt)
329                         vstfx->handle->plugincnt--;
330                 
331         /*vstfx_unload will unload the dll if the instance count allows - 
332         we need to do this because some plugins keep their own instance count
333         and (JUCE) manages the plugin UI in its own thread.  When the plugins
334         internal instance count reaches zero, JUCE stops the UI thread and won't
335         restart it until the next time the library is loaded.  If we don't unload
336         the lib JUCE will never restart*/
337         
338         
339         if (vstfx->handle->plugincnt)
340         {
341                 return;
342         }
343         
344         /*Valid plugin loaded - so we can unload it and NULL the pointer
345         to it.  We can't free the handle here because we don't know what else
346         might need it.  It should be / is freed when the plugin is deleted*/
347
348         if (vstfx->handle->dll)
349         {
350                 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
351                 vstfx->handle->dll = NULL;
352         }
353 }
354
355
356 bool 
357 vstfx_save_state (VSTFX* vstfx, char * filename)
358 {
359         FILE* f = fopen (filename, "wb");
360         if (f)
361         {
362                 int bytelen;
363                 int numParams = vstfx->plugin->numParams;
364                 int i;
365                 char productString[64];
366                 char effectName[64];
367                 char vendorString[64];
368                 int success;
369
370                 /* write header */
371                 
372                 fprintf(f, "<plugin_state>\n");
373
374                 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
375                 
376                 if(success == 1)
377                 {
378                         fprintf (f, "  <check field=\"productString\" value=\"%s\"/>\n", productString);
379                 }
380                 else
381                 {
382                         printf ("No product string\n");
383                 }
384
385                 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
386                 
387                 if(success == 1)
388                 {
389                         fprintf (f, "  <check field=\"effectName\" value=\"%s\"/>\n", effectName);
390                         printf ("Effect name: %s\n", effectName);
391                 }
392                 else
393                 {
394                         printf ("No effect name\n");
395                 }
396
397                 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
398                 
399                 if( success == 1 )
400                 {
401                         fprintf (f, "  <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
402                         printf ("Vendor string: %s\n", vendorString);
403                 }
404                 else
405                 {
406                         printf ("No vendor string\n");
407                 }
408
409
410                 if(vstfx->plugin->flags & 32 )
411                 {
412                         numParams = 0;
413                 }
414
415                 for(i=0; i < numParams; i++)
416                 {
417                         float val;
418                         
419                         pthread_mutex_lock( &vstfx->lock );
420                         val = vstfx->plugin->getParameter(vstfx->plugin, i );
421                         pthread_mutex_unlock( &vstfx->lock );
422                         fprintf( f, "  <param index=\"%d\" value=\"%f\"/>\n", i, val );
423                 }
424
425                 if(vstfx->plugin->flags & 32 )
426                 {
427                         printf( "getting chunk...\n" );
428                         void * chunk;
429                         bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
430                         printf( "got tha chunk..\n" );
431                         if( bytelen )
432                         {
433                                 if( bytelen < 0 )
434                                 {
435                                         printf( "Chunke len < 0 !!! Not saving chunk.\n" );
436                                 }
437                                 else
438                                 {
439                                         //char *encoded = g_base64_encode( chunk, bytelen );
440                                         //fprintf( f, "  <chunk size=\"%d\">\n    %s\n  </chunk>\n", bytelen, encoded );
441                                         //g_free( encoded );
442                                 }
443                         }
444                 } 
445
446                 fprintf( f, "</plugin_state>\n" );
447                 fclose( f );
448         }
449         else
450         {
451                 printf ("Could not open state file\n");
452                 return false;
453         }
454         return true;
455 }
456
457 /*Set up a call to the plugins 'dispatcher' function*/
458
459 int vstfx_call_dispatcher (VSTFX *vstfx, int opcode, int index, int val, void *ptr, float opt) 
460 {
461         pthread_mutex_lock (&vstfx->lock);
462         
463         /*Set up the opcode and parameters*/
464         
465         vstfx->dispatcher_opcode = opcode;
466         vstfx->dispatcher_index = index;
467         vstfx->dispatcher_val = val;
468         vstfx->dispatcher_ptr = ptr;
469         vstfx->dispatcher_opt = opt;
470         
471         /*Signal that we want the call to happen*/
472         
473         vstfx->dispatcher_wantcall = 1;
474
475         /*Wait for the call to happen*/
476
477         pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
478         pthread_mutex_unlock (&vstfx->lock);
479
480         /*Return the result*/
481         
482         return vstfx->dispatcher_retval;
483 }