annotate vamp-sdk/hostext/PluginBufferingAdapter.cpp @ 211:caa9d07bb9bd

* Update VC project file to handle proper export of plugin lookup function, and use the right dll name to match the other platforms and the .cat file
author cannam
date Sat, 18 Oct 2008 16:51:51 +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