annotate src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 415:1522e2f6d700

Fix handling of output sample rate in buffering adapter in case where SampleType is Fixed but no sample rate provided (which is invalid behaviour from the plugin, but we might as well do the right thing with it)
author Chris Cannam
date Fri, 04 Sep 2015 13:48:28 +0100
parents 656ce0eae135
children 35fa4733bc5d
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@290 9 Copyright 2006-2009 Chris Cannam and QMUL.
cannam@290 10 This file by Mark Levy and Chris Cannam, Copyright 2007-2009 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
Chris@415 44 #include <iostream>
Chris@415 45 using std::cerr;
Chris@415 46 using std::endl;
Chris@415 47
cannam@233 48 using std::vector;
cannam@233 49 using std::map;
cannam@233 50
cannam@263 51 _VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.cpp)
cannam@263 52
cannam@233 53 namespace Vamp {
cannam@233 54
cannam@233 55 namespace HostExt {
cannam@233 56
cannam@233 57 class PluginBufferingAdapter::Impl
cannam@233 58 {
cannam@233 59 public:
cannam@233 60 Impl(Plugin *plugin, float inputSampleRate);
cannam@233 61 ~Impl();
cannam@233 62
cannam@233 63 void setPluginStepSize(size_t stepSize);
cannam@233 64 void setPluginBlockSize(size_t blockSize);
cannam@233 65
cannam@233 66 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
cannam@233 67
cannam@233 68 void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
cannam@233 69
cannam@233 70 OutputList getOutputDescriptors() const;
cannam@233 71
cannam@267 72 void setParameter(std::string, float);
cannam@267 73 void selectProgram(std::string);
cannam@267 74
cannam@233 75 void reset();
cannam@233 76
cannam@233 77 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
cannam@233 78
cannam@233 79 FeatureSet getRemainingFeatures();
cannam@233 80
cannam@233 81 protected:
cannam@233 82 class RingBuffer
cannam@233 83 {
cannam@233 84 public:
cannam@233 85 RingBuffer(int n) :
cannam@233 86 m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
cannam@233 87 virtual ~RingBuffer() { delete[] m_buffer; }
cannam@233 88
cannam@233 89 int getSize() const { return m_size-1; }
cannam@233 90 void reset() { m_writer = 0; m_reader = 0; }
cannam@233 91
cannam@233 92 int getReadSpace() const {
cannam@233 93 int writer = m_writer, reader = m_reader, space;
cannam@233 94 if (writer > reader) space = writer - reader;
cannam@233 95 else if (writer < reader) space = (writer + m_size) - reader;
cannam@233 96 else space = 0;
cannam@233 97 return space;
cannam@233 98 }
cannam@233 99
cannam@233 100 int getWriteSpace() const {
cannam@233 101 int writer = m_writer;
cannam@233 102 int reader = m_reader;
cannam@233 103 int space = (reader + m_size - writer - 1);
cannam@233 104 if (space >= m_size) space -= m_size;
cannam@233 105 return space;
cannam@233 106 }
cannam@233 107
cannam@233 108 int peek(float *destination, int n) const {
cannam@233 109
cannam@233 110 int available = getReadSpace();
cannam@233 111
cannam@233 112 if (n > available) {
cannam@233 113 for (int i = available; i < n; ++i) {
cannam@233 114 destination[i] = 0.f;
cannam@233 115 }
cannam@233 116 n = available;
cannam@233 117 }
cannam@233 118 if (n == 0) return n;
cannam@233 119
cannam@233 120 int reader = m_reader;
cannam@233 121 int here = m_size - reader;
cannam@233 122 const float *const bufbase = m_buffer + reader;
cannam@233 123
cannam@233 124 if (here >= n) {
cannam@233 125 for (int i = 0; i < n; ++i) {
cannam@233 126 destination[i] = bufbase[i];
cannam@233 127 }
cannam@233 128 } else {
cannam@233 129 for (int i = 0; i < here; ++i) {
cannam@233 130 destination[i] = bufbase[i];
cannam@233 131 }
cannam@233 132 float *const destbase = destination + here;
cannam@233 133 const int nh = n - here;
cannam@233 134 for (int i = 0; i < nh; ++i) {
cannam@233 135 destbase[i] = m_buffer[i];
cannam@233 136 }
cannam@233 137 }
cannam@233 138
cannam@233 139 return n;
cannam@233 140 }
cannam@233 141
cannam@233 142 int skip(int n) {
cannam@233 143
cannam@233 144 int available = getReadSpace();
cannam@233 145 if (n > available) {
cannam@233 146 n = available;
cannam@233 147 }
cannam@233 148 if (n == 0) return n;
cannam@233 149
cannam@233 150 int reader = m_reader;
cannam@233 151 reader += n;
cannam@233 152 while (reader >= m_size) reader -= m_size;
cannam@233 153 m_reader = reader;
cannam@233 154 return n;
cannam@233 155 }
cannam@233 156
cannam@233 157 int write(const float *source, int n) {
cannam@233 158
cannam@233 159 int available = getWriteSpace();
cannam@233 160 if (n > available) {
cannam@233 161 n = available;
cannam@233 162 }
cannam@233 163 if (n == 0) return n;
cannam@233 164
cannam@233 165 int writer = m_writer;
cannam@233 166 int here = m_size - writer;
cannam@233 167 float *const bufbase = m_buffer + writer;
cannam@233 168
cannam@233 169 if (here >= n) {
cannam@233 170 for (int i = 0; i < n; ++i) {
cannam@233 171 bufbase[i] = source[i];
cannam@233 172 }
cannam@233 173 } else {
cannam@233 174 for (int i = 0; i < here; ++i) {
cannam@233 175 bufbase[i] = source[i];
cannam@233 176 }
cannam@233 177 const int nh = n - here;
cannam@233 178 const float *const srcbase = source + here;
cannam@233 179 float *const buf = m_buffer;
cannam@233 180 for (int i = 0; i < nh; ++i) {
cannam@233 181 buf[i] = srcbase[i];
cannam@233 182 }
cannam@233 183 }
cannam@233 184
cannam@233 185 writer += n;
cannam@233 186 while (writer >= m_size) writer -= m_size;
cannam@233 187 m_writer = writer;
cannam@233 188
cannam@233 189 return n;
cannam@233 190 }
cannam@233 191
cannam@233 192 int zero(int n) {
cannam@233 193
cannam@233 194 int available = getWriteSpace();
cannam@233 195 if (n > available) {
cannam@233 196 n = available;
cannam@233 197 }
cannam@233 198 if (n == 0) return n;
cannam@233 199
cannam@233 200 int writer = m_writer;
cannam@233 201 int here = m_size - writer;
cannam@233 202 float *const bufbase = m_buffer + writer;
cannam@233 203
cannam@233 204 if (here >= n) {
cannam@233 205 for (int i = 0; i < n; ++i) {
cannam@233 206 bufbase[i] = 0.f;
cannam@233 207 }
cannam@233 208 } else {
cannam@233 209 for (int i = 0; i < here; ++i) {
cannam@233 210 bufbase[i] = 0.f;
cannam@233 211 }
cannam@233 212 const int nh = n - here;
cannam@233 213 for (int i = 0; i < nh; ++i) {
cannam@233 214 m_buffer[i] = 0.f;
cannam@233 215 }
cannam@233 216 }
cannam@233 217
cannam@233 218 writer += n;
cannam@233 219 while (writer >= m_size) writer -= m_size;
cannam@233 220 m_writer = writer;
cannam@233 221
cannam@233 222 return n;
cannam@233 223 }
cannam@233 224
cannam@233 225 protected:
cannam@233 226 float *m_buffer;
cannam@233 227 int m_writer;
cannam@233 228 int m_reader;
cannam@233 229 int m_size;
cannam@233 230
cannam@233 231 private:
cannam@233 232 RingBuffer(const RingBuffer &); // not provided
cannam@233 233 RingBuffer &operator=(const RingBuffer &); // not provided
cannam@233 234 };
cannam@233 235
cannam@233 236 Plugin *m_plugin;
cannam@233 237 size_t m_inputStepSize; // value passed to wrapper initialise()
cannam@233 238 size_t m_inputBlockSize; // value passed to wrapper initialise()
cannam@233 239 size_t m_setStepSize; // value passed to setPluginStepSize()
cannam@233 240 size_t m_setBlockSize; // value passed to setPluginBlockSize()
cannam@233 241 size_t m_stepSize; // value actually used to initialise plugin
cannam@233 242 size_t m_blockSize; // value actually used to initialise plugin
cannam@233 243 size_t m_channels;
cannam@233 244 vector<RingBuffer *> m_queue;
cannam@233 245 float **m_buffers;
cannam@233 246 float m_inputSampleRate;
cannam@233 247 long m_frame;
cannam@233 248 bool m_unrun;
cannam@233 249 mutable OutputList m_outputs;
cannam@233 250 mutable std::map<int, bool> m_rewriteOutputTimes;
Chris@348 251 std::map<int, int> m_fixedRateFeatureNos; // output no -> feature no
cannam@233 252
cannam@233 253 void processBlock(FeatureSet& allFeatureSets);
Chris@348 254 void adjustFixedRateFeatureTime(int outputNo, Feature &);
cannam@233 255 };
cannam@233 256
cannam@233 257 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
cannam@233 258 PluginWrapper(plugin)
cannam@233 259 {
cannam@233 260 m_impl = new Impl(plugin, m_inputSampleRate);
cannam@233 261 }
cannam@233 262
cannam@233 263 PluginBufferingAdapter::~PluginBufferingAdapter()
cannam@233 264 {
cannam@233 265 delete m_impl;
cannam@233 266 }
cannam@233 267
cannam@233 268 size_t
cannam@233 269 PluginBufferingAdapter::getPreferredStepSize() const
cannam@233 270 {
cannam@233 271 return getPreferredBlockSize();
cannam@233 272 }
cannam@233 273
cannam@233 274 size_t
cannam@233 275 PluginBufferingAdapter::getPreferredBlockSize() const
cannam@233 276 {
cannam@233 277 return PluginWrapper::getPreferredBlockSize();
cannam@233 278 }
cannam@233 279
cannam@233 280 size_t
cannam@233 281 PluginBufferingAdapter::getPluginPreferredStepSize() const
cannam@233 282 {
cannam@233 283 return PluginWrapper::getPreferredStepSize();
cannam@233 284 }
cannam@233 285
cannam@233 286 size_t
cannam@233 287 PluginBufferingAdapter::getPluginPreferredBlockSize() const
cannam@233 288 {
cannam@233 289 return PluginWrapper::getPreferredBlockSize();
cannam@233 290 }
cannam@233 291
cannam@233 292 void
cannam@233 293 PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
cannam@233 294 {
cannam@233 295 m_impl->setPluginStepSize(stepSize);
cannam@233 296 }
cannam@233 297
cannam@233 298 void
cannam@233 299 PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
cannam@233 300 {
cannam@233 301 m_impl->setPluginBlockSize(blockSize);
cannam@233 302 }
cannam@233 303
cannam@233 304 void
cannam@233 305 PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
cannam@233 306 size_t &blockSize)
cannam@233 307 {
cannam@233 308 m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
cannam@233 309 }
cannam@233 310
cannam@233 311 bool
cannam@233 312 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 313 {
cannam@233 314 return m_impl->initialise(channels, stepSize, blockSize);
cannam@233 315 }
cannam@233 316
cannam@233 317 PluginBufferingAdapter::OutputList
cannam@233 318 PluginBufferingAdapter::getOutputDescriptors() const
cannam@233 319 {
cannam@233 320 return m_impl->getOutputDescriptors();
cannam@233 321 }
cannam@233 322
cannam@233 323 void
cannam@267 324 PluginBufferingAdapter::setParameter(std::string name, float value)
cannam@267 325 {
cannam@267 326 m_impl->setParameter(name, value);
cannam@267 327 }
cannam@267 328
cannam@267 329 void
cannam@267 330 PluginBufferingAdapter::selectProgram(std::string name)
cannam@267 331 {
cannam@267 332 m_impl->selectProgram(name);
cannam@267 333 }
cannam@267 334
cannam@267 335 void
cannam@233 336 PluginBufferingAdapter::reset()
cannam@233 337 {
cannam@233 338 m_impl->reset();
cannam@233 339 }
cannam@233 340
cannam@233 341 PluginBufferingAdapter::FeatureSet
cannam@233 342 PluginBufferingAdapter::process(const float *const *inputBuffers,
cannam@233 343 RealTime timestamp)
cannam@233 344 {
cannam@233 345 return m_impl->process(inputBuffers, timestamp);
cannam@233 346 }
cannam@233 347
cannam@233 348 PluginBufferingAdapter::FeatureSet
cannam@233 349 PluginBufferingAdapter::getRemainingFeatures()
cannam@233 350 {
cannam@233 351 return m_impl->getRemainingFeatures();
cannam@233 352 }
cannam@233 353
cannam@233 354 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
cannam@233 355 m_plugin(plugin),
cannam@233 356 m_inputStepSize(0),
cannam@233 357 m_inputBlockSize(0),
cannam@233 358 m_setStepSize(0),
cannam@233 359 m_setBlockSize(0),
cannam@233 360 m_stepSize(0),
cannam@233 361 m_blockSize(0),
cannam@233 362 m_channels(0),
cannam@233 363 m_queue(0),
cannam@233 364 m_buffers(0),
cannam@233 365 m_inputSampleRate(inputSampleRate),
cannam@233 366 m_frame(0),
cannam@233 367 m_unrun(true)
cannam@233 368 {
cannam@233 369 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
cannam@233 370 }
cannam@233 371
cannam@233 372 PluginBufferingAdapter::Impl::~Impl()
cannam@233 373 {
cannam@233 374 // the adapter will delete the plugin
cannam@233 375
cannam@233 376 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 377 delete m_queue[i];
cannam@233 378 delete[] m_buffers[i];
cannam@233 379 }
cannam@233 380 delete[] m_buffers;
cannam@233 381 }
cannam@233 382
cannam@233 383 void
cannam@233 384 PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
cannam@233 385 {
cannam@233 386 if (m_inputStepSize != 0) {
cannam@233 387 std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
cannam@233 388 return;
cannam@233 389 }
cannam@233 390 m_setStepSize = stepSize;
cannam@233 391 }
cannam@233 392
cannam@233 393 void
cannam@233 394 PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
cannam@233 395 {
cannam@233 396 if (m_inputBlockSize != 0) {
cannam@233 397 std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
cannam@233 398 return;
cannam@233 399 }
cannam@233 400 m_setBlockSize = blockSize;
cannam@233 401 }
cannam@233 402
cannam@233 403 void
cannam@233 404 PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
cannam@233 405 size_t &blockSize)
cannam@233 406 {
cannam@233 407 stepSize = m_stepSize;
cannam@233 408 blockSize = m_blockSize;
cannam@233 409 }
cannam@233 410
cannam@233 411 bool
cannam@233 412 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 413 {
cannam@233 414 if (stepSize != blockSize) {
cannam@233 415 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
cannam@233 416 return false;
cannam@233 417 }
cannam@233 418
cannam@233 419 m_channels = channels;
cannam@233 420 m_inputStepSize = stepSize;
cannam@233 421 m_inputBlockSize = blockSize;
cannam@233 422
cannam@233 423 // if the user has requested particular step or block sizes, use
cannam@233 424 // those; otherwise use the step and block sizes which the plugin
cannam@233 425 // prefers
cannam@233 426
cannam@233 427 m_stepSize = 0;
cannam@233 428 m_blockSize = 0;
cannam@233 429
cannam@233 430 if (m_setStepSize > 0) {
cannam@233 431 m_stepSize = m_setStepSize;
cannam@233 432 }
cannam@233 433 if (m_setBlockSize > 0) {
cannam@233 434 m_blockSize = m_setBlockSize;
cannam@233 435 }
cannam@233 436
cannam@233 437 if (m_stepSize == 0 && m_blockSize == 0) {
cannam@233 438 m_stepSize = m_plugin->getPreferredStepSize();
cannam@233 439 m_blockSize = m_plugin->getPreferredBlockSize();
cannam@233 440 }
cannam@233 441
cannam@233 442 bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
cannam@233 443
cannam@233 444 // or sensible defaults if it has no preference
cannam@233 445 if (m_blockSize == 0) {
cannam@233 446 if (m_stepSize == 0) {
cannam@233 447 m_blockSize = 1024;
cannam@269 448 if (freq) {
cannam@269 449 m_stepSize = m_blockSize / 2;
cannam@269 450 } else {
cannam@269 451 m_stepSize = m_blockSize;
cannam@269 452 }
cannam@233 453 } else if (freq) {
cannam@233 454 m_blockSize = m_stepSize * 2;
cannam@233 455 } else {
cannam@233 456 m_blockSize = m_stepSize;
cannam@233 457 }
cannam@233 458 } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
cannam@233 459 if (freq) {
cannam@233 460 m_stepSize = m_blockSize/2;
cannam@233 461 } else {
cannam@233 462 m_stepSize = m_blockSize;
cannam@233 463 }
cannam@233 464 }
cannam@233 465
cannam@233 466 // current implementation breaks if step is greater than block
cannam@233 467 if (m_stepSize > m_blockSize) {
cannam@233 468 size_t newBlockSize;
cannam@233 469 if (freq) {
cannam@233 470 newBlockSize = m_stepSize * 2;
cannam@233 471 } else {
cannam@233 472 newBlockSize = m_stepSize;
cannam@233 473 }
cannam@233 474 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 475 m_blockSize = newBlockSize;
cannam@233 476 }
cannam@233 477
cannam@282 478 // std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
cannam@282 479 // << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
cannam@233 480
cannam@233 481 m_buffers = new float *[m_channels];
cannam@233 482
cannam@233 483 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 484 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
cannam@233 485 m_buffers[i] = new float[m_blockSize];
cannam@233 486 }
cannam@233 487
cannam@267 488 bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
cannam@267 489
cannam@269 490 // std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl;
cannam@268 491
cannam@267 492 if (success) {
cannam@267 493 // Re-query outputs; properties such as bin count may have
cannam@267 494 // changed on initialise
cannam@267 495 m_outputs.clear();
cannam@267 496 (void)getOutputDescriptors();
cannam@267 497 }
cannam@267 498
cannam@267 499 return success;
cannam@233 500 }
cannam@233 501
cannam@233 502 PluginBufferingAdapter::OutputList
cannam@233 503 PluginBufferingAdapter::Impl::getOutputDescriptors() const
cannam@233 504 {
cannam@233 505 if (m_outputs.empty()) {
cannam@269 506 // std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl;
cannam@268 507
cannam@233 508 m_outputs = m_plugin->getOutputDescriptors();
cannam@233 509 }
cannam@233 510
cannam@233 511 PluginBufferingAdapter::OutputList outs = m_outputs;
cannam@233 512
cannam@233 513 for (size_t i = 0; i < outs.size(); ++i) {
cannam@233 514
cannam@233 515 switch (outs[i].sampleType) {
cannam@233 516
cannam@233 517 case OutputDescriptor::OneSamplePerStep:
cannam@233 518 outs[i].sampleType = OutputDescriptor::FixedSampleRate;
Chris@415 519 outs[i].sampleRate = m_inputSampleRate / m_stepSize;
cannam@233 520 m_rewriteOutputTimes[i] = true;
cannam@233 521 break;
cannam@233 522
cannam@233 523 case OutputDescriptor::FixedSampleRate:
cannam@233 524 if (outs[i].sampleRate == 0.f) {
Chris@415 525 outs[i].sampleRate = m_inputSampleRate / m_stepSize;
cannam@233 526 }
cannam@233 527 // We actually only need to rewrite output times for
cannam@233 528 // features that don't have timestamps already, but we
cannam@233 529 // can't tell from here whether our features will have
cannam@233 530 // timestamps or not
cannam@233 531 m_rewriteOutputTimes[i] = true;
cannam@233 532 break;
cannam@233 533
cannam@233 534 case OutputDescriptor::VariableSampleRate:
cannam@233 535 m_rewriteOutputTimes[i] = false;
cannam@233 536 break;
cannam@233 537 }
cannam@233 538 }
cannam@233 539
cannam@233 540 return outs;
cannam@233 541 }
cannam@233 542
cannam@233 543 void
cannam@267 544 PluginBufferingAdapter::Impl::setParameter(std::string name, float value)
cannam@267 545 {
cannam@267 546 m_plugin->setParameter(name, value);
cannam@267 547
cannam@267 548 // Re-query outputs; properties such as bin count may have changed
cannam@267 549 m_outputs.clear();
cannam@267 550 (void)getOutputDescriptors();
cannam@267 551 }
cannam@267 552
cannam@267 553 void
cannam@267 554 PluginBufferingAdapter::Impl::selectProgram(std::string name)
cannam@267 555 {
cannam@267 556 m_plugin->selectProgram(name);
cannam@267 557
cannam@267 558 // Re-query outputs; properties such as bin count may have changed
cannam@267 559 m_outputs.clear();
cannam@267 560 (void)getOutputDescriptors();
cannam@267 561 }
cannam@267 562
cannam@267 563 void
cannam@233 564 PluginBufferingAdapter::Impl::reset()
cannam@233 565 {
cannam@233 566 m_frame = 0;
cannam@233 567 m_unrun = true;
cannam@233 568
cannam@233 569 for (size_t i = 0; i < m_queue.size(); ++i) {
cannam@233 570 m_queue[i]->reset();
cannam@233 571 }
cannam@233 572
Chris@382 573 m_fixedRateFeatureNos.clear();
Chris@382 574
cannam@233 575 m_plugin->reset();
cannam@233 576 }
cannam@233 577
cannam@233 578 PluginBufferingAdapter::FeatureSet
cannam@233 579 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
cannam@233 580 RealTime timestamp)
cannam@233 581 {
cannam@233 582 if (m_inputStepSize == 0) {
cannam@233 583 std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
cannam@233 584 return FeatureSet();
cannam@233 585 }
cannam@233 586
cannam@233 587 FeatureSet allFeatureSets;
cannam@233 588
cannam@233 589 if (m_unrun) {
cannam@233 590 m_frame = RealTime::realTime2Frame(timestamp,
cannam@233 591 int(m_inputSampleRate + 0.5));
cannam@233 592 m_unrun = false;
cannam@233 593 }
cannam@233 594
cannam@233 595 // queue the new input
cannam@233 596
cannam@233 597 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 598 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
cannam@233 599 if (written < int(m_inputBlockSize) && i == 0) {
cannam@233 600 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
cannam@233 601 << "Buffer overflow: wrote " << written
cannam@233 602 << " of " << m_inputBlockSize
cannam@233 603 << " input samples (for plugin step size "
cannam@233 604 << m_stepSize << ", block size " << m_blockSize << ")"
cannam@233 605 << std::endl;
cannam@233 606 }
cannam@233 607 }
cannam@233 608
cannam@233 609 // process as much as we can
cannam@233 610
cannam@233 611 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
cannam@233 612 processBlock(allFeatureSets);
cannam@233 613 }
cannam@233 614
cannam@233 615 return allFeatureSets;
cannam@233 616 }
cannam@233 617
Chris@348 618 void
Chris@348 619 PluginBufferingAdapter::Impl::adjustFixedRateFeatureTime(int outputNo,
Chris@348 620 Feature &feature)
Chris@348 621 {
Chris@415 622 // cerr << "adjustFixedRateFeatureTime: from " << feature.timestamp;
Chris@415 623
Chris@415 624 double rate = m_outputs[outputNo].sampleRate;
Chris@415 625 if (rate == 0.0) {
Chris@415 626 rate = m_inputSampleRate / m_stepSize;
Chris@415 627 }
Chris@415 628
Chris@348 629 if (feature.hasTimestamp) {
Chris@348 630 double secs = feature.timestamp.sec;
Chris@348 631 secs += feature.timestamp.nsec / 1e9;
Chris@415 632 m_fixedRateFeatureNos[outputNo] = int(secs * rate + 0.5);
Chris@415 633 // cerr << " [secs = " << secs << ", no = " << m_fixedRateFeatureNos[outputNo] << "]";
Chris@348 634 }
Chris@348 635
Chris@348 636 feature.timestamp = RealTime::fromSeconds
Chris@415 637 (m_fixedRateFeatureNos[outputNo] / rate);
Chris@348 638
Chris@415 639 // cerr << " to " << feature.timestamp << " (rate = " << rate << ", hasTimestamp = " << feature.hasTimestamp << ")" << endl;
Chris@415 640
Chris@348 641 feature.hasTimestamp = true;
Chris@348 642
Chris@348 643 m_fixedRateFeatureNos[outputNo] = m_fixedRateFeatureNos[outputNo] + 1;
Chris@348 644 }
Chris@348 645
cannam@233 646 PluginBufferingAdapter::FeatureSet
cannam@233 647 PluginBufferingAdapter::Impl::getRemainingFeatures()
cannam@233 648 {
cannam@233 649 FeatureSet allFeatureSets;
cannam@233 650
cannam@233 651 // process remaining samples in queue
cannam@233 652 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
cannam@233 653 processBlock(allFeatureSets);
cannam@233 654 }
cannam@233 655
cannam@233 656 // pad any last samples remaining and process
cannam@233 657 if (m_queue[0]->getReadSpace() > 0) {
cannam@233 658 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 659 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
cannam@233 660 }
cannam@233 661 processBlock(allFeatureSets);
cannam@233 662 }
cannam@233 663
cannam@233 664 // get remaining features
cannam@233 665
cannam@233 666 FeatureSet featureSet = m_plugin->getRemainingFeatures();
cannam@233 667
cannam@233 668 for (map<int, FeatureList>::iterator iter = featureSet.begin();
cannam@233 669 iter != featureSet.end(); ++iter) {
Chris@348 670
Chris@348 671 int outputNo = iter->first;
cannam@233 672 FeatureList featureList = iter->second;
Chris@348 673
cannam@233 674 for (size_t i = 0; i < featureList.size(); ++i) {
Chris@348 675
Chris@348 676 if (m_outputs[outputNo].sampleType ==
Chris@348 677 OutputDescriptor::FixedSampleRate) {
Chris@348 678 adjustFixedRateFeatureTime(outputNo, featureList[i]);
Chris@348 679 }
Chris@348 680
Chris@348 681 allFeatureSets[outputNo].push_back(featureList[i]);
cannam@233 682 }
cannam@233 683 }
cannam@233 684
cannam@233 685 return allFeatureSets;
cannam@233 686 }
cannam@233 687
cannam@233 688 void
cannam@233 689 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
cannam@233 690 {
cannam@233 691 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 692 m_queue[i]->peek(m_buffers[i], m_blockSize);
cannam@233 693 }
cannam@233 694
cannam@233 695 long frame = m_frame;
cannam@233 696 RealTime timestamp = RealTime::frame2RealTime
cannam@233 697 (frame, int(m_inputSampleRate + 0.5));
cannam@233 698
cannam@233 699 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
cannam@233 700
cannam@287 701 PluginWrapper *wrapper = dynamic_cast<PluginWrapper *>(m_plugin);
cannam@287 702 RealTime adjustment;
cannam@287 703 if (wrapper) {
cannam@287 704 PluginInputDomainAdapter *ida =
cannam@287 705 wrapper->getWrapper<PluginInputDomainAdapter>();
cannam@287 706 if (ida) adjustment = ida->getTimestampAdjustment();
cannam@287 707 }
cannam@287 708
cannam@233 709 for (FeatureSet::iterator iter = featureSet.begin();
cannam@233 710 iter != featureSet.end(); ++iter) {
cannam@233 711
cannam@233 712 int outputNo = iter->first;
cannam@233 713
cannam@233 714 if (m_rewriteOutputTimes[outputNo]) {
cannam@233 715
cannam@233 716 FeatureList featureList = iter->second;
cannam@233 717
cannam@233 718 for (size_t i = 0; i < featureList.size(); ++i) {
cannam@233 719
cannam@233 720 switch (m_outputs[outputNo].sampleType) {
cannam@233 721
cannam@233 722 case OutputDescriptor::OneSamplePerStep:
cannam@233 723 // use our internal timestamp, always
cannam@287 724 featureList[i].timestamp = timestamp + adjustment;
cannam@233 725 featureList[i].hasTimestamp = true;
cannam@233 726 break;
cannam@233 727
cannam@233 728 case OutputDescriptor::FixedSampleRate:
Chris@348 729 adjustFixedRateFeatureTime(outputNo, featureList[i]);
cannam@233 730 break;
cannam@233 731
cannam@233 732 case OutputDescriptor::VariableSampleRate:
Chris@348 733 // plugin must set timestamp
Chris@348 734 break;
cannam@233 735
cannam@233 736 default:
cannam@233 737 break;
cannam@233 738 }
cannam@233 739
cannam@233 740 allFeatureSets[outputNo].push_back(featureList[i]);
cannam@233 741 }
cannam@233 742 } else {
cannam@233 743 for (size_t i = 0; i < iter->second.size(); ++i) {
cannam@233 744 allFeatureSets[outputNo].push_back(iter->second[i]);
cannam@233 745 }
cannam@233 746 }
cannam@233 747 }
cannam@233 748
cannam@233 749 // step forward
cannam@233 750
cannam@233 751 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 752 m_queue[i]->skip(m_stepSize);
cannam@233 753 }
cannam@233 754
cannam@233 755 // increment internal frame counter each time we step forward
cannam@233 756 m_frame += m_stepSize;
cannam@233 757 }
cannam@233 758
cannam@233 759 }
cannam@233 760
cannam@233 761 }
cannam@233 762
cannam@263 763 _VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.cpp)