Optimize automation-event process splitting
[ardour.git] / libs / ardour / vst_info_file.cc
1 /*
2     Copyright (C) 2012-2014 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 /** @file libs/ardour/vst_info_file.cc
21  *  @brief Code to manage info files containing cached information about a plugin.
22  *  e.g. its name, creator etc.
23  */
24
25 #include <cassert>
26
27 #include <sys/types.h>
28
29 #ifdef COMPILER_MSVC
30 #include <sys/utime.h>
31 #else
32 #include <unistd.h>
33 #include <utime.h>
34 #endif
35
36 #include <fcntl.h>
37 #include <errno.h>
38
39 #include <stdlib.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <string.h>
43
44 #include <glib.h>
45 #include "pbd/gstdio_compat.h"
46 #include <glibmm.h>
47
48 #include "pbd/error.h"
49 #include "pbd/compose.h"
50
51 #ifndef VST_SCANNER_APP
52 #include "ardour/plugin_manager.h" // scanner_bin_path
53 #include "ardour/rc_configuration.h"
54 #include "ardour/system_exec.h"
55 #endif
56
57 #include "ardour/filesystem_paths.h"
58 #include "ardour/linux_vst_support.h"
59 #include "ardour/mac_vst_support.h"
60 #include "ardour/plugin_types.h"
61 #include "ardour/vst_info_file.h"
62
63 #include "pbd/i18n.h"
64 #include "sha1.c"
65
66 #define MAX_STRING_LEN 256
67 #define PLUGIN_SCAN_TIMEOUT (Config->get_vst_scan_timeout()) // in deciseconds
68
69 using namespace std;
70 #ifndef VST_SCANNER_APP
71 namespace ARDOUR {
72 #endif
73
74 /* prototypes */
75 #ifdef WINDOWS_VST_SUPPORT
76 #include <fst.h>
77 static bool
78 vstfx_instantiate_and_get_info_fst (const char* dllpath, vector<VSTInfo*> *infos, int uniqueID);
79 #endif
80
81 #ifdef LXVST_SUPPORT
82 static bool vstfx_instantiate_and_get_info_lx (const char* dllpath, vector<VSTInfo*> *infos, int uniqueID);
83 #endif
84
85 #ifdef MACVST_SUPPORT
86 static bool vstfx_instantiate_and_get_info_mac (const char* dllpath, vector<VSTInfo*> *infos, int uniqueID);
87 #endif
88
89 /* ID for shell plugins */
90 static int vstfx_current_loading_id = 0;
91
92 /* *** CACHE FILE PATHS *** */
93
94 static string
95 get_vst_info_cache_dir () {
96         string dir = Glib::build_filename (ARDOUR::user_cache_directory (), "vst");
97         /* if the directory doesn't exist, try to create it */
98         if (!Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
99                 if (g_mkdir (dir.c_str (), 0700)) {
100                         PBD::fatal << "Cannot create VST info folder '" << dir << "'" << endmsg;
101                 }
102         }
103         return dir;
104 }
105
106 static string
107 vstfx_infofile_path (const char* dllpath)
108 {
109         char hash[41];
110         Sha1Digest s;
111         sha1_init (&s);
112         sha1_write (&s, (const uint8_t *) dllpath, strlen (dllpath));
113         sha1_result_hash (&s, hash);
114         return Glib::build_filename (get_vst_info_cache_dir (), std::string (hash) + std::string (VST_EXT_INFOFILE));
115 }
116
117
118 /* *** VST Blacklist *** */
119
120 static void vstfx_read_blacklist (std::string &bl) {
121         FILE * blacklist_fd = NULL;
122         bl = "";
123
124         string fn = Glib::build_filename (ARDOUR::user_cache_directory (), VST_BLACKLIST);
125
126         if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
127                 return;
128         }
129
130         if (! (blacklist_fd = g_fopen (fn.c_str (), "rb"))) {
131                 return;
132         }
133
134         while (!feof (blacklist_fd)) {
135                 char buf[1024];
136                 size_t s = fread (buf, sizeof(char), 1024, blacklist_fd);
137                 if (ferror (blacklist_fd)) {
138                         PBD::error << string_compose (_("error reading VST Blacklist file %1 (%2)"), fn, strerror (errno)) << endmsg;
139                         bl = "";
140                         break;
141                 }
142                 if (s == 0) {
143                         break;
144                 }
145                 bl.append (buf, s);
146         }
147         ::fclose (blacklist_fd);
148 }
149
150 /** mark plugin as blacklisted */
151 static void vstfx_blacklist (const char *id)
152 {
153         string fn = Glib::build_filename (ARDOUR::user_cache_directory (), VST_BLACKLIST);
154         FILE * blacklist_fd = NULL;
155         if (! (blacklist_fd = g_fopen (fn.c_str (), "a"))) {
156                 PBD::error << string_compose (_("Cannot append to VST blacklist for '%1'"), id) << endmsg;
157                 return;
158         }
159         assert (NULL == strchr (id, '\n'));
160         fprintf (blacklist_fd, "%s\n", id);
161         ::fclose (blacklist_fd);
162 }
163
164 /** mark plugin as not blacklisted */
165 static void vstfx_un_blacklist (const char *idcs)
166 {
167         string id (idcs);
168         string fn = Glib::build_filename (ARDOUR::user_cache_directory (), VST_BLACKLIST);
169         if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
170                 PBD::warning << _("Expected VST Blacklist file does not exist.") << endmsg;
171                 return;
172         }
173
174         std::string bl;
175         vstfx_read_blacklist (bl);
176
177         ::g_unlink (fn.c_str ());
178
179         assert (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS));
180         assert (id.find ("\n") == string::npos);
181
182         id += "\n"; // add separator
183         const size_t rpl = bl.find (id);
184         if (rpl != string::npos) {
185                 bl.replace (rpl, id.size (), "");
186         }
187         if (bl.empty ()) {
188                 return;
189         }
190
191         FILE * blacklist_fd = NULL;
192         if (! (blacklist_fd = g_fopen (fn.c_str (), "w"))) {
193                 PBD::error << _("Cannot open VST blacklist.") << endmsg;;
194                 return;
195         }
196         fprintf (blacklist_fd, "%s", bl.c_str ());
197         ::fclose (blacklist_fd);
198 }
199
200 /* return true if plugin is blacklisted */
201 static bool vst_is_blacklisted (const char *idcs)
202 {
203         // TODO ideally we'd also check if the VST has been updated since blacklisting
204         string id (idcs);
205         string fn = Glib::build_filename (ARDOUR::user_cache_directory (), VST_BLACKLIST);
206         if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
207                 return false;
208         }
209
210         std::string bl;
211         vstfx_read_blacklist (bl);
212
213         assert (id.find ("\n") == string::npos);
214
215         id += "\n"; // add separator
216         const size_t rpl = bl.find (id);
217         if (rpl != string::npos) {
218                 return true;
219         }
220         return false;
221 }
222
223
224
225 /* *** MEMORY MANAGEMENT *** */
226
227 /** cleanup single allocated VSTInfo */
228 static void
229 vstfx_free_info (VSTInfo *info)
230 {
231         for (int i = 0; i < info->numParams; i++) {
232                 free (info->ParamNames[i]);
233                 free (info->ParamLabels[i]);
234         }
235
236         free (info->name);
237         free (info->creator);
238         free (info->Category);
239         free (info->ParamNames);
240         free (info->ParamLabels);
241         free (info);
242 }
243
244 /** reset vector */
245 static void
246 vstfx_clear_info_list (vector<VSTInfo *> *infos)
247 {
248         for (vector<VSTInfo *>::iterator i = infos->begin (); i != infos->end (); ++i) {
249                 vstfx_free_info (*i);
250         }
251         infos->clear ();
252 }
253
254
255 /* *** CACHE FILE I/O *** */
256
257 /** Helper function to read a line from the cache file
258  * @return newly allocated string of NULL
259  */
260 static char *
261 read_string (FILE *fp)
262 {
263         char buf[MAX_STRING_LEN];
264
265         if (!fgets (buf, MAX_STRING_LEN, fp)) {
266                 return 0;
267         }
268
269         if (strlen (buf)) {
270                 /* strip lash char here: '\n',
271                  * since VST-params cannot be longer than 127 chars.
272                  */
273                 buf[strlen (buf)-1] = 0;
274                 return strdup (buf);
275         }
276         return 0;
277 }
278
279 /** Read an integer value from a line in fp into n,
280  *  @return true on failure, false on success.
281  */
282 static bool
283 read_int (FILE* fp, int* n)
284 {
285         char buf[MAX_STRING_LEN];
286
287         char* p = fgets (buf, MAX_STRING_LEN, fp);
288         if (p == 0) {
289                 return true;
290         }
291
292         return (sscanf (p, "%d", n) != 1);
293 }
294
295 /** parse a plugin-block from the cache info file */
296 static bool
297 vstfx_load_info_block (FILE* fp, VSTInfo *info)
298 {
299         if ((info->name = read_string (fp)) == 0) return false;
300         if ((info->creator = read_string (fp)) == 0) return false;
301         if (read_int (fp, &info->UniqueID)) return false;
302         if ((info->Category = read_string (fp)) == 0) return false;
303         if (read_int (fp, &info->numInputs)) return false;
304         if (read_int (fp, &info->numOutputs)) return false;
305         if (read_int (fp, &info->numParams)) return false;
306         if (read_int (fp, &info->wantMidi)) return false;
307         if (read_int (fp, &info->hasEditor)) return false;
308         if (read_int (fp, &info->canProcessReplacing)) return false;
309
310         /* backwards compatibility with old .fsi files */
311         if (info->wantMidi == -1) {
312                 info->wantMidi = 1;
313         }
314
315         info->isInstrument = (info->wantMidi & 4) ? 1 : 0;
316
317         info->isInstrument |= info->numInputs == 0 && info->numOutputs > 0 && 1 == (info->wantMidi & 1);
318         if (!strcmp (info->Category, "Instrument")) {
319                 info->isInstrument = 1;
320         }
321
322         if ((info->numParams) == 0) {
323                 info->ParamNames = NULL;
324                 info->ParamLabels = NULL;
325                 return true;
326         }
327
328         if ((info->ParamNames = (char **) malloc (sizeof (char*) * info->numParams)) == 0) {
329                 return false;
330         }
331
332         for (int i = 0; i < info->numParams; ++i) {
333                 if ((info->ParamNames[i] = read_string (fp)) == 0) return false;
334         }
335
336         if ((info->ParamLabels = (char **) malloc (sizeof (char*) * info->numParams)) == 0) {
337                 return false;
338         }
339
340         for (int i = 0; i < info->numParams; ++i) {
341                 if ((info->ParamLabels[i] = read_string (fp)) == 0) {
342                         return false;
343                 }
344         }
345         return true;
346 }
347
348 /** parse all blocks in a cache info file */
349 static bool
350 vstfx_load_info_file (FILE* fp, vector<VSTInfo*> *infos)
351 {
352         VSTInfo *info;
353         if ((info = (VSTInfo*) calloc (1, sizeof (VSTInfo))) == 0) {
354                 return false;
355         }
356         if (vstfx_load_info_block (fp, info)) {
357                 if (strncmp (info->Category, "Shell", 5)) {
358                         infos->push_back (info);
359                 } else {
360                         int plugin_cnt = 0;
361                         vstfx_free_info (info);
362                         if (!read_int (fp, &plugin_cnt)) {
363                                 for (int i = 0; i < plugin_cnt; i++) {
364                                         if ((info = (VSTInfo*) calloc (1, sizeof (VSTInfo))) == 0) {
365                                                 vstfx_clear_info_list (infos);
366                                                 return false;
367                                         }
368                                         if (vstfx_load_info_block (fp, info)) {
369                                                 infos->push_back (info);
370                                         } else {
371                                                 vstfx_free_info (info);
372                                                 vstfx_clear_info_list (infos);
373                                                 return false;
374                                         }
375                                 }
376                         } else {
377                                 return false; /* Bad file */
378                         }
379                 }
380                 return true;
381         }
382         vstfx_free_info (info);
383         vstfx_clear_info_list (infos);
384         return false;
385 }
386
387 static void
388 vstfx_write_info_block (FILE* fp, VSTInfo *info)
389 {
390         assert (info);
391         assert (fp);
392
393         fprintf (fp, "%s\n", info->name);
394         fprintf (fp, "%s\n", info->creator);
395         fprintf (fp, "%d\n", info->UniqueID);
396         fprintf (fp, "%s\n", info->Category);
397         fprintf (fp, "%d\n", info->numInputs);
398         fprintf (fp, "%d\n", info->numOutputs);
399         fprintf (fp, "%d\n", info->numParams);
400         fprintf (fp, "%d\n", info->wantMidi | (info->isInstrument ? 4 : 0));
401         fprintf (fp, "%d\n", info->hasEditor);
402         fprintf (fp, "%d\n", info->canProcessReplacing);
403
404         for (int i = 0; i < info->numParams; i++) {
405                 fprintf (fp, "%s\n", info->ParamNames[i]);
406         }
407
408         for (int i = 0; i < info->numParams; i++) {
409                 fprintf (fp, "%s\n", info->ParamLabels[i]);
410         }
411 }
412
413 static void
414 vstfx_write_info_file (FILE* fp, vector<VSTInfo *> *infos)
415 {
416         assert (infos);
417         assert (fp);
418
419         if (infos->size () > 1) {
420                 vector<VSTInfo *>::iterator x = infos->begin ();
421                 /* write out the shell info first along with count of the number of
422                  * plugins contained in this shell
423                  */
424                 vstfx_write_info_block (fp, *x);
425                 fprintf (fp, "%d\n", (int)infos->size () - 1 );
426                 ++x;
427                 /* Now write out the info for each plugin */
428                 for (; x != infos->end (); ++x) {
429                         vstfx_write_info_block (fp, *x);
430                 }
431         } else if (infos->size () == 1) {
432                 vstfx_write_info_block (fp, infos->front ());
433         } else {
434                 PBD::warning << _("VST object file contains no plugins.") << endmsg;
435         }
436 }
437
438
439 /* *** CACHE MANAGEMENT *** */
440
441 /** remove info file from cache */
442 static void
443 vstfx_remove_infofile (const char *dllpath)
444 {
445         ::g_unlink (vstfx_infofile_path (dllpath).c_str ());
446 }
447
448 /** cache file for given plugin
449  * @return FILE of the .fsi cache if found and up-to-date*/
450 static FILE *
451 vstfx_infofile_for_read (const char* dllpath)
452 {
453         const size_t slen = strlen (dllpath);
454         if (
455                         (slen <= 3 || g_ascii_strcasecmp (&dllpath[slen-3], ".so"))
456                         &&
457                         (slen <= 4 || g_ascii_strcasecmp (&dllpath[slen-4], ".vst"))
458                         &&
459                         (slen <= 4 || g_ascii_strcasecmp (&dllpath[slen-4], ".dll"))
460            ) {
461                 return 0;
462         }
463
464         string const path = vstfx_infofile_path (dllpath);
465
466         if (Glib::file_test (path, Glib::FileTest (Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR))) {
467                 GStatBuf dllstat;
468                 GStatBuf fsistat;
469
470                 if (g_stat (dllpath, &dllstat) == 0) {
471                         if (g_stat (path.c_str (), &fsistat) == 0) {
472                                 if (dllstat.st_mtime <= fsistat.st_mtime) {
473                                         /* plugin is older than info file */
474                                         return g_fopen (path.c_str (), "rb");
475                                 }
476                         }
477                 }
478                 PBD::warning << string_compose (_("Ignored VST plugin which is newer than cache: '%1' (cache: '%2')"), dllpath, path) << endmsg;
479                 PBD::info << _("Re-Scan Plugins (Preferences > Plugins) to update the cache, also make sure your system-time is set correctly.") << endmsg;
480         }
481         return NULL;
482 }
483
484 /** newly created cache file for given plugin
485  * @return FILE for the .fsi cache or NULL on error
486  */
487 static FILE *
488 vstfx_infofile_for_write (const char* dllpath)
489 {
490         const size_t slen = strlen (dllpath);
491         if (
492                         (slen <= 3 || g_ascii_strcasecmp (&dllpath[slen-3], ".so"))
493                         &&
494                         (slen <= 4 || g_ascii_strcasecmp (&dllpath[slen-4], ".vst"))
495                         &&
496                         (slen <= 4 || g_ascii_strcasecmp (&dllpath[slen-4], ".dll"))
497            ) {
498                 return NULL;
499         }
500
501         string const path = vstfx_infofile_path (dllpath);
502         return g_fopen (path.c_str (), "wb");
503 }
504
505 /** check if cache-file exists, is up-to-date and parse cache file
506  * @param infos [return] loaded plugin info
507  * @return true if .fsi cache was read successfully, false otherwise
508  */
509 static bool
510 vstfx_get_info_from_file (const char* dllpath, vector<VSTInfo*> *infos)
511 {
512         FILE* infofile;
513         bool rv = false;
514         if ((infofile = vstfx_infofile_for_read (dllpath)) != 0) {
515                 rv = vstfx_load_info_file (infofile, infos);
516                 fclose (infofile);
517                 if (!rv) {
518                         PBD::warning << string_compose (_("Cannot get VST information for '%1': failed to load cache file."), dllpath) << endmsg;
519                 }
520         }
521         return rv;
522 }
523
524
525
526 /* *** VST system-under-test methods *** */
527
528 static
529 bool vstfx_midi_input (VSTState* vstfx)
530 {
531         AEffect* plugin = vstfx->plugin;
532
533         /* should we send it VST events (i.e. MIDI) */
534
535         if ((plugin->flags & effFlagsIsSynth)
536                         || (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("receiveVstEvents"), 0.0f) > 0)
537                         || (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("receiveVstMidiEvents"), 0.0f) > 0)
538                  ) {
539                 return true;
540         }
541
542         return false;
543 }
544
545 static
546 bool vstfx_midi_output (VSTState* vstfx)
547 {
548         AEffect* plugin = vstfx->plugin;
549
550         int const vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, 0, 0.0f);
551
552         if (vst_version >= 2) {
553                 /* should we send it VST events (i.e. MIDI) */
554
555                 if (   (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("sendVstEvents"), 0.0f) > 0)
556                     || (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("sendVstMidiEvent"), 0.0f) > 0)
557                    ) {
558                         return true;
559                 }
560         }
561
562         return false;
563 }
564
565 /** simple 'dummy' audiomaster callback to instantiate the plugin
566  * and query information
567  */
568 static intptr_t
569 simple_master_callback (AEffect *, int32_t opcode, int32_t, intptr_t, void *ptr, float)
570 {
571         const char* vstfx_can_do_strings[] = {
572                 "supplyIdle",
573                 "sendVstTimeInfo",
574                 "sendVstEvents",
575                 "sendVstMidiEvent",
576                 "receiveVstEvents",
577                 "receiveVstMidiEvent",
578                 "supportShell",
579                 "shellCategory",
580                 "shellCategorycurID"
581         };
582         const int vstfx_can_do_string_count = 9;
583
584         if (opcode == audioMasterVersion) {
585                 return 2400;
586         }
587         else if (opcode == audioMasterCanDo) {
588                 for (int i = 0; i < vstfx_can_do_string_count; i++) {
589                         if (! strcmp (vstfx_can_do_strings[i], (const char*)ptr)) {
590                                 return 1;
591                         }
592                 }
593                 return 0;
594         }
595         else if (opcode == audioMasterCurrentId) {
596                 return vstfx_current_loading_id;
597         }
598         else {
599                 return 0;
600         }
601 }
602
603
604 /** main plugin query and test function */
605 static VSTInfo*
606 vstfx_parse_vst_state (VSTState* vstfx)
607 {
608         assert (vstfx);
609
610         VSTInfo* info = (VSTInfo*) malloc (sizeof (VSTInfo));
611         if (!info) {
612                 return 0;
613         }
614
615         /* We need to init the creator because some plugins
616          * fail to implement getVendorString, and so won't stuff the
617          * string with any name */
618
619         char creator[65] = "Unknown";
620         char name[65] = "";
621
622         AEffect* plugin = vstfx->plugin;
623
624
625         plugin->dispatcher (plugin, effGetEffectName, 0, 0, name, 0);
626
627         if (strlen (name) == 0) {
628                 plugin->dispatcher (plugin, effGetProductString, 0, 0, name, 0);
629         }
630
631         if (strlen (name) == 0) {
632                 info->name = strdup (vstfx->handle->name);
633         } else {
634                 info->name = strdup (name);
635         }
636
637         /*If the plugin doesn't bother to implement GetVendorString we will
638          * have pre-stuffed the string with 'Unknown' */
639
640         plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
641
642         /* Some plugins DO implement GetVendorString, but DON'T put a name in it
643          * so if its just a zero length string we replace it with 'Unknown' */
644
645         if (strlen (creator) == 0) {
646                 info->creator = strdup ("Unknown");
647         } else {
648                 info->creator = strdup (creator);
649         }
650
651
652         switch (plugin->dispatcher (plugin, effGetPlugCategory, 0, 0, 0, 0))
653         {
654                 case kPlugCategEffect:         info->Category = strdup ("Effect"); break;
655                 case kPlugCategSynth:          info->Category = strdup ("Instrument"); break;
656                 case kPlugCategAnalysis:       info->Category = strdup ("Analyser"); break;
657                 case kPlugCategMastering:      info->Category = strdup ("Mastering"); break;
658                 case kPlugCategSpacializer:    info->Category = strdup ("Spatial"); break;
659                 case kPlugCategRoomFx:         info->Category = strdup ("RoomFx"); break;
660                 case kPlugSurroundFx:          info->Category = strdup ("SurroundFx"); break;
661                 case kPlugCategRestoration:    info->Category = strdup ("Restoration"); break;
662                 case kPlugCategOfflineProcess: info->Category = strdup ("Offline"); break;
663                 case kPlugCategShell:          info->Category = strdup ("Shell"); break;
664                 case kPlugCategGenerator:      info->Category = strdup ("Generator"); break;
665                 default:                       info->Category = strdup ("Unknown"); break;
666         }
667
668         info->UniqueID = plugin->uniqueID;
669
670         info->numInputs = plugin->numInputs;
671         info->numOutputs = plugin->numOutputs;
672         info->numParams = plugin->numParams;
673         info->wantMidi = (vstfx_midi_input (vstfx) ? 1 : 0) | (vstfx_midi_output (vstfx) ? 2 : 0);
674         info->hasEditor = plugin->flags & effFlagsHasEditor ? true : false;
675         info->isInstrument = (plugin->flags & effFlagsIsSynth) ? 1 : 0;
676         info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? true : false;
677         info->ParamNames = (char **) malloc (sizeof (char*)*info->numParams);
678         info->ParamLabels = (char **) malloc (sizeof (char*)*info->numParams);
679
680 #ifdef __APPLE__
681         if (info->hasEditor) {
682                 /* we only support Cocoa UIs (just like Reaper) */
683                 info->hasEditor = (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f) & 0xffff0000) == 0xbeef0000;
684         }
685 #endif
686
687         for (int i = 0; i < info->numParams; ++i) {
688                 char name[VestigeMaxLabelLen];
689                 char label[VestigeMaxLabelLen];
690
691                 /* Not all plugins give parameters labels as well as names */
692
693                 strcpy (name, "No Name");
694                 strcpy (label, "No Label");
695
696                 plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
697                 info->ParamNames[i] = strdup (name);
698
699                 //NOTE: 'effGetParamLabel' is no longer defined in vestige headers
700                 //plugin->dispatcher (plugin, effGetParamLabel, i, 0, label, 0);
701                 info->ParamLabels[i] = strdup (label);
702         }
703         return info;
704 }
705
706 /** wrapper around \ref vstfx_parse_vst_state,
707  * iterate over plugins in shell, translate VST-info into ardour VSTState
708  */
709 static void
710 vstfx_info_from_plugin (const char *dllpath, VSTState* vstfx, vector<VSTInfo *> *infos, enum ARDOUR::PluginType type)
711 {
712         assert (vstfx);
713         VSTInfo *info;
714
715         if (!(info = vstfx_parse_vst_state (vstfx))) {
716                 return;
717         }
718
719         infos->push_back (info);
720 #if 1 // shell-plugin support
721         /* If this plugin is a Shell and we are not already inside a shell plugin
722          * read the info for all of the plugins contained in this shell.
723          */
724         if (!strncmp (info->Category, "Shell", 5)
725                         && vstfx->handle->plugincnt == 1) {
726                 int id;
727                 vector< pair<int, string> > ids;
728                 AEffect *plugin = vstfx->plugin;
729
730                 do {
731                         char name[65] = "Unknown";
732                         id = plugin->dispatcher (plugin, effShellGetNextPlugin, 0, 0, name, 0);
733                         ids.push_back (std::make_pair (id, name));
734                 } while ( id != 0 );
735
736                 switch (type) {
737 #ifdef WINDOWS_VST_SUPPORT
738                         case ARDOUR::Windows_VST:
739                                 fst_close (vstfx);
740                                 break;
741 #endif
742 #ifdef LXVST_SUPPORT
743                         case ARDOUR::LXVST:
744                                 vstfx_close (vstfx);
745                                 break;
746 #endif
747 #ifdef MACVST_SUPPORT
748                         case ARDOUR::MacVST:
749                                 mac_vst_close (vstfx);
750                                 break;
751 #endif
752                         default:
753                                 assert (0);
754                                 break;
755                 }
756
757                 for (vector< pair<int, string> >::iterator x = ids.begin (); x != ids.end (); ++x) {
758                         id = (*x).first;
759                         if (id == 0) continue;
760                         /* recurse vstfx_get_info() */
761
762                         bool ok;
763                         switch (type) {
764 #ifdef WINDOWS_VST_SUPPORT
765                                 case ARDOUR::Windows_VST:
766                                         ok = vstfx_instantiate_and_get_info_fst (dllpath, infos, id);
767                                         break;
768 #endif
769 #ifdef LXVST_SUPPORT
770                                 case ARDOUR::LXVST:
771                                         ok = vstfx_instantiate_and_get_info_lx (dllpath, infos, id);
772                                         break;
773 #endif
774 #ifdef MACVST_SUPPORT
775                                 case ARDOUR::MacVST:
776                                         ok = vstfx_instantiate_and_get_info_mac (dllpath, infos, id);
777                                         break;
778 #endif
779                                 default:
780                                         ok = false;
781                                         break;
782                         }
783                         if (ok) {
784                                 // One shell (some?, all?) does not report the actual plugin name
785                                 // even after the shelled plugin has been instantiated.
786                                 // Replace the name of the shell with the real name.
787                                 info = infos->back ();
788                                 free (info->name);
789
790                                 if ((*x).second.length () == 0) {
791                                         info->name = strdup ("Unknown");
792                                 }
793                                 else {
794                                         info->name = strdup ((*x).second.c_str ());
795                                 }
796                         }
797                 }
798         } else {
799                 switch (type) {
800 #ifdef WINDOWS_VST_SUPPORT
801                         case ARDOUR::Windows_VST:
802                                 fst_close (vstfx);
803                                 break;
804 #endif
805 #ifdef LXVST_SUPPORT
806                         case ARDOUR::LXVST:
807                                 vstfx_close (vstfx);
808                                 break;
809 #endif
810 #ifdef MACVST_SUPPORT
811                         case ARDOUR::MacVST:
812                                 mac_vst_close (vstfx);
813                                 break;
814 #endif
815                         default:
816                                 assert (0);
817                                 break;
818                 }
819         }
820 #endif
821 }
822
823
824
825 /* *** TOP-LEVEL PLUGIN INSTANTIATION FUNCTIONS *** */
826
827 #ifdef LXVST_SUPPORT
828 static bool
829 vstfx_instantiate_and_get_info_lx (
830                 const char* dllpath, vector<VSTInfo*> *infos, int uniqueID)
831 {
832         VSTHandle* h;
833         VSTState* vstfx;
834         if (!(h = vstfx_load (dllpath))) {
835                 PBD::warning << string_compose (_("Cannot get LinuxVST information from '%1': load failed."), dllpath) << endmsg;
836                 return false;
837         }
838
839         vstfx_current_loading_id = uniqueID;
840
841         if (!(vstfx = vstfx_instantiate (h, simple_master_callback, 0))) {
842                 vstfx_unload (h);
843                 PBD::warning << string_compose (_("Cannot get LinuxVST information from '%1': instantiation failed."), dllpath) << endmsg;
844                 return false;
845         }
846
847         vstfx_current_loading_id = 0;
848
849         vstfx_info_from_plugin (dllpath, vstfx, infos, ARDOUR::LXVST);
850
851         vstfx_unload (h);
852         return true;
853 }
854 #endif
855
856 #ifdef WINDOWS_VST_SUPPORT
857 static bool
858 vstfx_instantiate_and_get_info_fst (
859                 const char* dllpath, vector<VSTInfo*> *infos, int uniqueID)
860 {
861         VSTHandle* h;
862         VSTState* vstfx;
863         if (!(h = fst_load (dllpath))) {
864                 PBD::warning << string_compose (_("Cannot get Windows VST information from '%1': load failed."), dllpath) << endmsg;
865                 return false;
866         }
867
868         vstfx_current_loading_id = uniqueID;
869
870         if (!(vstfx = fst_instantiate (h, simple_master_callback, 0))) {
871                 fst_unload (&h);
872                 vstfx_current_loading_id = 0;
873                 PBD::warning << string_compose (_("Cannot get Windows VST information from '%1': instantiation failed."), dllpath) << endmsg;
874                 return false;
875         }
876         vstfx_current_loading_id = 0;
877
878         vstfx_info_from_plugin (dllpath, vstfx, infos, ARDOUR::Windows_VST);
879
880         return true;
881 }
882 #endif
883
884 #ifdef MACVST_SUPPORT
885 static bool
886 vstfx_instantiate_and_get_info_mac (
887                 const char* dllpath, vector<VSTInfo*> *infos, int uniqueID)
888 {
889         printf("vstfx_instantiate_and_get_info_mac %s\n", dllpath);
890         VSTHandle* h;
891         VSTState* vstfx;
892         if (!(h = mac_vst_load (dllpath))) {
893                 PBD::warning << string_compose (_("Cannot get MacVST information from '%1': load failed."), dllpath) << endmsg;
894                 return false;
895         }
896
897         vstfx_current_loading_id = uniqueID;
898
899         if (!(vstfx = mac_vst_instantiate (h, simple_master_callback, 0))) {
900                 mac_vst_unload (h);
901                 PBD::warning << string_compose (_("Cannot get MacVST information from '%1': instantiation failed."), dllpath) << endmsg;
902                 return false;
903         }
904
905         vstfx_current_loading_id = 0;
906
907         vstfx_info_from_plugin (dllpath, vstfx, infos, ARDOUR::MacVST);
908
909         mac_vst_unload (h);
910         return true;
911 }
912 #endif
913
914 /* *** ERROR LOGGING *** */
915 #ifndef VST_SCANNER_APP
916
917 static FILE * _errorlog_fd = 0;
918 static char * _errorlog_dll = 0;
919
920 static void parse_scanner_output (std::string msg, size_t /*len*/)
921 {
922         if (!_errorlog_fd && !_errorlog_dll) {
923                 PBD::error << "VST scanner: " << msg;
924                 return;
925         }
926
927 #if 0 // TODO
928         if (!_errorlog_fd) {
929                 if (!(_errorlog_fd = g_fopen (vstfx_errorfile_path (_errorlog_dll).c_str (), "w"))) {
930                         PBD::error << "Cannot create plugin error-log for plugin " << _errorlog_dll;
931                         free (_errorlog_dll);
932                         _errorlog_dll = NULL;
933                 }
934         }
935 #endif
936
937         if (_errorlog_fd) {
938                 fprintf (_errorlog_fd, "%s\n", msg.c_str ());
939         } else if (_errorlog_dll) {
940                 PBD::error << "VST '" << _errorlog_dll << "': " << msg;
941         } else {
942                 PBD::error << "VST scanner: " << msg;
943         }
944 }
945
946 static void
947 set_error_log (const char* dllpath) {
948         assert (!_errorlog_fd);
949         assert (!_errorlog_dll);
950         _errorlog_dll = strdup (dllpath);
951 }
952
953 static void
954 close_error_log () {
955         if (_errorlog_fd) {
956                 fclose (_errorlog_fd);
957                 _errorlog_fd = 0;
958         }
959         free (_errorlog_dll);
960         _errorlog_dll = 0;
961 }
962
963 #endif
964
965
966 /* *** the main function that uses all of the above *** */
967
968 static vector<VSTInfo *> *
969 vstfx_get_info (const char* dllpath, enum ARDOUR::PluginType type, enum VSTScanMode mode)
970 {
971         FILE* infofile;
972         vector<VSTInfo*> *infos = new vector<VSTInfo*>;
973
974         if (vst_is_blacklisted (dllpath)) {
975                 return infos;
976         }
977
978         if (vstfx_get_info_from_file (dllpath, infos)) {
979                 return infos;
980         }
981
982 #ifndef VST_SCANNER_APP
983         std::string scanner_bin_path = ARDOUR::PluginManager::scanner_bin_path;
984
985         if (mode == VST_SCAN_CACHE_ONLY) {
986                 /* never scan explicitly, use cache only */
987                 return infos;
988         }
989         else if (mode == VST_SCAN_USE_APP && scanner_bin_path != "") {
990                 /* use external scanner app */
991
992                 char **argp= (char**) calloc (3,sizeof (char*));
993                 argp[0] = strdup (scanner_bin_path.c_str ());
994                 argp[1] = strdup (dllpath);
995                 argp[2] = 0;
996
997                 set_error_log (dllpath);
998                 ARDOUR::SystemExec scanner (scanner_bin_path, argp);
999                 PBD::ScopedConnectionList cons;
1000                 scanner.ReadStdout.connect_same_thread (cons, boost::bind (&parse_scanner_output, _1 ,_2));
1001                 if (scanner.start (2 /* send stderr&stdout via signal */)) {
1002                         PBD::error << string_compose (_("Cannot launch VST scanner app '%1': %2"), scanner_bin_path, strerror (errno)) << endmsg;
1003                         close_error_log ();
1004                         return infos;
1005                 } else {
1006                         int timeout = PLUGIN_SCAN_TIMEOUT;
1007                         bool no_timeout = (timeout <= 0);
1008                         ARDOUR::PluginScanTimeout (timeout);
1009                         while (scanner.is_running () && (no_timeout || timeout > 0)) {
1010                                 if (!no_timeout && !ARDOUR::PluginManager::instance ().no_timeout ()) {
1011                                         if (timeout%5 == 0) {
1012                                                 ARDOUR::PluginScanTimeout (timeout);
1013                                         }
1014                                         --timeout;
1015                                 }
1016                                 ARDOUR::GUIIdle ();
1017                                 Glib::usleep (100000);
1018
1019                                 if (ARDOUR::PluginManager::instance ().cancelled ()) {
1020                                         // remove info file (might be incomplete)
1021                                         vstfx_remove_infofile (dllpath);
1022                                         // remove temporary blacklist file (scan incomplete)
1023                                         vstfx_un_blacklist (dllpath);
1024                                         scanner.terminate ();
1025                                         close_error_log ();
1026                                         return infos;
1027                                 }
1028                         }
1029                         scanner.terminate ();
1030                 }
1031                 close_error_log ();
1032                 /* re-read index (generated by external scanner) */
1033                 vstfx_clear_info_list (infos);
1034                 if (!vst_is_blacklisted (dllpath)) {
1035                         vstfx_get_info_from_file (dllpath, infos);
1036                 }
1037                 return infos;
1038         }
1039         /* else .. instantiate and check in in ardour process itself */
1040 #else
1041         (void) mode; // unused parameter
1042 #endif
1043
1044         bool ok;
1045         /* blacklist in case instantiation fails */
1046         vstfx_blacklist (dllpath);
1047
1048         switch (type) {
1049 #ifdef WINDOWS_VST_SUPPORT
1050                 case ARDOUR::Windows_VST:
1051                         ok = vstfx_instantiate_and_get_info_fst (dllpath, infos, 0);
1052                         break;
1053 #endif
1054 #ifdef LXVST_SUPPORT
1055                 case ARDOUR::LXVST:
1056                         ok = vstfx_instantiate_and_get_info_lx (dllpath, infos, 0);
1057                         break;
1058 #endif
1059 #ifdef MACVST_SUPPORT
1060                 case ARDOUR::MacVST:
1061                         ok = vstfx_instantiate_and_get_info_mac (dllpath, infos, 0);
1062                         break;
1063 #endif
1064                 default:
1065                         ok = false;
1066                         break;
1067         }
1068
1069         if (!ok) {
1070                 return infos;
1071         }
1072
1073         /* remove from blacklist */
1074         vstfx_un_blacklist (dllpath);
1075
1076         /* crate cache/whitelist */
1077         infofile = vstfx_infofile_for_write (dllpath);
1078         if (!infofile) {
1079                 PBD::warning << string_compose (_("Cannot cache VST information for '%1': cannot create cache file."), dllpath) << endmsg;
1080                 return infos;
1081         } else {
1082                 vstfx_write_info_file (infofile, infos);
1083                 fclose (infofile);
1084
1085                 /* In some cases the .dll may have a modification time in the future,
1086                  * (e.g. unzip a VST plugin: .zip files don't include timezones)
1087                  */
1088                 string const fsipath = vstfx_infofile_path (dllpath);
1089                 GStatBuf dllstat;
1090                 GStatBuf fsistat;
1091                 if (g_stat (dllpath, &dllstat) == 0 && g_stat (fsipath.c_str (), &fsistat) == 0) {
1092                         struct utimbuf utb;
1093                         utb.actime = fsistat.st_atime;
1094                         utb.modtime = std::max (dllstat.st_mtime, fsistat.st_mtime);
1095                         g_utime (fsipath.c_str (), &utb);
1096                 }
1097         }
1098         return infos;
1099 }
1100
1101
1102 /* *** public API *** */
1103
1104 void
1105 vstfx_free_info_list (vector<VSTInfo *> *infos)
1106 {
1107         for (vector<VSTInfo *>::iterator i = infos->begin (); i != infos->end (); ++i) {
1108                 vstfx_free_info (*i);
1109         }
1110         delete infos;
1111 }
1112
1113 #ifdef LXVST_SUPPORT
1114 vector<VSTInfo *> *
1115 vstfx_get_info_lx (char* dllpath, enum VSTScanMode mode)
1116 {
1117         return vstfx_get_info (dllpath, ARDOUR::LXVST, mode);
1118 }
1119 #endif
1120
1121 #ifdef MACVST_SUPPORT
1122 vector<VSTInfo *> *
1123 vstfx_get_info_mac (char* dllpath, enum VSTScanMode mode)
1124 {
1125         return vstfx_get_info (dllpath, ARDOUR::MacVST, mode);
1126 }
1127 #endif
1128
1129 #ifdef WINDOWS_VST_SUPPORT
1130 vector<VSTInfo *> *
1131 vstfx_get_info_fst (char* dllpath, enum VSTScanMode mode)
1132 {
1133         return vstfx_get_info (dllpath, ARDOUR::Windows_VST, mode);
1134 }
1135 #endif
1136
1137 #ifndef VST_SCANNER_APP
1138 } // namespace
1139 #endif