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