annotate src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 541:0e32c328b02a tip

Added tag vamp-plugin-sdk-v2.10 for changeset fa74c473e48c
author Chris Cannam
date Mon, 18 May 2020 11:53:49 +0100
parents 35fa4733bc5d
children
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) {
Chris@421 484 m_queue.push_back(new RingBuffer(int(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
Chris@421 513 for (int i = 0; i < int(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@421 519 outs[i].sampleRate = m_inputSampleRate / float(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@421 525 outs[i].sampleRate = m_inputSampleRate / float(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) {
Chris@421 598 int written = m_queue[i]->write(inputBuffers[i], int(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@421 626 rate = m_inputSampleRate / float(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) {
Chris@421 659 m_queue[i]->zero(int(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) {
Chris@421 692 m_queue[i]->peek(m_buffers[i], int(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) {
Chris@421 752 m_queue[i]->skip(int(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)