upgrade VAMP SDK to latest (or newer) version
[ardour2.git] / libs / vamp-sdk / src / vamp-hostsdk / PluginSummarisingAdapter.cpp
blobe3547a3daacfdb0b5e06b85a0791caa1e95df1cd
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
3 /*
4 Vamp
6 An API for audio analysis and feature extraction plugins.
8 Centre for Digital Music, Queen Mary, University of London.
9 Copyright 2006-2009 Chris Cannam and QMUL.
11 Permission is hereby granted, free of charge, to any person
12 obtaining a copy of this software and associated documentation
13 files (the "Software"), to deal in the Software without
14 restriction, including without limitation the rights to use, copy,
15 modify, merge, publish, distribute, sublicense, and/or sell copies
16 of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 Except as contained in this notice, the names of the Centre for
31 Digital Music; Queen Mary, University of London; and Chris Cannam
32 shall not be used in advertising or otherwise to promote the sale,
33 use or other dealings in this Software without prior written
34 authorization.
37 #include "vamp-hostsdk/PluginSummarisingAdapter.h"
39 #include <map>
40 #include <algorithm>
41 #include <cmath>
42 #include <climits>
44 //#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
45 //#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
47 _VAMP_SDK_HOSTSPACE_BEGIN(PluginSummarisingAdapter.cpp)
49 namespace Vamp {
51 namespace HostExt {
53 class PluginSummarisingAdapter::Impl
55 public:
56 Impl(Plugin *plugin, float inputSampleRate);
57 ~Impl();
59 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
61 void reset();
63 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
64 FeatureSet getRemainingFeatures();
66 void setSummarySegmentBoundaries(const SegmentBoundaries &);
68 FeatureList getSummaryForOutput(int output,
69 SummaryType type,
70 AveragingMethod avg);
72 FeatureSet getSummaryForAllOutputs(SummaryType type,
73 AveragingMethod avg);
75 protected:
76 Plugin *m_plugin;
77 float m_inputSampleRate;
78 size_t m_stepSize;
79 size_t m_blockSize;
81 SegmentBoundaries m_boundaries;
83 typedef std::vector<float> ValueList;
85 struct Result { // smaller than Feature
86 RealTime time;
87 RealTime duration;
88 ValueList values; // bin number -> value
91 typedef std::vector<Result> ResultList;
93 struct OutputAccumulator {
94 int bins;
95 ResultList results;
96 OutputAccumulator() : bins(0) { }
99 typedef std::map<int, OutputAccumulator> OutputAccumulatorMap;
100 OutputAccumulatorMap m_accumulators; // output number -> accumulator
102 typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap;
103 typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap;
104 OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented
106 typedef std::map<int, RealTime> OutputTimestampMap;
107 OutputTimestampMap m_prevTimestamps; // output number -> timestamp
108 OutputTimestampMap m_prevDurations; // output number -> durations
110 struct OutputBinSummary {
112 int count;
114 // extents
115 double minimum;
116 double maximum;
117 double sum;
119 // sample-average results
120 double median;
121 double mode;
122 double variance;
124 // continuous-time average results
125 double median_c;
126 double mode_c;
127 double mean_c;
128 double variance_c;
131 typedef std::map<int, OutputBinSummary> OutputSummary;
132 typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
133 typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
135 OutputSummarySegmentMap m_summaries;
137 bool m_reduced;
138 RealTime m_endTime;
140 void accumulate(const FeatureSet &fs, RealTime, bool final);
141 void accumulate(int output, const Feature &f, RealTime, bool final);
142 void accumulateFinalDurations();
143 void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
144 void segment();
145 void reduce();
147 std::string getSummaryLabel(SummaryType type, AveragingMethod avg);
150 static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
152 PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
153 PluginWrapper(plugin)
155 m_impl = new Impl(plugin, m_inputSampleRate);
158 PluginSummarisingAdapter::~PluginSummarisingAdapter()
160 delete m_impl;
163 bool
164 PluginSummarisingAdapter::initialise(size_t channels,
165 size_t stepSize, size_t blockSize)
167 return
168 PluginWrapper::initialise(channels, stepSize, blockSize) &&
169 m_impl->initialise(channels, stepSize, blockSize);
172 void
173 PluginSummarisingAdapter::reset()
175 m_impl->reset();
178 Plugin::FeatureSet
179 PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
181 return m_impl->process(inputBuffers, timestamp);
184 Plugin::FeatureSet
185 PluginSummarisingAdapter::getRemainingFeatures()
187 return m_impl->getRemainingFeatures();
190 void
191 PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b)
193 m_impl->setSummarySegmentBoundaries(b);
196 Plugin::FeatureList
197 PluginSummarisingAdapter::getSummaryForOutput(int output,
198 SummaryType type,
199 AveragingMethod avg)
201 return m_impl->getSummaryForOutput(output, type, avg);
204 Plugin::FeatureSet
205 PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
206 AveragingMethod avg)
208 return m_impl->getSummaryForAllOutputs(type, avg);
211 PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
212 m_plugin(plugin),
213 m_inputSampleRate(inputSampleRate),
214 m_reduced(false)
218 PluginSummarisingAdapter::Impl::~Impl()
222 bool
223 PluginSummarisingAdapter::Impl::initialise(size_t channels,
224 size_t stepSize, size_t blockSize)
226 m_stepSize = stepSize;
227 m_blockSize = blockSize;
228 return true;
231 void
232 PluginSummarisingAdapter::Impl::reset()
234 m_accumulators.clear();
235 m_segmentedAccumulators.clear();
236 m_prevTimestamps.clear();
237 m_prevDurations.clear();
238 m_summaries.clear();
239 m_reduced = false;
240 m_endTime = RealTime();
241 m_plugin->reset();
244 Plugin::FeatureSet
245 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
246 RealTime timestamp)
248 if (m_reduced) {
249 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
251 FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
252 accumulate(fs, timestamp, false);
253 m_endTime = timestamp +
254 RealTime::frame2RealTime(m_stepSize, int(m_inputSampleRate + 0.5));
255 return fs;
258 Plugin::FeatureSet
259 PluginSummarisingAdapter::Impl::getRemainingFeatures()
261 if (m_reduced) {
262 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
264 FeatureSet fs = m_plugin->getRemainingFeatures();
265 accumulate(fs, m_endTime, true);
266 return fs;
269 void
270 PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
272 m_boundaries = b;
273 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
274 std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl;
275 for (SegmentBoundaries::const_iterator i = m_boundaries.begin();
276 i != m_boundaries.end(); ++i) {
277 std::cerr << *i << " ";
279 std::cerr << std::endl;
280 #endif
283 Plugin::FeatureList
284 PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
285 SummaryType type,
286 AveragingMethod avg)
288 if (!m_reduced) {
289 accumulateFinalDurations();
290 segment();
291 reduce();
292 m_reduced = true;
295 bool continuous = (avg == ContinuousTimeAverage);
297 FeatureList fl;
298 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
299 i != m_summaries[output].end(); ++i) {
301 Feature f;
303 f.hasTimestamp = true;
304 f.timestamp = i->first;
306 f.hasDuration = true;
307 SummarySegmentMap::const_iterator ii = i;
308 if (++ii == m_summaries[output].end()) {
309 f.duration = m_endTime - f.timestamp;
310 } else {
311 f.duration = ii->first - f.timestamp;
314 f.label = getSummaryLabel(type, avg);
316 for (OutputSummary::const_iterator j = i->second.begin();
317 j != i->second.end(); ++j) {
319 // these will be ordered by bin number, and no bin numbers
320 // will be missing except at the end (because of the way
321 // the accumulators were initially filled in accumulate())
323 const OutputBinSummary &summary = j->second;
324 double result = 0.f;
326 switch (type) {
328 case Minimum:
329 result = summary.minimum;
330 break;
332 case Maximum:
333 result = summary.maximum;
334 break;
336 case Mean:
337 if (continuous) {
338 result = summary.mean_c;
339 } else if (summary.count) {
340 result = summary.sum / summary.count;
342 break;
344 case Median:
345 if (continuous) result = summary.median_c;
346 else result = summary.median;
347 break;
349 case Mode:
350 if (continuous) result = summary.mode_c;
351 else result = summary.mode;
352 break;
354 case Sum:
355 result = summary.sum;
356 break;
358 case Variance:
359 if (continuous) result = summary.variance_c;
360 else result = summary.variance;
361 break;
363 case StandardDeviation:
364 if (continuous) result = sqrtf(summary.variance_c);
365 else result = sqrtf(summary.variance);
366 break;
368 case Count:
369 result = summary.count;
370 break;
372 case UnknownSummaryType:
373 break;
375 default:
376 break;
379 f.values.push_back(result);
382 fl.push_back(f);
384 return fl;
387 Plugin::FeatureSet
388 PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
389 AveragingMethod avg)
391 if (!m_reduced) {
392 accumulateFinalDurations();
393 segment();
394 reduce();
395 m_reduced = true;
398 FeatureSet fs;
399 for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
400 i != m_summaries.end(); ++i) {
401 fs[i->first] = getSummaryForOutput(i->first, type, avg);
403 return fs;
406 void
407 PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
408 RealTime timestamp,
409 bool final)
411 for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
412 for (FeatureList::const_iterator j = i->second.begin();
413 j != i->second.end(); ++j) {
414 if (j->hasTimestamp) {
415 accumulate(i->first, *j, j->timestamp, final);
416 } else {
417 //!!! is this correct?
418 accumulate(i->first, *j, timestamp, final);
424 std::string
425 PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
426 AveragingMethod avg)
428 std::string label;
429 std::string avglabel;
431 if (avg == SampleAverage) avglabel = ", sample average";
432 else avglabel = ", continuous-time average";
434 switch (type) {
435 case Minimum: label = "(minimum value)"; break;
436 case Maximum: label = "(maximum value)"; break;
437 case Mean: label = "(mean value" + avglabel + ")"; break;
438 case Median: label = "(median value" + avglabel + ")"; break;
439 case Mode: label = "(modal value" + avglabel + ")"; break;
440 case Sum: label = "(sum)"; break;
441 case Variance: label = "(variance" + avglabel + ")"; break;
442 case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
443 case Count: label = "(count)"; break;
444 case UnknownSummaryType: label = "(unknown summary)"; break;
447 return label;
450 void
451 PluginSummarisingAdapter::Impl::accumulate(int output,
452 const Feature &f,
453 RealTime timestamp,
454 bool final)
456 // What should happen if a feature's duration spans a segment
457 // boundary? I think we probably want to chop it, and pretend
458 // that it appears in both. A very long feature (e.g. key, if the
459 // whole audio is in a single key) might span many or all
460 // segments, and we want that to be reflected in the results
461 // (e.g. it is the modal key in all of those segments, not just
462 // the first). This is actually quite complicated to do.
464 // If features spanning a boundary should be chopped, then we need
465 // to have per-segment accumulators (and the feature value goes
466 // into both -- with a separate phase to split the accumulator up
467 // into segments).
469 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
470 std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl;
471 #endif
473 // At each process step, accumulate() is called once for each
474 // feature on each output within that process's returned feature
475 // list, and with the timestamp passed in being that of the start
476 // of the process block.
478 // At the end (in getRemainingFeatures), accumulate() is called
479 // once for each feature on each output within the feature list
480 // returned by getRemainingFeatures, and with the timestamp being
481 // the same as the last process block and final set to true.
483 // (What if getRemainingFeatures doesn't return any features? We
484 // still need to ensure that the final duration is written. Need
485 // a separate function to close the durations.)
487 // At each call, we pull out the value for the feature and stuff
488 // it into the accumulator's appropriate values array; and we
489 // calculate the duration for the _previous_ feature, or pull it
490 // from the prevDurations array if the previous feature had a
491 // duration in its structure, and stuff that into the
492 // accumulator's appropriate durations array.
494 if (m_prevDurations.find(output) != m_prevDurations.end()) {
496 // Not the first time accumulate has been called for this
497 // output -- there has been a previous feature
499 RealTime prevDuration;
501 // Note that m_prevDurations[output] only contains the
502 // duration field that was contained in the previous feature.
503 // If it didn't have an explicit duration,
504 // m_prevDurations[output] should be INVALID_DURATION and we
505 // will have to calculate the duration from the previous and
506 // current timestamps.
508 if (m_prevDurations[output] != INVALID_DURATION) {
509 prevDuration = m_prevDurations[output];
510 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
511 std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl;
512 #endif
513 } else {
514 prevDuration = timestamp - m_prevTimestamps[output];
515 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
516 std::cerr << "Previous duration from diff: " << timestamp << " - "
517 << m_prevTimestamps[output] << std::endl;
518 #endif
521 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
522 std::cerr << "output " << output << ": ";
523 std::cerr << "Pushing previous duration as " << prevDuration << std::endl;
524 #endif
526 m_accumulators[output].results
527 [m_accumulators[output].results.size() - 1]
528 .duration = prevDuration;
531 if (f.hasDuration) m_prevDurations[output] = f.duration;
532 else m_prevDurations[output] = INVALID_DURATION;
534 m_prevTimestamps[output] = timestamp;
536 if (f.hasDuration) {
537 RealTime et = timestamp;
538 et = et + f.duration;
539 if (et > m_endTime) m_endTime = et;
542 Result result;
543 result.time = timestamp;
544 result.duration = INVALID_DURATION;
546 if (int(f.values.size()) > m_accumulators[output].bins) {
547 m_accumulators[output].bins = f.values.size();
550 for (int i = 0; i < int(f.values.size()); ++i) {
551 result.values.push_back(f.values[i]);
554 m_accumulators[output].results.push_back(result);
557 void
558 PluginSummarisingAdapter::Impl::accumulateFinalDurations()
560 for (OutputTimestampMap::iterator i = m_prevTimestamps.begin();
561 i != m_prevTimestamps.end(); ++i) {
563 int output = i->first;
565 int acount = m_accumulators[output].results.size();
567 if (acount == 0) continue;
569 RealTime prevTimestamp = i->second;
571 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
572 std::cerr << "output " << output << ": ";
573 #endif
575 if (m_prevDurations.find(output) != m_prevDurations.end() &&
576 m_prevDurations[output] != INVALID_DURATION) {
578 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
579 std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl;
580 #endif
582 m_accumulators[output].results[acount - 1].duration =
583 m_prevDurations[output];
585 } else {
587 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
588 std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl;
589 #endif
591 m_accumulators[output].results[acount - 1].duration =
592 m_endTime - m_prevTimestamps[output];
595 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
596 std::cerr << "so duration for result no " << acount-1 << " is "
597 << m_accumulators[output].results[acount-1].duration
598 << std::endl;
599 #endif
603 void
604 PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
605 RealTime &start,
606 RealTime &end)
608 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
609 std::cerr << "findSegmentBounds: t = " << t << std::endl;
610 #endif
612 SegmentBoundaries::const_iterator i = std::upper_bound
613 (m_boundaries.begin(), m_boundaries.end(), t);
615 start = RealTime::zeroTime;
616 end = m_endTime;
618 if (i != m_boundaries.end()) {
619 end = *i;
622 if (i != m_boundaries.begin()) {
623 start = *--i;
626 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
627 std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl;
628 #endif
631 void
632 PluginSummarisingAdapter::Impl::segment()
634 SegmentBoundaries::iterator boundaryitr = m_boundaries.begin();
635 RealTime segmentStart = RealTime::zeroTime;
637 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
638 std::cerr << "segment: starting" << std::endl;
639 #endif
641 for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
642 i != m_accumulators.end(); ++i) {
644 int output = i->first;
645 OutputAccumulator &source = i->second;
647 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
648 std::cerr << "segment: total results for output " << output << " = "
649 << source.results.size() << std::endl;
650 #endif
652 // This is basically nonsense if the results have no values
653 // (i.e. their times and counts are the only things of
654 // interest)... but perhaps it's the user's problem if they
655 // ask for segmentation (or any summary at all) in that case
657 for (int n = 0; n < int(source.results.size()); ++n) {
659 // This result spans source.results[n].time to
660 // source.results[n].time + source.results[n].duration.
661 // We need to dispose it into segments appropriately
663 RealTime resultStart = source.results[n].time;
664 RealTime resultEnd = resultStart + source.results[n].duration;
666 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
667 std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl;
668 #endif
670 RealTime segmentStart = RealTime::zeroTime;
671 RealTime segmentEnd = resultEnd - RealTime(1, 0);
673 RealTime prevSegmentStart = segmentStart - RealTime(1, 0);
675 while (segmentEnd < resultEnd) {
677 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
678 std::cerr << "segment end " << segmentEnd << " < result end "
679 << resultEnd << " (with result start " << resultStart << ")" << std::endl;
680 #endif
682 findSegmentBounds(resultStart, segmentStart, segmentEnd);
684 if (segmentStart == prevSegmentStart) {
685 // This can happen when we reach the end of the
686 // input, if a feature's end time overruns the
687 // input audio end time
688 break;
690 prevSegmentStart = segmentStart;
692 RealTime chunkStart = resultStart;
693 if (chunkStart < segmentStart) chunkStart = segmentStart;
695 RealTime chunkEnd = resultEnd;
696 if (chunkEnd > segmentEnd) chunkEnd = segmentEnd;
698 m_segmentedAccumulators[output][segmentStart].bins = source.bins;
700 Result chunk;
701 chunk.time = chunkStart;
702 chunk.duration = chunkEnd - chunkStart;
703 chunk.values = source.results[n].values;
705 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
706 std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl;
707 #endif
709 m_segmentedAccumulators[output][segmentStart].results
710 .push_back(chunk);
712 resultStart = chunkEnd;
718 struct ValueDurationFloatPair
720 float value;
721 float duration;
723 ValueDurationFloatPair() : value(0), duration(0) { }
724 ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
725 ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
726 value = p.value;
727 duration = p.duration;
728 return *this;
730 bool operator<(const ValueDurationFloatPair &p) const {
731 return value < p.value;
735 static double toSec(const RealTime &r)
737 return r.sec + double(r.nsec) / 1000000000.0;
740 void
741 PluginSummarisingAdapter::Impl::reduce()
743 for (OutputSegmentAccumulatorMap::iterator i =
744 m_segmentedAccumulators.begin();
745 i != m_segmentedAccumulators.end(); ++i) {
747 int output = i->first;
748 SegmentAccumulatorMap &segments = i->second;
750 for (SegmentAccumulatorMap::iterator j = segments.begin();
751 j != segments.end(); ++j) {
753 RealTime segmentStart = j->first;
754 OutputAccumulator &accumulator = j->second;
756 int sz = accumulator.results.size();
758 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
759 std::cerr << "reduce: segment starting at " << segmentStart
760 << " on output " << output << " has " << sz << " result(s)" << std::endl;
761 #endif
763 double totalDuration = 0.0;
764 //!!! is this right?
765 if (sz > 0) {
766 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
767 std::cerr << "last time = " << accumulator.results[sz-1].time
768 << ", duration = " << accumulator.results[sz-1].duration
769 << " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
770 << std::endl;
771 #endif
772 totalDuration = toSec((accumulator.results[sz-1].time +
773 accumulator.results[sz-1].duration) -
774 segmentStart);
777 for (int bin = 0; bin < accumulator.bins; ++bin) {
779 // work on all values over time for a single bin
781 OutputBinSummary summary;
783 summary.count = sz;
785 summary.minimum = 0.f;
786 summary.maximum = 0.f;
788 summary.median = 0.f;
789 summary.mode = 0.f;
790 summary.sum = 0.f;
791 summary.variance = 0.f;
793 summary.median_c = 0.f;
794 summary.mode_c = 0.f;
795 summary.mean_c = 0.f;
796 summary.variance_c = 0.f;
798 if (sz == 0) continue;
800 std::vector<ValueDurationFloatPair> valvec;
802 for (int k = 0; k < sz; ++k) {
803 while (int(accumulator.results[k].values.size()) <
804 accumulator.bins) {
805 accumulator.results[k].values.push_back(0.f);
809 for (int k = 0; k < sz; ++k) {
810 float value = accumulator.results[k].values[bin];
811 valvec.push_back(ValueDurationFloatPair
812 (value,
813 toSec(accumulator.results[k].duration)));
816 std::sort(valvec.begin(), valvec.end());
818 summary.minimum = valvec[0].value;
819 summary.maximum = valvec[sz-1].value;
821 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
822 std::cerr << "total duration = " << totalDuration << std::endl;
823 #endif
825 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
827 std::cerr << "value vector for medians:" << std::endl;
828 for (int k = 0; k < sz; ++k) {
829 std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
831 std::cerr << std::endl;
833 #endif
835 if (sz % 2 == 1) {
836 summary.median = valvec[sz/2].value;
837 } else {
838 summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
841 double duracc = 0.0;
842 summary.median_c = valvec[sz-1].value;
844 for (int k = 0; k < sz; ++k) {
845 duracc += valvec[k].duration;
846 if (duracc > totalDuration/2) {
847 summary.median_c = valvec[k].value;
848 break;
852 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
853 std::cerr << "median_c = " << summary.median_c << std::endl;
854 std::cerr << "median = " << summary.median << std::endl;
855 #endif
857 std::map<float, int> distribution;
859 for (int k = 0; k < sz; ++k) {
860 summary.sum += accumulator.results[k].values[bin];
861 distribution[accumulator.results[k].values[bin]] += 1;
864 int md = 0;
866 for (std::map<float, int>::iterator di = distribution.begin();
867 di != distribution.end(); ++di) {
868 if (di->second > md) {
869 md = di->second;
870 summary.mode = di->first;
874 distribution.clear();
876 std::map<float, double> distribution_c;
878 for (int k = 0; k < sz; ++k) {
879 distribution_c[accumulator.results[k].values[bin]]
880 += toSec(accumulator.results[k].duration);
883 double mrd = 0.0;
885 for (std::map<float, double>::iterator di = distribution_c.begin();
886 di != distribution_c.end(); ++di) {
887 if (di->second > mrd) {
888 mrd = di->second;
889 summary.mode_c = di->first;
893 distribution_c.clear();
895 if (totalDuration > 0.0) {
897 double sum_c = 0.0;
899 for (int k = 0; k < sz; ++k) {
900 double value = accumulator.results[k].values[bin]
901 * toSec(accumulator.results[k].duration);
902 sum_c += value;
905 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
906 std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
907 << sum_c / totalDuration << " (sz = " << sz << ")" << std::endl;
908 #endif
910 summary.mean_c = sum_c / totalDuration;
912 for (int k = 0; k < sz; ++k) {
913 double value = accumulator.results[k].values[bin];
914 // * toSec(accumulator.results[k].duration);
915 summary.variance_c +=
916 (value - summary.mean_c) * (value - summary.mean_c)
917 * toSec(accumulator.results[k].duration);
920 // summary.variance_c /= summary.count;
921 summary.variance_c /= totalDuration;
924 double mean = summary.sum / summary.count;
926 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
927 std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
928 << summary.sum / summary.count << std::endl;
929 #endif
931 for (int k = 0; k < sz; ++k) {
932 float value = accumulator.results[k].values[bin];
933 summary.variance += (value - mean) * (value - mean);
935 summary.variance /= summary.count;
937 m_summaries[output][segmentStart][bin] = summary;
942 m_segmentedAccumulators.clear();
943 m_accumulators.clear();
951 _VAMP_SDK_HOSTSPACE_END(PluginSummarisingAdapter.cpp)