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 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 effect) Chris@739: { Chris@739: lock_guard 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 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 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 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 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 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(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: }