Mercurial > hg > sonic-annotator
diff runner/FeatureExtractionManager.cpp @ 248:c8e5fcddf8be
Merge
author | Chris Cannam |
---|---|
date | Fri, 18 Mar 2016 15:15:55 +0000 |
parents | 9a10c3ffff47 |
children | 857ce6ecb163 |
line wrap: on
line diff
--- a/runner/FeatureExtractionManager.cpp Fri Mar 18 15:15:37 2016 +0000 +++ b/runner/FeatureExtractionManager.cpp Fri Mar 18 15:15:55 2016 +0000 @@ -323,6 +323,8 @@ << " (adapter step and block size " << m_blockSize << ")" << endl; +// cerr << "NOTE: That transform is: " << transform.toXmlString() << endl; + if (pida) { cerr << "NOTE: PluginInputDomainAdapter timestamp adjustment is " @@ -382,8 +384,11 @@ m_transformPluginMap[transform] = plugin; +// cerr << "NOTE: Assigned plugin " << plugin << " for transform: " << transform.toXmlString() << endl; + if (!(originalTransform == transform)) { m_transformPluginMap[originalTransform] = plugin; +// cerr << "NOTE: Also assigned plugin " << plugin << " for original transform: " << originalTransform.toXmlString() << endl; } } else { @@ -427,11 +432,36 @@ } bool FeatureExtractionManager::addFeatureExtractorFromFile -(QString transformXmlFile, const vector<FeatureWriter*> &writers) +(QString transformFile, const vector<FeatureWriter*> &writers) { + // We support two formats for transform description files, XML (in + // a format specific to Sonic Annotator) and RDF/Turtle. The RDF + // format can describe multiple transforms in a single file, the + // XML only one. + + // Possible errors we should report: + // + // 1. File does not exist or cannot be opened + // 2. File is ostensibly XML, but is not parseable + // 3. File is ostensibly Turtle, but is not parseable + // 4. File is XML, but contains no valid transform (e.g. is unrelated XML) + // 5. File is Turtle, but contains no valid transform(s) + // 6. File is Turtle and contains both valid and invalid transform(s) + + { + // We don't actually need to open this here yet, we just hoist + // it to the top for error reporting purposes + QFile file(transformFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + // Error case 1. File does not exist or cannot be opened + cerr << "ERROR: Failed to open transform file \"" << transformFile + << "\" for reading" << endl; + return false; + } + } + bool tryRdf = true; - - if (transformXmlFile.endsWith(".xml") || transformXmlFile.endsWith(".XML")) { + if (transformFile.endsWith(".xml") || transformFile.endsWith(".XML")) { // We don't support RDF-XML (and nor does the underlying // parser library) so skip the RDF parse if the filename // suggests XML, to avoid puking out a load of errors from @@ -439,44 +469,90 @@ tryRdf = false; } + bool tryXml = true; + if (transformFile.endsWith(".ttl") || transformFile.endsWith(".TTL") || + transformFile.endsWith(".ntriples") || transformFile.endsWith(".NTRIPLES") || + transformFile.endsWith(".n3") || transformFile.endsWith(".N3")) { + tryXml = false; + } + + QString rdfError, xmlError; + if (tryRdf) { + RDFTransformFactory factory - (QUrl::fromLocalFile(QFileInfo(transformXmlFile).absoluteFilePath()) + (QUrl::fromLocalFile(QFileInfo(transformFile).absoluteFilePath()) .toString()); ProgressPrinter printer("Parsing transforms RDF file"); std::vector<Transform> transforms = factory.getTransforms(&printer); - if (!factory.isOK()) { - cerr << "WARNING: FeatureExtractionManager::addFeatureExtractorFromFile: Failed to parse transforms file: " << factory.getErrorString().toStdString() << endl; + + if (factory.isOK()) { + if (transforms.empty()) { + cerr << "ERROR: Transform file \"" << transformFile + << "\" is valid RDF but defines no transforms" << endl; + return false; + } else { + bool success = true; + for (int i = 0; i < (int)transforms.size(); ++i) { + if (!addFeatureExtractor(transforms[i], writers)) { + success = false; + } + } + return success; + } + } else { // !factory.isOK() if (factory.isRDF()) { - return false; // no point trying it as XML + cerr << "ERROR: Invalid transform RDF file \"" << transformFile + << "\": " << factory.getErrorString() << endl; + return false; } - } - if (!transforms.empty()) { - bool success = true; - for (int i = 0; i < (int)transforms.size(); ++i) { - if (!addFeatureExtractor(transforms[i], writers)) { - success = false; - } - } - return success; + + // the not-RDF case: fall through without reporting an + // error, so we try the file as XML, and if that fails, we + // print a general unparseable-file error + rdfError = factory.getErrorString(); } } - QFile file(transformXmlFile); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - cerr << "ERROR: Failed to open transform XML file \"" - << transformXmlFile.toStdString() << "\" for reading" << endl; - return false; + if (tryXml) { + + QFile file(transformFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + cerr << "ERROR: Failed to open transform file \"" + << transformFile.toStdString() << "\" for reading" << endl; + return false; + } + + QTextStream *qts = new QTextStream(&file); + QString qs = qts->readAll(); + delete qts; + file.close(); + + Transform transform(qs); + xmlError = transform.getErrorString(); + + if (xmlError == "") { + + if (transform.getIdentifier() == "") { + cerr << "ERROR: Transform file \"" << transformFile + << "\" is valid XML but defines no transform" << endl; + return false; + } + + return addFeatureExtractor(transform, writers); + } } - QTextStream *qts = new QTextStream(&file); - QString qs = qts->readAll(); - delete qts; - file.close(); + cerr << "ERROR: Transform file \"" << transformFile + << "\" could not be parsed" << endl; + if (rdfError != "") { + cerr << "ERROR: RDF parser reported: " << rdfError << endl; + } + if (xmlError != "") { + cerr << "ERROR: XML parser reported: " << xmlError << endl; + } - Transform transform(qs); - - return addFeatureExtractor(transform, writers); + return false; } void FeatureExtractionManager::addSource(QString audioSource, bool willMultiplex) @@ -489,7 +565,7 @@ if (m_channels == 0 || m_defaultSampleRate == 0) { - ProgressPrinter retrievalProgress("Determining default rate and channel count from first input file..."); + ProgressPrinter retrievalProgress("Retrieving first input file to determine default rate and channel count..."); FileSource source(audioSource, &retrievalProgress); if (!source.isAvailable()) { @@ -524,14 +600,14 @@ if (m_channels == 0) { m_channels = reader->getChannelCount(); cerr << "Taking default channel count of " - << reader->getChannelCount() << " from file" << endl; + << reader->getChannelCount() << " from audio file" << endl; } } if (m_defaultSampleRate == 0) { m_defaultSampleRate = reader->getNativeRate(); cerr << "Taking default sample rate of " - << reader->getNativeRate() << "Hz from file" << endl; + << reader->getNativeRate() << "Hz from audio file" << endl; cerr << "(Note: Default may be overridden by transforms)" << endl; } @@ -616,6 +692,12 @@ if (!reader) { throw FailedToOpenFile(source); } + if (reader->getChannelCount() != m_channels || + reader->getNativeRate() != m_sampleRate) { + cerr << "NOTE: File will be mixed or resampled for processing, to: " + << m_channels << "ch at " + << m_sampleRate << "Hz" << endl; + } return reader; } @@ -628,12 +710,6 @@ cerr << "Audio file \"" << audioSource.toStdString() << "\": " << reader->getChannelCount() << "ch at " << reader->getNativeRate() << "Hz" << endl; - if (reader->getChannelCount() != m_channels || - reader->getNativeRate() != m_sampleRate) { - cerr << "NOTE: File will be mixed or resampled for processing, to: " - << m_channels << "ch at " - << m_sampleRate << "Hz" << endl; - } // allocate audio buffers float **data = new float *[m_channels]; @@ -671,7 +747,7 @@ PluginMap::iterator pi = m_plugins.find(plugin); - std::cerr << "Calling reset on " << plugin << std::endl; +// std::cerr << "Calling reset on " << plugin << std::endl; plugin->reset(); for (TransformWriterMap::iterator ti = pi->second.begin(); @@ -852,6 +928,7 @@ } if (!m_summaries.empty()) { + // Summaries requested on the command line, for all transforms PluginSummarisingAdapter *adapter = dynamic_cast<PluginSummarisingAdapter *>(plugin); if (!adapter) { @@ -868,12 +945,13 @@ featureSet = adapter->getSummaryForAllOutputs (getSummaryType(*sni), PluginSummarisingAdapter::ContinuousTimeAverage); - writeFeatures(audioSource, plugin, featureSet,//!!! *sni); + writeFeatures(audioSource, plugin, featureSet, Transform::stringToSummaryType(sni->c_str())); } } } + // Summaries specified in transform definitions themselves writeSummaries(audioSource, plugin); } @@ -895,11 +973,15 @@ const Transform &transform = ti->first; +// cerr << "FeatureExtractionManager::writeSummaries: plugin is " << plugin +// << ", found transform: " << transform.toXmlString() << endl; + Transform::SummaryType summaryType = transform.getSummaryType(); PluginSummarisingAdapter::SummaryType pType = (PluginSummarisingAdapter::SummaryType)summaryType; if (transform.getSummaryType() == Transform::NoSummary) { +// cerr << "(no summary, continuing)" << endl; continue; } @@ -913,7 +995,7 @@ Plugin::FeatureSet featureSet = adapter->getSummaryForAllOutputs (pType, PluginSummarisingAdapter::ContinuousTimeAverage); -// cout << "summary type " << int(pType) << " for transform:" << endl << transform.toXmlString().toStdString()<< endl << "... feature set with " << featureSet.size() << " elts" << endl; +// cerr << "summary type " << int(pType) << " for transform:" << endl << transform.toXmlString().toStdString()<< endl << "... feature set with " << featureSet.size() << " elts" << endl; writeFeatures(audioSource, plugin, featureSet, summaryType); } @@ -927,21 +1009,25 @@ // caller should have ensured plugin is in m_plugins PluginMap::iterator pi = m_plugins.find(plugin); + // Write features from the feature set passed in, according to the + // transforms listed for the given plugin with the given summary type + for (TransformWriterMap::const_iterator ti = pi->second.begin(); ti != pi->second.end(); ++ti) { const Transform &transform = ti->first; const vector<FeatureWriter *> &writers = ti->second; - - if (transform.getSummaryType() != Transform::NoSummary && - m_summaries.empty() && - summaryType == Transform::NoSummary) { - continue; - } - if (transform.getSummaryType() != Transform::NoSummary && - summaryType != Transform::NoSummary && - transform.getSummaryType() != summaryType) { +// cerr << "writeFeatures: plugin " << plugin << " has transform: " << transform.toXmlString() << endl; + + if (transform.getSummaryType() == Transform::NoSummary && + !m_summaries.empty()) { +// cerr << "transform has no summary, but summaries requested on command line, so going for it anyway" << endl; + } else if (transform.getSummaryType() != summaryType) { + // Either we're not writing a summary and the transform + // has one, or we're writing a summary but the transform + // has none or a different one; either way, skip it +// cerr << "summary type differs from passed-in one " << summaryType << endl; continue; } @@ -959,6 +1045,8 @@ Plugin::FeatureSet::const_iterator fsi = features.find(outputIndex); if (fsi == features.end()) continue; +// cerr << "this transform has " << writers.size() << " writer(s)" << endl; + for (int j = 0; j < (int)writers.size(); ++j) { writers[j]->write (audioSource, transform, desc, fsi->second,