annotate examples/AmplitudeFollower.cpp @ 415:1522e2f6d700

Fix handling of output sample rate in buffering adapter in case where SampleType is Fixed but no sample rate provided (which is invalid behaviour from the plugin, but we might as well do the right thing with it)
author Chris Cannam
date Fri, 04 Sep 2015 13:48:28 +0100
parents a69901aa85d2
children 75cc9ced3b01
rev   line source
cannam@41 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@41 2
cannam@41 3 /*
cannam@41 4 Vamp
cannam@41 5
cannam@41 6 An API for audio analysis and feature extraction plugins.
cannam@41 7
cannam@41 8 Centre for Digital Music, Queen Mary, University of London.
cannam@41 9 This file copyright 2006 Dan Stowell.
cannam@41 10
cannam@41 11 Permission is hereby granted, free of charge, to any person
cannam@41 12 obtaining a copy of this software and associated documentation
cannam@41 13 files (the "Software"), to deal in the Software without
cannam@41 14 restriction, including without limitation the rights to use, copy,
cannam@41 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@41 16 of the Software, and to permit persons to whom the Software is
cannam@41 17 furnished to do so, subject to the following conditions:
cannam@41 18
cannam@41 19 The above copyright notice and this permission notice shall be
cannam@41 20 included in all copies or substantial portions of the Software.
cannam@41 21
cannam@41 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@41 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@41 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@41 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@41 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@41 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@41 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@41 29
cannam@41 30 Except as contained in this notice, the names of the Centre for
cannam@41 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@41 32 shall not be used in advertising or otherwise to promote the sale,
cannam@41 33 use or other dealings in this Software without prior written
cannam@41 34 authorization.
cannam@41 35 */
cannam@41 36
cannam@41 37 #include "AmplitudeFollower.h"
cannam@41 38
cannam@41 39 #include <cmath>
cannam@41 40
cannam@41 41 #include <string>
cannam@41 42 #include <vector>
cannam@41 43 #include <iostream>
Chris@394 44 #include <algorithm>
cannam@41 45
cannam@41 46 using std::string;
cannam@41 47 using std::vector;
cannam@41 48 using std::cerr;
cannam@41 49 using std::endl;
cannam@41 50
cannam@54 51 /**
cannam@41 52 * An implementation of SuperCollider's amplitude-follower algorithm
cannam@41 53 * as a simple Vamp plugin.
cannam@41 54 */
cannam@41 55
cannam@41 56 AmplitudeFollower::AmplitudeFollower(float inputSampleRate) :
cannam@41 57 Plugin(inputSampleRate),
cannam@41 58 m_stepSize(0),
cannam@41 59 m_previn(0.0f),
cannam@41 60 m_clampcoef(0.01f),
cannam@41 61 m_relaxcoef(0.01f)
cannam@41 62 {
cannam@41 63 }
cannam@41 64
cannam@41 65 AmplitudeFollower::~AmplitudeFollower()
cannam@41 66 {
cannam@41 67 }
cannam@41 68
cannam@41 69 string
cannam@49 70 AmplitudeFollower::getIdentifier() const
cannam@41 71 {
cannam@41 72 return "amplitudefollower";
cannam@41 73 }
cannam@41 74
cannam@41 75 string
cannam@49 76 AmplitudeFollower::getName() const
cannam@49 77 {
cannam@49 78 return "Amplitude Follower";
cannam@49 79 }
cannam@49 80
cannam@49 81 string
cannam@41 82 AmplitudeFollower::getDescription() const
cannam@41 83 {
cannam@49 84 return "Track the amplitude of the audio signal";
cannam@41 85 }
cannam@41 86
cannam@41 87 string
cannam@41 88 AmplitudeFollower::getMaker() const
cannam@41 89 {
cannam@43 90 return "Vamp SDK Example Plugins";
cannam@41 91 }
cannam@41 92
cannam@41 93 int
cannam@41 94 AmplitudeFollower::getPluginVersion() const
cannam@41 95 {
cannam@41 96 return 1;
cannam@41 97 }
cannam@41 98
cannam@41 99 string
cannam@41 100 AmplitudeFollower::getCopyright() const
cannam@41 101 {
cannam@41 102 return "Code copyright 2006 Dan Stowell; method from SuperCollider. Freely redistributable (BSD license)";
cannam@41 103 }
cannam@41 104
cannam@41 105 bool
cannam@41 106 AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@41 107 {
cannam@41 108 if (channels < getMinChannelCount() ||
cannam@41 109 channels > getMaxChannelCount()) return false;
cannam@41 110
cannam@41 111 m_stepSize = std::min(stepSize, blockSize);
cannam@41 112
cannam@41 113 // Translate the coefficients
cannam@41 114 // from their "convenient" 60dB convergence-time values
cannam@41 115 // to real coefficients
cannam@41 116 m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate));
cannam@41 117 m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate));
cannam@41 118
cannam@41 119 return true;
cannam@41 120 }
cannam@41 121
cannam@41 122 void
cannam@41 123 AmplitudeFollower::reset()
cannam@41 124 {
cannam@41 125 m_previn = 0.0f;
cannam@41 126 }
cannam@41 127
cannam@41 128 AmplitudeFollower::OutputList
cannam@41 129 AmplitudeFollower::getOutputDescriptors() const
cannam@41 130 {
cannam@41 131 OutputList list;
cannam@41 132
cannam@41 133 OutputDescriptor sca;
cannam@49 134 sca.identifier = "amplitude";
cannam@49 135 sca.name = "Amplitude";
cannam@281 136 sca.description = "The peak tracked amplitude for the current processing block";
cannam@41 137 sca.unit = "V";
cannam@41 138 sca.hasFixedBinCount = true;
cannam@41 139 sca.binCount = 1;
cannam@41 140 sca.hasKnownExtents = false;
cannam@41 141 sca.isQuantized = false;
cannam@41 142 sca.sampleType = OutputDescriptor::OneSamplePerStep;
cannam@41 143 list.push_back(sca);
cannam@41 144
cannam@41 145 return list;
cannam@41 146 }
cannam@41 147
cannam@41 148 AmplitudeFollower::ParameterList
cannam@41 149 AmplitudeFollower::getParameterDescriptors() const
cannam@41 150 {
cannam@41 151 ParameterList list;
cannam@41 152
cannam@41 153 ParameterDescriptor att;
cannam@49 154 att.identifier = "attack";
cannam@49 155 att.name = "Attack time";
cannam@281 156 att.description = "The 60dB convergence time for an increase in amplitude";
cannam@41 157 att.unit = "s";
cannam@41 158 att.minValue = 0.0f;
cannam@41 159 att.maxValue = 1.f;
cannam@41 160 att.defaultValue = 0.01f;
cannam@41 161 att.isQuantized = false;
cannam@41 162
cannam@41 163 list.push_back(att);
cannam@41 164
cannam@41 165 ParameterDescriptor dec;
cannam@49 166 dec.identifier = "release";
cannam@49 167 dec.name = "Release time";
cannam@281 168 dec.description = "The 60dB convergence time for a decrease in amplitude";
cannam@41 169 dec.unit = "s";
cannam@41 170 dec.minValue = 0.0f;
cannam@41 171 dec.maxValue = 1.f;
cannam@41 172 dec.defaultValue = 0.01f;
cannam@41 173 dec.isQuantized = false;
cannam@41 174
cannam@41 175 list.push_back(dec);
cannam@41 176
cannam@41 177 return list;
cannam@41 178 }
cannam@41 179
cannam@49 180 void AmplitudeFollower::setParameter(std::string paramid, float newval)
cannam@41 181 {
cannam@49 182 if (paramid == "attack") {
cannam@41 183 m_clampcoef = newval;
cannam@49 184 } else if (paramid == "release") {
cannam@41 185 m_relaxcoef = newval;
cannam@41 186 }
cannam@41 187 }
cannam@41 188
cannam@49 189 float AmplitudeFollower::getParameter(std::string paramid) const
cannam@41 190 {
cannam@49 191 if (paramid == "attack") {
cannam@41 192 return m_clampcoef;
cannam@49 193 } else if (paramid == "release") {
cannam@41 194 return m_relaxcoef;
cannam@41 195 }
cannam@41 196
cannam@41 197 return 0.0f;
cannam@41 198 }
cannam@41 199
cannam@41 200 AmplitudeFollower::FeatureSet
cannam@47 201 AmplitudeFollower::process(const float *const *inputBuffers,
cannam@47 202 Vamp::RealTime timestamp)
cannam@41 203 {
cannam@41 204 if (m_stepSize == 0) {
cannam@41 205 cerr << "ERROR: AmplitudeFollower::process: "
cannam@41 206 << "AmplitudeFollower has not been initialised"
cannam@41 207 << endl;
cannam@41 208 return FeatureSet();
cannam@41 209 }
cannam@41 210
cannam@41 211 float previn = m_previn;
cannam@41 212
cannam@41 213 FeatureSet returnFeatures;
cannam@41 214
cannam@41 215 float val;
cannam@41 216 float peak = 0.0f;
cannam@41 217
cannam@41 218 for (size_t i = 0; i < m_stepSize; ++i) {
cannam@41 219
cannam@41 220 val = fabs(inputBuffers[0][i]);
cannam@41 221
cannam@41 222 if (val < previn) {
cannam@41 223 val = val + (previn - val) * m_relaxcoef;
cannam@41 224 } else {
cannam@41 225 val = val + (previn - val) * m_clampcoef;
cannam@41 226 }
cannam@41 227
cannam@41 228 if (val > peak) peak = val;
cannam@41 229 previn = val;
cannam@41 230 }
cannam@41 231
cannam@41 232 m_previn = previn;
cannam@41 233
cannam@41 234 // Now store the "feature" (peak amp) for this sample
cannam@41 235 Feature feature;
cannam@41 236 feature.hasTimestamp = false;
cannam@41 237 feature.values.push_back(peak);
cannam@41 238 returnFeatures[0].push_back(feature);
cannam@41 239
cannam@41 240 return returnFeatures;
cannam@41 241 }
cannam@41 242
cannam@41 243 AmplitudeFollower::FeatureSet
cannam@41 244 AmplitudeFollower::getRemainingFeatures()
cannam@41 245 {
cannam@41 246 return FeatureSet();
cannam@41 247 }
cannam@41 248