comparison host/vamp-simple-host.cpp @ 64:9d3272c7db60

* Merge from host-factory-stuff branch: this adds several helper classes in the hostext directory that should make a host's life much easier. This will become version 1.1 of the SDK, eventually.
author cannam
date Fri, 01 Jun 2007 15:10:17 +0000
parents d3995d2b5e08
children 6d16c376fd2f
comparison
equal deleted inserted replaced
54:933fee59d33a 64:9d3272c7db60
33 shall not be used in advertising or otherwise to promote the sale, 33 shall not be used in advertising or otherwise to promote the sale,
34 use or other dealings in this Software without prior written 34 use or other dealings in this Software without prior written
35 authorization. 35 authorization.
36 */ 36 */
37 37
38 #include "PluginHostAdapter.h" 38 #include "vamp-sdk/PluginHostAdapter.h"
39 #include "vamp.h" 39 #include "vamp-sdk/hostext/PluginChannelAdapter.h"
40 #include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
41 #include "vamp-sdk/hostext/PluginLoader.h"
42 #include "vamp/vamp.h"
40 43
41 #include <iostream> 44 #include <iostream>
42 #include <sndfile.h> 45 #include <sndfile.h>
43 #include <dirent.h> // POSIX directory open and read
44 46
45 #include "system.h" 47 #include "system.h"
46 48
47 #include <cmath> 49 #include <cmath>
48 50
50 using std::cerr; 52 using std::cerr;
51 using std::endl; 53 using std::endl;
52 using std::string; 54 using std::string;
53 using std::vector; 55 using std::vector;
54 56
55 #define HOST_VERSION "1.0" 57 using Vamp::HostExt::PluginLoader;
58
59 #define HOST_VERSION "1.1"
56 60
57 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet); 61 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet);
58 void transformInput(float *, size_t); 62 void transformInput(float *, size_t);
59 void fft(unsigned int, bool, double *, double *, double *, double *); 63 void fft(unsigned int, bool, double *, double *, double *, double *);
60 void printPluginPath(); 64 void printPluginPath(bool verbose);
61
62 #ifdef HAVE_OPENDIR
63 void enumeratePlugins(); 65 void enumeratePlugins();
64 #endif 66 void listPluginsInLibrary(string soname);
65 67 int runPlugin(string myname, string soname, string id, string output,
66 /* 68 int outputNo, string inputFile);
67 A very simple Vamp plugin host. Given the name of a plugin 69
68 library and the name of a sound file on the command line, it loads 70 void usage(const char *name)
69 the first plugin in the library and runs it on the sound file, 71 {
70 dumping the plugin's first output to stdout. 72 cerr << "\n"
71 */ 73 << name << ": A simple Vamp plugin host.\n\n"
74 "Centre for Digital Music, Queen Mary, University of London.\n"
75 "Copyright 2006-2007 Chris Cannam and QMUL.\n"
76 "Freely redistributable; published under a BSD-style license.\n\n"
77 "Usage:\n\n"
78 " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav\n"
79 " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno]\n\n"
80 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
81 " audio data in \"file.wav\"; retrieve the named \"output\", or output\n"
82 " number \"outputno\" (the first output by default) and dump it to\n"
83 " standard output.\n\n"
84 " " << name << " -l\n\n"
85 " -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n"
86 " " << name << " -p\n\n"
87 " -- Print out the Vamp plugin search path.\n\n"
88 " " << name << " -v\n\n"
89 " -- Display version information only.\n\n"
90 << endl;
91 exit(2);
92 }
72 93
73 int main(int argc, char **argv) 94 int main(int argc, char **argv)
74 { 95 {
75 if (argc < 2 || argc > 4) { 96 char *scooter = argv[0];
76 char *scooter = argv[0]; 97 char *name = 0;
77 char *name = 0; 98 while (scooter && *scooter) {
78 while (scooter && *scooter) { 99 if (*scooter == '/' || *scooter == '\\') name = ++scooter;
79 if (*scooter == '/' || *scooter == '\\') name = ++scooter; 100 else ++scooter;
80 else ++scooter; 101 }
81 } 102 if (!name || !*name) name = argv[0];
82 if (!name || !*name) name = argv[0];
83 cerr << "\n"
84 << name << ": A simple Vamp plugin host.\n\n"
85 "Centre for Digital Music, Queen Mary, University of London.\n"
86 "Copyright 2006 Chris Cannam and QMUL.\n"
87 "Freely redistributable; published under a BSD-style license.\n\n"
88 "Usage:\n\n"
89 " " << name << " pluginlibrary." << PLUGIN_SUFFIX << "\n\n"
90 " -- Load \"pluginlibrary\" and list the Vamp plugins it contains.\n\n"
91 " " << name << " pluginlibrary." << PLUGIN_SUFFIX << ":plugin file.wav [outputno]\n\n"
92 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
93 " audio data in \"file.wav\", dumping the output from \"outputno\"\n"
94 " (default 0) to standard output.\n\n"
95 #ifdef HAVE_OPENDIR
96 " " << name << " -l\n\n"
97 " -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n"
98 #endif
99 " " << name << " -p\n\n"
100 " -- Print out the Vamp plugin search path.\n\n"
101 " " << name << " -v\n\n"
102 " -- Display version information only.\n\n"
103 "Note that this host does not use the plugin search path when loadinga plugin.\nIf a plugin library is specified, it should be with a full file path.\n"
104 << endl;
105 return 2;
106 }
107 103
104 if (argc < 2 || argc > 4 ||
105 (argc == 2 &&
106 (!strcmp(argv[1], "-?") ||
107 !strcmp(argv[1], "-h") ||
108 !strcmp(argv[1], "--help")))) {
109
110 usage(name); // does not return
111 }
112
108 if (argc == 2 && !strcmp(argv[1], "-v")) { 113 if (argc == 2 && !strcmp(argv[1], "-v")) {
109 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl 114 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
110 << "Vamp API version: " << VAMP_API_VERSION << endl 115 << "Vamp API version: " << VAMP_API_VERSION << endl
111 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; 116 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
112 return 0; 117 return 0;
113 } 118 }
114 119
115 if (argc == 2 && !strcmp(argv[1], "-l")) { 120 if (argc == 2 && !strcmp(argv[1], "-l")) {
116 #ifdef HAVE_OPENDIR 121 printPluginPath(true);
117 enumeratePlugins(); 122 enumeratePlugins();
118 #endif
119 return 0; 123 return 0;
120 } 124 }
121 if (argc == 2 && !strcmp(argv[1], "-p")) { 125 if (argc == 2 && !strcmp(argv[1], "-p")) {
122 printPluginPath(); 126 printPluginPath(false);
123 return 0; 127 return 0;
124 } 128 }
125 129
126 cerr << endl << argv[0] << ": Running..." << endl; 130 cerr << endl << name << ": Running..." << endl;
127 131
128 string soname = argv[1]; 132 string soname = argv[1];
129 string plugid = ""; 133 string plugid = "";
134 string output = "";
135 int outputNo = -1;
130 string wavname; 136 string wavname;
131 if (argc >= 3) wavname = argv[2]; 137 if (argc >= 3) wavname = argv[2];
132 138
133 int sep = soname.find(":"); 139 string::size_type sep = soname.find(':');
134 if (sep >= 0 && sep < int(soname.length())) { 140
141 if (sep != string::npos) {
135 plugid = soname.substr(sep + 1); 142 plugid = soname.substr(sep + 1);
136 soname = soname.substr(0, sep); 143 soname = soname.substr(0, sep);
137 } 144
138 145 sep = plugid.find(':');
139 void *libraryHandle = DLOPEN(soname, RTLD_LAZY); 146 if (sep != string::npos) {
140 147 output = plugid.substr(sep + 1);
141 if (!libraryHandle) { 148 plugid = plugid.substr(0, sep);
142 cerr << argv[0] << ": Failed to open plugin library " 149 }
143 << soname << ": " << DLERROR() << endl; 150 }
144 return 1; 151
145 } 152 if (plugid == "") {
146 153 usage(name);
147 cerr << argv[0] << ": Opened plugin library " << soname << endl; 154 }
148 155
149 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) 156 if (argc == 4) outputNo = atoi(argv[3]);
150 DLSYM(libraryHandle, "vampGetPluginDescriptor"); 157
151 158 if (output != "" && outputNo != -1) {
152 if (!fn) { 159 usage(name);
153 cerr << argv[0] << ": No Vamp descriptor function in library " 160 }
154 << soname << endl; 161
155 DLCLOSE(libraryHandle); 162 return runPlugin(name, soname, plugid, output, outputNo, wavname);
156 return 1; 163 }
157 } 164
158 165
159 cerr << argv[0] << ": Found plugin descriptor function" << endl; 166 int runPlugin(string myname, string soname, string id,
160 167 string output, int outputNo, string wavname)
161 int index = 0; 168 {
162 int plugnumber = -1; 169 PluginLoader *loader = PluginLoader::getInstance();
163 const VampPluginDescriptor *descriptor = 0; 170
164 171 PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
165 while ((descriptor = fn(VAMP_API_VERSION, index))) {
166
167 Vamp::PluginHostAdapter plugin(descriptor, 48000);
168 cerr << argv[0] << ": Plugin " << (index+1)
169 << " is \"" << plugin.getIdentifier() << "\"" << endl;
170
171 if (plugin.getIdentifier() == plugid) plugnumber = index;
172
173 ++index;
174 }
175
176 cerr << argv[0] << ": Done\n" << endl;
177
178 if (wavname == "") {
179 DLCLOSE(libraryHandle);
180 return 0;
181 }
182
183 if (plugnumber < 0) {
184 if (plugid != "") {
185 cerr << "ERROR: No such plugin as " << plugid << " in library"
186 << endl;
187 DLCLOSE(libraryHandle);
188 return 0;
189 } else {
190 plugnumber = 0;
191 }
192 }
193
194 descriptor = fn(VAMP_API_VERSION, plugnumber);
195 if (!descriptor) {
196 DLCLOSE(libraryHandle);
197 return 0;
198 }
199 172
200 SNDFILE *sndfile; 173 SNDFILE *sndfile;
201 SF_INFO sfinfo; 174 SF_INFO sfinfo;
202 memset(&sfinfo, 0, sizeof(SF_INFO)); 175 memset(&sfinfo, 0, sizeof(SF_INFO));
203 176
204 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); 177 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
205 if (!sndfile) { 178 if (!sndfile) {
206 cerr << "ERROR: Failed to open input file \"" << wavname << "\": " 179 cerr << myname << ": ERROR: Failed to open input file \""
207 << sf_strerror(sndfile) << endl; 180 << wavname << "\": " << sf_strerror(sndfile) << endl;
208 DLCLOSE(libraryHandle);
209 return 1; 181 return 1;
210 } 182 }
211 183
212 Vamp::PluginHostAdapter *plugin = 184 Vamp::Plugin *plugin = loader->loadPlugin
213 new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate); 185 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL);
214 186 if (!plugin) {
215 cerr << "Running " << plugin->getIdentifier() << "..." << endl; 187 cerr << myname << ": ERROR: Failed to load plugin \"" << id
188 << "\" from library \"" << soname << "\"" << endl;
189 sf_close(sndfile);
190 return 1;
191 }
192
193 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
216 194
217 int blockSize = plugin->getPreferredBlockSize(); 195 int blockSize = plugin->getPreferredBlockSize();
218 int stepSize = plugin->getPreferredStepSize(); 196 int stepSize = plugin->getPreferredStepSize();
219
220 cerr << "Preferred block size = " << blockSize << ", step size = "
221 << stepSize << endl;
222
223 if (blockSize == 0) blockSize = 1024;
224
225 bool rightBlockSize = true;
226
227 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
228
229 int p = 1, b = blockSize;
230 while (b) {
231 p <<= 1;
232 b >>= 1;
233 }
234 if (p != blockSize * 2) {
235 cerr << "WARNING: Plugin requested non-power-of-two block size of "
236 << blockSize << ",\nwhich is not supported by this host. ";
237 blockSize = p;
238 cerr << "Rounding up to " << blockSize << "." << endl;
239 rightBlockSize = false;
240 }
241 if (stepSize == 0) stepSize = blockSize / 2;
242
243 } else {
244
245 if (stepSize == 0) stepSize = blockSize;
246 }
247 197
248 int channels = sfinfo.channels; 198 int channels = sfinfo.channels;
249 199
250 float *filebuf = new float[blockSize * channels]; 200 float *filebuf = new float[blockSize * channels];
251 float **plugbuf = new float*[channels]; 201 float **plugbuf = new float*[channels];
255 << stepSize << endl; 205 << stepSize << endl;
256 206
257 int minch = plugin->getMinChannelCount(); 207 int minch = plugin->getMinChannelCount();
258 int maxch = plugin->getMaxChannelCount(); 208 int maxch = plugin->getMaxChannelCount();
259 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; 209 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
210 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
260 211
261 Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors(); 212 Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
262 Vamp::Plugin::OutputDescriptor od; 213 Vamp::Plugin::OutputDescriptor od;
263 214
264 int returnValue = 1; 215 int returnValue = 1;
265 216
266 int output = 0; 217 if (outputs.empty()) {
267 if (argc == 4) output = atoi(argv[3]); 218 cerr << "ERROR: Plugin has no outputs!" << endl;
268 219 goto done;
269 bool mix = false; 220 }
270 221
271 if (minch > channels || maxch < channels) { 222 if (outputNo < 0) {
272 if (minch == 1) { 223
273 cerr << "WARNING: Sound file has " << channels << " channels, mixing down to 1" << endl; 224 for (size_t oi = 0; oi < outputs.size(); ++oi) {
274 mix = true; 225 if (outputs[oi].identifier == output) {
275 channels = 1; 226 outputNo = oi;
276 } else { 227 break;
277 cerr << "ERROR: Sound file has " << channels << " channels, out of range for plugin" << endl; 228 }
229 }
230
231 if (outputNo < 0) {
232 cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
278 goto done; 233 goto done;
279 } 234 }
280 } 235
281 236 } else {
282 if (outputs.empty()) { 237
283 cerr << "Plugin has no outputs!" << endl; 238 if (int(outputs.size()) <= outputNo) {
284 goto done; 239 cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
285 } 240 goto done;
286 241 }
287 if (int(outputs.size()) <= output) { 242 }
288 cerr << "Output " << output << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; 243
289 goto done; 244 od = outputs[outputNo];
290 } 245 cerr << "Output is: \"" << od.identifier << "\"" << endl;
291
292 od = outputs[output];
293 cerr << "Output is " << od.identifier << endl;
294 246
295 if (!plugin->initialise(channels, stepSize, blockSize)) { 247 if (!plugin->initialise(channels, stepSize, blockSize)) {
296 cerr << "ERROR: Plugin initialise (channels = " << channels 248 cerr << "ERROR: Plugin initialise (channels = " << channels
297 << ", stepSize = " << stepSize << ", blockSize = " 249 << ", stepSize = " << stepSize << ", blockSize = "
298 << blockSize << ") failed." << endl; 250 << blockSize << ") failed." << endl;
299 if (!rightBlockSize) {
300 cerr << "(Probably because I couldn't provide the plugin's preferred block size.)" << endl;
301 }
302 goto done; 251 goto done;
303 } 252 }
304 253
305 for (size_t i = 0; i < sfinfo.frames; i += stepSize) { 254 for (size_t i = 0; i < sfinfo.frames; i += stepSize) {
306 255
315 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; 264 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl;
316 break; 265 break;
317 } 266 }
318 267
319 for (int c = 0; c < channels; ++c) { 268 for (int c = 0; c < channels; ++c) {
320 for (int j = 0; j < blockSize; ++j) { 269 int j = 0;
270 while (j < count) {
271 plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
272 ++j;
273 }
274 while (j < blockSize) {
321 plugbuf[c][j] = 0.0f; 275 plugbuf[c][j] = 0.0f;
322 } 276 ++j;
323 }
324
325 for (int j = 0; j < blockSize && j < count; ++j) {
326 int tc = 0;
327 for (int c = 0; c < sfinfo.channels; ++c) {
328 tc = c;
329 if (mix) tc = 0;
330 plugbuf[tc][j] += filebuf[j * sfinfo.channels + c];
331 }
332 if (mix) {
333 plugbuf[0][j] /= sfinfo.channels;
334 }
335 }
336
337 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
338 for (int c = 0; c < sfinfo.channels; ++c) {
339 transformInput(plugbuf[c], blockSize);
340 if (mix) break;
341 } 277 }
342 } 278 }
343 279
344 printFeatures 280 printFeatures
345 (i, sfinfo.samplerate, output, plugin->process 281 (i, sfinfo.samplerate, outputNo, plugin->process
346 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate))); 282 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)));
347 } 283 }
348 284
349 printFeatures(sfinfo.frames, sfinfo.samplerate, output, 285 printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo,
350 plugin->getRemainingFeatures()); 286 plugin->getRemainingFeatures());
351 287
352 returnValue = 0; 288 returnValue = 0;
353 289
354 done: 290 done:
355 delete plugin; 291 delete plugin;
356
357 DLCLOSE(libraryHandle);
358 sf_close(sndfile); 292 sf_close(sndfile);
359 return returnValue; 293 return returnValue;
360 } 294 }
361 295
362 void 296 void
363 printPluginPath() 297 printPluginPath(bool verbose)
364 { 298 {
299 if (verbose) {
300 cout << "\nVamp plugin search path: ";
301 }
302
365 vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); 303 vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
366 for (size_t i = 0; i < path.size(); ++i) { 304 for (size_t i = 0; i < path.size(); ++i) {
367 cerr << path[i] << endl; 305 if (verbose) {
368 } 306 cout << "[" << path[i] << "]";
369 } 307 } else {
370 308 cout << path[i] << endl;
371 #ifdef HAVE_OPENDIR 309 }
310 }
311
312 if (verbose) cout << endl;
313 }
372 314
373 void 315 void
374 enumeratePlugins() 316 enumeratePlugins()
375 { 317 {
376 cerr << endl << "Vamp plugin libraries found in search path:" << endl; 318 PluginLoader *loader = PluginLoader::getInstance();
377 vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); 319
378 for (size_t i = 0; i < path.size(); ++i) { 320 cout << "\nVamp plugin libraries found in search path:" << endl;
379 cerr << "\n" << path[i] << ":" << endl; 321
380 DIR *d = opendir(path[i].c_str()); 322 std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
381 if (!d) { 323 typedef std::multimap<std::string, PluginLoader::PluginKey>
382 perror("Failed to open directory"); 324 LibraryMap;
383 continue; 325 LibraryMap libraryMap;
384 } 326
385 struct dirent *e = 0; 327 for (size_t i = 0; i < plugins.size(); ++i) {
386 while ((e = readdir(d))) { 328 std::string path = loader->getLibraryPathForPlugin(plugins[i]);
387 // cerr << "reading: " << e->d_name << endl; 329 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
388 if (!(e->d_type & DT_REG)) { 330 }
389 // cerr << e->d_name << ": not a regular file" << endl; 331
390 continue; 332 std::string prevPath = "";
391 } 333 int index = 0;
392 int len = strlen(e->d_name); 334
393 if (len < int(strlen(PLUGIN_SUFFIX) + 2) || 335 for (LibraryMap::iterator i = libraryMap.begin();
394 e->d_name[len - strlen(PLUGIN_SUFFIX) - 1] != '.' || 336 i != libraryMap.end(); ++i) {
395 strcmp(e->d_name + len - strlen(PLUGIN_SUFFIX), PLUGIN_SUFFIX)) { 337
396 // cerr << e->d_name << ": not a library file" << endl; 338 std::string path = i->first;
397 continue; 339 PluginLoader::PluginKey key = i->second;
398 } 340
399 char *fp = new char[path[i].length() + len + 3]; 341 if (path != prevPath) {
400 sprintf(fp, "%s/%s", path[i].c_str(), e->d_name); 342 prevPath = path;
401 void *handle = DLOPEN(string(fp), RTLD_LAZY); 343 index = 0;
402 if (handle) { 344 cout << "\n " << path << ":" << endl;
403 VampGetPluginDescriptorFunction fn = 345 }
404 (VampGetPluginDescriptorFunction)DLSYM 346
405 (handle, "vampGetPluginDescriptor"); 347 Vamp::Plugin *plugin = loader->loadPlugin(key, 48000);
406 if (fn) { 348 if (plugin) {
407 cerr << "\n " << e->d_name << ":" << endl; 349
408 int index = 0; 350 char c = char('A' + index);
409 const VampPluginDescriptor *descriptor = 0; 351 if (c > 'Z') c = char('a' + (index - 26));
410 while ((descriptor = fn(VAMP_API_VERSION, index))) { 352
411 Vamp::PluginHostAdapter plugin(descriptor, 48000); 353 cout << " [" << c << "] [v"
412 char c = char('A' + index); 354 << plugin->getVampApiVersion() << "] "
413 if (c > 'Z') c = char('a' + (index - 26)); 355 << plugin->getName() << ", \""
414 cerr << " [" << c << "] [v" 356 << plugin->getIdentifier() << "\"" << " ["
415 << plugin.getVampApiVersion() << "] " 357 << plugin->getMaker() << "]" << endl;
416 << plugin.getName() 358
417 << ", \"" << plugin.getIdentifier() << "\"" 359 PluginLoader::PluginCategoryHierarchy category =
418 << " [" << plugin.getMaker() 360 loader->getPluginCategory(key);
419 << "]" << endl; 361 if (!category.empty()) {
420 if (plugin.getDescription() != "") { 362 cout << " ";
421 cerr << " - " << plugin.getDescription() << endl; 363 for (size_t ci = 0; ci < category.size(); ++ci) {
422 } 364 cout << " > " << category[ci];
423 Vamp::Plugin::OutputList outputs = 365 }
424 plugin.getOutputDescriptors(); 366 cout << endl;
425 if (outputs.size() > 1) { 367 }
426 for (size_t j = 0; j < outputs.size(); ++j) { 368
427 cerr << " (" << j << ") " 369 if (plugin->getDescription() != "") {
428 << outputs[j].name 370 cout << " - " << plugin->getDescription() << endl;
429 << ", \"" << outputs[j].identifier << "\"" 371 }
430 << endl; 372
431 if (outputs[j].description != "") { 373 Vamp::Plugin::OutputList outputs =
432 cerr << " - " 374 plugin->getOutputDescriptors();
433 << outputs[j].description << endl; 375
434 } 376 if (outputs.size() > 1) {
435 } 377 for (size_t j = 0; j < outputs.size(); ++j) {
436 } 378 cout << " (" << j << ") "
437 ++index; 379 << outputs[j].name << ", \""
380 << outputs[j].identifier << "\"" << endl;
381 if (outputs[j].description != "") {
382 cout << " - "
383 << outputs[j].description << endl;
438 } 384 }
439 } else {
440 // cerr << e->d_name << ": no Vamp descriptor function" << endl;
441 } 385 }
442 DLCLOSE(handle); 386 }
443 } else { 387
444 cerr << "\n" << e->d_name << ": unable to load library (" << DLERROR() << ")" << endl; 388 ++index;
445 } 389
446 } 390 delete plugin;
447 closedir(d); 391 }
448 } 392 }
449 cerr << endl; 393
450 } 394 cout << endl;
451 395 }
452 #endif
453
454 396
455 void 397 void
456 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features) 398 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features)
457 { 399 {
458 for (unsigned int i = 0; i < features[output].size(); ++i) { 400 for (unsigned int i = 0; i < features[output].size(); ++i) {
466 } 408 }
467 cout << endl; 409 cout << endl;
468 } 410 }
469 } 411 }
470 412
471 void
472 transformInput(float *buffer, size_t size)
473 {
474 double *inbuf = new double[size * 2];
475 double *outbuf = new double[size * 2];
476
477 // Copy across with Hanning window
478 for (size_t i = 0; i < size; ++i) {
479 inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size));
480 inbuf[i + size] = 0.0;
481 }
482
483 for (size_t i = 0; i < size/2; ++i) {
484 double temp = inbuf[i];
485 inbuf[i] = inbuf[i + size/2];
486 inbuf[i + size/2] = temp;
487 }
488
489 fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size);
490
491 for (size_t i = 0; i <= size/2; ++i) {
492 buffer[i * 2] = outbuf[i];
493 buffer[i * 2 + 1] = outbuf[i + size];
494 }
495
496 delete[] inbuf;
497 delete[] outbuf;
498 }
499
500 void
501 fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io)
502 {
503 if (!ri || !ro || !io) return;
504
505 unsigned int bits;
506 unsigned int i, j, k, m;
507 unsigned int blockSize, blockEnd;
508
509 double tr, ti;
510
511 if (n < 2) return;
512 if (n & (n-1)) return;
513
514 double angle = 2.0 * M_PI;
515 if (inverse) angle = -angle;
516
517 for (i = 0; ; ++i) {
518 if (n & (1 << i)) {
519 bits = i;
520 break;
521 }
522 }
523
524 static unsigned int tableSize = 0;
525 static int *table = 0;
526
527 if (tableSize != n) {
528
529 delete[] table;
530
531 table = new int[n];
532
533 for (i = 0; i < n; ++i) {
534
535 m = i;
536
537 for (j = k = 0; j < bits; ++j) {
538 k = (k << 1) | (m & 1);
539 m >>= 1;
540 }
541
542 table[i] = k;
543 }
544
545 tableSize = n;
546 }
547
548 if (ii) {
549 for (i = 0; i < n; ++i) {
550 ro[table[i]] = ri[i];
551 io[table[i]] = ii[i];
552 }
553 } else {
554 for (i = 0; i < n; ++i) {
555 ro[table[i]] = ri[i];
556 io[table[i]] = 0.0;
557 }
558 }
559
560 blockEnd = 1;
561
562 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
563
564 double delta = angle / (double)blockSize;
565 double sm2 = -sin(-2 * delta);
566 double sm1 = -sin(-delta);
567 double cm2 = cos(-2 * delta);
568 double cm1 = cos(-delta);
569 double w = 2 * cm1;
570 double ar[3], ai[3];
571
572 for (i = 0; i < n; i += blockSize) {
573
574 ar[2] = cm2;
575 ar[1] = cm1;
576
577 ai[2] = sm2;
578 ai[1] = sm1;
579
580 for (j = i, m = 0; m < blockEnd; j++, m++) {
581
582 ar[0] = w * ar[1] - ar[2];
583 ar[2] = ar[1];
584 ar[1] = ar[0];
585
586 ai[0] = w * ai[1] - ai[2];
587 ai[2] = ai[1];
588 ai[1] = ai[0];
589
590 k = j + blockEnd;
591 tr = ar[0] * ro[k] - ai[0] * io[k];
592 ti = ar[0] * io[k] + ai[0] * ro[k];
593
594 ro[k] = ro[j] - tr;
595 io[k] = io[j] - ti;
596
597 ro[j] += tr;
598 io[j] += ti;
599 }
600 }
601
602 blockEnd = blockSize;
603 }
604
605 if (inverse) {
606
607 double denom = (double)n;
608
609 for (i = 0; i < n; i++) {
610 ro[i] /= denom;
611 io[i] /= denom;
612 }
613 }
614 }
615 413
616 414