Mercurial > hg > sonic-annotator
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; |