annotate src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 354:e85513153c71

Initialise rate to 0. Otherwise there's a danger plugins will change the SampleType (e.g. to VariableSampleRate) but not set the rate because they don't think they need it (when in fact it needs to be set to 0)
author Chris Cannam
date Thu, 28 Mar 2013 15:49:17 +0000
parents bd9a63d35e71
children 656ce0eae135
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
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;
Chris@348 247 std::map<int, int> m_fixedRateFeatureNos; // output no -> feature no
cannam@233 248
cannam@233 249 void processBlock(FeatureSet& allFeatureSets);
Chris@348 250 void adjustFixedRateFeatureTime(int outputNo, Feature &);
cannam@233 251 };
cannam@233 252
cannam@233 253 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
cannam@233 254 PluginWrapper(plugin)
cannam@233 255 {
cannam@233 256 m_impl = new Impl(plugin, m_inputSampleRate);
cannam@233 257 }
cannam@233 258
cannam@233 259 PluginBufferingAdapter::~PluginBufferingAdapter()
cannam@233 260 {
cannam@233 261 delete m_impl;
cannam@233 262 }
cannam@233 263
cannam@233 264 size_t
cannam@233 265 PluginBufferingAdapter::getPreferredStepSize() const
cannam@233 266 {
cannam@233 267 return getPreferredBlockSize();
cannam@233 268 }
cannam@233 269
cannam@233 270 size_t
cannam@233 271 PluginBufferingAdapter::getPreferredBlockSize() const
cannam@233 272 {
cannam@233 273 return PluginWrapper::getPreferredBlockSize();
cannam@233 274 }
cannam@233 275
cannam@233 276 size_t
cannam@233 277 PluginBufferingAdapter::getPluginPreferredStepSize() const
cannam@233 278 {
cannam@233 279 return PluginWrapper::getPreferredStepSize();
cannam@233 280 }
cannam@233 281
cannam@233 282 size_t
cannam@233 283 PluginBufferingAdapter::getPluginPreferredBlockSize() const
cannam@233 284 {
cannam@233 285 return PluginWrapper::getPreferredBlockSize();
cannam@233 286 }
cannam@233 287
cannam@233 288 void
cannam@233 289 PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
cannam@233 290 {
cannam@233 291 m_impl->setPluginStepSize(stepSize);
cannam@233 292 }
cannam@233 293
cannam@233 294 void
cannam@233 295 PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
cannam@233 296 {
cannam@233 297 m_impl->setPluginBlockSize(blockSize);
cannam@233 298 }
cannam@233 299
cannam@233 300 void
cannam@233 301 PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
cannam@233 302 size_t &blockSize)
cannam@233 303 {
cannam@233 304 m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
cannam@233 305 }
cannam@233 306
cannam@233 307 bool
cannam@233 308 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 309 {
cannam@233 310 return m_impl->initialise(channels, stepSize, blockSize);
cannam@233 311 }
cannam@233 312
cannam@233 313 PluginBufferingAdapter::OutputList
cannam@233 314 PluginBufferingAdapter::getOutputDescriptors() const
cannam@233 315 {
cannam@233 316 return m_impl->getOutputDescriptors();
cannam@233 317 }
cannam@233 318
cannam@233 319 void
cannam@267 320 PluginBufferingAdapter::setParameter(std::string name, float value)
cannam@267 321 {
cannam@267 322 m_impl->setParameter(name, value);
cannam@267 323 }
cannam@267 324
cannam@267 325 void
cannam@267 326 PluginBufferingAdapter::selectProgram(std::string name)
cannam@267 327 {
cannam@267 328 m_impl->selectProgram(name);
cannam@267 329 }
cannam@267 330
cannam@267 331 void
cannam@233 332 PluginBufferingAdapter::reset()
cannam@233 333 {
cannam@233 334 m_impl->reset();
cannam@233 335 }
cannam@233 336
cannam@233 337 PluginBufferingAdapter::FeatureSet
cannam@233 338 PluginBufferingAdapter::process(const float *const *inputBuffers,
cannam@233 339 RealTime timestamp)
cannam@233 340 {
cannam@233 341 return m_impl->process(inputBuffers, timestamp);
cannam@233 342 }
cannam@233 343
cannam@233 344 PluginBufferingAdapter::FeatureSet
cannam@233 345 PluginBufferingAdapter::getRemainingFeatures()
cannam@233 346 {
cannam@233 347 return m_impl->getRemainingFeatures();
cannam@233 348 }
cannam@233 349
cannam@233 350 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
cannam@233 351 m_plugin(plugin),
cannam@233 352 m_inputStepSize(0),
cannam@233 353 m_inputBlockSize(0),
cannam@233 354 m_setStepSize(0),
cannam@233 355 m_setBlockSize(0),
cannam@233 356 m_stepSize(0),
cannam@233 357 m_blockSize(0),
cannam@233 358 m_channels(0),
cannam@233 359 m_queue(0),
cannam@233 360 m_buffers(0),
cannam@233 361 m_inputSampleRate(inputSampleRate),
cannam@233 362 m_frame(0),
cannam@233 363 m_unrun(true)
cannam@233 364 {
cannam@233 365 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
cannam@233 366 }
cannam@233 367
cannam@233 368 PluginBufferingAdapter::Impl::~Impl()
cannam@233 369 {
cannam@233 370 // the adapter will delete the plugin
cannam@233 371
cannam@233 372 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 373 delete m_queue[i];
cannam@233 374 delete[] m_buffers[i];
cannam@233 375 }
cannam@233 376 delete[] m_buffers;
cannam@233 377 }
cannam@233 378
cannam@233 379 void
cannam@233 380 PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
cannam@233 381 {
cannam@233 382 if (m_inputStepSize != 0) {
cannam@233 383 std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
cannam@233 384 return;
cannam@233 385 }
cannam@233 386 m_setStepSize = stepSize;
cannam@233 387 }
cannam@233 388
cannam@233 389 void
cannam@233 390 PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
cannam@233 391 {
cannam@233 392 if (m_inputBlockSize != 0) {
cannam@233 393 std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
cannam@233 394 return;
cannam@233 395 }
cannam@233 396 m_setBlockSize = blockSize;
cannam@233 397 }
cannam@233 398
cannam@233 399 void
cannam@233 400 PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
cannam@233 401 size_t &blockSize)
cannam@233 402 {
cannam@233 403 stepSize = m_stepSize;
cannam@233 404 blockSize = m_blockSize;
cannam@233 405 }
cannam@233 406
cannam@233 407 bool
cannam@233 408 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@233 409 {
cannam@233 410 if (stepSize != blockSize) {
cannam@233 411 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
cannam@233 412 return false;
cannam@233 413 }
cannam@233 414
cannam@233 415 m_channels = channels;
cannam@233 416 m_inputStepSize = stepSize;
cannam@233 417 m_inputBlockSize = blockSize;
cannam@233 418
cannam@233 419 // if the user has requested particular step or block sizes, use
cannam@233 420 // those; otherwise use the step and block sizes which the plugin
cannam@233 421 // prefers
cannam@233 422
cannam@233 423 m_stepSize = 0;
cannam@233 424 m_blockSize = 0;
cannam@233 425
cannam@233 426 if (m_setStepSize > 0) {
cannam@233 427 m_stepSize = m_setStepSize;
cannam@233 428 }
cannam@233 429 if (m_setBlockSize > 0) {
cannam@233 430 m_blockSize = m_setBlockSize;
cannam@233 431 }
cannam@233 432
cannam@233 433 if (m_stepSize == 0 && m_blockSize == 0) {
cannam@233 434 m_stepSize = m_plugin->getPreferredStepSize();
cannam@233 435 m_blockSize = m_plugin->getPreferredBlockSize();
cannam@233 436 }
cannam@233 437
cannam@233 438 bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
cannam@233 439
cannam@233 440 // or sensible defaults if it has no preference
cannam@233 441 if (m_blockSize == 0) {
cannam@233 442 if (m_stepSize == 0) {
cannam@233 443 m_blockSize = 1024;
cannam@269 444 if (freq) {
cannam@269 445 m_stepSize = m_blockSize / 2;
cannam@269 446 } else {
cannam@269 447 m_stepSize = m_blockSize;
cannam@269 448 }
cannam@233 449 } else if (freq) {
cannam@233 450 m_blockSize = m_stepSize * 2;
cannam@233 451 } else {
cannam@233 452 m_blockSize = m_stepSize;
cannam@233 453 }
cannam@233 454 } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
cannam@233 455 if (freq) {
cannam@233 456 m_stepSize = m_blockSize/2;
cannam@233 457 } else {
cannam@233 458 m_stepSize = m_blockSize;
cannam@233 459 }
cannam@233 460 }
cannam@233 461
cannam@233 462 // current implementation breaks if step is greater than block
cannam@233 463 if (m_stepSize > m_blockSize) {
cannam@233 464 size_t newBlockSize;
cannam@233 465 if (freq) {
cannam@233 466 newBlockSize = m_stepSize * 2;
cannam@233 467 } else {
cannam@233 468 newBlockSize = m_stepSize;
cannam@233 469 }
cannam@233 470 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 471 m_blockSize = newBlockSize;
cannam@233 472 }
cannam@233 473
cannam@282 474 // std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
cannam@282 475 // << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
cannam@233 476
cannam@233 477 m_buffers = new float *[m_channels];
cannam@233 478
cannam@233 479 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 480 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
cannam@233 481 m_buffers[i] = new float[m_blockSize];
cannam@233 482 }
cannam@233 483
cannam@267 484 bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
cannam@267 485
cannam@269 486 // std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl;
cannam@268 487
cannam@267 488 if (success) {
cannam@267 489 // Re-query outputs; properties such as bin count may have
cannam@267 490 // changed on initialise
cannam@267 491 m_outputs.clear();
cannam@267 492 (void)getOutputDescriptors();
cannam@267 493 }
cannam@267 494
cannam@267 495 return success;
cannam@233 496 }
cannam@233 497
cannam@233 498 PluginBufferingAdapter::OutputList
cannam@233 499 PluginBufferingAdapter::Impl::getOutputDescriptors() const
cannam@233 500 {
cannam@233 501 if (m_outputs.empty()) {
cannam@269 502 // std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl;
cannam@268 503
cannam@233 504 m_outputs = m_plugin->getOutputDescriptors();
cannam@233 505 }
cannam@233 506
cannam@233 507 PluginBufferingAdapter::OutputList outs = m_outputs;
cannam@233 508
cannam@233 509 for (size_t i = 0; i < outs.size(); ++i) {
cannam@233 510
cannam@233 511 switch (outs[i].sampleType) {
cannam@233 512
cannam@233 513 case OutputDescriptor::OneSamplePerStep:
cannam@233 514 outs[i].sampleType = OutputDescriptor::FixedSampleRate;
cannam@233 515 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
cannam@233 516 m_rewriteOutputTimes[i] = true;
cannam@233 517 break;
cannam@233 518
cannam@233 519 case OutputDescriptor::FixedSampleRate:
cannam@233 520 if (outs[i].sampleRate == 0.f) {
cannam@233 521 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
cannam@233 522 }
cannam@233 523 // We actually only need to rewrite output times for
cannam@233 524 // features that don't have timestamps already, but we
cannam@233 525 // can't tell from here whether our features will have
cannam@233 526 // timestamps or not
cannam@233 527 m_rewriteOutputTimes[i] = true;
cannam@233 528 break;
cannam@233 529
cannam@233 530 case OutputDescriptor::VariableSampleRate:
cannam@233 531 m_rewriteOutputTimes[i] = false;
cannam@233 532 break;
cannam@233 533 }
cannam@233 534 }
cannam@233 535
cannam@233 536 return outs;
cannam@233 537 }
cannam@233 538
cannam@233 539 void
cannam@267 540 PluginBufferingAdapter::Impl::setParameter(std::string name, float value)
cannam@267 541 {
cannam@267 542 m_plugin->setParameter(name, value);
cannam@267 543
cannam@267 544 // Re-query outputs; properties such as bin count may have changed
cannam@267 545 m_outputs.clear();
cannam@267 546 (void)getOutputDescriptors();
cannam@267 547 }
cannam@267 548
cannam@267 549 void
cannam@267 550 PluginBufferingAdapter::Impl::selectProgram(std::string name)
cannam@267 551 {
cannam@267 552 m_plugin->selectProgram(name);
cannam@267 553
cannam@267 554 // Re-query outputs; properties such as bin count may have changed
cannam@267 555 m_outputs.clear();
cannam@267 556 (void)getOutputDescriptors();
cannam@267 557 }
cannam@267 558
cannam@267 559 void
cannam@233 560 PluginBufferingAdapter::Impl::reset()
cannam@233 561 {
cannam@233 562 m_frame = 0;
cannam@233 563 m_unrun = true;
cannam@233 564
cannam@233 565 for (size_t i = 0; i < m_queue.size(); ++i) {
cannam@233 566 m_queue[i]->reset();
cannam@233 567 }
cannam@233 568
cannam@233 569 m_plugin->reset();
cannam@233 570 }
cannam@233 571
cannam@233 572 PluginBufferingAdapter::FeatureSet
cannam@233 573 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
cannam@233 574 RealTime timestamp)
cannam@233 575 {
cannam@233 576 if (m_inputStepSize == 0) {
cannam@233 577 std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
cannam@233 578 return FeatureSet();
cannam@233 579 }
cannam@233 580
cannam@233 581 FeatureSet allFeatureSets;
cannam@233 582
cannam@233 583 if (m_unrun) {
cannam@233 584 m_frame = RealTime::realTime2Frame(timestamp,
cannam@233 585 int(m_inputSampleRate + 0.5));
cannam@233 586 m_unrun = false;
cannam@233 587 }
cannam@233 588
cannam@233 589 // queue the new input
cannam@233 590
cannam@233 591 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 592 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
cannam@233 593 if (written < int(m_inputBlockSize) && i == 0) {
cannam@233 594 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
cannam@233 595 << "Buffer overflow: wrote " << written
cannam@233 596 << " of " << m_inputBlockSize
cannam@233 597 << " input samples (for plugin step size "
cannam@233 598 << m_stepSize << ", block size " << m_blockSize << ")"
cannam@233 599 << std::endl;
cannam@233 600 }
cannam@233 601 }
cannam@233 602
cannam@233 603 // process as much as we can
cannam@233 604
cannam@233 605 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
cannam@233 606 processBlock(allFeatureSets);
cannam@233 607 }
cannam@233 608
cannam@233 609 return allFeatureSets;
cannam@233 610 }
cannam@233 611
Chris@348 612 void
Chris@348 613 PluginBufferingAdapter::Impl::adjustFixedRateFeatureTime(int outputNo,
Chris@348 614 Feature &feature)
Chris@348 615 {
Chris@348 616 if (feature.hasTimestamp) {
Chris@348 617 double secs = feature.timestamp.sec;
Chris@348 618 secs += feature.timestamp.nsec / 1e9;
Chris@348 619 m_fixedRateFeatureNos[outputNo] =
Chris@353 620 int(secs * double(m_outputs[outputNo].sampleRate) + 0.5);
Chris@348 621 }
Chris@348 622
Chris@348 623 feature.timestamp = RealTime::fromSeconds
Chris@353 624 (m_fixedRateFeatureNos[outputNo] / double(m_outputs[outputNo].sampleRate));
Chris@348 625
Chris@348 626 feature.hasTimestamp = true;
Chris@348 627
Chris@348 628 m_fixedRateFeatureNos[outputNo] = m_fixedRateFeatureNos[outputNo] + 1;
Chris@348 629 }
Chris@348 630
cannam@233 631 PluginBufferingAdapter::FeatureSet
cannam@233 632 PluginBufferingAdapter::Impl::getRemainingFeatures()
cannam@233 633 {
cannam@233 634 FeatureSet allFeatureSets;
cannam@233 635
cannam@233 636 // process remaining samples in queue
cannam@233 637 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
cannam@233 638 processBlock(allFeatureSets);
cannam@233 639 }
cannam@233 640
cannam@233 641 // pad any last samples remaining and process
cannam@233 642 if (m_queue[0]->getReadSpace() > 0) {
cannam@233 643 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 644 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
cannam@233 645 }
cannam@233 646 processBlock(allFeatureSets);
cannam@233 647 }
cannam@233 648
cannam@233 649 // get remaining features
cannam@233 650
cannam@233 651 FeatureSet featureSet = m_plugin->getRemainingFeatures();
cannam@233 652
cannam@233 653 for (map<int, FeatureList>::iterator iter = featureSet.begin();
cannam@233 654 iter != featureSet.end(); ++iter) {
Chris@348 655
Chris@348 656 int outputNo = iter->first;
cannam@233 657 FeatureList featureList = iter->second;
Chris@348 658
cannam@233 659 for (size_t i = 0; i < featureList.size(); ++i) {
Chris@348 660
Chris@348 661 if (m_outputs[outputNo].sampleType ==
Chris@348 662 OutputDescriptor::FixedSampleRate) {
Chris@348 663 adjustFixedRateFeatureTime(outputNo, featureList[i]);
Chris@348 664 }
Chris@348 665
Chris@348 666 allFeatureSets[outputNo].push_back(featureList[i]);
cannam@233 667 }
cannam@233 668 }
cannam@233 669
cannam@233 670 return allFeatureSets;
cannam@233 671 }
cannam@233 672
cannam@233 673 void
cannam@233 674 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
cannam@233 675 {
cannam@233 676 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 677 m_queue[i]->peek(m_buffers[i], m_blockSize);
cannam@233 678 }
cannam@233 679
cannam@233 680 long frame = m_frame;
cannam@233 681 RealTime timestamp = RealTime::frame2RealTime
cannam@233 682 (frame, int(m_inputSampleRate + 0.5));
cannam@233 683
cannam@233 684 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
cannam@233 685
cannam@287 686 PluginWrapper *wrapper = dynamic_cast<PluginWrapper *>(m_plugin);
cannam@287 687 RealTime adjustment;
cannam@287 688 if (wrapper) {
cannam@287 689 PluginInputDomainAdapter *ida =
cannam@287 690 wrapper->getWrapper<PluginInputDomainAdapter>();
cannam@287 691 if (ida) adjustment = ida->getTimestampAdjustment();
cannam@287 692 }
cannam@287 693
cannam@233 694 for (FeatureSet::iterator iter = featureSet.begin();
cannam@233 695 iter != featureSet.end(); ++iter) {
cannam@233 696
cannam@233 697 int outputNo = iter->first;
cannam@233 698
cannam@233 699 if (m_rewriteOutputTimes[outputNo]) {
cannam@233 700
cannam@233 701 FeatureList featureList = iter->second;
cannam@233 702
cannam@233 703 for (size_t i = 0; i < featureList.size(); ++i) {
cannam@233 704
cannam@233 705 switch (m_outputs[outputNo].sampleType) {
cannam@233 706
cannam@233 707 case OutputDescriptor::OneSamplePerStep:
cannam@233 708 // use our internal timestamp, always
cannam@287 709 featureList[i].timestamp = timestamp + adjustment;
cannam@233 710 featureList[i].hasTimestamp = true;
cannam@233 711 break;
cannam@233 712
cannam@233 713 case OutputDescriptor::FixedSampleRate:
Chris@348 714 adjustFixedRateFeatureTime(outputNo, featureList[i]);
cannam@233 715 break;
cannam@233 716
cannam@233 717 case OutputDescriptor::VariableSampleRate:
Chris@348 718 // plugin must set timestamp
Chris@348 719 break;
cannam@233 720
cannam@233 721 default:
cannam@233 722 break;
cannam@233 723 }
cannam@233 724
cannam@233 725 allFeatureSets[outputNo].push_back(featureList[i]);
cannam@233 726 }
cannam@233 727 } else {
cannam@233 728 for (size_t i = 0; i < iter->second.size(); ++i) {
cannam@233 729 allFeatureSets[outputNo].push_back(iter->second[i]);
cannam@233 730 }
cannam@233 731 }
cannam@233 732 }
cannam@233 733
cannam@233 734 // step forward
cannam@233 735
cannam@233 736 for (size_t i = 0; i < m_channels; ++i) {
cannam@233 737 m_queue[i]->skip(m_stepSize);
cannam@233 738 }
cannam@233 739
cannam@233 740 // increment internal frame counter each time we step forward
cannam@233 741 m_frame += m_stepSize;
cannam@233 742 }
cannam@233 743
cannam@233 744 }
cannam@233 745
cannam@233 746 }
cannam@233 747
cannam@263 748 _VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.cpp)