cannam@233
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@233
|
2
|
cannam@233
|
3 /*
|
cannam@233
|
4 Vamp
|
cannam@233
|
5
|
cannam@233
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@233
|
7
|
cannam@233
|
8 Centre for Digital Music, Queen Mary, University of London.
|
cannam@290
|
9 Copyright 2006-2009 Chris Cannam and QMUL.
|
cannam@233
|
10
|
cannam@233
|
11 Permission is hereby granted, free of charge, to any person
|
cannam@233
|
12 obtaining a copy of this software and associated documentation
|
cannam@233
|
13 files (the "Software"), to deal in the Software without
|
cannam@233
|
14 restriction, including without limitation the rights to use, copy,
|
cannam@233
|
15 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@233
|
16 of the Software, and to permit persons to whom the Software is
|
cannam@233
|
17 furnished to do so, subject to the following conditions:
|
cannam@233
|
18
|
cannam@233
|
19 The above copyright notice and this permission notice shall be
|
cannam@233
|
20 included in all copies or substantial portions of the Software.
|
cannam@233
|
21
|
cannam@233
|
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@233
|
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@233
|
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@233
|
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@233
|
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@233
|
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@233
|
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@233
|
29
|
cannam@233
|
30 Except as contained in this notice, the names of the Centre for
|
cannam@233
|
31 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@233
|
32 shall not be used in advertising or otherwise to promote the sale,
|
cannam@233
|
33 use or other dealings in this Software without prior written
|
cannam@233
|
34 authorization.
|
cannam@233
|
35 */
|
cannam@233
|
36
|
cannam@233
|
37 #include <vamp-hostsdk/PluginSummarisingAdapter.h>
|
cannam@233
|
38
|
cannam@233
|
39 #include <map>
|
cannam@233
|
40 #include <algorithm>
|
cannam@233
|
41 #include <cmath>
|
cannam@233
|
42 #include <climits>
|
cannam@233
|
43
|
Chris@418
|
44 using namespace std;
|
Chris@418
|
45
|
cannam@273
|
46 //#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
|
cannam@233
|
47 //#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
|
cannam@233
|
48
|
cannam@263
|
49 _VAMP_SDK_HOSTSPACE_BEGIN(PluginSummarisingAdapter.cpp)
|
cannam@263
|
50
|
cannam@233
|
51 namespace Vamp {
|
cannam@233
|
52
|
cannam@233
|
53 namespace HostExt {
|
cannam@233
|
54
|
cannam@233
|
55 class PluginSummarisingAdapter::Impl
|
cannam@233
|
56 {
|
cannam@233
|
57 public:
|
cannam@233
|
58 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@233
|
59 ~Impl();
|
cannam@233
|
60
|
cannam@233
|
61 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@233
|
62
|
cannam@275
|
63 void reset();
|
cannam@275
|
64
|
cannam@233
|
65 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@233
|
66 FeatureSet getRemainingFeatures();
|
cannam@233
|
67
|
cannam@233
|
68 void setSummarySegmentBoundaries(const SegmentBoundaries &);
|
cannam@233
|
69
|
cannam@233
|
70 FeatureList getSummaryForOutput(int output,
|
cannam@233
|
71 SummaryType type,
|
cannam@233
|
72 AveragingMethod avg);
|
cannam@233
|
73
|
cannam@233
|
74 FeatureSet getSummaryForAllOutputs(SummaryType type,
|
cannam@233
|
75 AveragingMethod avg);
|
cannam@233
|
76
|
cannam@233
|
77 protected:
|
cannam@233
|
78 Plugin *m_plugin;
|
cannam@233
|
79 float m_inputSampleRate;
|
cannam@233
|
80 size_t m_stepSize;
|
cannam@233
|
81 size_t m_blockSize;
|
cannam@233
|
82
|
cannam@233
|
83 SegmentBoundaries m_boundaries;
|
cannam@233
|
84
|
Chris@418
|
85 typedef vector<float> ValueList;
|
cannam@233
|
86
|
cannam@233
|
87 struct Result { // smaller than Feature
|
cannam@233
|
88 RealTime time;
|
cannam@233
|
89 RealTime duration;
|
cannam@233
|
90 ValueList values; // bin number -> value
|
cannam@233
|
91 };
|
cannam@233
|
92
|
Chris@418
|
93 typedef vector<Result> ResultList;
|
cannam@233
|
94
|
cannam@233
|
95 struct OutputAccumulator {
|
cannam@233
|
96 int bins;
|
cannam@233
|
97 ResultList results;
|
cannam@233
|
98 OutputAccumulator() : bins(0) { }
|
cannam@233
|
99 };
|
cannam@233
|
100
|
Chris@418
|
101 typedef map<int, OutputAccumulator> OutputAccumulatorMap;
|
cannam@233
|
102 OutputAccumulatorMap m_accumulators; // output number -> accumulator
|
cannam@233
|
103
|
Chris@418
|
104 typedef map<RealTime, OutputAccumulator> SegmentAccumulatorMap;
|
Chris@418
|
105 typedef map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap;
|
cannam@233
|
106 OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented
|
cannam@233
|
107
|
Chris@418
|
108 typedef map<int, RealTime> OutputTimestampMap;
|
cannam@233
|
109 OutputTimestampMap m_prevTimestamps; // output number -> timestamp
|
cannam@233
|
110 OutputTimestampMap m_prevDurations; // output number -> durations
|
cannam@233
|
111
|
cannam@233
|
112 struct OutputBinSummary {
|
cannam@233
|
113
|
cannam@233
|
114 int count;
|
cannam@233
|
115
|
cannam@233
|
116 // extents
|
cannam@233
|
117 double minimum;
|
cannam@233
|
118 double maximum;
|
cannam@233
|
119 double sum;
|
cannam@233
|
120
|
cannam@233
|
121 // sample-average results
|
cannam@233
|
122 double median;
|
cannam@233
|
123 double mode;
|
cannam@233
|
124 double variance;
|
cannam@233
|
125
|
cannam@233
|
126 // continuous-time average results
|
cannam@233
|
127 double median_c;
|
cannam@233
|
128 double mode_c;
|
cannam@233
|
129 double mean_c;
|
cannam@233
|
130 double variance_c;
|
cannam@233
|
131 };
|
cannam@233
|
132
|
Chris@418
|
133 typedef map<int, OutputBinSummary> OutputSummary;
|
Chris@418
|
134 typedef map<RealTime, OutputSummary> SummarySegmentMap;
|
Chris@418
|
135 typedef map<int, SummarySegmentMap> OutputSummarySegmentMap;
|
cannam@233
|
136
|
cannam@233
|
137 OutputSummarySegmentMap m_summaries;
|
cannam@233
|
138
|
cannam@233
|
139 bool m_reduced;
|
cannam@233
|
140 RealTime m_endTime;
|
cannam@233
|
141
|
cannam@233
|
142 void accumulate(const FeatureSet &fs, RealTime, bool final);
|
cannam@233
|
143 void accumulate(int output, const Feature &f, RealTime, bool final);
|
cannam@233
|
144 void accumulateFinalDurations();
|
cannam@233
|
145 void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
|
cannam@233
|
146 void segment();
|
cannam@233
|
147 void reduce();
|
cannam@233
|
148
|
Chris@418
|
149 string getSummaryLabel(SummaryType type, AveragingMethod avg);
|
cannam@233
|
150 };
|
cannam@233
|
151
|
cannam@233
|
152 static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
|
cannam@233
|
153
|
cannam@233
|
154 PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
|
cannam@233
|
155 PluginWrapper(plugin)
|
cannam@233
|
156 {
|
cannam@233
|
157 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@233
|
158 }
|
cannam@233
|
159
|
cannam@233
|
160 PluginSummarisingAdapter::~PluginSummarisingAdapter()
|
cannam@233
|
161 {
|
cannam@233
|
162 delete m_impl;
|
cannam@233
|
163 }
|
cannam@233
|
164
|
cannam@233
|
165 bool
|
cannam@233
|
166 PluginSummarisingAdapter::initialise(size_t channels,
|
cannam@233
|
167 size_t stepSize, size_t blockSize)
|
cannam@233
|
168 {
|
cannam@233
|
169 return
|
cannam@233
|
170 PluginWrapper::initialise(channels, stepSize, blockSize) &&
|
cannam@233
|
171 m_impl->initialise(channels, stepSize, blockSize);
|
cannam@233
|
172 }
|
cannam@233
|
173
|
cannam@275
|
174 void
|
cannam@275
|
175 PluginSummarisingAdapter::reset()
|
cannam@275
|
176 {
|
cannam@275
|
177 m_impl->reset();
|
cannam@275
|
178 }
|
cannam@275
|
179
|
cannam@233
|
180 Plugin::FeatureSet
|
cannam@233
|
181 PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
|
cannam@233
|
182 {
|
cannam@233
|
183 return m_impl->process(inputBuffers, timestamp);
|
cannam@233
|
184 }
|
cannam@233
|
185
|
cannam@233
|
186 Plugin::FeatureSet
|
cannam@233
|
187 PluginSummarisingAdapter::getRemainingFeatures()
|
cannam@233
|
188 {
|
cannam@233
|
189 return m_impl->getRemainingFeatures();
|
cannam@233
|
190 }
|
cannam@233
|
191
|
cannam@233
|
192 void
|
cannam@233
|
193 PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b)
|
cannam@233
|
194 {
|
cannam@233
|
195 m_impl->setSummarySegmentBoundaries(b);
|
cannam@233
|
196 }
|
cannam@233
|
197
|
cannam@233
|
198 Plugin::FeatureList
|
cannam@233
|
199 PluginSummarisingAdapter::getSummaryForOutput(int output,
|
cannam@233
|
200 SummaryType type,
|
cannam@233
|
201 AveragingMethod avg)
|
cannam@233
|
202 {
|
cannam@233
|
203 return m_impl->getSummaryForOutput(output, type, avg);
|
cannam@233
|
204 }
|
cannam@233
|
205
|
cannam@233
|
206 Plugin::FeatureSet
|
cannam@233
|
207 PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
|
cannam@233
|
208 AveragingMethod avg)
|
cannam@233
|
209 {
|
cannam@233
|
210 return m_impl->getSummaryForAllOutputs(type, avg);
|
cannam@233
|
211 }
|
cannam@233
|
212
|
cannam@233
|
213 PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@233
|
214 m_plugin(plugin),
|
cannam@233
|
215 m_inputSampleRate(inputSampleRate),
|
cannam@233
|
216 m_reduced(false)
|
cannam@233
|
217 {
|
cannam@233
|
218 }
|
cannam@233
|
219
|
cannam@233
|
220 PluginSummarisingAdapter::Impl::~Impl()
|
cannam@233
|
221 {
|
cannam@233
|
222 }
|
cannam@233
|
223
|
cannam@233
|
224 bool
|
Chris@385
|
225 PluginSummarisingAdapter::Impl::initialise(size_t, size_t stepSize, size_t blockSize)
|
cannam@233
|
226 {
|
cannam@233
|
227 m_stepSize = stepSize;
|
cannam@233
|
228 m_blockSize = blockSize;
|
cannam@233
|
229 return true;
|
cannam@233
|
230 }
|
cannam@233
|
231
|
cannam@275
|
232 void
|
cannam@275
|
233 PluginSummarisingAdapter::Impl::reset()
|
cannam@275
|
234 {
|
cannam@275
|
235 m_accumulators.clear();
|
cannam@275
|
236 m_segmentedAccumulators.clear();
|
cannam@275
|
237 m_prevTimestamps.clear();
|
cannam@275
|
238 m_prevDurations.clear();
|
cannam@275
|
239 m_summaries.clear();
|
cannam@275
|
240 m_reduced = false;
|
cannam@275
|
241 m_endTime = RealTime();
|
cannam@275
|
242 m_plugin->reset();
|
cannam@275
|
243 }
|
cannam@275
|
244
|
cannam@233
|
245 Plugin::FeatureSet
|
cannam@233
|
246 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@233
|
247 RealTime timestamp)
|
cannam@233
|
248 {
|
cannam@233
|
249 if (m_reduced) {
|
Chris@418
|
250 cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << endl;
|
cannam@233
|
251 }
|
cannam@233
|
252 FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
|
cannam@233
|
253 accumulate(fs, timestamp, false);
|
cannam@233
|
254 m_endTime = timestamp +
|
cannam@272
|
255 RealTime::frame2RealTime(m_stepSize, int(m_inputSampleRate + 0.5));
|
Chris@418
|
256 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
257 cerr << "timestamp = " << timestamp << ", end time becomes " << m_endTime
|
Chris@418
|
258 << endl;
|
Chris@418
|
259 #endif
|
cannam@233
|
260 return fs;
|
cannam@233
|
261 }
|
cannam@233
|
262
|
cannam@233
|
263 Plugin::FeatureSet
|
cannam@233
|
264 PluginSummarisingAdapter::Impl::getRemainingFeatures()
|
cannam@233
|
265 {
|
cannam@233
|
266 if (m_reduced) {
|
Chris@418
|
267 cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << endl;
|
cannam@233
|
268 }
|
cannam@233
|
269 FeatureSet fs = m_plugin->getRemainingFeatures();
|
cannam@233
|
270 accumulate(fs, m_endTime, true);
|
cannam@233
|
271 return fs;
|
cannam@233
|
272 }
|
cannam@233
|
273
|
cannam@233
|
274 void
|
cannam@233
|
275 PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
|
cannam@233
|
276 {
|
cannam@233
|
277 m_boundaries = b;
|
cannam@233
|
278 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
279 cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << endl;
|
cannam@233
|
280 for (SegmentBoundaries::const_iterator i = m_boundaries.begin();
|
cannam@233
|
281 i != m_boundaries.end(); ++i) {
|
Chris@418
|
282 cerr << *i << " ";
|
cannam@233
|
283 }
|
Chris@418
|
284 cerr << endl;
|
cannam@233
|
285 #endif
|
cannam@233
|
286 }
|
cannam@233
|
287
|
cannam@233
|
288 Plugin::FeatureList
|
cannam@233
|
289 PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
|
cannam@233
|
290 SummaryType type,
|
cannam@233
|
291 AveragingMethod avg)
|
cannam@233
|
292 {
|
cannam@233
|
293 if (!m_reduced) {
|
cannam@233
|
294 accumulateFinalDurations();
|
cannam@233
|
295 segment();
|
cannam@233
|
296 reduce();
|
cannam@233
|
297 m_reduced = true;
|
cannam@233
|
298 }
|
cannam@233
|
299
|
cannam@233
|
300 bool continuous = (avg == ContinuousTimeAverage);
|
cannam@233
|
301
|
cannam@233
|
302 FeatureList fl;
|
cannam@233
|
303 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
|
cannam@233
|
304 i != m_summaries[output].end(); ++i) {
|
cannam@233
|
305
|
cannam@233
|
306 Feature f;
|
cannam@233
|
307
|
cannam@233
|
308 f.hasTimestamp = true;
|
cannam@233
|
309 f.timestamp = i->first;
|
cannam@233
|
310
|
cannam@233
|
311 f.hasDuration = true;
|
cannam@233
|
312 SummarySegmentMap::const_iterator ii = i;
|
cannam@233
|
313 if (++ii == m_summaries[output].end()) {
|
cannam@233
|
314 f.duration = m_endTime - f.timestamp;
|
cannam@233
|
315 } else {
|
cannam@233
|
316 f.duration = ii->first - f.timestamp;
|
cannam@233
|
317 }
|
cannam@233
|
318
|
cannam@233
|
319 f.label = getSummaryLabel(type, avg);
|
cannam@233
|
320
|
cannam@233
|
321 for (OutputSummary::const_iterator j = i->second.begin();
|
cannam@233
|
322 j != i->second.end(); ++j) {
|
cannam@233
|
323
|
cannam@233
|
324 // these will be ordered by bin number, and no bin numbers
|
cannam@233
|
325 // will be missing except at the end (because of the way
|
cannam@233
|
326 // the accumulators were initially filled in accumulate())
|
cannam@233
|
327
|
cannam@233
|
328 const OutputBinSummary &summary = j->second;
|
cannam@233
|
329 double result = 0.f;
|
cannam@233
|
330
|
cannam@233
|
331 switch (type) {
|
cannam@233
|
332
|
cannam@233
|
333 case Minimum:
|
cannam@233
|
334 result = summary.minimum;
|
cannam@233
|
335 break;
|
cannam@233
|
336
|
cannam@233
|
337 case Maximum:
|
cannam@233
|
338 result = summary.maximum;
|
cannam@233
|
339 break;
|
cannam@233
|
340
|
cannam@233
|
341 case Mean:
|
cannam@233
|
342 if (continuous) {
|
cannam@233
|
343 result = summary.mean_c;
|
cannam@233
|
344 } else if (summary.count) {
|
cannam@233
|
345 result = summary.sum / summary.count;
|
cannam@233
|
346 }
|
cannam@233
|
347 break;
|
cannam@233
|
348
|
cannam@233
|
349 case Median:
|
cannam@233
|
350 if (continuous) result = summary.median_c;
|
cannam@233
|
351 else result = summary.median;
|
cannam@233
|
352 break;
|
cannam@233
|
353
|
cannam@233
|
354 case Mode:
|
cannam@233
|
355 if (continuous) result = summary.mode_c;
|
cannam@233
|
356 else result = summary.mode;
|
cannam@233
|
357 break;
|
cannam@233
|
358
|
cannam@233
|
359 case Sum:
|
cannam@233
|
360 result = summary.sum;
|
cannam@233
|
361 break;
|
cannam@233
|
362
|
cannam@233
|
363 case Variance:
|
cannam@233
|
364 if (continuous) result = summary.variance_c;
|
cannam@233
|
365 else result = summary.variance;
|
cannam@233
|
366 break;
|
cannam@233
|
367
|
cannam@233
|
368 case StandardDeviation:
|
cannam@233
|
369 if (continuous) result = sqrtf(summary.variance_c);
|
cannam@233
|
370 else result = sqrtf(summary.variance);
|
cannam@233
|
371 break;
|
cannam@233
|
372
|
cannam@233
|
373 case Count:
|
cannam@233
|
374 result = summary.count;
|
cannam@233
|
375 break;
|
cannam@233
|
376
|
cannam@233
|
377 case UnknownSummaryType:
|
cannam@233
|
378 break;
|
cannam@233
|
379
|
cannam@233
|
380 default:
|
cannam@233
|
381 break;
|
cannam@233
|
382 }
|
cannam@233
|
383
|
cannam@233
|
384 f.values.push_back(result);
|
cannam@233
|
385 }
|
cannam@233
|
386
|
cannam@233
|
387 fl.push_back(f);
|
cannam@233
|
388 }
|
cannam@233
|
389 return fl;
|
cannam@233
|
390 }
|
cannam@233
|
391
|
cannam@233
|
392 Plugin::FeatureSet
|
cannam@233
|
393 PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
|
cannam@233
|
394 AveragingMethod avg)
|
cannam@233
|
395 {
|
cannam@233
|
396 if (!m_reduced) {
|
cannam@233
|
397 accumulateFinalDurations();
|
cannam@233
|
398 segment();
|
cannam@233
|
399 reduce();
|
cannam@233
|
400 m_reduced = true;
|
cannam@233
|
401 }
|
cannam@233
|
402
|
cannam@233
|
403 FeatureSet fs;
|
cannam@233
|
404 for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
|
cannam@233
|
405 i != m_summaries.end(); ++i) {
|
cannam@233
|
406 fs[i->first] = getSummaryForOutput(i->first, type, avg);
|
cannam@233
|
407 }
|
cannam@233
|
408 return fs;
|
cannam@233
|
409 }
|
cannam@233
|
410
|
cannam@233
|
411 void
|
cannam@233
|
412 PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
|
cannam@233
|
413 RealTime timestamp,
|
cannam@233
|
414 bool final)
|
cannam@233
|
415 {
|
cannam@233
|
416 for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
|
cannam@233
|
417 for (FeatureList::const_iterator j = i->second.begin();
|
cannam@233
|
418 j != i->second.end(); ++j) {
|
cannam@233
|
419 if (j->hasTimestamp) {
|
cannam@233
|
420 accumulate(i->first, *j, j->timestamp, final);
|
cannam@233
|
421 } else {
|
cannam@233
|
422 //!!! is this correct?
|
cannam@233
|
423 accumulate(i->first, *j, timestamp, final);
|
cannam@233
|
424 }
|
cannam@233
|
425 }
|
cannam@233
|
426 }
|
cannam@233
|
427 }
|
cannam@233
|
428
|
Chris@418
|
429 string
|
cannam@233
|
430 PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
|
cannam@233
|
431 AveragingMethod avg)
|
cannam@233
|
432 {
|
Chris@418
|
433 string label;
|
Chris@418
|
434 string avglabel;
|
cannam@233
|
435
|
cannam@233
|
436 if (avg == SampleAverage) avglabel = ", sample average";
|
cannam@233
|
437 else avglabel = ", continuous-time average";
|
cannam@233
|
438
|
cannam@233
|
439 switch (type) {
|
cannam@233
|
440 case Minimum: label = "(minimum value)"; break;
|
cannam@233
|
441 case Maximum: label = "(maximum value)"; break;
|
cannam@233
|
442 case Mean: label = "(mean value" + avglabel + ")"; break;
|
cannam@233
|
443 case Median: label = "(median value" + avglabel + ")"; break;
|
cannam@233
|
444 case Mode: label = "(modal value" + avglabel + ")"; break;
|
cannam@233
|
445 case Sum: label = "(sum)"; break;
|
cannam@233
|
446 case Variance: label = "(variance" + avglabel + ")"; break;
|
cannam@233
|
447 case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
|
cannam@233
|
448 case Count: label = "(count)"; break;
|
cannam@233
|
449 case UnknownSummaryType: label = "(unknown summary)"; break;
|
cannam@233
|
450 }
|
cannam@233
|
451
|
cannam@233
|
452 return label;
|
cannam@233
|
453 }
|
cannam@233
|
454
|
cannam@233
|
455 void
|
cannam@233
|
456 PluginSummarisingAdapter::Impl::accumulate(int output,
|
cannam@233
|
457 const Feature &f,
|
cannam@233
|
458 RealTime timestamp,
|
Chris@418
|
459 bool
|
Chris@418
|
460 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
461 final
|
Chris@418
|
462 #endif
|
Chris@418
|
463 )
|
cannam@233
|
464 {
|
cannam@248
|
465 // What should happen if a feature's duration spans a segment
|
cannam@248
|
466 // boundary? I think we probably want to chop it, and pretend
|
cannam@248
|
467 // that it appears in both. A very long feature (e.g. key, if the
|
cannam@248
|
468 // whole audio is in a single key) might span many or all
|
cannam@248
|
469 // segments, and we want that to be reflected in the results
|
cannam@248
|
470 // (e.g. it is the modal key in all of those segments, not just
|
cannam@248
|
471 // the first). This is actually quite complicated to do.
|
cannam@233
|
472
|
cannam@248
|
473 // If features spanning a boundary should be chopped, then we need
|
cannam@248
|
474 // to have per-segment accumulators (and the feature value goes
|
cannam@248
|
475 // into both -- with a separate phase to split the accumulator up
|
cannam@248
|
476 // into segments).
|
cannam@233
|
477
|
cannam@233
|
478 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
479 cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << endl;
|
cannam@233
|
480 #endif
|
cannam@233
|
481
|
cannam@233
|
482 // At each process step, accumulate() is called once for each
|
cannam@233
|
483 // feature on each output within that process's returned feature
|
cannam@233
|
484 // list, and with the timestamp passed in being that of the start
|
cannam@233
|
485 // of the process block.
|
cannam@233
|
486
|
cannam@233
|
487 // At the end (in getRemainingFeatures), accumulate() is called
|
cannam@233
|
488 // once for each feature on each output within the feature list
|
cannam@233
|
489 // returned by getRemainingFeatures, and with the timestamp being
|
cannam@233
|
490 // the same as the last process block and final set to true.
|
cannam@233
|
491
|
cannam@233
|
492 // (What if getRemainingFeatures doesn't return any features? We
|
cannam@233
|
493 // still need to ensure that the final duration is written. Need
|
cannam@233
|
494 // a separate function to close the durations.)
|
cannam@233
|
495
|
cannam@233
|
496 // At each call, we pull out the value for the feature and stuff
|
cannam@233
|
497 // it into the accumulator's appropriate values array; and we
|
cannam@233
|
498 // calculate the duration for the _previous_ feature, or pull it
|
cannam@233
|
499 // from the prevDurations array if the previous feature had a
|
cannam@233
|
500 // duration in its structure, and stuff that into the
|
cannam@233
|
501 // accumulator's appropriate durations array.
|
cannam@233
|
502
|
cannam@233
|
503 if (m_prevDurations.find(output) != m_prevDurations.end()) {
|
cannam@233
|
504
|
cannam@233
|
505 // Not the first time accumulate has been called for this
|
cannam@233
|
506 // output -- there has been a previous feature
|
cannam@233
|
507
|
cannam@233
|
508 RealTime prevDuration;
|
cannam@233
|
509
|
cannam@233
|
510 // Note that m_prevDurations[output] only contains the
|
cannam@233
|
511 // duration field that was contained in the previous feature.
|
cannam@233
|
512 // If it didn't have an explicit duration,
|
cannam@233
|
513 // m_prevDurations[output] should be INVALID_DURATION and we
|
cannam@233
|
514 // will have to calculate the duration from the previous and
|
cannam@233
|
515 // current timestamps.
|
cannam@233
|
516
|
cannam@233
|
517 if (m_prevDurations[output] != INVALID_DURATION) {
|
cannam@233
|
518 prevDuration = m_prevDurations[output];
|
cannam@233
|
519 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
520 cerr << "Previous duration from previous feature: " << prevDuration << endl;
|
cannam@233
|
521 #endif
|
cannam@233
|
522 } else {
|
cannam@233
|
523 prevDuration = timestamp - m_prevTimestamps[output];
|
cannam@233
|
524 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
525 cerr << "Previous duration from diff: " << timestamp << " - "
|
Chris@418
|
526 << m_prevTimestamps[output] << endl;
|
cannam@233
|
527 #endif
|
cannam@233
|
528 }
|
cannam@233
|
529
|
cannam@233
|
530 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
531 cerr << "output " << output << ": ";
|
Chris@418
|
532 cerr << "Pushing previous duration as " << prevDuration << endl;
|
cannam@233
|
533 #endif
|
cannam@233
|
534
|
cannam@233
|
535 m_accumulators[output].results
|
cannam@233
|
536 [m_accumulators[output].results.size() - 1]
|
cannam@233
|
537 .duration = prevDuration;
|
cannam@233
|
538 }
|
cannam@233
|
539
|
cannam@233
|
540 if (f.hasDuration) m_prevDurations[output] = f.duration;
|
cannam@233
|
541 else m_prevDurations[output] = INVALID_DURATION;
|
cannam@233
|
542
|
cannam@233
|
543 m_prevTimestamps[output] = timestamp;
|
cannam@233
|
544
|
cannam@233
|
545 if (f.hasDuration) {
|
cannam@233
|
546 RealTime et = timestamp;
|
cannam@233
|
547 et = et + f.duration;
|
cannam@233
|
548 if (et > m_endTime) m_endTime = et;
|
Chris@418
|
549 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
550 cerr << "feature has duration, updating end time to " << m_endTime << endl;
|
Chris@418
|
551 #endif
|
cannam@233
|
552 }
|
cannam@233
|
553
|
cannam@233
|
554 Result result;
|
cannam@233
|
555 result.time = timestamp;
|
cannam@233
|
556 result.duration = INVALID_DURATION;
|
cannam@233
|
557
|
cannam@265
|
558 if (int(f.values.size()) > m_accumulators[output].bins) {
|
cannam@233
|
559 m_accumulators[output].bins = f.values.size();
|
cannam@233
|
560 }
|
cannam@233
|
561
|
cannam@233
|
562 for (int i = 0; i < int(f.values.size()); ++i) {
|
cannam@233
|
563 result.values.push_back(f.values[i]);
|
cannam@233
|
564 }
|
cannam@233
|
565
|
cannam@233
|
566 m_accumulators[output].results.push_back(result);
|
cannam@233
|
567 }
|
cannam@233
|
568
|
cannam@233
|
569 void
|
cannam@233
|
570 PluginSummarisingAdapter::Impl::accumulateFinalDurations()
|
cannam@233
|
571 {
|
cannam@233
|
572 for (OutputTimestampMap::iterator i = m_prevTimestamps.begin();
|
cannam@233
|
573 i != m_prevTimestamps.end(); ++i) {
|
cannam@233
|
574
|
cannam@233
|
575 int output = i->first;
|
cannam@233
|
576
|
cannam@233
|
577 int acount = m_accumulators[output].results.size();
|
cannam@233
|
578
|
cannam@233
|
579 if (acount == 0) continue;
|
cannam@233
|
580
|
cannam@233
|
581 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
582 cerr << "output " << output << ": ";
|
cannam@233
|
583 #endif
|
cannam@233
|
584
|
cannam@233
|
585 if (m_prevDurations.find(output) != m_prevDurations.end() &&
|
cannam@233
|
586 m_prevDurations[output] != INVALID_DURATION) {
|
cannam@233
|
587
|
cannam@233
|
588 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
589 cerr << "Pushing final duration from feature as " << m_prevDurations[output] << endl;
|
cannam@233
|
590 #endif
|
cannam@233
|
591
|
cannam@233
|
592 m_accumulators[output].results[acount - 1].duration =
|
cannam@233
|
593 m_prevDurations[output];
|
cannam@233
|
594
|
cannam@233
|
595 } else {
|
cannam@233
|
596
|
cannam@233
|
597 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
598 cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << endl;
|
cannam@233
|
599 #endif
|
cannam@233
|
600
|
cannam@233
|
601 m_accumulators[output].results[acount - 1].duration =
|
cannam@233
|
602 m_endTime - m_prevTimestamps[output];
|
cannam@233
|
603 }
|
cannam@233
|
604
|
cannam@233
|
605 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
606 cerr << "so duration for result no " << acount-1 << " is "
|
cannam@233
|
607 << m_accumulators[output].results[acount-1].duration
|
Chris@418
|
608 << endl;
|
cannam@233
|
609 #endif
|
cannam@233
|
610 }
|
cannam@233
|
611 }
|
cannam@233
|
612
|
cannam@233
|
613 void
|
cannam@233
|
614 PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
|
cannam@233
|
615 RealTime &start,
|
cannam@233
|
616 RealTime &end)
|
cannam@233
|
617 {
|
cannam@233
|
618 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
619 cerr << "findSegmentBounds: t = " << t << endl;
|
cannam@233
|
620 #endif
|
cannam@233
|
621
|
Chris@418
|
622 SegmentBoundaries::const_iterator i = upper_bound
|
cannam@233
|
623 (m_boundaries.begin(), m_boundaries.end(), t);
|
cannam@233
|
624
|
cannam@233
|
625 start = RealTime::zeroTime;
|
cannam@233
|
626 end = m_endTime;
|
cannam@233
|
627
|
cannam@233
|
628 if (i != m_boundaries.end()) {
|
cannam@233
|
629 end = *i;
|
cannam@233
|
630 }
|
cannam@233
|
631
|
cannam@233
|
632 if (i != m_boundaries.begin()) {
|
cannam@233
|
633 start = *--i;
|
cannam@233
|
634 }
|
cannam@233
|
635
|
cannam@233
|
636 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
637 cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << endl;
|
cannam@233
|
638 #endif
|
cannam@233
|
639 }
|
cannam@233
|
640
|
cannam@233
|
641 void
|
cannam@233
|
642 PluginSummarisingAdapter::Impl::segment()
|
cannam@233
|
643 {
|
cannam@233
|
644 SegmentBoundaries::iterator boundaryitr = m_boundaries.begin();
|
cannam@233
|
645
|
cannam@274
|
646 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
647 cerr << "segment: starting" << endl;
|
cannam@274
|
648 #endif
|
cannam@274
|
649
|
cannam@233
|
650 for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
|
cannam@233
|
651 i != m_accumulators.end(); ++i) {
|
cannam@233
|
652
|
cannam@233
|
653 int output = i->first;
|
cannam@233
|
654 OutputAccumulator &source = i->second;
|
cannam@233
|
655
|
cannam@233
|
656 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
657 cerr << "segment: total results for output " << output << " = "
|
Chris@418
|
658 << source.results.size() << endl;
|
cannam@233
|
659 #endif
|
cannam@233
|
660
|
cannam@248
|
661 // This is basically nonsense if the results have no values
|
cannam@248
|
662 // (i.e. their times and counts are the only things of
|
cannam@248
|
663 // interest)... but perhaps it's the user's problem if they
|
cannam@248
|
664 // ask for segmentation (or any summary at all) in that case
|
cannam@233
|
665
|
cannam@265
|
666 for (int n = 0; n < int(source.results.size()); ++n) {
|
cannam@233
|
667
|
cannam@233
|
668 // This result spans source.results[n].time to
|
cannam@233
|
669 // source.results[n].time + source.results[n].duration.
|
cannam@233
|
670 // We need to dispose it into segments appropriately
|
cannam@233
|
671
|
cannam@233
|
672 RealTime resultStart = source.results[n].time;
|
cannam@233
|
673 RealTime resultEnd = resultStart + source.results[n].duration;
|
cannam@233
|
674
|
cannam@233
|
675 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
676 cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << endl;
|
cannam@233
|
677 #endif
|
cannam@233
|
678
|
cannam@233
|
679 RealTime segmentStart = RealTime::zeroTime;
|
cannam@233
|
680 RealTime segmentEnd = resultEnd - RealTime(1, 0);
|
cannam@233
|
681
|
cannam@274
|
682 RealTime prevSegmentStart = segmentStart - RealTime(1, 0);
|
cannam@274
|
683
|
cannam@233
|
684 while (segmentEnd < resultEnd) {
|
cannam@233
|
685
|
cannam@274
|
686 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
687 cerr << "segment end " << segmentEnd << " < result end "
|
Chris@418
|
688 << resultEnd << " (with result start " << resultStart << ")" << endl;
|
cannam@274
|
689 #endif
|
cannam@274
|
690
|
cannam@233
|
691 findSegmentBounds(resultStart, segmentStart, segmentEnd);
|
cannam@274
|
692
|
cannam@274
|
693 if (segmentStart == prevSegmentStart) {
|
cannam@274
|
694 // This can happen when we reach the end of the
|
cannam@274
|
695 // input, if a feature's end time overruns the
|
cannam@274
|
696 // input audio end time
|
cannam@274
|
697 break;
|
cannam@274
|
698 }
|
cannam@274
|
699 prevSegmentStart = segmentStart;
|
cannam@233
|
700
|
cannam@233
|
701 RealTime chunkStart = resultStart;
|
cannam@233
|
702 if (chunkStart < segmentStart) chunkStart = segmentStart;
|
cannam@233
|
703
|
cannam@233
|
704 RealTime chunkEnd = resultEnd;
|
cannam@233
|
705 if (chunkEnd > segmentEnd) chunkEnd = segmentEnd;
|
cannam@233
|
706
|
cannam@233
|
707 m_segmentedAccumulators[output][segmentStart].bins = source.bins;
|
cannam@233
|
708
|
cannam@233
|
709 Result chunk;
|
cannam@233
|
710 chunk.time = chunkStart;
|
cannam@233
|
711 chunk.duration = chunkEnd - chunkStart;
|
cannam@233
|
712 chunk.values = source.results[n].values;
|
cannam@233
|
713
|
cannam@233
|
714 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
|
Chris@418
|
715 cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << endl;
|
cannam@233
|
716 #endif
|
cannam@233
|
717
|
cannam@233
|
718 m_segmentedAccumulators[output][segmentStart].results
|
cannam@233
|
719 .push_back(chunk);
|
cannam@233
|
720
|
cannam@233
|
721 resultStart = chunkEnd;
|
cannam@233
|
722 }
|
cannam@233
|
723 }
|
cannam@233
|
724 }
|
cannam@233
|
725 }
|
cannam@233
|
726
|
cannam@233
|
727 struct ValueDurationFloatPair
|
cannam@233
|
728 {
|
cannam@233
|
729 float value;
|
cannam@233
|
730 float duration;
|
cannam@233
|
731
|
cannam@233
|
732 ValueDurationFloatPair() : value(0), duration(0) { }
|
cannam@233
|
733 ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
|
cannam@233
|
734 ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
|
cannam@233
|
735 value = p.value;
|
cannam@233
|
736 duration = p.duration;
|
cannam@233
|
737 return *this;
|
cannam@233
|
738 }
|
cannam@233
|
739 bool operator<(const ValueDurationFloatPair &p) const {
|
cannam@233
|
740 return value < p.value;
|
cannam@233
|
741 }
|
cannam@233
|
742 };
|
cannam@233
|
743
|
cannam@233
|
744 static double toSec(const RealTime &r)
|
cannam@233
|
745 {
|
cannam@233
|
746 return r.sec + double(r.nsec) / 1000000000.0;
|
cannam@233
|
747 }
|
cannam@233
|
748
|
cannam@233
|
749 void
|
cannam@233
|
750 PluginSummarisingAdapter::Impl::reduce()
|
cannam@233
|
751 {
|
cannam@233
|
752 for (OutputSegmentAccumulatorMap::iterator i =
|
cannam@233
|
753 m_segmentedAccumulators.begin();
|
cannam@233
|
754 i != m_segmentedAccumulators.end(); ++i) {
|
cannam@233
|
755
|
cannam@233
|
756 int output = i->first;
|
cannam@233
|
757 SegmentAccumulatorMap &segments = i->second;
|
cannam@233
|
758
|
cannam@233
|
759 for (SegmentAccumulatorMap::iterator j = segments.begin();
|
cannam@233
|
760 j != segments.end(); ++j) {
|
cannam@233
|
761
|
cannam@233
|
762 RealTime segmentStart = j->first;
|
cannam@233
|
763 OutputAccumulator &accumulator = j->second;
|
cannam@233
|
764
|
cannam@233
|
765 int sz = accumulator.results.size();
|
cannam@233
|
766
|
cannam@233
|
767 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
768 cerr << "reduce: segment starting at " << segmentStart
|
Chris@418
|
769 << " on output " << output << " has " << sz << " result(s)" << endl;
|
cannam@233
|
770 #endif
|
cannam@233
|
771
|
cannam@233
|
772 double totalDuration = 0.0;
|
cannam@233
|
773 //!!! is this right?
|
cannam@233
|
774 if (sz > 0) {
|
cannam@233
|
775 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
776 cerr << "last time = " << accumulator.results[sz-1].time
|
cannam@233
|
777 << ", duration = " << accumulator.results[sz-1].duration
|
cannam@233
|
778 << " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
|
Chris@418
|
779 << endl;
|
cannam@233
|
780 #endif
|
cannam@233
|
781 totalDuration = toSec((accumulator.results[sz-1].time +
|
cannam@233
|
782 accumulator.results[sz-1].duration) -
|
cannam@233
|
783 segmentStart);
|
cannam@233
|
784 }
|
cannam@233
|
785
|
cannam@233
|
786 for (int bin = 0; bin < accumulator.bins; ++bin) {
|
cannam@233
|
787
|
cannam@233
|
788 // work on all values over time for a single bin
|
cannam@233
|
789
|
Chris@418
|
790 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
791 cerr << "bin " << bin << ":" << endl;
|
Chris@418
|
792 #endif
|
Chris@418
|
793
|
cannam@233
|
794 OutputBinSummary summary;
|
cannam@233
|
795
|
cannam@233
|
796 summary.count = sz;
|
cannam@233
|
797
|
cannam@233
|
798 summary.minimum = 0.f;
|
cannam@233
|
799 summary.maximum = 0.f;
|
cannam@233
|
800
|
cannam@233
|
801 summary.median = 0.f;
|
cannam@233
|
802 summary.mode = 0.f;
|
cannam@233
|
803 summary.sum = 0.f;
|
cannam@233
|
804 summary.variance = 0.f;
|
cannam@233
|
805
|
cannam@233
|
806 summary.median_c = 0.f;
|
cannam@233
|
807 summary.mode_c = 0.f;
|
cannam@233
|
808 summary.mean_c = 0.f;
|
cannam@233
|
809 summary.variance_c = 0.f;
|
cannam@233
|
810
|
cannam@233
|
811 if (sz == 0) continue;
|
cannam@233
|
812
|
Chris@418
|
813 vector<ValueDurationFloatPair> valvec;
|
cannam@233
|
814
|
cannam@233
|
815 for (int k = 0; k < sz; ++k) {
|
cannam@265
|
816 while (int(accumulator.results[k].values.size()) <
|
cannam@233
|
817 accumulator.bins) {
|
cannam@233
|
818 accumulator.results[k].values.push_back(0.f);
|
cannam@233
|
819 }
|
cannam@233
|
820 }
|
cannam@233
|
821
|
cannam@233
|
822 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
823 float value = accumulator.results[k].values[bin];
|
cannam@233
|
824 valvec.push_back(ValueDurationFloatPair
|
cannam@233
|
825 (value,
|
cannam@233
|
826 toSec(accumulator.results[k].duration)));
|
cannam@233
|
827 }
|
cannam@233
|
828
|
Chris@418
|
829 sort(valvec.begin(), valvec.end());
|
cannam@233
|
830
|
cannam@233
|
831 summary.minimum = valvec[0].value;
|
cannam@233
|
832 summary.maximum = valvec[sz-1].value;
|
cannam@233
|
833
|
cannam@233
|
834 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
835 cerr << "total duration = " << totalDuration << endl;
|
cannam@233
|
836 #endif
|
cannam@233
|
837
|
cannam@233
|
838 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
cannam@233
|
839 /*
|
Chris@418
|
840 cerr << "value vector for medians:" << endl;
|
cannam@233
|
841 for (int k = 0; k < sz; ++k) {
|
Chris@418
|
842 cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
|
cannam@233
|
843 }
|
Chris@418
|
844 cerr << endl;
|
cannam@233
|
845 */
|
cannam@233
|
846 #endif
|
cannam@233
|
847
|
cannam@233
|
848 if (sz % 2 == 1) {
|
cannam@233
|
849 summary.median = valvec[sz/2].value;
|
cannam@233
|
850 } else {
|
cannam@233
|
851 summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
|
cannam@233
|
852 }
|
cannam@233
|
853
|
cannam@233
|
854 double duracc = 0.0;
|
cannam@233
|
855 summary.median_c = valvec[sz-1].value;
|
cannam@233
|
856
|
cannam@233
|
857 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
858 duracc += valvec[k].duration;
|
cannam@233
|
859 if (duracc > totalDuration/2) {
|
cannam@233
|
860 summary.median_c = valvec[k].value;
|
cannam@233
|
861 break;
|
cannam@233
|
862 }
|
cannam@233
|
863 }
|
cannam@233
|
864
|
cannam@233
|
865 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
866 cerr << "median_c = " << summary.median_c << endl;
|
Chris@418
|
867 cerr << "median = " << summary.median << endl;
|
cannam@233
|
868 #endif
|
cannam@233
|
869
|
Chris@418
|
870 map<float, int> distribution;
|
cannam@233
|
871
|
cannam@233
|
872 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
873 summary.sum += accumulator.results[k].values[bin];
|
cannam@233
|
874 distribution[accumulator.results[k].values[bin]] += 1;
|
cannam@233
|
875 }
|
cannam@233
|
876
|
cannam@233
|
877 int md = 0;
|
cannam@233
|
878
|
Chris@418
|
879 for (map<float, int>::iterator di = distribution.begin();
|
cannam@233
|
880 di != distribution.end(); ++di) {
|
cannam@233
|
881 if (di->second > md) {
|
cannam@233
|
882 md = di->second;
|
cannam@233
|
883 summary.mode = di->first;
|
cannam@233
|
884 }
|
cannam@233
|
885 }
|
cannam@233
|
886
|
cannam@233
|
887 distribution.clear();
|
cannam@233
|
888
|
Chris@418
|
889 map<float, double> distribution_c;
|
cannam@233
|
890
|
cannam@233
|
891 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
892 distribution_c[accumulator.results[k].values[bin]]
|
cannam@233
|
893 += toSec(accumulator.results[k].duration);
|
cannam@233
|
894 }
|
cannam@233
|
895
|
cannam@233
|
896 double mrd = 0.0;
|
cannam@233
|
897
|
Chris@418
|
898 for (map<float, double>::iterator di = distribution_c.begin();
|
cannam@233
|
899 di != distribution_c.end(); ++di) {
|
cannam@233
|
900 if (di->second > mrd) {
|
cannam@233
|
901 mrd = di->second;
|
cannam@233
|
902 summary.mode_c = di->first;
|
cannam@233
|
903 }
|
cannam@233
|
904 }
|
cannam@233
|
905
|
cannam@233
|
906 distribution_c.clear();
|
cannam@233
|
907
|
cannam@233
|
908 if (totalDuration > 0.0) {
|
cannam@233
|
909
|
cannam@233
|
910 double sum_c = 0.0;
|
cannam@233
|
911
|
cannam@233
|
912 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
913 double value = accumulator.results[k].values[bin]
|
cannam@233
|
914 * toSec(accumulator.results[k].duration);
|
cannam@233
|
915 sum_c += value;
|
cannam@233
|
916 }
|
cannam@233
|
917
|
cannam@233
|
918 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
919 cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
|
Chris@418
|
920 << sum_c / totalDuration << " (sz = " << sz << ")" << endl;
|
cannam@233
|
921 #endif
|
cannam@233
|
922
|
cannam@233
|
923 summary.mean_c = sum_c / totalDuration;
|
cannam@233
|
924
|
cannam@233
|
925 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
926 double value = accumulator.results[k].values[bin];
|
cannam@233
|
927 // * toSec(accumulator.results[k].duration);
|
cannam@233
|
928 summary.variance_c +=
|
cannam@233
|
929 (value - summary.mean_c) * (value - summary.mean_c)
|
cannam@233
|
930 * toSec(accumulator.results[k].duration);
|
cannam@233
|
931 }
|
cannam@233
|
932
|
cannam@233
|
933 // summary.variance_c /= summary.count;
|
cannam@233
|
934 summary.variance_c /= totalDuration;
|
cannam@233
|
935 }
|
cannam@233
|
936
|
cannam@233
|
937 double mean = summary.sum / summary.count;
|
cannam@233
|
938
|
cannam@233
|
939 #ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
|
Chris@418
|
940 cerr << "mean = " << summary.sum << " / " << summary.count << " = "
|
Chris@418
|
941 << summary.sum / summary.count << endl;
|
cannam@233
|
942 #endif
|
cannam@233
|
943
|
cannam@233
|
944 for (int k = 0; k < sz; ++k) {
|
cannam@233
|
945 float value = accumulator.results[k].values[bin];
|
cannam@233
|
946 summary.variance += (value - mean) * (value - mean);
|
cannam@233
|
947 }
|
cannam@233
|
948 summary.variance /= summary.count;
|
cannam@233
|
949
|
cannam@233
|
950 m_summaries[output][segmentStart][bin] = summary;
|
cannam@233
|
951 }
|
cannam@233
|
952 }
|
cannam@233
|
953 }
|
cannam@233
|
954
|
cannam@233
|
955 m_segmentedAccumulators.clear();
|
cannam@233
|
956 m_accumulators.clear();
|
cannam@233
|
957 }
|
cannam@233
|
958
|
cannam@233
|
959
|
cannam@233
|
960 }
|
cannam@233
|
961
|
cannam@233
|
962 }
|
cannam@233
|
963
|
cannam@263
|
964 _VAMP_SDK_HOSTSPACE_END(PluginSummarisingAdapter.cpp)
|
cannam@263
|
965
|