Chris@4: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@5: /* Chris@20: Copyright (c) 2016 Queen Mary, University of London Chris@5: Chris@20: Permission is hereby granted, free of charge, to any person Chris@20: obtaining a copy of this software and associated documentation Chris@20: files (the "Software"), to deal in the Software without Chris@20: restriction, including without limitation the rights to use, copy, Chris@20: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@20: of the Software, and to permit persons to whom the Software is Chris@20: furnished to do so, subject to the following conditions: Chris@5: Chris@20: The above copyright notice and this permission notice shall be Chris@20: included in all copies or substantial portions of the Software. Chris@5: Chris@20: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@20: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@20: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@20: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY Chris@20: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@20: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@20: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@5: Chris@20: Except as contained in this notice, the names of the Centre for Chris@20: Digital Music and Queen Mary, University of London shall not be Chris@20: used in advertising or otherwise to promote the sale, use or other Chris@20: dealings in this Software without prior written authorization. Chris@5: */ Chris@4: Chris@4: #include "knownplugins.h" Chris@4: Chris@4: #include Chris@4: Chris@4: using namespace std; Chris@4: Chris@4: #if defined(_WIN32) Chris@4: #define PATH_SEPARATOR ';' Chris@4: #else Chris@4: #define PATH_SEPARATOR ':' Chris@4: #endif Chris@4: Chris@6: KnownPlugins::KnownPlugins(string helperExecutableName, Chris@6: PluginCandidates::LogCallback *cb) : Chris@20: m_candidates(helperExecutableName), Chris@20: m_helperExecutableName(helperExecutableName) Chris@4: { Chris@6: m_candidates.setLogCallback(cb); Chris@34: Chris@34: std::string variableSuffix = ""; Chris@34: if (is32bit()) { Chris@34: variableSuffix = "_32"; Chris@34: } Chris@6: Chris@34: m_known[VampPlugin] = { Chris@34: "vamp", Chris@34: "VAMP_PATH" + variableSuffix, Chris@34: expandConventionalPath(VampPlugin, "VAMP_PATH" + variableSuffix), Chris@34: "vampGetPluginDescriptor" Chris@34: }; Chris@34: Chris@34: m_known[LADSPAPlugin] = { Chris@34: "ladspa", Chris@34: "LADSPA_PATH" + variableSuffix, Chris@34: expandConventionalPath(LADSPAPlugin, "LADSPA_PATH" + variableSuffix), Chris@34: "ladspa_descriptor" Chris@34: }; Chris@34: Chris@34: m_known[DSSIPlugin] = { Chris@34: "dssi", Chris@34: "DSSI_PATH" + variableSuffix, Chris@34: expandConventionalPath(DSSIPlugin, "DSSI_PATH" + variableSuffix), Chris@34: "dssi_descriptor" Chris@4: }; Chris@4: Chris@4: for (const auto &k: m_known) { Chris@19: m_candidates.scan(k.second.tag, k.second.path, k.second.descriptor); Chris@4: } Chris@4: } Chris@4: Chris@34: std::vector Chris@34: KnownPlugins::getKnownPluginTypes() const Chris@34: { Chris@34: std::vector kt; Chris@34: Chris@34: for (const auto &k: m_known) { Chris@34: kt.push_back(k.first); Chris@34: } Chris@34: Chris@34: return kt; Chris@34: } Chris@34: Chris@20: bool Chris@20: KnownPlugins::is32bit() const Chris@20: { Chris@20: return m_helperExecutableName.find("-32") != std::string::npos; Chris@20: } Chris@20: Chris@4: string Chris@4: KnownPlugins::getDefaultPath(PluginType type) Chris@4: { Chris@4: switch (type) { Chris@4: Chris@4: #if defined(_WIN32) Chris@4: Chris@4: case VampPlugin: Chris@19: return "%ProgramFiles%\\Vamp Plugins"; Chris@4: case LADSPAPlugin: Chris@19: return "%ProgramFiles%\\LADSPA Plugins;%ProgramFiles%\\Audacity\\Plug-Ins"; Chris@4: case DSSIPlugin: Chris@19: return "%ProgramFiles%\\DSSI Plugins"; Chris@19: Chris@4: #elif defined(__APPLE__) Chris@19: Chris@4: case VampPlugin: Chris@19: return "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"; Chris@4: case LADSPAPlugin: Chris@19: return "$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA"; Chris@4: case DSSIPlugin: Chris@19: return "$HOME/Library/Audio/Plug-Ins/DSSI:/Library/Audio/Plug-Ins/DSSI"; Chris@19: Chris@4: #else /* Linux, BSDs, etc */ Chris@19: Chris@4: case VampPlugin: Chris@19: return "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"; Chris@4: case LADSPAPlugin: Chris@19: return "$HOME/ladspa:$HOME/.ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa"; Chris@4: case DSSIPlugin: Chris@19: return "$HOME/dssi:$HOME/.dssi:/usr/local/lib/dssi:/usr/lib/dssi"; Chris@4: #endif Chris@4: } Chris@4: Chris@4: throw logic_error("unknown or unhandled plugin type"); Chris@4: } Chris@4: Chris@4: vector Chris@4: KnownPlugins::expandConventionalPath(PluginType type, string var) Chris@4: { Chris@4: vector pathList; Chris@4: string path; Chris@4: Chris@4: char *cpath = getenv(var.c_str()); Chris@4: if (cpath) path = cpath; Chris@4: Chris@4: if (path == "") { Chris@4: Chris@4: path = getDefaultPath(type); Chris@4: Chris@19: if (path != "") { Chris@4: Chris@19: char *home = getenv("HOME"); Chris@19: if (home) { Chris@19: string::size_type f; Chris@19: while ((f = path.find("$HOME")) != string::npos && Chris@19: f < path.length()) { Chris@19: path.replace(f, 5, home); Chris@19: } Chris@19: } Chris@4: Chris@4: #ifdef _WIN32 Chris@20: const char *pfiles = 0; Chris@34: const char *pfiles32 = 0; Chris@34: Chris@34: pfiles = getenv("ProgramFiles"); Chris@34: if (!pfiles) { Chris@34: pfiles = "C:\\Program Files"; Chris@20: } Chris@34: Chris@34: pfiles32 = getenv("ProgramFiles(x86)"); Chris@34: if (!pfiles32) { Chris@34: pfiles32 = "C:\\Program Files (x86)"; Chris@20: } Chris@34: Chris@20: string::size_type f; Chris@20: while ((f = path.find("%ProgramFiles%")) != string::npos && Chris@20: f < path.length()) { Chris@34: if (is32bit()) { Chris@34: path.replace(f, 14, pfiles32); Chris@34: } else { Chris@34: path.replace(f, 14, pfiles); Chris@34: } Chris@20: } Chris@4: #endif Chris@19: } Chris@4: } Chris@4: Chris@4: string::size_type index = 0, newindex = 0; Chris@4: Chris@4: while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) { Chris@19: pathList.push_back(path.substr(index, newindex - index).c_str()); Chris@19: index = newindex + 1; Chris@4: } Chris@4: Chris@4: pathList.push_back(path.substr(index)); Chris@4: Chris@4: return pathList; Chris@4: } Chris@4: Chris@4: string Chris@4: KnownPlugins::getFailureReport() const Chris@4: { Chris@4: vector failures; Chris@4: Chris@4: for (auto t: getKnownPluginTypes()) { Chris@19: auto ff = m_candidates.getFailedLibrariesFor(getTagFor(t)); Chris@19: failures.insert(failures.end(), ff.begin(), ff.end()); Chris@4: } Chris@4: Chris@4: if (failures.empty()) return ""; Chris@4: Chris@15: int n = int(failures.size()); Chris@4: int i = 0; Chris@4: Chris@4: ostringstream os; Chris@4: Chris@4: os << "
    "; Chris@4: for (auto f: failures) { Chris@19: os << "
  • " + f.library; Chris@19: if (f.message != "") { Chris@19: os << "
    " + f.message + ""; Chris@19: } else { Chris@19: os << "
    unknown error"; Chris@19: } Chris@19: os << "
  • "; Chris@4: Chris@19: if (n > 10) { Chris@19: if (++i == 5) { Chris@19: os << "
  • (... and " << (n - i) << " further failures)
  • "; Chris@19: break; Chris@19: } Chris@19: } Chris@4: } Chris@4: os << "
"; Chris@4: Chris@4: return os.str(); Chris@4: }