comparison host/vamp-simple-host.cpp @ 56:4ab6224110ef host-factory-stuff

* implement plugin loader and plugin input-domain adapter (to do basic ffts)
author cannam
date Fri, 04 May 2007 15:21:12 +0000
parents d3995d2b5e08
children 09a1aac6c362
comparison
equal deleted inserted replaced
55:0dad357a3406 56:4ab6224110ef
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 "PluginHostAdapter.h"
39 #include "PluginInputDomainAdapter.h"
40 #include "PluginLoader.h"
39 #include "vamp.h" 41 #include "vamp.h"
40 42
41 #include <iostream> 43 #include <iostream>
42 #include <sndfile.h> 44 #include <sndfile.h>
43 #include <dirent.h> // POSIX directory open and read
44 45
45 #include "system.h" 46 #include "system.h"
46 47
47 #include <cmath> 48 #include <cmath>
48 49
56 57
57 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet); 58 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet);
58 void transformInput(float *, size_t); 59 void transformInput(float *, size_t);
59 void fft(unsigned int, bool, double *, double *, double *, double *); 60 void fft(unsigned int, bool, double *, double *, double *, double *);
60 void printPluginPath(); 61 void printPluginPath();
61
62 #ifdef HAVE_OPENDIR
63 void enumeratePlugins(); 62 void enumeratePlugins();
64 #endif
65 63
66 /* 64 /*
67 A very simple Vamp plugin host. Given the name of a plugin 65 A very simple Vamp plugin host. Given the name of a plugin
68 library and the name of a sound file on the command line, it loads 66 library and the name of a sound file on the command line, it loads
69 the first plugin in the library and runs it on the sound file, 67 the first plugin in the library and runs it on the sound file,
70 dumping the plugin's first output to stdout. 68 dumping the plugin's first output to stdout.
71 */ 69 */
72 70
73 int main(int argc, char **argv) 71 int main(int argc, char **argv)
74 { 72 {
75 if (argc < 2 || argc > 4) { 73 if (argc < 2 || argc > 4 ||
74 (argc == 2 &&
75 (!strcmp(argv[1], "-?") ||
76 !strcmp(argv[1], "-h") ||
77 !strcmp(argv[1], "--help")))) {
78
76 char *scooter = argv[0]; 79 char *scooter = argv[0];
77 char *name = 0; 80 char *name = 0;
78 while (scooter && *scooter) { 81 while (scooter && *scooter) {
79 if (*scooter == '/' || *scooter == '\\') name = ++scooter; 82 if (*scooter == '/' || *scooter == '\\') name = ++scooter;
80 else ++scooter; 83 else ++scooter;
111 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; 114 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl;
112 return 0; 115 return 0;
113 } 116 }
114 117
115 if (argc == 2 && !strcmp(argv[1], "-l")) { 118 if (argc == 2 && !strcmp(argv[1], "-l")) {
116 #ifdef HAVE_OPENDIR
117 enumeratePlugins(); 119 enumeratePlugins();
118 #endif
119 return 0; 120 return 0;
120 } 121 }
121 if (argc == 2 && !strcmp(argv[1], "-p")) { 122 if (argc == 2 && !strcmp(argv[1], "-p")) {
122 printPluginPath(); 123 printPluginPath();
123 return 0; 124 return 0;
207 << sf_strerror(sndfile) << endl; 208 << sf_strerror(sndfile) << endl;
208 DLCLOSE(libraryHandle); 209 DLCLOSE(libraryHandle);
209 return 1; 210 return 1;
210 } 211 }
211 212
212 Vamp::PluginHostAdapter *plugin = 213 Vamp::Plugin *plugin =
213 new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate); 214 new Vamp::PluginInputDomainAdapter
215 (new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate));
214 216
215 cerr << "Running " << plugin->getIdentifier() << "..." << endl; 217 cerr << "Running " << plugin->getIdentifier() << "..." << endl;
216 218
217 int blockSize = plugin->getPreferredBlockSize(); 219 int blockSize = plugin->getPreferredBlockSize();
218 int stepSize = plugin->getPreferredStepSize(); 220 int stepSize = plugin->getPreferredStepSize();
332 if (mix) { 334 if (mix) {
333 plugbuf[0][j] /= sfinfo.channels; 335 plugbuf[0][j] /= sfinfo.channels;
334 } 336 }
335 } 337 }
336 338
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 }
342 }
343
344 printFeatures 339 printFeatures
345 (i, sfinfo.samplerate, output, plugin->process 340 (i, sfinfo.samplerate, output, plugin->process
346 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate))); 341 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)));
347 } 342 }
348 343
366 for (size_t i = 0; i < path.size(); ++i) { 361 for (size_t i = 0; i < path.size(); ++i) {
367 cerr << path[i] << endl; 362 cerr << path[i] << endl;
368 } 363 }
369 } 364 }
370 365
371 #ifdef HAVE_OPENDIR
372
373 void 366 void
374 enumeratePlugins() 367 enumeratePlugins()
375 { 368 {
369 Vamp::PluginLoader loader;
370
376 cerr << endl << "Vamp plugin libraries found in search path:" << endl; 371 cerr << endl << "Vamp plugin libraries found in search path:" << endl;
377 vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); 372
378 for (size_t i = 0; i < path.size(); ++i) { 373 std::vector<Vamp::PluginLoader::PluginKey> plugins = loader.listPlugins();
379 cerr << "\n" << path[i] << ":" << endl; 374 typedef std::multimap<std::string, Vamp::PluginLoader::PluginKey>
380 DIR *d = opendir(path[i].c_str()); 375 LibraryMap;
381 if (!d) { 376 LibraryMap libraryMap;
382 perror("Failed to open directory"); 377
383 continue; 378 for (size_t i = 0; i < plugins.size(); ++i) {
384 } 379 std::string path = loader.getLibraryPath(plugins[i]);
385 struct dirent *e = 0; 380 libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
386 while ((e = readdir(d))) { 381 }
387 // cerr << "reading: " << e->d_name << endl; 382
388 if (!(e->d_type & DT_REG)) { 383 std::string prevPath = "";
389 // cerr << e->d_name << ": not a regular file" << endl; 384 int index = 0;
390 continue; 385
386 for (LibraryMap::iterator i = libraryMap.begin();
387 i != libraryMap.end(); ++i) {
388
389 std::string path = i->first;
390 Vamp::PluginLoader::PluginKey key = i->second;
391
392 if (path != prevPath) {
393 prevPath = path;
394 index = 0;
395 cerr << "\n " << path << ":" << endl;
396 }
397
398 Vamp::Plugin *plugin = loader.load(key, 48000);
399 if (plugin) {
400
401 char c = char('A' + index);
402 if (c > 'Z') c = char('a' + (index - 26));
403
404 cerr << " [" << c << "] [v"
405 << plugin->getVampApiVersion() << "] "
406 << plugin->getName() << ", \""
407 << plugin->getIdentifier() << "\"" << " ["
408 << plugin->getMaker() << "]" << endl;
409
410 if (plugin->getDescription() != "") {
411 cerr << " - " << plugin->getDescription() << endl;
391 } 412 }
392 int len = strlen(e->d_name); 413
393 if (len < int(strlen(PLUGIN_SUFFIX) + 2) || 414 Vamp::Plugin::OutputList outputs =
394 e->d_name[len - strlen(PLUGIN_SUFFIX) - 1] != '.' || 415 plugin->getOutputDescriptors();
395 strcmp(e->d_name + len - strlen(PLUGIN_SUFFIX), PLUGIN_SUFFIX)) { 416
396 // cerr << e->d_name << ": not a library file" << endl; 417 if (outputs.size() > 1) {
397 continue; 418 for (size_t j = 0; j < outputs.size(); ++j) {
419 cerr << " (" << j << ") "
420 << outputs[j].name << ", \""
421 << outputs[j].identifier << "\"" << endl;
422 if (outputs[j].description != "") {
423 cerr << " - "
424 << outputs[j].description << endl;
425 }
426 }
398 } 427 }
399 char *fp = new char[path[i].length() + len + 3]; 428
400 sprintf(fp, "%s/%s", path[i].c_str(), e->d_name); 429 ++index;
401 void *handle = DLOPEN(string(fp), RTLD_LAZY); 430 }
402 if (handle) { 431 }
403 VampGetPluginDescriptorFunction fn = 432
404 (VampGetPluginDescriptorFunction)DLSYM
405 (handle, "vampGetPluginDescriptor");
406 if (fn) {
407 cerr << "\n " << e->d_name << ":" << endl;
408 int index = 0;
409 const VampPluginDescriptor *descriptor = 0;
410 while ((descriptor = fn(VAMP_API_VERSION, index))) {
411 Vamp::PluginHostAdapter plugin(descriptor, 48000);
412 char c = char('A' + index);
413 if (c > 'Z') c = char('a' + (index - 26));
414 cerr << " [" << c << "] [v"
415 << plugin.getVampApiVersion() << "] "
416 << plugin.getName()
417 << ", \"" << plugin.getIdentifier() << "\""
418 << " [" << plugin.getMaker()
419 << "]" << endl;
420 if (plugin.getDescription() != "") {
421 cerr << " - " << plugin.getDescription() << endl;
422 }
423 Vamp::Plugin::OutputList outputs =
424 plugin.getOutputDescriptors();
425 if (outputs.size() > 1) {
426 for (size_t j = 0; j < outputs.size(); ++j) {
427 cerr << " (" << j << ") "
428 << outputs[j].name
429 << ", \"" << outputs[j].identifier << "\""
430 << endl;
431 if (outputs[j].description != "") {
432 cerr << " - "
433 << outputs[j].description << endl;
434 }
435 }
436 }
437 ++index;
438 }
439 } else {
440 // cerr << e->d_name << ": no Vamp descriptor function" << endl;
441 }
442 DLCLOSE(handle);
443 } else {
444 cerr << "\n" << e->d_name << ": unable to load library (" << DLERROR() << ")" << endl;
445 }
446 }
447 closedir(d);
448 }
449 cerr << endl; 433 cerr << endl;
450 } 434 }
451
452 #endif
453
454 435
455 void 436 void
456 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features) 437 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features)
457 { 438 {
458 for (unsigned int i = 0; i < features[output].size(); ++i) { 439 for (unsigned int i = 0; i < features[output].size(); ++i) {
466 } 447 }
467 cout << endl; 448 cout << endl;
468 } 449 }
469 } 450 }
470 451
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 452
616 453