annotate vamp-sdk/hostext/PluginBufferingAdapter.cpp @ 225:f8b38a017d9a distinct-libraries

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