comparison vamp-sdk/hostext/PluginSummarisingAdapter.cpp @ 195:1e4c6f25ded6

* More accurate calculation of summaries in continuous-time mode * Labels * Make some debug output optional
author cannam
date Tue, 07 Oct 2008 16:57:10 +0000
parents 27cfae2a4155
children aaa55dfd2a1e
comparison
equal deleted inserted replaced
194:27cfae2a4155 195:1e4c6f25ded6
38 38
39 #include <map> 39 #include <map>
40 #include <cmath> 40 #include <cmath>
41 #include <climits> 41 #include <climits>
42 42
43 //#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1 43 #define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
44 //#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
44 45
45 namespace Vamp { 46 namespace Vamp {
46 47
47 namespace HostExt { 48 namespace HostExt {
48 49
50 { 51 {
51 public: 52 public:
52 Impl(Plugin *plugin, float inputSampleRate); 53 Impl(Plugin *plugin, float inputSampleRate);
53 ~Impl(); 54 ~Impl();
54 55
56 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
57
55 FeatureSet process(const float *const *inputBuffers, RealTime timestamp); 58 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
56 FeatureSet getRemainingFeatures(); 59 FeatureSet getRemainingFeatures();
57 60
58 void setSummarySegmentBoundaries(const SegmentBoundaries &); 61 void setSummarySegmentBoundaries(const SegmentBoundaries &);
59 62
65 AveragingMethod avg); 68 AveragingMethod avg);
66 69
67 protected: 70 protected:
68 Plugin *m_plugin; 71 Plugin *m_plugin;
69 float m_inputSampleRate; 72 float m_inputSampleRate;
73 size_t m_stepSize;
74 size_t m_blockSize;
70 75
71 SegmentBoundaries m_boundaries; 76 SegmentBoundaries m_boundaries;
72 77
73 typedef std::vector<float> ValueList; 78 typedef std::vector<float> ValueList;
74 79
100 struct OutputBinSummary { 105 struct OutputBinSummary {
101 106
102 int count; 107 int count;
103 108
104 // extents 109 // extents
105 float minimum; 110 double minimum;
106 float maximum; 111 double maximum;
107 float sum; 112 double sum;
108 113
109 // sample-average results 114 // sample-average results
110 float median; 115 double median;
111 float mode; 116 double mode;
112 float variance; 117 double variance;
113 118
114 // continuous-time average results 119 // continuous-time average results
115 float median_c; 120 double median_c;
116 float mode_c; 121 double mode_c;
117 float mean_c; 122 double mean_c;
118 float variance_c; 123 double variance_c;
119 }; 124 };
120 125
121 typedef std::map<int, OutputBinSummary> OutputSummary; 126 typedef std::map<int, OutputBinSummary> OutputSummary;
122 typedef std::map<RealTime, OutputSummary> SummarySegmentMap; 127 typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
123 typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap; 128 typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
124 129
125 OutputSummarySegmentMap m_summaries; 130 OutputSummarySegmentMap m_summaries;
126 131
127 bool m_reduced; 132 bool m_reduced;
128 RealTime m_lastTimestamp; 133 RealTime m_endTime;
129 134
130 void accumulate(const FeatureSet &fs, RealTime, bool final); 135 void accumulate(const FeatureSet &fs, RealTime, bool final);
131 void accumulate(int output, const Feature &f, RealTime, bool final); 136 void accumulate(int output, const Feature &f, RealTime, bool final);
132 void accumulateFinalDurations(); 137 void accumulateFinalDurations();
133 void findSegmentBounds(RealTime t, RealTime &start, RealTime &end); 138 void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
134 void segment(); 139 void segment();
135 void reduce(); 140 void reduce();
141
142 std::string getSummaryLabel(SummaryType type, AveragingMethod avg);
136 }; 143 };
137 144
138 static RealTime INVALID_DURATION(INT_MIN, INT_MIN); 145 static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
139 146
140 PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) : 147 PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
146 PluginSummarisingAdapter::~PluginSummarisingAdapter() 153 PluginSummarisingAdapter::~PluginSummarisingAdapter()
147 { 154 {
148 delete m_impl; 155 delete m_impl;
149 } 156 }
150 157
158 bool
159 PluginSummarisingAdapter::initialise(size_t channels,
160 size_t stepSize, size_t blockSize)
161 {
162 return
163 PluginWrapper::initialise(channels, stepSize, blockSize) &&
164 m_impl->initialise(channels, stepSize, blockSize);
165 }
166
151 Plugin::FeatureSet 167 Plugin::FeatureSet
152 PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp) 168 PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
153 { 169 {
154 return m_impl->process(inputBuffers, timestamp); 170 return m_impl->process(inputBuffers, timestamp);
155 } 171 }
190 206
191 PluginSummarisingAdapter::Impl::~Impl() 207 PluginSummarisingAdapter::Impl::~Impl()
192 { 208 {
193 } 209 }
194 210
211 bool
212 PluginSummarisingAdapter::Impl::initialise(size_t channels,
213 size_t stepSize, size_t blockSize)
214 {
215 m_stepSize = stepSize;
216 m_blockSize = blockSize;
217 return true;
218 }
219
195 Plugin::FeatureSet 220 Plugin::FeatureSet
196 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, RealTime timestamp) 221 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
222 RealTime timestamp)
197 { 223 {
198 if (m_reduced) { 224 if (m_reduced) {
199 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; 225 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
200 } 226 }
201 FeatureSet fs = m_plugin->process(inputBuffers, timestamp); 227 FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
202 accumulate(fs, timestamp, false); 228 accumulate(fs, timestamp, false);
203 //!!! should really be "timestamp plus step size" 229 m_endTime = timestamp +
204 m_lastTimestamp = timestamp; 230 RealTime::frame2RealTime(m_stepSize, m_inputSampleRate);
205 return fs; 231 return fs;
206 } 232 }
207 233
208 Plugin::FeatureSet 234 Plugin::FeatureSet
209 PluginSummarisingAdapter::Impl::getRemainingFeatures() 235 PluginSummarisingAdapter::Impl::getRemainingFeatures()
210 { 236 {
211 if (m_reduced) { 237 if (m_reduced) {
212 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; 238 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
213 } 239 }
214 FeatureSet fs = m_plugin->getRemainingFeatures(); 240 FeatureSet fs = m_plugin->getRemainingFeatures();
215 accumulate(fs, m_lastTimestamp, true); 241 accumulate(fs, m_endTime, true);
216 return fs; 242 return fs;
217 } 243 }
218 244
219 void 245 void
220 PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b) 246 PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
247 FeatureList fl; 273 FeatureList fl;
248 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); 274 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
249 i != m_summaries[output].end(); ++i) { 275 i != m_summaries[output].end(); ++i) {
250 276
251 Feature f; 277 Feature f;
278
252 f.hasTimestamp = true; 279 f.hasTimestamp = true;
253 f.timestamp = i->first; 280 f.timestamp = i->first;
254 f.hasDuration = false; 281
282 f.hasDuration = true;
283 SummarySegmentMap::const_iterator ii = i;
284 if (++ii == m_summaries[output].end()) {
285 f.duration = m_endTime - f.timestamp;
286 } else {
287 f.duration = ii->first - f.timestamp;
288 }
289
290 f.label = getSummaryLabel(type, avg);
255 291
256 for (OutputSummary::const_iterator j = i->second.begin(); 292 for (OutputSummary::const_iterator j = i->second.begin();
257 j != i->second.end(); ++j) { 293 j != i->second.end(); ++j) {
258 294
259 // these will be ordered by bin number, and no bin numbers 295 // these will be ordered by bin number, and no bin numbers
260 // will be missing except at the end (because of the way 296 // will be missing except at the end (because of the way
261 // the accumulators were initially filled in accumulate()) 297 // the accumulators were initially filled in accumulate())
262 298
263 const OutputBinSummary &summary = j->second; 299 const OutputBinSummary &summary = j->second;
264 float result = 0.f; 300 double result = 0.f;
265 301
266 switch (type) { 302 switch (type) {
267 303
268 case Minimum: 304 case Minimum:
269 result = summary.minimum; 305 result = summary.minimum;
359 } 395 }
360 } 396 }
361 } 397 }
362 } 398 }
363 399
400 std::string
401 PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
402 AveragingMethod avg)
403 {
404 std::string label;
405 std::string avglabel;
406
407 if (avg == SampleAverage) avglabel = ", sample average";
408 else avglabel = ", continuous-time average";
409
410 switch (type) {
411 case Minimum: label = "(minimum value)"; break;
412 case Maximum: label = "(maximum value)"; break;
413 case Mean: label = "(mean value" + avglabel + ")"; break;
414 case Median: label = "(median value" + avglabel + ")"; break;
415 case Mode: label = "(modal value" + avglabel + ")"; break;
416 case Sum: label = "(sum)"; break;
417 case Variance: label = "(variance" + avglabel + ")"; break;
418 case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
419 case Count: label = "(count)"; break;
420 case UnknownSummaryType: label = "(unknown summary)"; break;
421 }
422
423 return label;
424 }
425
364 void 426 void
365 PluginSummarisingAdapter::Impl::accumulate(int output, 427 PluginSummarisingAdapter::Impl::accumulate(int output,
366 const Feature &f, 428 const Feature &f,
367 RealTime timestamp, 429 RealTime timestamp,
368 bool final) 430 bool final)
450 if (f.hasDuration) m_prevDurations[output] = f.duration; 512 if (f.hasDuration) m_prevDurations[output] = f.duration;
451 else m_prevDurations[output] = INVALID_DURATION; 513 else m_prevDurations[output] = INVALID_DURATION;
452 514
453 m_prevTimestamps[output] = timestamp; 515 m_prevTimestamps[output] = timestamp;
454 516
455 //!!! should really be "timestamp plus duration" or "timestamp plus output resolution" 517 if (f.hasDuration) {
456 if (timestamp > m_lastTimestamp) m_lastTimestamp = timestamp; 518 RealTime et = timestamp;
519 et = et + f.duration;
520 if (et > m_endTime) m_endTime = et;
521 }
457 522
458 Result result; 523 Result result;
459 result.time = timestamp; 524 result.time = timestamp;
460 result.duration = INVALID_DURATION; 525 result.duration = INVALID_DURATION;
461 526
499 m_prevDurations[output]; 564 m_prevDurations[output];
500 565
501 } else { 566 } else {
502 567
503 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 568 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
504 std::cerr << "Pushing final duration from diff as " << m_lastTimestamp << " - " << m_prevTimestamps[output] << std::endl; 569 std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl;
505 #endif 570 #endif
506 571
507 m_accumulators[output].results[acount - 1].duration = 572 m_accumulators[output].results[acount - 1].duration =
508 m_lastTimestamp - m_prevTimestamps[output]; 573 m_endTime - m_prevTimestamps[output];
509 } 574 }
510 575
511 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 576 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
512 std::cerr << "so duration for result no " << acount-1 << " is " 577 std::cerr << "so duration for result no " << acount-1 << " is "
513 << m_accumulators[output].results[acount-1].duration 578 << m_accumulators[output].results[acount-1].duration
519 void 584 void
520 PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t, 585 PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
521 RealTime &start, 586 RealTime &start,
522 RealTime &end) 587 RealTime &end)
523 { 588 {
524 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 589 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
525 std::cerr << "findSegmentBounds: t = " << t << std::endl; 590 std::cerr << "findSegmentBounds: t = " << t << std::endl;
526 #endif 591 #endif
527 592
528 SegmentBoundaries::const_iterator i = std::upper_bound 593 SegmentBoundaries::const_iterator i = std::upper_bound
529 (m_boundaries.begin(), m_boundaries.end(), t); 594 (m_boundaries.begin(), m_boundaries.end(), t);
530 595
531 start = RealTime::zeroTime; 596 start = RealTime::zeroTime;
532 end = m_lastTimestamp; 597 end = m_endTime;
533 598
534 if (i != m_boundaries.end()) { 599 if (i != m_boundaries.end()) {
535 end = *i; 600 end = *i;
536 } 601 }
537 602
538 if (i != m_boundaries.begin()) { 603 if (i != m_boundaries.begin()) {
539 start = *--i; 604 start = *--i;
540 } 605 }
541 606
542 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 607 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
543 std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl; 608 std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl;
544 #endif 609 #endif
545 } 610 }
546 611
547 void 612 void
554 i != m_accumulators.end(); ++i) { 619 i != m_accumulators.end(); ++i) {
555 620
556 int output = i->first; 621 int output = i->first;
557 OutputAccumulator &source = i->second; 622 OutputAccumulator &source = i->second;
558 623
559 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 624 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
560 std::cerr << "segment: total results for output " << output << " = " 625 std::cerr << "segment: total results for output " << output << " = "
561 << source.results.size() << std::endl; 626 << source.results.size() << std::endl;
562 #endif 627 #endif
563 628
564 //!!! This is basically nonsense if the results have no values 629 //!!! This is basically nonsense if the results have no values
573 // We need to dispose it into segments appropriately 638 // We need to dispose it into segments appropriately
574 639
575 RealTime resultStart = source.results[n].time; 640 RealTime resultStart = source.results[n].time;
576 RealTime resultEnd = resultStart + source.results[n].duration; 641 RealTime resultEnd = resultStart + source.results[n].duration;
577 642
578 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 643 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
579 std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl; 644 std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl;
580 #endif 645 #endif
581 646
582 RealTime segmentStart = RealTime::zeroTime; 647 RealTime segmentStart = RealTime::zeroTime;
583 RealTime segmentEnd = resultEnd - RealTime(1, 0); 648 RealTime segmentEnd = resultEnd - RealTime(1, 0);
597 Result chunk; 662 Result chunk;
598 chunk.time = chunkStart; 663 chunk.time = chunkStart;
599 chunk.duration = chunkEnd - chunkStart; 664 chunk.duration = chunkEnd - chunkStart;
600 chunk.values = source.results[n].values; 665 chunk.values = source.results[n].values;
601 666
602 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 667 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
603 std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl; 668 std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl;
604 #endif 669 #endif
605 670
606 m_segmentedAccumulators[output][segmentStart].results 671 m_segmentedAccumulators[output][segmentStart].results
607 .push_back(chunk); 672 .push_back(chunk);
608 673
609 resultStart = chunkEnd; 674 resultStart = chunkEnd;
610 } 675 }
611 } 676 }
612 } 677 }
613
614
615
616 /*
617 if (boundaryitr == m_boundaries.end()) {
618 m_segmentedAccumulators[output][segmentStart] = source;
619 source.clear();
620 continue;
621 }
622 */
623
624
625
626
627 } 678 }
628 679
629 struct ValueDurationFloatPair 680 struct ValueDurationFloatPair
630 { 681 {
631 float value; 682 float value;
675 //!!! is this right? 726 //!!! is this right?
676 if (sz > 0) { 727 if (sz > 0) {
677 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 728 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
678 std::cerr << "last time = " << accumulator.results[sz-1].time 729 std::cerr << "last time = " << accumulator.results[sz-1].time
679 << ", duration = " << accumulator.results[sz-1].duration 730 << ", duration = " << accumulator.results[sz-1].duration
731 << " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
680 << std::endl; 732 << std::endl;
681 #endif 733 #endif
682 totalDuration = toSec((accumulator.results[sz-1].time + 734 totalDuration = toSec((accumulator.results[sz-1].time +
683 accumulator.results[sz-1].duration) - 735 accumulator.results[sz-1].duration) -
684 segmentStart); 736 segmentStart);
731 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 783 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
732 std::cerr << "total duration = " << totalDuration << std::endl; 784 std::cerr << "total duration = " << totalDuration << std::endl;
733 #endif 785 #endif
734 786
735 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 787 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
788 /*
736 std::cerr << "value vector for medians:" << std::endl; 789 std::cerr << "value vector for medians:" << std::endl;
737 for (int k = 0; k < sz; ++k) { 790 for (int k = 0; k < sz; ++k) {
738 std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") "; 791 std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
739 } 792 }
740 std::cerr << std::endl; 793 std::cerr << std::endl;
794 */
741 #endif 795 #endif
742 796
743 if (sz % 2 == 1) { 797 if (sz % 2 == 1) {
744 summary.median = valvec[sz/2].value; 798 summary.median = valvec[sz/2].value;
745 } else { 799 } else {
816 #endif 870 #endif
817 871
818 summary.mean_c = sum_c / totalDuration; 872 summary.mean_c = sum_c / totalDuration;
819 873
820 for (int k = 0; k < sz; ++k) { 874 for (int k = 0; k < sz; ++k) {
821 double value = accumulator.results[k].values[bin] 875 double value = accumulator.results[k].values[bin];
876 // * toSec(accumulator.results[k].duration);
877 summary.variance_c +=
878 (value - summary.mean_c) * (value - summary.mean_c)
822 * toSec(accumulator.results[k].duration); 879 * toSec(accumulator.results[k].duration);
823 summary.variance_c +=
824 (value - summary.mean_c) * (value - summary.mean_c);
825 } 880 }
826 881
827 summary.variance_c /= summary.count; 882 // summary.variance_c /= summary.count;
828 } 883 summary.variance_c /= totalDuration;
829 884 }
830 float mean = summary.sum / summary.count; 885
886 double mean = summary.sum / summary.count;
831 887
832 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER 888 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
833 std::cerr << "mean = " << summary.sum << " / " << summary.count << " = " 889 std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
834 << summary.sum / summary.count << std::endl; 890 << summary.sum / summary.count << std::endl;
835 #endif 891 #endif