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];
242
float sqrmag = real * real + imag * imag;
244
if (m_priorMagnitudes[i] > 0.f) {
245
float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
247
// std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
249
if (diff >= m_threshold) ++count;
252
m_priorMagnitudes[i] = sqrmag;
255
FeatureSet returnFeatures;
257
Feature detectionFunction;
258
detectionFunction.hasTimestamp = false;
259
detectionFunction.values.push_back(count);
260
returnFeatures[1].push_back(detectionFunction);
262
if (m_dfMinus2 < m_dfMinus1 &&
263
m_dfMinus1 >= count &&
264
m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
267
onset.hasTimestamp = true;
268
onset.timestamp = ts - Vamp::RealTime::frame2RealTime
269
(m_stepSize, lrintf(m_inputSampleRate));
270
returnFeatures[0].push_back(onset);
273
m_dfMinus2 = m_dfMinus1;
276
return returnFeatures;
279
PercussionOnsetDetector::FeatureSet
280
PercussionOnsetDetector::getRemainingFeatures()