annotate src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 263:4454843ff384

* OK, we're going to have to place the host stuff in its own namespace too. Otherwise our new SV build on OSX fails to load old plugins because they pull in the host namespace PluginBase and thus report the wrong Vamp version... *sigh*
author cannam
date Thu, 20 Nov 2008 15:01:30 +0000
parents 521734d2b498
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)