annotate audio/AudioCallbackPlaySource.cpp @ 496:4f1d280903ad tony-2.0-integration

Update analysis stuff when recording starts (and when model is added) rather than when it ends. Not continuing to update during recording though...
author Chris Cannam
date Mon, 12 Oct 2015 17:10:43 +0100
parents 6ec35c1690c0
children cd9dec2f47e8
rev   line source
Chris@43 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@43 2
Chris@43 3 /*
Chris@43 4 Sonic Visualiser
Chris@43 5 An audio file viewer and annotation editor.
Chris@43 6 Centre for Digital Music, Queen Mary, University of London.
Chris@43 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@43 8
Chris@43 9 This program is free software; you can redistribute it and/or
Chris@43 10 modify it under the terms of the GNU General Public License as
Chris@43 11 published by the Free Software Foundation; either version 2 of the
Chris@43 12 License, or (at your option) any later version. See the file
Chris@43 13 COPYING included with this distribution for more information.
Chris@43 14 */
Chris@43 15
Chris@43 16 #include "AudioCallbackPlaySource.h"
Chris@43 17
Chris@43 18 #include "AudioGenerator.h"
Chris@43 19
Chris@43 20 #include "data/model/Model.h"
Chris@105 21 #include "base/ViewManagerBase.h"
Chris@43 22 #include "base/PlayParameterRepository.h"
Chris@43 23 #include "base/Preferences.h"
Chris@43 24 #include "data/model/DenseTimeValueModel.h"
Chris@43 25 #include "data/model/WaveFileModel.h"
Chris@43 26 #include "data/model/SparseOneDimensionalModel.h"
Chris@43 27 #include "plugin/RealTimePluginInstance.h"
Chris@62 28
Chris@468 29 #include "bqaudioio/SystemPlaybackTarget.h"
Chris@91 30
Chris@62 31 #include <rubberband/RubberBandStretcher.h>
Chris@62 32 using namespace RubberBand;
Chris@43 33
Chris@43 34 #include <iostream>
Chris@43 35 #include <cassert>
Chris@43 36
Chris@174 37 //#define DEBUG_AUDIO_PLAY_SOURCE 1
Chris@43 38 //#define DEBUG_AUDIO_PLAY_SOURCE_PLAYING 1
Chris@43 39
Chris@366 40 static const int DEFAULT_RING_BUFFER_SIZE = 131071;
Chris@43 41
Chris@105 42 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManagerBase *manager,
Chris@57 43 QString clientName) :
Chris@43 44 m_viewManager(manager),
Chris@43 45 m_audioGenerator(new AudioGenerator()),
Chris@468 46 m_clientName(clientName.toUtf8().data()),
Chris@43 47 m_readBuffers(0),
Chris@43 48 m_writeBuffers(0),
Chris@43 49 m_readBufferFill(0),
Chris@43 50 m_writeBufferFill(0),
Chris@43 51 m_bufferScavenger(1),
Chris@43 52 m_sourceChannelCount(0),
Chris@43 53 m_blockSize(1024),
Chris@43 54 m_sourceSampleRate(0),
Chris@43 55 m_targetSampleRate(0),
Chris@43 56 m_playLatency(0),
Chris@91 57 m_target(0),
Chris@91 58 m_lastRetrievalTimestamp(0.0),
Chris@91 59 m_lastRetrievedBlockSize(0),
Chris@102 60 m_trustworthyTimestamps(true),
Chris@102 61 m_lastCurrentFrame(0),
Chris@43 62 m_playing(false),
Chris@43 63 m_exiting(false),
Chris@43 64 m_lastModelEndFrame(0),
Chris@193 65 m_ringBufferSize(DEFAULT_RING_BUFFER_SIZE),
Chris@43 66 m_outputLeft(0.0),
Chris@43 67 m_outputRight(0.0),
Chris@43 68 m_auditioningPlugin(0),
Chris@43 69 m_auditioningPluginBypassed(false),
Chris@94 70 m_playStartFrame(0),
Chris@94 71 m_playStartFramePassed(false),
Chris@43 72 m_timeStretcher(0),
Chris@130 73 m_monoStretcher(0),
Chris@91 74 m_stretchRatio(1.0),
Chris@405 75 m_stretchMono(false),
Chris@91 76 m_stretcherInputCount(0),
Chris@91 77 m_stretcherInputs(0),
Chris@91 78 m_stretcherInputSizes(0),
Chris@43 79 m_fillThread(0),
Chris@43 80 m_converter(0),
Chris@43 81 m_crapConverter(0),
Chris@43 82 m_resampleQuality(Preferences::getInstance()->getResampleQuality())
Chris@43 83 {
Chris@43 84 m_viewManager->setAudioPlaySource(this);
Chris@43 85
Chris@43 86 connect(m_viewManager, SIGNAL(selectionChanged()),
Chris@43 87 this, SLOT(selectionChanged()));
Chris@43 88 connect(m_viewManager, SIGNAL(playLoopModeChanged()),
Chris@43 89 this, SLOT(playLoopModeChanged()));
Chris@43 90 connect(m_viewManager, SIGNAL(playSelectionModeChanged()),
Chris@43 91 this, SLOT(playSelectionModeChanged()));
Chris@43 92
Chris@300 93 connect(this, SIGNAL(playStatusChanged(bool)),
Chris@300 94 m_viewManager, SLOT(playStatusChanged(bool)));
Chris@300 95
Chris@43 96 connect(PlayParameterRepository::getInstance(),
Chris@43 97 SIGNAL(playParametersChanged(PlayParameters *)),
Chris@43 98 this, SLOT(playParametersChanged(PlayParameters *)));
Chris@43 99
Chris@43 100 connect(Preferences::getInstance(),
Chris@43 101 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
Chris@43 102 this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
Chris@43 103 }
Chris@43 104
Chris@43 105 AudioCallbackPlaySource::~AudioCallbackPlaySource()
Chris@43 106 {
Chris@177 107 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 108 SVDEBUG << "AudioCallbackPlaySource::~AudioCallbackPlaySource entering" << endl;
Chris@177 109 #endif
Chris@43 110 m_exiting = true;
Chris@43 111
Chris@43 112 if (m_fillThread) {
Chris@212 113 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 114 cout << "AudioCallbackPlaySource dtor: awakening thread" << endl;
Chris@212 115 #endif
Chris@212 116 m_condition.wakeAll();
Chris@43 117 m_fillThread->wait();
Chris@43 118 delete m_fillThread;
Chris@43 119 }
Chris@43 120
Chris@43 121 clearModels();
Chris@43 122
Chris@43 123 if (m_readBuffers != m_writeBuffers) {
Chris@43 124 delete m_readBuffers;
Chris@43 125 }
Chris@43 126
Chris@43 127 delete m_writeBuffers;
Chris@43 128
Chris@43 129 delete m_audioGenerator;
Chris@43 130
Chris@366 131 for (int i = 0; i < m_stretcherInputCount; ++i) {
Chris@91 132 delete[] m_stretcherInputs[i];
Chris@91 133 }
Chris@91 134 delete[] m_stretcherInputSizes;
Chris@91 135 delete[] m_stretcherInputs;
Chris@91 136
Chris@130 137 delete m_timeStretcher;
Chris@130 138 delete m_monoStretcher;
Chris@130 139
Chris@43 140 m_bufferScavenger.scavenge(true);
Chris@43 141 m_pluginScavenger.scavenge(true);
Chris@177 142 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 143 SVDEBUG << "AudioCallbackPlaySource::~AudioCallbackPlaySource finishing" << endl;
Chris@177 144 #endif
Chris@43 145 }
Chris@43 146
Chris@43 147 void
Chris@43 148 AudioCallbackPlaySource::addModel(Model *model)
Chris@43 149 {
Chris@43 150 if (m_models.find(model) != m_models.end()) return;
Chris@43 151
Chris@418 152 bool willPlay = m_audioGenerator->addModel(model);
Chris@43 153
Chris@43 154 m_mutex.lock();
Chris@43 155
Chris@43 156 m_models.insert(model);
Chris@43 157 if (model->getEndFrame() > m_lastModelEndFrame) {
Chris@43 158 m_lastModelEndFrame = model->getEndFrame();
Chris@43 159 }
Chris@43 160
Chris@43 161 bool buffersChanged = false, srChanged = false;
Chris@43 162
Chris@366 163 int modelChannels = 1;
Chris@43 164 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model);
Chris@43 165 if (dtvm) modelChannels = dtvm->getChannelCount();
Chris@43 166 if (modelChannels > m_sourceChannelCount) {
Chris@43 167 m_sourceChannelCount = modelChannels;
Chris@43 168 }
Chris@43 169
Chris@43 170 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@295 171 cout << "AudioCallbackPlaySource: Adding model with " << modelChannels << " channels at rate " << model->getSampleRate() << endl;
Chris@43 172 #endif
Chris@43 173
Chris@43 174 if (m_sourceSampleRate == 0) {
Chris@43 175
Chris@43 176 m_sourceSampleRate = model->getSampleRate();
Chris@43 177 srChanged = true;
Chris@43 178
Chris@43 179 } else if (model->getSampleRate() != m_sourceSampleRate) {
Chris@43 180
Chris@43 181 // If this is a dense time-value model and we have no other, we
Chris@43 182 // can just switch to this model's sample rate
Chris@43 183
Chris@43 184 if (dtvm) {
Chris@43 185
Chris@43 186 bool conflicting = false;
Chris@43 187
Chris@43 188 for (std::set<Model *>::const_iterator i = m_models.begin();
Chris@43 189 i != m_models.end(); ++i) {
Chris@43 190 // Only wave file models can be considered conflicting --
Chris@43 191 // writable wave file models are derived and we shouldn't
Chris@43 192 // take their rates into account. Also, don't give any
Chris@43 193 // particular weight to a file that's already playing at
Chris@43 194 // the wrong rate anyway
Chris@43 195 WaveFileModel *wfm = dynamic_cast<WaveFileModel *>(*i);
Chris@43 196 if (wfm && wfm != dtvm &&
Chris@43 197 wfm->getSampleRate() != model->getSampleRate() &&
Chris@43 198 wfm->getSampleRate() == m_sourceSampleRate) {
Chris@233 199 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl;
Chris@43 200 conflicting = true;
Chris@43 201 break;
Chris@43 202 }
Chris@43 203 }
Chris@43 204
Chris@43 205 if (conflicting) {
Chris@43 206
Chris@233 207 SVDEBUG << "AudioCallbackPlaySource::addModel: ERROR: "
Chris@229 208 << "New model sample rate does not match" << endl
Chris@43 209 << "existing model(s) (new " << model->getSampleRate()
Chris@43 210 << " vs " << m_sourceSampleRate
Chris@43 211 << "), playback will be wrong"
Chris@229 212 << endl;
Chris@43 213
Chris@43 214 emit sampleRateMismatch(model->getSampleRate(),
Chris@43 215 m_sourceSampleRate,
Chris@43 216 false);
Chris@43 217 } else {
Chris@43 218 m_sourceSampleRate = model->getSampleRate();
Chris@43 219 srChanged = true;
Chris@43 220 }
Chris@43 221 }
Chris@43 222 }
Chris@43 223
Chris@366 224 if (!m_writeBuffers || (int)m_writeBuffers->size() < getTargetChannelCount()) {
Chris@43 225 clearRingBuffers(true, getTargetChannelCount());
Chris@43 226 buffersChanged = true;
Chris@43 227 } else {
Chris@418 228 if (willPlay) clearRingBuffers(true);
Chris@43 229 }
Chris@43 230
Chris@43 231 if (buffersChanged || srChanged) {
Chris@43 232 if (m_converter) {
Chris@43 233 src_delete(m_converter);
Chris@43 234 src_delete(m_crapConverter);
Chris@43 235 m_converter = 0;
Chris@43 236 m_crapConverter = 0;
Chris@43 237 }
Chris@43 238 }
Chris@43 239
Chris@164 240 rebuildRangeLists();
Chris@164 241
Chris@43 242 m_mutex.unlock();
Chris@43 243
Chris@43 244 m_audioGenerator->setTargetChannelCount(getTargetChannelCount());
Chris@43 245
Chris@43 246 if (!m_fillThread) {
Chris@43 247 m_fillThread = new FillThread(*this);
Chris@43 248 m_fillThread->start();
Chris@43 249 }
Chris@43 250
Chris@43 251 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 252 cout << "AudioCallbackPlaySource::addModel: now have " << m_models.size() << " model(s) -- emitting modelReplaced" << endl;
Chris@43 253 #endif
Chris@43 254
Chris@43 255 if (buffersChanged || srChanged) {
Chris@43 256 emit modelReplaced();
Chris@43 257 }
Chris@43 258
Chris@435 259 connect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@435 260 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@43 261
Chris@212 262 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 263 cout << "AudioCallbackPlaySource::addModel: awakening thread" << endl;
Chris@212 264 #endif
Chris@212 265
Chris@43 266 m_condition.wakeAll();
Chris@43 267 }
Chris@43 268
Chris@43 269 void
Chris@435 270 AudioCallbackPlaySource::modelChangedWithin(sv_frame_t
Chris@367 271 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@367 272 startFrame
Chris@367 273 #endif
Chris@435 274 , sv_frame_t endFrame)
Chris@43 275 {
Chris@43 276 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@367 277 SVDEBUG << "AudioCallbackPlaySource::modelChangedWithin(" << startFrame << "," << endFrame << ")" << endl;
Chris@43 278 #endif
Chris@93 279 if (endFrame > m_lastModelEndFrame) {
Chris@93 280 m_lastModelEndFrame = endFrame;
Chris@99 281 rebuildRangeLists();
Chris@93 282 }
Chris@43 283 }
Chris@43 284
Chris@43 285 void
Chris@43 286 AudioCallbackPlaySource::removeModel(Model *model)
Chris@43 287 {
Chris@43 288 m_mutex.lock();
Chris@43 289
Chris@43 290 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 291 cout << "AudioCallbackPlaySource::removeModel(" << model << ")" << endl;
Chris@43 292 #endif
Chris@43 293
Chris@435 294 disconnect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@435 295 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@43 296
Chris@43 297 m_models.erase(model);
Chris@43 298
Chris@43 299 if (m_models.empty()) {
Chris@43 300 if (m_converter) {
Chris@43 301 src_delete(m_converter);
Chris@43 302 src_delete(m_crapConverter);
Chris@43 303 m_converter = 0;
Chris@43 304 m_crapConverter = 0;
Chris@43 305 }
Chris@43 306 m_sourceSampleRate = 0;
Chris@43 307 }
Chris@43 308
Chris@436 309 sv_frame_t lastEnd = 0;
Chris@43 310 for (std::set<Model *>::const_iterator i = m_models.begin();
Chris@43 311 i != m_models.end(); ++i) {
Chris@164 312 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 313 cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << endl;
Chris@164 314 #endif
Chris@367 315 if ((*i)->getEndFrame() > lastEnd) {
Chris@367 316 lastEnd = (*i)->getEndFrame();
Chris@367 317 }
Chris@164 318 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 319 cout << "(done, lastEnd now " << lastEnd << ")" << endl;
Chris@164 320 #endif
Chris@43 321 }
Chris@43 322 m_lastModelEndFrame = lastEnd;
Chris@43 323
Chris@212 324 m_audioGenerator->removeModel(model);
Chris@212 325
Chris@43 326 m_mutex.unlock();
Chris@43 327
Chris@43 328 clearRingBuffers();
Chris@43 329 }
Chris@43 330
Chris@43 331 void
Chris@43 332 AudioCallbackPlaySource::clearModels()
Chris@43 333 {
Chris@43 334 m_mutex.lock();
Chris@43 335
Chris@43 336 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 337 cout << "AudioCallbackPlaySource::clearModels()" << endl;
Chris@43 338 #endif
Chris@43 339
Chris@43 340 m_models.clear();
Chris@43 341
Chris@43 342 if (m_converter) {
Chris@43 343 src_delete(m_converter);
Chris@43 344 src_delete(m_crapConverter);
Chris@43 345 m_converter = 0;
Chris@43 346 m_crapConverter = 0;
Chris@43 347 }
Chris@43 348
Chris@43 349 m_lastModelEndFrame = 0;
Chris@43 350
Chris@43 351 m_sourceSampleRate = 0;
Chris@43 352
Chris@43 353 m_mutex.unlock();
Chris@43 354
Chris@43 355 m_audioGenerator->clearModels();
Chris@93 356
Chris@93 357 clearRingBuffers();
Chris@43 358 }
Chris@43 359
Chris@43 360 void
Chris@366 361 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, int count)
Chris@43 362 {
Chris@43 363 if (!haveLock) m_mutex.lock();
Chris@43 364
Chris@445 365 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@397 366 cerr << "clearRingBuffers" << endl;
Chris@445 367 #endif
Chris@397 368
Chris@93 369 rebuildRangeLists();
Chris@93 370
Chris@43 371 if (count == 0) {
Chris@436 372 if (m_writeBuffers) count = int(m_writeBuffers->size());
Chris@43 373 }
Chris@43 374
Chris@445 375 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@397 376 cerr << "current playing frame = " << getCurrentPlayingFrame() << endl;
Chris@397 377
Chris@397 378 cerr << "write buffer fill (before) = " << m_writeBufferFill << endl;
Chris@445 379 #endif
Chris@445 380
Chris@93 381 m_writeBufferFill = getCurrentBufferedFrame();
Chris@43 382
Chris@445 383 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@397 384 cerr << "current buffered frame = " << m_writeBufferFill << endl;
Chris@445 385 #endif
Chris@397 386
Chris@43 387 if (m_readBuffers != m_writeBuffers) {
Chris@43 388 delete m_writeBuffers;
Chris@43 389 }
Chris@43 390
Chris@43 391 m_writeBuffers = new RingBufferVector;
Chris@43 392
Chris@366 393 for (int i = 0; i < count; ++i) {
Chris@43 394 m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize));
Chris@43 395 }
Chris@43 396
Chris@442 397 m_audioGenerator->reset();
Chris@442 398
Chris@293 399 // cout << "AudioCallbackPlaySource::clearRingBuffers: Created "
Chris@293 400 // << count << " write buffers" << endl;
Chris@43 401
Chris@43 402 if (!haveLock) {
Chris@43 403 m_mutex.unlock();
Chris@43 404 }
Chris@43 405 }
Chris@43 406
Chris@43 407 void
Chris@434 408 AudioCallbackPlaySource::play(sv_frame_t startFrame)
Chris@43 409 {
Chris@414 410 if (!m_sourceSampleRate) {
Chris@414 411 cerr << "AudioCallbackPlaySource::play: No source sample rate available, not playing" << endl;
Chris@414 412 return;
Chris@414 413 }
Chris@414 414
Chris@43 415 if (m_viewManager->getPlaySelectionMode() &&
Chris@43 416 !m_viewManager->getSelections().empty()) {
Chris@60 417
Chris@233 418 SVDEBUG << "AudioCallbackPlaySource::play: constraining frame " << startFrame << " to selection = ";
Chris@94 419
Chris@60 420 startFrame = m_viewManager->constrainFrameToSelection(startFrame);
Chris@60 421
Chris@233 422 SVDEBUG << startFrame << endl;
Chris@94 423
Chris@43 424 } else {
Chris@454 425 if (startFrame < 0) {
Chris@454 426 startFrame = 0;
Chris@454 427 }
Chris@43 428 if (startFrame >= m_lastModelEndFrame) {
Chris@43 429 startFrame = 0;
Chris@43 430 }
Chris@43 431 }
Chris@43 432
Chris@132 433 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 434 cerr << "play(" << startFrame << ") -> playback model ";
Chris@132 435 #endif
Chris@60 436
Chris@60 437 startFrame = m_viewManager->alignReferenceToPlaybackFrame(startFrame);
Chris@60 438
Chris@189 439 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 440 cerr << startFrame << endl;
Chris@189 441 #endif
Chris@60 442
Chris@43 443 // The fill thread will automatically empty its buffers before
Chris@43 444 // starting again if we have not so far been playing, but not if
Chris@43 445 // we're just re-seeking.
Chris@102 446 // NO -- we can end up playing some first -- always reset here
Chris@43 447
Chris@43 448 m_mutex.lock();
Chris@102 449
Chris@91 450 if (m_timeStretcher) {
Chris@91 451 m_timeStretcher->reset();
Chris@91 452 }
Chris@130 453 if (m_monoStretcher) {
Chris@130 454 m_monoStretcher->reset();
Chris@130 455 }
Chris@102 456
Chris@102 457 m_readBufferFill = m_writeBufferFill = startFrame;
Chris@102 458 if (m_readBuffers) {
Chris@366 459 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@102 460 RingBuffer<float> *rb = getReadRingBuffer(c);
Chris@132 461 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 462 cerr << "reset ring buffer for channel " << c << endl;
Chris@132 463 #endif
Chris@102 464 if (rb) rb->reset();
Chris@102 465 }
Chris@43 466 }
Chris@102 467 if (m_converter) src_reset(m_converter);
Chris@102 468 if (m_crapConverter) src_reset(m_crapConverter);
Chris@102 469
Chris@43 470 m_mutex.unlock();
Chris@43 471
Chris@43 472 m_audioGenerator->reset();
Chris@43 473
Chris@94 474 m_playStartFrame = startFrame;
Chris@94 475 m_playStartFramePassed = false;
Chris@94 476 m_playStartedAt = RealTime::zeroTime;
Chris@94 477 if (m_target) {
Chris@94 478 m_playStartedAt = RealTime::fromSeconds(m_target->getCurrentTime());
Chris@94 479 }
Chris@94 480
Chris@43 481 bool changed = !m_playing;
Chris@91 482 m_lastRetrievalTimestamp = 0;
Chris@102 483 m_lastCurrentFrame = 0;
Chris@43 484 m_playing = true;
Chris@212 485
Chris@212 486 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 487 cout << "AudioCallbackPlaySource::play: awakening thread" << endl;
Chris@212 488 #endif
Chris@212 489
Chris@43 490 m_condition.wakeAll();
Chris@158 491 if (changed) {
Chris@158 492 emit playStatusChanged(m_playing);
Chris@158 493 emit activity(tr("Play from %1").arg
Chris@158 494 (RealTime::frame2RealTime
Chris@158 495 (m_playStartFrame, m_sourceSampleRate).toText().c_str()));
Chris@158 496 }
Chris@43 497 }
Chris@43 498
Chris@43 499 void
Chris@43 500 AudioCallbackPlaySource::stop()
Chris@43 501 {
Chris@212 502 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 503 SVDEBUG << "AudioCallbackPlaySource::stop()" << endl;
Chris@212 504 #endif
Chris@43 505 bool changed = m_playing;
Chris@43 506 m_playing = false;
Chris@212 507
Chris@212 508 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 509 cout << "AudioCallbackPlaySource::stop: awakening thread" << endl;
Chris@212 510 #endif
Chris@212 511
Chris@43 512 m_condition.wakeAll();
Chris@91 513 m_lastRetrievalTimestamp = 0;
Chris@158 514 if (changed) {
Chris@158 515 emit playStatusChanged(m_playing);
Chris@158 516 emit activity(tr("Stop at %1").arg
Chris@158 517 (RealTime::frame2RealTime
Chris@158 518 (m_lastCurrentFrame, m_sourceSampleRate).toText().c_str()));
Chris@158 519 }
Chris@102 520 m_lastCurrentFrame = 0;
Chris@43 521 }
Chris@43 522
Chris@43 523 void
Chris@43 524 AudioCallbackPlaySource::selectionChanged()
Chris@43 525 {
Chris@43 526 if (m_viewManager->getPlaySelectionMode()) {
Chris@43 527 clearRingBuffers();
Chris@43 528 }
Chris@43 529 }
Chris@43 530
Chris@43 531 void
Chris@43 532 AudioCallbackPlaySource::playLoopModeChanged()
Chris@43 533 {
Chris@43 534 clearRingBuffers();
Chris@43 535 }
Chris@43 536
Chris@43 537 void
Chris@43 538 AudioCallbackPlaySource::playSelectionModeChanged()
Chris@43 539 {
Chris@43 540 if (!m_viewManager->getSelections().empty()) {
Chris@43 541 clearRingBuffers();
Chris@43 542 }
Chris@43 543 }
Chris@43 544
Chris@43 545 void
Chris@43 546 AudioCallbackPlaySource::playParametersChanged(PlayParameters *)
Chris@43 547 {
Chris@43 548 clearRingBuffers();
Chris@43 549 }
Chris@43 550
Chris@43 551 void
Chris@43 552 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n)
Chris@43 553 {
Chris@43 554 if (n == "Resample Quality") {
Chris@43 555 setResampleQuality(Preferences::getInstance()->getResampleQuality());
Chris@43 556 }
Chris@43 557 }
Chris@43 558
Chris@43 559 void
Chris@43 560 AudioCallbackPlaySource::audioProcessingOverload()
Chris@43 561 {
Chris@293 562 cerr << "Audio processing overload!" << endl;
Chris@130 563
Chris@130 564 if (!m_playing) return;
Chris@130 565
Chris@43 566 RealTimePluginInstance *ap = m_auditioningPlugin;
Chris@130 567 if (ap && !m_auditioningPluginBypassed) {
Chris@43 568 m_auditioningPluginBypassed = true;
Chris@43 569 emit audioOverloadPluginDisabled();
Chris@130 570 return;
Chris@130 571 }
Chris@130 572
Chris@130 573 if (m_timeStretcher &&
Chris@130 574 m_timeStretcher->getTimeRatio() < 1.0 &&
Chris@130 575 m_stretcherInputCount > 1 &&
Chris@130 576 m_monoStretcher && !m_stretchMono) {
Chris@130 577 m_stretchMono = true;
Chris@130 578 emit audioTimeStretchMultiChannelDisabled();
Chris@130 579 return;
Chris@43 580 }
Chris@43 581 }
Chris@43 582
Chris@43 583 void
Chris@468 584 AudioCallbackPlaySource::setSystemPlaybackTarget(breakfastquay::SystemPlaybackTarget *target)
Chris@43 585 {
Chris@91 586 m_target = target;
Chris@468 587 }
Chris@468 588
Chris@468 589 void
Chris@468 590 AudioCallbackPlaySource::setSystemPlaybackBlockSize(int size)
Chris@468 591 {
Chris@293 592 cout << "AudioCallbackPlaySource::setTarget: Block size -> " << size << endl;
Chris@193 593 if (size != 0) {
Chris@193 594 m_blockSize = size;
Chris@193 595 }
Chris@193 596 if (size * 4 > m_ringBufferSize) {
Chris@472 597 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@472 598 cerr << "AudioCallbackPlaySource::setTarget: Buffer size "
Chris@472 599 << size << " > a quarter of ring buffer size "
Chris@472 600 << m_ringBufferSize << ", calling for more ring buffer"
Chris@472 601 << endl;
Chris@472 602 #endif
Chris@193 603 m_ringBufferSize = size * 4;
Chris@193 604 if (m_writeBuffers && !m_writeBuffers->empty()) {
Chris@193 605 clearRingBuffers();
Chris@193 606 }
Chris@193 607 }
Chris@43 608 }
Chris@43 609
Chris@366 610 int
Chris@43 611 AudioCallbackPlaySource::getTargetBlockSize() const
Chris@43 612 {
Chris@293 613 // cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << endl;
Chris@436 614 return int(m_blockSize);
Chris@43 615 }
Chris@43 616
Chris@43 617 void
Chris@468 618 AudioCallbackPlaySource::setSystemPlaybackLatency(int latency)
Chris@43 619 {
Chris@43 620 m_playLatency = latency;
Chris@43 621 }
Chris@43 622
Chris@434 623 sv_frame_t
Chris@43 624 AudioCallbackPlaySource::getTargetPlayLatency() const
Chris@43 625 {
Chris@43 626 return m_playLatency;
Chris@43 627 }
Chris@43 628
Chris@434 629 sv_frame_t
Chris@43 630 AudioCallbackPlaySource::getCurrentPlayingFrame()
Chris@43 631 {
Chris@91 632 // This method attempts to estimate which audio sample frame is
Chris@91 633 // "currently coming through the speakers".
Chris@91 634
Chris@436 635 sv_samplerate_t targetRate = getTargetSampleRate();
Chris@436 636 sv_frame_t latency = m_playLatency; // at target rate
Chris@402 637 RealTime latency_t = RealTime::zeroTime;
Chris@402 638
Chris@402 639 if (targetRate != 0) {
Chris@402 640 latency_t = RealTime::frame2RealTime(latency, targetRate);
Chris@402 641 }
Chris@93 642
Chris@93 643 return getCurrentFrame(latency_t);
Chris@93 644 }
Chris@93 645
Chris@434 646 sv_frame_t
Chris@93 647 AudioCallbackPlaySource::getCurrentBufferedFrame()
Chris@93 648 {
Chris@93 649 return getCurrentFrame(RealTime::zeroTime);
Chris@93 650 }
Chris@93 651
Chris@434 652 sv_frame_t
Chris@93 653 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t)
Chris@93 654 {
Chris@91 655 // We resample when filling the ring buffer, and time-stretch when
Chris@91 656 // draining it. The buffer contains data at the "target rate" and
Chris@91 657 // the latency provided by the target is also at the target rate.
Chris@91 658 // Because of the multiple rates involved, we do the actual
Chris@91 659 // calculation using RealTime instead.
Chris@43 660
Chris@434 661 sv_samplerate_t sourceRate = getSourceSampleRate();
Chris@434 662 sv_samplerate_t targetRate = getTargetSampleRate();
Chris@91 663
Chris@91 664 if (sourceRate == 0 || targetRate == 0) return 0;
Chris@91 665
Chris@366 666 int inbuffer = 0; // at target rate
Chris@91 667
Chris@366 668 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 669 RingBuffer<float> *rb = getReadRingBuffer(c);
Chris@43 670 if (rb) {
Chris@366 671 int here = rb->getReadSpace();
Chris@91 672 if (c == 0 || here < inbuffer) inbuffer = here;
Chris@43 673 }
Chris@43 674 }
Chris@43 675
Chris@436 676 sv_frame_t readBufferFill = m_readBufferFill;
Chris@436 677 sv_frame_t lastRetrievedBlockSize = m_lastRetrievedBlockSize;
Chris@91 678 double lastRetrievalTimestamp = m_lastRetrievalTimestamp;
Chris@91 679 double currentTime = 0.0;
Chris@91 680 if (m_target) currentTime = m_target->getCurrentTime();
Chris@91 681
Chris@102 682 bool looping = m_viewManager->getPlayLoopMode();
Chris@102 683
Chris@91 684 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate);
Chris@91 685
Chris@436 686 sv_frame_t stretchlat = 0;
Chris@91 687 double timeRatio = 1.0;
Chris@91 688
Chris@91 689 if (m_timeStretcher) {
Chris@91 690 stretchlat = m_timeStretcher->getLatency();
Chris@91 691 timeRatio = m_timeStretcher->getTimeRatio();
Chris@43 692 }
Chris@43 693
Chris@91 694 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate);
Chris@43 695
Chris@91 696 // When the target has just requested a block from us, the last
Chris@91 697 // sample it obtained was our buffer fill frame count minus the
Chris@91 698 // amount of read space (converted back to source sample rate)
Chris@91 699 // remaining now. That sample is not expected to be played until
Chris@91 700 // the target's play latency has elapsed. By the time the
Chris@91 701 // following block is requested, that sample will be at the
Chris@91 702 // target's play latency minus the last requested block size away
Chris@91 703 // from being played.
Chris@91 704
Chris@91 705 RealTime sincerequest_t = RealTime::zeroTime;
Chris@91 706 RealTime lastretrieved_t = RealTime::zeroTime;
Chris@91 707
Chris@102 708 if (m_target &&
Chris@102 709 m_trustworthyTimestamps &&
Chris@102 710 lastRetrievalTimestamp != 0.0) {
Chris@91 711
Chris@91 712 lastretrieved_t = RealTime::frame2RealTime
Chris@91 713 (lastRetrievedBlockSize, targetRate);
Chris@91 714
Chris@91 715 // calculate number of frames at target rate that have elapsed
Chris@91 716 // since the end of the last call to getSourceSamples
Chris@91 717
Chris@102 718 if (m_trustworthyTimestamps && !looping) {
Chris@91 719
Chris@102 720 // this adjustment seems to cause more problems when looping
Chris@102 721 double elapsed = currentTime - lastRetrievalTimestamp;
Chris@102 722
Chris@102 723 if (elapsed > 0.0) {
Chris@102 724 sincerequest_t = RealTime::fromSeconds(elapsed);
Chris@102 725 }
Chris@91 726 }
Chris@91 727
Chris@91 728 } else {
Chris@91 729
Chris@91 730 lastretrieved_t = RealTime::frame2RealTime
Chris@91 731 (getTargetBlockSize(), targetRate);
Chris@62 732 }
Chris@91 733
Chris@91 734 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate);
Chris@91 735
Chris@91 736 if (timeRatio != 1.0) {
Chris@91 737 lastretrieved_t = lastretrieved_t / timeRatio;
Chris@91 738 sincerequest_t = sincerequest_t / timeRatio;
Chris@163 739 latency_t = latency_t / timeRatio;
Chris@43 740 }
Chris@43 741
Chris@91 742 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 743 cerr << "\nbuffered to: " << bufferedto_t << ", in buffer: " << inbuffer_t << ", time ratio " << timeRatio << "\n stretcher latency: " << stretchlat_t << ", device latency: " << latency_t << "\n since request: " << sincerequest_t << ", last retrieved quantity: " << lastretrieved_t << endl;
Chris@91 744 #endif
Chris@43 745
Chris@93 746 // Normally the range lists should contain at least one item each
Chris@93 747 // -- if playback is unconstrained, that item should report the
Chris@93 748 // entire source audio duration.
Chris@43 749
Chris@93 750 if (m_rangeStarts.empty()) {
Chris@93 751 rebuildRangeLists();
Chris@93 752 }
Chris@92 753
Chris@93 754 if (m_rangeStarts.empty()) {
Chris@93 755 // this code is only used in case of error in rebuildRangeLists
Chris@93 756 RealTime playing_t = bufferedto_t
Chris@93 757 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
Chris@93 758 + sincerequest_t;
Chris@193 759 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
Chris@434 760 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
Chris@93 761 return m_viewManager->alignPlaybackFrameToReference(frame);
Chris@93 762 }
Chris@43 763
Chris@91 764 int inRange = 0;
Chris@91 765 int index = 0;
Chris@91 766
Chris@366 767 for (int i = 0; i < (int)m_rangeStarts.size(); ++i) {
Chris@93 768 if (bufferedto_t >= m_rangeStarts[i]) {
Chris@93 769 inRange = index;
Chris@93 770 } else {
Chris@93 771 break;
Chris@93 772 }
Chris@93 773 ++index;
Chris@93 774 }
Chris@93 775
Chris@436 776 if (inRange >= int(m_rangeStarts.size())) {
Chris@436 777 inRange = int(m_rangeStarts.size())-1;
Chris@436 778 }
Chris@93 779
Chris@94 780 RealTime playing_t = bufferedto_t;
Chris@93 781
Chris@93 782 playing_t = playing_t
Chris@93 783 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
Chris@93 784 + sincerequest_t;
Chris@94 785
Chris@94 786 // This rather gross little hack is used to ensure that latency
Chris@94 787 // compensation doesn't result in the playback pointer appearing
Chris@94 788 // to start earlier than the actual playback does. It doesn't
Chris@94 789 // work properly (hence the bail-out in the middle) because if we
Chris@94 790 // are playing a relatively short looped region, the playing time
Chris@94 791 // estimated from the buffer fill frame may have wrapped around
Chris@94 792 // the region boundary and end up being much smaller than the
Chris@94 793 // theoretical play start frame, perhaps even for the entire
Chris@94 794 // duration of playback!
Chris@94 795
Chris@94 796 if (!m_playStartFramePassed) {
Chris@94 797 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame,
Chris@94 798 sourceRate);
Chris@94 799 if (playing_t < playstart_t) {
Chris@293 800 // cerr << "playing_t " << playing_t << " < playstart_t "
Chris@293 801 // << playstart_t << endl;
Chris@122 802 if (/*!!! sincerequest_t > RealTime::zeroTime && */
Chris@94 803 m_playStartedAt + latency_t + stretchlat_t <
Chris@94 804 RealTime::fromSeconds(currentTime)) {
Chris@293 805 // cerr << "but we've been playing for long enough that I think we should disregard it (it probably results from loop wrapping)" << endl;
Chris@94 806 m_playStartFramePassed = true;
Chris@94 807 } else {
Chris@94 808 playing_t = playstart_t;
Chris@94 809 }
Chris@94 810 } else {
Chris@94 811 m_playStartFramePassed = true;
Chris@94 812 }
Chris@94 813 }
Chris@163 814
Chris@163 815 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 816 cerr << "playing_t " << playing_t;
Chris@163 817 #endif
Chris@94 818
Chris@94 819 playing_t = playing_t - m_rangeStarts[inRange];
Chris@93 820
Chris@93 821 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 822 cerr << " as offset into range " << inRange << " (start =" << m_rangeStarts[inRange] << " duration =" << m_rangeDurations[inRange] << ") = " << playing_t << endl;
Chris@93 823 #endif
Chris@93 824
Chris@93 825 while (playing_t < RealTime::zeroTime) {
Chris@93 826
Chris@93 827 if (inRange == 0) {
Chris@93 828 if (looping) {
Chris@436 829 inRange = int(m_rangeStarts.size()) - 1;
Chris@93 830 } else {
Chris@93 831 break;
Chris@93 832 }
Chris@93 833 } else {
Chris@93 834 --inRange;
Chris@93 835 }
Chris@93 836
Chris@93 837 playing_t = playing_t + m_rangeDurations[inRange];
Chris@93 838 }
Chris@93 839
Chris@93 840 playing_t = playing_t + m_rangeStarts[inRange];
Chris@93 841
Chris@93 842 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 843 cerr << " playing time: " << playing_t << endl;
Chris@93 844 #endif
Chris@93 845
Chris@93 846 if (!looping) {
Chris@366 847 if (inRange == (int)m_rangeStarts.size()-1 &&
Chris@93 848 playing_t >= m_rangeStarts[inRange] + m_rangeDurations[inRange]) {
Chris@293 849 cerr << "Not looping, inRange " << inRange << " == rangeStarts.size()-1, playing_t " << playing_t << " >= m_rangeStarts[inRange] " << m_rangeStarts[inRange] << " + m_rangeDurations[inRange] " << m_rangeDurations[inRange] << " -- stopping" << endl;
Chris@93 850 stop();
Chris@93 851 }
Chris@93 852 }
Chris@93 853
Chris@93 854 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
Chris@93 855
Chris@434 856 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
Chris@102 857
Chris@102 858 if (m_lastCurrentFrame > 0 && !looping) {
Chris@102 859 if (frame < m_lastCurrentFrame) {
Chris@102 860 frame = m_lastCurrentFrame;
Chris@102 861 }
Chris@102 862 }
Chris@102 863
Chris@102 864 m_lastCurrentFrame = frame;
Chris@102 865
Chris@93 866 return m_viewManager->alignPlaybackFrameToReference(frame);
Chris@93 867 }
Chris@93 868
Chris@93 869 void
Chris@93 870 AudioCallbackPlaySource::rebuildRangeLists()
Chris@93 871 {
Chris@93 872 bool constrained = (m_viewManager->getPlaySelectionMode());
Chris@93 873
Chris@93 874 m_rangeStarts.clear();
Chris@93 875 m_rangeDurations.clear();
Chris@93 876
Chris@436 877 sv_samplerate_t sourceRate = getSourceSampleRate();
Chris@93 878 if (sourceRate == 0) return;
Chris@93 879
Chris@93 880 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
Chris@93 881 if (end == RealTime::zeroTime) return;
Chris@93 882
Chris@93 883 if (!constrained) {
Chris@93 884 m_rangeStarts.push_back(RealTime::zeroTime);
Chris@93 885 m_rangeDurations.push_back(end);
Chris@93 886 return;
Chris@93 887 }
Chris@93 888
Chris@93 889 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@93 890 MultiSelection::SelectionList::const_iterator i;
Chris@93 891
Chris@93 892 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 893 SVDEBUG << "AudioCallbackPlaySource::rebuildRangeLists" << endl;
Chris@93 894 #endif
Chris@93 895
Chris@93 896 if (!selections.empty()) {
Chris@91 897
Chris@91 898 for (i = selections.begin(); i != selections.end(); ++i) {
Chris@91 899
Chris@91 900 RealTime start =
Chris@91 901 (RealTime::frame2RealTime
Chris@91 902 (m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
Chris@91 903 sourceRate));
Chris@91 904 RealTime duration =
Chris@91 905 (RealTime::frame2RealTime
Chris@91 906 (m_viewManager->alignReferenceToPlaybackFrame(i->getEndFrame()) -
Chris@91 907 m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
Chris@91 908 sourceRate));
Chris@91 909
Chris@93 910 m_rangeStarts.push_back(start);
Chris@93 911 m_rangeDurations.push_back(duration);
Chris@91 912 }
Chris@93 913 } else {
Chris@93 914 m_rangeStarts.push_back(RealTime::zeroTime);
Chris@93 915 m_rangeDurations.push_back(end);
Chris@43 916 }
Chris@43 917
Chris@93 918 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 919 cerr << "Now have " << m_rangeStarts.size() << " play ranges" << endl;
Chris@91 920 #endif
Chris@43 921 }
Chris@43 922
Chris@43 923 void
Chris@43 924 AudioCallbackPlaySource::setOutputLevels(float left, float right)
Chris@43 925 {
Chris@43 926 m_outputLeft = left;
Chris@43 927 m_outputRight = right;
Chris@43 928 }
Chris@43 929
Chris@43 930 bool
Chris@43 931 AudioCallbackPlaySource::getOutputLevels(float &left, float &right)
Chris@43 932 {
Chris@43 933 left = m_outputLeft;
Chris@43 934 right = m_outputRight;
Chris@43 935 return true;
Chris@43 936 }
Chris@43 937
Chris@43 938 void
Chris@468 939 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr)
Chris@43 940 {
Chris@244 941 bool first = (m_targetSampleRate == 0);
Chris@244 942
Chris@43 943 m_targetSampleRate = sr;
Chris@43 944 initialiseConverter();
Chris@244 945
Chris@244 946 if (first && (m_stretchRatio != 1.f)) {
Chris@244 947 // couldn't create a stretcher before because we had no sample
Chris@244 948 // rate: make one now
Chris@244 949 setTimeStretch(m_stretchRatio);
Chris@244 950 }
Chris@43 951 }
Chris@43 952
Chris@43 953 void
Chris@43 954 AudioCallbackPlaySource::initialiseConverter()
Chris@43 955 {
Chris@43 956 m_mutex.lock();
Chris@43 957
Chris@43 958 if (m_converter) {
Chris@43 959 src_delete(m_converter);
Chris@43 960 src_delete(m_crapConverter);
Chris@43 961 m_converter = 0;
Chris@43 962 m_crapConverter = 0;
Chris@43 963 }
Chris@43 964
Chris@43 965 if (getSourceSampleRate() != getTargetSampleRate()) {
Chris@43 966
Chris@43 967 int err = 0;
Chris@43 968
Chris@43 969 m_converter = src_new(m_resampleQuality == 2 ? SRC_SINC_BEST_QUALITY :
Chris@43 970 m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY :
Chris@43 971 m_resampleQuality == 0 ? SRC_SINC_FASTEST :
Chris@43 972 SRC_SINC_MEDIUM_QUALITY,
Chris@43 973 getTargetChannelCount(), &err);
Chris@43 974
Chris@43 975 if (m_converter) {
Chris@43 976 m_crapConverter = src_new(SRC_LINEAR,
Chris@43 977 getTargetChannelCount(),
Chris@43 978 &err);
Chris@43 979 }
Chris@43 980
Chris@43 981 if (!m_converter || !m_crapConverter) {
Chris@293 982 cerr
Chris@43 983 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: "
Chris@293 984 << src_strerror(err) << endl;
Chris@43 985
Chris@43 986 if (m_converter) {
Chris@43 987 src_delete(m_converter);
Chris@43 988 m_converter = 0;
Chris@43 989 }
Chris@43 990
Chris@43 991 if (m_crapConverter) {
Chris@43 992 src_delete(m_crapConverter);
Chris@43 993 m_crapConverter = 0;
Chris@43 994 }
Chris@43 995
Chris@43 996 m_mutex.unlock();
Chris@43 997
Chris@43 998 emit sampleRateMismatch(getSourceSampleRate(),
Chris@43 999 getTargetSampleRate(),
Chris@43 1000 false);
Chris@43 1001 } else {
Chris@43 1002
Chris@43 1003 m_mutex.unlock();
Chris@43 1004
Chris@43 1005 emit sampleRateMismatch(getSourceSampleRate(),
Chris@43 1006 getTargetSampleRate(),
Chris@43 1007 true);
Chris@43 1008 }
Chris@43 1009 } else {
Chris@43 1010 m_mutex.unlock();
Chris@43 1011 }
Chris@43 1012 }
Chris@43 1013
Chris@43 1014 void
Chris@43 1015 AudioCallbackPlaySource::setResampleQuality(int q)
Chris@43 1016 {
Chris@43 1017 if (q == m_resampleQuality) return;
Chris@43 1018 m_resampleQuality = q;
Chris@43 1019
Chris@43 1020 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 1021 SVDEBUG << "AudioCallbackPlaySource::setResampleQuality: setting to "
Chris@229 1022 << m_resampleQuality << endl;
Chris@43 1023 #endif
Chris@43 1024
Chris@43 1025 initialiseConverter();
Chris@43 1026 }
Chris@43 1027
Chris@43 1028 void
Chris@107 1029 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a)
Chris@43 1030 {
Chris@107 1031 RealTimePluginInstance *plugin = dynamic_cast<RealTimePluginInstance *>(a);
Chris@107 1032 if (a && !plugin) {
Chris@293 1033 cerr << "WARNING: AudioCallbackPlaySource::setAuditioningEffect: auditionable object " << a << " is not a real-time plugin instance" << endl;
Chris@107 1034 }
Chris@204 1035
Chris@204 1036 m_mutex.lock();
Chris@43 1037 m_auditioningPlugin = plugin;
Chris@43 1038 m_auditioningPluginBypassed = false;
Chris@204 1039 m_mutex.unlock();
Chris@43 1040 }
Chris@43 1041
Chris@43 1042 void
Chris@43 1043 AudioCallbackPlaySource::setSoloModelSet(std::set<Model *> s)
Chris@43 1044 {
Chris@43 1045 m_audioGenerator->setSoloModelSet(s);
Chris@43 1046 clearRingBuffers();
Chris@43 1047 }
Chris@43 1048
Chris@43 1049 void
Chris@43 1050 AudioCallbackPlaySource::clearSoloModelSet()
Chris@43 1051 {
Chris@43 1052 m_audioGenerator->clearSoloModelSet();
Chris@43 1053 clearRingBuffers();
Chris@43 1054 }
Chris@43 1055
Chris@434 1056 sv_samplerate_t
Chris@43 1057 AudioCallbackPlaySource::getTargetSampleRate() const
Chris@43 1058 {
Chris@43 1059 if (m_targetSampleRate) return m_targetSampleRate;
Chris@43 1060 else return getSourceSampleRate();
Chris@43 1061 }
Chris@43 1062
Chris@366 1063 int
Chris@43 1064 AudioCallbackPlaySource::getSourceChannelCount() const
Chris@43 1065 {
Chris@43 1066 return m_sourceChannelCount;
Chris@43 1067 }
Chris@43 1068
Chris@366 1069 int
Chris@43 1070 AudioCallbackPlaySource::getTargetChannelCount() const
Chris@43 1071 {
Chris@43 1072 if (m_sourceChannelCount < 2) return 2;
Chris@43 1073 return m_sourceChannelCount;
Chris@43 1074 }
Chris@43 1075
Chris@434 1076 sv_samplerate_t
Chris@43 1077 AudioCallbackPlaySource::getSourceSampleRate() const
Chris@43 1078 {
Chris@43 1079 return m_sourceSampleRate;
Chris@43 1080 }
Chris@43 1081
Chris@43 1082 void
Chris@436 1083 AudioCallbackPlaySource::setTimeStretch(double factor)
Chris@43 1084 {
Chris@91 1085 m_stretchRatio = factor;
Chris@91 1086
Chris@244 1087 if (!getTargetSampleRate()) return; // have to make our stretcher later
Chris@244 1088
Chris@436 1089 if (m_timeStretcher || (factor == 1.0)) {
Chris@91 1090 // stretch ratio will be set in next process call if appropriate
Chris@62 1091 } else {
Chris@91 1092 m_stretcherInputCount = getTargetChannelCount();
Chris@62 1093 RubberBandStretcher *stretcher = new RubberBandStretcher
Chris@436 1094 (int(getTargetSampleRate()),
Chris@91 1095 m_stretcherInputCount,
Chris@62 1096 RubberBandStretcher::OptionProcessRealTime,
Chris@62 1097 factor);
Chris@130 1098 RubberBandStretcher *monoStretcher = new RubberBandStretcher
Chris@436 1099 (int(getTargetSampleRate()),
Chris@130 1100 1,
Chris@130 1101 RubberBandStretcher::OptionProcessRealTime,
Chris@130 1102 factor);
Chris@91 1103 m_stretcherInputs = new float *[m_stretcherInputCount];
Chris@436 1104 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount];
Chris@366 1105 for (int c = 0; c < m_stretcherInputCount; ++c) {
Chris@91 1106 m_stretcherInputSizes[c] = 16384;
Chris@91 1107 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
Chris@91 1108 }
Chris@130 1109 m_monoStretcher = monoStretcher;
Chris@62 1110 m_timeStretcher = stretcher;
Chris@62 1111 }
Chris@158 1112
Chris@158 1113 emit activity(tr("Change time-stretch factor to %1").arg(factor));
Chris@43 1114 }
Chris@43 1115
Chris@471 1116 int
Chris@468 1117 AudioCallbackPlaySource::getSourceSamples(int count, float **buffer)
Chris@43 1118 {
Chris@43 1119 if (!m_playing) {
Chris@193 1120 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1121 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Not playing" << endl;
Chris@193 1122 #endif
Chris@366 1123 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@130 1124 for (int i = 0; i < count; ++i) {
Chris@43 1125 buffer[ch][i] = 0.0;
Chris@43 1126 }
Chris@43 1127 }
Chris@471 1128 return 0;
Chris@43 1129 }
Chris@43 1130
Chris@212 1131 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1132 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Playing" << endl;
Chris@212 1133 #endif
Chris@212 1134
Chris@43 1135 // Ensure that all buffers have at least the amount of data we
Chris@43 1136 // need -- else reduce the size of our requests correspondingly
Chris@43 1137
Chris@366 1138 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@43 1139
Chris@43 1140 RingBuffer<float> *rb = getReadRingBuffer(ch);
Chris@43 1141
Chris@43 1142 if (!rb) {
Chris@293 1143 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
Chris@43 1144 << "No ring buffer available for channel " << ch
Chris@293 1145 << ", returning no data here" << endl;
Chris@43 1146 count = 0;
Chris@43 1147 break;
Chris@43 1148 }
Chris@43 1149
Chris@366 1150 int rs = rb->getReadSpace();
Chris@43 1151 if (rs < count) {
Chris@43 1152 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1153 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
Chris@43 1154 << "Ring buffer for channel " << ch << " has only "
Chris@193 1155 << rs << " (of " << count << ") samples available ("
Chris@193 1156 << "ring buffer size is " << rb->getSize() << ", write "
Chris@193 1157 << "space " << rb->getWriteSpace() << "), "
Chris@293 1158 << "reducing request size" << endl;
Chris@43 1159 #endif
Chris@43 1160 count = rs;
Chris@43 1161 }
Chris@43 1162 }
Chris@43 1163
Chris@471 1164 if (count == 0) return 0;
Chris@43 1165
Chris@62 1166 RubberBandStretcher *ts = m_timeStretcher;
Chris@130 1167 RubberBandStretcher *ms = m_monoStretcher;
Chris@130 1168
Chris@436 1169 double ratio = ts ? ts->getTimeRatio() : 1.0;
Chris@91 1170
Chris@91 1171 if (ratio != m_stretchRatio) {
Chris@91 1172 if (!ts) {
Chris@293 1173 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << endl;
Chris@436 1174 m_stretchRatio = 1.0;
Chris@91 1175 } else {
Chris@91 1176 ts->setTimeRatio(m_stretchRatio);
Chris@130 1177 if (ms) ms->setTimeRatio(m_stretchRatio);
Chris@130 1178 if (m_stretchRatio >= 1.0) m_stretchMono = false;
Chris@130 1179 }
Chris@130 1180 }
Chris@130 1181
Chris@130 1182 int stretchChannels = m_stretcherInputCount;
Chris@130 1183 if (m_stretchMono) {
Chris@130 1184 if (ms) {
Chris@130 1185 ts = ms;
Chris@130 1186 stretchChannels = 1;
Chris@130 1187 } else {
Chris@130 1188 m_stretchMono = false;
Chris@91 1189 }
Chris@91 1190 }
Chris@91 1191
Chris@91 1192 if (m_target) {
Chris@91 1193 m_lastRetrievedBlockSize = count;
Chris@91 1194 m_lastRetrievalTimestamp = m_target->getCurrentTime();
Chris@91 1195 }
Chris@43 1196
Chris@62 1197 if (!ts || ratio == 1.f) {
Chris@43 1198
Chris@130 1199 int got = 0;
Chris@43 1200
Chris@366 1201 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@43 1202
Chris@43 1203 RingBuffer<float> *rb = getReadRingBuffer(ch);
Chris@43 1204
Chris@43 1205 if (rb) {
Chris@43 1206
Chris@43 1207 // this is marginally more likely to leave our channels in
Chris@43 1208 // sync after a processing failure than just passing "count":
Chris@436 1209 sv_frame_t request = count;
Chris@43 1210 if (ch > 0) request = got;
Chris@43 1211
Chris@436 1212 got = rb->read(buffer[ch], int(request));
Chris@43 1213
Chris@43 1214 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 1215 cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << endl;
Chris@43 1216 #endif
Chris@43 1217 }
Chris@43 1218
Chris@366 1219 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@130 1220 for (int i = got; i < count; ++i) {
Chris@43 1221 buffer[ch][i] = 0.0;
Chris@43 1222 }
Chris@43 1223 }
Chris@43 1224 }
Chris@43 1225
Chris@43 1226 applyAuditioningEffect(count, buffer);
Chris@43 1227
Chris@212 1228 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1229 cout << "AudioCallbackPlaySource::getSamples: awakening thread" << endl;
Chris@212 1230 #endif
Chris@212 1231
Chris@43 1232 m_condition.wakeAll();
Chris@91 1233
Chris@471 1234 return got;
Chris@43 1235 }
Chris@43 1236
Chris@366 1237 int channels = getTargetChannelCount();
Chris@436 1238 sv_frame_t available;
Chris@436 1239 sv_frame_t fedToStretcher = 0;
Chris@91 1240 int warned = 0;
Chris@43 1241
Chris@91 1242 // The input block for a given output is approx output / ratio,
Chris@91 1243 // but we can't predict it exactly, for an adaptive timestretcher.
Chris@91 1244
Chris@91 1245 while ((available = ts->available()) < count) {
Chris@91 1246
Chris@436 1247 sv_frame_t reqd = lrint(double(count - available) / ratio);
Chris@436 1248 reqd = std::max(reqd, sv_frame_t(ts->getSamplesRequired()));
Chris@91 1249 if (reqd == 0) reqd = 1;
Chris@91 1250
Chris@436 1251 sv_frame_t got = reqd;
Chris@91 1252
Chris@91 1253 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 1254 cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << endl;
Chris@62 1255 #endif
Chris@43 1256
Chris@366 1257 for (int c = 0; c < channels; ++c) {
Chris@131 1258 if (c >= m_stretcherInputCount) continue;
Chris@91 1259 if (reqd > m_stretcherInputSizes[c]) {
Chris@91 1260 if (c == 0) {
Chris@293 1261 cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << endl;
Chris@91 1262 }
Chris@91 1263 delete[] m_stretcherInputs[c];
Chris@91 1264 m_stretcherInputSizes[c] = reqd * 2;
Chris@91 1265 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
Chris@91 1266 }
Chris@91 1267 }
Chris@43 1268
Chris@366 1269 for (int c = 0; c < channels; ++c) {
Chris@131 1270 if (c >= m_stretcherInputCount) continue;
Chris@91 1271 RingBuffer<float> *rb = getReadRingBuffer(c);
Chris@91 1272 if (rb) {
Chris@436 1273 sv_frame_t gotHere;
Chris@130 1274 if (stretchChannels == 1 && c > 0) {
Chris@436 1275 gotHere = rb->readAdding(m_stretcherInputs[0], int(got));
Chris@130 1276 } else {
Chris@436 1277 gotHere = rb->read(m_stretcherInputs[c], int(got));
Chris@130 1278 }
Chris@91 1279 if (gotHere < got) got = gotHere;
Chris@91 1280
Chris@91 1281 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@91 1282 if (c == 0) {
Chris@233 1283 SVDEBUG << "feeding stretcher: got " << gotHere
Chris@229 1284 << ", " << rb->getReadSpace() << " remain" << endl;
Chris@91 1285 }
Chris@62 1286 #endif
Chris@43 1287
Chris@91 1288 } else {
Chris@293 1289 cerr << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << endl;
Chris@43 1290 }
Chris@43 1291 }
Chris@43 1292
Chris@43 1293 if (got < reqd) {
Chris@293 1294 cerr << "WARNING: Read underrun in playback ("
Chris@293 1295 << got << " < " << reqd << ")" << endl;
Chris@43 1296 }
Chris@43 1297
Chris@463 1298 ts->process(m_stretcherInputs, size_t(got), false);
Chris@91 1299
Chris@91 1300 fedToStretcher += got;
Chris@43 1301
Chris@43 1302 if (got == 0) break;
Chris@43 1303
Chris@62 1304 if (ts->available() == available) {
Chris@293 1305 cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << endl;
Chris@43 1306 if (++warned == 5) break;
Chris@43 1307 }
Chris@43 1308 }
Chris@43 1309
Chris@463 1310 ts->retrieve(buffer, size_t(count));
Chris@43 1311
Chris@130 1312 for (int c = stretchChannels; c < getTargetChannelCount(); ++c) {
Chris@130 1313 for (int i = 0; i < count; ++i) {
Chris@130 1314 buffer[c][i] = buffer[0][i];
Chris@130 1315 }
Chris@130 1316 }
Chris@130 1317
Chris@43 1318 applyAuditioningEffect(count, buffer);
Chris@43 1319
Chris@212 1320 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1321 cout << "AudioCallbackPlaySource::getSamples [stretched]: awakening thread" << endl;
Chris@212 1322 #endif
Chris@212 1323
Chris@43 1324 m_condition.wakeAll();
Chris@43 1325
Chris@471 1326 return count;
Chris@43 1327 }
Chris@43 1328
Chris@43 1329 void
Chris@434 1330 AudioCallbackPlaySource::applyAuditioningEffect(sv_frame_t count, float **buffers)
Chris@43 1331 {
Chris@43 1332 if (m_auditioningPluginBypassed) return;
Chris@43 1333 RealTimePluginInstance *plugin = m_auditioningPlugin;
Chris@43 1334 if (!plugin) return;
Chris@204 1335
Chris@366 1336 if ((int)plugin->getAudioInputCount() != getTargetChannelCount()) {
Chris@293 1337 // cerr << "plugin input count " << plugin->getAudioInputCount()
Chris@43 1338 // << " != our channel count " << getTargetChannelCount()
Chris@293 1339 // << endl;
Chris@43 1340 return;
Chris@43 1341 }
Chris@366 1342 if ((int)plugin->getAudioOutputCount() != getTargetChannelCount()) {
Chris@293 1343 // cerr << "plugin output count " << plugin->getAudioOutputCount()
Chris@43 1344 // << " != our channel count " << getTargetChannelCount()
Chris@293 1345 // << endl;
Chris@43 1346 return;
Chris@43 1347 }
Chris@366 1348 if ((int)plugin->getBufferSize() < count) {
Chris@293 1349 // cerr << "plugin buffer size " << plugin->getBufferSize()
Chris@102 1350 // << " < our block size " << count
Chris@293 1351 // << endl;
Chris@43 1352 return;
Chris@43 1353 }
Chris@43 1354
Chris@43 1355 float **ib = plugin->getAudioInputBuffers();
Chris@43 1356 float **ob = plugin->getAudioOutputBuffers();
Chris@43 1357
Chris@366 1358 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@366 1359 for (int i = 0; i < count; ++i) {
Chris@43 1360 ib[c][i] = buffers[c][i];
Chris@43 1361 }
Chris@43 1362 }
Chris@43 1363
Chris@436 1364 plugin->run(Vamp::RealTime::zeroTime, int(count));
Chris@43 1365
Chris@366 1366 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@366 1367 for (int i = 0; i < count; ++i) {
Chris@43 1368 buffers[c][i] = ob[c][i];
Chris@43 1369 }
Chris@43 1370 }
Chris@43 1371 }
Chris@43 1372
Chris@43 1373 // Called from fill thread, m_playing true, mutex held
Chris@43 1374 bool
Chris@43 1375 AudioCallbackPlaySource::fillBuffers()
Chris@43 1376 {
Chris@43 1377 static float *tmp = 0;
Chris@436 1378 static sv_frame_t tmpSize = 0;
Chris@43 1379
Chris@434 1380 sv_frame_t space = 0;
Chris@366 1381 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 1382 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1383 if (wb) {
Chris@434 1384 sv_frame_t spaceHere = wb->getWriteSpace();
Chris@43 1385 if (c == 0 || spaceHere < space) space = spaceHere;
Chris@43 1386 }
Chris@43 1387 }
Chris@43 1388
Chris@103 1389 if (space == 0) {
Chris@103 1390 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1391 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl;
Chris@103 1392 #endif
Chris@103 1393 return false;
Chris@103 1394 }
Chris@43 1395
Chris@434 1396 sv_frame_t f = m_writeBufferFill;
Chris@43 1397
Chris@43 1398 bool readWriteEqual = (m_readBuffers == m_writeBuffers);
Chris@43 1399
Chris@43 1400 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@193 1401 if (!readWriteEqual) {
Chris@293 1402 cout << "AudioCallbackPlaySourceFillThread: note read buffers != write buffers" << endl;
Chris@193 1403 }
Chris@293 1404 cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << endl;
Chris@43 1405 #endif
Chris@43 1406
Chris@43 1407 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1408 cout << "buffered to " << f << " already" << endl;
Chris@43 1409 #endif
Chris@43 1410
Chris@43 1411 bool resample = (getSourceSampleRate() != getTargetSampleRate());
Chris@43 1412
Chris@43 1413 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1414 cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << endl;
Chris@43 1415 #endif
Chris@43 1416
Chris@366 1417 int channels = getTargetChannelCount();
Chris@43 1418
Chris@434 1419 sv_frame_t orig = space;
Chris@434 1420 sv_frame_t got = 0;
Chris@43 1421
Chris@43 1422 static float **bufferPtrs = 0;
Chris@366 1423 static int bufferPtrCount = 0;
Chris@43 1424
Chris@43 1425 if (bufferPtrCount < channels) {
Chris@43 1426 if (bufferPtrs) delete[] bufferPtrs;
Chris@43 1427 bufferPtrs = new float *[channels];
Chris@43 1428 bufferPtrCount = channels;
Chris@43 1429 }
Chris@43 1430
Chris@436 1431 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize();
Chris@43 1432
Chris@43 1433 if (resample && !m_converter) {
Chris@43 1434 static bool warned = false;
Chris@43 1435 if (!warned) {
Chris@293 1436 cerr << "WARNING: sample rates differ, but no converter available!" << endl;
Chris@43 1437 warned = true;
Chris@43 1438 }
Chris@43 1439 }
Chris@43 1440
Chris@43 1441 if (resample && m_converter) {
Chris@43 1442
Chris@43 1443 double ratio =
Chris@43 1444 double(getTargetSampleRate()) / double(getSourceSampleRate());
Chris@436 1445 orig = sv_frame_t(double(orig) / ratio + 0.1);
Chris@43 1446
Chris@43 1447 // orig must be a multiple of generatorBlockSize
Chris@43 1448 orig = (orig / generatorBlockSize) * generatorBlockSize;
Chris@43 1449 if (orig == 0) return false;
Chris@43 1450
Chris@436 1451 sv_frame_t work = std::max(orig, space);
Chris@43 1452
Chris@43 1453 // We only allocate one buffer, but we use it in two halves.
Chris@43 1454 // We place the non-interleaved values in the second half of
Chris@43 1455 // the buffer (orig samples for channel 0, orig samples for
Chris@43 1456 // channel 1 etc), and then interleave them into the first
Chris@43 1457 // half of the buffer. Then we resample back into the second
Chris@43 1458 // half (interleaved) and de-interleave the results back to
Chris@43 1459 // the start of the buffer for insertion into the ringbuffers.
Chris@43 1460 // What a faff -- especially as we've already de-interleaved
Chris@43 1461 // the audio data from the source file elsewhere before we
Chris@43 1462 // even reach this point.
Chris@43 1463
Chris@43 1464 if (tmpSize < channels * work * 2) {
Chris@43 1465 delete[] tmp;
Chris@43 1466 tmp = new float[channels * work * 2];
Chris@43 1467 tmpSize = channels * work * 2;
Chris@43 1468 }
Chris@43 1469
Chris@43 1470 float *nonintlv = tmp + channels * work;
Chris@43 1471 float *intlv = tmp;
Chris@43 1472 float *srcout = tmp + channels * work;
Chris@43 1473
Chris@366 1474 for (int c = 0; c < channels; ++c) {
Chris@366 1475 for (int i = 0; i < orig; ++i) {
Chris@43 1476 nonintlv[channels * i + c] = 0.0f;
Chris@43 1477 }
Chris@43 1478 }
Chris@43 1479
Chris@366 1480 for (int c = 0; c < channels; ++c) {
Chris@43 1481 bufferPtrs[c] = nonintlv + c * orig;
Chris@43 1482 }
Chris@43 1483
Chris@163 1484 got = mixModels(f, orig, bufferPtrs); // also modifies f
Chris@43 1485
Chris@43 1486 // and interleave into first half
Chris@366 1487 for (int c = 0; c < channels; ++c) {
Chris@366 1488 for (int i = 0; i < got; ++i) {
Chris@43 1489 float sample = nonintlv[c * got + i];
Chris@43 1490 intlv[channels * i + c] = sample;
Chris@43 1491 }
Chris@43 1492 }
Chris@43 1493
Chris@43 1494 SRC_DATA data;
Chris@43 1495 data.data_in = intlv;
Chris@43 1496 data.data_out = srcout;
Chris@463 1497 data.input_frames = long(got);
Chris@463 1498 data.output_frames = long(work);
Chris@43 1499 data.src_ratio = ratio;
Chris@43 1500 data.end_of_input = 0;
Chris@43 1501
Chris@43 1502 int err = 0;
Chris@43 1503
Chris@62 1504 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
Chris@43 1505 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1506 cout << "Using crappy converter" << endl;
Chris@43 1507 #endif
Chris@43 1508 err = src_process(m_crapConverter, &data);
Chris@43 1509 } else {
Chris@43 1510 err = src_process(m_converter, &data);
Chris@43 1511 }
Chris@43 1512
Chris@436 1513 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1);
Chris@43 1514
Chris@43 1515 if (err) {
Chris@293 1516 cerr
Chris@43 1517 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: "
Chris@293 1518 << src_strerror(err) << endl;
Chris@43 1519 //!!! Then what?
Chris@43 1520 } else {
Chris@43 1521 got = data.input_frames_used;
Chris@43 1522 toCopy = data.output_frames_gen;
Chris@43 1523 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1524 cout << "Resampled " << got << " frames to " << toCopy << " frames" << endl;
Chris@43 1525 #endif
Chris@43 1526 }
Chris@43 1527
Chris@366 1528 for (int c = 0; c < channels; ++c) {
Chris@366 1529 for (int i = 0; i < toCopy; ++i) {
Chris@43 1530 tmp[i] = srcout[channels * i + c];
Chris@43 1531 }
Chris@43 1532 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@436 1533 if (wb) wb->write(tmp, int(toCopy));
Chris@43 1534 }
Chris@43 1535
Chris@43 1536 m_writeBufferFill = f;
Chris@43 1537 if (readWriteEqual) m_readBufferFill = f;
Chris@43 1538
Chris@43 1539 } else {
Chris@43 1540
Chris@43 1541 // space must be a multiple of generatorBlockSize
Chris@436 1542 sv_frame_t reqSpace = space;
Chris@195 1543 space = (reqSpace / generatorBlockSize) * generatorBlockSize;
Chris@91 1544 if (space == 0) {
Chris@91 1545 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1546 cout << "requested fill of " << reqSpace
Chris@195 1547 << " is less than generator block size of "
Chris@293 1548 << generatorBlockSize << ", leaving it" << endl;
Chris@91 1549 #endif
Chris@91 1550 return false;
Chris@91 1551 }
Chris@43 1552
Chris@43 1553 if (tmpSize < channels * space) {
Chris@43 1554 delete[] tmp;
Chris@43 1555 tmp = new float[channels * space];
Chris@43 1556 tmpSize = channels * space;
Chris@43 1557 }
Chris@43 1558
Chris@366 1559 for (int c = 0; c < channels; ++c) {
Chris@43 1560
Chris@43 1561 bufferPtrs[c] = tmp + c * space;
Chris@43 1562
Chris@366 1563 for (int i = 0; i < space; ++i) {
Chris@43 1564 tmp[c * space + i] = 0.0f;
Chris@43 1565 }
Chris@43 1566 }
Chris@43 1567
Chris@436 1568 sv_frame_t got = mixModels(f, space, bufferPtrs); // also modifies f
Chris@43 1569
Chris@366 1570 for (int c = 0; c < channels; ++c) {
Chris@43 1571
Chris@43 1572 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1573 if (wb) {
Chris@436 1574 int actual = wb->write(bufferPtrs[c], int(got));
Chris@43 1575 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1576 cout << "Wrote " << actual << " samples for ch " << c << ", now "
Chris@43 1577 << wb->getReadSpace() << " to read"
Chris@293 1578 << endl;
Chris@43 1579 #endif
Chris@43 1580 if (actual < got) {
Chris@293 1581 cerr << "WARNING: Buffer overrun in channel " << c
Chris@43 1582 << ": wrote " << actual << " of " << got
Chris@293 1583 << " samples" << endl;
Chris@43 1584 }
Chris@43 1585 }
Chris@43 1586 }
Chris@43 1587
Chris@43 1588 m_writeBufferFill = f;
Chris@43 1589 if (readWriteEqual) m_readBufferFill = f;
Chris@43 1590
Chris@163 1591 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1592 cout << "Read buffer fill is now " << m_readBufferFill << endl;
Chris@163 1593 #endif
Chris@163 1594
Chris@43 1595 //!!! how do we know when ended? need to mark up a fully-buffered flag and check this if we find the buffers empty in getSourceSamples
Chris@43 1596 }
Chris@43 1597
Chris@43 1598 return true;
Chris@43 1599 }
Chris@43 1600
Chris@434 1601 sv_frame_t
Chris@434 1602 AudioCallbackPlaySource::mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers)
Chris@43 1603 {
Chris@434 1604 sv_frame_t processed = 0;
Chris@434 1605 sv_frame_t chunkStart = frame;
Chris@434 1606 sv_frame_t chunkSize = count;
Chris@434 1607 sv_frame_t selectionSize = 0;
Chris@434 1608 sv_frame_t nextChunkStart = chunkStart + chunkSize;
Chris@43 1609
Chris@43 1610 bool looping = m_viewManager->getPlayLoopMode();
Chris@43 1611 bool constrained = (m_viewManager->getPlaySelectionMode() &&
Chris@43 1612 !m_viewManager->getSelections().empty());
Chris@43 1613
Chris@43 1614 static float **chunkBufferPtrs = 0;
Chris@366 1615 static int chunkBufferPtrCount = 0;
Chris@366 1616 int channels = getTargetChannelCount();
Chris@43 1617
Chris@43 1618 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1619 cout << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << endl;
Chris@43 1620 #endif
Chris@43 1621
Chris@43 1622 if (chunkBufferPtrCount < channels) {
Chris@43 1623 if (chunkBufferPtrs) delete[] chunkBufferPtrs;
Chris@43 1624 chunkBufferPtrs = new float *[channels];
Chris@43 1625 chunkBufferPtrCount = channels;
Chris@43 1626 }
Chris@43 1627
Chris@366 1628 for (int c = 0; c < channels; ++c) {
Chris@43 1629 chunkBufferPtrs[c] = buffers[c];
Chris@43 1630 }
Chris@43 1631
Chris@43 1632 while (processed < count) {
Chris@43 1633
Chris@43 1634 chunkSize = count - processed;
Chris@43 1635 nextChunkStart = chunkStart + chunkSize;
Chris@43 1636 selectionSize = 0;
Chris@43 1637
Chris@434 1638 sv_frame_t fadeIn = 0, fadeOut = 0;
Chris@43 1639
Chris@43 1640 if (constrained) {
Chris@60 1641
Chris@434 1642 sv_frame_t rChunkStart =
Chris@60 1643 m_viewManager->alignPlaybackFrameToReference(chunkStart);
Chris@43 1644
Chris@43 1645 Selection selection =
Chris@60 1646 m_viewManager->getContainingSelection(rChunkStart, true);
Chris@43 1647
Chris@43 1648 if (selection.isEmpty()) {
Chris@43 1649 if (looping) {
Chris@43 1650 selection = *m_viewManager->getSelections().begin();
Chris@60 1651 chunkStart = m_viewManager->alignReferenceToPlaybackFrame
Chris@60 1652 (selection.getStartFrame());
Chris@43 1653 fadeIn = 50;
Chris@43 1654 }
Chris@43 1655 }
Chris@43 1656
Chris@43 1657 if (selection.isEmpty()) {
Chris@43 1658
Chris@43 1659 chunkSize = 0;
Chris@43 1660 nextChunkStart = chunkStart;
Chris@43 1661
Chris@43 1662 } else {
Chris@43 1663
Chris@434 1664 sv_frame_t sf = m_viewManager->alignReferenceToPlaybackFrame
Chris@60 1665 (selection.getStartFrame());
Chris@434 1666 sv_frame_t ef = m_viewManager->alignReferenceToPlaybackFrame
Chris@60 1667 (selection.getEndFrame());
Chris@43 1668
Chris@60 1669 selectionSize = ef - sf;
Chris@60 1670
Chris@60 1671 if (chunkStart < sf) {
Chris@60 1672 chunkStart = sf;
Chris@43 1673 fadeIn = 50;
Chris@43 1674 }
Chris@43 1675
Chris@43 1676 nextChunkStart = chunkStart + chunkSize;
Chris@43 1677
Chris@60 1678 if (nextChunkStart >= ef) {
Chris@60 1679 nextChunkStart = ef;
Chris@43 1680 fadeOut = 50;
Chris@43 1681 }
Chris@43 1682
Chris@43 1683 chunkSize = nextChunkStart - chunkStart;
Chris@43 1684 }
Chris@43 1685
Chris@43 1686 } else if (looping && m_lastModelEndFrame > 0) {
Chris@43 1687
Chris@43 1688 if (chunkStart >= m_lastModelEndFrame) {
Chris@43 1689 chunkStart = 0;
Chris@43 1690 }
Chris@43 1691 if (chunkSize > m_lastModelEndFrame - chunkStart) {
Chris@43 1692 chunkSize = m_lastModelEndFrame - chunkStart;
Chris@43 1693 }
Chris@43 1694 nextChunkStart = chunkStart + chunkSize;
Chris@43 1695 }
Chris@43 1696
Chris@293 1697 // cout << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << endl;
Chris@43 1698
Chris@43 1699 if (!chunkSize) {
Chris@43 1700 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1701 cout << "Ending selection playback at " << nextChunkStart << endl;
Chris@43 1702 #endif
Chris@43 1703 // We need to maintain full buffers so that the other
Chris@43 1704 // thread can tell where it's got to in the playback -- so
Chris@43 1705 // return the full amount here
Chris@43 1706 frame = frame + count;
Chris@43 1707 return count;
Chris@43 1708 }
Chris@43 1709
Chris@43 1710 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1711 cout << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << endl;
Chris@43 1712 #endif
Chris@43 1713
Chris@43 1714 if (selectionSize < 100) {
Chris@43 1715 fadeIn = 0;
Chris@43 1716 fadeOut = 0;
Chris@43 1717 } else if (selectionSize < 300) {
Chris@43 1718 if (fadeIn > 0) fadeIn = 10;
Chris@43 1719 if (fadeOut > 0) fadeOut = 10;
Chris@43 1720 }
Chris@43 1721
Chris@43 1722 if (fadeIn > 0) {
Chris@43 1723 if (processed * 2 < fadeIn) {
Chris@43 1724 fadeIn = processed * 2;
Chris@43 1725 }
Chris@43 1726 }
Chris@43 1727
Chris@43 1728 if (fadeOut > 0) {
Chris@43 1729 if ((count - processed - chunkSize) * 2 < fadeOut) {
Chris@43 1730 fadeOut = (count - processed - chunkSize) * 2;
Chris@43 1731 }
Chris@43 1732 }
Chris@43 1733
Chris@43 1734 for (std::set<Model *>::iterator mi = m_models.begin();
Chris@43 1735 mi != m_models.end(); ++mi) {
Chris@43 1736
Chris@366 1737 (void) m_audioGenerator->mixModel(*mi, chunkStart,
Chris@366 1738 chunkSize, chunkBufferPtrs,
Chris@366 1739 fadeIn, fadeOut);
Chris@43 1740 }
Chris@43 1741
Chris@366 1742 for (int c = 0; c < channels; ++c) {
Chris@43 1743 chunkBufferPtrs[c] += chunkSize;
Chris@43 1744 }
Chris@43 1745
Chris@43 1746 processed += chunkSize;
Chris@43 1747 chunkStart = nextChunkStart;
Chris@43 1748 }
Chris@43 1749
Chris@43 1750 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1751 cout << "Returning selection playback " << processed << " frames to " << nextChunkStart << endl;
Chris@43 1752 #endif
Chris@43 1753
Chris@43 1754 frame = nextChunkStart;
Chris@43 1755 return processed;
Chris@43 1756 }
Chris@43 1757
Chris@43 1758 void
Chris@43 1759 AudioCallbackPlaySource::unifyRingBuffers()
Chris@43 1760 {
Chris@43 1761 if (m_readBuffers == m_writeBuffers) return;
Chris@43 1762
Chris@43 1763 // only unify if there will be something to read
Chris@366 1764 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 1765 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1766 if (wb) {
Chris@43 1767 if (wb->getReadSpace() < m_blockSize * 2) {
Chris@43 1768 if ((m_writeBufferFill + m_blockSize * 2) <
Chris@43 1769 m_lastModelEndFrame) {
Chris@43 1770 // OK, we don't have enough and there's more to
Chris@43 1771 // read -- don't unify until we can do better
Chris@193 1772 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1773 SVDEBUG << "AudioCallbackPlaySource::unifyRingBuffers: Not unifying: write buffer has less (" << wb->getReadSpace() << ") than " << m_blockSize*2 << " to read and write buffer fill (" << m_writeBufferFill << ") is not close to end frame (" << m_lastModelEndFrame << ")" << endl;
Chris@193 1774 #endif
Chris@43 1775 return;
Chris@43 1776 }
Chris@43 1777 }
Chris@43 1778 break;
Chris@43 1779 }
Chris@43 1780 }
Chris@43 1781
Chris@436 1782 sv_frame_t rf = m_readBufferFill;
Chris@43 1783 RingBuffer<float> *rb = getReadRingBuffer(0);
Chris@43 1784 if (rb) {
Chris@366 1785 int rs = rb->getReadSpace();
Chris@43 1786 //!!! incorrect when in non-contiguous selection, see comments elsewhere
Chris@293 1787 // cout << "rs = " << rs << endl;
Chris@43 1788 if (rs < rf) rf -= rs;
Chris@43 1789 else rf = 0;
Chris@43 1790 }
Chris@43 1791
Chris@193 1792 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1793 SVDEBUG << "AudioCallbackPlaySource::unifyRingBuffers: m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << endl;
Chris@193 1794 #endif
Chris@43 1795
Chris@436 1796 sv_frame_t wf = m_writeBufferFill;
Chris@436 1797 sv_frame_t skip = 0;
Chris@366 1798 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 1799 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1800 if (wb) {
Chris@43 1801 if (c == 0) {
Chris@43 1802
Chris@366 1803 int wrs = wb->getReadSpace();
Chris@293 1804 // cout << "wrs = " << wrs << endl;
Chris@43 1805
Chris@43 1806 if (wrs < wf) wf -= wrs;
Chris@43 1807 else wf = 0;
Chris@293 1808 // cout << "wf = " << wf << endl;
Chris@43 1809
Chris@43 1810 if (wf < rf) skip = rf - wf;
Chris@43 1811 if (skip == 0) break;
Chris@43 1812 }
Chris@43 1813
Chris@293 1814 // cout << "skipping " << skip << endl;
Chris@436 1815 wb->skip(int(skip));
Chris@43 1816 }
Chris@43 1817 }
Chris@43 1818
Chris@43 1819 m_bufferScavenger.claim(m_readBuffers);
Chris@43 1820 m_readBuffers = m_writeBuffers;
Chris@43 1821 m_readBufferFill = m_writeBufferFill;
Chris@193 1822 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 1823 cerr << "unified" << endl;
Chris@193 1824 #endif
Chris@43 1825 }
Chris@43 1826
Chris@43 1827 void
Chris@43 1828 AudioCallbackPlaySource::FillThread::run()
Chris@43 1829 {
Chris@43 1830 AudioCallbackPlaySource &s(m_source);
Chris@43 1831
Chris@43 1832 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1833 cout << "AudioCallbackPlaySourceFillThread starting" << endl;
Chris@43 1834 #endif
Chris@43 1835
Chris@43 1836 s.m_mutex.lock();
Chris@43 1837
Chris@43 1838 bool previouslyPlaying = s.m_playing;
Chris@43 1839 bool work = false;
Chris@43 1840
Chris@43 1841 while (!s.m_exiting) {
Chris@43 1842
Chris@43 1843 s.unifyRingBuffers();
Chris@43 1844 s.m_bufferScavenger.scavenge();
Chris@43 1845 s.m_pluginScavenger.scavenge();
Chris@43 1846
Chris@43 1847 if (work && s.m_playing && s.getSourceSampleRate()) {
Chris@43 1848
Chris@43 1849 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1850 cout << "AudioCallbackPlaySourceFillThread: not waiting" << endl;
Chris@43 1851 #endif
Chris@43 1852
Chris@43 1853 s.m_mutex.unlock();
Chris@43 1854 s.m_mutex.lock();
Chris@43 1855
Chris@43 1856 } else {
Chris@43 1857
Chris@436 1858 double ms = 100;
Chris@43 1859 if (s.getSourceSampleRate() > 0) {
Chris@436 1860 ms = double(s.m_ringBufferSize) / s.getSourceSampleRate() * 1000.0;
Chris@43 1861 }
Chris@43 1862
Chris@43 1863 if (s.m_playing) ms /= 10;
Chris@43 1864
Chris@43 1865 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1866 if (!s.m_playing) cout << endl;
Chris@293 1867 cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << endl;
Chris@43 1868 #endif
Chris@43 1869
Chris@366 1870 s.m_condition.wait(&s.m_mutex, int(ms));
Chris@43 1871 }
Chris@43 1872
Chris@43 1873 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1874 cout << "AudioCallbackPlaySourceFillThread: awoken" << endl;
Chris@43 1875 #endif
Chris@43 1876
Chris@43 1877 work = false;
Chris@43 1878
Chris@103 1879 if (!s.getSourceSampleRate()) {
Chris@103 1880 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1881 cout << "AudioCallbackPlaySourceFillThread: source sample rate is zero" << endl;
Chris@103 1882 #endif
Chris@103 1883 continue;
Chris@103 1884 }
Chris@43 1885
Chris@43 1886 bool playing = s.m_playing;
Chris@43 1887
Chris@43 1888 if (playing && !previouslyPlaying) {
Chris@43 1889 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1890 cout << "AudioCallbackPlaySourceFillThread: playback state changed, resetting" << endl;
Chris@43 1891 #endif
Chris@366 1892 for (int c = 0; c < s.getTargetChannelCount(); ++c) {
Chris@43 1893 RingBuffer<float> *rb = s.getReadRingBuffer(c);
Chris@43 1894 if (rb) rb->reset();
Chris@43 1895 }
Chris@43 1896 }
Chris@43 1897 previouslyPlaying = playing;
Chris@43 1898
Chris@43 1899 work = s.fillBuffers();
Chris@43 1900 }
Chris@43 1901
Chris@43 1902 s.m_mutex.unlock();
Chris@43 1903 }
Chris@43 1904