Mercurial > hg > vamp-plugin-sdk
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 |