1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
6 An API for audio analysis and feature extraction plugins.
8 Centre for Digital Music, Queen Mary, University of London.
9 Copyright 2006 Chris Cannam.
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:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
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.
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
37 #include "PercussionOnsetDetector.h"
47 PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
48 Plugin(inputSampleRate),
59 PercussionOnsetDetector::~PercussionOnsetDetector()
61 delete[] m_priorMagnitudes;
65 PercussionOnsetDetector::getIdentifier() const
67 return "percussiononsets";
71 PercussionOnsetDetector::getName() const
73 return "Simple Percussion Onset Detector";
77 PercussionOnsetDetector::getDescription() const
79 return "Detect percussive note onsets by identifying broadband energy rises";
83 PercussionOnsetDetector::getMaker() const
85 return "Vamp SDK Example Plugins";
89 PercussionOnsetDetector::getPluginVersion() const
95 PercussionOnsetDetector::getCopyright() const
97 return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)";
101 PercussionOnsetDetector::getPreferredStepSize() const
107 PercussionOnsetDetector::getPreferredBlockSize() const
113 PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
115 if (channels < getMinChannelCount() ||
116 channels > getMaxChannelCount()) return false;
118 m_stepSize = stepSize;
119 m_blockSize = blockSize;
121 m_priorMagnitudes = new float[m_blockSize/2];
123 for (size_t i = 0; i < m_blockSize/2; ++i) {
124 m_priorMagnitudes[i] = 0.f;
134 PercussionOnsetDetector::reset()
136 for (size_t i = 0; i < m_blockSize/2; ++i) {
137 m_priorMagnitudes[i] = 0.f;
144 PercussionOnsetDetector::ParameterList
145 PercussionOnsetDetector::getParameterDescriptors() const
149 ParameterDescriptor d;
150 d.identifier = "threshold";
151 d.name = "Energy rise threshold";
152 d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
157 d.isQuantized = false;
160 d.identifier = "sensitivity";
161 d.name = "Sensitivity";
162 d.description = "Sensitivity of peak detector applied to broadband detection function";
167 d.isQuantized = false;
174 PercussionOnsetDetector::getParameter(std::string id) const
176 if (id == "threshold") return m_threshold;
177 if (id == "sensitivity") return m_sensitivity;
182 PercussionOnsetDetector::setParameter(std::string id, float value)
184 if (id == "threshold") {
185 if (value < 0) value = 0;
186 if (value > 20) value = 20;
188 } else if (id == "sensitivity") {
189 if (value < 0) value = 0;
190 if (value > 100) value = 100;
191 m_sensitivity = value;
195 PercussionOnsetDetector::OutputList
196 PercussionOnsetDetector::getOutputDescriptors() const
201 d.identifier = "onsets";
203 d.description = "Percussive note onset locations";
205 d.hasFixedBinCount = true;
207 d.hasKnownExtents = false;
208 d.isQuantized = false;
209 d.sampleType = OutputDescriptor::VariableSampleRate;
210 d.sampleRate = m_inputSampleRate;
213 d.identifier = "detectionfunction";
214 d.name = "Detection Function";
215 d.description = "Broadband energy rise detection function";
217 d.isQuantized = true;
218 d.quantizeStep = 1.0;
219 d.sampleType = OutputDescriptor::OneSamplePerStep;
225 PercussionOnsetDetector::FeatureSet
226 PercussionOnsetDetector::process(const float *const *inputBuffers,
229 if (m_stepSize == 0) {
230 cerr << "ERROR: PercussionOnsetDetector::process: "
231 << "PercussionOnsetDetector has not been initialised"
238 for (size_t i = 1; i < m_blockSize/2; ++i) {
240 float real = inputBuffers[0][i*2];
241 float imag = inputBuffers[0][i*2 + 1];
243 float sqrmag = real * real + imag * imag;
245 if (m_priorMagnitudes[i] > 0.f) {
246 float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
248 // std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
250 if (diff >= m_threshold) ++count;
253 m_priorMagnitudes[i] = sqrmag;
256 FeatureSet returnFeatures;
258 Feature detectionFunction;
259 detectionFunction.hasTimestamp = false;
260 detectionFunction.values.push_back(count);
261 returnFeatures[1].push_back(detectionFunction);
263 if (m_dfMinus2 < m_dfMinus1 &&
264 m_dfMinus1 >= count &&
265 m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
268 onset.hasTimestamp = true;
269 onset.timestamp = ts - Vamp::RealTime::frame2RealTime
270 (m_stepSize, lrintf(m_inputSampleRate));
271 returnFeatures[0].push_back(onset);
274 m_dfMinus2 = m_dfMinus1;
277 return returnFeatures;
280 PercussionOnsetDetector::FeatureSet
281 PercussionOnsetDetector::getRemainingFeatures()