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