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@182
|
299 if (j->hasTimestamp) {
|
cannam@182
|
300 accumulate(i->first, *j, j->timestamp, final);
|
cannam@182
|
301 } else {
|
cannam@182
|
302 //!!! is this correct?
|
cannam@182
|
303 accumulate(i->first, *j, timestamp, final);
|
cannam@182
|
304 }
|
cannam@174
|
305 }
|
cannam@174
|
306 }
|
cannam@174
|
307 }
|
cannam@174
|
308
|
cannam@174
|
309 void
|
cannam@174
|
310 PluginSummarisingAdapter::Impl::accumulate(int output,
|
cannam@174
|
311 const Feature &f,
|
cannam@180
|
312 RealTime timestamp,
|
cannam@180
|
313 bool final)
|
cannam@174
|
314 {
|
cannam@180
|
315 //!!! to do: use timestamp to determine which segment we're on
|
cannam@180
|
316
|
cannam@174
|
317 m_accumulators[output].count++;
|
cannam@180
|
318
|
cannam@182
|
319 std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << std::endl;
|
cannam@182
|
320
|
cannam@182
|
321 //!!! m_prevDuration needs to be per output
|
cannam@182
|
322
|
cannam@182
|
323 //!!! also, this will not work if we are called repeatedly with
|
cannam@182
|
324 //!!! the same timestamp -- no values will be registered until a
|
cannam@182
|
325 //!!! new timestamp is seen -- we need a better test for "not
|
cannam@182
|
326 //!!! first result" below
|
cannam@182
|
327
|
cannam@180
|
328 if (m_prevDuration == RealTime::zeroTime) {
|
cannam@180
|
329 if (m_prevTimestamps.find(output) != m_prevTimestamps.end()) {
|
cannam@180
|
330 m_prevDuration = timestamp - m_prevTimestamps[output];
|
cannam@180
|
331 }
|
cannam@180
|
332 }
|
cannam@180
|
333 if (m_prevDuration != RealTime::zeroTime ||
|
cannam@180
|
334 !m_accumulators[output].durations.empty()) {
|
cannam@180
|
335 // ... i.e. if not first result. We don't push a duration
|
cannam@180
|
336 // when we process the first result; then the duration we push
|
cannam@180
|
337 // each time is that for the result before the one we're
|
cannam@180
|
338 // processing, and we push an extra one at the end. This
|
cannam@180
|
339 // permits handling the case where the feature itself doesn't
|
cannam@180
|
340 // have a duration field, and we have to calculate it from the
|
cannam@180
|
341 // time to the following feature. The net effect is simply
|
cannam@180
|
342 // that values[n] and durations[n] refer to the same result.
|
cannam@180
|
343 m_accumulators[output].durations.push_back(m_prevDuration);
|
cannam@180
|
344 }
|
cannam@180
|
345
|
cannam@180
|
346 m_prevTimestamps[output] = timestamp;
|
cannam@180
|
347
|
cannam@174
|
348 for (int i = 0; i < int(f.values.size()); ++i) {
|
cannam@174
|
349 m_accumulators[output].values[i].push_back(f.values[i]);
|
cannam@174
|
350 }
|
cannam@180
|
351
|
cannam@180
|
352 if (final) {
|
cannam@180
|
353 RealTime finalDuration;
|
cannam@180
|
354 if (f.hasDuration) finalDuration = f.duration;
|
cannam@180
|
355 m_accumulators[output].durations.push_back(finalDuration);
|
cannam@180
|
356 }
|
cannam@180
|
357
|
cannam@180
|
358 if (f.hasDuration) m_prevDuration = f.duration;
|
cannam@180
|
359 else m_prevDuration = RealTime::zeroTime;
|
cannam@174
|
360 }
|
cannam@174
|
361
|
cannam@181
|
362 struct ValueDurationFloatPair
|
cannam@181
|
363 {
|
cannam@181
|
364 float value;
|
cannam@181
|
365 float duration;
|
cannam@181
|
366
|
cannam@181
|
367 ValueDurationFloatPair() : value(0), duration(0) { }
|
cannam@181
|
368 ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
|
cannam@181
|
369 ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
|
cannam@181
|
370 value = p.value;
|
cannam@181
|
371 duration = p.duration;
|
cannam@181
|
372 return *this;
|
cannam@181
|
373 }
|
cannam@181
|
374 bool operator<(const ValueDurationFloatPair &p) const {
|
cannam@181
|
375 return value < p.value;
|
cannam@181
|
376 }
|
cannam@181
|
377 };
|
cannam@181
|
378
|
cannam@181
|
379 static double toSec(const RealTime &r)
|
cannam@181
|
380 {
|
cannam@181
|
381 return r.sec + double(r.nsec) / 1000000000.0;
|
cannam@181
|
382 }
|
cannam@181
|
383
|
cannam@174
|
384 void
|
cannam@174
|
385 PluginSummarisingAdapter::Impl::reduce()
|
cannam@174
|
386 {
|
cannam@174
|
387 RealTime segmentStart = RealTime::zeroTime; //!!!
|
cannam@174
|
388
|
cannam@174
|
389 for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
|
cannam@174
|
390 i != m_accumulators.end(); ++i) {
|
cannam@174
|
391
|
cannam@174
|
392 int output = i->first;
|
cannam@174
|
393 OutputAccumulator &accumulator = i->second;
|
cannam@174
|
394
|
cannam@182
|
395 double totalDuration = 0.0;
|
cannam@181
|
396 for (int k = 0; k < accumulator.durations.size(); ++k) {
|
cannam@181
|
397 totalDuration += toSec(accumulator.durations[k]);
|
cannam@180
|
398 }
|
cannam@180
|
399
|
cannam@174
|
400 for (BinValueMap::iterator j = accumulator.values.begin();
|
cannam@174
|
401 j != accumulator.values.end(); ++j) {
|
cannam@174
|
402
|
cannam@180
|
403 // work on all values over time for a single bin
|
cannam@180
|
404
|
cannam@174
|
405 int bin = j->first;
|
cannam@181
|
406 const ValueList &values = j->second;
|
cannam@180
|
407 const DurationList &durations = accumulator.durations;
|
cannam@174
|
408
|
cannam@174
|
409 OutputBinSummary summary;
|
cannam@180
|
410
|
cannam@180
|
411 summary.count = accumulator.count;
|
cannam@180
|
412
|
cannam@174
|
413 summary.minimum = 0.f;
|
cannam@174
|
414 summary.maximum = 0.f;
|
cannam@180
|
415
|
cannam@174
|
416 summary.median = 0.f;
|
cannam@174
|
417 summary.mode = 0.f;
|
cannam@174
|
418 summary.sum = 0.f;
|
cannam@174
|
419 summary.variance = 0.f;
|
cannam@180
|
420
|
cannam@180
|
421 summary.median_c = 0.f;
|
cannam@180
|
422 summary.mode_c = 0.f;
|
cannam@180
|
423 summary.mean_c = 0.f;
|
cannam@180
|
424 summary.variance_c = 0.f;
|
cannam@180
|
425
|
cannam@174
|
426 if (summary.count == 0 || values.empty()) continue;
|
cannam@174
|
427
|
cannam@174
|
428 int sz = values.size();
|
cannam@174
|
429
|
cannam@180
|
430 if (sz != durations.size()) {
|
cannam@180
|
431 std::cerr << "WARNING: sz " << sz << " != durations.size() "
|
cannam@180
|
432 << durations.size() << std::endl;
|
cannam@181
|
433 // while (durations.size() < sz) {
|
cannam@181
|
434 // durations.push_back(RealTime::zeroTime);
|
cannam@181
|
435 // }
|
cannam@181
|
436 //!!! then what?
|
cannam@180
|
437 }
|
cannam@180
|
438
|
cannam@181
|
439 std::vector<ValueDurationFloatPair> valvec;
|
cannam@181
|
440
|
cannam@181
|
441 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
442 valvec.push_back(ValueDurationFloatPair(values[k],
|
cannam@181
|
443 toSec(durations[k])));
|
cannam@181
|
444 }
|
cannam@181
|
445
|
cannam@181
|
446 std::sort(valvec.begin(), valvec.end());
|
cannam@181
|
447
|
cannam@181
|
448 summary.minimum = valvec[0].value;
|
cannam@181
|
449 summary.maximum = valvec[sz-1].value;
|
cannam@174
|
450
|
cannam@174
|
451 if (sz % 2 == 1) {
|
cannam@181
|
452 summary.median = valvec[sz/2].value;
|
cannam@174
|
453 } else {
|
cannam@181
|
454 summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
|
cannam@174
|
455 }
|
cannam@181
|
456
|
cannam@181
|
457 double duracc = 0.0;
|
cannam@181
|
458 summary.median_c = valvec[sz-1].value;
|
cannam@174
|
459
|
cannam@181
|
460 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
461 duracc += valvec[k].duration;
|
cannam@181
|
462 if (duracc > totalDuration/2) {
|
cannam@181
|
463 summary.median_c = valvec[k].value;
|
cannam@181
|
464 break;
|
cannam@181
|
465 }
|
cannam@181
|
466 }
|
cannam@181
|
467
|
cannam@174
|
468 std::map<float, int> distribution;
|
cannam@174
|
469
|
cannam@174
|
470 for (int k = 0; k < sz; ++k) {
|
cannam@174
|
471 summary.sum += values[k];
|
cannam@180
|
472 distribution[values[k]] += 1;
|
cannam@174
|
473 }
|
cannam@174
|
474
|
cannam@174
|
475 int md = 0;
|
cannam@174
|
476
|
cannam@174
|
477 for (std::map<float, int>::iterator di = distribution.begin();
|
cannam@174
|
478 di != distribution.end(); ++di) {
|
cannam@174
|
479 if (di->second > md) {
|
cannam@174
|
480 md = di->second;
|
cannam@174
|
481 summary.mode = di->first;
|
cannam@174
|
482 }
|
cannam@174
|
483 }
|
cannam@174
|
484
|
cannam@174
|
485 distribution.clear();
|
cannam@174
|
486
|
cannam@180
|
487 //!!! we want to omit this bit if the features all have
|
cannam@180
|
488 //!!! equal duration (and set mode_c equal to mode instead)
|
cannam@180
|
489
|
cannam@181
|
490 std::map<float, double> distribution_c;
|
cannam@180
|
491
|
cannam@180
|
492 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
493 distribution_c[values[k]] += toSec(durations[k]);
|
cannam@180
|
494 }
|
cannam@180
|
495
|
cannam@181
|
496 double mrd = 0.0;
|
cannam@180
|
497
|
cannam@181
|
498 for (std::map<float, double>::iterator di = distribution_c.begin();
|
cannam@180
|
499 di != distribution_c.end(); ++di) {
|
cannam@180
|
500 if (di->second > mrd) {
|
cannam@180
|
501 mrd = di->second;
|
cannam@180
|
502 summary.mode_c = di->first;
|
cannam@180
|
503 }
|
cannam@180
|
504 }
|
cannam@180
|
505
|
cannam@180
|
506 distribution_c.clear();
|
cannam@180
|
507
|
cannam@181
|
508 if (totalDuration > 0.0) {
|
cannam@181
|
509
|
cannam@181
|
510 double sum_c = 0.0;
|
cannam@181
|
511
|
cannam@181
|
512 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
513 double value = values[k] * toSec(durations[k]);
|
cannam@181
|
514 sum_c += value;
|
cannam@181
|
515 }
|
cannam@182
|
516
|
cannam@182
|
517 std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
|
cannam@182
|
518 << sum_c / totalDuration << std::endl;
|
cannam@181
|
519
|
cannam@181
|
520 summary.mean_c = sum_c / totalDuration;
|
cannam@181
|
521
|
cannam@181
|
522 for (int k = 0; k < sz; ++k) {
|
cannam@181
|
523 double value = values[k] * toSec(durations[k]);
|
cannam@181
|
524 summary.variance_c +=
|
cannam@181
|
525 (value - summary.mean_c) * (value - summary.mean_c);
|
cannam@181
|
526 }
|
cannam@181
|
527
|
cannam@181
|
528 summary.variance_c /= summary.count;
|
cannam@181
|
529 }
|
cannam@181
|
530
|
cannam@181
|
531 //!!! still to handle: median_c
|
cannam@180
|
532
|
cannam@174
|
533 float mean = summary.sum / summary.count;
|
cannam@174
|
534
|
cannam@182
|
535 std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
|
cannam@182
|
536 << summary.sum / summary.count << std::endl;
|
cannam@182
|
537
|
cannam@174
|
538 for (int k = 0; k < sz; ++k) {
|
cannam@174
|
539 summary.variance += (values[k] - mean) * (values[k] - mean);
|
cannam@174
|
540 }
|
cannam@174
|
541 summary.variance /= summary.count;
|
cannam@174
|
542
|
cannam@174
|
543 m_summaries[output][segmentStart][bin] = summary;
|
cannam@174
|
544 }
|
cannam@174
|
545 }
|
cannam@175
|
546
|
cannam@175
|
547 m_accumulators.clear();
|
cannam@174
|
548 }
|
cannam@174
|
549
|
cannam@174
|
550
|
cannam@174
|
551 }
|
cannam@174
|
552
|
cannam@174
|
553 }
|
cannam@174
|
554
|