From fac93f7a82833b094c36164d733bb3c352a7223e Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 23 Feb 2014 17:52:49 +0100 Subject: preparations for VST Shell plugins (mostly mixbus code forward port) --- libs/ardour/ardour/session.h | 4 + libs/ardour/ardour/vst_info_file.h | 8 +- libs/ardour/plugin_manager.cc | 193 ++++++++++++++++++++------------- libs/ardour/session_vst.cc | 19 +++- libs/ardour/vst_info_file.cc | 214 +++++++++++++++++++++++++++---------- libs/ardour/windows_vst_plugin.cc | 4 + 6 files changed, 300 insertions(+), 142 deletions(-) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index f77e09736f..d183494f87 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -756,6 +756,10 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop /* VST support */ + static int vst_current_loading_id; + static const char* vst_can_do_strings[]; + static const int vst_can_do_string_count; + static intptr_t vst_callback ( AEffect* effect, int32_t opcode, diff --git a/libs/ardour/ardour/vst_info_file.h b/libs/ardour/ardour/vst_info_file.h index 2da203a54c..ac7167bc90 100644 --- a/libs/ardour/ardour/vst_info_file.h +++ b/libs/ardour/ardour/vst_info_file.h @@ -23,15 +23,17 @@ #include "ardour/libardour_visibility.h" #include "ardour/vst_types.h" +#include -LIBARDOUR_API extern void vstfx_free_info (VSTInfo *); +LIBARDOUR_API extern void vstfx_free_info (VSTInfo *); +LIBARDOUR_API extern void vstfx_free_info_list (std::vector *infos); #ifdef LXVST_SUPPORT -LIBARDOUR_API extern VSTInfo * vstfx_get_info_lx (char *); +LIBARDOUR_API extern std::vector * vstfx_get_info_lx (char *); #endif #ifdef WINDOWS_VST_SUPPORT -LIBARDOUR_API extern VSTInfo * vstfx_get_info_fst (char *); +LIBARDOUR_API extern std::vector * vstfx_get_info_fst (char *); #endif #endif /* __vstfx_h__ */ diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 6e9aa4fc18..8b77bee0af 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -94,7 +94,7 @@ using namespace std; PluginManager* PluginManager::_instance = 0; PluginManager& -PluginManager::instance() +PluginManager::instance() { if (!_instance) { _instance = new PluginManager; @@ -215,7 +215,7 @@ PluginManager::ladspa_refresh () /* Only add standard locations to ladspa_path if it doesn't * already contain them. Check for trailing G_DIR_SEPARATOR too. */ - + vector ladspa_modules; DEBUG_TRACE (DEBUG::PluginManager, string_compose ("LADSPA: search along: [%1]\n", ladspa_search_path().to_string())); @@ -229,7 +229,7 @@ PluginManager::ladspa_refresh () find_matching_files_in_search_path (ladspa_search_path (), dylib_extension_pattern, ladspa_modules); - + find_matching_files_in_search_path (ladspa_search_path (), dll_extension_pattern, ladspa_modules); @@ -288,7 +288,7 @@ PluginManager::add_presets(string domain) warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg; } } - + vector_delete (presets); } #endif @@ -557,46 +557,72 @@ PluginManager::windows_vst_discover_from_path (string path) int PluginManager::windows_vst_discover (string path) { - VSTInfo* finfo; - char buf[32]; + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("windows_vst_discover '%1'\n", path)); - if ((finfo = vstfx_get_info_fst (const_cast (path.c_str()))) == 0) { + vector * finfos = vstfx_get_info_fst (const_cast (path.c_str())); + + if (finfos->empty()) { + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Windows VST information from '%1'\n", path)); warning << "Cannot get Windows VST information from " << path << endmsg; return -1; } - if (!finfo->canProcessReplacing) { - warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"), - finfo->name, PROGRAM_NAME) - << endl; - } + uint32_t discovered = 0; + for (vector::iterator x = finfos->begin(); x != finfos->end(); ++x) { + VSTInfo* finfo = *x; + char buf[32]; - PluginInfoPtr info (new WindowsVSTPluginInfo); + if (!finfo->canProcessReplacing) { + warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"), + finfo->name, PROGRAM_NAME) + << endl; + continue; + } - /* what a joke freeware VST is */ + PluginInfoPtr info (new WindowsVSTPluginInfo); - if (!strcasecmp ("The Unnamed plugin", finfo->name)) { - info->name = PBD::basename_nosuffix (path); - } else { - info->name = finfo->name; - } + /* what a joke freeware VST is */ + if (!strcasecmp ("The Unnamed plugin", finfo->name)) { + info->name = PBD::basename_nosuffix (path); + } else { + info->name = finfo->name; + } - snprintf (buf, sizeof (buf), "%d", finfo->UniqueID); - info->unique_id = buf; - info->category = "VST"; - info->path = path; - info->creator = finfo->creator; - info->index = 0; - info->n_inputs.set_audio (finfo->numInputs); - info->n_outputs.set_audio (finfo->numOutputs); - info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0); - info->type = ARDOUR::Windows_VST; - _windows_vst_plugin_info->push_back (info); - vstfx_free_info(finfo); + snprintf (buf, sizeof (buf), "%d", finfo->UniqueID); + info->unique_id = buf; + info->category = "VST"; + info->path = path; + info->creator = finfo->creator; + info->index = 0; + info->n_inputs.set_audio (finfo->numInputs); + info->n_outputs.set_audio (finfo->numOutputs); + info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0); + info->type = ARDOUR::Windows_VST; + + // TODO: check dup-IDs (lxvst AND windows vst) + bool duplicate = false; + + if (!_windows_vst_plugin_info->empty()) { + for (PluginInfoList::iterator i =_windows_vst_plugin_info->begin(); i != _windows_vst_plugin_info->end(); ++i) { + if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) { + warning << "Ignoring duplicate Windows VST plugin " << info->name << "\n"; + duplicate = true; + break; + } + } + } - return 0; + if (!duplicate) { + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Windows VST plugin ID '%1'\n", info->unique_id)); + _windows_vst_plugin_info->push_back (info); + discovered++; + } + } + + vstfx_free_info_list (finfos); + return discovered > 0 ? 0 : -1; } #endif // WINDOWS_VST_SUPPORT @@ -669,62 +695,75 @@ PluginManager::lxvst_discover_from_path (string path) int PluginManager::lxvst_discover (string path) { - VSTInfo* finfo; - char buf[32]; - DEBUG_TRACE (DEBUG::PluginManager, string_compose ("checking apparent LXVST plugin at %1\n", path)); - if ((finfo = vstfx_get_info_lx (const_cast (path.c_str()))) == 0) { + vector * finfos = vstfx_get_info_lx (const_cast (path.c_str())); + + if (finfos->empty()) { + DEBUG_TRACE (DEBUG::PluginManager, string_compose ("Cannot get Linux VST information from '%1'\n", path)); + warning << "Cannot get Linux VST information from " << path << endmsg; return -1; } - if (!finfo->canProcessReplacing) { - warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"), - finfo->name, PROGRAM_NAME) - << endl; - } + uint32_t discovered = 0; + for (vector::iterator x = finfos->begin(); x != finfos->end(); ++x) { + VSTInfo* finfo = *x; + char buf[32]; - PluginInfoPtr info(new LXVSTPluginInfo); + if (!finfo->canProcessReplacing) { + warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in %2 at this time"), + finfo->name, PROGRAM_NAME) + << endl; + continue; + } - if (!strcasecmp ("The Unnamed plugin", finfo->name)) { - info->name = PBD::basename_nosuffix (path); - } else { - info->name = finfo->name; - } - - - snprintf (buf, sizeof (buf), "%d", finfo->UniqueID); - info->unique_id = buf; - info->category = "linuxVSTs"; - info->path = path; - info->creator = finfo->creator; - info->index = 0; - info->n_inputs.set_audio (finfo->numInputs); - info->n_outputs.set_audio (finfo->numOutputs); - info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0); - info->type = ARDOUR::LXVST; - - /* Make sure we don't find the same plugin in more than one place along - the LXVST_PATH We can't use a simple 'find' because the path is included - in the PluginInfo, and that is the one thing we can be sure MUST be - different if a duplicate instance is found. So we just compare the type - and unique ID (which for some VSTs isn't actually unique...) - */ - - if (!_lxvst_plugin_info->empty()) { - for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) { - if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) { - warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n"; - vstfx_free_info(finfo); - return 0; + PluginInfoPtr info(new LXVSTPluginInfo); + + if (!strcasecmp ("The Unnamed plugin", finfo->name)) { + info->name = PBD::basename_nosuffix (path); + } else { + info->name = finfo->name; + } + + + snprintf (buf, sizeof (buf), "%d", finfo->UniqueID); + info->unique_id = buf; + info->category = "linuxVSTs"; + info->path = path; + info->creator = finfo->creator; + info->index = 0; + info->n_inputs.set_audio (finfo->numInputs); + info->n_outputs.set_audio (finfo->numOutputs); + info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0); + info->type = ARDOUR::LXVST; + + /* Make sure we don't find the same plugin in more than one place along + the LXVST_PATH We can't use a simple 'find' because the path is included + in the PluginInfo, and that is the one thing we can be sure MUST be + different if a duplicate instance is found. So we just compare the type + and unique ID (which for some VSTs isn't actually unique...) + */ + + // TODO: check dup-IDs with windowsVST, too + bool duplicate = false; + if (!_lxvst_plugin_info->empty()) { + for (PluginInfoList::iterator i =_lxvst_plugin_info->begin(); i != _lxvst_plugin_info->end(); ++i) { + if ((info->type == (*i)->type)&&(info->unique_id == (*i)->unique_id)) { + warning << "Ignoring duplicate Linux VST plugin " << info->name << "\n"; + duplicate = true; + break; + } } } + + if (!duplicate) { + _lxvst_plugin_info->push_back (info); + discovered++; + } } - - _lxvst_plugin_info->push_back (info); - vstfx_free_info (finfo); - return 0; + vstfx_free_info_list (finfos); + return discovered > 0 ? 0 : -1; } #endif // LXVST_SUPPORT diff --git a/libs/ardour/session_vst.cc b/libs/ardour/session_vst.cc index 61805be2cd..54843965b4 100644 --- a/libs/ardour/session_vst.cc +++ b/libs/ardour/session_vst.cc @@ -45,6 +45,15 @@ static int debug_callbacks = -1; using namespace ARDOUR; +int Session::vst_current_loading_id = 0; +const char* Session::vst_can_do_strings[] = { + X_("supplyIdle"), + X_("sendVstTimeInfo"), + X_("supportShell"), + X_("shellCategory") +}; +const int Session::vst_can_do_string_count = sizeof (vst_can_do_strings) / sizeof (char*); + intptr_t Session::vst_callback ( AEffect* effect, int32_t opcode, @@ -97,9 +106,8 @@ intptr_t Session::vst_callback ( case audioMasterCurrentId: SHOW_CALLBACK ("amc: audioMasterCurrentId\n"); - // returns the unique id of a plug that's currently - // loading - return 0; + // returns the unique id of a plug that's currently loading + return vst_current_loading_id; case audioMasterIdle: SHOW_CALLBACK ("amc: audioMasterIdle\n"); @@ -408,6 +416,11 @@ intptr_t Session::vst_callback ( case audioMasterCanDo: SHOW_CALLBACK ("amc: audioMasterCanDo\n"); // string in ptr, (const char*)ptr + for (int i = 0; i < vst_can_do_string_count; i++) { + if (! strcmp(vst_can_do_strings[i], (const char*)ptr)) { + return 1; + } + } return 0; case audioMasterGetLanguage: diff --git a/libs/ardour/vst_info_file.cc b/libs/ardour/vst_info_file.cc index 7d5aaf3795..50d94850d6 100644 --- a/libs/ardour/vst_info_file.cc +++ b/libs/ardour/vst_info_file.cc @@ -84,51 +84,89 @@ read_int (FILE* fp, int* n) return (sscanf (p, "%d", n) != 1); } -static VSTInfo * -load_vstfx_info_file (FILE* fp) +static void +vstfx_clear_info_list (vector *infos) { - VSTInfo *info; - - if ((info = (VSTInfo*) malloc (sizeof (VSTInfo))) == 0) { - return 0; + for (vector::iterator i = infos->begin(); i != infos->end(); ++i) { + vstfx_free_info(*i); } + infos->clear(); +} - if ((info->name = read_string(fp)) == 0) goto error; - if ((info->creator = read_string(fp)) == 0) goto error; - if (read_int (fp, &info->UniqueID)) goto error; - if ((info->Category = read_string(fp)) == 0) goto error; - if (read_int (fp, &info->numInputs)) goto error; - if (read_int (fp, &info->numOutputs)) goto error; - if (read_int (fp, &info->numParams)) goto error; - if (read_int (fp, &info->wantMidi)) goto error; - if (read_int (fp, &info->hasEditor)) goto error; - if (read_int (fp, &info->canProcessReplacing)) goto error; +static bool +vstfx_load_info_block(FILE* fp, VSTInfo *info) +{ + if ((info->name = read_string(fp)) == 0) return false; + if ((info->creator = read_string(fp)) == 0) return false; + if (read_int (fp, &info->UniqueID)) return false; + if ((info->Category = read_string(fp)) == 0) return false; + if (read_int (fp, &info->numInputs)) return false; + if (read_int (fp, &info->numOutputs)) return false; + if (read_int (fp, &info->numParams)) return false; + if (read_int (fp, &info->wantMidi)) return false; + if (read_int (fp, &info->hasEditor)) return false; + if (read_int (fp, &info->canProcessReplacing)) return false; if ((info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams)) == 0) { - goto error; + return false; } for (int i = 0; i < info->numParams; ++i) { - if ((info->ParamNames[i] = read_string(fp)) == 0) goto error; + if ((info->ParamNames[i] = read_string(fp)) == 0) return false; } if ((info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams)) == 0) { - goto error; + return false; } for (int i = 0; i < info->numParams; ++i) { - if ((info->ParamLabels[i] = read_string(fp)) == 0) goto error; + if ((info->ParamLabels[i] = read_string(fp)) == 0) { + return false; + } } + return true; +} - return info; - -error: - free (info); - return 0; +static bool +vstfx_load_info_file (FILE* fp, vector *infos) +{ + VSTInfo *info; + if ((info = (VSTInfo*) calloc (1, sizeof (VSTInfo))) == 0) { + return false; + } + if (vstfx_load_info_block(fp, info)) { + if (strncmp (info->Category, "Shell", 5)) { + infos->push_back(info); + } else { + int plugin_cnt = 0; + vstfx_free_info(info); + if (read_int (fp, &plugin_cnt)) { + for (int i = 0; i < plugin_cnt; i++) { + if ((info = (VSTInfo*) calloc (1, sizeof (VSTInfo))) == 0) { + vstfx_clear_info_list(infos); + return false; + } + if (vstfx_load_info_block(fp, info)) { + infos->push_back(info); + } else { + vstfx_free_info(info); + vstfx_clear_info_list(infos); + return false; + } + } + } else { + return false; /* Bad file */ + } + } + return true; + } + vstfx_free_info(info); + vstfx_clear_info_list(infos); + return false; } -static int -save_vstfx_info_file (VSTInfo *info, FILE* fp) +static void +vstfx_write_info_block (FILE* fp, VSTInfo *info) { assert (info); assert (fp); @@ -151,8 +189,31 @@ save_vstfx_info_file (VSTInfo *info, FILE* fp) for (int i = 0; i < info->numParams; i++) { fprintf (fp, "%s\n", info->ParamLabels[i]); } +} - return 0; +static void +vstfx_write_info_file (FILE* fp, vector *infos) +{ + assert(infos); + assert(fp); + + if (infos->size() > 1) { + vector::iterator x = infos->begin(); + /* write out the shell info first along with count of the number of + * plugins contained in this shell + */ + vstfx_write_info_block(fp, *x); + fprintf( fp, "%d\n", infos->size() - 1 ); + ++x; + /* Now write out the info for each plugin */ + for (; x != infos->end(); ++x) { + vstfx_write_info_block(fp, *x); + } + } else if (infos->size() == 1) { + vstfx_write_info_block(fp, infos->front()); + } else { + PBD::warning << "Zero plugins in VST." << endmsg; // XXX here? + } } static string @@ -351,28 +412,49 @@ vstfx_info_from_plugin (VSTState* vstfx) static intptr_t simple_master_callback (AEffect *, int32_t opcode, int32_t, intptr_t, void *, float) { +#if 0 + static const char* can_do_strings[] = { + X_("supportShell"), + X_("shellCategory") + }; + static const int can_do_string_count = sizeof (can_do_strings) / sizeof (char*); + static int current_loading_id = 0; +#endif + if (opcode == audioMasterVersion) { return 2; - } else { + } +#if 0 + else if (opcode == audioMasterCanDo) { + for (int i = 0; i < can_do_string_count; i++) { + if (! strcmp(can_do_strings[i], (const char*)ptr)) { + return 1; + } + } + return 0; + } + else if (opcode == audioMasterCurrentId) { + return current_loading_id; + } +#endif + else { return 0; } } -static VSTInfo * -vstfx_get_info_from_file(char* dllpath, bool &found) +static bool +vstfx_get_info_from_file(char* dllpath, vector *infos) { FILE* infofile; - VSTInfo *info = 0; - found = false; + bool rv = false; if ((infofile = vstfx_infofile_for_read (dllpath)) != 0) { - found = true; - info = load_vstfx_info_file (infofile); + rv = vstfx_load_info_file(infofile, infos); fclose (infofile); - if (info == 0) { + if (!rv) { PBD::warning << "Cannot get LinuxVST information form " << dllpath << ": info file load failed." << endmsg; } } - return info; + return rv; } void @@ -391,35 +473,46 @@ vstfx_free_info (VSTInfo *info) free (info); } +void +vstfx_free_info_list (vector *infos) +{ + for (vector::iterator i = infos->begin(); i != infos->end(); ++i) { + vstfx_free_info(*i); + } + delete infos; +} + #ifdef LXVST_SUPPORT /** Try to get plugin info - first by looking for a .fsi cache of the data, and if that doesn't exist, load the plugin, get its data and then cache it for future ref */ -VSTInfo * +vector * vstfx_get_info_lx (char* dllpath) { FILE* infofile; VSTHandle* h; VSTState* vstfx; + vector *infos = new vector; - bool used_cache; - VSTInfo* info = vstfx_get_info_from_file(dllpath, used_cache); - if (used_cache) { + // TODO check blacklist + // TODO pre-check file extension ? + + if (vstfx_get_info_from_file(dllpath, infos)) { PBD::info << "using cache for LinuxVST plugin '" << dllpath << "'" << endmsg; - return info; + return infos; } if (!(h = vstfx_load(dllpath))) { PBD::warning << "Cannot get LinuxVST information from " << dllpath << ": load failed." << endmsg; - return 0; + return infos; } if (!(vstfx = vstfx_instantiate(h, simple_master_callback, 0))) { vstfx_unload(h); PBD::warning << "Cannot get LinuxVST information from " << dllpath << ": instantiation failed." << endmsg; - return 0; + return infos; } infofile = vstfx_infofile_for_write (dllpath); @@ -431,44 +524,46 @@ vstfx_get_info_lx (char* dllpath) return 0; } - info = vstfx_info_from_plugin (vstfx); + VSTInfo* info = vstfx_info_from_plugin (vstfx); + infos->push_back(info); //XXX - save_vstfx_info_file (info, infofile); + vstfx_write_info_file (infofile, infos); fclose (infofile); vstfx_close (vstfx); vstfx_unload (h); - - return info; + return infos; } #endif #ifdef WINDOWS_VST_SUPPORT #include -VSTInfo * +vector * vstfx_get_info_fst (char* dllpath) { FILE* infofile; VSTHandle* h; VSTState* vstfx; + vector *infos = new vector; + + // TODO check blacklist + // TODO pre-check file extension ? - bool used_cache; - VSTInfo* info = vstfx_get_info_from_file(dllpath, used_cache); - if (used_cache) { + if (vstfx_get_info_from_file(dllpath, infos)) { PBD::info << "using cache for VST plugin '" << dllpath << "'" << endmsg; - return info; + return infos; } if(!(h = fst_load(dllpath))) { PBD::warning << "Cannot get VST information from " << dllpath << ": load failed." << endmsg; - return 0; + return infos; } if(!(vstfx = fst_instantiate(h, simple_master_callback, 0))) { fst_unload(&h); PBD::warning << "Cannot get VST information from " << dllpath << ": instantiation failed." << endmsg; - return 0; + return infos; } infofile = vstfx_infofile_for_write (dllpath); @@ -480,13 +575,14 @@ vstfx_get_info_fst (char* dllpath) return 0; } - info = vstfx_info_from_plugin(vstfx); - save_vstfx_info_file (info, infofile); + VSTInfo* info = vstfx_info_from_plugin(vstfx); + infos->push_back(info); //XXX + + vstfx_write_info_file (infofile, infos); fclose (infofile); fst_close(vstfx); //fst_unload(&h); // XXX -> fst_close() - - return info; + return infos; } #endif diff --git a/libs/ardour/windows_vst_plugin.cc b/libs/ardour/windows_vst_plugin.cc index 9fe9ba0049..e8afb67c1d 100644 --- a/libs/ardour/windows_vst_plugin.cc +++ b/libs/ardour/windows_vst_plugin.cc @@ -31,9 +31,11 @@ using namespace PBD; WindowsVSTPlugin::WindowsVSTPlugin (AudioEngine& e, Session& session, VSTHandle* h) : VSTPlugin (e, session, h) { + Session::vst_current_loading_id = 0; // TODO if ((_state = fst_instantiate (_handle, Session::vst_callback, this)) == 0) { throw failed_constructor(); } + Session::vst_current_loading_id = 0; set_plugin (_state->plugin); } @@ -43,9 +45,11 @@ WindowsVSTPlugin::WindowsVSTPlugin (const WindowsVSTPlugin &other) { _handle = other._handle; + Session::vst_current_loading_id = PBD::atoi(other.unique_id()); if ((_state = fst_instantiate (_handle, Session::vst_callback, this)) == 0) { throw failed_constructor(); } + Session::vst_current_loading_id = 0; _plugin = _state->plugin; } -- cgit v1.2.3