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@175
|
40 #include <cmath>
|
cannam@174
|
41
|
cannam@173
|
42 namespace Vamp {
|
cannam@173
|
43
|
cannam@173
|
44 namespace HostExt {
|
cannam@173
|
45
|
cannam@173
|
46 class PluginSummarisingAdapter::Impl
|
cannam@173
|
47 {
|
cannam@173
|
48 public:
|
cannam@173
|
49 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@173
|
50 ~Impl();
|
cannam@173
|
51
|
cannam@173
|
52 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@173
|
53 FeatureSet getRemainingFeatures();
|
cannam@173
|
54
|
cannam@173
|
55 void setSummarySegmentBoundaries(const SegmentBoundaries &);
|
cannam@173
|
56
|
cannam@180
|
57 FeatureList getSummaryForOutput(int output,
|
cannam@180
|
58 SummaryType type,
|
cannam@180
|
59 AveragingMethod avg);
|
cannam@180
|
60
|
cannam@180
|
61 FeatureSet getSummaryForAllOutputs(SummaryType type,
|
cannam@180
|
62 AveragingMethod avg);
|
cannam@173
|
63
|
cannam@173
|
64 protected:
|
cannam@174
|
65 Plugin *m_plugin;
|
cannam@181
|
66 float m_inputSampleRate;
|
cannam@174
|
67
|
cannam@173
|
68 SegmentBoundaries m_boundaries;
|
cannam@174
|
69
|
cannam@174
|
70 typedef std::vector<float> ValueList;
|
cannam@174
|
71 typedef std::map<int, ValueList> BinValueMap;
|
cannam@180
|
72 typedef std::vector<RealTime> DurationList;
|
cannam@174
|
73
|
cannam@174
|
74 struct OutputAccumulator {
|
cannam@174
|
75 int count;
|
cannam@180
|
76 BinValueMap values; // bin number -> values ordered by time
|
cannam@180
|
77 DurationList durations;
|
cannam@180
|
78 OutputAccumulator() : count(0), values(), durations() { }
|
cannam@174
|
79 };
|
cannam@174
|
80
|
cannam@174
|
81 typedef std::map<int, OutputAccumulator> OutputAccumulatorMap;
|
cannam@180
|
82 OutputAccumulatorMap m_accumulators; // output number -> accumulator
|
cannam@180
|
83
|
cannam@180
|
84 typedef std::map<int, RealTime> OutputTimestampMap;
|
cannam@180
|
85 OutputTimestampMap m_prevTimestamps; // output number -> timestamp
|
cannam@174
|
86
|
cannam@174
|
87 struct OutputBinSummary {
|
cannam@180
|
88
|
cannam@180
|
89 int count;
|
cannam@180
|
90
|
cannam@180
|
91 // extents
|
cannam@174
|
92 float minimum;
|
cannam@174
|
93 float maximum;
|
cannam@180
|
94 float sum;
|
cannam@180
|
95
|
cannam@180
|
96 // sample-average results
|
cannam@174
|
97 float median;
|
cannam@174
|
98 float mode;
|
cannam@174
|
99 float variance;
|
cannam@180
|
100
|
cannam@180
|
101 // continuous-time average results
|
cannam@180
|
102 float median_c;
|
cannam@180
|
103 float mode_c;
|
cannam@180
|
104 float mean_c;
|
cannam@180
|
105 float variance_c;
|
cannam@174
|
106 };
|
cannam@174
|
107
|
cannam@174
|
108 typedef std::map<int, OutputBinSummary> OutputSummary;
|
cannam@174
|
109 typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
|
cannam@174
|
110 typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
|
cannam@174
|
111
|
cannam@174
|
112 OutputSummarySegmentMap m_summaries;
|
cannam@174
|
113
|
cannam@174
|
114 RealTime m_lastTimestamp;
|
cannam@180
|
115 RealTime m_prevDuration;
|
cannam@174
|
116
|
cannam@180
|
117 void accumulate(const FeatureSet &fs, RealTime, bool final);
|
cannam@180
|
118 void accumulate(int output, const Feature &f, RealTime, bool final);
|
cannam@174
|
119 void reduce();
|
cannam@173
|
120 };
|
cannam@173
|
121
|
cannam@173
|
122 PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
|
cannam@173
|
123 PluginWrapper(plugin)
|
cannam@173
|
124 {
|
cannam@173
|
125 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@173
|
126 }
|
cannam@173
|
127
|
cannam@173
|
128 PluginSummarisingAdapter::~PluginSummarisingAdapter()
|
cannam@173
|
129 {
|
cannam@173
|
130 delete m_impl;
|
cannam@173
|
131 }
|
cannam@173
|
132
|
cannam@173
|
133 Plugin::FeatureSet
|
cannam@173
|
134 PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
|
cannam@173
|
135 {
|
cannam@173
|
136 return m_impl->process(inputBuffers, timestamp);
|
cannam@173
|
137 }
|
cannam@173
|
138
|
cannam@174
|
139 Plugin::FeatureSet
|
cannam@174
|
140 PluginSummarisingAdapter::getRemainingFeatures()
|
cannam@174
|
141 {
|
cannam@174
|
142 return m_impl->getRemainingFeatures();
|
cannam@174
|
143 }
|
cannam@174
|
144
|
cannam@175
|
145 Plugin::FeatureList
|
cannam@180
|
146 PluginSummarisingAdapter::getSummaryForOutput(int output,
|
cannam@180
|
147 SummaryType type,
|
cannam@180
|
148 AveragingMethod avg)
|
cannam@175
|
149 {
|
cannam@180
|
150 return m_impl->getSummaryForOutput(output, type, avg);
|
cannam@176
|
151 }
|
cannam@176
|
152
|
cannam@176
|
153 Plugin::FeatureSet
|
cannam@180
|
154 PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
|
cannam@180
|
155 AveragingMethod avg)
|
cannam@176
|
156 {
|
cannam@180
|
157 return m_impl->getSummaryForAllOutputs(type, avg);
|
cannam@175
|
158 }
|
cannam@173
|
159
|
cannam@173
|
160 PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@181
|
161 m_plugin(plugin),
|
cannam@181
|
162 m_inputSampleRate(inputSampleRate)
|
cannam@173
|
163 {
|
cannam@173
|
164 }
|
cannam@173
|
165
|
cannam@173
|
166 PluginSummarisingAdapter::Impl::~Impl()
|
cannam@173
|
167 {
|
cannam@173
|
168 }
|
cannam@173
|
169
|
cannam@174
|
170 Plugin::FeatureSet
|
cannam@174
|
171 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, RealTime timestamp)
|
cannam@174
|
172 {
|
cannam@174
|
173 FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
|
cannam@180
|
174 accumulate(fs, timestamp, false);
|
cannam@174
|
175 m_lastTimestamp = timestamp;
|
cannam@174
|
176 return fs;
|
cannam@174
|
177 }
|
cannam@174
|
178
|
cannam@174
|
179 Plugin::FeatureSet
|
cannam@174
|
180 PluginSummarisingAdapter::Impl::getRemainingFeatures()
|
cannam@174
|
181 {
|
cannam@174
|
182 FeatureSet fs = m_plugin->getRemainingFeatures();
|
cannam@180
|
183 accumulate(fs, m_lastTimestamp, true);
|
cannam@174
|
184 reduce();
|
cannam@174
|
185 return fs;
|
cannam@174
|
186 }
|
cannam@174
|
187
|
cannam@175
|
188 Plugin::FeatureList
|
cannam@180
|
189 PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
|
cannam@180
|
190 SummaryType type,
|
cannam@180
|
191 AveragingMethod avg)
|
cannam@175
|
192 {
|
cannam@180
|
193 bool continuous = (avg == ContinuousTimeAverage);
|
cannam@180
|
194
|
cannam@175
|
195 //!!! need to ensure that this is only called after processing is
|
cannam@175
|
196 //!!! complete (at the moment processing is "completed" in the
|
cannam@175
|
197 //!!! call to getRemainingFeatures, but we don't want to require
|
cannam@175
|
198 //!!! the host to call getRemainingFeatures at all unless it
|
cannam@175
|
199 //!!! actually wants the raw features too -- calling getSummary
|
cannam@175
|
200 //!!! should be enough -- we do need to ensure that all data has
|
cannam@175
|
201 //!!! been processed though!)
|
cannam@175
|
202 FeatureList fl;
|
cannam@175
|
203 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
|
cannam@175
|
204 i != m_summaries[output].end(); ++i) {
|
cannam@177
|
205
|
cannam@175
|
206 Feature f;
|
cannam@175
|
207 f.hasTimestamp = true;
|
cannam@175
|
208 f.timestamp = i->first;
|
cannam@175
|
209 f.hasDuration = false;
|
cannam@177
|
210
|
cannam@175
|
211 for (OutputSummary::const_iterator j = i->second.begin();
|
cannam@175
|
212 j != i->second.end(); ++j) {
|
cannam@175
|
213
|
cannam@175
|
214 // these will be ordered by bin number, and no bin numbers
|
cannam@175
|
215 // will be missing except at the end (because of the way
|
cannam@175
|
216 // the accumulators were initially filled in accumulate())
|
cannam@175
|
217
|
cannam@175
|
218 const OutputBinSummary &summary = j->second;
|
cannam@175
|
219 float result = 0.f;
|
cannam@175
|
220
|
cannam@175
|
221 switch (type) {
|
cannam@175
|
222
|
cannam@175
|
223 case Minimum:
|
cannam@175
|
224 result = summary.minimum;
|
cannam@175
|
225 break;
|
cannam@175
|
226
|
cannam@175
|
227 case Maximum:
|
cannam@175
|
228 result = summary.maximum;
|
cannam@175
|
229 break;
|
cannam@175
|
230
|
cannam@175
|
231 case Mean:
|
cannam@180
|
232 if (continuous) {
|
cannam@180
|
233 result = summary.mean_c;
|
cannam@180
|
234 } else if (summary.count) {
|
cannam@175
|
235 result = summary.sum / summary.count;
|
cannam@175
|
236 }
|
cannam@175
|
237 break;
|
cannam@175
|
238
|
cannam@175
|
239 case Median:
|
cannam@180
|
240 if (continuous) result = summary.median_c;
|
cannam@180
|
241 else result = summary.median;
|
cannam@175
|
242 break;
|
cannam@175
|
243
|
cannam@175
|
244 case Mode:
|
cannam@180
|
245 if (continuous) result = summary.mode_c;
|
cannam@180
|
246 else result = summary.mode;
|
cannam@175
|
247 break;
|
cannam@175
|
248
|
cannam@175
|
249 case Sum:
|
cannam@175
|
250 result = summary.sum;
|
cannam@175
|
251 break;
|
cannam@175
|
252
|
cannam@175
|
253 case Variance:
|
cannam@180
|
254 if (continuous) result = summary.variance_c;
|
cannam@180
|
255 else result = summary.variance;
|
cannam@175
|
256 break;
|
cannam@175
|
257
|
cannam@175
|
258 case StandardDeviation:
|
cannam@180
|
259 if (continuous) result = sqrtf(summary.variance_c);
|
cannam@180
|
260 else result = sqrtf(summary.variance);
|
cannam@175
|
261 break;
|
cannam@175
|
262
|
cannam@175
|
263 case Count:
|
cannam@175
|
264 result = summary.count;
|
cannam@175
|
265 break;
|
cannam@180
|
266
|
cannam@180
|
267 default:
|
cannam@180
|
268 break;
|
cannam@175
|
269 }
|
cannam@177
|
270
|
cannam@177
|
271 f.values.push_back(result);
|
cannam@175
|
272 }
|
cannam@175
|
273
|
cannam@175
|
274 fl.push_back(f);
|
cannam@175
|
275 }
|
cannam@175
|
276 return fl;
|
cannam@175
|
277 }
|
cannam@175
|
278
|
cannam@176
|
279 Plugin::FeatureSet
|
cannam@180
|
280 PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
|
cannam@180
|
281 AveragingMethod avg)
|
cannam@176
|
282 {
|
cannam@176
|
283 FeatureSet fs;
|
cannam@176
|
284 for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
|
cannam@176
|
285 i != m_summaries.end(); ++i) {
|
cannam@180
|
286 fs[i->first] = getSummaryForOutput(i->first, type, avg);
|
cannam@176
|
287 }
|
cannam@176
|
288 return fs;
|
cannam@176
|
289 }
|
cannam@176
|
290
|
cannam@174
|
291 void
|
cannam@174
|
292 PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
|
cannam@180
|
293 RealTime timestamp,
|
cannam@180
|
294 bool final)
|
cannam@174
|
295 {
|
cannam@174
|
296 for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
|
cannam@174
|
297 for (FeatureList::const_iterator j = i->second.begin();
|
cannam@174
|
298 j != i->second.end(); ++j) {
|
cannam@180
|
299 accumulate(i->first, *j, timestamp, final);
|
cannam@174
|
300 }
|
cannam@174
|
301 }
|
cannam@174
|
302 }
|
cannam@174
|
303
|
cannam@174
|
304 void
|
cannam@174
|
305 PluginSummarisingAdapter::Impl::accumulate(int output,
|
cannam@174
|
306 const Feature &f,
|
cannam@180
|
307 RealTime timestamp,
|
cannam@180
|
308 bool final)
|
cannam@174
|
309 {
|
cannam@180
|
310 //!!! to do: use timestamp to determine which segment we're on
|
cannam@180
|
311
|
cannam@174
|
312 m_accumulators[output].count++;
|
cannam@180
|
313
|
cannam@180
|
314 if (m_prevDuration == RealTime::zeroTime) {
|
cannam@180
|
315 if (m_prevTimestamps.find(output) != m_prevTimestamps.end()) {
|
cannam@180
|
316 m_prevDuration = timestamp - m_prevTimestamps[output];
|
cannam@180
|
317 }
|
cannam@180
|
318 }
|
cannam@180
|
319 if (m_prevDuration != RealTime::zeroTime ||
|
cannam@180
|
320 !m_accumulators[output].durations.empty()) {
|
cannam@180
|
321 // ... i.e. if not first result. We don't push a duration
|
cannam@180
|
322 // when we process the first result; then the duration we push
|
cannam@180
|
323 // each time is that for the result before the one we're
|
cannam@180
|
324 // processing, and we push an extra one at the end. This
|
cannam@180
|
325 // permits handling the case where the feature itself doesn't
|
cannam@180
|
326 // have a duration field, and we have to calculate it from the
|
cannam@180
|
327 // time to the following feature. The net effect is simply
|
cannam@180
|
328 // that values[n] and durations[n] refer to the same result.
|
cannam@180
|
329 m_accumulators[output].durations.push_back(m_prevDuration);
|
cannam@180
|
330 }
|
cannam@180
|
331
|
cannam@180
|
332 m_prevTimestamps[output] = timestamp;
|
cannam@180
|
333
|
cannam@174
|
334 for (int i = 0; i < int(f.values.size()); ++i) {
|
cannam@174
|
335 m_accumulators[output].values[i].push_back(f.values[i]);
|
cannam@174
|
336 }
|
cannam@180
|
337
|
cannam@180
|
338 if (final) {
|
cannam@180
|
339 RealTime finalDuration;
|
cannam@180
|
340 if (f.hasDuration) finalDuration = f.duration;
|
cannam@180
|
341 m_accumulators[output].durations.push_back(finalDuration);
|
cannam@180
|
342 }
|
cannam@180
|
343
|
cannam@180
|
344 if (f.hasDuration) m_prevDuration = f.duration;
|
cannam@180
|
345 else m_prevDuration = RealTime::zeroTime;
|
cannam@174
|
346 }
|
cannam@174
|
347
|
cannam@181
|
348 struct ValueDurationFloatPair
|
cannam@181
|
349 {
|
cannam@181
|
350 float value;
|
cannam@181
|
351 float duration;
|
cannam@181
|
352
|
cannam@181
|
353 ValueDurationFloatPair() : value(0), duration(0) { }
|
cannam@181
|
354 ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
|
cannam@181
|
355 ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
|
cannam@181
|
356 value = p.value;
|
cannam@181
|
357 duration = p.duration;
|
cannam@181
|
358 return *this;
|
cannam@181
|
359 }
|
cannam@181
|
360 bool operator<(const ValueDurationFloatPair &p) const {
|
cannam@181
|
361 return value < p.value;
|
cannam@181
|
362 }
|
cannam@181
|
363 };
|
cannam@181
|
364
|
cannam@181
|
365 static double toSec(const RealTime &r)
|
cannam@181
|
366 {
|
cannam@181
|
367 return r.sec + double(r.nsec) / 1000000000.0;
|
cannam@181
|
368 }
|
cannam@181
|
369
|
cannam@174
|
370 void
|
cannam@174
|
371 PluginSummarisingAdapter::Impl::reduce()
|
cannam@174
|
372 {
|
cannam@174
|
373 RealTime segmentStart = RealTime::zeroTime; //!!!
|
cannam@174
|
374
|
cannam@174
|
375 for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
|
cannam@174
|
376 i != m_accumulators.end(); ++i) {
|
cannam@174
|
377
|
cannam@174
|
378 int output = i->first;
|
cannam@174
|
379 OutputAccumulator &accumulator = i->second;
|
cannam@174
|
380
|
cannam@181
|
381 double totalDuration;
|
cannam@181
|
382 for (int k = 0; k < accumulator.durations.size(); ++k) {
|
cannam@181
|
383 totalDuration += toSec(accumulator.durations[k]);
|
cannam@180
|
384 }
|
cannam@180
|
385
|
cannam@174
|
386 for (BinValueMap::iterator j = accumulator.values.begin();
|
cannam@174
|
387 j != accumulator.values.end(); ++j) {
|
cannam@174
|
388
|
cannam@180
|
389 // work on all values over time for a single bin
|
cannam@180
|
390
|
cannam@174
|
391 int bin = j->first;
|
cannam@181
|
392 const ValueList &values = j->second;
|
cannam@180
|
393 const DurationList &durations = accumulator.durations;
|
cannam@174
|
394
|
cannam@174
|
395 OutputBinSummary summary;
|
cannam@180
|
396
|
cannam@180
|
397 summary.count = accumulator.count;
|
cannam@180
|
398
|
cannam@174
|
399 summary.minimum = 0.f;
|
cannam@174
|
400 summary.maximum = 0.f;
|
cannam@180
|
401
|
cannam@174
|
402 summary.median = 0.f;
|
cannam@174
|
403 summary.mode = 0.f;
|
cannam@174
|
404 summary.sum = 0.f;
|
cannam@174
|
405 summary.variance = 0.f;
|
cannam@180
|
406
|
cannam@180
|
407 summary.median_c = 0.f;
|
cannam@180
|
408 summary.mode_c = 0.f;
|
cannam@180
|
409 summary.mean_c = 0.f;
|
cannam@180
|
410 summary.variance_c = 0.f;
|
cannam@180
|
411
|
cannam@174
|
412 if (summary.count == 0 || values.empty()) continue;
|
cannam@174
|
413
|
cannam@174
|
414 int sz = values.size();
|
cannam@174
|
415
|
cannam@180
|
416 if (sz != durations.size()) {
|
cannam@180
|
417 std::cerr << "WARNING: sz " << sz << " != durations.size() "
|
cannam@180
|
418 << durations.size() << std::endl;
|
cannam@181
|
419 // while (durations.size() < sz) {
|
cannam@181
|
420 // durations.push_back(RealTime::zeroTime);
|
cannam@181
|
421 // }
|
cannam@181
|
422 //!!! then what?
|
cannam@180
|
423 }
|
cannam@180
|
424
|
cannam@181
|
425 std::vector<ValueDurationFloatPair> valvec;
|
cannam@181
|
426
|
cannam@181
|
427 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
428 valvec.push_back(ValueDurationFloatPair(values[k],
|
cannam@181
|
429 toSec(durations[k])));
|
cannam@181
|
430 }
|
cannam@181
|
431
|
cannam@181
|
432 std::sort(valvec.begin(), valvec.end());
|
cannam@181
|
433
|
cannam@181
|
434 summary.minimum = valvec[0].value;
|
cannam@181
|
435 summary.maximum = valvec[sz-1].value;
|
cannam@174
|
436
|
cannam@174
|
437 if (sz % 2 == 1) {
|
cannam@181
|
438 summary.median = valvec[sz/2].value;
|
cannam@174
|
439 } else {
|
cannam@181
|
440 summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
|
cannam@174
|
441 }
|
cannam@181
|
442
|
cannam@181
|
443 double duracc = 0.0;
|
cannam@181
|
444 summary.median_c = valvec[sz-1].value;
|
cannam@174
|
445
|
cannam@181
|
446 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
447 duracc += valvec[k].duration;
|
cannam@181
|
448 if (duracc > totalDuration/2) {
|
cannam@181
|
449 summary.median_c = valvec[k].value;
|
cannam@181
|
450 break;
|
cannam@181
|
451 }
|
cannam@181
|
452 }
|
cannam@181
|
453
|
cannam@174
|
454 std::map<float, int> distribution;
|
cannam@174
|
455
|
cannam@174
|
456 for (int k = 0; k < sz; ++k) {
|
cannam@174
|
457 summary.sum += values[k];
|
cannam@180
|
458 distribution[values[k]] += 1;
|
cannam@174
|
459 }
|
cannam@174
|
460
|
cannam@174
|
461 int md = 0;
|
cannam@174
|
462
|
cannam@174
|
463 for (std::map<float, int>::iterator di = distribution.begin();
|
cannam@174
|
464 di != distribution.end(); ++di) {
|
cannam@174
|
465 if (di->second > md) {
|
cannam@174
|
466 md = di->second;
|
cannam@174
|
467 summary.mode = di->first;
|
cannam@174
|
468 }
|
cannam@174
|
469 }
|
cannam@174
|
470
|
cannam@174
|
471 distribution.clear();
|
cannam@174
|
472
|
cannam@180
|
473 //!!! we want to omit this bit if the features all have
|
cannam@180
|
474 //!!! equal duration (and set mode_c equal to mode instead)
|
cannam@180
|
475
|
cannam@181
|
476 std::map<float, double> distribution_c;
|
cannam@180
|
477
|
cannam@180
|
478 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
479 distribution_c[values[k]] += toSec(durations[k]);
|
cannam@180
|
480 }
|
cannam@180
|
481
|
cannam@181
|
482 double mrd = 0.0;
|
cannam@180
|
483
|
cannam@181
|
484 for (std::map<float, double>::iterator di = distribution_c.begin();
|
cannam@180
|
485 di != distribution_c.end(); ++di) {
|
cannam@180
|
486 if (di->second > mrd) {
|
cannam@180
|
487 mrd = di->second;
|
cannam@180
|
488 summary.mode_c = di->first;
|
cannam@180
|
489 }
|
cannam@180
|
490 }
|
cannam@180
|
491
|
cannam@180
|
492 distribution_c.clear();
|
cannam@180
|
493
|
cannam@181
|
494 if (totalDuration > 0.0) {
|
cannam@181
|
495
|
cannam@181
|
496 double sum_c = 0.0;
|
cannam@181
|
497
|
cannam@181
|
498 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
499 double value = values[k] * toSec(durations[k]);
|
cannam@181
|
500 sum_c += value;
|
cannam@181
|
501 }
|
cannam@181
|
502
|
cannam@181
|
503 summary.mean_c = sum_c / totalDuration;
|
cannam@181
|
504
|
cannam@181
|
505 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
506 double value = values[k] * toSec(durations[k]);
|
cannam@181
|
507 summary.variance_c +=
|
cannam@181
|
508 (value - summary.mean_c) * (value - summary.mean_c);
|
cannam@181
|
509 }
|
cannam@181
|
510
|
cannam@181
|
511 summary.variance_c /= summary.count;
|
cannam@181
|
512 }
|
cannam@181
|
513
|
cannam@181
|
514 //!!! still to handle: median_c
|
cannam@180
|
515
|
cannam@174
|
516 float mean = summary.sum / summary.count;
|
cannam@174
|
517
|
cannam@174
|
518 for (int k = 0; k < sz; ++k) {
|
cannam@174
|
519 summary.variance += (values[k] - mean) * (values[k] - mean);
|
cannam@174
|
520 }
|
cannam@174
|
521 summary.variance /= summary.count;
|
cannam@174
|
522
|
cannam@174
|
523 m_summaries[output][segmentStart][bin] = summary;
|
cannam@174
|
524 }
|
cannam@174
|
525 }
|
cannam@175
|
526
|
cannam@175
|
527 m_accumulators.clear();
|
cannam@174
|
528 }
|
cannam@174
|
529
|
cannam@174
|
530
|
cannam@174
|
531 }
|
cannam@174
|
532
|
cannam@174
|
533 }
|
cannam@174
|
534
|