AudioCallbackPlaySource.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "AudioCallbackPlaySource.h"
00017 
00018 #include "AudioGenerator.h"
00019 
00020 #include "data/model/Model.h"
00021 #include "view/ViewManager.h"
00022 #include "base/PlayParameterRepository.h"
00023 #include "base/Preferences.h"
00024 #include "data/model/DenseTimeValueModel.h"
00025 #include "data/model/WaveFileModel.h"
00026 #include "data/model/SparseOneDimensionalModel.h"
00027 #include "plugin/RealTimePluginInstance.h"
00028 
00029 #include "AudioCallbackPlayTarget.h"
00030 
00031 #include <rubberband/RubberBandStretcher.h>
00032 using namespace RubberBand;
00033 
00034 #include <iostream>
00035 #include <cassert>
00036 
00037 //#define DEBUG_AUDIO_PLAY_SOURCE 1
00038 //#define DEBUG_AUDIO_PLAY_SOURCE_PLAYING 1
00039 
00040 const size_t AudioCallbackPlaySource::m_ringBufferSize = 131071;
00041 
00042 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManager *manager,
00043                                                  QString clientName) :
00044     m_viewManager(manager),
00045     m_audioGenerator(new AudioGenerator()),
00046     m_clientName(clientName),
00047     m_readBuffers(0),
00048     m_writeBuffers(0),
00049     m_readBufferFill(0),
00050     m_writeBufferFill(0),
00051     m_bufferScavenger(1),
00052     m_sourceChannelCount(0),
00053     m_blockSize(1024),
00054     m_sourceSampleRate(0),
00055     m_targetSampleRate(0),
00056     m_playLatency(0),
00057     m_target(0),
00058     m_lastRetrievalTimestamp(0.0),
00059     m_lastRetrievedBlockSize(0),
00060     m_playing(false),
00061     m_exiting(false),
00062     m_lastModelEndFrame(0),
00063     m_outputLeft(0.0),
00064     m_outputRight(0.0),
00065     m_auditioningPlugin(0),
00066     m_auditioningPluginBypassed(false),
00067     m_playStartFrame(0),
00068     m_playStartFramePassed(false),
00069     m_timeStretcher(0),
00070     m_stretchRatio(1.0),
00071     m_stretcherInputCount(0),
00072     m_stretcherInputs(0),
00073     m_stretcherInputSizes(0),
00074     m_fillThread(0),
00075     m_converter(0),
00076     m_crapConverter(0),
00077     m_resampleQuality(Preferences::getInstance()->getResampleQuality())
00078 {
00079     m_viewManager->setAudioPlaySource(this);
00080 
00081     connect(m_viewManager, SIGNAL(selectionChanged()),
00082             this, SLOT(selectionChanged()));
00083     connect(m_viewManager, SIGNAL(playLoopModeChanged()),
00084             this, SLOT(playLoopModeChanged()));
00085     connect(m_viewManager, SIGNAL(playSelectionModeChanged()),
00086             this, SLOT(playSelectionModeChanged()));
00087 
00088     connect(PlayParameterRepository::getInstance(),
00089             SIGNAL(playParametersChanged(PlayParameters *)),
00090             this, SLOT(playParametersChanged(PlayParameters *)));
00091 
00092     connect(Preferences::getInstance(),
00093             SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
00094             this, SLOT(preferenceChanged(PropertyContainer::PropertyName)));
00095 }
00096 
00097 AudioCallbackPlaySource::~AudioCallbackPlaySource()
00098 {
00099     m_exiting = true;
00100 
00101     if (m_fillThread) {
00102         m_condition.wakeAll();
00103         m_fillThread->wait();
00104         delete m_fillThread;
00105     }
00106 
00107     clearModels();
00108     
00109     if (m_readBuffers != m_writeBuffers) {
00110         delete m_readBuffers;
00111     }
00112 
00113     delete m_writeBuffers;
00114 
00115     delete m_audioGenerator;
00116 
00117     for (size_t i = 0; i < m_stretcherInputCount; ++i) {
00118         delete[] m_stretcherInputs[i];
00119     }
00120     delete[] m_stretcherInputSizes;
00121     delete[] m_stretcherInputs;
00122 
00123     m_bufferScavenger.scavenge(true);
00124     m_pluginScavenger.scavenge(true);
00125 }
00126 
00127 void
00128 AudioCallbackPlaySource::addModel(Model *model)
00129 {
00130     if (m_models.find(model) != m_models.end()) return;
00131 
00132     bool canPlay = m_audioGenerator->addModel(model);
00133 
00134     m_mutex.lock();
00135 
00136     m_models.insert(model);
00137     if (model->getEndFrame() > m_lastModelEndFrame) {
00138         m_lastModelEndFrame = model->getEndFrame();
00139     }
00140 
00141     bool buffersChanged = false, srChanged = false;
00142 
00143     size_t modelChannels = 1;
00144     DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model);
00145     if (dtvm) modelChannels = dtvm->getChannelCount();
00146     if (modelChannels > m_sourceChannelCount) {
00147         m_sourceChannelCount = modelChannels;
00148     }
00149 
00150 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00151     std::cout << "Adding model with " << modelChannels << " channels " << std::endl;
00152 #endif
00153 
00154     if (m_sourceSampleRate == 0) {
00155 
00156         m_sourceSampleRate = model->getSampleRate();
00157         srChanged = true;
00158 
00159     } else if (model->getSampleRate() != m_sourceSampleRate) {
00160 
00161         // If this is a dense time-value model and we have no other, we
00162         // can just switch to this model's sample rate
00163 
00164         if (dtvm) {
00165 
00166             bool conflicting = false;
00167 
00168             for (std::set<Model *>::const_iterator i = m_models.begin();
00169                  i != m_models.end(); ++i) {
00170                 // Only wave file models can be considered conflicting --
00171                 // writable wave file models are derived and we shouldn't
00172                 // take their rates into account.  Also, don't give any
00173                 // particular weight to a file that's already playing at
00174                 // the wrong rate anyway
00175                 WaveFileModel *wfm = dynamic_cast<WaveFileModel *>(*i);
00176                 if (wfm && wfm != dtvm &&
00177                     wfm->getSampleRate() != model->getSampleRate() &&
00178                     wfm->getSampleRate() == m_sourceSampleRate) {
00179                     std::cerr << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << std::endl;
00180                     conflicting = true;
00181                     break;
00182                 }
00183             }
00184 
00185             if (conflicting) {
00186 
00187                 std::cerr << "AudioCallbackPlaySource::addModel: ERROR: "
00188                           << "New model sample rate does not match" << std::endl
00189                           << "existing model(s) (new " << model->getSampleRate()
00190                           << " vs " << m_sourceSampleRate
00191                           << "), playback will be wrong"
00192                           << std::endl;
00193                 
00194                 emit sampleRateMismatch(model->getSampleRate(),
00195                                         m_sourceSampleRate,
00196                                         false);
00197             } else {
00198                 m_sourceSampleRate = model->getSampleRate();
00199                 srChanged = true;
00200             }
00201         }
00202     }
00203 
00204     if (!m_writeBuffers || (m_writeBuffers->size() < getTargetChannelCount())) {
00205         clearRingBuffers(true, getTargetChannelCount());
00206         buffersChanged = true;
00207     } else {
00208         if (canPlay) clearRingBuffers(true);
00209     }
00210 
00211     if (buffersChanged || srChanged) {
00212         if (m_converter) {
00213             src_delete(m_converter);
00214             src_delete(m_crapConverter);
00215             m_converter = 0;
00216             m_crapConverter = 0;
00217         }
00218     }
00219 
00220     m_mutex.unlock();
00221 
00222     m_audioGenerator->setTargetChannelCount(getTargetChannelCount());
00223 
00224     if (!m_fillThread) {
00225         m_fillThread = new FillThread(*this);
00226         m_fillThread->start();
00227     }
00228 
00229 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00230     std::cout << "AudioCallbackPlaySource::addModel: now have " << m_models.size() << " model(s) -- emitting modelReplaced" << std::endl;
00231 #endif
00232 
00233     if (buffersChanged || srChanged) {
00234         emit modelReplaced();
00235     }
00236 
00237     connect(model, SIGNAL(modelChanged(size_t, size_t)),
00238             this, SLOT(modelChanged(size_t, size_t)));
00239 
00240     m_condition.wakeAll();
00241 }
00242 
00243 void
00244 AudioCallbackPlaySource::modelChanged(size_t startFrame, size_t endFrame)
00245 {
00246 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00247     std::cerr << "AudioCallbackPlaySource::modelChanged(" << startFrame << "," << endFrame << ")" << std::endl;
00248 #endif
00249     if (endFrame > m_lastModelEndFrame) {
00250         m_lastModelEndFrame = endFrame;
00251         rebuildRangeLists();
00252     }
00253 }
00254 
00255 void
00256 AudioCallbackPlaySource::removeModel(Model *model)
00257 {
00258     m_mutex.lock();
00259 
00260 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00261     std::cout << "AudioCallbackPlaySource::removeModel(" << model << ")" << std::endl;
00262 #endif
00263 
00264     disconnect(model, SIGNAL(modelChanged(size_t, size_t)),
00265                this, SLOT(modelChanged(size_t, size_t)));
00266 
00267     m_models.erase(model);
00268 
00269     if (m_models.empty()) {
00270         if (m_converter) {
00271             src_delete(m_converter);
00272             src_delete(m_crapConverter);
00273             m_converter = 0;
00274             m_crapConverter = 0;
00275         }
00276         m_sourceSampleRate = 0;
00277     }
00278 
00279     size_t lastEnd = 0;
00280     for (std::set<Model *>::const_iterator i = m_models.begin();
00281          i != m_models.end(); ++i) {
00282 //      std::cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << std::endl;
00283         if ((*i)->getEndFrame() > lastEnd) lastEnd = (*i)->getEndFrame();
00284 //      std::cout << "(done, lastEnd now " << lastEnd << ")" << std::endl;
00285     }
00286     m_lastModelEndFrame = lastEnd;
00287 
00288     m_mutex.unlock();
00289 
00290     m_audioGenerator->removeModel(model);
00291 
00292     clearRingBuffers();
00293 }
00294 
00295 void
00296 AudioCallbackPlaySource::clearModels()
00297 {
00298     m_mutex.lock();
00299 
00300 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00301     std::cout << "AudioCallbackPlaySource::clearModels()" << std::endl;
00302 #endif
00303 
00304     m_models.clear();
00305 
00306     if (m_converter) {
00307         src_delete(m_converter);
00308         src_delete(m_crapConverter);
00309         m_converter = 0;
00310         m_crapConverter = 0;
00311     }
00312 
00313     m_lastModelEndFrame = 0;
00314 
00315     m_sourceSampleRate = 0;
00316 
00317     m_mutex.unlock();
00318 
00319     m_audioGenerator->clearModels();
00320 
00321     clearRingBuffers();
00322 }    
00323 
00324 void
00325 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, size_t count)
00326 {
00327     if (!haveLock) m_mutex.lock();
00328 
00329     rebuildRangeLists();
00330 
00331     if (count == 0) {
00332         if (m_writeBuffers) count = m_writeBuffers->size();
00333     }
00334 
00335     m_writeBufferFill = getCurrentBufferedFrame();
00336 
00337     if (m_readBuffers != m_writeBuffers) {
00338         delete m_writeBuffers;
00339     }
00340 
00341     m_writeBuffers = new RingBufferVector;
00342 
00343     for (size_t i = 0; i < count; ++i) {
00344         m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize));
00345     }
00346 
00347 //    std::cout << "AudioCallbackPlaySource::clearRingBuffers: Created "
00348 //            << count << " write buffers" << std::endl;
00349 
00350     if (!haveLock) {
00351         m_mutex.unlock();
00352     }
00353 }
00354 
00355 void
00356 AudioCallbackPlaySource::play(size_t startFrame)
00357 {
00358     if (m_viewManager->getPlaySelectionMode() &&
00359         !m_viewManager->getSelections().empty()) {
00360 
00361         std::cerr << "AudioCallbackPlaySource::play: constraining frame " << startFrame << " to selection = ";
00362 
00363         startFrame = m_viewManager->constrainFrameToSelection(startFrame);
00364 
00365         std::cerr << startFrame << std::endl;
00366 
00367     } else {
00368         if (startFrame >= m_lastModelEndFrame) {
00369             startFrame = 0;
00370         }
00371     }
00372 
00373     std::cerr << "play(" << startFrame << ") -> playback model ";
00374 
00375     startFrame = m_viewManager->alignReferenceToPlaybackFrame(startFrame);
00376 
00377     std::cerr << startFrame << std::endl;
00378 
00379     // The fill thread will automatically empty its buffers before
00380     // starting again if we have not so far been playing, but not if
00381     // we're just re-seeking.
00382 
00383     m_mutex.lock();
00384     if (m_timeStretcher) {
00385         m_timeStretcher->reset();
00386     }
00387     if (m_playing) {
00388         std::cerr << "playing already, resetting" << std::endl;
00389         m_readBufferFill = m_writeBufferFill = startFrame;
00390         if (m_readBuffers) {
00391             for (size_t c = 0; c < getTargetChannelCount(); ++c) {
00392                 RingBuffer<float> *rb = getReadRingBuffer(c);
00393                 std::cerr << "reset ring buffer for channel " << c << std::endl;
00394                 if (rb) rb->reset();
00395             }
00396         }
00397         if (m_converter) src_reset(m_converter);
00398         if (m_crapConverter) src_reset(m_crapConverter);
00399     } else {
00400         if (m_converter) src_reset(m_converter);
00401         if (m_crapConverter) src_reset(m_crapConverter);
00402         m_readBufferFill = m_writeBufferFill = startFrame;
00403     }
00404     m_mutex.unlock();
00405 
00406     m_audioGenerator->reset();
00407 
00408     m_playStartFrame = startFrame;
00409     m_playStartFramePassed = false;
00410     m_playStartedAt = RealTime::zeroTime;
00411     if (m_target) {
00412         m_playStartedAt = RealTime::fromSeconds(m_target->getCurrentTime());
00413     }
00414 
00415     bool changed = !m_playing;
00416     m_lastRetrievalTimestamp = 0;
00417     m_playing = true;
00418     m_condition.wakeAll();
00419     if (changed) emit playStatusChanged(m_playing);
00420 }
00421 
00422 void
00423 AudioCallbackPlaySource::stop()
00424 {
00425     bool changed = m_playing;
00426     m_playing = false;
00427     m_condition.wakeAll();
00428     m_lastRetrievalTimestamp = 0;
00429     if (changed) emit playStatusChanged(m_playing);
00430 }
00431 
00432 void
00433 AudioCallbackPlaySource::selectionChanged()
00434 {
00435     if (m_viewManager->getPlaySelectionMode()) {
00436         clearRingBuffers();
00437     }
00438 }
00439 
00440 void
00441 AudioCallbackPlaySource::playLoopModeChanged()
00442 {
00443     clearRingBuffers();
00444 }
00445 
00446 void
00447 AudioCallbackPlaySource::playSelectionModeChanged()
00448 {
00449     if (!m_viewManager->getSelections().empty()) {
00450         clearRingBuffers();
00451     }
00452 }
00453 
00454 void
00455 AudioCallbackPlaySource::playParametersChanged(PlayParameters *)
00456 {
00457     clearRingBuffers();
00458 }
00459 
00460 void
00461 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n)
00462 {
00463     if (n == "Resample Quality") {
00464         setResampleQuality(Preferences::getInstance()->getResampleQuality());
00465     }
00466 }
00467 
00468 void
00469 AudioCallbackPlaySource::audioProcessingOverload()
00470 {
00471     RealTimePluginInstance *ap = m_auditioningPlugin;
00472     if (ap && m_playing && !m_auditioningPluginBypassed) {
00473         m_auditioningPluginBypassed = true;
00474         emit audioOverloadPluginDisabled();
00475     }
00476 }
00477 
00478 void
00479 AudioCallbackPlaySource::setTarget(AudioCallbackPlayTarget *target, size_t size)
00480 {
00481     m_target = target;
00482 //    std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
00483     assert(size < m_ringBufferSize);
00484     m_blockSize = size;
00485 }
00486 
00487 size_t
00488 AudioCallbackPlaySource::getTargetBlockSize() const
00489 {
00490 //    std::cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << std::endl;
00491     return m_blockSize;
00492 }
00493 
00494 void
00495 AudioCallbackPlaySource::setTargetPlayLatency(size_t latency)
00496 {
00497     m_playLatency = latency;
00498 }
00499 
00500 size_t
00501 AudioCallbackPlaySource::getTargetPlayLatency() const
00502 {
00503     return m_playLatency;
00504 }
00505 
00506 size_t
00507 AudioCallbackPlaySource::getCurrentPlayingFrame()
00508 {
00509     // This method attempts to estimate which audio sample frame is
00510     // "currently coming through the speakers".
00511 
00512     size_t targetRate = getTargetSampleRate();
00513     size_t latency = m_playLatency; // at target rate
00514     RealTime latency_t = RealTime::frame2RealTime(latency, targetRate);
00515 
00516     return getCurrentFrame(latency_t);
00517 }
00518 
00519 size_t
00520 AudioCallbackPlaySource::getCurrentBufferedFrame()
00521 {
00522     return getCurrentFrame(RealTime::zeroTime);
00523 }
00524 
00525 size_t
00526 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t)
00527 {
00528     bool resample = false;
00529     double resampleRatio = 1.0;
00530 
00531     // We resample when filling the ring buffer, and time-stretch when
00532     // draining it.  The buffer contains data at the "target rate" and
00533     // the latency provided by the target is also at the target rate.
00534     // Because of the multiple rates involved, we do the actual
00535     // calculation using RealTime instead.
00536 
00537     size_t sourceRate = getSourceSampleRate();
00538     size_t targetRate = getTargetSampleRate();
00539 
00540     if (sourceRate == 0 || targetRate == 0) return 0;
00541 
00542     size_t inbuffer = 0; // at target rate
00543 
00544     for (size_t c = 0; c < getTargetChannelCount(); ++c) {
00545         RingBuffer<float> *rb = getReadRingBuffer(c);
00546         if (rb) {
00547             size_t here = rb->getReadSpace();
00548             if (c == 0 || here < inbuffer) inbuffer = here;
00549         }
00550     }
00551 
00552     size_t readBufferFill = m_readBufferFill;
00553     size_t lastRetrievedBlockSize = m_lastRetrievedBlockSize;
00554     double lastRetrievalTimestamp = m_lastRetrievalTimestamp;
00555     double currentTime = 0.0;
00556     if (m_target) currentTime = m_target->getCurrentTime();
00557 
00558     RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate);
00559 
00560     size_t stretchlat = 0;
00561     double timeRatio = 1.0;
00562 
00563     if (m_timeStretcher) {
00564         stretchlat = m_timeStretcher->getLatency();
00565         timeRatio = m_timeStretcher->getTimeRatio();
00566     }
00567 
00568     RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate);
00569 
00570     // When the target has just requested a block from us, the last
00571     // sample it obtained was our buffer fill frame count minus the
00572     // amount of read space (converted back to source sample rate)
00573     // remaining now.  That sample is not expected to be played until
00574     // the target's play latency has elapsed.  By the time the
00575     // following block is requested, that sample will be at the
00576     // target's play latency minus the last requested block size away
00577     // from being played.
00578 
00579     RealTime sincerequest_t = RealTime::zeroTime;
00580     RealTime lastretrieved_t = RealTime::zeroTime;
00581 
00582     if (m_target && lastRetrievalTimestamp != 0.0) {
00583 
00584         lastretrieved_t = RealTime::frame2RealTime
00585             (lastRetrievedBlockSize, targetRate);
00586 
00587         // calculate number of frames at target rate that have elapsed
00588         // since the end of the last call to getSourceSamples
00589 
00590         double elapsed = currentTime - lastRetrievalTimestamp;
00591 
00592         if (elapsed > 0.0) {
00593             sincerequest_t = RealTime::fromSeconds(elapsed);
00594         }
00595 
00596     } else {
00597 
00598         lastretrieved_t = RealTime::frame2RealTime
00599             (getTargetBlockSize(), targetRate);
00600     }
00601 
00602     RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate);
00603 
00604     if (timeRatio != 1.0) {
00605         lastretrieved_t = lastretrieved_t / timeRatio;
00606         sincerequest_t = sincerequest_t / timeRatio;
00607     }
00608 
00609     bool looping = m_viewManager->getPlayLoopMode();
00610 
00611 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
00612     std::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: " << lastretrieved_t << std::endl;
00613 #endif
00614 
00615     RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
00616 
00617     // Normally the range lists should contain at least one item each
00618     // -- if playback is unconstrained, that item should report the
00619     // entire source audio duration.
00620 
00621     if (m_rangeStarts.empty()) {
00622         rebuildRangeLists();
00623     }
00624 
00625     if (m_rangeStarts.empty()) {
00626         // this code is only used in case of error in rebuildRangeLists
00627         RealTime playing_t = bufferedto_t
00628             - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
00629             + sincerequest_t;
00630         size_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
00631         return m_viewManager->alignPlaybackFrameToReference(frame);
00632     }
00633 
00634     int inRange = 0;
00635     int index = 0;
00636 
00637     for (size_t i = 0; i < m_rangeStarts.size(); ++i) {
00638         if (bufferedto_t >= m_rangeStarts[i]) {
00639             inRange = index;
00640         } else {
00641             break;
00642         }
00643         ++index;
00644     }
00645 
00646     if (inRange >= m_rangeStarts.size()) inRange = m_rangeStarts.size()-1;
00647 
00648     RealTime playing_t = bufferedto_t;
00649 
00650     playing_t = playing_t
00651         - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
00652         + sincerequest_t;
00653 
00654     // This rather gross little hack is used to ensure that latency
00655     // compensation doesn't result in the playback pointer appearing
00656     // to start earlier than the actual playback does.  It doesn't
00657     // work properly (hence the bail-out in the middle) because if we
00658     // are playing a relatively short looped region, the playing time
00659     // estimated from the buffer fill frame may have wrapped around
00660     // the region boundary and end up being much smaller than the
00661     // theoretical play start frame, perhaps even for the entire
00662     // duration of playback!
00663 
00664     if (!m_playStartFramePassed) {
00665         RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame,
00666                                                         sourceRate);
00667         if (playing_t < playstart_t) {
00668 //            std::cerr << "playing_t " << playing_t << " < playstart_t " 
00669 //                      << playstart_t << std::endl;
00670             if (sincerequest_t > RealTime::zeroTime &&
00671                 m_playStartedAt + latency_t + stretchlat_t <
00672                 RealTime::fromSeconds(currentTime)) {
00673 //                std::cerr << "but we've been playing for long enough that I think we should disregard it (it probably results from loop wrapping)" << std::endl;
00674                 m_playStartFramePassed = true;
00675             } else {
00676                 playing_t = playstart_t;
00677             }
00678         } else {
00679             m_playStartFramePassed = true;
00680         }
00681     }
00682 
00683     playing_t = playing_t - m_rangeStarts[inRange];
00684  
00685 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
00686     std::cerr << "playing_t as offset into range " << inRange << " (with start = " << m_rangeStarts[inRange] << ") = " << playing_t << std::endl;
00687 #endif
00688 
00689     while (playing_t < RealTime::zeroTime) {
00690 
00691         if (inRange == 0) {
00692             if (looping) {
00693                 inRange = m_rangeStarts.size() - 1;
00694             } else {
00695                 break;
00696             }
00697         } else {
00698             --inRange;
00699         }
00700 
00701         playing_t = playing_t + m_rangeDurations[inRange];
00702     }
00703 
00704     playing_t = playing_t + m_rangeStarts[inRange];
00705 
00706 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
00707     std::cerr << "  playing time: " << playing_t << std::endl;
00708 #endif
00709 
00710     if (!looping) {
00711         if (inRange == m_rangeStarts.size()-1 &&
00712             playing_t >= m_rangeStarts[inRange] + m_rangeDurations[inRange]) {
00713 std::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" << std::endl;
00714             stop();
00715         }
00716     }
00717 
00718     if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
00719 
00720     size_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
00721     return m_viewManager->alignPlaybackFrameToReference(frame);
00722 }
00723 
00724 void
00725 AudioCallbackPlaySource::rebuildRangeLists()
00726 {
00727     bool constrained = (m_viewManager->getPlaySelectionMode());
00728 
00729     m_rangeStarts.clear();
00730     m_rangeDurations.clear();
00731 
00732     size_t sourceRate = getSourceSampleRate();
00733     if (sourceRate == 0) return;
00734 
00735     RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
00736     if (end == RealTime::zeroTime) return;
00737 
00738     if (!constrained) {
00739         m_rangeStarts.push_back(RealTime::zeroTime);
00740         m_rangeDurations.push_back(end);
00741         return;
00742     }
00743 
00744     MultiSelection::SelectionList selections = m_viewManager->getSelections();
00745     MultiSelection::SelectionList::const_iterator i;
00746 
00747 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00748     std::cerr << "AudioCallbackPlaySource::rebuildRangeLists" << std::endl;
00749 #endif
00750 
00751     if (!selections.empty()) {
00752 
00753         for (i = selections.begin(); i != selections.end(); ++i) {
00754             
00755             RealTime start =
00756                 (RealTime::frame2RealTime
00757                  (m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
00758                   sourceRate));
00759             RealTime duration = 
00760                 (RealTime::frame2RealTime
00761                  (m_viewManager->alignReferenceToPlaybackFrame(i->getEndFrame()) -
00762                   m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
00763                   sourceRate));
00764             
00765             m_rangeStarts.push_back(start);
00766             m_rangeDurations.push_back(duration);
00767         }
00768     } else {
00769         m_rangeStarts.push_back(RealTime::zeroTime);
00770         m_rangeDurations.push_back(end);
00771     }
00772 
00773 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00774     std::cerr << "Now have " << m_rangeStarts.size() << " play ranges" << std::endl;
00775 #endif
00776 }
00777 
00778 void
00779 AudioCallbackPlaySource::setOutputLevels(float left, float right)
00780 {
00781     m_outputLeft = left;
00782     m_outputRight = right;
00783 }
00784 
00785 bool
00786 AudioCallbackPlaySource::getOutputLevels(float &left, float &right)
00787 {
00788     left = m_outputLeft;
00789     right = m_outputRight;
00790     return true;
00791 }
00792 
00793 void
00794 AudioCallbackPlaySource::setTargetSampleRate(size_t sr)
00795 {
00796     m_targetSampleRate = sr;
00797     initialiseConverter();
00798 }
00799 
00800 void
00801 AudioCallbackPlaySource::initialiseConverter()
00802 {
00803     m_mutex.lock();
00804 
00805     if (m_converter) {
00806         src_delete(m_converter);
00807         src_delete(m_crapConverter);
00808         m_converter = 0;
00809         m_crapConverter = 0;
00810     }
00811 
00812     if (getSourceSampleRate() != getTargetSampleRate()) {
00813 
00814         int err = 0;
00815 
00816         m_converter = src_new(m_resampleQuality == 2 ? SRC_SINC_BEST_QUALITY :
00817                               m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY :
00818                               m_resampleQuality == 0 ? SRC_SINC_FASTEST :
00819                                                        SRC_SINC_MEDIUM_QUALITY,
00820                               getTargetChannelCount(), &err);
00821 
00822         if (m_converter) {
00823             m_crapConverter = src_new(SRC_LINEAR,
00824                                       getTargetChannelCount(),
00825                                       &err);
00826         }
00827 
00828         if (!m_converter || !m_crapConverter) {
00829             std::cerr
00830                 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: "
00831                 << src_strerror(err) << std::endl;
00832 
00833             if (m_converter) {
00834                 src_delete(m_converter);
00835                 m_converter = 0;
00836             } 
00837 
00838             if (m_crapConverter) {
00839                 src_delete(m_crapConverter);
00840                 m_crapConverter = 0;
00841             }
00842 
00843             m_mutex.unlock();
00844 
00845             emit sampleRateMismatch(getSourceSampleRate(),
00846                                     getTargetSampleRate(),
00847                                     false);
00848         } else {
00849 
00850             m_mutex.unlock();
00851 
00852             emit sampleRateMismatch(getSourceSampleRate(),
00853                                     getTargetSampleRate(),
00854                                     true);
00855         }
00856     } else {
00857         m_mutex.unlock();
00858     }
00859 }
00860 
00861 void
00862 AudioCallbackPlaySource::setResampleQuality(int q)
00863 {
00864     if (q == m_resampleQuality) return;
00865     m_resampleQuality = q;
00866 
00867 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00868     std::cerr << "AudioCallbackPlaySource::setResampleQuality: setting to "
00869               << m_resampleQuality << std::endl;
00870 #endif
00871 
00872     initialiseConverter();
00873 }
00874 
00875 void
00876 AudioCallbackPlaySource::setAuditioningPlugin(RealTimePluginInstance *plugin)
00877 {
00878     RealTimePluginInstance *formerPlugin = m_auditioningPlugin;
00879     m_auditioningPlugin = plugin;
00880     m_auditioningPluginBypassed = false;
00881     if (formerPlugin) m_pluginScavenger.claim(formerPlugin);
00882 }
00883 
00884 void
00885 AudioCallbackPlaySource::setSoloModelSet(std::set<Model *> s)
00886 {
00887     m_audioGenerator->setSoloModelSet(s);
00888     clearRingBuffers();
00889 }
00890 
00891 void
00892 AudioCallbackPlaySource::clearSoloModelSet()
00893 {
00894     m_audioGenerator->clearSoloModelSet();
00895     clearRingBuffers();
00896 }
00897 
00898 size_t
00899 AudioCallbackPlaySource::getTargetSampleRate() const
00900 {
00901     if (m_targetSampleRate) return m_targetSampleRate;
00902     else return getSourceSampleRate();
00903 }
00904 
00905 size_t
00906 AudioCallbackPlaySource::getSourceChannelCount() const
00907 {
00908     return m_sourceChannelCount;
00909 }
00910 
00911 size_t
00912 AudioCallbackPlaySource::getTargetChannelCount() const
00913 {
00914     if (m_sourceChannelCount < 2) return 2;
00915     return m_sourceChannelCount;
00916 }
00917 
00918 size_t
00919 AudioCallbackPlaySource::getSourceSampleRate() const
00920 {
00921     return m_sourceSampleRate;
00922 }
00923 
00924 void
00925 AudioCallbackPlaySource::setTimeStretch(float factor)
00926 {
00927     m_stretchRatio = factor;
00928 
00929     if (m_timeStretcher || (factor == 1.f)) {
00930         // stretch ratio will be set in next process call if appropriate
00931         return;
00932     } else {
00933         m_stretcherInputCount = getTargetChannelCount();
00934         RubberBandStretcher *stretcher = new RubberBandStretcher
00935             (getTargetSampleRate(),
00936              m_stretcherInputCount,
00937              RubberBandStretcher::OptionProcessRealTime,
00938              factor);
00939         m_stretcherInputs = new float *[m_stretcherInputCount];
00940         m_stretcherInputSizes = new size_t[m_stretcherInputCount];
00941         for (size_t c = 0; c < m_stretcherInputCount; ++c) {
00942             m_stretcherInputSizes[c] = 16384;
00943             m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
00944         }
00945         m_timeStretcher = stretcher;
00946         return;
00947     }
00948 }
00949 
00950 size_t
00951 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
00952 {
00953     if (!m_playing) {
00954         for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
00955             for (size_t i = 0; i < count; ++i) {
00956                 buffer[ch][i] = 0.0;
00957             }
00958         }
00959         return 0;
00960     }
00961 
00962     // Ensure that all buffers have at least the amount of data we
00963     // need -- else reduce the size of our requests correspondingly
00964 
00965     for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
00966 
00967         RingBuffer<float> *rb = getReadRingBuffer(ch);
00968         
00969         if (!rb) {
00970             std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
00971                       << "No ring buffer available for channel " << ch
00972                       << ", returning no data here" << std::endl;
00973             count = 0;
00974             break;
00975         }
00976 
00977         size_t rs = rb->getReadSpace();
00978         if (rs < count) {
00979 #ifdef DEBUG_AUDIO_PLAY_SOURCE
00980             std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
00981                       << "Ring buffer for channel " << ch << " has only "
00982                       << rs << " (of " << count << ") samples available, "
00983                       << "reducing request size" << std::endl;
00984 #endif
00985             count = rs;
00986         }
00987     }
00988 
00989     if (count == 0) return 0;
00990 
00991     RubberBandStretcher *ts = m_timeStretcher;
00992     float ratio = ts ? ts->getTimeRatio() : 1.f;
00993 
00994     if (ratio != m_stretchRatio) {
00995         if (!ts) {
00996             std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << std::endl;
00997             m_stretchRatio = 1.f;
00998         } else {
00999             ts->setTimeRatio(m_stretchRatio);
01000         }
01001     }
01002 
01003     if (m_target) {
01004         m_lastRetrievedBlockSize = count;
01005         m_lastRetrievalTimestamp = m_target->getCurrentTime();
01006     }
01007 
01008     if (!ts || ratio == 1.f) {
01009 
01010         size_t got = 0;
01011 
01012         for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
01013 
01014             RingBuffer<float> *rb = getReadRingBuffer(ch);
01015 
01016             if (rb) {
01017 
01018                 // this is marginally more likely to leave our channels in
01019                 // sync after a processing failure than just passing "count":
01020                 size_t request = count;
01021                 if (ch > 0) request = got;
01022 
01023                 got = rb->read(buffer[ch], request);
01024             
01025 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
01026                 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << std::endl;
01027 #endif
01028             }
01029 
01030             for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
01031                 for (size_t i = got; i < count; ++i) {
01032                     buffer[ch][i] = 0.0;
01033                 }
01034             }
01035         }
01036 
01037         applyAuditioningEffect(count, buffer);
01038 
01039         m_condition.wakeAll();
01040 
01041         return got;
01042     }
01043 
01044     size_t channels = getTargetChannelCount();
01045     size_t available;
01046     int warned = 0;
01047     size_t fedToStretcher = 0;
01048 
01049     // The input block for a given output is approx output / ratio,
01050     // but we can't predict it exactly, for an adaptive timestretcher.
01051 
01052     while ((available = ts->available()) < count) {
01053 
01054         size_t reqd = lrintf((count - available) / ratio);
01055         reqd = std::max(reqd, ts->getSamplesRequired());
01056         if (reqd == 0) reqd = 1;
01057                 
01058         size_t got = reqd;
01059 
01060 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
01061         std::cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << std::endl;
01062 #endif
01063 
01064         for (size_t c = 0; c < channels; ++c) {
01065             if (c >= m_stretcherInputCount) continue;
01066             if (reqd > m_stretcherInputSizes[c]) {
01067                 if (c == 0) {
01068                     std::cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << std::endl;
01069                 }
01070                 delete[] m_stretcherInputs[c];
01071                 m_stretcherInputSizes[c] = reqd * 2;
01072                 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
01073             }
01074         }
01075 
01076         for (size_t c = 0; c < channels; ++c) {
01077             if (c >= m_stretcherInputCount) continue;
01078             RingBuffer<float> *rb = getReadRingBuffer(c);
01079             if (rb) {
01080                 size_t gotHere = rb->read(m_stretcherInputs[c], got);
01081                 if (gotHere < got) got = gotHere;
01082                 
01083 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
01084                 if (c == 0) {
01085                     std::cerr << "feeding stretcher: got " << gotHere
01086                               << ", " << rb->getReadSpace() << " remain" << std::endl;
01087                 }
01088 #endif
01089                 
01090             } else {
01091                 std::cerr << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << std::endl;
01092             }
01093         }
01094 
01095         if (got < reqd) {
01096             std::cerr << "WARNING: Read underrun in playback ("
01097                       << got << " < " << reqd << ")" << std::endl;
01098         }
01099 
01100         ts->process(m_stretcherInputs, got, false);
01101 
01102         fedToStretcher += got;
01103 
01104         if (got == 0) break;
01105 
01106         if (ts->available() == available) {
01107             std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << std::endl;
01108             if (++warned == 5) break;
01109         }
01110     }
01111 
01112     ts->retrieve(buffer, count);
01113 
01114     applyAuditioningEffect(count, buffer);
01115 
01116     m_condition.wakeAll();
01117 
01118     return count;
01119 }
01120 
01121 void
01122 AudioCallbackPlaySource::applyAuditioningEffect(size_t count, float **buffers)
01123 {
01124     if (m_auditioningPluginBypassed) return;
01125     RealTimePluginInstance *plugin = m_auditioningPlugin;
01126     if (!plugin) return;
01127 
01128     if (plugin->getAudioInputCount() != getTargetChannelCount()) {
01129 //        std::cerr << "plugin input count " << plugin->getAudioInputCount() 
01130 //                  << " != our channel count " << getTargetChannelCount()
01131 //                  << std::endl;
01132         return;
01133     }
01134     if (plugin->getAudioOutputCount() != getTargetChannelCount()) {
01135 //        std::cerr << "plugin output count " << plugin->getAudioOutputCount() 
01136 //                  << " != our channel count " << getTargetChannelCount()
01137 //                  << std::endl;
01138         return;
01139     }
01140     if (plugin->getBufferSize() != count) {
01141 //        std::cerr << "plugin buffer size " << plugin->getBufferSize() 
01142 //                  << " != our block size " << count
01143 //                  << std::endl;
01144         return;
01145     }
01146 
01147     float **ib = plugin->getAudioInputBuffers();
01148     float **ob = plugin->getAudioOutputBuffers();
01149 
01150     for (size_t c = 0; c < getTargetChannelCount(); ++c) {
01151         for (size_t i = 0; i < count; ++i) {
01152             ib[c][i] = buffers[c][i];
01153         }
01154     }
01155 
01156     plugin->run(Vamp::RealTime::zeroTime);
01157     
01158     for (size_t c = 0; c < getTargetChannelCount(); ++c) {
01159         for (size_t i = 0; i < count; ++i) {
01160             buffers[c][i] = ob[c][i];
01161         }
01162     }
01163 }    
01164 
01165 // Called from fill thread, m_playing true, mutex held
01166 bool
01167 AudioCallbackPlaySource::fillBuffers()
01168 {
01169     static float *tmp = 0;
01170     static size_t tmpSize = 0;
01171 
01172     size_t space = 0;
01173     for (size_t c = 0; c < getTargetChannelCount(); ++c) {
01174         RingBuffer<float> *wb = getWriteRingBuffer(c);
01175         if (wb) {
01176             size_t spaceHere = wb->getWriteSpace();
01177             if (c == 0 || spaceHere < space) space = spaceHere;
01178         }
01179     }
01180     
01181     if (space == 0) return false;
01182 
01183     size_t f = m_writeBufferFill;
01184         
01185     bool readWriteEqual = (m_readBuffers == m_writeBuffers);
01186 
01187 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01188     std::cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << std::endl;
01189 #endif
01190 
01191 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01192     std::cout << "buffered to " << f << " already" << std::endl;
01193 #endif
01194 
01195     bool resample = (getSourceSampleRate() != getTargetSampleRate());
01196 
01197 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01198     std::cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << std::endl;
01199 #endif
01200 
01201     size_t channels = getTargetChannelCount();
01202 
01203     size_t orig = space;
01204     size_t got = 0;
01205 
01206     static float **bufferPtrs = 0;
01207     static size_t bufferPtrCount = 0;
01208 
01209     if (bufferPtrCount < channels) {
01210         if (bufferPtrs) delete[] bufferPtrs;
01211         bufferPtrs = new float *[channels];
01212         bufferPtrCount = channels;
01213     }
01214 
01215     size_t generatorBlockSize = m_audioGenerator->getBlockSize();
01216 
01217     if (resample && !m_converter) {
01218         static bool warned = false;
01219         if (!warned) {
01220             std::cerr << "WARNING: sample rates differ, but no converter available!" << std::endl;
01221             warned = true;
01222         }
01223     }
01224 
01225     if (resample && m_converter) {
01226 
01227         double ratio =
01228             double(getTargetSampleRate()) / double(getSourceSampleRate());
01229         orig = size_t(orig / ratio + 0.1);
01230 
01231         // orig must be a multiple of generatorBlockSize
01232         orig = (orig / generatorBlockSize) * generatorBlockSize;
01233         if (orig == 0) return false;
01234 
01235         size_t work = std::max(orig, space);
01236 
01237         // We only allocate one buffer, but we use it in two halves.
01238         // We place the non-interleaved values in the second half of
01239         // the buffer (orig samples for channel 0, orig samples for
01240         // channel 1 etc), and then interleave them into the first
01241         // half of the buffer.  Then we resample back into the second
01242         // half (interleaved) and de-interleave the results back to
01243         // the start of the buffer for insertion into the ringbuffers.
01244         // What a faff -- especially as we've already de-interleaved
01245         // the audio data from the source file elsewhere before we
01246         // even reach this point.
01247         
01248         if (tmpSize < channels * work * 2) {
01249             delete[] tmp;
01250             tmp = new float[channels * work * 2];
01251             tmpSize = channels * work * 2;
01252         }
01253 
01254         float *nonintlv = tmp + channels * work;
01255         float *intlv = tmp;
01256         float *srcout = tmp + channels * work;
01257         
01258         for (size_t c = 0; c < channels; ++c) {
01259             for (size_t i = 0; i < orig; ++i) {
01260                 nonintlv[channels * i + c] = 0.0f;
01261             }
01262         }
01263 
01264         for (size_t c = 0; c < channels; ++c) {
01265             bufferPtrs[c] = nonintlv + c * orig;
01266         }
01267 
01268         got = mixModels(f, orig, bufferPtrs);
01269 
01270         // and interleave into first half
01271         for (size_t c = 0; c < channels; ++c) {
01272             for (size_t i = 0; i < got; ++i) {
01273                 float sample = nonintlv[c * got + i];
01274                 intlv[channels * i + c] = sample;
01275             }
01276         }
01277                 
01278         SRC_DATA data;
01279         data.data_in = intlv;
01280         data.data_out = srcout;
01281         data.input_frames = got;
01282         data.output_frames = work;
01283         data.src_ratio = ratio;
01284         data.end_of_input = 0;
01285         
01286         int err = 0;
01287 
01288         if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
01289 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01290             std::cout << "Using crappy converter" << std::endl;
01291 #endif
01292             err = src_process(m_crapConverter, &data);
01293         } else {
01294             err = src_process(m_converter, &data);
01295         }
01296 
01297         size_t toCopy = size_t(got * ratio + 0.1);
01298 
01299         if (err) {
01300             std::cerr
01301                 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: "
01302                 << src_strerror(err) << std::endl;
01304         } else {
01305             got = data.input_frames_used;
01306             toCopy = data.output_frames_gen;
01307 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01308             std::cout << "Resampled " << got << " frames to " << toCopy << " frames" << std::endl;
01309 #endif
01310         }
01311         
01312         for (size_t c = 0; c < channels; ++c) {
01313             for (size_t i = 0; i < toCopy; ++i) {
01314                 tmp[i] = srcout[channels * i + c];
01315             }
01316             RingBuffer<float> *wb = getWriteRingBuffer(c);
01317             if (wb) wb->write(tmp, toCopy);
01318         }
01319 
01320         m_writeBufferFill = f;
01321         if (readWriteEqual) m_readBufferFill = f;
01322 
01323     } else {
01324 
01325         // space must be a multiple of generatorBlockSize
01326         space = (space / generatorBlockSize) * generatorBlockSize;
01327         if (space == 0) {
01328 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01329             std::cout << "requested fill is less than generator block size of "
01330                       << generatorBlockSize << ", leaving it" << std::endl;
01331 #endif
01332             return false;
01333         }
01334 
01335         if (tmpSize < channels * space) {
01336             delete[] tmp;
01337             tmp = new float[channels * space];
01338             tmpSize = channels * space;
01339         }
01340 
01341         for (size_t c = 0; c < channels; ++c) {
01342 
01343             bufferPtrs[c] = tmp + c * space;
01344             
01345             for (size_t i = 0; i < space; ++i) {
01346                 tmp[c * space + i] = 0.0f;
01347             }
01348         }
01349 
01350         size_t got = mixModels(f, space, bufferPtrs);
01351 
01352         for (size_t c = 0; c < channels; ++c) {
01353 
01354             RingBuffer<float> *wb = getWriteRingBuffer(c);
01355             if (wb) {
01356                 size_t actual = wb->write(bufferPtrs[c], got);
01357 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01358                 std::cout << "Wrote " << actual << " samples for ch " << c << ", now "
01359                           << wb->getReadSpace() << " to read" 
01360                           << std::endl;
01361 #endif
01362                 if (actual < got) {
01363                     std::cerr << "WARNING: Buffer overrun in channel " << c
01364                               << ": wrote " << actual << " of " << got
01365                               << " samples" << std::endl;
01366                 }
01367             }
01368         }
01369 
01370         m_writeBufferFill = f;
01371         if (readWriteEqual) m_readBufferFill = f;
01372 
01374     }
01375 
01376     return true;
01377 }    
01378 
01379 size_t
01380 AudioCallbackPlaySource::mixModels(size_t &frame, size_t count, float **buffers)
01381 {
01382     size_t processed = 0;
01383     size_t chunkStart = frame;
01384     size_t chunkSize = count;
01385     size_t selectionSize = 0;
01386     size_t nextChunkStart = chunkStart + chunkSize;
01387     
01388     bool looping = m_viewManager->getPlayLoopMode();
01389     bool constrained = (m_viewManager->getPlaySelectionMode() &&
01390                         !m_viewManager->getSelections().empty());
01391 
01392     static float **chunkBufferPtrs = 0;
01393     static size_t chunkBufferPtrCount = 0;
01394     size_t channels = getTargetChannelCount();
01395 
01396 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01397     std::cout << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl;
01398 #endif
01399 
01400     if (chunkBufferPtrCount < channels) {
01401         if (chunkBufferPtrs) delete[] chunkBufferPtrs;
01402         chunkBufferPtrs = new float *[channels];
01403         chunkBufferPtrCount = channels;
01404     }
01405 
01406     for (size_t c = 0; c < channels; ++c) {
01407         chunkBufferPtrs[c] = buffers[c];
01408     }
01409 
01410     while (processed < count) {
01411         
01412         chunkSize = count - processed;
01413         nextChunkStart = chunkStart + chunkSize;
01414         selectionSize = 0;
01415 
01416         size_t fadeIn = 0, fadeOut = 0;
01417 
01418         if (constrained) {
01419 
01420             size_t rChunkStart =
01421                 m_viewManager->alignPlaybackFrameToReference(chunkStart);
01422             
01423             Selection selection =
01424                 m_viewManager->getContainingSelection(rChunkStart, true);
01425             
01426             if (selection.isEmpty()) {
01427                 if (looping) {
01428                     selection = *m_viewManager->getSelections().begin();
01429                     chunkStart = m_viewManager->alignReferenceToPlaybackFrame
01430                         (selection.getStartFrame());
01431                     fadeIn = 50;
01432                 }
01433             }
01434 
01435             if (selection.isEmpty()) {
01436 
01437                 chunkSize = 0;
01438                 nextChunkStart = chunkStart;
01439 
01440             } else {
01441 
01442                 size_t sf = m_viewManager->alignReferenceToPlaybackFrame
01443                     (selection.getStartFrame());
01444                 size_t ef = m_viewManager->alignReferenceToPlaybackFrame
01445                     (selection.getEndFrame());
01446 
01447                 selectionSize = ef - sf;
01448 
01449                 if (chunkStart < sf) {
01450                     chunkStart = sf;
01451                     fadeIn = 50;
01452                 }
01453 
01454                 nextChunkStart = chunkStart + chunkSize;
01455 
01456                 if (nextChunkStart >= ef) {
01457                     nextChunkStart = ef;
01458                     fadeOut = 50;
01459                 }
01460 
01461                 chunkSize = nextChunkStart - chunkStart;
01462             }
01463         
01464         } else if (looping && m_lastModelEndFrame > 0) {
01465 
01466             if (chunkStart >= m_lastModelEndFrame) {
01467                 chunkStart = 0;
01468             }
01469             if (chunkSize > m_lastModelEndFrame - chunkStart) {
01470                 chunkSize = m_lastModelEndFrame - chunkStart;
01471             }
01472             nextChunkStart = chunkStart + chunkSize;
01473         }
01474         
01475 //      std::cout << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << std::endl;
01476 
01477         if (!chunkSize) {
01478 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01479             std::cout << "Ending selection playback at " << nextChunkStart << std::endl;
01480 #endif
01481             // We need to maintain full buffers so that the other
01482             // thread can tell where it's got to in the playback -- so
01483             // return the full amount here
01484             frame = frame + count;
01485             return count;
01486         }
01487 
01488 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01489         std::cout << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl;
01490 #endif
01491 
01492         size_t got = 0;
01493 
01494         if (selectionSize < 100) {
01495             fadeIn = 0;
01496             fadeOut = 0;
01497         } else if (selectionSize < 300) {
01498             if (fadeIn > 0) fadeIn = 10;
01499             if (fadeOut > 0) fadeOut = 10;
01500         }
01501 
01502         if (fadeIn > 0) {
01503             if (processed * 2 < fadeIn) {
01504                 fadeIn = processed * 2;
01505             }
01506         }
01507 
01508         if (fadeOut > 0) {
01509             if ((count - processed - chunkSize) * 2 < fadeOut) {
01510                 fadeOut = (count - processed - chunkSize) * 2;
01511             }
01512         }
01513 
01514         for (std::set<Model *>::iterator mi = m_models.begin();
01515              mi != m_models.end(); ++mi) {
01516             
01517             got = m_audioGenerator->mixModel(*mi, chunkStart, 
01518                                              chunkSize, chunkBufferPtrs,
01519                                              fadeIn, fadeOut);
01520         }
01521 
01522         for (size_t c = 0; c < channels; ++c) {
01523             chunkBufferPtrs[c] += chunkSize;
01524         }
01525 
01526         processed += chunkSize;
01527         chunkStart = nextChunkStart;
01528     }
01529 
01530 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01531     std::cout << "Returning selection playback " << processed << " frames to " << nextChunkStart << std::endl;
01532 #endif
01533 
01534     frame = nextChunkStart;
01535     return processed;
01536 }
01537 
01538 void
01539 AudioCallbackPlaySource::unifyRingBuffers()
01540 {
01541     if (m_readBuffers == m_writeBuffers) return;
01542 
01543     // only unify if there will be something to read
01544     for (size_t c = 0; c < getTargetChannelCount(); ++c) {
01545         RingBuffer<float> *wb = getWriteRingBuffer(c);
01546         if (wb) {
01547             if (wb->getReadSpace() < m_blockSize * 2) {
01548                 if ((m_writeBufferFill + m_blockSize * 2) < 
01549                     m_lastModelEndFrame) {
01550                     // OK, we don't have enough and there's more to
01551                     // read -- don't unify until we can do better
01552                     return;
01553                 }
01554             }
01555             break;
01556         }
01557     }
01558 
01559     size_t rf = m_readBufferFill;
01560     RingBuffer<float> *rb = getReadRingBuffer(0);
01561     if (rb) {
01562         size_t rs = rb->getReadSpace();
01564 //      std::cout << "rs = " << rs << std::endl;
01565         if (rs < rf) rf -= rs;
01566         else rf = 0;
01567     }
01568     
01569     //std::cout << "m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl;
01570 
01571     size_t wf = m_writeBufferFill;
01572     size_t skip = 0;
01573     for (size_t c = 0; c < getTargetChannelCount(); ++c) {
01574         RingBuffer<float> *wb = getWriteRingBuffer(c);
01575         if (wb) {
01576             if (c == 0) {
01577                 
01578                 size_t wrs = wb->getReadSpace();
01579 //              std::cout << "wrs = " << wrs << std::endl;
01580 
01581                 if (wrs < wf) wf -= wrs;
01582                 else wf = 0;
01583 //              std::cout << "wf = " << wf << std::endl;
01584                 
01585                 if (wf < rf) skip = rf - wf;
01586                 if (skip == 0) break;
01587             }
01588 
01589 //          std::cout << "skipping " << skip << std::endl;
01590             wb->skip(skip);
01591         }
01592     }
01593                     
01594     m_bufferScavenger.claim(m_readBuffers);
01595     m_readBuffers = m_writeBuffers;
01596     m_readBufferFill = m_writeBufferFill;
01597 //    std::cout << "unified" << std::endl;
01598 }
01599 
01600 void
01601 AudioCallbackPlaySource::FillThread::run()
01602 {
01603     AudioCallbackPlaySource &s(m_source);
01604     
01605 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01606     std::cout << "AudioCallbackPlaySourceFillThread starting" << std::endl;
01607 #endif
01608 
01609     s.m_mutex.lock();
01610 
01611     bool previouslyPlaying = s.m_playing;
01612     bool work = false;
01613 
01614     while (!s.m_exiting) {
01615 
01616         s.unifyRingBuffers();
01617         s.m_bufferScavenger.scavenge();
01618         s.m_pluginScavenger.scavenge();
01619 
01620         if (work && s.m_playing && s.getSourceSampleRate()) {
01621             
01622 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01623             std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl;
01624 #endif
01625 
01626             s.m_mutex.unlock();
01627             s.m_mutex.lock();
01628 
01629         } else {
01630             
01631             float ms = 100;
01632             if (s.getSourceSampleRate() > 0) {
01633                 ms = float(m_ringBufferSize) / float(s.getSourceSampleRate()) * 1000.0;
01634             }
01635             
01636             if (s.m_playing) ms /= 10;
01637 
01638 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01639             if (!s.m_playing) std::cout << std::endl;
01640             std::cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << std::endl;
01641 #endif
01642             
01643             s.m_condition.wait(&s.m_mutex, size_t(ms));
01644         }
01645 
01646 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01647         std::cout << "AudioCallbackPlaySourceFillThread: awoken" << std::endl;
01648 #endif
01649 
01650         work = false;
01651 
01652         if (!s.getSourceSampleRate()) continue;
01653 
01654         bool playing = s.m_playing;
01655 
01656         if (playing && !previouslyPlaying) {
01657 #ifdef DEBUG_AUDIO_PLAY_SOURCE
01658             std::cout << "AudioCallbackPlaySourceFillThread: playback state changed, resetting" << std::endl;
01659 #endif
01660             for (size_t c = 0; c < s.getTargetChannelCount(); ++c) {
01661                 RingBuffer<float> *rb = s.getReadRingBuffer(c);
01662                 if (rb) rb->reset();
01663             }
01664         }
01665         previouslyPlaying = playing;
01666 
01667         work = s.fillBuffers();
01668     }
01669 
01670     s.m_mutex.unlock();
01671 }
01672 

Generated on Wed Feb 20 15:45:24 2008 for SonicVisualiser by  doxygen 1.5.1