annotate audio/AudioCallbackPlaySource.cpp @ 626:51ecc3e2d71c

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