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