| Chris@739 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@739 | 2 | 
| Chris@739 | 3 /* | 
| Chris@739 | 4     Sonic Visualiser | 
| Chris@739 | 5     An audio file viewer and annotation editor. | 
| Chris@739 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@739 | 7 | 
| Chris@739 | 8     This program is free software; you can redistribute it and/or | 
| Chris@739 | 9     modify it under the terms of the GNU General Public License as | 
| Chris@739 | 10     published by the Free Software Foundation; either version 2 of the | 
| Chris@739 | 11     License, or (at your option) any later version.  See the file | 
| Chris@739 | 12     COPYING included with this distribution for more information. | 
| Chris@739 | 13 */ | 
| Chris@739 | 14 | 
| Chris@739 | 15 #include "EffectWrapper.h" | 
| Chris@739 | 16 | 
| Chris@739 | 17 #include <rubberband/RubberBandStretcher.h> | 
| Chris@739 | 18 | 
| Chris@739 | 19 #include "base/Debug.h" | 
| Chris@739 | 20 | 
| Chris@740 | 21 //#define DEBUG_EFFECT_WRAPPER 1 | 
| Chris@740 | 22 | 
| Chris@739 | 23 using namespace std; | 
| Chris@739 | 24 | 
| Chris@739 | 25 static const int DEFAULT_RING_BUFFER_SIZE = 131071; | 
| Chris@739 | 26 | 
| Chris@739 | 27 EffectWrapper::EffectWrapper(ApplicationPlaybackSource *source) : | 
| Chris@739 | 28     m_source(source), | 
| Chris@739 | 29     m_bypassed(false), | 
| Chris@739 | 30     m_failed(false), | 
| Chris@739 | 31     m_channelCount(0) | 
| Chris@739 | 32 { | 
| Chris@739 | 33 } | 
| Chris@739 | 34 | 
| Chris@739 | 35 EffectWrapper::~EffectWrapper() | 
| Chris@739 | 36 { | 
| Chris@739 | 37 } | 
| Chris@739 | 38 | 
| Chris@739 | 39 void | 
| Chris@739 | 40 EffectWrapper::setEffect(weak_ptr<RealTimePluginInstance> effect) | 
| Chris@739 | 41 { | 
| Chris@739 | 42     lock_guard<mutex> guard(m_mutex); | 
| Chris@739 | 43 | 
| Chris@740 | 44 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 45     SVCERR << "EffectWrapper[" << this | 
| Chris@740 | 46            << "]::setEffect(" << effect.lock() << ")" << endl; | 
| Chris@740 | 47 #endif | 
| Chris@740 | 48 | 
| Chris@739 | 49     m_effect = effect; | 
| Chris@739 | 50     m_failed = false; | 
| Chris@739 | 51 } | 
| Chris@739 | 52 | 
| Chris@749 | 53 bool | 
| Chris@749 | 54 EffectWrapper::haveEffect() const | 
| Chris@749 | 55 { | 
| Chris@749 | 56     return m_effect.lock() != nullptr; | 
| Chris@749 | 57 } | 
| Chris@749 | 58 | 
| Chris@749 | 59 void | 
| Chris@749 | 60 EffectWrapper::clearEffect() | 
| Chris@749 | 61 { | 
| Chris@749 | 62     m_effect = {}; | 
| Chris@749 | 63 } | 
| Chris@749 | 64 | 
| Chris@739 | 65 void | 
| Chris@739 | 66 EffectWrapper::setBypassed(bool bypassed) | 
| Chris@739 | 67 { | 
| Chris@739 | 68     lock_guard<mutex> guard(m_mutex); | 
| Chris@739 | 69 | 
| Chris@740 | 70 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 71     SVCERR << "EffectWrapper[" << this | 
| Chris@740 | 72            << "]::setBypassed(" << bypassed << ")" << endl; | 
| Chris@740 | 73 #endif | 
| Chris@740 | 74 | 
| Chris@739 | 75     m_bypassed = bypassed; | 
| Chris@739 | 76 } | 
| Chris@739 | 77 | 
| Chris@739 | 78 bool | 
| Chris@739 | 79 EffectWrapper::isBypassed() const | 
| Chris@739 | 80 { | 
| Chris@739 | 81     lock_guard<mutex> guard(m_mutex); | 
| Chris@739 | 82 | 
| Chris@739 | 83     return m_bypassed; | 
| Chris@739 | 84 } | 
| Chris@739 | 85 | 
| Chris@739 | 86 void | 
| Chris@739 | 87 EffectWrapper::reset() | 
| Chris@739 | 88 { | 
| Chris@739 | 89     lock_guard<mutex> guard(m_mutex); | 
| Chris@739 | 90 | 
| Chris@740 | 91 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 92     SVCERR << "EffectWrapper[" << this << "]::reset" << endl; | 
| Chris@740 | 93 #endif | 
| Chris@740 | 94 | 
| Chris@739 | 95     for (auto &rb: m_effectOutputBuffers) { | 
| Chris@739 | 96         rb.reset(); | 
| Chris@739 | 97     } | 
| Chris@740 | 98 | 
| Chris@740 | 99     m_failed = false; | 
| Chris@739 | 100 } | 
| Chris@739 | 101 | 
| Chris@739 | 102 int | 
| Chris@739 | 103 EffectWrapper::getSourceSamples(float *const *samples, | 
| Chris@739 | 104                                 int nchannels, int nframes) | 
| Chris@739 | 105 { | 
| Chris@739 | 106     lock_guard<mutex> guard(m_mutex); | 
| Chris@739 | 107 | 
| Chris@740 | 108 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 109     SVCERR << "EffectWrapper[" << this << "]::getSourceSamples: " << nframes | 
| Chris@740 | 110            << " frames across " << nchannels << " channels" << endl; | 
| Chris@740 | 111 #endif | 
| Chris@740 | 112 | 
| Chris@739 | 113     auto effect(m_effect.lock()); | 
| Chris@739 | 114 | 
| Chris@740 | 115     if (!effect) { | 
| Chris@740 | 116 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 117         SVCERR << "EffectWrapper::getSourceSamples: " | 
| Chris@740 | 118                << "no effect is set" << endl; | 
| Chris@740 | 119 #endif | 
| Chris@739 | 120         return m_source->getSourceSamples(samples, nchannels, nframes); | 
| Chris@739 | 121     } | 
| Chris@739 | 122 | 
| Chris@740 | 123     if (m_bypassed || m_failed) { | 
| Chris@740 | 124 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 125         SVCERR << "EffectWrapper::getSourceSamples: " | 
| Chris@740 | 126                << "effect is bypassed or has failed" << endl; | 
| Chris@740 | 127 #endif | 
| Chris@740 | 128         return m_source->getSourceSamples(samples, nchannels, nframes); | 
| Chris@740 | 129     } | 
| Chris@740 | 130 | 
| Chris@739 | 131     static int warnings = 0; | 
| Chris@739 | 132     if (nchannels != m_channelCount) { | 
| Chris@739 | 133         if (warnings >= 0) { | 
| Chris@740 | 134             SVCERR << "WARNING: EffectWrapper::getSourceSamples called for a number of channels different from that set with setSystemPlaybackChannelCount (" | 
| Chris@739 | 135                    << nchannels << " vs " << m_channelCount << ")" << endl; | 
| Chris@739 | 136             if (++warnings == 6) { | 
| Chris@739 | 137                 SVCERR << "(further warnings will be suppressed)" << endl; | 
| Chris@739 | 138                 warnings = -1; | 
| Chris@739 | 139             } | 
| Chris@739 | 140         } | 
| Chris@739 | 141         return 0; | 
| Chris@739 | 142     } | 
| Chris@739 | 143 | 
| Chris@739 | 144     if ((int)effect->getAudioInputCount() != m_channelCount) { | 
| Chris@739 | 145         if (!m_failed) { | 
| Chris@739 | 146             SVCERR << "EffectWrapper::getSourceSamples: " | 
| Chris@739 | 147                    << "Can't run plugin: plugin input count " | 
| Chris@739 | 148                    << effect->getAudioInputCount() | 
| Chris@739 | 149                    << " != our channel count " << m_channelCount | 
| Chris@739 | 150                    << " (future errors for this plugin will be suppressed)" | 
| Chris@739 | 151                    << endl; | 
| Chris@739 | 152             m_failed = true; | 
| Chris@739 | 153         } | 
| Chris@739 | 154     } | 
| Chris@739 | 155     if ((int)effect->getAudioOutputCount() != m_channelCount) { | 
| Chris@739 | 156         if (!m_failed) { | 
| Chris@739 | 157             SVCERR << "EffectWrapper::getSourceSamples: " | 
| Chris@739 | 158                    << "Can't run plugin: plugin output count " | 
| Chris@739 | 159                    << effect->getAudioOutputCount() | 
| Chris@739 | 160                    << " != our channel count " << m_channelCount | 
| Chris@739 | 161                    << " (future errors for this plugin will be suppressed)" | 
| Chris@739 | 162                    << endl; | 
| Chris@739 | 163             m_failed = true; | 
| Chris@739 | 164         } | 
| Chris@739 | 165     } | 
| Chris@739 | 166 | 
| Chris@739 | 167     if (m_failed) { | 
| Chris@739 | 168         return m_source->getSourceSamples(samples, nchannels, nframes); | 
| Chris@739 | 169     } | 
| Chris@739 | 170 | 
| Chris@739 | 171     float **ib = effect->getAudioInputBuffers(); | 
| Chris@739 | 172     float **ob = effect->getAudioOutputBuffers(); | 
| Chris@739 | 173     int blockSize = effect->getBufferSize(); | 
| Chris@739 | 174 | 
| Chris@739 | 175     int got = 0; | 
| Chris@739 | 176 | 
| Chris@739 | 177     while (got < nframes) { | 
| Chris@739 | 178 | 
| Chris@739 | 179         int read = 0; | 
| Chris@739 | 180         for (int c = 0; c < nchannels; ++c) { | 
| Chris@740 | 181             read = m_effectOutputBuffers[c].read(samples[c] + got, | 
| Chris@740 | 182                                                  nframes - got); | 
| Chris@739 | 183         } | 
| Chris@739 | 184 | 
| Chris@739 | 185         got += read; | 
| Chris@739 | 186 | 
| Chris@739 | 187         if (got < nframes) { | 
| Chris@739 | 188 | 
| Chris@739 | 189             int toRun = m_source->getSourceSamples(ib, nchannels, blockSize); | 
| Chris@739 | 190             if (toRun <= 0) break; | 
| Chris@739 | 191 | 
| Chris@740 | 192 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 193             SVCERR << "EffectWrapper::getSourceSamples: Running effect " | 
| Chris@740 | 194                    << "for " << toRun << " frames" << endl; | 
| Chris@740 | 195 #endif | 
| Chris@739 | 196             effect->run(Vamp::RealTime::zeroTime, toRun); | 
| Chris@739 | 197 | 
| Chris@739 | 198             for (int c = 0; c < nchannels; ++c) { | 
| Chris@739 | 199                 m_effectOutputBuffers[c].write(ob[c], toRun); | 
| Chris@739 | 200             } | 
| Chris@739 | 201         } | 
| Chris@739 | 202     } | 
| Chris@739 | 203 | 
| Chris@739 | 204     return got; | 
| Chris@739 | 205 } | 
| Chris@739 | 206 | 
| Chris@739 | 207 void | 
| Chris@739 | 208 EffectWrapper::setSystemPlaybackChannelCount(int count) | 
| Chris@739 | 209 { | 
| Chris@739 | 210     { | 
| Chris@739 | 211         lock_guard<mutex> guard(m_mutex); | 
| Chris@740 | 212 #ifdef DEBUG_EFFECT_WRAPPER | 
| Chris@740 | 213         SVCERR << "EffectWrapper[" << this | 
| Chris@740 | 214                << "]::setSystemPlaybackChannelCount(" << count << ")" << endl; | 
| Chris@740 | 215 #endif | 
| Chris@739 | 216         m_effectOutputBuffers.resize | 
| Chris@739 | 217             (count, RingBuffer<float>(DEFAULT_RING_BUFFER_SIZE)); | 
| Chris@739 | 218         m_channelCount = count; | 
| Chris@739 | 219     } | 
| Chris@739 | 220     m_source->setSystemPlaybackChannelCount(count); | 
| Chris@739 | 221 } | 
| Chris@739 | 222 | 
| Chris@739 | 223 void | 
| Chris@739 | 224 EffectWrapper::setSystemPlaybackSampleRate(int rate) | 
| Chris@739 | 225 { | 
| Chris@739 | 226     m_source->setSystemPlaybackSampleRate(rate); | 
| Chris@739 | 227 } | 
| Chris@739 | 228 | 
| Chris@739 | 229 std::string | 
| Chris@739 | 230 EffectWrapper::getClientName() const | 
| Chris@739 | 231 { | 
| Chris@739 | 232     return m_source->getClientName(); | 
| Chris@739 | 233 } | 
| Chris@739 | 234 | 
| Chris@739 | 235 int | 
| Chris@739 | 236 EffectWrapper::getApplicationSampleRate() const | 
| Chris@739 | 237 { | 
| Chris@739 | 238     return m_source->getApplicationSampleRate(); | 
| Chris@739 | 239 } | 
| Chris@739 | 240 | 
| Chris@739 | 241 int | 
| Chris@739 | 242 EffectWrapper::getApplicationChannelCount() const | 
| Chris@739 | 243 { | 
| Chris@739 | 244     return m_source->getApplicationChannelCount(); | 
| Chris@739 | 245 } | 
| Chris@739 | 246 | 
| Chris@739 | 247 void | 
| Chris@739 | 248 EffectWrapper::setSystemPlaybackBlockSize(int sz) | 
| Chris@739 | 249 { | 
| Chris@739 | 250     SVDEBUG << "NOTE: EffectWrapper::setSystemPlaybackBlockSize called " | 
| Chris@739 | 251             << "with size = " << sz << "; not passing to wrapped source, as " | 
| Chris@739 | 252             << "actual block size will vary" << endl; | 
| Chris@739 | 253 } | 
| Chris@739 | 254 | 
| Chris@739 | 255 void | 
| Chris@739 | 256 EffectWrapper::setSystemPlaybackLatency(int latency) | 
| Chris@739 | 257 { | 
| Chris@739 | 258     m_source->setSystemPlaybackLatency(latency); | 
| Chris@739 | 259 } | 
| Chris@739 | 260 | 
| Chris@739 | 261 void | 
| Chris@739 | 262 EffectWrapper::setOutputLevels(float left, float right) | 
| Chris@739 | 263 { | 
| Chris@739 | 264     m_source->setOutputLevels(left, right); | 
| Chris@739 | 265 } | 
| Chris@739 | 266 | 
| Chris@739 | 267 void | 
| Chris@739 | 268 EffectWrapper::audioProcessingOverload() | 
| Chris@739 | 269 { | 
| Chris@739 | 270     m_source->audioProcessingOverload(); | 
| Chris@739 | 271 } |