| Chris@4 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@5 | 2 /* | 
| Chris@5 | 3     Copyright (c) 2016 Queen Mary, University of London | 
| Chris@5 | 4 | 
| Chris@5 | 5     Permission is hereby granted, free of charge, to any person | 
| Chris@5 | 6     obtaining a copy of this software and associated documentation | 
| Chris@5 | 7     files (the "Software"), to deal in the Software without | 
| Chris@5 | 8     restriction, including without limitation the rights to use, copy, | 
| Chris@5 | 9     modify, merge, publish, distribute, sublicense, and/or sell copies | 
| Chris@5 | 10     of the Software, and to permit persons to whom the Software is | 
| Chris@5 | 11     furnished to do so, subject to the following conditions: | 
| Chris@5 | 12 | 
| Chris@5 | 13     The above copyright notice and this permission notice shall be | 
| Chris@5 | 14     included in all copies or substantial portions of the Software. | 
| Chris@5 | 15 | 
| Chris@5 | 16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 
| Chris@5 | 17     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 
| Chris@5 | 18     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 
| Chris@5 | 19     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | 
| Chris@5 | 20     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | 
| Chris@5 | 21     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | 
| Chris@5 | 22     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 
| Chris@5 | 23 | 
| Chris@5 | 24     Except as contained in this notice, the names of the Centre for | 
| Chris@5 | 25     Digital Music and Queen Mary, University of London shall not be | 
| Chris@5 | 26     used in advertising or otherwise to promote the sale, use or other | 
| Chris@5 | 27     dealings in this Software without prior written authorization. | 
| Chris@5 | 28 */ | 
| Chris@4 | 29 | 
| Chris@4 | 30 #include "knownplugins.h" | 
| Chris@4 | 31 | 
| Chris@4 | 32 #include <sstream> | 
| Chris@4 | 33 | 
| Chris@4 | 34 using namespace std; | 
| Chris@4 | 35 | 
| Chris@4 | 36 #if defined(_WIN32) | 
| Chris@4 | 37 #define PATH_SEPARATOR ';' | 
| Chris@4 | 38 #else | 
| Chris@4 | 39 #define PATH_SEPARATOR ':' | 
| Chris@4 | 40 #endif | 
| Chris@4 | 41 | 
| Chris@6 | 42 KnownPlugins::KnownPlugins(string helperExecutableName, | 
| Chris@6 | 43                            PluginCandidates::LogCallback *cb) : | 
| Chris@6 | 44     m_candidates(helperExecutableName) | 
| Chris@4 | 45 { | 
| Chris@6 | 46     m_candidates.setLogCallback(cb); | 
| Chris@6 | 47 | 
| Chris@4 | 48     m_known = { | 
| Chris@4 | 49 	{ | 
| Chris@4 | 50 	    VampPlugin, | 
| Chris@4 | 51 	    { | 
| Chris@4 | 52 		"vamp", | 
| Chris@4 | 53 		expandConventionalPath(VampPlugin, "VAMP_PATH"), | 
| Chris@4 | 54 		"vampGetPluginDescriptor" | 
| Chris@4 | 55 	    }, | 
| Chris@4 | 56 	}, { | 
| Chris@4 | 57 	    LADSPAPlugin, | 
| Chris@4 | 58 	    { | 
| Chris@4 | 59 		"ladspa", | 
| Chris@4 | 60 		expandConventionalPath(LADSPAPlugin, "LADSPA_PATH"), | 
| Chris@4 | 61 		"ladspa_descriptor" | 
| Chris@4 | 62 	    }, | 
| Chris@4 | 63 	}, { | 
| Chris@4 | 64 	    DSSIPlugin, | 
| Chris@4 | 65 	    { | 
| Chris@4 | 66 		"dssi", | 
| Chris@4 | 67 		expandConventionalPath(DSSIPlugin, "DSSI_PATH"), | 
| Chris@4 | 68 		"dssi_descriptor" | 
| Chris@4 | 69 	    } | 
| Chris@4 | 70 	} | 
| Chris@4 | 71     }; | 
| Chris@4 | 72 | 
| Chris@4 | 73     for (const auto &k: m_known) { | 
| Chris@4 | 74 	m_candidates.scan(k.second.tag, k.second.path, k.second.descriptor); | 
| Chris@4 | 75     } | 
| Chris@4 | 76 } | 
| Chris@4 | 77 | 
| Chris@4 | 78 string | 
| Chris@4 | 79 KnownPlugins::getDefaultPath(PluginType type) | 
| Chris@4 | 80 { | 
| Chris@4 | 81     switch (type) { | 
| Chris@4 | 82 | 
| Chris@4 | 83 #if defined(_WIN32) | 
| Chris@4 | 84 | 
| Chris@4 | 85     case VampPlugin: | 
| Chris@4 | 86 	return "%ProgramFiles%\\Vamp Plugins"; | 
| Chris@4 | 87     case LADSPAPlugin: | 
| Chris@4 | 88 	return "%ProgramFiles%\\LADSPA Plugins;%ProgramFiles%\\Audacity\\Plug-Ins"; | 
| Chris@4 | 89     case DSSIPlugin: | 
| Chris@4 | 90 	return "%ProgramFiles%\\DSSI Plugins"; | 
| Chris@4 | 91 | 
| Chris@4 | 92 #elif defined(__APPLE__) | 
| Chris@4 | 93 | 
| Chris@4 | 94     case VampPlugin: | 
| Chris@4 | 95 	return "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"; | 
| Chris@4 | 96     case LADSPAPlugin: | 
| Chris@4 | 97 	return "$HOME/Library/Audio/Plug-Ins/LADSPA:/Library/Audio/Plug-Ins/LADSPA"; | 
| Chris@4 | 98     case DSSIPlugin: | 
| Chris@4 | 99 	return "$HOME/Library/Audio/Plug-Ins/DSSI:/Library/Audio/Plug-Ins/DSSI"; | 
| Chris@4 | 100 | 
| Chris@4 | 101 #else /* Linux, BSDs, etc */ | 
| Chris@4 | 102 | 
| Chris@4 | 103     case VampPlugin: | 
| Chris@4 | 104 	return "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"; | 
| Chris@4 | 105     case LADSPAPlugin: | 
| Chris@4 | 106 	return "$HOME/ladspa:$HOME/.ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa"; | 
| Chris@4 | 107     case DSSIPlugin: | 
| Chris@4 | 108 	return "$HOME/dssi:$HOME/.dssi:/usr/local/lib/dssi:/usr/lib/dssi"; | 
| Chris@4 | 109 #endif | 
| Chris@4 | 110     } | 
| Chris@4 | 111 | 
| Chris@4 | 112     throw logic_error("unknown or unhandled plugin type"); | 
| Chris@4 | 113 } | 
| Chris@4 | 114 | 
| Chris@4 | 115 vector<string> | 
| Chris@4 | 116 KnownPlugins::expandConventionalPath(PluginType type, string var) | 
| Chris@4 | 117 { | 
| Chris@4 | 118     vector<string> pathList; | 
| Chris@4 | 119     string path; | 
| Chris@4 | 120 | 
| Chris@4 | 121     char *cpath = getenv(var.c_str()); | 
| Chris@4 | 122     if (cpath) path = cpath; | 
| Chris@4 | 123 | 
| Chris@4 | 124     if (path == "") { | 
| Chris@4 | 125 | 
| Chris@4 | 126         path = getDefaultPath(type); | 
| Chris@4 | 127 | 
| Chris@4 | 128 	if (path != "") { | 
| Chris@4 | 129 | 
| Chris@4 | 130 	    char *home = getenv("HOME"); | 
| Chris@4 | 131 	    if (home) { | 
| Chris@4 | 132 		string::size_type f; | 
| Chris@4 | 133 		while ((f = path.find("$HOME")) != string::npos && | 
| Chris@4 | 134 		       f < path.length()) { | 
| Chris@4 | 135 		    path.replace(f, 5, home); | 
| Chris@4 | 136 		} | 
| Chris@4 | 137 	    } | 
| Chris@4 | 138 | 
| Chris@4 | 139 #ifdef _WIN32 | 
| Chris@4 | 140 	    char *pfiles = getenv("ProgramFiles"); | 
| Chris@4 | 141 	    if (!pfiles) pfiles = "C:\\Program Files"; | 
| Chris@4 | 142 	    { | 
| Chris@4 | 143 		string::size_type f; | 
| Chris@4 | 144 		while ((f = path.find("%ProgramFiles%")) != string::npos && | 
| Chris@4 | 145 		       f < path.length()) { | 
| Chris@4 | 146 		    path.replace(f, 14, pfiles); | 
| Chris@4 | 147 		} | 
| Chris@4 | 148 	    } | 
| Chris@4 | 149 #endif | 
| Chris@4 | 150 	} | 
| Chris@4 | 151     } | 
| Chris@4 | 152 | 
| Chris@4 | 153     string::size_type index = 0, newindex = 0; | 
| Chris@4 | 154 | 
| Chris@4 | 155     while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) { | 
| Chris@4 | 156 	pathList.push_back(path.substr(index, newindex - index).c_str()); | 
| Chris@4 | 157 	index = newindex + 1; | 
| Chris@4 | 158     } | 
| Chris@4 | 159 | 
| Chris@4 | 160     pathList.push_back(path.substr(index)); | 
| Chris@4 | 161 | 
| Chris@4 | 162     return pathList; | 
| Chris@4 | 163 } | 
| Chris@4 | 164 | 
| Chris@4 | 165 string | 
| Chris@4 | 166 KnownPlugins::getFailureReport() const | 
| Chris@4 | 167 { | 
| Chris@4 | 168     vector<PluginCandidates::FailureRec> failures; | 
| Chris@4 | 169 | 
| Chris@4 | 170     for (auto t: getKnownPluginTypes()) { | 
| Chris@4 | 171 	auto ff = m_candidates.getFailedLibrariesFor(getTagFor(t)); | 
| Chris@4 | 172 	failures.insert(failures.end(), ff.begin(), ff.end()); | 
| Chris@4 | 173     } | 
| Chris@4 | 174 | 
| Chris@4 | 175     if (failures.empty()) return ""; | 
| Chris@4 | 176 | 
| Chris@4 | 177     int n = failures.size(); | 
| Chris@4 | 178     int i = 0; | 
| Chris@4 | 179 | 
| Chris@4 | 180     ostringstream os; | 
| Chris@4 | 181 | 
| Chris@4 | 182     os << "<ul>"; | 
| Chris@4 | 183     for (auto f: failures) { | 
| Chris@4 | 184 	os << "<li>" + f.library; | 
| Chris@4 | 185 	if (f.message != "") { | 
| Chris@4 | 186 	    os << " (" + f.message + ")"; | 
| Chris@4 | 187 	} else { | 
| Chris@4 | 188 	    os << " (unknown error)"; | 
| Chris@4 | 189 	} | 
| Chris@4 | 190 	os << "</li>"; | 
| Chris@4 | 191 | 
| Chris@4 | 192 	if (n > 10) { | 
| Chris@4 | 193 	    if (++i == 5) { | 
| Chris@4 | 194 		os << "<li>(... and " << (n - i) << " further failures)</li>"; | 
| Chris@4 | 195 		break; | 
| Chris@4 | 196 	    } | 
| Chris@4 | 197 	} | 
| Chris@4 | 198     } | 
| Chris@4 | 199     os << "</ul>"; | 
| Chris@4 | 200 | 
| Chris@4 | 201     return os.str(); | 
| Chris@4 | 202 } |