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