annotate src/vamp-hostsdk/hostext/PluginBufferingAdapter.cpp @ 229:3451f7dfa2be distinct-libraries

* more moving
author cannam
date Thu, 06 Nov 2008 16:55:15 +0000
parents 6b30e064cab7
children 5ee166dccfff
rev   line source
cannam@227 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@227 2
cannam@227 3 /*
cannam@227 4 Vamp
cannam@227 5
cannam@227 6 An API for audio analysis and feature extraction plugins.
cannam@227 7
cannam@227 8 Centre for Digital Music, Queen Mary, University of London.
cannam@227 9 Copyright 2006-2007 Chris Cannam and QMUL.
cannam@227 10 This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL.
cannam@227 11
cannam@227 12 Permission is hereby granted, free of charge, to any person
cannam@227 13 obtaining a copy of this software and associated documentation
cannam@227 14 files (the "Software"), to deal in the Software without
cannam@227 15 restriction, including without limitation the rights to use, copy,
cannam@227 16 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@227 17 of the Software, and to permit persons to whom the Software is
cannam@227 18 furnished to do so, subject to the following conditions:
cannam@227 19
cannam@227 20 The above copyright notice and this permission notice shall be
cannam@227 21 included in all copies or substantial portions of the Software.
cannam@227 22
cannam@227 23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@227 24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@227 25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@227 26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@227 27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@227 28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@227 29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@227 30
cannam@227 31 Except as contained in this notice, the names of the Centre for
cannam@227 32 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@227 33 shall not be used in advertising or otherwise to promote the sale,
cannam@227 34 use or other dealings in this Software without prior written
cannam@227 35 authorization.
cannam@227 36 */
cannam@227 37
cannam@227 38 #include <vector>
cannam@227 39 #include <map>
cannam@227 40
cannam@227 41 #include "PluginBufferingAdapter.h"
cannam@227 42
cannam@227 43 using std::vector;
cannam@227 44 using std::map;
cannam@227 45
cannam@227 46 namespace Vamp {
cannam@227 47
cannam@227 48 namespace HostExt {
cannam@227 49
cannam@227 50 class PluginBufferingAdapter::Impl
cannam@227 51 {
cannam@227 52 public:
cannam@227 53 Impl(Plugin *plugin, float inputSampleRate);
cannam@227 54 ~Impl();
cannam@227 55
cannam@227 56 void setPluginStepSize(size_t stepSize);
cannam@227 57 void setPluginBlockSize(size_t blockSize);
cannam@227 58
cannam@227 59 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
cannam@227 60
cannam@227 61 void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
cannam@227 62
cannam@227 63 OutputList getOutputDescriptors() const;
cannam@227 64
cannam@227 65 void reset();
cannam@227 66
cannam@227 67 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
cannam@227 68
cannam@227 69 FeatureSet getRemainingFeatures();
cannam@227 70
cannam@227 71 protected:
cannam@227 72 class RingBuffer
cannam@227 73 {
cannam@227 74 public:
cannam@227 75 RingBuffer(int n) :
cannam@227 76 m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
cannam@227 77 virtual ~RingBuffer() { delete[] m_buffer; }
cannam@227 78
cannam@227 79 int getSize() const { return m_size-1; }
cannam@227 80 void reset() { m_writer = 0; m_reader = 0; }
cannam@227 81
cannam@227 82 int getReadSpace() const {
cannam@227 83 int writer = m_writer, reader = m_reader, space;
cannam@227 84 if (writer > reader) space = writer - reader;
cannam@227 85 else if (writer < reader) space = (writer + m_size) - reader;
cannam@227 86 else space = 0;
cannam@227 87 return space;
cannam@227 88 }
cannam@227 89
cannam@227 90 int getWriteSpace() const {
cannam@227 91 int writer = m_writer;
cannam@227 92 int reader = m_reader;
cannam@227 93 int space = (reader + m_size - writer - 1);
cannam@227 94 if (space >= m_size) space -= m_size;
cannam@227 95 return space;
cannam@227 96 }
cannam@227 97
cannam@227 98 int peek(float *destination, int n) const {
cannam@227 99
cannam@227 100 int available = getReadSpace();
cannam@227 101
cannam@227 102 if (n > available) {
cannam@227 103 for (int i = available; i < n; ++i) {
cannam@227 104 destination[i] = 0.f;
cannam@227 105 }
cannam@227 106 n = available;
cannam@227 107 }
cannam@227 108 if (n == 0) return n;
cannam@227 109
cannam@227 110 int reader = m_reader;
cannam@227 111 int here = m_size - reader;
cannam@227 112 const float *const bufbase = m_buffer + reader;
cannam@227 113
cannam@227 114 if (here >= n) {
cannam@227 115 for (int i = 0; i < n; ++i) {
cannam@227 116 destination[i] = bufbase[i];
cannam@227 117 }
cannam@227 118 } else {
cannam@227 119 for (int i = 0; i < here; ++i) {
cannam@227 120 destination[i] = bufbase[i];
cannam@227 121 }
cannam@227 122 float *const destbase = destination + here;
cannam@227 123 const int nh = n - here;
cannam@227 124 for (int i = 0; i < nh; ++i) {
cannam@227 125 destbase[i] = m_buffer[i];
cannam@227 126 }
cannam@227 127 }
cannam@227 128
cannam@227 129 return n;
cannam@227 130 }
cannam@227 131
cannam@227 132 int skip(int n) {
cannam@227 133
cannam@227 134 int available = getReadSpace();
cannam@227 135 if (n > available) {
cannam@227 136 n = available;
cannam@227 137 }
cannam@227 138 if (n == 0) return n;
cannam@227 139
cannam@227 140 int reader = m_reader;
cannam@227 141 reader += n;
cannam@227 142 while (reader >= m_size) reader -= m_size;
cannam@227 143 m_reader = reader;
cannam@227 144 return n;
cannam@227 145 }
cannam@227 146
cannam@227 147 int write(const float *source, int n) {
cannam@227 148
cannam@227 149 int available = getWriteSpace();
cannam@227 150 if (n > available) {
cannam@227 151 n = available;
cannam@227 152 }
cannam@227 153 if (n == 0) return n;
cannam@227 154
cannam@227 155 int writer = m_writer;
cannam@227 156 int here = m_size - writer;
cannam@227 157 float *const bufbase = m_buffer + writer;
cannam@227 158
cannam@227 159 if (here >= n) {
cannam@227 160 for (int i = 0; i < n; ++i) {
cannam@227 161 bufbase[i] = source[i];
cannam@227 162 }
cannam@227 163 } else {
cannam@227 164 for (int i = 0; i < here; ++i) {
cannam@227 165 bufbase[i] = source[i];
cannam@227 166 }
cannam@227 167 const int nh = n - here;
cannam@227 168 const float *const srcbase = source + here;
cannam@227 169 float *const buf = m_buffer;
cannam@227 170 for (int i = 0; i < nh; ++i) {
cannam@227 171 buf[i] = srcbase[i];
cannam@227 172 }
cannam@227 173 }
cannam@227 174
cannam@227 175 writer += n;
cannam@227 176 while (writer >= m_size) writer -= m_size;
cannam@227 177 m_writer = writer;
cannam@227 178
cannam@227 179 return n;
cannam@227 180 }
cannam@227 181
cannam@227 182 int zero(int n) {
cannam@227 183
cannam@227 184 int available = getWriteSpace();
cannam@227 185 if (n > available) {
cannam@227 186 n = available;
cannam@227 187 }
cannam@227 188 if (n == 0) return n;
cannam@227 189
cannam@227 190 int writer = m_writer;
cannam@227 191 int here = m_size - writer;
cannam@227 192 float *const bufbase = m_buffer + writer;
cannam@227 193
cannam@227 194 if (here >= n) {
cannam@227 195 for (int i = 0; i < n; ++i) {
cannam@227 196 bufbase[i] = 0.f;
cannam@227 197 }
cannam@227 198 } else {
cannam@227 199 for (int i = 0; i < here; ++i) {
cannam@227 200 bufbase[i] = 0.f;
cannam@227 201 }
cannam@227 202 const int nh = n - here;
cannam@227 203 for (int i = 0; i < nh; ++i) {
cannam@227 204 m_buffer[i] = 0.f;
cannam@227 205 }
cannam@227 206 }
cannam@227 207
cannam@227 208 writer += n;
cannam@227 209 while (writer >= m_size) writer -= m_size;
cannam@227 210 m_writer = writer;
cannam@227 211
cannam@227 212 return n;
cannam@227 213 }
cannam@227 214
cannam@227 215 protected:
cannam@227 216 float *m_buffer;
cannam@227 217 int m_writer;
cannam@227 218 int m_reader;
cannam@227 219 int m_size;
cannam@227 220
cannam@227 221 private:
cannam@227 222 RingBuffer(const RingBuffer &); // not provided
cannam@227 223 RingBuffer &operator=(const RingBuffer &); // not provided
cannam@227 224 };
cannam@227 225
cannam@227 226 Plugin *m_plugin;
cannam@227 227 size_t m_inputStepSize; // value passed to wrapper initialise()
cannam@227 228 size_t m_inputBlockSize; // value passed to wrapper initialise()
cannam@227 229 size_t m_setStepSize; // value passed to setPluginStepSize()
cannam@227 230 size_t m_setBlockSize; // value passed to setPluginBlockSize()
cannam@227 231 size_t m_stepSize; // value actually used to initialise plugin
cannam@227 232 size_t m_blockSize; // value actually used to initialise plugin
cannam@227 233 size_t m_channels;
cannam@227 234 vector<RingBuffer *> m_queue;
cannam@227 235 float **m_buffers;
cannam@227 236 float m_inputSampleRate;
cannam@227 237 long m_frame;
cannam@227 238 bool m_unrun;
cannam@227 239 mutable OutputList m_outputs;
cannam@227 240 mutable std::map<int, bool> m_rewriteOutputTimes;
cannam@227 241
cannam@227 242 void processBlock(FeatureSet& allFeatureSets);
cannam@227 243 };
cannam@227 244
cannam@227 245 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
cannam@227 246 PluginWrapper(plugin)
cannam@227 247 {
cannam@227 248 m_impl = new Impl(plugin, m_inputSampleRate);
cannam@227 249 }
cannam@227 250
cannam@227 251 PluginBufferingAdapter::~PluginBufferingAdapter()
cannam@227 252 {
cannam@227 253 delete m_impl;
cannam@227 254 }
cannam@227 255
cannam@227 256 size_t
cannam@227 257 PluginBufferingAdapter::getPreferredStepSize() const
cannam@227 258 {
cannam@227 259 return getPreferredBlockSize();
cannam@227 260 }
cannam@227 261
cannam@227 262 size_t
cannam@227 263 PluginBufferingAdapter::getPreferredBlockSize() const
cannam@227 264 {
cannam@227 265 return PluginWrapper::getPreferredBlockSize();
cannam@227 266 }
cannam@227 267
cannam@227 268 size_t
cannam@227 269 PluginBufferingAdapter::getPluginPreferredStepSize() const
cannam@227 270 {
cannam@227 271 return PluginWrapper::getPreferredStepSize();
cannam@227 272 }
cannam@227 273
cannam@227 274 size_t
cannam@227 275 PluginBufferingAdapter::getPluginPreferredBlockSize() const
cannam@227 276 {
cannam@227 277 return PluginWrapper::getPreferredBlockSize();
cannam@227 278 }
cannam@227 279
cannam@227 280 void
cannam@227 281 PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
cannam@227 282 {
cannam@227 283 m_impl->setPluginStepSize(stepSize);
cannam@227 284 }
cannam@227 285
cannam@227 286 void
cannam@227 287 PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
cannam@227 288 {
cannam@227 289 m_impl->setPluginBlockSize(blockSize);
cannam@227 290 }
cannam@227 291
cannam@227 292 void
cannam@227 293 PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
cannam@227 294 size_t &blockSize)
cannam@227 295 {
cannam@227 296 m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
cannam@227 297 }
cannam@227 298
cannam@227 299 bool
cannam@227 300 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@227 301 {
cannam@227 302 return m_impl->initialise(channels, stepSize, blockSize);
cannam@227 303 }
cannam@227 304
cannam@227 305 PluginBufferingAdapter::OutputList
cannam@227 306 PluginBufferingAdapter::getOutputDescriptors() const
cannam@227 307 {
cannam@227 308 return m_impl->getOutputDescriptors();
cannam@227 309 }
cannam@227 310
cannam@227 311 void
cannam@227 312 PluginBufferingAdapter::reset()
cannam@227 313 {
cannam@227 314 m_impl->reset();
cannam@227 315 }
cannam@227 316
cannam@227 317 PluginBufferingAdapter::FeatureSet
cannam@227 318 PluginBufferingAdapter::process(const float *const *inputBuffers,
cannam@227 319 RealTime timestamp)
cannam@227 320 {
cannam@227 321 return m_impl->process(inputBuffers, timestamp);
cannam@227 322 }
cannam@227 323
cannam@227 324 PluginBufferingAdapter::FeatureSet
cannam@227 325 PluginBufferingAdapter::getRemainingFeatures()
cannam@227 326 {
cannam@227 327 return m_impl->getRemainingFeatures();
cannam@227 328 }
cannam@227 329
cannam@227 330 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
cannam@227 331 m_plugin(plugin),
cannam@227 332 m_inputStepSize(0),
cannam@227 333 m_inputBlockSize(0),
cannam@227 334 m_setStepSize(0),
cannam@227 335 m_setBlockSize(0),
cannam@227 336 m_stepSize(0),
cannam@227 337 m_blockSize(0),
cannam@227 338 m_channels(0),
cannam@227 339 m_queue(0),
cannam@227 340 m_buffers(0),
cannam@227 341 m_inputSampleRate(inputSampleRate),
cannam@227 342 m_frame(0),
cannam@227 343 m_unrun(true)
cannam@227 344 {
cannam@227 345 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
cannam@227 346 }
cannam@227 347
cannam@227 348 PluginBufferingAdapter::Impl::~Impl()
cannam@227 349 {
cannam@227 350 // the adapter will delete the plugin
cannam@227 351
cannam@227 352 for (size_t i = 0; i < m_channels; ++i) {
cannam@227 353 delete m_queue[i];
cannam@227 354 delete[] m_buffers[i];
cannam@227 355 }
cannam@227 356 delete[] m_buffers;
cannam@227 357 }
cannam@227 358
cannam@227 359 void
cannam@227 360 PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
cannam@227 361 {
cannam@227 362 if (m_inputStepSize != 0) {
cannam@227 363 std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
cannam@227 364 return;
cannam@227 365 }
cannam@227 366 m_setStepSize = stepSize;
cannam@227 367 }
cannam@227 368
cannam@227 369 void
cannam@227 370 PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
cannam@227 371 {
cannam@227 372 if (m_inputBlockSize != 0) {
cannam@227 373 std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
cannam@227 374 return;
cannam@227 375 }
cannam@227 376 m_setBlockSize = blockSize;
cannam@227 377 }
cannam@227 378
cannam@227 379 void
cannam@227 380 PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
cannam@227 381 size_t &blockSize)
cannam@227 382 {
cannam@227 383 stepSize = m_stepSize;
cannam@227 384 blockSize = m_blockSize;
cannam@227 385 }
cannam@227 386
cannam@227 387 bool
cannam@227 388 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@227 389 {
cannam@227 390 if (stepSize != blockSize) {
cannam@227 391 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
cannam@227 392 return false;
cannam@227 393 }
cannam@227 394
cannam@227 395 m_channels = channels;
cannam@227 396 m_inputStepSize = stepSize;
cannam@227 397 m_inputBlockSize = blockSize;
cannam@227 398
cannam@227 399 // if the user has requested particular step or block sizes, use
cannam@227 400 // those; otherwise use the step and block sizes which the plugin
cannam@227 401 // prefers
cannam@227 402
cannam@227 403 m_stepSize = 0;
cannam@227 404 m_blockSize = 0;
cannam@227 405
cannam@227 406 if (m_setStepSize > 0) {
cannam@227 407 m_stepSize = m_setStepSize;
cannam@227 408 }
cannam@227 409 if (m_setBlockSize > 0) {
cannam@227 410 m_blockSize = m_setBlockSize;
cannam@227 411 }
cannam@227 412
cannam@227 413 if (m_stepSize == 0 && m_blockSize == 0) {
cannam@227 414 m_stepSize = m_plugin->getPreferredStepSize();
cannam@227 415 m_blockSize = m_plugin->getPreferredBlockSize();
cannam@227 416 }
cannam@227 417
cannam@227 418 bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
cannam@227 419
cannam@227 420 // or sensible defaults if it has no preference
cannam@227 421 if (m_blockSize == 0) {
cannam@227 422 if (m_stepSize == 0) {
cannam@227 423 m_blockSize = 1024;
cannam@227 424 } else if (freq) {
cannam@227 425 m_blockSize = m_stepSize * 2;
cannam@227 426 } else {
cannam@227 427 m_blockSize = m_stepSize;
cannam@227 428 }
cannam@227 429 } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
cannam@227 430 if (freq) {
cannam@227 431 m_stepSize = m_blockSize/2;
cannam@227 432 } else {
cannam@227 433 m_stepSize = m_blockSize;
cannam@227 434 }
cannam@227 435 }
cannam@227 436
cannam@227 437 // current implementation breaks if step is greater than block
cannam@227 438 if (m_stepSize > m_blockSize) {
cannam@227 439 size_t newBlockSize;
cannam@227 440 if (freq) {
cannam@227 441 newBlockSize = m_stepSize * 2;
cannam@227 442 } else {
cannam@227 443 newBlockSize = m_stepSize;
cannam@227 444 }
cannam@227 445 std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl;
cannam@227 446 m_blockSize = newBlockSize;
cannam@227 447 }
cannam@227 448
cannam@227 449 std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
cannam@227 450 << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
cannam@227 451
cannam@227 452 m_buffers = new float *[m_channels];
cannam@227 453
cannam@227 454 for (size_t i = 0; i < m_channels; ++i) {
cannam@227 455 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
cannam@227 456 m_buffers[i] = new float[m_blockSize];
cannam@227 457 }
cannam@227 458
cannam@227 459 return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
cannam@227 460 }
cannam@227 461
cannam@227 462 PluginBufferingAdapter::OutputList
cannam@227 463 PluginBufferingAdapter::Impl::getOutputDescriptors() const
cannam@227 464 {
cannam@227 465 if (m_outputs.empty()) {
cannam@227 466 m_outputs = m_plugin->getOutputDescriptors();
cannam@227 467 }
cannam@227 468
cannam@227 469 PluginBufferingAdapter::OutputList outs = m_outputs;
cannam@227 470
cannam@227 471 for (size_t i = 0; i < outs.size(); ++i) {
cannam@227 472
cannam@227 473 switch (outs[i].sampleType) {
cannam@227 474
cannam@227 475 case OutputDescriptor::OneSamplePerStep:
cannam@227 476 outs[i].sampleType = OutputDescriptor::FixedSampleRate;
cannam@227 477 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
cannam@227 478 m_rewriteOutputTimes[i] = true;
cannam@227 479 break;
cannam@227 480
cannam@227 481 case OutputDescriptor::FixedSampleRate:
cannam@227 482 if (outs[i].sampleRate == 0.f) {
cannam@227 483 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
cannam@227 484 }
cannam@227 485 // We actually only need to rewrite output times for
cannam@227 486 // features that don't have timestamps already, but we
cannam@227 487 // can't tell from here whether our features will have
cannam@227 488 // timestamps or not
cannam@227 489 m_rewriteOutputTimes[i] = true;
cannam@227 490 break;
cannam@227 491
cannam@227 492 case OutputDescriptor::VariableSampleRate:
cannam@227 493 m_rewriteOutputTimes[i] = false;
cannam@227 494 break;
cannam@227 495 }
cannam@227 496 }
cannam@227 497
cannam@227 498 return outs;
cannam@227 499 }
cannam@227 500
cannam@227 501 void
cannam@227 502 PluginBufferingAdapter::Impl::reset()
cannam@227 503 {
cannam@227 504 m_frame = 0;
cannam@227 505 m_unrun = true;
cannam@227 506
cannam@227 507 for (size_t i = 0; i < m_queue.size(); ++i) {
cannam@227 508 m_queue[i]->reset();
cannam@227 509 }
cannam@227 510
cannam@227 511 m_plugin->reset();
cannam@227 512 }
cannam@227 513
cannam@227 514 PluginBufferingAdapter::FeatureSet
cannam@227 515 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
cannam@227 516 RealTime timestamp)
cannam@227 517 {
cannam@227 518 if (m_inputStepSize == 0) {
cannam@227 519 std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
cannam@227 520 return FeatureSet();
cannam@227 521 }
cannam@227 522
cannam@227 523 FeatureSet allFeatureSets;
cannam@227 524
cannam@227 525 if (m_unrun) {
cannam@227 526 m_frame = RealTime::realTime2Frame(timestamp,
cannam@227 527 int(m_inputSampleRate + 0.5));
cannam@227 528 m_unrun = false;
cannam@227 529 }
cannam@227 530
cannam@227 531 // queue the new input
cannam@227 532
cannam@227 533 for (size_t i = 0; i < m_channels; ++i) {
cannam@227 534 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
cannam@227 535 if (written < int(m_inputBlockSize) && i == 0) {
cannam@227 536 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
cannam@227 537 << "Buffer overflow: wrote " << written
cannam@227 538 << " of " << m_inputBlockSize
cannam@227 539 << " input samples (for plugin step size "
cannam@227 540 << m_stepSize << ", block size " << m_blockSize << ")"
cannam@227 541 << std::endl;
cannam@227 542 }
cannam@227 543 }
cannam@227 544
cannam@227 545 // process as much as we can
cannam@227 546
cannam@227 547 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
cannam@227 548 processBlock(allFeatureSets);
cannam@227 549 }
cannam@227 550
cannam@227 551 return allFeatureSets;
cannam@227 552 }
cannam@227 553
cannam@227 554 PluginBufferingAdapter::FeatureSet
cannam@227 555 PluginBufferingAdapter::Impl::getRemainingFeatures()
cannam@227 556 {
cannam@227 557 FeatureSet allFeatureSets;
cannam@227 558
cannam@227 559 // process remaining samples in queue
cannam@227 560 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
cannam@227 561 processBlock(allFeatureSets);
cannam@227 562 }
cannam@227 563
cannam@227 564 // pad any last samples remaining and process
cannam@227 565 if (m_queue[0]->getReadSpace() > 0) {
cannam@227 566 for (size_t i = 0; i < m_channels; ++i) {
cannam@227 567 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
cannam@227 568 }
cannam@227 569 processBlock(allFeatureSets);
cannam@227 570 }
cannam@227 571
cannam@227 572 // get remaining features
cannam@227 573
cannam@227 574 FeatureSet featureSet = m_plugin->getRemainingFeatures();
cannam@227 575
cannam@227 576 for (map<int, FeatureList>::iterator iter = featureSet.begin();
cannam@227 577 iter != featureSet.end(); ++iter) {
cannam@227 578 FeatureList featureList = iter->second;
cannam@227 579 for (size_t i = 0; i < featureList.size(); ++i) {
cannam@227 580 allFeatureSets[iter->first].push_back(featureList[i]);
cannam@227 581 }
cannam@227 582 }
cannam@227 583
cannam@227 584 return allFeatureSets;
cannam@227 585 }
cannam@227 586
cannam@227 587 void
cannam@227 588 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
cannam@227 589 {
cannam@227 590 for (size_t i = 0; i < m_channels; ++i) {
cannam@227 591 m_queue[i]->peek(m_buffers[i], m_blockSize);
cannam@227 592 }
cannam@227 593
cannam@227 594 long frame = m_frame;
cannam@227 595 RealTime timestamp = RealTime::frame2RealTime
cannam@227 596 (frame, int(m_inputSampleRate + 0.5));
cannam@227 597
cannam@227 598 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
cannam@227 599
cannam@227 600 for (FeatureSet::iterator iter = featureSet.begin();
cannam@227 601 iter != featureSet.end(); ++iter) {
cannam@227 602
cannam@227 603 int outputNo = iter->first;
cannam@227 604
cannam@227 605 if (m_rewriteOutputTimes[outputNo]) {
cannam@227 606
cannam@227 607 FeatureList featureList = iter->second;
cannam@227 608
cannam@227 609 for (size_t i = 0; i < featureList.size(); ++i) {
cannam@227 610
cannam@227 611 switch (m_outputs[outputNo].sampleType) {
cannam@227 612
cannam@227 613 case OutputDescriptor::OneSamplePerStep:
cannam@227 614 // use our internal timestamp, always
cannam@227 615 featureList[i].timestamp = timestamp;
cannam@227 616 featureList[i].hasTimestamp = true;
cannam@227 617 break;
cannam@227 618
cannam@227 619 case OutputDescriptor::FixedSampleRate:
cannam@227 620 // use our internal timestamp if feature lacks one
cannam@227 621 if (!featureList[i].hasTimestamp) {
cannam@227 622 featureList[i].timestamp = timestamp;
cannam@227 623 featureList[i].hasTimestamp = true;
cannam@227 624 }
cannam@227 625 break;
cannam@227 626
cannam@227 627 case OutputDescriptor::VariableSampleRate:
cannam@227 628 break; // plugin must set timestamp
cannam@227 629
cannam@227 630 default:
cannam@227 631 break;
cannam@227 632 }
cannam@227 633
cannam@227 634 allFeatureSets[outputNo].push_back(featureList[i]);
cannam@227 635 }
cannam@227 636 } else {
cannam@227 637 for (size_t i = 0; i < iter->second.size(); ++i) {
cannam@227 638 allFeatureSets[outputNo].push_back(iter->second[i]);
cannam@227 639 }
cannam@227 640 }
cannam@227 641 }
cannam@227 642
cannam@227 643 // step forward
cannam@227 644
cannam@227 645 for (size_t i = 0; i < m_channels; ++i) {
cannam@227 646 m_queue[i]->skip(m_stepSize);
cannam@227 647 }
cannam@227 648
cannam@227 649 // increment internal frame counter each time we step forward
cannam@227 650 m_frame += m_stepSize;
cannam@227 651 }
cannam@227 652
cannam@227 653 }
cannam@227 654
cannam@227 655 }
cannam@227 656
cannam@227 657