annotate src/vamp-hostsdk/Files.cpp @ 434:e979a9c4ffb6 vampipe

Switch from Cross FFT with option of FFTW build, to KissFFT only (code bundled). This is much faster than the default build and simpler than managing two options.
author Chris Cannam
date Tue, 16 Aug 2016 16:04:09 +0100
parents 35fa4733bc5d
children 79a219ba6178
rev   line source
Chris@390 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@390 2
Chris@390 3 /*
Chris@390 4 Vamp
Chris@390 5
Chris@390 6 An API for audio analysis and feature extraction plugins.
Chris@390 7
Chris@390 8 Centre for Digital Music, Queen Mary, University of London.
Chris@390 9 Copyright 2006-2015 Chris Cannam and QMUL.
Chris@390 10
Chris@390 11 Permission is hereby granted, free of charge, to any person
Chris@390 12 obtaining a copy of this software and associated documentation
Chris@390 13 files (the "Software"), to deal in the Software without
Chris@390 14 restriction, including without limitation the rights to use, copy,
Chris@390 15 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@390 16 of the Software, and to permit persons to whom the Software is
Chris@390 17 furnished to do so, subject to the following conditions:
Chris@390 18
Chris@390 19 The above copyright notice and this permission notice shall be
Chris@390 20 included in all copies or substantial portions of the Software.
Chris@390 21
Chris@390 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@390 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@390 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@390 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@390 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@390 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@390 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@390 29
Chris@390 30 Except as contained in this notice, the names of the Centre for
Chris@390 31 Digital Music; Queen Mary, University of London; and Chris Cannam
Chris@390 32 shall not be used in advertising or otherwise to promote the sale,
Chris@390 33 use or other dealings in this Software without prior written
Chris@390 34 authorization.
Chris@390 35 */
Chris@390 36
Chris@390 37 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@390 38
Chris@390 39 #include "Files.h"
Chris@390 40
Chris@390 41 #include <cctype> // tolower
Chris@390 42
Chris@390 43 #include <cstring>
Chris@390 44
Chris@390 45 #ifdef _WIN32
Chris@390 46
Chris@390 47 #include <windows.h>
Chris@390 48 #include <tchar.h>
Chris@390 49 #define PLUGIN_SUFFIX "dll"
Chris@390 50
Chris@390 51 #else /* ! _WIN32 */
Chris@390 52
Chris@390 53 #include <dirent.h>
Chris@390 54 #include <dlfcn.h>
Chris@390 55
Chris@390 56 #ifdef __APPLE__
Chris@390 57 #define PLUGIN_SUFFIX "dylib"
Chris@390 58 #else /* ! __APPLE__ */
Chris@390 59 #define PLUGIN_SUFFIX "so"
Chris@390 60 #endif /* ! __APPLE__ */
Chris@390 61
Chris@390 62 #endif /* ! _WIN32 */
Chris@390 63
Chris@390 64 using namespace std;
Chris@390 65
Chris@390 66 vector<string>
Chris@390 67 Files::listLibraryFiles()
Chris@390 68 {
Chris@390 69 return listLibraryFilesMatching("");
Chris@390 70 }
Chris@390 71
Chris@390 72 vector<string>
Chris@390 73 Files::listLibraryFilesMatching(string libraryName)
Chris@390 74 {
Chris@390 75 vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
Chris@390 76 vector<string> libraryFiles;
Chris@390 77
Chris@421 78 // we match case-insensitively, but only with ascii range
Chris@421 79 // characters (this string is expected to be utf-8)
Chris@390 80 for (size_t i = 0; i < libraryName.length(); ++i) {
Chris@421 81 if (!(libraryName[i] & 0x80)) {
Chris@421 82 libraryName[i] = char(tolower(libraryName[i]));
Chris@421 83 }
Chris@390 84 }
Chris@390 85
Chris@390 86 for (size_t i = 0; i < path.size(); ++i) {
Chris@390 87
Chris@390 88 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
Chris@390 89
Chris@390 90 for (vector<string>::iterator fi = files.begin();
Chris@390 91 fi != files.end(); ++fi) {
Chris@390 92
Chris@390 93 if (libraryName != "") {
Chris@421 94 // we match case-insensitively, but only with ascii
Chris@421 95 // range characters (this string is expected to be
Chris@421 96 // utf-8)
Chris@390 97 string temp = *fi;
Chris@390 98 for (size_t i = 0; i < temp.length(); ++i) {
Chris@421 99 if (!(temp[i] & 0x80)) {
Chris@421 100 temp[i] = char(tolower(temp[i]));
Chris@421 101 }
Chris@390 102 }
Chris@390 103 // libraryName should be lacking an extension, as it
Chris@390 104 // is supposed to have come from the plugin key
Chris@390 105 string::size_type pi = temp.find('.');
Chris@390 106 if (pi == string::npos) {
Chris@390 107 if (libraryName != temp) continue;
Chris@390 108 } else {
Chris@390 109 if (libraryName != temp.substr(0, pi)) continue;
Chris@390 110 }
Chris@390 111 }
Chris@390 112
Chris@390 113 string fullPath = path[i];
Chris@390 114 fullPath = splicePath(fullPath, *fi);
Chris@390 115 libraryFiles.push_back(fullPath);
Chris@390 116 }
Chris@390 117 }
Chris@390 118
Chris@390 119 return libraryFiles;
Chris@390 120 }
Chris@390 121
Chris@390 122 void *
Chris@390 123 Files::loadLibrary(string path)
Chris@390 124 {
Chris@390 125 void *handle = 0;
Chris@390 126 #ifdef _WIN32
Chris@390 127 #ifdef UNICODE
Chris@390 128 int len = path.length() + 1; // cannot be more wchars than length in bytes of utf8 string
Chris@390 129 wchar_t *buffer = new wchar_t[len];
Chris@390 130 int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
Chris@390 131 if (rv <= 0) {
Chris@390 132 cerr << "Vamp::HostExt: Unable to convert library path \""
Chris@390 133 << path << "\" to wide characters " << endl;
Chris@390 134 delete[] buffer;
Chris@390 135 return handle;
Chris@390 136 }
Chris@390 137 handle = LoadLibrary(buffer);
Chris@390 138 delete[] buffer;
Chris@390 139 #else
Chris@390 140 handle = LoadLibrary(path.c_str());
Chris@390 141 #endif
Chris@390 142 if (!handle) {
Chris@390 143 cerr << "Vamp::HostExt: Unable to load library \""
Chris@390 144 << path << "\"" << endl;
Chris@390 145 }
Chris@390 146 #else
Chris@390 147 handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
Chris@390 148 if (!handle) {
Chris@390 149 cerr << "Vamp::HostExt: Unable to load library \""
Chris@390 150 << path << "\": " << dlerror() << endl;
Chris@390 151 }
Chris@390 152 #endif
Chris@390 153 return handle;
Chris@390 154 }
Chris@390 155
Chris@390 156 void
Chris@390 157 Files::unloadLibrary(void *handle)
Chris@390 158 {
Chris@390 159 #ifdef _WIN32
Chris@390 160 FreeLibrary((HINSTANCE)handle);
Chris@390 161 #else
Chris@390 162 dlclose(handle);
Chris@390 163 #endif
Chris@390 164 }
Chris@390 165
Chris@390 166 void *
Chris@390 167 Files::lookupInLibrary(void *handle, const char *symbol)
Chris@390 168 {
Chris@390 169 #ifdef _WIN32
Chris@390 170 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
Chris@390 171 #else
Chris@390 172 return (void *)dlsym(handle, symbol);
Chris@390 173 #endif
Chris@390 174 }
Chris@390 175
Chris@390 176 string
Chris@390 177 Files::lcBasename(string path)
Chris@390 178 {
Chris@390 179 string basename(path);
Chris@390 180
Chris@390 181 string::size_type li = basename.rfind('/');
Chris@390 182 if (li != string::npos) basename = basename.substr(li + 1);
Chris@390 183
Chris@403 184 #ifdef _WIN32
Chris@405 185 li = basename.rfind('\\');
Chris@403 186 if (li != string::npos) basename = basename.substr(li + 1);
Chris@403 187 #endif
Chris@403 188
Chris@390 189 li = basename.find('.');
Chris@390 190 if (li != string::npos) basename = basename.substr(0, li);
Chris@390 191
Chris@421 192 // case-insensitive, but only with ascii range characters (this
Chris@421 193 // string is expected to be utf-8)
Chris@390 194 for (size_t i = 0; i < basename.length(); ++i) {
Chris@421 195 if (!(basename[i] & 0x80)) {
Chris@421 196 basename[i] = char(tolower(basename[i]));
Chris@421 197 }
Chris@390 198 }
Chris@390 199
Chris@390 200 return basename;
Chris@390 201 }
Chris@390 202
Chris@390 203 string
Chris@390 204 Files::splicePath(string a, string b)
Chris@390 205 {
Chris@390 206 #ifdef _WIN32
Chris@390 207 return a + "\\" + b;
Chris@390 208 #else
Chris@390 209 return a + "/" + b;
Chris@390 210 #endif
Chris@390 211 }
Chris@390 212
Chris@390 213 vector<string>
Chris@390 214 Files::listFiles(string dir, string extension)
Chris@390 215 {
Chris@390 216 vector<string> files;
Chris@390 217
Chris@390 218 #ifdef _WIN32
Chris@390 219 string expression = dir + "\\*." + extension;
Chris@390 220 #ifdef UNICODE
Chris@390 221 int len = expression.length() + 1; // cannot be more wchars than length in bytes of utf8 string
Chris@390 222 wchar_t *buffer = new wchar_t[len];
Chris@390 223 int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
Chris@390 224 if (rv <= 0) {
Chris@390 225 cerr << "Vamp::HostExt: Unable to convert wildcard path \""
Chris@390 226 << expression << "\" to wide characters" << endl;
Chris@390 227 delete[] buffer;
Chris@390 228 return files;
Chris@390 229 }
Chris@390 230 WIN32_FIND_DATA data;
Chris@390 231 HANDLE fh = FindFirstFile(buffer, &data);
Chris@390 232 if (fh == INVALID_HANDLE_VALUE) {
Chris@390 233 delete[] buffer;
Chris@390 234 return files;
Chris@390 235 }
Chris@390 236
Chris@390 237 bool ok = true;
Chris@390 238 while (ok) {
Chris@390 239 wchar_t *fn = data.cFileName;
Chris@390 240 int wlen = wcslen(fn) + 1;
Chris@390 241 int maxlen = wlen * 6;
Chris@390 242 char *conv = new char[maxlen];
Chris@390 243 int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
Chris@390 244 if (rv > 0) {
Chris@390 245 files.push_back(conv);
Chris@390 246 }
Chris@390 247 delete[] conv;
Chris@390 248 ok = FindNextFile(fh, &data);
Chris@390 249 }
Chris@390 250
Chris@390 251 FindClose(fh);
Chris@390 252 delete[] buffer;
Chris@390 253 #else
Chris@390 254 WIN32_FIND_DATA data;
Chris@390 255 HANDLE fh = FindFirstFile(expression.c_str(), &data);
Chris@390 256 if (fh == INVALID_HANDLE_VALUE) return files;
Chris@390 257
Chris@390 258 bool ok = true;
Chris@390 259 while (ok) {
Chris@390 260 files.push_back(data.cFileName);
Chris@390 261 ok = FindNextFile(fh, &data);
Chris@390 262 }
Chris@390 263
Chris@390 264 FindClose(fh);
Chris@390 265 #endif
Chris@390 266 #else
Chris@390 267
Chris@390 268 size_t extlen = extension.length();
Chris@390 269 DIR *d = opendir(dir.c_str());
Chris@390 270 if (!d) return files;
Chris@390 271
Chris@390 272 struct dirent *e = 0;
Chris@390 273 while ((e = readdir(d))) {
Chris@390 274
Chris@390 275 size_t len = strlen(e->d_name);
Chris@390 276 if (len < extlen + 2 ||
Chris@390 277 e->d_name + len - extlen - 1 != "." + extension) {
Chris@390 278 continue;
Chris@390 279 }
Chris@390 280
Chris@390 281 files.push_back(e->d_name);
Chris@390 282 }
Chris@390 283
Chris@390 284 closedir(d);
Chris@390 285 #endif
Chris@390 286
Chris@390 287 return files;
Chris@390 288 }