annotate examples/PercussionOnsetDetector.cpp @ 98:896a97349ac5

* Add a static wrapper object to wrap the static instance pointer, so that it can be properly deleted on program exit instead of showing up in certain tools as leaked
author cannam
date Mon, 03 Dec 2007 12:57:27 +0000
parents c8b48bc6db3d
children a5187dad96cd
rev   line source
cannam@35 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@35 2
cannam@35 3 /*
cannam@35 4 Vamp
cannam@35 5
cannam@35 6 An API for audio analysis and feature extraction plugins.
cannam@35 7
cannam@35 8 Centre for Digital Music, Queen Mary, University of London.
cannam@35 9 Copyright 2006 Chris Cannam.
cannam@35 10
cannam@35 11 Permission is hereby granted, free of charge, to any person
cannam@35 12 obtaining a copy of this software and associated documentation
cannam@35 13 files (the "Software"), to deal in the Software without
cannam@35 14 restriction, including without limitation the rights to use, copy,
cannam@35 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@35 16 of the Software, and to permit persons to whom the Software is
cannam@35 17 furnished to do so, subject to the following conditions:
cannam@35 18
cannam@35 19 The above copyright notice and this permission notice shall be
cannam@35 20 included in all copies or substantial portions of the Software.
cannam@35 21
cannam@35 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@35 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@35 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@35 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@35 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@35 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@35 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@35 29
cannam@35 30 Except as contained in this notice, the names of the Centre for
cannam@35 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@35 32 shall not be used in advertising or otherwise to promote the sale,
cannam@35 33 use or other dealings in this Software without prior written
cannam@35 34 authorization.
cannam@35 35 */
cannam@35 36
cannam@35 37 #include "PercussionOnsetDetector.h"
cannam@35 38
cannam@35 39 using std::string;
cannam@35 40 using std::vector;
cannam@35 41 using std::cerr;
cannam@35 42 using std::endl;
cannam@35 43
cannam@35 44 #include <cmath>
cannam@35 45
cannam@35 46
cannam@35 47 PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
cannam@35 48 Plugin(inputSampleRate),
cannam@35 49 m_stepSize(0),
cannam@35 50 m_blockSize(0),
cannam@35 51 m_threshold(3),
cannam@35 52 m_sensitivity(40),
cannam@35 53 m_priorMagnitudes(0),
cannam@35 54 m_dfMinus1(0),
cannam@35 55 m_dfMinus2(0)
cannam@35 56 {
cannam@35 57 }
cannam@35 58
cannam@35 59 PercussionOnsetDetector::~PercussionOnsetDetector()
cannam@35 60 {
cannam@35 61 delete[] m_priorMagnitudes;
cannam@35 62 }
cannam@35 63
cannam@35 64 string
cannam@49 65 PercussionOnsetDetector::getIdentifier() const
cannam@35 66 {
cannam@35 67 return "percussiononsets";
cannam@35 68 }
cannam@35 69
cannam@35 70 string
cannam@49 71 PercussionOnsetDetector::getName() const
cannam@49 72 {
cannam@49 73 return "Simple Percussion Onset Detector";
cannam@49 74 }
cannam@49 75
cannam@49 76 string
cannam@35 77 PercussionOnsetDetector::getDescription() const
cannam@35 78 {
cannam@49 79 return "Detect percussive note onsets by identifying broadband energy rises";
cannam@35 80 }
cannam@35 81
cannam@35 82 string
cannam@35 83 PercussionOnsetDetector::getMaker() const
cannam@35 84 {
cannam@43 85 return "Vamp SDK Example Plugins";
cannam@35 86 }
cannam@35 87
cannam@35 88 int
cannam@35 89 PercussionOnsetDetector::getPluginVersion() const
cannam@35 90 {
cannam@35 91 return 2;
cannam@35 92 }
cannam@35 93
cannam@35 94 string
cannam@35 95 PercussionOnsetDetector::getCopyright() const
cannam@35 96 {
cannam@35 97 return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)";
cannam@35 98 }
cannam@35 99
cannam@35 100 size_t
cannam@35 101 PercussionOnsetDetector::getPreferredStepSize() const
cannam@35 102 {
cannam@35 103 return 0;
cannam@35 104 }
cannam@35 105
cannam@35 106 size_t
cannam@35 107 PercussionOnsetDetector::getPreferredBlockSize() const
cannam@35 108 {
cannam@35 109 return 1024;
cannam@35 110 }
cannam@35 111
cannam@35 112 bool
cannam@35 113 PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@35 114 {
cannam@35 115 if (channels < getMinChannelCount() ||
cannam@35 116 channels > getMaxChannelCount()) return false;
cannam@35 117
cannam@35 118 m_stepSize = stepSize;
cannam@35 119 m_blockSize = blockSize;
cannam@35 120
cannam@35 121 m_priorMagnitudes = new float[m_blockSize/2];
cannam@35 122
cannam@35 123 for (size_t i = 0; i < m_blockSize/2; ++i) {
cannam@35 124 m_priorMagnitudes[i] = 0.f;
cannam@35 125 }
cannam@35 126
cannam@35 127 m_dfMinus1 = 0.f;
cannam@35 128 m_dfMinus2 = 0.f;
cannam@35 129
cannam@35 130 return true;
cannam@35 131 }
cannam@35 132
cannam@35 133 void
cannam@35 134 PercussionOnsetDetector::reset()
cannam@35 135 {
cannam@35 136 for (size_t i = 0; i < m_blockSize/2; ++i) {
cannam@35 137 m_priorMagnitudes[i] = 0.f;
cannam@35 138 }
cannam@35 139
cannam@35 140 m_dfMinus1 = 0.f;
cannam@35 141 m_dfMinus2 = 0.f;
cannam@35 142 }
cannam@35 143
cannam@35 144 PercussionOnsetDetector::ParameterList
cannam@35 145 PercussionOnsetDetector::getParameterDescriptors() const
cannam@35 146 {
cannam@35 147 ParameterList list;
cannam@35 148
cannam@35 149 ParameterDescriptor d;
cannam@49 150 d.identifier = "threshold";
cannam@49 151 d.name = "Energy rise threshold";
cannam@49 152 d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
cannam@35 153 d.unit = "dB";
cannam@35 154 d.minValue = 0;
cannam@35 155 d.maxValue = 20;
cannam@35 156 d.defaultValue = 3;
cannam@35 157 d.isQuantized = false;
cannam@35 158 list.push_back(d);
cannam@35 159
cannam@49 160 d.identifier = "sensitivity";
cannam@49 161 d.name = "Sensitivity";
cannam@49 162 d.description = "Sensitivity of peak detector applied to broadband detection function";
cannam@35 163 d.unit = "%";
cannam@35 164 d.minValue = 0;
cannam@35 165 d.maxValue = 100;
cannam@35 166 d.defaultValue = 40;
cannam@35 167 d.isQuantized = false;
cannam@35 168 list.push_back(d);
cannam@35 169
cannam@35 170 return list;
cannam@35 171 }
cannam@35 172
cannam@35 173 float
cannam@49 174 PercussionOnsetDetector::getParameter(std::string id) const
cannam@35 175 {
cannam@49 176 if (id == "threshold") return m_threshold;
cannam@49 177 if (id == "sensitivity") return m_sensitivity;
cannam@35 178 return 0.f;
cannam@35 179 }
cannam@35 180
cannam@35 181 void
cannam@49 182 PercussionOnsetDetector::setParameter(std::string id, float value)
cannam@35 183 {
cannam@49 184 if (id == "threshold") {
cannam@35 185 if (value < 0) value = 0;
cannam@35 186 if (value > 20) value = 20;
cannam@35 187 m_threshold = value;
cannam@49 188 } else if (id == "sensitivity") {
cannam@35 189 if (value < 0) value = 0;
cannam@35 190 if (value > 100) value = 100;
cannam@35 191 m_sensitivity = value;
cannam@35 192 }
cannam@35 193 }
cannam@35 194
cannam@35 195 PercussionOnsetDetector::OutputList
cannam@35 196 PercussionOnsetDetector::getOutputDescriptors() const
cannam@35 197 {
cannam@35 198 OutputList list;
cannam@35 199
cannam@35 200 OutputDescriptor d;
cannam@49 201 d.identifier = "onsets";
cannam@49 202 d.name = "Onsets";
cannam@49 203 d.description = "Percussive note onset locations";
cannam@35 204 d.unit = "";
cannam@35 205 d.hasFixedBinCount = true;
cannam@35 206 d.binCount = 0;
cannam@35 207 d.hasKnownExtents = false;
cannam@35 208 d.isQuantized = false;
cannam@35 209 d.sampleType = OutputDescriptor::VariableSampleRate;
cannam@35 210 d.sampleRate = m_inputSampleRate;
cannam@35 211 list.push_back(d);
cannam@35 212
cannam@49 213 d.identifier = "detectionfunction";
cannam@49 214 d.name = "Detection Function";
cannam@49 215 d.description = "Broadband energy rise detection function";
cannam@35 216 d.binCount = 1;
cannam@35 217 d.isQuantized = true;
cannam@35 218 d.quantizeStep = 1.0;
cannam@35 219 d.sampleType = OutputDescriptor::OneSamplePerStep;
cannam@35 220 list.push_back(d);
cannam@35 221
cannam@35 222 return list;
cannam@35 223 }
cannam@35 224
cannam@35 225 PercussionOnsetDetector::FeatureSet
cannam@47 226 PercussionOnsetDetector::process(const float *const *inputBuffers,
cannam@47 227 Vamp::RealTime ts)
cannam@35 228 {
cannam@35 229 if (m_stepSize == 0) {
cannam@35 230 cerr << "ERROR: PercussionOnsetDetector::process: "
cannam@35 231 << "PercussionOnsetDetector has not been initialised"
cannam@35 232 << endl;
cannam@35 233 return FeatureSet();
cannam@35 234 }
cannam@35 235
cannam@35 236 int count = 0;
cannam@35 237
cannam@35 238 for (size_t i = 1; i < m_blockSize/2; ++i) {
cannam@35 239
cannam@35 240 float real = inputBuffers[0][i*2];
cannam@35 241 float imag = inputBuffers[0][i*2 + 1];
cannam@82 242
cannam@35 243 float sqrmag = real * real + imag * imag;
cannam@35 244
cannam@35 245 if (m_priorMagnitudes[i] > 0.f) {
cannam@35 246 float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
cannam@35 247
cannam@35 248 // std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
cannam@35 249
cannam@35 250 if (diff >= m_threshold) ++count;
cannam@35 251 }
cannam@35 252
cannam@35 253 m_priorMagnitudes[i] = sqrmag;
cannam@35 254 }
cannam@35 255
cannam@35 256 FeatureSet returnFeatures;
cannam@35 257
cannam@35 258 Feature detectionFunction;
cannam@35 259 detectionFunction.hasTimestamp = false;
cannam@35 260 detectionFunction.values.push_back(count);
cannam@35 261 returnFeatures[1].push_back(detectionFunction);
cannam@35 262
cannam@35 263 if (m_dfMinus2 < m_dfMinus1 &&
cannam@35 264 m_dfMinus1 >= count &&
cannam@37 265 m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
cannam@35 266
cannam@35 267 Feature onset;
cannam@35 268 onset.hasTimestamp = true;
cannam@35 269 onset.timestamp = ts - Vamp::RealTime::frame2RealTime
cannam@36 270 (m_stepSize, lrintf(m_inputSampleRate));
cannam@35 271 returnFeatures[0].push_back(onset);
cannam@35 272 }
cannam@35 273
cannam@35 274 m_dfMinus2 = m_dfMinus1;
cannam@35 275 m_dfMinus1 = count;
cannam@35 276
cannam@35 277 return returnFeatures;
cannam@35 278 }
cannam@35 279
cannam@35 280 PercussionOnsetDetector::FeatureSet
cannam@35 281 PercussionOnsetDetector::getRemainingFeatures()
cannam@35 282 {
cannam@35 283 return FeatureSet();
cannam@35 284 }
cannam@35 285