# HG changeset patch # User cannam # Date 1221140819 0 # Node ID 701505ac170c052e166d57ae670a8514eef99052 # Parent 26c200c3fc426c0638c5fc4c81b1092384d59969 * Reorganise accumulators to facilitate segmentation diff -r 26c200c3fc42 -r 701505ac170c vamp-sdk/hostext/PluginSummarisingAdapter.cpp --- a/vamp-sdk/hostext/PluginSummarisingAdapter.cpp Wed Sep 10 14:54:25 2008 +0000 +++ b/vamp-sdk/hostext/PluginSummarisingAdapter.cpp Thu Sep 11 13:46:59 2008 +0000 @@ -67,21 +67,30 @@ float m_inputSampleRate; SegmentBoundaries m_boundaries; - + typedef std::vector ValueList; - typedef std::map BinValueMap; - typedef std::vector DurationList; - + + struct Result { // smaller than Feature + RealTime time; + RealTime duration; + ValueList values; // bin number -> value + }; + + typedef std::vector ResultList; + struct OutputAccumulator { - int count; - BinValueMap values; // bin number -> values ordered by time - DurationList durations; - OutputAccumulator() : count(0), values(), durations() { } + int bins; + ResultList results; + OutputAccumulator() : bins(0) { } }; typedef std::map OutputAccumulatorMap; OutputAccumulatorMap m_accumulators; // output number -> accumulator + typedef std::map SegmentAccumulatorMap; + typedef std::map OutputSegmentAccumulatorMap; + OutputSegmentAccumulatorMap m_segmentedAccumulators; + typedef std::map OutputTimestampMap; OutputTimestampMap m_prevTimestamps; // output number -> timestamp OutputTimestampMap m_prevDurations; // output number -> durations @@ -119,6 +128,7 @@ void accumulate(const FeatureSet &fs, RealTime, bool final); void accumulate(int output, const Feature &f, RealTime, bool final); void accumulateFinalDurations(); + void segment(); void reduce(); }; @@ -181,6 +191,7 @@ } FeatureSet fs = m_plugin->process(inputBuffers, timestamp); accumulate(fs, timestamp, false); + //!!! should really be "timestamp plus step size" m_lastTimestamp = timestamp; return fs; } @@ -201,7 +212,11 @@ SummaryType type, AveragingMethod avg) { - if (!m_reduced) reduce(); + if (!m_reduced) { + segment(); + reduce(); + m_reduced = true; + } bool continuous = (avg == ContinuousTimeAverage); @@ -286,7 +301,11 @@ PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, AveragingMethod avg) { - if (!m_reduced) reduce(); + if (!m_reduced) { + segment(); + reduce(); + m_reduced = true; + } FeatureSet fs; for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); @@ -321,8 +340,22 @@ bool final) { //!!! to do: use timestamp to determine which segment we're on + +//!!! What should happen if a feature's duration spans a segment +// boundary? I think we probably want to chop it, and pretend that it +// appears in both -- don't we? do we? A very long feature (e.g. key, +// if the whole audio is in a single key) might span many or all +// segments, and we want that to be reflected in the results (e.g. it +// is the modal key in all of those segments, not just the first). +// That is actually quite complicated to do! - m_accumulators[output].count++; +//!!! This affects how we record things. If features spanning a +// boundary should be chopped, then we need to have per-segment +// accumulators (and the feature value goes into both -- perhaps we +// need a separate phase to split the accumulator up into segments). +// If features spanning a boundary should be counted only in the first +// segment, with their full duration, then we should store them in a +// single accumulator and distribute into segments only on reduce. std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl; @@ -373,18 +406,33 @@ std::cerr << "output " << output << ": "; std::cerr << "Pushing previous duration as " << prevDuration << std::endl; - m_accumulators[output].durations.push_back(prevDuration); + + m_accumulators[output].results + [m_accumulators[output].results.size() - 1] + .duration = prevDuration; } if (f.hasDuration) m_prevDurations[output] = f.duration; else m_prevDurations[output] = INVALID_DURATION; m_prevTimestamps[output] = timestamp; + + //!!! should really be "timestamp plus duration" or "timestamp plus output resolution" if (timestamp > m_lastTimestamp) m_lastTimestamp = timestamp; + Result result; + result.time = timestamp; + result.duration = INVALID_DURATION; + + if (f.values.size() > m_accumulators[output].bins) { + m_accumulators[output].bins = f.values.size(); + } + for (int i = 0; i < int(f.values.size()); ++i) { - m_accumulators[output].values[i].push_back(f.values[i]); + result.values.push_back(f.values[i]); } + + m_accumulators[output].results.push_back(result); } void @@ -394,6 +442,11 @@ i != m_prevTimestamps.end(); ++i) { int output = i->first; + + int acount = m_accumulators[output].results.size(); + + if (acount == 0) continue; + RealTime prevTimestamp = i->second; std::cerr << "output " << output << ": "; @@ -403,18 +456,50 @@ std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl; - m_accumulators[output].durations.push_back(m_prevDurations[output]); + m_accumulators[output].results[acount - 1].duration = + m_prevDurations[output]; } else { std::cerr << "Pushing final duration from diff as " << m_lastTimestamp << " - " << m_prevTimestamps[output] << std::endl; - m_accumulators[output].durations.push_back - (m_lastTimestamp - m_prevTimestamps[output]); + m_accumulators[output].results[acount - 1].duration = + m_lastTimestamp - m_prevTimestamps[output]; } } } +void +PluginSummarisingAdapter::Impl::segment() +{ +/* + SegmentBoundaries::iterator boundaryitr = m_boundaries.begin(); + RealTime segmentStart = RealTime::zeroTime; + + for (OutputAccumulatorMap::iterator i = m_accumulators.begin(); + i != m_accumulators.end(); ++i) { + + int output = i->first; + OutputAccumulator &source = i->second; + RealTime accumulatedTime = RealTime::zeroTime; + + for (int n = 0; n < source.durations.size(); ++n) { +*/ + + +/* + if (boundaryitr == m_boundaries.end()) { + m_segmentedAccumulators[output][segmentStart] = source; + source.clear(); + continue; + } +*/ + + + + +} + struct ValueDurationFloatPair { float value; @@ -450,23 +535,22 @@ int output = i->first; OutputAccumulator &accumulator = i->second; + int sz = accumulator.results.size(); + double totalDuration = 0.0; - for (int k = 0; k < accumulator.durations.size(); ++k) { - totalDuration += toSec(accumulator.durations[k]); + //!!! is this right? + if (sz > 0) { + totalDuration = toSec(accumulator.results[sz-1].time + + accumulator.results[sz-1].duration); } - for (BinValueMap::iterator j = accumulator.values.begin(); - j != accumulator.values.end(); ++j) { + for (int bin = 0; bin < accumulator.bins; ++bin) { // work on all values over time for a single bin - int bin = j->first; - const ValueList &values = j->second; - const DurationList &durations = accumulator.durations; - OutputBinSummary summary; - summary.count = accumulator.count; + summary.count = sz; summary.minimum = 0.f; summary.maximum = 0.f; @@ -481,24 +565,22 @@ summary.mean_c = 0.f; summary.variance_c = 0.f; - if (summary.count == 0 || values.empty()) continue; - - int sz = values.size(); - - if (sz != durations.size()) { - std::cerr << "WARNING: sz " << sz << " != durations.size() " - << durations.size() << std::endl; -// while (durations.size() < sz) { -// durations.push_back(RealTime::zeroTime); -// } -//!!! then what? - } + if (sz == 0) continue; std::vector valvec; for (int k = 0; k < sz; ++k) { - valvec.push_back(ValueDurationFloatPair(values[k], - toSec(durations[k]))); + while (accumulator.results[k].values.size() < + accumulator.bins) { + accumulator.results[k].values.push_back(0.f); + } + } + + for (int k = 0; k < sz; ++k) { + float value = accumulator.results[k].values[bin]; + valvec.push_back(ValueDurationFloatPair + (value, + toSec(accumulator.results[k].duration))); } std::sort(valvec.begin(), valvec.end()); @@ -522,12 +604,15 @@ break; } } + + std::cerr << "median_c = " << summary.median_c << std::endl; + std::cerr << "median = " << summary.median << std::endl; std::map distribution; for (int k = 0; k < sz; ++k) { - summary.sum += values[k]; - distribution[values[k]] += 1; + summary.sum += accumulator.results[k].values[bin]; + distribution[accumulator.results[k].values[bin]] += 1; } int md = 0; @@ -542,13 +627,11 @@ distribution.clear(); - //!!! we want to omit this bit if the features all have - //!!! equal duration (and set mode_c equal to mode instead) - std::map distribution_c; for (int k = 0; k < sz; ++k) { - distribution_c[values[k]] += toSec(durations[k]); + distribution_c[accumulator.results[k].values[bin]] + += toSec(accumulator.results[k].duration); } double mrd = 0.0; @@ -568,7 +651,8 @@ double sum_c = 0.0; for (int k = 0; k < sz; ++k) { - double value = values[k] * toSec(durations[k]); + double value = accumulator.results[k].values[bin] + * toSec(accumulator.results[k].duration); sum_c += value; } @@ -578,7 +662,8 @@ summary.mean_c = sum_c / totalDuration; for (int k = 0; k < sz; ++k) { - double value = values[k] * toSec(durations[k]); + double value = accumulator.results[k].values[bin] + * toSec(accumulator.results[k].duration); summary.variance_c += (value - summary.mean_c) * (value - summary.mean_c); } @@ -586,15 +671,14 @@ summary.variance_c /= summary.count; } - //!!! still to handle: median_c - float mean = summary.sum / summary.count; std::cerr << "mean = " << summary.sum << " / " << summary.count << " = " << summary.sum / summary.count << std::endl; for (int k = 0; k < sz; ++k) { - summary.variance += (values[k] - mean) * (values[k] - mean); + float value = accumulator.results[k].values[bin]; + summary.variance += (value - mean) * (value - mean); } summary.variance /= summary.count; @@ -603,7 +687,6 @@ } m_accumulators.clear(); - m_reduced = true; }