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