cannam@0: cannam@0:
cannam@0:00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: 00002 cannam@0: 00003 /* cannam@0: 00004 Vamp cannam@0: 00005 cannam@0: 00006 An API for audio analysis and feature extraction plugins. cannam@0: 00007 cannam@0: 00008 Centre for Digital Music, Queen Mary, University of London. cannam@0: 00009 Copyright 2006-2007 Chris Cannam and QMUL. cannam@0: 00010 This file by Mark Levy and Chris Cannam. cannam@0: 00011 cannam@0: 00012 Permission is hereby granted, free of charge, to any person cannam@0: 00013 obtaining a copy of this software and associated documentation cannam@0: 00014 files (the "Software"), to deal in the Software without cannam@0: 00015 restriction, including without limitation the rights to use, copy, cannam@0: 00016 modify, merge, publish, distribute, sublicense, and/or sell copies cannam@0: 00017 of the Software, and to permit persons to whom the Software is cannam@0: 00018 furnished to do so, subject to the following conditions: cannam@0: 00019 cannam@0: 00020 The above copyright notice and this permission notice shall be cannam@0: 00021 included in all copies or substantial portions of the Software. cannam@0: 00022 cannam@0: 00023 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@0: 00024 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@0: 00025 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@0: 00026 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR cannam@0: 00027 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@0: 00028 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@0: 00029 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@0: 00030 cannam@0: 00031 Except as contained in this notice, the names of the Centre for cannam@0: 00032 Digital Music; Queen Mary, University of London; and Chris Cannam cannam@0: 00033 shall not be used in advertising or otherwise to promote the sale, cannam@0: 00034 use or other dealings in this Software without prior written cannam@0: 00035 authorization. cannam@0: 00036 */ cannam@0: 00037 cannam@0: 00038 #include <vector> cannam@0: 00039 #include <map> cannam@0: 00040 cannam@0: 00041 #include "PluginBufferingAdapter.h" cannam@0: 00042 cannam@0: 00043 using std::vector; cannam@0: 00044 using std::map; cannam@0: 00045 cannam@0: 00046 namespace Vamp { cannam@0: 00047 cannam@0: 00048 namespace HostExt { cannam@0: 00049 cannam@0: 00050 class PluginBufferingAdapter::Impl cannam@0: 00051 { cannam@0: 00052 public: cannam@0: 00053 Impl(Plugin *plugin, float inputSampleRate); cannam@0: 00054 ~Impl(); cannam@0: 00055 cannam@0: 00056 bool initialise(size_t channels, size_t stepSize, size_t blockSize); cannam@0: 00057 cannam@0: 00058 OutputList getOutputDescriptors() const; cannam@0: 00059 cannam@0: 00060 void reset(); cannam@0: 00061 cannam@0: 00062 FeatureSet process(const float *const *inputBuffers, RealTime timestamp); cannam@0: 00063 cannam@0: 00064 FeatureSet getRemainingFeatures(); cannam@0: 00065 cannam@0: 00066 protected: cannam@0: 00067 class RingBuffer cannam@0: 00068 { cannam@0: 00069 public: cannam@0: 00070 RingBuffer(int n) : cannam@0: 00071 m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { } cannam@0: 00072 virtual ~RingBuffer() { delete[] m_buffer; } cannam@0: 00073 cannam@0: 00074 int getSize() const { return m_size-1; } cannam@0: 00075 void reset() { m_writer = 0; m_reader = 0; } cannam@0: 00076 cannam@0: 00077 int getReadSpace() const { cannam@0: 00078 int writer = m_writer, reader = m_reader, space; cannam@0: 00079 if (writer > reader) space = writer - reader; cannam@0: 00080 else if (writer < reader) space = (writer + m_size) - reader; cannam@0: 00081 else space = 0; cannam@0: 00082 return space; cannam@0: 00083 } cannam@0: 00084 cannam@0: 00085 int getWriteSpace() const { cannam@0: 00086 int writer = m_writer; cannam@0: 00087 int reader = m_reader; cannam@0: 00088 int space = (reader + m_size - writer - 1); cannam@0: 00089 if (space >= m_size) space -= m_size; cannam@0: 00090 return space; cannam@0: 00091 } cannam@0: 00092 cannam@0: 00093 int peek(float *destination, int n) const { cannam@0: 00094 cannam@0: 00095 int available = getReadSpace(); cannam@0: 00096 cannam@0: 00097 if (n > available) { cannam@0: 00098 for (int i = available; i < n; ++i) { cannam@0: 00099 destination[i] = 0.f; cannam@0: 00100 } cannam@0: 00101 n = available; cannam@0: 00102 } cannam@0: 00103 if (n == 0) return n; cannam@0: 00104 cannam@0: 00105 int reader = m_reader; cannam@0: 00106 int here = m_size - reader; cannam@0: 00107 const float *const bufbase = m_buffer + reader; cannam@0: 00108 cannam@0: 00109 if (here >= n) { cannam@0: 00110 for (int i = 0; i < n; ++i) { cannam@0: 00111 destination[i] = bufbase[i]; cannam@0: 00112 } cannam@0: 00113 } else { cannam@0: 00114 for (int i = 0; i < here; ++i) { cannam@0: 00115 destination[i] = bufbase[i]; cannam@0: 00116 } cannam@0: 00117 float *const destbase = destination + here; cannam@0: 00118 const int nh = n - here; cannam@0: 00119 for (int i = 0; i < nh; ++i) { cannam@0: 00120 destbase[i] = m_buffer[i]; cannam@0: 00121 } cannam@0: 00122 } cannam@0: 00123 cannam@0: 00124 return n; cannam@0: 00125 } cannam@0: 00126 cannam@0: 00127 int skip(int n) { cannam@0: 00128 cannam@0: 00129 int available = getReadSpace(); cannam@0: 00130 if (n > available) { cannam@0: 00131 n = available; cannam@0: 00132 } cannam@0: 00133 if (n == 0) return n; cannam@0: 00134 cannam@0: 00135 int reader = m_reader; cannam@0: 00136 reader += n; cannam@0: 00137 while (reader >= m_size) reader -= m_size; cannam@0: 00138 m_reader = reader; cannam@0: 00139 return n; cannam@0: 00140 } cannam@0: 00141 cannam@0: 00142 int write(const float *source, int n) { cannam@0: 00143 cannam@0: 00144 int available = getWriteSpace(); cannam@0: 00145 if (n > available) { cannam@0: 00146 n = available; cannam@0: 00147 } cannam@0: 00148 if (n == 0) return n; cannam@0: 00149 cannam@0: 00150 int writer = m_writer; cannam@0: 00151 int here = m_size - writer; cannam@0: 00152 float *const bufbase = m_buffer + writer; cannam@0: 00153 cannam@0: 00154 if (here >= n) { cannam@0: 00155 for (int i = 0; i < n; ++i) { cannam@0: 00156 bufbase[i] = source[i]; cannam@0: 00157 } cannam@0: 00158 } else { cannam@0: 00159 for (int i = 0; i < here; ++i) { cannam@0: 00160 bufbase[i] = source[i]; cannam@0: 00161 } cannam@0: 00162 const int nh = n - here; cannam@0: 00163 const float *const srcbase = source + here; cannam@0: 00164 float *const buf = m_buffer; cannam@0: 00165 for (int i = 0; i < nh; ++i) { cannam@0: 00166 buf[i] = srcbase[i]; cannam@0: 00167 } cannam@0: 00168 } cannam@0: 00169 cannam@0: 00170 writer += n; cannam@0: 00171 while (writer >= m_size) writer -= m_size; cannam@0: 00172 m_writer = writer; cannam@0: 00173 cannam@0: 00174 return n; cannam@0: 00175 } cannam@0: 00176 cannam@0: 00177 int zero(int n) { cannam@0: 00178 cannam@0: 00179 int available = getWriteSpace(); cannam@0: 00180 if (n > available) { cannam@0: 00181 n = available; cannam@0: 00182 } cannam@0: 00183 if (n == 0) return n; cannam@0: 00184 cannam@0: 00185 int writer = m_writer; cannam@0: 00186 int here = m_size - writer; cannam@0: 00187 float *const bufbase = m_buffer + writer; cannam@0: 00188 cannam@0: 00189 if (here >= n) { cannam@0: 00190 for (int i = 0; i < n; ++i) { cannam@0: 00191 bufbase[i] = 0.f; cannam@0: 00192 } cannam@0: 00193 } else { cannam@0: 00194 for (int i = 0; i < here; ++i) { cannam@0: 00195 bufbase[i] = 0.f; cannam@0: 00196 } cannam@0: 00197 const int nh = n - here; cannam@0: 00198 for (int i = 0; i < nh; ++i) { cannam@0: 00199 m_buffer[i] = 0.f; cannam@0: 00200 } cannam@0: 00201 } cannam@0: 00202 cannam@0: 00203 writer += n; cannam@0: 00204 while (writer >= m_size) writer -= m_size; cannam@0: 00205 m_writer = writer; cannam@0: 00206 cannam@0: 00207 return n; cannam@0: 00208 } cannam@0: 00209 cannam@0: 00210 protected: cannam@0: 00211 float *m_buffer; cannam@0: 00212 int m_writer; cannam@0: 00213 int m_reader; cannam@0: 00214 int m_size; cannam@0: 00215 cannam@0: 00216 private: cannam@0: 00217 RingBuffer(const RingBuffer &); // not provided cannam@0: 00218 RingBuffer &operator=(const RingBuffer &); // not provided cannam@0: 00219 }; cannam@0: 00220 cannam@0: 00221 Plugin *m_plugin; cannam@0: 00222 size_t m_inputStepSize; cannam@0: 00223 size_t m_inputBlockSize; cannam@0: 00224 size_t m_stepSize; cannam@0: 00225 size_t m_blockSize; cannam@0: 00226 size_t m_channels; cannam@0: 00227 vector<RingBuffer *> m_queue; cannam@0: 00228 float **m_buffers; cannam@0: 00229 float m_inputSampleRate; cannam@0: 00230 long m_frame; cannam@0: 00231 bool m_unrun; cannam@0: 00232 mutable OutputList m_outputs; cannam@0: 00233 mutable std::map<int, bool> m_rewriteOutputTimes; cannam@0: 00234 cannam@0: 00235 void processBlock(FeatureSet& allFeatureSets); cannam@0: 00236 }; cannam@0: 00237 cannam@0: 00238 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) : cannam@0: 00239 PluginWrapper(plugin) cannam@0: 00240 { cannam@0: 00241 m_impl = new Impl(plugin, m_inputSampleRate); cannam@0: 00242 } cannam@0: 00243 cannam@0: 00244 PluginBufferingAdapter::~PluginBufferingAdapter() cannam@0: 00245 { cannam@0: 00246 delete m_impl; cannam@0: 00247 } cannam@0: 00248 cannam@0: 00249 bool cannam@0: 00250 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) cannam@0: 00251 { cannam@0: 00252 return m_impl->initialise(channels, stepSize, blockSize); cannam@0: 00253 } cannam@0: 00254 cannam@0: 00255 PluginBufferingAdapter::OutputList cannam@0: 00256 PluginBufferingAdapter::getOutputDescriptors() const cannam@0: 00257 { cannam@0: 00258 return m_impl->getOutputDescriptors(); cannam@0: 00259 } cannam@0: 00260 cannam@0: 00261 void cannam@0: 00262 PluginBufferingAdapter::reset() cannam@0: 00263 { cannam@0: 00264 m_impl->reset(); cannam@0: 00265 } cannam@0: 00266 cannam@0: 00267 PluginBufferingAdapter::FeatureSet cannam@0: 00268 PluginBufferingAdapter::process(const float *const *inputBuffers, cannam@0: 00269 RealTime timestamp) cannam@0: 00270 { cannam@0: 00271 return m_impl->process(inputBuffers, timestamp); cannam@0: 00272 } cannam@0: 00273 cannam@0: 00274 PluginBufferingAdapter::FeatureSet cannam@0: 00275 PluginBufferingAdapter::getRemainingFeatures() cannam@0: 00276 { cannam@0: 00277 return m_impl->getRemainingFeatures(); cannam@0: 00278 } cannam@0: 00279 cannam@0: 00280 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : cannam@0: 00281 m_plugin(plugin), cannam@0: 00282 m_inputStepSize(0), cannam@0: 00283 m_inputBlockSize(0), cannam@0: 00284 m_stepSize(0), cannam@0: 00285 m_blockSize(0), cannam@0: 00286 m_channels(0), cannam@0: 00287 m_queue(0), cannam@0: 00288 m_buffers(0), cannam@0: 00289 m_inputSampleRate(inputSampleRate), cannam@0: 00290 m_frame(0), cannam@0: 00291 m_unrun(true) cannam@0: 00292 { cannam@0: 00293 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes cannam@0: 00294 } cannam@0: 00295 cannam@0: 00296 PluginBufferingAdapter::Impl::~Impl() cannam@0: 00297 { cannam@0: 00298 // the adapter will delete the plugin cannam@0: 00299 cannam@0: 00300 for (size_t i = 0; i < m_channels; ++i) { cannam@0: 00301 delete m_queue[i]; cannam@0: 00302 delete[] m_buffers[i]; cannam@0: 00303 } cannam@0: 00304 delete[] m_buffers; cannam@0: 00305 } cannam@0: 00306 cannam@0: 00307 size_t cannam@0: 00308 PluginBufferingAdapter::getPreferredStepSize() const cannam@0: 00309 { cannam@0: 00310 return getPreferredBlockSize(); cannam@0: 00311 } cannam@0: 00312 cannam@0: 00313 bool cannam@0: 00314 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) cannam@0: 00315 { cannam@0: 00316 if (stepSize != blockSize) { cannam@0: 00317 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl; cannam@0: 00318 return false; cannam@0: 00319 } cannam@0: 00320 cannam@0: 00321 m_channels = channels; cannam@0: 00322 m_inputStepSize = stepSize; cannam@0: 00323 m_inputBlockSize = blockSize; cannam@0: 00324 cannam@0: 00325 // use the step and block sizes which the plugin prefers cannam@0: 00326 m_stepSize = m_plugin->getPreferredStepSize(); cannam@0: 00327 m_blockSize = m_plugin->getPreferredBlockSize(); cannam@0: 00328 cannam@0: 00329 // or sensible defaults if it has no preference cannam@0: 00330 if (m_blockSize == 0) { cannam@0: 00331 m_blockSize = 1024; cannam@0: 00332 } cannam@0: 00333 if (m_stepSize == 0) { cannam@0: 00334 if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { cannam@0: 00335 m_stepSize = m_blockSize/2; cannam@0: 00336 } else { cannam@0: 00337 m_stepSize = m_blockSize; cannam@0: 00338 } cannam@0: 00339 } else if (m_stepSize > m_blockSize) { cannam@0: 00340 if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { cannam@0: 00341 m_blockSize = m_stepSize * 2; cannam@0: 00342 } else { cannam@0: 00343 m_blockSize = m_stepSize; cannam@0: 00344 } cannam@0: 00345 } cannam@0: 00346 cannam@0: 00347 std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize cannam@0: 00348 << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl; cannam@0: 00349 cannam@0: 00350 // current implementation breaks if step is greater than block cannam@0: 00351 if (m_stepSize > m_blockSize) { cannam@0: 00352 std::cerr << "PluginBufferingAdapter::initialise: plugin's preferred stepSize greater than blockSize, giving up!" << std::endl; cannam@0: 00353 return false; cannam@0: 00354 } cannam@0: 00355 cannam@0: 00356 m_buffers = new float *[m_channels]; cannam@0: 00357 cannam@0: 00358 for (size_t i = 0; i < m_channels; ++i) { cannam@0: 00359 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize)); cannam@0: 00360 m_buffers[i] = new float[m_blockSize]; cannam@0: 00361 } cannam@0: 00362 cannam@0: 00363 return m_plugin->initialise(m_channels, m_stepSize, m_blockSize); cannam@0: 00364 } cannam@0: 00365 cannam@0: 00366 PluginBufferingAdapter::OutputList cannam@0: 00367 PluginBufferingAdapter::Impl::getOutputDescriptors() const cannam@0: 00368 { cannam@0: 00369 if (m_outputs.empty()) { cannam@0: 00370 m_outputs = m_plugin->getOutputDescriptors(); cannam@0: 00371 } cannam@0: 00372 cannam@0: 00373 PluginBufferingAdapter::OutputList outs = m_outputs; cannam@0: 00374 cannam@0: 00375 for (size_t i = 0; i < outs.size(); ++i) { cannam@0: 00376 cannam@0: 00377 switch (outs[i].sampleType) { cannam@0: 00378 cannam@0: 00379 case OutputDescriptor::OneSamplePerStep: cannam@0: 00380 outs[i].sampleType = OutputDescriptor::FixedSampleRate; cannam@0: 00381 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; cannam@0: 00382 m_rewriteOutputTimes[i] = true; cannam@0: 00383 break; cannam@0: 00384 cannam@0: 00385 case OutputDescriptor::FixedSampleRate: cannam@0: 00386 if (outs[i].sampleRate == 0.f) { cannam@0: 00387 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize; cannam@0: 00388 } cannam@0: 00389 // We actually only need to rewrite output times for cannam@0: 00390 // features that don't have timestamps already, but we cannam@0: 00391 // can't tell from here whether our features will have cannam@0: 00392 // timestamps or not cannam@0: 00393 m_rewriteOutputTimes[i] = true; cannam@0: 00394 break; cannam@0: 00395 cannam@0: 00396 case OutputDescriptor::VariableSampleRate: cannam@0: 00397 m_rewriteOutputTimes[i] = false; cannam@0: 00398 break; cannam@0: 00399 } cannam@0: 00400 } cannam@0: 00401 cannam@0: 00402 return outs; cannam@0: 00403 } cannam@0: 00404 cannam@0: 00405 void cannam@0: 00406 PluginBufferingAdapter::Impl::reset() cannam@0: 00407 { cannam@0: 00408 m_frame = 0; cannam@0: 00409 m_unrun = true; cannam@0: 00410 cannam@0: 00411 for (size_t i = 0; i < m_queue.size(); ++i) { cannam@0: 00412 m_queue[i]->reset(); cannam@0: 00413 } cannam@0: 00414 } cannam@0: 00415 cannam@0: 00416 PluginBufferingAdapter::FeatureSet cannam@0: 00417 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers, cannam@0: 00418 RealTime timestamp) cannam@0: 00419 { cannam@0: 00420 FeatureSet allFeatureSets; cannam@0: 00421 cannam@0: 00422 if (m_unrun) { cannam@0: 00423 m_frame = RealTime::realTime2Frame(timestamp, cannam@0: 00424 int(m_inputSampleRate + 0.5)); cannam@0: 00425 m_unrun = false; cannam@0: 00426 } cannam@0: 00427 cannam@0: 00428 // queue the new input cannam@0: 00429 cannam@0: 00430 for (size_t i = 0; i < m_channels; ++i) { cannam@0: 00431 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize); cannam@0: 00432 if (written < int(m_inputBlockSize) && i == 0) { cannam@0: 00433 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: " cannam@0: 00434 << "Buffer overflow: wrote " << written cannam@0: 00435 << " of " << m_inputBlockSize cannam@0: 00436 << " input samples (for plugin step size " cannam@0: 00437 << m_stepSize << ", block size " << m_blockSize << ")" cannam@0: 00438 << std::endl; cannam@0: 00439 } cannam@0: 00440 } cannam@0: 00441 cannam@0: 00442 // process as much as we can cannam@0: 00443 cannam@0: 00444 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { cannam@0: 00445 processBlock(allFeatureSets); cannam@0: 00446 } cannam@0: 00447 cannam@0: 00448 return allFeatureSets; cannam@0: 00449 } cannam@0: 00450 cannam@0: 00451 PluginBufferingAdapter::FeatureSet cannam@0: 00452 PluginBufferingAdapter::Impl::getRemainingFeatures() cannam@0: 00453 { cannam@0: 00454 FeatureSet allFeatureSets; cannam@0: 00455 cannam@0: 00456 // process remaining samples in queue cannam@0: 00457 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) { cannam@0: 00458 processBlock(allFeatureSets); cannam@0: 00459 } cannam@0: 00460 cannam@0: 00461 // pad any last samples remaining and process cannam@0: 00462 if (m_queue[0]->getReadSpace() > 0) { cannam@0: 00463 for (size_t i = 0; i < m_channels; ++i) { cannam@0: 00464 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace()); cannam@0: 00465 } cannam@0: 00466 processBlock(allFeatureSets); cannam@0: 00467 } cannam@0: 00468 cannam@0: 00469 // get remaining features cannam@0: 00470 cannam@0: 00471 FeatureSet featureSet = m_plugin->getRemainingFeatures(); cannam@0: 00472 cannam@0: 00473 for (map<int, FeatureList>::iterator iter = featureSet.begin(); cannam@0: 00474 iter != featureSet.end(); ++iter) { cannam@0: 00475 FeatureList featureList = iter->second; cannam@0: 00476 for (size_t i = 0; i < featureList.size(); ++i) { cannam@0: 00477 allFeatureSets[iter->first].push_back(featureList[i]); cannam@0: 00478 } cannam@0: 00479 } cannam@0: 00480 cannam@0: 00481 return allFeatureSets; cannam@0: 00482 } cannam@0: 00483 cannam@0: 00484 void cannam@0: 00485 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets) cannam@0: 00486 { cannam@0: 00487 for (size_t i = 0; i < m_channels; ++i) { cannam@0: 00488 m_queue[i]->peek(m_buffers[i], m_blockSize); cannam@0: 00489 } cannam@0: 00490 cannam@0: 00491 long frame = m_frame; cannam@0: 00492 RealTime timestamp = RealTime::frame2RealTime cannam@0: 00493 (frame, int(m_inputSampleRate + 0.5)); cannam@0: 00494 cannam@0: 00495 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp); cannam@0: 00496 cannam@0: 00497 for (FeatureSet::iterator iter = featureSet.begin(); cannam@0: 00498 iter != featureSet.end(); ++iter) { cannam@0: 00499 cannam@0: 00500 int outputNo = iter->first; cannam@0: 00501 cannam@0: 00502 if (m_rewriteOutputTimes[outputNo]) { cannam@0: 00503 cannam@0: 00504 FeatureList featureList = iter->second; cannam@0: 00505 cannam@0: 00506 for (size_t i = 0; i < featureList.size(); ++i) { cannam@0: 00507 cannam@0: 00508 switch (m_outputs[outputNo].sampleType) { cannam@0: 00509 cannam@0: 00510 case OutputDescriptor::OneSamplePerStep: cannam@0: 00511 // use our internal timestamp, always cannam@0: 00512 featureList[i].timestamp = timestamp; cannam@0: 00513 featureList[i].hasTimestamp = true; cannam@0: 00514 break; cannam@0: 00515 cannam@0: 00516 case OutputDescriptor::FixedSampleRate: cannam@0: 00517 // use our internal timestamp if feature lacks one cannam@0: 00518 if (!featureList[i].hasTimestamp) { cannam@0: 00519 featureList[i].timestamp = timestamp; cannam@0: 00520 featureList[i].hasTimestamp = true; cannam@0: 00521 } cannam@0: 00522 break; cannam@0: 00523 cannam@0: 00524 case OutputDescriptor::VariableSampleRate: cannam@0: 00525 break; // plugin must set timestamp cannam@0: 00526 cannam@0: 00527 default: cannam@0: 00528 break; cannam@0: 00529 } cannam@0: 00530 cannam@0: 00531 allFeatureSets[outputNo].push_back(featureList[i]); cannam@0: 00532 } cannam@0: 00533 } else { cannam@0: 00534 for (size_t i = 0; i < iter->second.size(); ++i) { cannam@0: 00535 allFeatureSets[outputNo].push_back(iter->second[i]); cannam@0: 00536 } cannam@0: 00537 } cannam@0: 00538 } cannam@0: 00539 cannam@0: 00540 // step forward cannam@0: 00541 cannam@0: 00542 for (size_t i = 0; i < m_channels; ++i) { cannam@0: 00543 m_queue[i]->skip(m_stepSize); cannam@0: 00544 } cannam@0: 00545 cannam@0: 00546 // increment internal frame counter each time we step forward cannam@0: 00547 m_frame += m_stepSize; cannam@0: 00548 } cannam@0: 00549 cannam@0: 00550 } cannam@0: 00551 cannam@0: 00552 } cannam@0: 00553 cannam@0: 00554 cannam@0: