Mercurial > hg > vamp-plugin-sdk
comparison vamp-sdk/hostext/PluginSummarisingAdapter.cpp @ 183:c053ababbf7e
* Fixes to continuous time averaging
author | cannam |
---|---|
date | Fri, 05 Sep 2008 13:52:57 +0000 |
parents | 3fcac0f3afdc |
children | 26c200c3fc42 |
comparison
equal
deleted
inserted
replaced
182:3fcac0f3afdc | 183:c053ababbf7e |
---|---|
81 typedef std::map<int, OutputAccumulator> OutputAccumulatorMap; | 81 typedef std::map<int, OutputAccumulator> OutputAccumulatorMap; |
82 OutputAccumulatorMap m_accumulators; // output number -> accumulator | 82 OutputAccumulatorMap m_accumulators; // output number -> accumulator |
83 | 83 |
84 typedef std::map<int, RealTime> OutputTimestampMap; | 84 typedef std::map<int, RealTime> OutputTimestampMap; |
85 OutputTimestampMap m_prevTimestamps; // output number -> timestamp | 85 OutputTimestampMap m_prevTimestamps; // output number -> timestamp |
86 OutputTimestampMap m_prevDurations; // output number -> durations | |
86 | 87 |
87 struct OutputBinSummary { | 88 struct OutputBinSummary { |
88 | 89 |
89 int count; | 90 int count; |
90 | 91 |
109 typedef std::map<RealTime, OutputSummary> SummarySegmentMap; | 110 typedef std::map<RealTime, OutputSummary> SummarySegmentMap; |
110 typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap; | 111 typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap; |
111 | 112 |
112 OutputSummarySegmentMap m_summaries; | 113 OutputSummarySegmentMap m_summaries; |
113 | 114 |
115 bool m_reduced; | |
114 RealTime m_lastTimestamp; | 116 RealTime m_lastTimestamp; |
115 RealTime m_prevDuration; | |
116 | 117 |
117 void accumulate(const FeatureSet &fs, RealTime, bool final); | 118 void accumulate(const FeatureSet &fs, RealTime, bool final); |
118 void accumulate(int output, const Feature &f, RealTime, bool final); | 119 void accumulate(int output, const Feature &f, RealTime, bool final); |
119 void reduce(); | 120 void reduce(); |
120 }; | 121 }; |
157 return m_impl->getSummaryForAllOutputs(type, avg); | 158 return m_impl->getSummaryForAllOutputs(type, avg); |
158 } | 159 } |
159 | 160 |
160 PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : | 161 PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : |
161 m_plugin(plugin), | 162 m_plugin(plugin), |
162 m_inputSampleRate(inputSampleRate) | 163 m_inputSampleRate(inputSampleRate), |
164 m_reduced(false) | |
163 { | 165 { |
164 } | 166 } |
165 | 167 |
166 PluginSummarisingAdapter::Impl::~Impl() | 168 PluginSummarisingAdapter::Impl::~Impl() |
167 { | 169 { |
168 } | 170 } |
169 | 171 |
170 Plugin::FeatureSet | 172 Plugin::FeatureSet |
171 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, RealTime timestamp) | 173 PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers, RealTime timestamp) |
172 { | 174 { |
175 if (m_reduced) { | |
176 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; | |
177 } | |
173 FeatureSet fs = m_plugin->process(inputBuffers, timestamp); | 178 FeatureSet fs = m_plugin->process(inputBuffers, timestamp); |
174 accumulate(fs, timestamp, false); | 179 accumulate(fs, timestamp, false); |
175 m_lastTimestamp = timestamp; | 180 m_lastTimestamp = timestamp; |
176 return fs; | 181 return fs; |
177 } | 182 } |
178 | 183 |
179 Plugin::FeatureSet | 184 Plugin::FeatureSet |
180 PluginSummarisingAdapter::Impl::getRemainingFeatures() | 185 PluginSummarisingAdapter::Impl::getRemainingFeatures() |
181 { | 186 { |
187 if (m_reduced) { | |
188 std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl; | |
189 } | |
182 FeatureSet fs = m_plugin->getRemainingFeatures(); | 190 FeatureSet fs = m_plugin->getRemainingFeatures(); |
183 accumulate(fs, m_lastTimestamp, true); | 191 accumulate(fs, m_lastTimestamp, true); |
184 reduce(); | |
185 return fs; | 192 return fs; |
186 } | 193 } |
187 | 194 |
188 Plugin::FeatureList | 195 Plugin::FeatureList |
189 PluginSummarisingAdapter::Impl::getSummaryForOutput(int output, | 196 PluginSummarisingAdapter::Impl::getSummaryForOutput(int output, |
190 SummaryType type, | 197 SummaryType type, |
191 AveragingMethod avg) | 198 AveragingMethod avg) |
192 { | 199 { |
200 if (!m_reduced) reduce(); | |
201 | |
193 bool continuous = (avg == ContinuousTimeAverage); | 202 bool continuous = (avg == ContinuousTimeAverage); |
194 | 203 |
195 //!!! need to ensure that this is only called after processing is | |
196 //!!! complete (at the moment processing is "completed" in the | |
197 //!!! call to getRemainingFeatures, but we don't want to require | |
198 //!!! the host to call getRemainingFeatures at all unless it | |
199 //!!! actually wants the raw features too -- calling getSummary | |
200 //!!! should be enough -- we do need to ensure that all data has | |
201 //!!! been processed though!) | |
202 FeatureList fl; | 204 FeatureList fl; |
203 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); | 205 for (SummarySegmentMap::const_iterator i = m_summaries[output].begin(); |
204 i != m_summaries[output].end(); ++i) { | 206 i != m_summaries[output].end(); ++i) { |
205 | 207 |
206 Feature f; | 208 Feature f; |
278 | 280 |
279 Plugin::FeatureSet | 281 Plugin::FeatureSet |
280 PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, | 282 PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type, |
281 AveragingMethod avg) | 283 AveragingMethod avg) |
282 { | 284 { |
285 if (!m_reduced) reduce(); | |
286 | |
283 FeatureSet fs; | 287 FeatureSet fs; |
284 for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); | 288 for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin(); |
285 i != m_summaries.end(); ++i) { | 289 i != m_summaries.end(); ++i) { |
286 fs[i->first] = getSummaryForOutput(i->first, type, avg); | 290 fs[i->first] = getSummaryForOutput(i->first, type, avg); |
287 } | 291 } |
316 | 320 |
317 m_accumulators[output].count++; | 321 m_accumulators[output].count++; |
318 | 322 |
319 std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << std::endl; | 323 std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << std::endl; |
320 | 324 |
321 //!!! m_prevDuration needs to be per output | |
322 | |
323 //!!! also, this will not work if we are called repeatedly with | 325 //!!! also, this will not work if we are called repeatedly with |
324 //!!! the same timestamp -- no values will be registered until a | 326 //!!! the same timestamp -- no values will be registered until a |
325 //!!! new timestamp is seen -- we need a better test for "not | 327 //!!! new timestamp is seen -- we need a better test for "not |
326 //!!! first result" below | 328 //!!! first result" below |
327 | 329 |
328 if (m_prevDuration == RealTime::zeroTime) { | 330 if (m_prevDurations[output] == RealTime::zeroTime) { |
329 if (m_prevTimestamps.find(output) != m_prevTimestamps.end()) { | 331 if (m_prevTimestamps.find(output) != m_prevTimestamps.end()) { |
330 m_prevDuration = timestamp - m_prevTimestamps[output]; | 332 m_prevDurations[output] = timestamp - m_prevTimestamps[output]; |
331 } | 333 } |
332 } | 334 } |
333 if (m_prevDuration != RealTime::zeroTime || | 335 if (m_prevDurations[output] != RealTime::zeroTime || |
334 !m_accumulators[output].durations.empty()) { | 336 !m_accumulators[output].durations.empty()) { |
335 // ... i.e. if not first result. We don't push a duration | 337 // ... i.e. if not first result. We don't push a duration |
336 // when we process the first result; then the duration we push | 338 // when we process the first result; then the duration we push |
337 // each time is that for the result before the one we're | 339 // each time is that for the result before the one we're |
338 // processing, and we push an extra one at the end. This | 340 // processing, and we push an extra one at the end. This |
339 // permits handling the case where the feature itself doesn't | 341 // permits handling the case where the feature itself doesn't |
340 // have a duration field, and we have to calculate it from the | 342 // have a duration field, and we have to calculate it from the |
341 // time to the following feature. The net effect is simply | 343 // time to the following feature. The net effect is simply |
342 // that values[n] and durations[n] refer to the same result. | 344 // that values[n] and durations[n] refer to the same result. |
343 m_accumulators[output].durations.push_back(m_prevDuration); | 345 m_accumulators[output].durations.push_back(m_prevDurations[output]); |
344 } | 346 } |
345 | 347 |
346 m_prevTimestamps[output] = timestamp; | 348 m_prevTimestamps[output] = timestamp; |
347 | 349 |
348 for (int i = 0; i < int(f.values.size()); ++i) { | 350 for (int i = 0; i < int(f.values.size()); ++i) { |
353 RealTime finalDuration; | 355 RealTime finalDuration; |
354 if (f.hasDuration) finalDuration = f.duration; | 356 if (f.hasDuration) finalDuration = f.duration; |
355 m_accumulators[output].durations.push_back(finalDuration); | 357 m_accumulators[output].durations.push_back(finalDuration); |
356 } | 358 } |
357 | 359 |
358 if (f.hasDuration) m_prevDuration = f.duration; | 360 if (f.hasDuration) m_prevDurations[output] = f.duration; |
359 else m_prevDuration = RealTime::zeroTime; | 361 else m_prevDurations[output] = RealTime::zeroTime; |
360 } | 362 } |
361 | 363 |
362 struct ValueDurationFloatPair | 364 struct ValueDurationFloatPair |
363 { | 365 { |
364 float value; | 366 float value; |
543 m_summaries[output][segmentStart][bin] = summary; | 545 m_summaries[output][segmentStart][bin] = summary; |
544 } | 546 } |
545 } | 547 } |
546 | 548 |
547 m_accumulators.clear(); | 549 m_accumulators.clear(); |
548 } | 550 m_reduced = true; |
549 | 551 } |
550 | 552 |
551 } | 553 |
552 | 554 } |
553 } | 555 |
554 | 556 } |
557 |