annotate src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 265:03c7167e1f30

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