comparison runner/main.cpp @ 288:fd4a6183482f kapoor_1202

Merge from branch piper-nopiper. The next release will be based on this.
author Chris Cannam
date Fri, 02 Dec 2016 10:04:44 +0000
parents 329c29264aaf
children c1862b8712ca
comparison
equal deleted inserted replaced
259:9e7d180be225 288:fd4a6183482f
34 #include "../version.h" 34 #include "../version.h"
35 35
36 #include "base/Exceptions.h" 36 #include "base/Exceptions.h"
37 #include "base/TempDirectory.h" 37 #include "base/TempDirectory.h"
38 #include "base/ProgressPrinter.h" 38 #include "base/ProgressPrinter.h"
39 #include "base/Debug.h"
39 40
40 #include "data/fileio/AudioFileReaderFactory.h" 41 #include "data/fileio/AudioFileReaderFactory.h"
41 #include "data/fileio/PlaylistFileReader.h" 42 #include "data/fileio/PlaylistFileReader.h"
42 43
43 #include "transform/Transform.h" 44 #include "transform/Transform.h"
342 << wrapCol("Normalise each input audio file to signal abs max = 1.f.") 343 << wrapCol("Normalise each input audio file to signal abs max = 1.f.")
343 << endl << endl; 344 << endl << endl;
344 cerr << " -f, --force " 345 cerr << " -f, --force "
345 << wrapCol("Continue with subsequent files following an error.") 346 << wrapCol("Continue with subsequent files following an error.")
346 << endl << endl; 347 << endl << endl;
348 cerr << " -q, --quiet "
349 << wrapCol("Suppress informational output that would otherwise be printed to stderr and to a log file. Sonic Annotator may run faster with this option, especially if the application data directory is on a shared storage resource, but no diagnostic information will be available except for the application's return code.")
350 << endl << endl;
347 cerr << "Housekeeping options:" 351 cerr << "Housekeeping options:"
348 << endl << endl; 352 << endl << endl;
349 cerr << " -l, --list List available transform ids to standard output." << endl; 353 cerr << " -l, --list List available transform ids to standard output." << endl;
350 cerr << " --list-writers List supported writer types to standard output." << endl; 354 cerr << " --list-writers List supported writer types to standard output." << endl;
351 cerr << " --list-formats List supported input audio formats to standard output." << endl; 355 cerr << " --list-formats List supported input audio formats to standard output." << endl;
472 findSourcesRecursive(QString dirname, QStringList &addTo, int &found) 476 findSourcesRecursive(QString dirname, QStringList &addTo, int &found)
473 { 477 {
474 QDir dir(dirname); 478 QDir dir(dirname);
475 479
476 QString printable = dir.dirName().left(20); 480 QString printable = dir.dirName().left(20);
477 cerr << "\rScanning \"" << printable << "\"..." 481 SVCERR << "\rScanning \"" << printable << "\"..."
478 << QString(" ").left(20 - printable.length()) 482 << QString(" ").left(20 - printable.length())
479 << " [" << found << " audio file(s)]"; 483 << " [" << found << " audio file(s)]";
480 484
481 QString extensions = AudioFileReaderFactory::getKnownExtensions(); 485 QString extensions = AudioFileReaderFactory::getKnownExtensions();
482 QStringList extlist = extensions.split(" ", QString::SkipEmptyParts); 486 QStringList extlist = extensions.split(" ", QString::SkipEmptyParts);
499 expandPlaylists(QStringList sources) 503 expandPlaylists(QStringList sources)
500 { 504 {
501 QStringList expanded; 505 QStringList expanded;
502 foreach (QString path, sources) { 506 foreach (QString path, sources) {
503 if (QFileInfo(path).suffix().toLower() == "m3u") { 507 if (QFileInfo(path).suffix().toLower() == "m3u") {
508 SVDEBUG << "Expanding m3u playlist file \"" << path << "\"" << endl;
504 ProgressPrinter retrievalProgress("Opening playlist file..."); 509 ProgressPrinter retrievalProgress("Opening playlist file...");
505 FileSource source(path, &retrievalProgress); 510 FileSource source(path, &retrievalProgress);
506 if (!source.isAvailable()) { 511 if (!source.isAvailable()) {
507 // Don't fail or throw an exception here, just keep 512 // Don't fail or throw an exception here, just keep
508 // the file in the list -- it will be tested again 513 // the file in the list -- it will be tested again
517 if (reader.isOK()) { 522 if (reader.isOK()) {
518 vector<QString> files = reader.load(); 523 vector<QString> files = reader.load();
519 for (int i = 0; i < (int)files.size(); ++i) { 524 for (int i = 0; i < (int)files.size(); ++i) {
520 expanded.push_back(files[i]); 525 expanded.push_back(files[i]);
521 } 526 }
527 SVDEBUG << "Done, m3u playlist references "
528 << files.size() << " file(s)" << endl;
522 } 529 }
523 } else { 530 } else {
524 // not a playlist 531 // not a playlist
525 expanded.push_back(path); 532 expanded.push_back(path);
526 } 533 }
532 readSegmentBoundaries(QString url, 539 readSegmentBoundaries(QString url,
533 Vamp::HostExt::PluginSummarisingAdapter::SegmentBoundaries &boundaries) 540 Vamp::HostExt::PluginSummarisingAdapter::SegmentBoundaries &boundaries)
534 { 541 {
535 FileSource source(url); 542 FileSource source(url);
536 if (!source.isAvailable()) { 543 if (!source.isAvailable()) {
537 cerr << "File or URL \"" << url << "\" could not be retrieved" << endl; 544 SVCERR << "File or URL \"" << url << "\" could not be retrieved" << endl;
538 return false; 545 return false;
539 } 546 }
540 source.waitForData(); 547 source.waitForData();
541 548
542 QString filename = source.getLocalFilename(); 549 QString filename = source.getLocalFilename();
543 QFile file(filename); 550 QFile file(filename);
544 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 551 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
545 cerr << "File \"" << filename << "\" could not be read" << endl; 552 SVCERR << "File \"" << filename << "\" could not be read" << endl;
546 return false; 553 return false;
547 } 554 }
548 555
549 QTextStream in(&file); 556 QTextStream in(&file);
550 int lineNo = 0; 557 int lineNo = 0;
563 } 570 }
564 if (!bits.empty()) { 571 if (!bits.empty()) {
565 importantBit = bits[0]; 572 importantBit = bits[0];
566 } 573 }
567 if (importantBit == QString()) { 574 if (importantBit == QString()) {
568 cerr << "WARNING: Skipping line " << lineNo << " (no content found)" 575 SVCERR << "WARNING: Skipping line " << lineNo << " (no content found)"
569 << endl; 576 << endl;
570 continue; 577 continue;
571 } 578 }
572 bool good = false; 579 bool good = false;
573 boundaries.insert(Vamp::RealTime::fromSeconds 580 boundaries.insert(Vamp::RealTime::fromSeconds
574 (importantBit.toDouble(&good))); 581 (importantBit.toDouble(&good)));
575 if (!good) { 582 if (!good) {
576 cerr << "Unparseable or non-numeric segment boundary at line " 583 SVCERR << "Unparseable or non-numeric segment boundary at line "
577 << lineNo << endl; 584 << lineNo << endl;
578 return false; 585 return false;
579 } 586 }
580 } 587 }
581 588
598 set<string> requestedSummaryTypes; 605 set<string> requestedSummaryTypes;
599 bool force = false; 606 bool force = false;
600 bool multiplex = false; 607 bool multiplex = false;
601 bool recursive = false; 608 bool recursive = false;
602 bool normalise = false; 609 bool normalise = false;
610 bool quiet = false;
603 bool list = false; 611 bool list = false;
604 bool listWriters = false; 612 bool listWriters = false;
605 bool listFormats = false; 613 bool listFormats = false;
606 bool summaryOnly = false; 614 bool summaryOnly = false;
607 QString skeletonFor = ""; 615 QString skeletonFor = "";
754 normalise = true; 762 normalise = true;
755 continue; 763 continue;
756 } else if (arg == "-f" || arg == "--force") { 764 } else if (arg == "-f" || arg == "--force") {
757 force = true; 765 force = true;
758 continue; 766 continue;
767 } else if (arg == "-q" || arg == "--quiet") {
768 quiet = true;
769 continue;
759 } else if (arg == "--list-writers") { 770 } else if (arg == "--list-writers") {
760 listWriters = true; 771 listWriters = true;
761 continue; 772 continue;
762 } else if (arg == "--list-formats") { 773 } else if (arg == "--list-formats") {
763 listFormats = true; 774 listFormats = true;
800 } else { 811 } else {
801 otherArgs.push_back(args[i]); 812 otherArgs.push_back(args[i]);
802 } 813 }
803 } 814 }
804 815
816 if (quiet) {
817 SVDebug::silence();
818 SVCerr::silence();
819 }
820
805 if (list) { 821 if (list) {
806 if (!requestedWriterTags.empty() || skeletonFor != "") { 822 if (!requestedWriterTags.empty() || skeletonFor != "") {
807 cerr << helpStr << endl; 823 cerr << helpStr << endl;
808 exit(2); 824 exit(2);
809 } 825 }
908 } 924 }
909 } 925 }
910 926
911 QSettings settings; 927 QSettings settings;
912 928
913 #ifdef HAVE_FFTW3
914 settings.beginGroup("FFTWisdom");
915 QString wisdom = settings.value("wisdom").toString();
916 if (wisdom != "") {
917 fftw_import_wisdom_from_string(wisdom.toLocal8Bit().data());
918 }
919 settings.endGroup();
920 #endif
921
922 settings.beginGroup("RDF"); 929 settings.beginGroup("RDF");
923 if (!settings.contains("rdf-indices")) { 930 if (!settings.contains("rdf-indices")) {
924 QStringList list; 931 QStringList list;
925 list << "http://www.vamp-plugins.org/rdf/plugins/index.txt"; 932 list << "http://www.vamp-plugins.org/rdf/plugins/index.txt";
926 settings.setValue("rdf-indices", list); 933 settings.setValue("rdf-indices", list);
927 } 934 }
928 settings.endGroup(); 935 settings.endGroup();
929 936
930 FeatureExtractionManager manager; 937 FeatureExtractionManager manager(!quiet);
931 938
932 manager.setNormalise(normalise); 939 manager.setNormalise(normalise);
933 940
934 if (!requestedSummaryTypes.empty()) { 941 if (!requestedSummaryTypes.empty()) {
935 if (!manager.setSummaryTypes(requestedSummaryTypes, 942 if (!manager.setSummaryTypes(requestedSummaryTypes,
1038 exit(2); 1045 exit(2);
1039 } 1046 }
1040 1047
1041 for (set<string>::const_iterator i = requestedTransformListFiles.begin(); 1048 for (set<string>::const_iterator i = requestedTransformListFiles.begin();
1042 i != requestedTransformListFiles.end(); ++i) { 1049 i != requestedTransformListFiles.end(); ++i) {
1050 SVDEBUG << "Reading transform list file \"" << *i << "\"" << endl;
1043 PlaylistFileReader reader(i->c_str()); 1051 PlaylistFileReader reader(i->c_str());
1044 if (reader.isOK()) { 1052 if (reader.isOK()) {
1045 vector<QString> files = reader.load(); 1053 vector<QString> files = reader.load();
1046 for (int j = 0; j < (int)files.size(); ++j) { 1054 for (int j = 0; j < (int)files.size(); ++j) {
1047 requestedTransformFiles.insert(files[j].toStdString()); 1055 requestedTransformFiles.insert(files[j].toStdString());
1048 } 1056 }
1049 } else { 1057 } else {
1050 cerr << myname << ": failed to read template list file \"" << *i << "\"" << endl; 1058 SVCERR << myname << ": failed to read transform list file \"" << *i << "\"" << endl;
1051 exit(2); 1059 exit(2);
1052 } 1060 }
1053 } 1061 }
1054 1062
1055 QStringList sources; 1063 QStringList sources;
1057 sources = otherArgs; 1065 sources = otherArgs;
1058 } else { 1066 } else {
1059 for (QStringList::const_iterator i = otherArgs.begin(); 1067 for (QStringList::const_iterator i = otherArgs.begin();
1060 i != otherArgs.end(); ++i) { 1068 i != otherArgs.end(); ++i) {
1061 if (QDir(*i).exists()) { 1069 if (QDir(*i).exists()) {
1062 cerr << "Directory found and recursive flag set, scanning for audio files..." << endl; 1070 SVCERR << "Directory found and recursive flag set, scanning for audio files..." << endl;
1063 int found = 0; 1071 int found = 0;
1064 findSourcesRecursive(*i, sources, found); 1072 findSourcesRecursive(*i, sources, found);
1065 cerr << "\rDone, found " << found << " supported audio file(s) " << endl; 1073 SVCERR << "\rDone, found " << found << " supported audio file(s) " << endl;
1066 } else { 1074 } else {
1067 sources.push_back(*i); 1075 sources.push_back(*i);
1068 } 1076 }
1069 } 1077 }
1070 } 1078 }
1078 i != sources.end(); ++i) { 1086 i != sources.end(); ++i) {
1079 try { 1087 try {
1080 manager.addSource(*i, multiplex); 1088 manager.addSource(*i, multiplex);
1081 } catch (const std::exception &e) { 1089 } catch (const std::exception &e) {
1082 badSources.insert(*i); 1090 badSources.insert(*i);
1083 cerr << "ERROR: Failed to process file \"" << i->toStdString() 1091 SVCERR << "ERROR: Failed to process file \"" << i->toStdString()
1084 << "\": " << e.what() << endl; 1092 << "\": " << e.what() << endl;
1085 if (force) { 1093 if (force) {
1086 // print a note only if we have more files to process 1094 // print a note only if we have more files to process
1087 QStringList::const_iterator j = i; 1095 QStringList::const_iterator j = i;
1088 if (++j != sources.end()) { 1096 if (++j != sources.end()) {
1089 cerr << "NOTE: \"--force\" option was provided, continuing (more errors may occur)" << endl; 1097 SVCERR << "NOTE: \"--force\" option was provided, continuing (more errors may occur)" << endl;
1090 } 1098 }
1091 } else { 1099 } else {
1092 cerr << "NOTE: If you want to continue with processing any further files after an" << endl 1100 SVCERR << "NOTE: If you want to continue with processing any further files after an" << endl
1093 << "error like this, use the --force option" << endl; 1101 << "error like this, use the --force option" << endl;
1094 good = false; 1102 good = false;
1095 break; 1103 break;
1096 } 1104 }
1097 } 1105 }
1104 for (set<string>::const_iterator i = requestedTransformFiles.begin(); 1112 for (set<string>::const_iterator i = requestedTransformFiles.begin();
1105 i != requestedTransformFiles.end(); ++i) { 1113 i != requestedTransformFiles.end(); ++i) {
1106 if (manager.addFeatureExtractorFromFile(i->c_str(), writers)) { 1114 if (manager.addFeatureExtractorFromFile(i->c_str(), writers)) {
1107 haveFeatureExtractor = true; 1115 haveFeatureExtractor = true;
1108 } else { 1116 } else {
1109 cerr << "ERROR: Failed to add feature extractor from transform file \"" << *i << "\"" << endl; 1117 SVCERR << "ERROR: Failed to add feature extractor from transform file \"" << *i << "\"" << endl;
1110 good = false; 1118 good = false;
1111 } 1119 }
1112 } 1120 }
1113 1121
1114 for (set<string>::const_iterator i = requestedDefaultTransforms.begin(); 1122 for (set<string>::const_iterator i = requestedDefaultTransforms.begin();
1115 i != requestedDefaultTransforms.end(); ++i) { 1123 i != requestedDefaultTransforms.end(); ++i) {
1116 if (manager.addDefaultFeatureExtractor(i->c_str(), writers)) { 1124 if (manager.addDefaultFeatureExtractor(i->c_str(), writers)) {
1117 haveFeatureExtractor = true; 1125 haveFeatureExtractor = true;
1118 } else { 1126 } else {
1119 cerr << "ERROR: Failed to add default feature extractor for transform \"" << *i << "\"" << endl; 1127 SVCERR << "ERROR: Failed to add default feature extractor for transform \"" << *i << "\"" << endl;
1120 good = false; 1128 good = false;
1121 } 1129 }
1122 } 1130 }
1123 1131
1124 if (!haveFeatureExtractor) { 1132 if (!haveFeatureExtractor) {
1125 cerr << myname << ": no feature extractors added" << endl; 1133 SVCERR << myname << ": no feature extractors added" << endl;
1126 good = false; 1134 good = false;
1127 } 1135 }
1128 } 1136 }
1129 1137
1130 if (good) { 1138 if (good) {
1139 for (int i = 0; i < (int)writers.size(); ++i) { 1147 for (int i = 0; i < (int)writers.size(); ++i) {
1140 writers[i]->setNofM(1, 1); 1148 writers[i]->setNofM(1, 1);
1141 } 1149 }
1142 manager.extractFeaturesMultiplexed(goodSources); 1150 manager.extractFeaturesMultiplexed(goodSources);
1143 } catch (const std::exception &e) { 1151 } catch (const std::exception &e) {
1144 cerr << "ERROR: Feature extraction failed: " 1152 SVCERR << "ERROR: Feature extraction failed: "
1145 << e.what() << endl; 1153 << e.what() << endl;
1146 } 1154 }
1147 } else { 1155 } else {
1148 int n = 0; 1156 int n = 0;
1149 for (QStringList::const_iterator i = goodSources.begin(); 1157 for (QStringList::const_iterator i = goodSources.begin();
1150 i != goodSources.end(); ++i) { 1158 i != goodSources.end(); ++i) {
1151 std::cerr << "Extracting features for: \"" << i->toStdString() 1159 SVCERR << "Extracting features for: \"" << *i << "\"" << endl;
1152 << "\"" << std::endl;
1153 ++n; 1160 ++n;
1154 try { 1161 try {
1155 for (int j = 0; j < (int)writers.size(); ++j) { 1162 for (int j = 0; j < (int)writers.size(); ++j) {
1156 writers[j]->setNofM(n, goodSources.size()); 1163 writers[j]->setNofM(n, goodSources.size());
1157 } 1164 }
1158 manager.extractFeatures(*i); 1165 manager.extractFeatures(*i);
1159 } catch (const std::exception &e) { 1166 } catch (const std::exception &e) {
1160 cerr << "ERROR: Feature extraction failed for \"" 1167 SVCERR << "ERROR: Feature extraction failed for \""
1161 << i->toStdString() << "\": " << e.what() << endl; 1168 << i->toStdString() << "\": " << e.what() << endl;
1162 if (force) { 1169 if (force) {
1163 // print a note only if we have more files to process 1170 // print a note only if we have more files to process
1164 QStringList::const_iterator j = i; 1171 QStringList::const_iterator j = i;
1165 if (++j != sources.end()) { 1172 if (++j != sources.end()) {
1166 cerr << "NOTE: \"--force\" option was provided, continuing (more errors may occur)" << endl; 1173 SVCERR << "NOTE: \"--force\" option was provided, continuing (more errors may occur)" << endl;
1167 } 1174 }
1168 } else { 1175 } else {
1169 cerr << "NOTE: If you want to continue with processing any further files after an" << endl 1176 SVCERR << "NOTE: If you want to continue with processing any further files after an" << endl
1170 << "error like this, use the --force option" << endl; 1177 << "error like this, use the --force option" << endl;
1171 good = false; 1178 good = false;
1172 break; 1179 break;
1173 } 1180 }
1174 } 1181 }
1175 } 1182 }
1176 } 1183 }
1177 } 1184 }
1178 1185
1179 for (int i = 0; i < (int)writers.size(); ++i) delete writers[i]; 1186 for (int i = 0; i < (int)writers.size(); ++i) delete writers[i];
1180
1181 #ifdef HAVE_FFTW3
1182 settings.beginGroup("FFTWisdom");
1183 char *cwisdom = fftw_export_wisdom_to_string();
1184 if (cwisdom) {
1185 settings.setValue("wisdom", cwisdom);
1186 fftw_free(cwisdom);
1187 }
1188 settings.endGroup();
1189 #endif
1190 1187
1191 TempDirectory::getInstance()->cleanup(); 1188 TempDirectory::getInstance()->cleanup();
1192 1189
1193 if (good) return 0; 1190 if (good) return 0;
1194 else return 1; 1191 else return 1;