annotate audioio/AudioCallbackPlaySource.cpp @ 451:dc1a360f2b69

Allow layers to be loaded without models if their layer class explicitly says it's OK (otherwise default template won't load, as it has an empty waveform layer)
author Chris Cannam
date Mon, 20 Apr 2015 10:10:26 +0100
parents c48bc6ddfe17
children 3e2a2ca24d90
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@91 29 #include "AudioCallbackPlayTarget.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@57 46 m_clientName(clientName),
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@43 425 if (startFrame >= m_lastModelEndFrame) {
Chris@43 426 startFrame = 0;
Chris@43 427 }
Chris@43 428 }
Chris@43 429
Chris@132 430 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 431 cerr << "play(" << startFrame << ") -> playback model ";
Chris@132 432 #endif
Chris@60 433
Chris@60 434 startFrame = m_viewManager->alignReferenceToPlaybackFrame(startFrame);
Chris@60 435
Chris@189 436 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 437 cerr << startFrame << endl;
Chris@189 438 #endif
Chris@60 439
Chris@43 440 // The fill thread will automatically empty its buffers before
Chris@43 441 // starting again if we have not so far been playing, but not if
Chris@43 442 // we're just re-seeking.
Chris@102 443 // NO -- we can end up playing some first -- always reset here
Chris@43 444
Chris@43 445 m_mutex.lock();
Chris@102 446
Chris@91 447 if (m_timeStretcher) {
Chris@91 448 m_timeStretcher->reset();
Chris@91 449 }
Chris@130 450 if (m_monoStretcher) {
Chris@130 451 m_monoStretcher->reset();
Chris@130 452 }
Chris@102 453
Chris@102 454 m_readBufferFill = m_writeBufferFill = startFrame;
Chris@102 455 if (m_readBuffers) {
Chris@366 456 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@102 457 RingBuffer<float> *rb = getReadRingBuffer(c);
Chris@132 458 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 459 cerr << "reset ring buffer for channel " << c << endl;
Chris@132 460 #endif
Chris@102 461 if (rb) rb->reset();
Chris@102 462 }
Chris@43 463 }
Chris@102 464 if (m_converter) src_reset(m_converter);
Chris@102 465 if (m_crapConverter) src_reset(m_crapConverter);
Chris@102 466
Chris@43 467 m_mutex.unlock();
Chris@43 468
Chris@43 469 m_audioGenerator->reset();
Chris@43 470
Chris@94 471 m_playStartFrame = startFrame;
Chris@94 472 m_playStartFramePassed = false;
Chris@94 473 m_playStartedAt = RealTime::zeroTime;
Chris@94 474 if (m_target) {
Chris@94 475 m_playStartedAt = RealTime::fromSeconds(m_target->getCurrentTime());
Chris@94 476 }
Chris@94 477
Chris@43 478 bool changed = !m_playing;
Chris@91 479 m_lastRetrievalTimestamp = 0;
Chris@102 480 m_lastCurrentFrame = 0;
Chris@43 481 m_playing = true;
Chris@212 482
Chris@212 483 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 484 cout << "AudioCallbackPlaySource::play: awakening thread" << endl;
Chris@212 485 #endif
Chris@212 486
Chris@43 487 m_condition.wakeAll();
Chris@158 488 if (changed) {
Chris@158 489 emit playStatusChanged(m_playing);
Chris@158 490 emit activity(tr("Play from %1").arg
Chris@158 491 (RealTime::frame2RealTime
Chris@158 492 (m_playStartFrame, m_sourceSampleRate).toText().c_str()));
Chris@158 493 }
Chris@43 494 }
Chris@43 495
Chris@43 496 void
Chris@43 497 AudioCallbackPlaySource::stop()
Chris@43 498 {
Chris@212 499 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 500 SVDEBUG << "AudioCallbackPlaySource::stop()" << endl;
Chris@212 501 #endif
Chris@43 502 bool changed = m_playing;
Chris@43 503 m_playing = false;
Chris@212 504
Chris@212 505 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 506 cout << "AudioCallbackPlaySource::stop: awakening thread" << endl;
Chris@212 507 #endif
Chris@212 508
Chris@43 509 m_condition.wakeAll();
Chris@91 510 m_lastRetrievalTimestamp = 0;
Chris@158 511 if (changed) {
Chris@158 512 emit playStatusChanged(m_playing);
Chris@158 513 emit activity(tr("Stop at %1").arg
Chris@158 514 (RealTime::frame2RealTime
Chris@158 515 (m_lastCurrentFrame, m_sourceSampleRate).toText().c_str()));
Chris@158 516 }
Chris@102 517 m_lastCurrentFrame = 0;
Chris@43 518 }
Chris@43 519
Chris@43 520 void
Chris@43 521 AudioCallbackPlaySource::selectionChanged()
Chris@43 522 {
Chris@43 523 if (m_viewManager->getPlaySelectionMode()) {
Chris@43 524 clearRingBuffers();
Chris@43 525 }
Chris@43 526 }
Chris@43 527
Chris@43 528 void
Chris@43 529 AudioCallbackPlaySource::playLoopModeChanged()
Chris@43 530 {
Chris@43 531 clearRingBuffers();
Chris@43 532 }
Chris@43 533
Chris@43 534 void
Chris@43 535 AudioCallbackPlaySource::playSelectionModeChanged()
Chris@43 536 {
Chris@43 537 if (!m_viewManager->getSelections().empty()) {
Chris@43 538 clearRingBuffers();
Chris@43 539 }
Chris@43 540 }
Chris@43 541
Chris@43 542 void
Chris@43 543 AudioCallbackPlaySource::playParametersChanged(PlayParameters *)
Chris@43 544 {
Chris@43 545 clearRingBuffers();
Chris@43 546 }
Chris@43 547
Chris@43 548 void
Chris@43 549 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n)
Chris@43 550 {
Chris@43 551 if (n == "Resample Quality") {
Chris@43 552 setResampleQuality(Preferences::getInstance()->getResampleQuality());
Chris@43 553 }
Chris@43 554 }
Chris@43 555
Chris@43 556 void
Chris@43 557 AudioCallbackPlaySource::audioProcessingOverload()
Chris@43 558 {
Chris@293 559 cerr << "Audio processing overload!" << endl;
Chris@130 560
Chris@130 561 if (!m_playing) return;
Chris@130 562
Chris@43 563 RealTimePluginInstance *ap = m_auditioningPlugin;
Chris@130 564 if (ap && !m_auditioningPluginBypassed) {
Chris@43 565 m_auditioningPluginBypassed = true;
Chris@43 566 emit audioOverloadPluginDisabled();
Chris@130 567 return;
Chris@130 568 }
Chris@130 569
Chris@130 570 if (m_timeStretcher &&
Chris@130 571 m_timeStretcher->getTimeRatio() < 1.0 &&
Chris@130 572 m_stretcherInputCount > 1 &&
Chris@130 573 m_monoStretcher && !m_stretchMono) {
Chris@130 574 m_stretchMono = true;
Chris@130 575 emit audioTimeStretchMultiChannelDisabled();
Chris@130 576 return;
Chris@43 577 }
Chris@43 578 }
Chris@43 579
Chris@43 580 void
Chris@366 581 AudioCallbackPlaySource::setTarget(AudioCallbackPlayTarget *target, int size)
Chris@43 582 {
Chris@91 583 m_target = target;
Chris@293 584 cout << "AudioCallbackPlaySource::setTarget: Block size -> " << size << endl;
Chris@193 585 if (size != 0) {
Chris@193 586 m_blockSize = size;
Chris@193 587 }
Chris@193 588 if (size * 4 > m_ringBufferSize) {
Chris@233 589 SVDEBUG << "AudioCallbackPlaySource::setTarget: Buffer size "
Chris@193 590 << size << " > a quarter of ring buffer size "
Chris@193 591 << m_ringBufferSize << ", calling for more ring buffer"
Chris@229 592 << endl;
Chris@193 593 m_ringBufferSize = size * 4;
Chris@193 594 if (m_writeBuffers && !m_writeBuffers->empty()) {
Chris@193 595 clearRingBuffers();
Chris@193 596 }
Chris@193 597 }
Chris@43 598 }
Chris@43 599
Chris@366 600 int
Chris@43 601 AudioCallbackPlaySource::getTargetBlockSize() const
Chris@43 602 {
Chris@293 603 // cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << endl;
Chris@436 604 return int(m_blockSize);
Chris@43 605 }
Chris@43 606
Chris@43 607 void
Chris@434 608 AudioCallbackPlaySource::setTargetPlayLatency(sv_frame_t latency)
Chris@43 609 {
Chris@43 610 m_playLatency = latency;
Chris@43 611 }
Chris@43 612
Chris@434 613 sv_frame_t
Chris@43 614 AudioCallbackPlaySource::getTargetPlayLatency() const
Chris@43 615 {
Chris@43 616 return m_playLatency;
Chris@43 617 }
Chris@43 618
Chris@434 619 sv_frame_t
Chris@43 620 AudioCallbackPlaySource::getCurrentPlayingFrame()
Chris@43 621 {
Chris@91 622 // This method attempts to estimate which audio sample frame is
Chris@91 623 // "currently coming through the speakers".
Chris@91 624
Chris@436 625 sv_samplerate_t targetRate = getTargetSampleRate();
Chris@436 626 sv_frame_t latency = m_playLatency; // at target rate
Chris@402 627 RealTime latency_t = RealTime::zeroTime;
Chris@402 628
Chris@402 629 if (targetRate != 0) {
Chris@402 630 latency_t = RealTime::frame2RealTime(latency, targetRate);
Chris@402 631 }
Chris@93 632
Chris@93 633 return getCurrentFrame(latency_t);
Chris@93 634 }
Chris@93 635
Chris@434 636 sv_frame_t
Chris@93 637 AudioCallbackPlaySource::getCurrentBufferedFrame()
Chris@93 638 {
Chris@93 639 return getCurrentFrame(RealTime::zeroTime);
Chris@93 640 }
Chris@93 641
Chris@434 642 sv_frame_t
Chris@93 643 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t)
Chris@93 644 {
Chris@91 645 // We resample when filling the ring buffer, and time-stretch when
Chris@91 646 // draining it. The buffer contains data at the "target rate" and
Chris@91 647 // the latency provided by the target is also at the target rate.
Chris@91 648 // Because of the multiple rates involved, we do the actual
Chris@91 649 // calculation using RealTime instead.
Chris@43 650
Chris@434 651 sv_samplerate_t sourceRate = getSourceSampleRate();
Chris@434 652 sv_samplerate_t targetRate = getTargetSampleRate();
Chris@91 653
Chris@91 654 if (sourceRate == 0 || targetRate == 0) return 0;
Chris@91 655
Chris@366 656 int inbuffer = 0; // at target rate
Chris@91 657
Chris@366 658 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 659 RingBuffer<float> *rb = getReadRingBuffer(c);
Chris@43 660 if (rb) {
Chris@366 661 int here = rb->getReadSpace();
Chris@91 662 if (c == 0 || here < inbuffer) inbuffer = here;
Chris@43 663 }
Chris@43 664 }
Chris@43 665
Chris@436 666 sv_frame_t readBufferFill = m_readBufferFill;
Chris@436 667 sv_frame_t lastRetrievedBlockSize = m_lastRetrievedBlockSize;
Chris@91 668 double lastRetrievalTimestamp = m_lastRetrievalTimestamp;
Chris@91 669 double currentTime = 0.0;
Chris@91 670 if (m_target) currentTime = m_target->getCurrentTime();
Chris@91 671
Chris@102 672 bool looping = m_viewManager->getPlayLoopMode();
Chris@102 673
Chris@91 674 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate);
Chris@91 675
Chris@436 676 sv_frame_t stretchlat = 0;
Chris@91 677 double timeRatio = 1.0;
Chris@91 678
Chris@91 679 if (m_timeStretcher) {
Chris@91 680 stretchlat = m_timeStretcher->getLatency();
Chris@91 681 timeRatio = m_timeStretcher->getTimeRatio();
Chris@43 682 }
Chris@43 683
Chris@91 684 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate);
Chris@43 685
Chris@91 686 // When the target has just requested a block from us, the last
Chris@91 687 // sample it obtained was our buffer fill frame count minus the
Chris@91 688 // amount of read space (converted back to source sample rate)
Chris@91 689 // remaining now. That sample is not expected to be played until
Chris@91 690 // the target's play latency has elapsed. By the time the
Chris@91 691 // following block is requested, that sample will be at the
Chris@91 692 // target's play latency minus the last requested block size away
Chris@91 693 // from being played.
Chris@91 694
Chris@91 695 RealTime sincerequest_t = RealTime::zeroTime;
Chris@91 696 RealTime lastretrieved_t = RealTime::zeroTime;
Chris@91 697
Chris@102 698 if (m_target &&
Chris@102 699 m_trustworthyTimestamps &&
Chris@102 700 lastRetrievalTimestamp != 0.0) {
Chris@91 701
Chris@91 702 lastretrieved_t = RealTime::frame2RealTime
Chris@91 703 (lastRetrievedBlockSize, targetRate);
Chris@91 704
Chris@91 705 // calculate number of frames at target rate that have elapsed
Chris@91 706 // since the end of the last call to getSourceSamples
Chris@91 707
Chris@102 708 if (m_trustworthyTimestamps && !looping) {
Chris@91 709
Chris@102 710 // this adjustment seems to cause more problems when looping
Chris@102 711 double elapsed = currentTime - lastRetrievalTimestamp;
Chris@102 712
Chris@102 713 if (elapsed > 0.0) {
Chris@102 714 sincerequest_t = RealTime::fromSeconds(elapsed);
Chris@102 715 }
Chris@91 716 }
Chris@91 717
Chris@91 718 } else {
Chris@91 719
Chris@91 720 lastretrieved_t = RealTime::frame2RealTime
Chris@91 721 (getTargetBlockSize(), targetRate);
Chris@62 722 }
Chris@91 723
Chris@91 724 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate);
Chris@91 725
Chris@91 726 if (timeRatio != 1.0) {
Chris@91 727 lastretrieved_t = lastretrieved_t / timeRatio;
Chris@91 728 sincerequest_t = sincerequest_t / timeRatio;
Chris@163 729 latency_t = latency_t / timeRatio;
Chris@43 730 }
Chris@43 731
Chris@91 732 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 733 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 734 #endif
Chris@43 735
Chris@93 736 // Normally the range lists should contain at least one item each
Chris@93 737 // -- if playback is unconstrained, that item should report the
Chris@93 738 // entire source audio duration.
Chris@43 739
Chris@93 740 if (m_rangeStarts.empty()) {
Chris@93 741 rebuildRangeLists();
Chris@93 742 }
Chris@92 743
Chris@93 744 if (m_rangeStarts.empty()) {
Chris@93 745 // this code is only used in case of error in rebuildRangeLists
Chris@93 746 RealTime playing_t = bufferedto_t
Chris@93 747 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
Chris@93 748 + sincerequest_t;
Chris@193 749 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
Chris@434 750 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
Chris@93 751 return m_viewManager->alignPlaybackFrameToReference(frame);
Chris@93 752 }
Chris@43 753
Chris@91 754 int inRange = 0;
Chris@91 755 int index = 0;
Chris@91 756
Chris@366 757 for (int i = 0; i < (int)m_rangeStarts.size(); ++i) {
Chris@93 758 if (bufferedto_t >= m_rangeStarts[i]) {
Chris@93 759 inRange = index;
Chris@93 760 } else {
Chris@93 761 break;
Chris@93 762 }
Chris@93 763 ++index;
Chris@93 764 }
Chris@93 765
Chris@436 766 if (inRange >= int(m_rangeStarts.size())) {
Chris@436 767 inRange = int(m_rangeStarts.size())-1;
Chris@436 768 }
Chris@93 769
Chris@94 770 RealTime playing_t = bufferedto_t;
Chris@93 771
Chris@93 772 playing_t = playing_t
Chris@93 773 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
Chris@93 774 + sincerequest_t;
Chris@94 775
Chris@94 776 // This rather gross little hack is used to ensure that latency
Chris@94 777 // compensation doesn't result in the playback pointer appearing
Chris@94 778 // to start earlier than the actual playback does. It doesn't
Chris@94 779 // work properly (hence the bail-out in the middle) because if we
Chris@94 780 // are playing a relatively short looped region, the playing time
Chris@94 781 // estimated from the buffer fill frame may have wrapped around
Chris@94 782 // the region boundary and end up being much smaller than the
Chris@94 783 // theoretical play start frame, perhaps even for the entire
Chris@94 784 // duration of playback!
Chris@94 785
Chris@94 786 if (!m_playStartFramePassed) {
Chris@94 787 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame,
Chris@94 788 sourceRate);
Chris@94 789 if (playing_t < playstart_t) {
Chris@293 790 // cerr << "playing_t " << playing_t << " < playstart_t "
Chris@293 791 // << playstart_t << endl;
Chris@122 792 if (/*!!! sincerequest_t > RealTime::zeroTime && */
Chris@94 793 m_playStartedAt + latency_t + stretchlat_t <
Chris@94 794 RealTime::fromSeconds(currentTime)) {
Chris@293 795 // 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 796 m_playStartFramePassed = true;
Chris@94 797 } else {
Chris@94 798 playing_t = playstart_t;
Chris@94 799 }
Chris@94 800 } else {
Chris@94 801 m_playStartFramePassed = true;
Chris@94 802 }
Chris@94 803 }
Chris@163 804
Chris@163 805 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 806 cerr << "playing_t " << playing_t;
Chris@163 807 #endif
Chris@94 808
Chris@94 809 playing_t = playing_t - m_rangeStarts[inRange];
Chris@93 810
Chris@93 811 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 812 cerr << " as offset into range " << inRange << " (start =" << m_rangeStarts[inRange] << " duration =" << m_rangeDurations[inRange] << ") = " << playing_t << endl;
Chris@93 813 #endif
Chris@93 814
Chris@93 815 while (playing_t < RealTime::zeroTime) {
Chris@93 816
Chris@93 817 if (inRange == 0) {
Chris@93 818 if (looping) {
Chris@436 819 inRange = int(m_rangeStarts.size()) - 1;
Chris@93 820 } else {
Chris@93 821 break;
Chris@93 822 }
Chris@93 823 } else {
Chris@93 824 --inRange;
Chris@93 825 }
Chris@93 826
Chris@93 827 playing_t = playing_t + m_rangeDurations[inRange];
Chris@93 828 }
Chris@93 829
Chris@93 830 playing_t = playing_t + m_rangeStarts[inRange];
Chris@93 831
Chris@93 832 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 833 cerr << " playing time: " << playing_t << endl;
Chris@93 834 #endif
Chris@93 835
Chris@93 836 if (!looping) {
Chris@366 837 if (inRange == (int)m_rangeStarts.size()-1 &&
Chris@93 838 playing_t >= m_rangeStarts[inRange] + m_rangeDurations[inRange]) {
Chris@293 839 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 840 stop();
Chris@93 841 }
Chris@93 842 }
Chris@93 843
Chris@93 844 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
Chris@93 845
Chris@434 846 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
Chris@102 847
Chris@102 848 if (m_lastCurrentFrame > 0 && !looping) {
Chris@102 849 if (frame < m_lastCurrentFrame) {
Chris@102 850 frame = m_lastCurrentFrame;
Chris@102 851 }
Chris@102 852 }
Chris@102 853
Chris@102 854 m_lastCurrentFrame = frame;
Chris@102 855
Chris@93 856 return m_viewManager->alignPlaybackFrameToReference(frame);
Chris@93 857 }
Chris@93 858
Chris@93 859 void
Chris@93 860 AudioCallbackPlaySource::rebuildRangeLists()
Chris@93 861 {
Chris@93 862 bool constrained = (m_viewManager->getPlaySelectionMode());
Chris@93 863
Chris@93 864 m_rangeStarts.clear();
Chris@93 865 m_rangeDurations.clear();
Chris@93 866
Chris@436 867 sv_samplerate_t sourceRate = getSourceSampleRate();
Chris@93 868 if (sourceRate == 0) return;
Chris@93 869
Chris@93 870 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
Chris@93 871 if (end == RealTime::zeroTime) return;
Chris@93 872
Chris@93 873 if (!constrained) {
Chris@93 874 m_rangeStarts.push_back(RealTime::zeroTime);
Chris@93 875 m_rangeDurations.push_back(end);
Chris@93 876 return;
Chris@93 877 }
Chris@93 878
Chris@93 879 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@93 880 MultiSelection::SelectionList::const_iterator i;
Chris@93 881
Chris@93 882 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 883 SVDEBUG << "AudioCallbackPlaySource::rebuildRangeLists" << endl;
Chris@93 884 #endif
Chris@93 885
Chris@93 886 if (!selections.empty()) {
Chris@91 887
Chris@91 888 for (i = selections.begin(); i != selections.end(); ++i) {
Chris@91 889
Chris@91 890 RealTime start =
Chris@91 891 (RealTime::frame2RealTime
Chris@91 892 (m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
Chris@91 893 sourceRate));
Chris@91 894 RealTime duration =
Chris@91 895 (RealTime::frame2RealTime
Chris@91 896 (m_viewManager->alignReferenceToPlaybackFrame(i->getEndFrame()) -
Chris@91 897 m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
Chris@91 898 sourceRate));
Chris@91 899
Chris@93 900 m_rangeStarts.push_back(start);
Chris@93 901 m_rangeDurations.push_back(duration);
Chris@91 902 }
Chris@93 903 } else {
Chris@93 904 m_rangeStarts.push_back(RealTime::zeroTime);
Chris@93 905 m_rangeDurations.push_back(end);
Chris@43 906 }
Chris@43 907
Chris@93 908 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 909 cerr << "Now have " << m_rangeStarts.size() << " play ranges" << endl;
Chris@91 910 #endif
Chris@43 911 }
Chris@43 912
Chris@43 913 void
Chris@43 914 AudioCallbackPlaySource::setOutputLevels(float left, float right)
Chris@43 915 {
Chris@43 916 m_outputLeft = left;
Chris@43 917 m_outputRight = right;
Chris@43 918 }
Chris@43 919
Chris@43 920 bool
Chris@43 921 AudioCallbackPlaySource::getOutputLevels(float &left, float &right)
Chris@43 922 {
Chris@43 923 left = m_outputLeft;
Chris@43 924 right = m_outputRight;
Chris@43 925 return true;
Chris@43 926 }
Chris@43 927
Chris@43 928 void
Chris@434 929 AudioCallbackPlaySource::setTargetSampleRate(sv_samplerate_t sr)
Chris@43 930 {
Chris@244 931 bool first = (m_targetSampleRate == 0);
Chris@244 932
Chris@43 933 m_targetSampleRate = sr;
Chris@43 934 initialiseConverter();
Chris@244 935
Chris@244 936 if (first && (m_stretchRatio != 1.f)) {
Chris@244 937 // couldn't create a stretcher before because we had no sample
Chris@244 938 // rate: make one now
Chris@244 939 setTimeStretch(m_stretchRatio);
Chris@244 940 }
Chris@43 941 }
Chris@43 942
Chris@43 943 void
Chris@43 944 AudioCallbackPlaySource::initialiseConverter()
Chris@43 945 {
Chris@43 946 m_mutex.lock();
Chris@43 947
Chris@43 948 if (m_converter) {
Chris@43 949 src_delete(m_converter);
Chris@43 950 src_delete(m_crapConverter);
Chris@43 951 m_converter = 0;
Chris@43 952 m_crapConverter = 0;
Chris@43 953 }
Chris@43 954
Chris@43 955 if (getSourceSampleRate() != getTargetSampleRate()) {
Chris@43 956
Chris@43 957 int err = 0;
Chris@43 958
Chris@43 959 m_converter = src_new(m_resampleQuality == 2 ? SRC_SINC_BEST_QUALITY :
Chris@43 960 m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY :
Chris@43 961 m_resampleQuality == 0 ? SRC_SINC_FASTEST :
Chris@43 962 SRC_SINC_MEDIUM_QUALITY,
Chris@43 963 getTargetChannelCount(), &err);
Chris@43 964
Chris@43 965 if (m_converter) {
Chris@43 966 m_crapConverter = src_new(SRC_LINEAR,
Chris@43 967 getTargetChannelCount(),
Chris@43 968 &err);
Chris@43 969 }
Chris@43 970
Chris@43 971 if (!m_converter || !m_crapConverter) {
Chris@293 972 cerr
Chris@43 973 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: "
Chris@293 974 << src_strerror(err) << endl;
Chris@43 975
Chris@43 976 if (m_converter) {
Chris@43 977 src_delete(m_converter);
Chris@43 978 m_converter = 0;
Chris@43 979 }
Chris@43 980
Chris@43 981 if (m_crapConverter) {
Chris@43 982 src_delete(m_crapConverter);
Chris@43 983 m_crapConverter = 0;
Chris@43 984 }
Chris@43 985
Chris@43 986 m_mutex.unlock();
Chris@43 987
Chris@43 988 emit sampleRateMismatch(getSourceSampleRate(),
Chris@43 989 getTargetSampleRate(),
Chris@43 990 false);
Chris@43 991 } else {
Chris@43 992
Chris@43 993 m_mutex.unlock();
Chris@43 994
Chris@43 995 emit sampleRateMismatch(getSourceSampleRate(),
Chris@43 996 getTargetSampleRate(),
Chris@43 997 true);
Chris@43 998 }
Chris@43 999 } else {
Chris@43 1000 m_mutex.unlock();
Chris@43 1001 }
Chris@43 1002 }
Chris@43 1003
Chris@43 1004 void
Chris@43 1005 AudioCallbackPlaySource::setResampleQuality(int q)
Chris@43 1006 {
Chris@43 1007 if (q == m_resampleQuality) return;
Chris@43 1008 m_resampleQuality = q;
Chris@43 1009
Chris@43 1010 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@233 1011 SVDEBUG << "AudioCallbackPlaySource::setResampleQuality: setting to "
Chris@229 1012 << m_resampleQuality << endl;
Chris@43 1013 #endif
Chris@43 1014
Chris@43 1015 initialiseConverter();
Chris@43 1016 }
Chris@43 1017
Chris@43 1018 void
Chris@107 1019 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a)
Chris@43 1020 {
Chris@107 1021 RealTimePluginInstance *plugin = dynamic_cast<RealTimePluginInstance *>(a);
Chris@107 1022 if (a && !plugin) {
Chris@293 1023 cerr << "WARNING: AudioCallbackPlaySource::setAuditioningEffect: auditionable object " << a << " is not a real-time plugin instance" << endl;
Chris@107 1024 }
Chris@204 1025
Chris@204 1026 m_mutex.lock();
Chris@43 1027 m_auditioningPlugin = plugin;
Chris@43 1028 m_auditioningPluginBypassed = false;
Chris@204 1029 m_mutex.unlock();
Chris@43 1030 }
Chris@43 1031
Chris@43 1032 void
Chris@43 1033 AudioCallbackPlaySource::setSoloModelSet(std::set<Model *> s)
Chris@43 1034 {
Chris@43 1035 m_audioGenerator->setSoloModelSet(s);
Chris@43 1036 clearRingBuffers();
Chris@43 1037 }
Chris@43 1038
Chris@43 1039 void
Chris@43 1040 AudioCallbackPlaySource::clearSoloModelSet()
Chris@43 1041 {
Chris@43 1042 m_audioGenerator->clearSoloModelSet();
Chris@43 1043 clearRingBuffers();
Chris@43 1044 }
Chris@43 1045
Chris@434 1046 sv_samplerate_t
Chris@43 1047 AudioCallbackPlaySource::getTargetSampleRate() const
Chris@43 1048 {
Chris@43 1049 if (m_targetSampleRate) return m_targetSampleRate;
Chris@43 1050 else return getSourceSampleRate();
Chris@43 1051 }
Chris@43 1052
Chris@366 1053 int
Chris@43 1054 AudioCallbackPlaySource::getSourceChannelCount() const
Chris@43 1055 {
Chris@43 1056 return m_sourceChannelCount;
Chris@43 1057 }
Chris@43 1058
Chris@366 1059 int
Chris@43 1060 AudioCallbackPlaySource::getTargetChannelCount() const
Chris@43 1061 {
Chris@43 1062 if (m_sourceChannelCount < 2) return 2;
Chris@43 1063 return m_sourceChannelCount;
Chris@43 1064 }
Chris@43 1065
Chris@434 1066 sv_samplerate_t
Chris@43 1067 AudioCallbackPlaySource::getSourceSampleRate() const
Chris@43 1068 {
Chris@43 1069 return m_sourceSampleRate;
Chris@43 1070 }
Chris@43 1071
Chris@43 1072 void
Chris@436 1073 AudioCallbackPlaySource::setTimeStretch(double factor)
Chris@43 1074 {
Chris@91 1075 m_stretchRatio = factor;
Chris@91 1076
Chris@244 1077 if (!getTargetSampleRate()) return; // have to make our stretcher later
Chris@244 1078
Chris@436 1079 if (m_timeStretcher || (factor == 1.0)) {
Chris@91 1080 // stretch ratio will be set in next process call if appropriate
Chris@62 1081 } else {
Chris@91 1082 m_stretcherInputCount = getTargetChannelCount();
Chris@62 1083 RubberBandStretcher *stretcher = new RubberBandStretcher
Chris@436 1084 (int(getTargetSampleRate()),
Chris@91 1085 m_stretcherInputCount,
Chris@62 1086 RubberBandStretcher::OptionProcessRealTime,
Chris@62 1087 factor);
Chris@130 1088 RubberBandStretcher *monoStretcher = new RubberBandStretcher
Chris@436 1089 (int(getTargetSampleRate()),
Chris@130 1090 1,
Chris@130 1091 RubberBandStretcher::OptionProcessRealTime,
Chris@130 1092 factor);
Chris@91 1093 m_stretcherInputs = new float *[m_stretcherInputCount];
Chris@436 1094 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount];
Chris@366 1095 for (int c = 0; c < m_stretcherInputCount; ++c) {
Chris@91 1096 m_stretcherInputSizes[c] = 16384;
Chris@91 1097 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
Chris@91 1098 }
Chris@130 1099 m_monoStretcher = monoStretcher;
Chris@62 1100 m_timeStretcher = stretcher;
Chris@62 1101 }
Chris@158 1102
Chris@158 1103 emit activity(tr("Change time-stretch factor to %1").arg(factor));
Chris@43 1104 }
Chris@43 1105
Chris@434 1106 sv_frame_t
Chris@434 1107 AudioCallbackPlaySource::getSourceSamples(sv_frame_t count, float **buffer)
Chris@43 1108 {
Chris@43 1109 if (!m_playing) {
Chris@193 1110 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1111 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Not playing" << endl;
Chris@193 1112 #endif
Chris@366 1113 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@130 1114 for (int i = 0; i < count; ++i) {
Chris@43 1115 buffer[ch][i] = 0.0;
Chris@43 1116 }
Chris@43 1117 }
Chris@43 1118 return 0;
Chris@43 1119 }
Chris@43 1120
Chris@212 1121 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1122 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Playing" << endl;
Chris@212 1123 #endif
Chris@212 1124
Chris@43 1125 // Ensure that all buffers have at least the amount of data we
Chris@43 1126 // need -- else reduce the size of our requests correspondingly
Chris@43 1127
Chris@366 1128 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@43 1129
Chris@43 1130 RingBuffer<float> *rb = getReadRingBuffer(ch);
Chris@43 1131
Chris@43 1132 if (!rb) {
Chris@293 1133 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
Chris@43 1134 << "No ring buffer available for channel " << ch
Chris@293 1135 << ", returning no data here" << endl;
Chris@43 1136 count = 0;
Chris@43 1137 break;
Chris@43 1138 }
Chris@43 1139
Chris@366 1140 int rs = rb->getReadSpace();
Chris@43 1141 if (rs < count) {
Chris@43 1142 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1143 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
Chris@43 1144 << "Ring buffer for channel " << ch << " has only "
Chris@193 1145 << rs << " (of " << count << ") samples available ("
Chris@193 1146 << "ring buffer size is " << rb->getSize() << ", write "
Chris@193 1147 << "space " << rb->getWriteSpace() << "), "
Chris@293 1148 << "reducing request size" << endl;
Chris@43 1149 #endif
Chris@43 1150 count = rs;
Chris@43 1151 }
Chris@43 1152 }
Chris@43 1153
Chris@43 1154 if (count == 0) return 0;
Chris@43 1155
Chris@62 1156 RubberBandStretcher *ts = m_timeStretcher;
Chris@130 1157 RubberBandStretcher *ms = m_monoStretcher;
Chris@130 1158
Chris@436 1159 double ratio = ts ? ts->getTimeRatio() : 1.0;
Chris@91 1160
Chris@91 1161 if (ratio != m_stretchRatio) {
Chris@91 1162 if (!ts) {
Chris@293 1163 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << endl;
Chris@436 1164 m_stretchRatio = 1.0;
Chris@91 1165 } else {
Chris@91 1166 ts->setTimeRatio(m_stretchRatio);
Chris@130 1167 if (ms) ms->setTimeRatio(m_stretchRatio);
Chris@130 1168 if (m_stretchRatio >= 1.0) m_stretchMono = false;
Chris@130 1169 }
Chris@130 1170 }
Chris@130 1171
Chris@130 1172 int stretchChannels = m_stretcherInputCount;
Chris@130 1173 if (m_stretchMono) {
Chris@130 1174 if (ms) {
Chris@130 1175 ts = ms;
Chris@130 1176 stretchChannels = 1;
Chris@130 1177 } else {
Chris@130 1178 m_stretchMono = false;
Chris@91 1179 }
Chris@91 1180 }
Chris@91 1181
Chris@91 1182 if (m_target) {
Chris@91 1183 m_lastRetrievedBlockSize = count;
Chris@91 1184 m_lastRetrievalTimestamp = m_target->getCurrentTime();
Chris@91 1185 }
Chris@43 1186
Chris@62 1187 if (!ts || ratio == 1.f) {
Chris@43 1188
Chris@130 1189 int got = 0;
Chris@43 1190
Chris@366 1191 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@43 1192
Chris@43 1193 RingBuffer<float> *rb = getReadRingBuffer(ch);
Chris@43 1194
Chris@43 1195 if (rb) {
Chris@43 1196
Chris@43 1197 // this is marginally more likely to leave our channels in
Chris@43 1198 // sync after a processing failure than just passing "count":
Chris@436 1199 sv_frame_t request = count;
Chris@43 1200 if (ch > 0) request = got;
Chris@43 1201
Chris@436 1202 got = rb->read(buffer[ch], int(request));
Chris@43 1203
Chris@43 1204 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 1205 cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << endl;
Chris@43 1206 #endif
Chris@43 1207 }
Chris@43 1208
Chris@366 1209 for (int ch = 0; ch < getTargetChannelCount(); ++ch) {
Chris@130 1210 for (int i = got; i < count; ++i) {
Chris@43 1211 buffer[ch][i] = 0.0;
Chris@43 1212 }
Chris@43 1213 }
Chris@43 1214 }
Chris@43 1215
Chris@43 1216 applyAuditioningEffect(count, buffer);
Chris@43 1217
Chris@212 1218 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1219 cout << "AudioCallbackPlaySource::getSamples: awakening thread" << endl;
Chris@212 1220 #endif
Chris@212 1221
Chris@43 1222 m_condition.wakeAll();
Chris@91 1223
Chris@43 1224 return got;
Chris@43 1225 }
Chris@43 1226
Chris@366 1227 int channels = getTargetChannelCount();
Chris@436 1228 sv_frame_t available;
Chris@436 1229 sv_frame_t fedToStretcher = 0;
Chris@91 1230 int warned = 0;
Chris@43 1231
Chris@91 1232 // The input block for a given output is approx output / ratio,
Chris@91 1233 // but we can't predict it exactly, for an adaptive timestretcher.
Chris@91 1234
Chris@91 1235 while ((available = ts->available()) < count) {
Chris@91 1236
Chris@436 1237 sv_frame_t reqd = lrint(double(count - available) / ratio);
Chris@436 1238 reqd = std::max(reqd, sv_frame_t(ts->getSamplesRequired()));
Chris@91 1239 if (reqd == 0) reqd = 1;
Chris@91 1240
Chris@436 1241 sv_frame_t got = reqd;
Chris@91 1242
Chris@91 1243 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 1244 cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << endl;
Chris@62 1245 #endif
Chris@43 1246
Chris@366 1247 for (int c = 0; c < channels; ++c) {
Chris@131 1248 if (c >= m_stretcherInputCount) continue;
Chris@91 1249 if (reqd > m_stretcherInputSizes[c]) {
Chris@91 1250 if (c == 0) {
Chris@293 1251 cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << endl;
Chris@91 1252 }
Chris@91 1253 delete[] m_stretcherInputs[c];
Chris@91 1254 m_stretcherInputSizes[c] = reqd * 2;
Chris@91 1255 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
Chris@91 1256 }
Chris@91 1257 }
Chris@43 1258
Chris@366 1259 for (int c = 0; c < channels; ++c) {
Chris@131 1260 if (c >= m_stretcherInputCount) continue;
Chris@91 1261 RingBuffer<float> *rb = getReadRingBuffer(c);
Chris@91 1262 if (rb) {
Chris@436 1263 sv_frame_t gotHere;
Chris@130 1264 if (stretchChannels == 1 && c > 0) {
Chris@436 1265 gotHere = rb->readAdding(m_stretcherInputs[0], int(got));
Chris@130 1266 } else {
Chris@436 1267 gotHere = rb->read(m_stretcherInputs[c], int(got));
Chris@130 1268 }
Chris@91 1269 if (gotHere < got) got = gotHere;
Chris@91 1270
Chris@91 1271 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@91 1272 if (c == 0) {
Chris@233 1273 SVDEBUG << "feeding stretcher: got " << gotHere
Chris@229 1274 << ", " << rb->getReadSpace() << " remain" << endl;
Chris@91 1275 }
Chris@62 1276 #endif
Chris@43 1277
Chris@91 1278 } else {
Chris@293 1279 cerr << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << endl;
Chris@43 1280 }
Chris@43 1281 }
Chris@43 1282
Chris@43 1283 if (got < reqd) {
Chris@293 1284 cerr << "WARNING: Read underrun in playback ("
Chris@293 1285 << got << " < " << reqd << ")" << endl;
Chris@43 1286 }
Chris@43 1287
Chris@91 1288 ts->process(m_stretcherInputs, got, false);
Chris@91 1289
Chris@91 1290 fedToStretcher += got;
Chris@43 1291
Chris@43 1292 if (got == 0) break;
Chris@43 1293
Chris@62 1294 if (ts->available() == available) {
Chris@293 1295 cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << endl;
Chris@43 1296 if (++warned == 5) break;
Chris@43 1297 }
Chris@43 1298 }
Chris@43 1299
Chris@62 1300 ts->retrieve(buffer, count);
Chris@43 1301
Chris@130 1302 for (int c = stretchChannels; c < getTargetChannelCount(); ++c) {
Chris@130 1303 for (int i = 0; i < count; ++i) {
Chris@130 1304 buffer[c][i] = buffer[0][i];
Chris@130 1305 }
Chris@130 1306 }
Chris@130 1307
Chris@43 1308 applyAuditioningEffect(count, buffer);
Chris@43 1309
Chris@212 1310 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1311 cout << "AudioCallbackPlaySource::getSamples [stretched]: awakening thread" << endl;
Chris@212 1312 #endif
Chris@212 1313
Chris@43 1314 m_condition.wakeAll();
Chris@43 1315
Chris@43 1316 return count;
Chris@43 1317 }
Chris@43 1318
Chris@43 1319 void
Chris@434 1320 AudioCallbackPlaySource::applyAuditioningEffect(sv_frame_t count, float **buffers)
Chris@43 1321 {
Chris@43 1322 if (m_auditioningPluginBypassed) return;
Chris@43 1323 RealTimePluginInstance *plugin = m_auditioningPlugin;
Chris@43 1324 if (!plugin) return;
Chris@204 1325
Chris@366 1326 if ((int)plugin->getAudioInputCount() != getTargetChannelCount()) {
Chris@293 1327 // cerr << "plugin input count " << plugin->getAudioInputCount()
Chris@43 1328 // << " != our channel count " << getTargetChannelCount()
Chris@293 1329 // << endl;
Chris@43 1330 return;
Chris@43 1331 }
Chris@366 1332 if ((int)plugin->getAudioOutputCount() != getTargetChannelCount()) {
Chris@293 1333 // cerr << "plugin output count " << plugin->getAudioOutputCount()
Chris@43 1334 // << " != our channel count " << getTargetChannelCount()
Chris@293 1335 // << endl;
Chris@43 1336 return;
Chris@43 1337 }
Chris@366 1338 if ((int)plugin->getBufferSize() < count) {
Chris@293 1339 // cerr << "plugin buffer size " << plugin->getBufferSize()
Chris@102 1340 // << " < our block size " << count
Chris@293 1341 // << endl;
Chris@43 1342 return;
Chris@43 1343 }
Chris@43 1344
Chris@43 1345 float **ib = plugin->getAudioInputBuffers();
Chris@43 1346 float **ob = plugin->getAudioOutputBuffers();
Chris@43 1347
Chris@366 1348 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@366 1349 for (int i = 0; i < count; ++i) {
Chris@43 1350 ib[c][i] = buffers[c][i];
Chris@43 1351 }
Chris@43 1352 }
Chris@43 1353
Chris@436 1354 plugin->run(Vamp::RealTime::zeroTime, int(count));
Chris@43 1355
Chris@366 1356 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@366 1357 for (int i = 0; i < count; ++i) {
Chris@43 1358 buffers[c][i] = ob[c][i];
Chris@43 1359 }
Chris@43 1360 }
Chris@43 1361 }
Chris@43 1362
Chris@43 1363 // Called from fill thread, m_playing true, mutex held
Chris@43 1364 bool
Chris@43 1365 AudioCallbackPlaySource::fillBuffers()
Chris@43 1366 {
Chris@43 1367 static float *tmp = 0;
Chris@436 1368 static sv_frame_t tmpSize = 0;
Chris@43 1369
Chris@434 1370 sv_frame_t space = 0;
Chris@366 1371 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 1372 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1373 if (wb) {
Chris@434 1374 sv_frame_t spaceHere = wb->getWriteSpace();
Chris@43 1375 if (c == 0 || spaceHere < space) space = spaceHere;
Chris@43 1376 }
Chris@43 1377 }
Chris@43 1378
Chris@103 1379 if (space == 0) {
Chris@103 1380 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1381 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl;
Chris@103 1382 #endif
Chris@103 1383 return false;
Chris@103 1384 }
Chris@43 1385
Chris@434 1386 sv_frame_t f = m_writeBufferFill;
Chris@43 1387
Chris@43 1388 bool readWriteEqual = (m_readBuffers == m_writeBuffers);
Chris@43 1389
Chris@43 1390 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@193 1391 if (!readWriteEqual) {
Chris@293 1392 cout << "AudioCallbackPlaySourceFillThread: note read buffers != write buffers" << endl;
Chris@193 1393 }
Chris@293 1394 cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << endl;
Chris@43 1395 #endif
Chris@43 1396
Chris@43 1397 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1398 cout << "buffered to " << f << " already" << endl;
Chris@43 1399 #endif
Chris@43 1400
Chris@43 1401 bool resample = (getSourceSampleRate() != getTargetSampleRate());
Chris@43 1402
Chris@43 1403 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1404 cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << endl;
Chris@43 1405 #endif
Chris@43 1406
Chris@366 1407 int channels = getTargetChannelCount();
Chris@43 1408
Chris@434 1409 sv_frame_t orig = space;
Chris@434 1410 sv_frame_t got = 0;
Chris@43 1411
Chris@43 1412 static float **bufferPtrs = 0;
Chris@366 1413 static int bufferPtrCount = 0;
Chris@43 1414
Chris@43 1415 if (bufferPtrCount < channels) {
Chris@43 1416 if (bufferPtrs) delete[] bufferPtrs;
Chris@43 1417 bufferPtrs = new float *[channels];
Chris@43 1418 bufferPtrCount = channels;
Chris@43 1419 }
Chris@43 1420
Chris@436 1421 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize();
Chris@43 1422
Chris@43 1423 if (resample && !m_converter) {
Chris@43 1424 static bool warned = false;
Chris@43 1425 if (!warned) {
Chris@293 1426 cerr << "WARNING: sample rates differ, but no converter available!" << endl;
Chris@43 1427 warned = true;
Chris@43 1428 }
Chris@43 1429 }
Chris@43 1430
Chris@43 1431 if (resample && m_converter) {
Chris@43 1432
Chris@43 1433 double ratio =
Chris@43 1434 double(getTargetSampleRate()) / double(getSourceSampleRate());
Chris@436 1435 orig = sv_frame_t(double(orig) / ratio + 0.1);
Chris@43 1436
Chris@43 1437 // orig must be a multiple of generatorBlockSize
Chris@43 1438 orig = (orig / generatorBlockSize) * generatorBlockSize;
Chris@43 1439 if (orig == 0) return false;
Chris@43 1440
Chris@436 1441 sv_frame_t work = std::max(orig, space);
Chris@43 1442
Chris@43 1443 // We only allocate one buffer, but we use it in two halves.
Chris@43 1444 // We place the non-interleaved values in the second half of
Chris@43 1445 // the buffer (orig samples for channel 0, orig samples for
Chris@43 1446 // channel 1 etc), and then interleave them into the first
Chris@43 1447 // half of the buffer. Then we resample back into the second
Chris@43 1448 // half (interleaved) and de-interleave the results back to
Chris@43 1449 // the start of the buffer for insertion into the ringbuffers.
Chris@43 1450 // What a faff -- especially as we've already de-interleaved
Chris@43 1451 // the audio data from the source file elsewhere before we
Chris@43 1452 // even reach this point.
Chris@43 1453
Chris@43 1454 if (tmpSize < channels * work * 2) {
Chris@43 1455 delete[] tmp;
Chris@43 1456 tmp = new float[channels * work * 2];
Chris@43 1457 tmpSize = channels * work * 2;
Chris@43 1458 }
Chris@43 1459
Chris@43 1460 float *nonintlv = tmp + channels * work;
Chris@43 1461 float *intlv = tmp;
Chris@43 1462 float *srcout = tmp + channels * work;
Chris@43 1463
Chris@366 1464 for (int c = 0; c < channels; ++c) {
Chris@366 1465 for (int i = 0; i < orig; ++i) {
Chris@43 1466 nonintlv[channels * i + c] = 0.0f;
Chris@43 1467 }
Chris@43 1468 }
Chris@43 1469
Chris@366 1470 for (int c = 0; c < channels; ++c) {
Chris@43 1471 bufferPtrs[c] = nonintlv + c * orig;
Chris@43 1472 }
Chris@43 1473
Chris@163 1474 got = mixModels(f, orig, bufferPtrs); // also modifies f
Chris@43 1475
Chris@43 1476 // and interleave into first half
Chris@366 1477 for (int c = 0; c < channels; ++c) {
Chris@366 1478 for (int i = 0; i < got; ++i) {
Chris@43 1479 float sample = nonintlv[c * got + i];
Chris@43 1480 intlv[channels * i + c] = sample;
Chris@43 1481 }
Chris@43 1482 }
Chris@43 1483
Chris@43 1484 SRC_DATA data;
Chris@43 1485 data.data_in = intlv;
Chris@43 1486 data.data_out = srcout;
Chris@43 1487 data.input_frames = got;
Chris@43 1488 data.output_frames = work;
Chris@43 1489 data.src_ratio = ratio;
Chris@43 1490 data.end_of_input = 0;
Chris@43 1491
Chris@43 1492 int err = 0;
Chris@43 1493
Chris@62 1494 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
Chris@43 1495 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1496 cout << "Using crappy converter" << endl;
Chris@43 1497 #endif
Chris@43 1498 err = src_process(m_crapConverter, &data);
Chris@43 1499 } else {
Chris@43 1500 err = src_process(m_converter, &data);
Chris@43 1501 }
Chris@43 1502
Chris@436 1503 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1);
Chris@43 1504
Chris@43 1505 if (err) {
Chris@293 1506 cerr
Chris@43 1507 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: "
Chris@293 1508 << src_strerror(err) << endl;
Chris@43 1509 //!!! Then what?
Chris@43 1510 } else {
Chris@43 1511 got = data.input_frames_used;
Chris@43 1512 toCopy = data.output_frames_gen;
Chris@43 1513 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1514 cout << "Resampled " << got << " frames to " << toCopy << " frames" << endl;
Chris@43 1515 #endif
Chris@43 1516 }
Chris@43 1517
Chris@366 1518 for (int c = 0; c < channels; ++c) {
Chris@366 1519 for (int i = 0; i < toCopy; ++i) {
Chris@43 1520 tmp[i] = srcout[channels * i + c];
Chris@43 1521 }
Chris@43 1522 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@436 1523 if (wb) wb->write(tmp, int(toCopy));
Chris@43 1524 }
Chris@43 1525
Chris@43 1526 m_writeBufferFill = f;
Chris@43 1527 if (readWriteEqual) m_readBufferFill = f;
Chris@43 1528
Chris@43 1529 } else {
Chris@43 1530
Chris@43 1531 // space must be a multiple of generatorBlockSize
Chris@436 1532 sv_frame_t reqSpace = space;
Chris@195 1533 space = (reqSpace / generatorBlockSize) * generatorBlockSize;
Chris@91 1534 if (space == 0) {
Chris@91 1535 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1536 cout << "requested fill of " << reqSpace
Chris@195 1537 << " is less than generator block size of "
Chris@293 1538 << generatorBlockSize << ", leaving it" << endl;
Chris@91 1539 #endif
Chris@91 1540 return false;
Chris@91 1541 }
Chris@43 1542
Chris@43 1543 if (tmpSize < channels * space) {
Chris@43 1544 delete[] tmp;
Chris@43 1545 tmp = new float[channels * space];
Chris@43 1546 tmpSize = channels * space;
Chris@43 1547 }
Chris@43 1548
Chris@366 1549 for (int c = 0; c < channels; ++c) {
Chris@43 1550
Chris@43 1551 bufferPtrs[c] = tmp + c * space;
Chris@43 1552
Chris@366 1553 for (int i = 0; i < space; ++i) {
Chris@43 1554 tmp[c * space + i] = 0.0f;
Chris@43 1555 }
Chris@43 1556 }
Chris@43 1557
Chris@436 1558 sv_frame_t got = mixModels(f, space, bufferPtrs); // also modifies f
Chris@43 1559
Chris@366 1560 for (int c = 0; c < channels; ++c) {
Chris@43 1561
Chris@43 1562 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1563 if (wb) {
Chris@436 1564 int actual = wb->write(bufferPtrs[c], int(got));
Chris@43 1565 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1566 cout << "Wrote " << actual << " samples for ch " << c << ", now "
Chris@43 1567 << wb->getReadSpace() << " to read"
Chris@293 1568 << endl;
Chris@43 1569 #endif
Chris@43 1570 if (actual < got) {
Chris@293 1571 cerr << "WARNING: Buffer overrun in channel " << c
Chris@43 1572 << ": wrote " << actual << " of " << got
Chris@293 1573 << " samples" << endl;
Chris@43 1574 }
Chris@43 1575 }
Chris@43 1576 }
Chris@43 1577
Chris@43 1578 m_writeBufferFill = f;
Chris@43 1579 if (readWriteEqual) m_readBufferFill = f;
Chris@43 1580
Chris@163 1581 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1582 cout << "Read buffer fill is now " << m_readBufferFill << endl;
Chris@163 1583 #endif
Chris@163 1584
Chris@43 1585 //!!! 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 1586 }
Chris@43 1587
Chris@43 1588 return true;
Chris@43 1589 }
Chris@43 1590
Chris@434 1591 sv_frame_t
Chris@434 1592 AudioCallbackPlaySource::mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers)
Chris@43 1593 {
Chris@434 1594 sv_frame_t processed = 0;
Chris@434 1595 sv_frame_t chunkStart = frame;
Chris@434 1596 sv_frame_t chunkSize = count;
Chris@434 1597 sv_frame_t selectionSize = 0;
Chris@434 1598 sv_frame_t nextChunkStart = chunkStart + chunkSize;
Chris@43 1599
Chris@43 1600 bool looping = m_viewManager->getPlayLoopMode();
Chris@43 1601 bool constrained = (m_viewManager->getPlaySelectionMode() &&
Chris@43 1602 !m_viewManager->getSelections().empty());
Chris@43 1603
Chris@43 1604 static float **chunkBufferPtrs = 0;
Chris@366 1605 static int chunkBufferPtrCount = 0;
Chris@366 1606 int channels = getTargetChannelCount();
Chris@43 1607
Chris@43 1608 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1609 cout << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << endl;
Chris@43 1610 #endif
Chris@43 1611
Chris@43 1612 if (chunkBufferPtrCount < channels) {
Chris@43 1613 if (chunkBufferPtrs) delete[] chunkBufferPtrs;
Chris@43 1614 chunkBufferPtrs = new float *[channels];
Chris@43 1615 chunkBufferPtrCount = channels;
Chris@43 1616 }
Chris@43 1617
Chris@366 1618 for (int c = 0; c < channels; ++c) {
Chris@43 1619 chunkBufferPtrs[c] = buffers[c];
Chris@43 1620 }
Chris@43 1621
Chris@43 1622 while (processed < count) {
Chris@43 1623
Chris@43 1624 chunkSize = count - processed;
Chris@43 1625 nextChunkStart = chunkStart + chunkSize;
Chris@43 1626 selectionSize = 0;
Chris@43 1627
Chris@434 1628 sv_frame_t fadeIn = 0, fadeOut = 0;
Chris@43 1629
Chris@43 1630 if (constrained) {
Chris@60 1631
Chris@434 1632 sv_frame_t rChunkStart =
Chris@60 1633 m_viewManager->alignPlaybackFrameToReference(chunkStart);
Chris@43 1634
Chris@43 1635 Selection selection =
Chris@60 1636 m_viewManager->getContainingSelection(rChunkStart, true);
Chris@43 1637
Chris@43 1638 if (selection.isEmpty()) {
Chris@43 1639 if (looping) {
Chris@43 1640 selection = *m_viewManager->getSelections().begin();
Chris@60 1641 chunkStart = m_viewManager->alignReferenceToPlaybackFrame
Chris@60 1642 (selection.getStartFrame());
Chris@43 1643 fadeIn = 50;
Chris@43 1644 }
Chris@43 1645 }
Chris@43 1646
Chris@43 1647 if (selection.isEmpty()) {
Chris@43 1648
Chris@43 1649 chunkSize = 0;
Chris@43 1650 nextChunkStart = chunkStart;
Chris@43 1651
Chris@43 1652 } else {
Chris@43 1653
Chris@434 1654 sv_frame_t sf = m_viewManager->alignReferenceToPlaybackFrame
Chris@60 1655 (selection.getStartFrame());
Chris@434 1656 sv_frame_t ef = m_viewManager->alignReferenceToPlaybackFrame
Chris@60 1657 (selection.getEndFrame());
Chris@43 1658
Chris@60 1659 selectionSize = ef - sf;
Chris@60 1660
Chris@60 1661 if (chunkStart < sf) {
Chris@60 1662 chunkStart = sf;
Chris@43 1663 fadeIn = 50;
Chris@43 1664 }
Chris@43 1665
Chris@43 1666 nextChunkStart = chunkStart + chunkSize;
Chris@43 1667
Chris@60 1668 if (nextChunkStart >= ef) {
Chris@60 1669 nextChunkStart = ef;
Chris@43 1670 fadeOut = 50;
Chris@43 1671 }
Chris@43 1672
Chris@43 1673 chunkSize = nextChunkStart - chunkStart;
Chris@43 1674 }
Chris@43 1675
Chris@43 1676 } else if (looping && m_lastModelEndFrame > 0) {
Chris@43 1677
Chris@43 1678 if (chunkStart >= m_lastModelEndFrame) {
Chris@43 1679 chunkStart = 0;
Chris@43 1680 }
Chris@43 1681 if (chunkSize > m_lastModelEndFrame - chunkStart) {
Chris@43 1682 chunkSize = m_lastModelEndFrame - chunkStart;
Chris@43 1683 }
Chris@43 1684 nextChunkStart = chunkStart + chunkSize;
Chris@43 1685 }
Chris@43 1686
Chris@293 1687 // cout << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << endl;
Chris@43 1688
Chris@43 1689 if (!chunkSize) {
Chris@43 1690 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1691 cout << "Ending selection playback at " << nextChunkStart << endl;
Chris@43 1692 #endif
Chris@43 1693 // We need to maintain full buffers so that the other
Chris@43 1694 // thread can tell where it's got to in the playback -- so
Chris@43 1695 // return the full amount here
Chris@43 1696 frame = frame + count;
Chris@43 1697 return count;
Chris@43 1698 }
Chris@43 1699
Chris@43 1700 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1701 cout << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << endl;
Chris@43 1702 #endif
Chris@43 1703
Chris@43 1704 if (selectionSize < 100) {
Chris@43 1705 fadeIn = 0;
Chris@43 1706 fadeOut = 0;
Chris@43 1707 } else if (selectionSize < 300) {
Chris@43 1708 if (fadeIn > 0) fadeIn = 10;
Chris@43 1709 if (fadeOut > 0) fadeOut = 10;
Chris@43 1710 }
Chris@43 1711
Chris@43 1712 if (fadeIn > 0) {
Chris@43 1713 if (processed * 2 < fadeIn) {
Chris@43 1714 fadeIn = processed * 2;
Chris@43 1715 }
Chris@43 1716 }
Chris@43 1717
Chris@43 1718 if (fadeOut > 0) {
Chris@43 1719 if ((count - processed - chunkSize) * 2 < fadeOut) {
Chris@43 1720 fadeOut = (count - processed - chunkSize) * 2;
Chris@43 1721 }
Chris@43 1722 }
Chris@43 1723
Chris@43 1724 for (std::set<Model *>::iterator mi = m_models.begin();
Chris@43 1725 mi != m_models.end(); ++mi) {
Chris@43 1726
Chris@366 1727 (void) m_audioGenerator->mixModel(*mi, chunkStart,
Chris@366 1728 chunkSize, chunkBufferPtrs,
Chris@366 1729 fadeIn, fadeOut);
Chris@43 1730 }
Chris@43 1731
Chris@366 1732 for (int c = 0; c < channels; ++c) {
Chris@43 1733 chunkBufferPtrs[c] += chunkSize;
Chris@43 1734 }
Chris@43 1735
Chris@43 1736 processed += chunkSize;
Chris@43 1737 chunkStart = nextChunkStart;
Chris@43 1738 }
Chris@43 1739
Chris@43 1740 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1741 cout << "Returning selection playback " << processed << " frames to " << nextChunkStart << endl;
Chris@43 1742 #endif
Chris@43 1743
Chris@43 1744 frame = nextChunkStart;
Chris@43 1745 return processed;
Chris@43 1746 }
Chris@43 1747
Chris@43 1748 void
Chris@43 1749 AudioCallbackPlaySource::unifyRingBuffers()
Chris@43 1750 {
Chris@43 1751 if (m_readBuffers == m_writeBuffers) return;
Chris@43 1752
Chris@43 1753 // only unify if there will be something to read
Chris@366 1754 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 1755 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1756 if (wb) {
Chris@43 1757 if (wb->getReadSpace() < m_blockSize * 2) {
Chris@43 1758 if ((m_writeBufferFill + m_blockSize * 2) <
Chris@43 1759 m_lastModelEndFrame) {
Chris@43 1760 // OK, we don't have enough and there's more to
Chris@43 1761 // read -- don't unify until we can do better
Chris@193 1762 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1763 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 1764 #endif
Chris@43 1765 return;
Chris@43 1766 }
Chris@43 1767 }
Chris@43 1768 break;
Chris@43 1769 }
Chris@43 1770 }
Chris@43 1771
Chris@436 1772 sv_frame_t rf = m_readBufferFill;
Chris@43 1773 RingBuffer<float> *rb = getReadRingBuffer(0);
Chris@43 1774 if (rb) {
Chris@366 1775 int rs = rb->getReadSpace();
Chris@43 1776 //!!! incorrect when in non-contiguous selection, see comments elsewhere
Chris@293 1777 // cout << "rs = " << rs << endl;
Chris@43 1778 if (rs < rf) rf -= rs;
Chris@43 1779 else rf = 0;
Chris@43 1780 }
Chris@43 1781
Chris@193 1782 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@233 1783 SVDEBUG << "AudioCallbackPlaySource::unifyRingBuffers: m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << endl;
Chris@193 1784 #endif
Chris@43 1785
Chris@436 1786 sv_frame_t wf = m_writeBufferFill;
Chris@436 1787 sv_frame_t skip = 0;
Chris@366 1788 for (int c = 0; c < getTargetChannelCount(); ++c) {
Chris@43 1789 RingBuffer<float> *wb = getWriteRingBuffer(c);
Chris@43 1790 if (wb) {
Chris@43 1791 if (c == 0) {
Chris@43 1792
Chris@366 1793 int wrs = wb->getReadSpace();
Chris@293 1794 // cout << "wrs = " << wrs << endl;
Chris@43 1795
Chris@43 1796 if (wrs < wf) wf -= wrs;
Chris@43 1797 else wf = 0;
Chris@293 1798 // cout << "wf = " << wf << endl;
Chris@43 1799
Chris@43 1800 if (wf < rf) skip = rf - wf;
Chris@43 1801 if (skip == 0) break;
Chris@43 1802 }
Chris@43 1803
Chris@293 1804 // cout << "skipping " << skip << endl;
Chris@436 1805 wb->skip(int(skip));
Chris@43 1806 }
Chris@43 1807 }
Chris@43 1808
Chris@43 1809 m_bufferScavenger.claim(m_readBuffers);
Chris@43 1810 m_readBuffers = m_writeBuffers;
Chris@43 1811 m_readBufferFill = m_writeBufferFill;
Chris@193 1812 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
Chris@293 1813 cerr << "unified" << endl;
Chris@193 1814 #endif
Chris@43 1815 }
Chris@43 1816
Chris@43 1817 void
Chris@43 1818 AudioCallbackPlaySource::FillThread::run()
Chris@43 1819 {
Chris@43 1820 AudioCallbackPlaySource &s(m_source);
Chris@43 1821
Chris@43 1822 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1823 cout << "AudioCallbackPlaySourceFillThread starting" << endl;
Chris@43 1824 #endif
Chris@43 1825
Chris@43 1826 s.m_mutex.lock();
Chris@43 1827
Chris@43 1828 bool previouslyPlaying = s.m_playing;
Chris@43 1829 bool work = false;
Chris@43 1830
Chris@43 1831 while (!s.m_exiting) {
Chris@43 1832
Chris@43 1833 s.unifyRingBuffers();
Chris@43 1834 s.m_bufferScavenger.scavenge();
Chris@43 1835 s.m_pluginScavenger.scavenge();
Chris@43 1836
Chris@43 1837 if (work && s.m_playing && s.getSourceSampleRate()) {
Chris@43 1838
Chris@43 1839 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1840 cout << "AudioCallbackPlaySourceFillThread: not waiting" << endl;
Chris@43 1841 #endif
Chris@43 1842
Chris@43 1843 s.m_mutex.unlock();
Chris@43 1844 s.m_mutex.lock();
Chris@43 1845
Chris@43 1846 } else {
Chris@43 1847
Chris@436 1848 double ms = 100;
Chris@43 1849 if (s.getSourceSampleRate() > 0) {
Chris@436 1850 ms = double(s.m_ringBufferSize) / s.getSourceSampleRate() * 1000.0;
Chris@43 1851 }
Chris@43 1852
Chris@43 1853 if (s.m_playing) ms /= 10;
Chris@43 1854
Chris@43 1855 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1856 if (!s.m_playing) cout << endl;
Chris@293 1857 cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << endl;
Chris@43 1858 #endif
Chris@43 1859
Chris@366 1860 s.m_condition.wait(&s.m_mutex, int(ms));
Chris@43 1861 }
Chris@43 1862
Chris@43 1863 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1864 cout << "AudioCallbackPlaySourceFillThread: awoken" << endl;
Chris@43 1865 #endif
Chris@43 1866
Chris@43 1867 work = false;
Chris@43 1868
Chris@103 1869 if (!s.getSourceSampleRate()) {
Chris@103 1870 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1871 cout << "AudioCallbackPlaySourceFillThread: source sample rate is zero" << endl;
Chris@103 1872 #endif
Chris@103 1873 continue;
Chris@103 1874 }
Chris@43 1875
Chris@43 1876 bool playing = s.m_playing;
Chris@43 1877
Chris@43 1878 if (playing && !previouslyPlaying) {
Chris@43 1879 #ifdef DEBUG_AUDIO_PLAY_SOURCE
Chris@293 1880 cout << "AudioCallbackPlaySourceFillThread: playback state changed, resetting" << endl;
Chris@43 1881 #endif
Chris@366 1882 for (int c = 0; c < s.getTargetChannelCount(); ++c) {
Chris@43 1883 RingBuffer<float> *rb = s.getReadRingBuffer(c);
Chris@43 1884 if (rb) rb->reset();
Chris@43 1885 }
Chris@43 1886 }
Chris@43 1887 previouslyPlaying = playing;
Chris@43 1888
Chris@43 1889 work = s.fillBuffers();
Chris@43 1890 }
Chris@43 1891
Chris@43 1892 s.m_mutex.unlock();
Chris@43 1893 }
Chris@43 1894