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