annotate src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 287:f3b1ba71a305

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