Chris@739: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@739: 
Chris@739: /*
Chris@739:     Sonic Visualiser
Chris@739:     An audio file viewer and annotation editor.
Chris@739:     Centre for Digital Music, Queen Mary, University of London.
Chris@739:     
Chris@739:     This program is free software; you can redistribute it and/or
Chris@739:     modify it under the terms of the GNU General Public License as
Chris@739:     published by the Free Software Foundation; either version 2 of the
Chris@739:     License, or (at your option) any later version.  See the file
Chris@739:     COPYING included with this distribution for more information.
Chris@739: */
Chris@739: 
Chris@739: #include "EffectWrapper.h"
Chris@739: 
Chris@739: #include <rubberband/RubberBandStretcher.h>
Chris@739: 
Chris@739: #include "base/Debug.h"
Chris@739: 
Chris@740: //#define DEBUG_EFFECT_WRAPPER 1
Chris@740: 
Chris@739: using namespace std;
Chris@739: 
Chris@739: static const int DEFAULT_RING_BUFFER_SIZE = 131071;
Chris@739: 
Chris@739: EffectWrapper::EffectWrapper(ApplicationPlaybackSource *source) :
Chris@739:     m_source(source),
Chris@739:     m_bypassed(false),
Chris@739:     m_failed(false),
Chris@739:     m_channelCount(0)
Chris@739: {
Chris@739: }
Chris@739: 
Chris@739: EffectWrapper::~EffectWrapper()
Chris@739: {
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setEffect(weak_ptr<RealTimePluginInstance> effect)
Chris@739: {
Chris@739:     lock_guard<mutex> guard(m_mutex);
Chris@739: 
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:     SVCERR << "EffectWrapper[" << this
Chris@740:            << "]::setEffect(" << effect.lock() << ")" << endl;
Chris@740: #endif
Chris@740:     
Chris@739:     m_effect = effect;
Chris@739:     m_failed = false;
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setBypassed(bool bypassed)
Chris@739: {
Chris@739:     lock_guard<mutex> guard(m_mutex);
Chris@739: 
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:     SVCERR << "EffectWrapper[" << this
Chris@740:            << "]::setBypassed(" << bypassed << ")" << endl;
Chris@740: #endif
Chris@740: 
Chris@739:     m_bypassed = bypassed;
Chris@739: }
Chris@739: 
Chris@739: bool
Chris@739: EffectWrapper::isBypassed() const
Chris@739: {
Chris@739:     lock_guard<mutex> guard(m_mutex);
Chris@739: 
Chris@739:     return m_bypassed;
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::reset()
Chris@739: {
Chris@739:     lock_guard<mutex> guard(m_mutex);
Chris@739: 
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:     SVCERR << "EffectWrapper[" << this << "]::reset" << endl;
Chris@740: #endif
Chris@740: 
Chris@739:     for (auto &rb: m_effectOutputBuffers) {
Chris@739:         rb.reset();
Chris@739:     }
Chris@740: 
Chris@740:     m_failed = false;
Chris@739: }
Chris@739: 
Chris@739: int
Chris@739: EffectWrapper::getSourceSamples(float *const *samples,
Chris@739:                                 int nchannels, int nframes)
Chris@739: {
Chris@739:     lock_guard<mutex> guard(m_mutex);
Chris@739: 
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:     SVCERR << "EffectWrapper[" << this << "]::getSourceSamples: " << nframes
Chris@740:            << " frames across " << nchannels << " channels" << endl;
Chris@740: #endif
Chris@740:     
Chris@739:     auto effect(m_effect.lock());
Chris@739:     
Chris@740:     if (!effect) {
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:         SVCERR << "EffectWrapper::getSourceSamples: "
Chris@740:                << "no effect is set" << endl;
Chris@740: #endif
Chris@739:         return m_source->getSourceSamples(samples, nchannels, nframes);
Chris@739:     }
Chris@739: 
Chris@740:     if (m_bypassed || m_failed) {
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:         SVCERR << "EffectWrapper::getSourceSamples: "
Chris@740:                << "effect is bypassed or has failed" << endl;
Chris@740: #endif
Chris@740:         return m_source->getSourceSamples(samples, nchannels, nframes);
Chris@740:     }
Chris@740:     
Chris@739:     static int warnings = 0;
Chris@739:     if (nchannels != m_channelCount) {
Chris@739:         if (warnings >= 0) {
Chris@740:             SVCERR << "WARNING: EffectWrapper::getSourceSamples called for a number of channels different from that set with setSystemPlaybackChannelCount ("
Chris@739:                    << nchannels << " vs " << m_channelCount << ")" << endl;
Chris@739:             if (++warnings == 6) {
Chris@739:                 SVCERR << "(further warnings will be suppressed)" << endl;
Chris@739:                 warnings = -1;
Chris@739:             }
Chris@739:         }
Chris@739:         return 0;
Chris@739:     }
Chris@739:     
Chris@739:     if ((int)effect->getAudioInputCount() != m_channelCount) {
Chris@739:         if (!m_failed) {
Chris@739:             SVCERR << "EffectWrapper::getSourceSamples: "
Chris@739:                    << "Can't run plugin: plugin input count "
Chris@739:                    << effect->getAudioInputCount() 
Chris@739:                    << " != our channel count " << m_channelCount
Chris@739:                    << " (future errors for this plugin will be suppressed)"
Chris@739:                    << endl;
Chris@739:             m_failed = true;
Chris@739:         }
Chris@739:     }
Chris@739:     if ((int)effect->getAudioOutputCount() != m_channelCount) {
Chris@739:         if (!m_failed) {
Chris@739:             SVCERR << "EffectWrapper::getSourceSamples: "
Chris@739:                    << "Can't run plugin: plugin output count "
Chris@739:                    << effect->getAudioOutputCount() 
Chris@739:                    << " != our channel count " << m_channelCount
Chris@739:                    << " (future errors for this plugin will be suppressed)"
Chris@739:                    << endl;
Chris@739:             m_failed = true;
Chris@739:         }
Chris@739:     }
Chris@739: 
Chris@739:     if (m_failed) {
Chris@739:         return m_source->getSourceSamples(samples, nchannels, nframes);
Chris@739:     }
Chris@739:     
Chris@739:     float **ib = effect->getAudioInputBuffers();
Chris@739:     float **ob = effect->getAudioOutputBuffers();
Chris@739:     int blockSize = effect->getBufferSize();
Chris@739:     
Chris@739:     int got = 0;
Chris@739: 
Chris@739:     while (got < nframes) {
Chris@739: 
Chris@739:         int read = 0;
Chris@739:         for (int c = 0; c < nchannels; ++c) {
Chris@740:             read = m_effectOutputBuffers[c].read(samples[c] + got,
Chris@740:                                                  nframes - got);
Chris@739:         }
Chris@739: 
Chris@739:         got += read;
Chris@739: 
Chris@739:         if (got < nframes) {
Chris@739: 
Chris@739:             int toRun = m_source->getSourceSamples(ib, nchannels, blockSize);
Chris@739:             if (toRun <= 0) break;
Chris@739: 
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:             SVCERR << "EffectWrapper::getSourceSamples: Running effect "
Chris@740:                    << "for " << toRun << " frames" << endl;
Chris@740: #endif
Chris@739:             effect->run(Vamp::RealTime::zeroTime, toRun);
Chris@739: 
Chris@739:             for (int c = 0; c < nchannels; ++c) {
Chris@739:                 m_effectOutputBuffers[c].write(ob[c], toRun);
Chris@739:             }
Chris@739:         }
Chris@739:     }
Chris@739:         
Chris@739:     return got;
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setSystemPlaybackChannelCount(int count)
Chris@739: {
Chris@739:     {
Chris@739:         lock_guard<mutex> guard(m_mutex);
Chris@740: #ifdef DEBUG_EFFECT_WRAPPER
Chris@740:         SVCERR << "EffectWrapper[" << this
Chris@740:                << "]::setSystemPlaybackChannelCount(" << count << ")" << endl;
Chris@740: #endif
Chris@739:         m_effectOutputBuffers.resize
Chris@739:             (count, RingBuffer<float>(DEFAULT_RING_BUFFER_SIZE));
Chris@739:         m_channelCount = count;
Chris@739:     }
Chris@739:     m_source->setSystemPlaybackChannelCount(count);
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setSystemPlaybackSampleRate(int rate)
Chris@739: {
Chris@739:     m_source->setSystemPlaybackSampleRate(rate);
Chris@739: }
Chris@739: 
Chris@739: std::string
Chris@739: EffectWrapper::getClientName() const
Chris@739: {
Chris@739:     return m_source->getClientName();
Chris@739: }
Chris@739: 
Chris@739: int
Chris@739: EffectWrapper::getApplicationSampleRate() const
Chris@739: {
Chris@739:     return m_source->getApplicationSampleRate();
Chris@739: }
Chris@739: 
Chris@739: int
Chris@739: EffectWrapper::getApplicationChannelCount() const
Chris@739: {
Chris@739:     return m_source->getApplicationChannelCount();
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setSystemPlaybackBlockSize(int sz)
Chris@739: {
Chris@739:     SVDEBUG << "NOTE: EffectWrapper::setSystemPlaybackBlockSize called "
Chris@739:             << "with size = " << sz << "; not passing to wrapped source, as "
Chris@739:             << "actual block size will vary" << endl;
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setSystemPlaybackLatency(int latency)
Chris@739: {
Chris@739:     m_source->setSystemPlaybackLatency(latency);
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::setOutputLevels(float left, float right)
Chris@739: {
Chris@739:     m_source->setOutputLevels(left, right);
Chris@739: }
Chris@739: 
Chris@739: void
Chris@739: EffectWrapper::audioProcessingOverload()
Chris@739: {
Chris@739:     m_source->audioProcessingOverload();
Chris@739: }