# HG changeset patch # User Chris Cannam # Date 1413356401 -3600 # Node ID 946115b8baddf4bb718cbe3ca15934e6cd3e6f53 # Parent 0fd5c3c28814db66b9a9cd11044692c2ed699731 Proper implementation of fill-ends flag in LabFeatureWriter diff -r 0fd5c3c28814 -r 946115b8badd runner/LabFeatureWriter.cpp --- a/runner/LabFeatureWriter.cpp Tue Oct 14 18:50:01 2014 +0100 +++ b/runner/LabFeatureWriter.cpp Wed Oct 15 08:00:01 2014 +0100 @@ -78,58 +78,99 @@ const Transform &transform, const Plugin::OutputDescriptor& , const Plugin::FeatureList& features, - std::string summaryType) + std::string) { // Select appropriate output file for our track/transform // combination - QTextStream *sptr = getOutputStream(trackId, transform.getIdentifier()); + TransformId transformId = transform.getIdentifier(); + + QTextStream *sptr = getOutputStream(trackId, transformId); if (!sptr) { - throw FailedToOpenOutputStream(trackId, transform.getIdentifier()); + throw FailedToOpenOutputStream(trackId, transformId); } QTextStream &stream = *sptr; - QString sep = "\t"; + int n = features.size(); - for (unsigned int i = 0; i < features.size(); ++i) { + if (n == 0) return; - QString timestamp = features[i].timestamp.toString().c_str(); - timestamp.replace(QRegExp("^ +"), ""); - stream << timestamp; + TrackTransformPair tt(trackId, transformId); - Vamp::RealTime endTime; - bool haveEndTime = true; + if (m_pending.find(tt) != m_pending.end()) { + writeFeature(stream, m_pending[tt], &features[0]); + m_pending.erase(tt); + } - if (features[i].hasDuration) { - endTime = features[i].timestamp + features[i].duration; - } else if (m_forceEnd) { - if (i+1 < features.size()) { - endTime = features[i+1].timestamp; - } else { - //!!! what to do??? can we get the end time of the input file? - endTime = features[i].timestamp; - } - } else { - haveEndTime = false; - } + if (m_forceEnd) { + // can't write final feature until we know its end time + --n; + m_pending[tt] = features[n]; + } - if (haveEndTime) { - QString e = endTime.toString().c_str(); - e.replace(QRegExp("^ +"), ""); - stream << sep << e; - } - - for (unsigned int j = 0; j < features[i].values.size(); ++j) { - stream << sep << features[i].values[j]; - } - - if (features[i].label != "") { - stream << sep << "\"" << features[i].label.c_str() << "\""; - } - - stream << "\n"; + for (int i = 0; i < n; ++i) { + writeFeature(stream, features[i], m_forceEnd ? &features[i+1] : 0); } } +void +LabFeatureWriter::finish() +{ + for (PendingFeatures::const_iterator i = m_pending.begin(); + i != m_pending.end(); ++i) { + TrackTransformPair tt = i->first; + Plugin::Feature f = i->second; + QTextStream *sptr = getOutputStream(tt.first, tt.second); + if (!sptr) { + throw FailedToOpenOutputStream(tt.first, tt.second); + } + QTextStream &stream = *sptr; + // final feature has its own time as end time (we can't + // reliably determine the end of audio file, and because of + // the nature of block processing, the feature could even + // start beyond that anyway) + writeFeature(stream, f, &f); + } +} +void +LabFeatureWriter::writeFeature(QTextStream &stream, + const Plugin::Feature &f, + const Plugin::Feature *optionalNextFeature) +{ + QString sep = "\t"; + + QString timestamp = f.timestamp.toString().c_str(); + timestamp.replace(QRegExp("^ +"), ""); + stream << timestamp; + + Vamp::RealTime endTime; + bool haveEndTime = true; + + if (f.hasDuration) { + endTime = f.timestamp + f.duration; + } else if (optionalNextFeature) { + endTime = optionalNextFeature->timestamp; + } else { + haveEndTime = false; + } + + if (haveEndTime) { + QString e = endTime.toString().c_str(); + e.replace(QRegExp("^ +"), ""); + stream << sep << e; + } + + for (unsigned int j = 0; j < f.values.size(); ++j) { + stream << sep << f.values[j]; + } + + if (f.label != "") { + stream << sep << "\"" << f.label.c_str() << "\""; + } + + stream << "\n"; +} + + diff -r 0fd5c3c28814 -r 946115b8badd runner/LabFeatureWriter.h --- a/runner/LabFeatureWriter.h Tue Oct 14 18:50:01 2014 +0100 +++ b/runner/LabFeatureWriter.h Wed Oct 15 08:00:01 2014 +0100 @@ -51,10 +51,19 @@ const Vamp::Plugin::FeatureList &features, std::string summaryType = ""); + virtual void finish(); + virtual QString getWriterTag() const { return "lab"; } private: bool m_forceEnd; + + typedef map PendingFeatures; + PendingFeatures m_pending; + + void writeFeature(QTextStream &, + const Vamp::Plugin::Feature &f, + const Vamp::Plugin::Feature *optionalNextFeature); }; #endif diff -r 0fd5c3c28814 -r 946115b8badd tests/test-lab-writer/expected/curve-vsr-fill-ends.lab --- a/tests/test-lab-writer/expected/curve-vsr-fill-ends.lab Tue Oct 14 18:50:01 2014 +0100 +++ b/tests/test-lab-writer/expected/curve-vsr-fill-ends.lab Wed Oct 15 08:00:01 2014 +0100 @@ -2,7 +2,7 @@ 0.750000000 1.500000000 0.1 "2 of 10: 0.1 at 0.75" 1.500000000 2.250000000 0.2 "3 of 10: 0.2 at 1.5" 2.250000000 3.000000000 0.3 "4 of 10: 0.3 at 2.25" -3.000000000 3.7500000000 0.4 "5 of 10: 0.4 at 3" +3.000000000 3.750000000 0.4 "5 of 10: 0.4 at 3" 3.750000000 4.500000000 0.5 "6 of 10: 0.5 at 3.75" 4.500000000 5.250000000 0.6 "7 of 10: 0.6 at 4.5" 5.250000000 6.000000000 0.7 "8 of 10: 0.7 at 5.25"