annotate plugins/BeatDetect.cpp @ 4:ffd3c1699bee

* Use SDK library instead of objects
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 06 Apr 2006 12:27:01 +0000
parents 991d0fe8bb27
children b033ac01902b
rev   line source
c@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@0 2
c@0 3 /*
c@0 4 QM Vamp Plugin Set
c@0 5
c@0 6 Centre for Digital Music, Queen Mary, University of London.
c@0 7 All rights reserved.
c@0 8 */
c@0 9
c@0 10 #include "BeatDetect.h"
c@0 11
c@3 12 #include <dsp/onsets/DetectionFunction.h>
c@3 13 #include <dsp/tempotracking/TempoTrack.h>
c@0 14
c@0 15 using std::string;
c@0 16 using std::vector;
c@0 17 using std::cerr;
c@0 18 using std::endl;
c@0 19
c@0 20 float BeatDetector::m_stepSecs = 0.01161;
c@0 21
c@0 22 class BeatDetectorData
c@0 23 {
c@0 24 public:
c@0 25 BeatDetectorData(const DFConfig &config) : dfConfig(config) {
c@0 26 df = new DetectionFunction(config);
c@0 27 }
c@0 28 ~BeatDetectorData() {
c@0 29 delete df;
c@0 30 }
c@0 31 void reset() {
c@0 32 delete df;
c@0 33 df = new DetectionFunction(dfConfig);
c@0 34 dfOutput.clear();
c@0 35 }
c@0 36
c@0 37 DFConfig dfConfig;
c@0 38 DetectionFunction *df;
c@0 39 vector<double> dfOutput;
c@0 40 };
c@0 41
c@0 42
c@0 43 BeatDetector::BeatDetector(float inputSampleRate) :
c@0 44 Vamp::Plugin(inputSampleRate),
c@0 45 m_d(0),
c@0 46 m_dfType(DF_COMPLEXSD)
c@0 47 {
c@0 48 }
c@0 49
c@0 50 BeatDetector::~BeatDetector()
c@0 51 {
c@0 52 delete m_d;
c@0 53 }
c@0 54
c@0 55 string
c@0 56 BeatDetector::getName() const
c@0 57 {
c@0 58 return "beats";
c@0 59 }
c@0 60
c@0 61 string
c@0 62 BeatDetector::getDescription() const
c@0 63 {
c@0 64 return "Beat Detector";
c@0 65 }
c@0 66
c@0 67 string
c@0 68 BeatDetector::getMaker() const
c@0 69 {
c@0 70 return "QMUL";
c@0 71 }
c@0 72
c@0 73 int
c@0 74 BeatDetector::getPluginVersion() const
c@0 75 {
c@0 76 return 1;
c@0 77 }
c@0 78
c@0 79 string
c@0 80 BeatDetector::getCopyright() const
c@0 81 {
c@0 82 return "Copyright (c) 2006 - All Rights Reserved";
c@0 83 }
c@0 84
c@0 85 BeatDetector::ParameterList
c@0 86 BeatDetector::getParameterDescriptors() const
c@0 87 {
c@0 88 ParameterList list;
c@0 89
c@0 90 ParameterDescriptor desc;
c@0 91 desc.name = "dftype";
c@0 92 desc.description = "Onset Detection Function Type";
c@0 93 desc.minValue = 0;
c@0 94 desc.maxValue = 3;
c@0 95 desc.defaultValue = 3;
c@0 96 desc.isQuantized = true;
c@0 97 desc.quantizeStep = 1;
c@0 98 desc.valueNames.push_back("High-Frequency Content");
c@0 99 desc.valueNames.push_back("Spectral Difference");
c@0 100 desc.valueNames.push_back("Phase Deviation");
c@0 101 desc.valueNames.push_back("Complex Domain");
c@0 102 list.push_back(desc);
c@0 103
c@0 104 return list;
c@0 105 }
c@0 106
c@0 107 float
c@0 108 BeatDetector::getParameter(std::string name) const
c@0 109 {
c@0 110 if (name == "dftype") {
c@0 111 switch (m_dfType) {
c@0 112 case DF_HFC: return 0;
c@0 113 case DF_SPECDIFF: return 1;
c@0 114 case DF_PHASEDEV: return 2;
c@0 115 default: case DF_COMPLEXSD: return 3;
c@0 116 }
c@0 117 }
c@0 118 return 0.0;
c@0 119 }
c@0 120
c@0 121 void
c@0 122 BeatDetector::setParameter(std::string name, float value)
c@0 123 {
c@0 124 if (name == "dftype") {
c@0 125 switch (lrintf(value)) {
c@0 126 case 0: m_dfType = DF_HFC; break;
c@0 127 case 1: m_dfType = DF_SPECDIFF; break;
c@0 128 case 2: m_dfType = DF_PHASEDEV; break;
c@0 129 default: case 3: m_dfType = DF_COMPLEXSD; break;
c@0 130 }
c@0 131 }
c@0 132 }
c@0 133
c@0 134 bool
c@0 135 BeatDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@0 136 {
c@0 137 if (m_d) {
c@0 138 delete m_d;
c@0 139 m_d = 0;
c@0 140 }
c@0 141
c@0 142 if (channels < getMinChannelCount() ||
c@0 143 channels > getMaxChannelCount()) return false;
c@0 144
c@0 145 DFConfig dfConfig;
c@0 146 dfConfig.DFType = m_dfType;
c@0 147 dfConfig.stepSecs = float(stepSize) / m_inputSampleRate;
c@0 148 dfConfig.stepSize = stepSize;
c@0 149 dfConfig.frameLength = blockSize;
c@0 150
c@0 151 m_d = new BeatDetectorData(dfConfig);
c@0 152 return true;
c@0 153 }
c@0 154
c@0 155 void
c@0 156 BeatDetector::reset()
c@0 157 {
c@0 158 if (m_d) m_d->reset();
c@0 159 }
c@0 160
c@0 161 size_t
c@0 162 BeatDetector::getPreferredStepSize() const
c@0 163 {
c@0 164 return size_t(m_inputSampleRate * m_stepSecs + 0.0001);
c@0 165 }
c@0 166
c@0 167 size_t
c@0 168 BeatDetector::getPreferredBlockSize() const
c@0 169 {
c@0 170 return getPreferredStepSize() * 2;
c@0 171 }
c@0 172
c@0 173 BeatDetector::OutputList
c@0 174 BeatDetector::getOutputDescriptors() const
c@0 175 {
c@0 176 OutputList list;
c@0 177
c@0 178 OutputDescriptor beat;
c@0 179 beat.name = "beats";
c@0 180 beat.unit = "";
c@0 181 beat.description = "Detected Beats";
c@0 182 beat.hasFixedBinCount = true;
c@0 183 beat.binCount = 0;
c@0 184 beat.sampleType = OutputDescriptor::VariableSampleRate;
c@0 185 beat.sampleRate = 1.0 / m_stepSecs;
c@0 186
c@0 187 OutputDescriptor df;
c@0 188 df.name = "detection_fn";
c@0 189 df.unit = "";
c@0 190 df.description = "Beat Detection Function";
c@0 191 df.hasFixedBinCount = true;
c@0 192 df.binCount = 1;
c@0 193 df.hasKnownExtents = false;
c@0 194 df.isQuantized = false;
c@0 195 df.sampleType = OutputDescriptor::OneSamplePerStep;
c@0 196
c@0 197 list.push_back(beat);
c@0 198 list.push_back(df);
c@0 199
c@0 200 return list;
c@0 201 }
c@0 202
c@0 203 BeatDetector::FeatureSet
c@0 204 BeatDetector::process(float **inputBuffers, Vamp::RealTime /* timestamp */)
c@0 205 {
c@0 206 if (!m_d) {
c@0 207 cerr << "ERROR: BeatDetector::process: "
c@0 208 << "BeatDetector has not been initialised"
c@0 209 << endl;
c@0 210 return FeatureSet();
c@0 211 }
c@0 212
c@0 213 // convert float* to double*
c@0 214 double *tempBuffer = new double[m_d->dfConfig.frameLength];
c@0 215 for (size_t i = 0; i < m_d->dfConfig.frameLength; ++i) {
c@0 216 tempBuffer[i] = inputBuffers[0][i];
c@0 217 }
c@0 218
c@0 219 double output = m_d->df->process(tempBuffer);
c@0 220 delete[] tempBuffer;
c@0 221
c@0 222 m_d->dfOutput.push_back(output);
c@0 223
c@0 224 FeatureSet returnFeatures;
c@0 225
c@0 226 Feature feature;
c@0 227 feature.hasTimestamp = false;
c@0 228 feature.values.push_back(output);
c@0 229
c@0 230 returnFeatures[1].push_back(feature); // detection function is output 1
c@0 231 return returnFeatures;
c@0 232 }
c@0 233
c@0 234 BeatDetector::FeatureSet
c@0 235 BeatDetector::getRemainingFeatures()
c@0 236 {
c@0 237 if (!m_d) {
c@0 238 cerr << "ERROR: BeatDetector::getRemainingFeatures: "
c@0 239 << "BeatDetector has not been initialised"
c@0 240 << endl;
c@0 241 return FeatureSet();
c@0 242 }
c@0 243
c@0 244 double aCoeffs[] = { 1.0000, -0.5949, 0.2348 };
c@0 245 double bCoeffs[] = { 0.1600, 0.3200, 0.1600 };
c@0 246
c@0 247 TTParams ttParams;
c@0 248 ttParams.winLength = 512;
c@0 249 ttParams.lagLength = 128;
c@0 250 ttParams.LPOrd = 2;
c@0 251 ttParams.LPACoeffs = aCoeffs;
c@0 252 ttParams.LPBCoeffs = bCoeffs;
c@0 253 ttParams.alpha = 9;
c@0 254 ttParams.WinT.post = 8;
c@0 255 ttParams.WinT.pre = 7;
c@0 256
c@0 257 TempoTrack tempoTracker(ttParams);
c@0 258 vector<int> beats = tempoTracker.process(m_d->dfOutput);
c@0 259
c@0 260 FeatureSet returnFeatures;
c@0 261
c@0 262 for (size_t i = 0; i < beats.size(); ++i) {
c@0 263
c@0 264 size_t frame = beats[i] * m_d->dfConfig.stepSize;
c@0 265
c@0 266 Feature feature;
c@0 267 feature.hasTimestamp = true;
c@0 268 feature.timestamp = Vamp::RealTime::frame2RealTime
c@0 269 (frame, lrintf(m_inputSampleRate));
c@0 270
c@0 271 float bpm = 0.0;
c@0 272 int frameIncrement = 0;
c@0 273
c@0 274 if (i < beats.size() - 1) {
c@0 275
c@0 276 frameIncrement = (beats[i+1] - beats[i]) * m_d->dfConfig.stepSize;
c@0 277
c@0 278 // one beat is frameIncrement frames, so there are
c@0 279 // samplerate/frameIncrement bps, so
c@0 280 // 60*samplerate/frameIncrement bpm
c@0 281
c@0 282 if (frameIncrement > 0) {
c@0 283 bpm = (60.0 * m_inputSampleRate) / frameIncrement;
c@0 284 bpm = int(bpm * 100.0 + 0.5) / 100.0;
c@0 285 static char label[100];
c@0 286 sprintf(label, "%f bpm", bpm);
c@0 287 feature.label = label;
c@0 288 }
c@0 289 }
c@0 290
c@0 291 returnFeatures[0].push_back(feature); // beats are output 0
c@0 292 }
c@0 293
c@0 294 return returnFeatures;
c@0 295 }
c@0 296