annotate src/vamp-plugin-sdk-2.4/examples/PercussionOnsetDetector.cpp @ 83:ae30d91d2ffe

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