Mercurial > hg > vamp-plugin-sdk
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 |