annotate audio/TimeStretchWrapper.cpp @ 749:54393ed09d65

Add haveEffect, implement clearEffect
author Chris Cannam
date Wed, 22 Apr 2020 17:10:36 +0100
parents 846970dbef17
children
rev   line source
Chris@738 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@738 2
Chris@738 3 /*
Chris@738 4 Sonic Visualiser
Chris@738 5 An audio file viewer and annotation editor.
Chris@738 6 Centre for Digital Music, Queen Mary, University of London.
Chris@738 7
Chris@738 8 This program is free software; you can redistribute it and/or
Chris@738 9 modify it under the terms of the GNU General Public License as
Chris@738 10 published by the Free Software Foundation; either version 2 of the
Chris@738 11 License, or (at your option) any later version. See the file
Chris@738 12 COPYING included with this distribution for more information.
Chris@738 13 */
Chris@738 14
Chris@738 15 #include "TimeStretchWrapper.h"
Chris@738 16
Chris@738 17 #include <rubberband/RubberBandStretcher.h>
Chris@738 18
Chris@738 19 #include "base/Debug.h"
Chris@738 20
Chris@738 21 using namespace RubberBand;
Chris@738 22 using namespace std;
Chris@738 23
Chris@738 24 TimeStretchWrapper::TimeStretchWrapper(ApplicationPlaybackSource *source) :
Chris@738 25 m_source(source),
Chris@738 26 m_stretcher(nullptr),
Chris@738 27 m_timeRatio(1.0),
Chris@738 28 m_stretcherInputSize(16384),
Chris@738 29 m_channelCount(0),
Chris@738 30 m_sampleRate(0)
Chris@738 31 {
Chris@738 32 }
Chris@738 33
Chris@738 34 TimeStretchWrapper::~TimeStretchWrapper()
Chris@738 35 {
Chris@738 36 delete m_stretcher;
Chris@738 37 }
Chris@738 38
Chris@738 39 void
Chris@738 40 TimeStretchWrapper::setTimeStretchRatio(double ratio)
Chris@738 41 {
Chris@738 42 lock_guard<mutex> guard(m_mutex);
Chris@738 43
Chris@738 44 SVDEBUG << "TimeStretchWrapper::setTimeStretchRatio: setting ratio to "
Chris@738 45 << ratio << " (was " << m_timeRatio << ")" << endl;
Chris@738 46
Chris@738 47 m_timeRatio = ratio;
Chris@738 48
Chris@738 49 // Stretcher will be updated by checkStretcher() from next call to
Chris@738 50 // getSourceSamples()
Chris@738 51 }
Chris@738 52
Chris@738 53 void
Chris@738 54 TimeStretchWrapper::reset()
Chris@738 55 {
Chris@738 56 lock_guard<mutex> guard(m_mutex);
Chris@738 57
Chris@738 58 if (m_stretcher) {
Chris@738 59 m_stretcher->reset();
Chris@738 60 }
Chris@738 61 }
Chris@738 62
Chris@738 63 int
Chris@738 64 TimeStretchWrapper::getSourceSamples(float *const *samples,
Chris@738 65 int nchannels, int nframes)
Chris@738 66 {
Chris@738 67 checkStretcher();
Chris@738 68
Chris@738 69 lock_guard<mutex> guard(m_mutex);
Chris@738 70
Chris@738 71 static int warnings = 0;
Chris@738 72 if (nchannels != m_channelCount) {
Chris@738 73 if (warnings >= 0) {
Chris@738 74 SVCERR << "WARNING: getSourceSamples called for a number of channels different from that set with setSystemPlaybackChannelCount ("
Chris@738 75 << nchannels << " vs " << m_channelCount << ")" << endl;
Chris@738 76 if (++warnings == 6) {
Chris@738 77 SVCERR << "(further warnings will be suppressed)" << endl;
Chris@738 78 warnings = -1;
Chris@738 79 }
Chris@738 80 }
Chris@738 81 return 0;
Chris@738 82 }
Chris@738 83
Chris@738 84 if (!m_stretcher) {
Chris@738 85 return m_source->getSourceSamples(samples, nchannels, nframes);
Chris@738 86 }
Chris@738 87
Chris@738 88 vector<float *> inputPtrs(m_channelCount, nullptr);
Chris@738 89 for (int i = 0; i < m_channelCount; ++i) {
Chris@738 90 inputPtrs[i] = m_inputs[i].data();
Chris@738 91 }
Chris@738 92
Chris@738 93 // The input block for a given output is approx output / ratio,
Chris@738 94 // but we can't predict it exactly, for an adaptive timestretcher.
Chris@738 95
Chris@740 96 sv_frame_t available;
Chris@740 97
Chris@738 98 while ((available = m_stretcher->available()) < nframes) {
Chris@738 99
Chris@740 100 int reqd = int(ceil(double(nframes - available) / m_timeRatio));
Chris@740 101 reqd = std::max(reqd, int(m_stretcher->getSamplesRequired()));
Chris@738 102 reqd = std::min(reqd, m_stretcherInputSize);
Chris@738 103 if (reqd == 0) reqd = 1;
Chris@738 104
Chris@738 105 int got = m_source->getSourceSamples
Chris@738 106 (inputPtrs.data(), nchannels, reqd);
Chris@738 107
Chris@738 108 if (got <= 0) {
Chris@738 109 SVCERR << "WARNING: Failed to obtain any source samples at all"
Chris@738 110 << endl;
Chris@738 111 return 0;
Chris@738 112 }
Chris@738 113
Chris@738 114 m_stretcher->process
Chris@738 115 (inputPtrs.data(), size_t(got), false);
Chris@738 116 }
Chris@738 117
Chris@738 118 return int(m_stretcher->retrieve(samples, nframes));
Chris@738 119 }
Chris@738 120
Chris@738 121 void
Chris@738 122 TimeStretchWrapper::checkStretcher()
Chris@738 123 {
Chris@738 124 lock_guard<mutex> guard(m_mutex);
Chris@738 125
Chris@738 126 if (m_timeRatio == 1.0 || !m_channelCount || !m_sampleRate) {
Chris@738 127 if (m_stretcher) {
Chris@740 128 SVDEBUG << "TimeStretchWrapper::checkStretcher: m_timeRatio = "
Chris@740 129 << m_timeRatio << ", m_channelCount = " << m_channelCount
Chris@740 130 << ", m_sampleRate = " << m_sampleRate
Chris@740 131 << ", deleting existing stretcher" << endl;
Chris@738 132 delete m_stretcher;
Chris@738 133 m_stretcher = nullptr;
Chris@738 134 }
Chris@738 135 return;
Chris@738 136 }
Chris@738 137
Chris@738 138 if (m_stretcher) {
Chris@738 139 SVDEBUG << "TimeStretchWrapper::checkStretcher: setting stretcher ratio to " << m_timeRatio << endl;
Chris@738 140 m_stretcher->setTimeRatio(m_timeRatio);
Chris@738 141 return;
Chris@738 142 }
Chris@738 143
Chris@738 144 SVDEBUG << "TimeStretchWrapper::checkStretcher: creating stretcher with ratio " << m_timeRatio << endl;
Chris@738 145
Chris@738 146 m_stretcher = new RubberBandStretcher
Chris@740 147 (size_t(round(m_sampleRate)),
Chris@738 148 m_channelCount,
Chris@738 149 RubberBandStretcher::OptionProcessRealTime,
Chris@738 150 m_timeRatio);
Chris@738 151
Chris@738 152 m_inputs.resize(m_channelCount);
Chris@738 153 for (auto &v: m_inputs) {
Chris@738 154 v.resize(m_stretcherInputSize);
Chris@738 155 }
Chris@738 156 }
Chris@738 157
Chris@738 158 void
Chris@738 159 TimeStretchWrapper::setSystemPlaybackChannelCount(int count)
Chris@738 160 {
Chris@738 161 {
Chris@738 162 lock_guard<mutex> guard(m_mutex);
Chris@738 163 if (m_channelCount != count) {
Chris@738 164 delete m_stretcher;
Chris@738 165 m_stretcher = nullptr;
Chris@738 166 }
Chris@738 167 m_channelCount = count;
Chris@738 168 }
Chris@738 169 m_source->setSystemPlaybackChannelCount(count);
Chris@738 170 }
Chris@738 171
Chris@738 172 void
Chris@738 173 TimeStretchWrapper::setSystemPlaybackSampleRate(int rate)
Chris@738 174 {
Chris@738 175 {
Chris@738 176 lock_guard<mutex> guard(m_mutex);
Chris@738 177 if (m_sampleRate != rate) {
Chris@738 178 delete m_stretcher;
Chris@738 179 m_stretcher = nullptr;
Chris@738 180 }
Chris@738 181 m_sampleRate = rate;
Chris@738 182 }
Chris@738 183 m_source->setSystemPlaybackSampleRate(rate);
Chris@738 184 }
Chris@738 185
Chris@738 186 std::string
Chris@738 187 TimeStretchWrapper::getClientName() const
Chris@738 188 {
Chris@738 189 return m_source->getClientName();
Chris@738 190 }
Chris@738 191
Chris@738 192 int
Chris@738 193 TimeStretchWrapper::getApplicationSampleRate() const
Chris@738 194 {
Chris@738 195 return m_source->getApplicationSampleRate();
Chris@738 196 }
Chris@738 197
Chris@738 198 int
Chris@738 199 TimeStretchWrapper::getApplicationChannelCount() const
Chris@738 200 {
Chris@738 201 return m_source->getApplicationChannelCount();
Chris@738 202 }
Chris@738 203
Chris@738 204 void
Chris@739 205 TimeStretchWrapper::setSystemPlaybackBlockSize(int sz)
Chris@738 206 {
Chris@739 207 SVDEBUG << "NOTE: TimeStretchWrapper::setSystemPlaybackBlockSize called "
Chris@739 208 << "with size = " << sz << "; not passing to wrapped source, as "
Chris@739 209 << "actual block size will vary" << endl;
Chris@738 210 }
Chris@738 211
Chris@738 212 void
Chris@738 213 TimeStretchWrapper::setSystemPlaybackLatency(int latency)
Chris@738 214 {
Chris@738 215 m_source->setSystemPlaybackLatency(latency);
Chris@738 216 }
Chris@738 217
Chris@738 218 void
Chris@738 219 TimeStretchWrapper::setOutputLevels(float left, float right)
Chris@738 220 {
Chris@738 221 m_source->setOutputLevels(left, right);
Chris@738 222 }
Chris@738 223
Chris@738 224 void
Chris@738 225 TimeStretchWrapper::audioProcessingOverload()
Chris@738 226 {
Chris@738 227 m_source->audioProcessingOverload();
Chris@738 228 }