annotate BeatRootVampPlugin.cpp @ 23:633ec097fa56

Expose the processing parameters Simon suggests
author Chris Cannam
date Tue, 03 Sep 2013 17:32:09 +0100
parents 6afcb5edd7ab
children b9c2f444cdaa
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Vamp feature extraction plugin for the BeatRoot beat tracker.
Chris@0 5
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7 This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "BeatRootVampPlugin.h"
Chris@2 17 #include "BeatRootProcessor.h"
Chris@0 18
Chris@10 19 #include "Event.h"
Chris@10 20
Chris@10 21 #include <vamp-sdk/RealTime.h>
Chris@9 22 #include <vamp-sdk/PluginAdapter.h>
Chris@0 23
Chris@0 24 BeatRootVampPlugin::BeatRootVampPlugin(float inputSampleRate) :
Chris@0 25 Plugin(inputSampleRate)
Chris@0 26 {
Chris@23 27 m_processor = new BeatRootProcessor(inputSampleRate, AgentParameters());
Chris@0 28 }
Chris@0 29
Chris@0 30 BeatRootVampPlugin::~BeatRootVampPlugin()
Chris@0 31 {
Chris@0 32 delete m_processor;
Chris@0 33 }
Chris@0 34
Chris@0 35 string
Chris@0 36 BeatRootVampPlugin::getIdentifier() const
Chris@0 37 {
Chris@0 38 return "beatroot";
Chris@0 39 }
Chris@0 40
Chris@0 41 string
Chris@0 42 BeatRootVampPlugin::getName() const
Chris@0 43 {
Chris@0 44 return "BeatRoot Beat Tracker";
Chris@0 45 }
Chris@0 46
Chris@0 47 string
Chris@0 48 BeatRootVampPlugin::getDescription() const
Chris@0 49 {
Chris@0 50 return "Identify beat locations in music";
Chris@0 51 }
Chris@0 52
Chris@0 53 string
Chris@0 54 BeatRootVampPlugin::getMaker() const
Chris@0 55 {
Chris@0 56 return "Simon Dixon (plugin by Chris Cannam)";
Chris@0 57 }
Chris@0 58
Chris@0 59 int
Chris@0 60 BeatRootVampPlugin::getPluginVersion() const
Chris@0 61 {
Chris@0 62 // Increment this each time you release a version that behaves
Chris@0 63 // differently from the previous one
Chris@0 64 return 1;
Chris@0 65 }
Chris@0 66
Chris@0 67 string
Chris@0 68 BeatRootVampPlugin::getCopyright() const
Chris@0 69 {
Chris@0 70 return "GPL";
Chris@0 71 }
Chris@0 72
Chris@0 73 BeatRootVampPlugin::InputDomain
Chris@0 74 BeatRootVampPlugin::getInputDomain() const
Chris@0 75 {
Chris@0 76 return FrequencyDomain;
Chris@0 77 }
Chris@0 78
Chris@0 79 size_t
Chris@0 80 BeatRootVampPlugin::getPreferredBlockSize() const
Chris@0 81 {
Chris@0 82 return m_processor->getFFTSize();
Chris@0 83 }
Chris@0 84
Chris@0 85 size_t
Chris@0 86 BeatRootVampPlugin::getPreferredStepSize() const
Chris@0 87 {
Chris@0 88 return m_processor->getHopSize();
Chris@0 89 }
Chris@0 90
Chris@0 91 size_t
Chris@0 92 BeatRootVampPlugin::getMinChannelCount() const
Chris@0 93 {
Chris@0 94 return 1;
Chris@0 95 }
Chris@0 96
Chris@0 97 size_t
Chris@0 98 BeatRootVampPlugin::getMaxChannelCount() const
Chris@0 99 {
Chris@0 100 return 1;
Chris@0 101 }
Chris@0 102
Chris@0 103 BeatRootVampPlugin::ParameterList
Chris@0 104 BeatRootVampPlugin::getParameterDescriptors() const
Chris@0 105 {
Chris@0 106 ParameterList list;
Chris@23 107
Chris@23 108 ParameterDescriptor desc;
Chris@23 109
Chris@23 110 double postMarginFactor;
Chris@23 111
Chris@23 112 /** The maximum amount by which a beat can be earlier than the
Chris@23 113 * predicted beat time, expressed as a fraction of the beat
Chris@23 114 * period. */
Chris@23 115 double preMarginFactor;
Chris@23 116
Chris@23 117 /** The maximum allowed deviation from the initial tempo,
Chris@23 118 * expressed as a fraction of the initial beat period. */
Chris@23 119 double maxChange;
Chris@23 120
Chris@23 121 /** The default value of expiryTime, which is the time (in
Chris@23 122 * seconds) after which an Agent that has no Event matching its
Chris@23 123 * beat predictions will be destroyed. */
Chris@23 124
Chris@23 125 desc.identifier = "preMarginFactor";
Chris@23 126 desc.name = "Pre-Margin Factor";
Chris@23 127 desc.description = "The maximum amount by which a beat can be earlier than the predicted beat time, expressed as a fraction of the beat period.";
Chris@23 128 desc.minValue = 0;
Chris@23 129 desc.maxValue = 1;
Chris@23 130 desc.defaultValue = AgentParameters::DEFAULT_PRE_MARGIN_FACTOR;
Chris@23 131 desc.isQuantized = false;
Chris@23 132 list.push_back(desc);
Chris@23 133
Chris@23 134 desc.identifier = "postMarginFactor";
Chris@23 135 desc.name = "Post-Margin Factor";
Chris@23 136 desc.description = "The maximum amount by which a beat can be later than the predicted beat time, expressed as a fraction of the beat period.";
Chris@23 137 desc.minValue = 0;
Chris@23 138 desc.maxValue = 1;
Chris@23 139 desc.defaultValue = AgentParameters::DEFAULT_POST_MARGIN_FACTOR;
Chris@23 140 desc.isQuantized = false;
Chris@23 141 list.push_back(desc);
Chris@23 142
Chris@23 143 desc.identifier = "maxChange";
Chris@23 144 desc.name = "Maximum Change";
Chris@23 145 desc.description = "The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period.";
Chris@23 146 desc.minValue = 0;
Chris@23 147 desc.maxValue = 1;
Chris@23 148 desc.defaultValue = AgentParameters::DEFAULT_MAX_CHANGE;
Chris@23 149 desc.isQuantized = false;
Chris@23 150 list.push_back(desc);
Chris@23 151
Chris@23 152 desc.identifier = "expiryTime";
Chris@23 153 desc.name = "Expiry Time";
Chris@23 154 desc.description = "The default value of expiryTime, which is the time (in seconds) after which an Agent that has no Event matching its beat predictions will be destroyed.";
Chris@23 155 desc.minValue = 2;
Chris@23 156 desc.maxValue = 120;
Chris@23 157 desc.defaultValue = AgentParameters::DEFAULT_EXPIRY_TIME;
Chris@23 158 desc.isQuantized = false;
Chris@23 159 list.push_back(desc);
Chris@23 160
Chris@23 161 // Simon says...
Chris@23 162
Chris@23 163 // These are the parameters that should be exposed (Agent.cpp):
Chris@23 164
Chris@23 165 // If Pop, both margins should be lower (0.1). If classical
Chris@23 166 // music, post margin can be increased
Chris@23 167 //
Chris@23 168 // double Agent::POST_MARGIN_FACTOR = 0.3;
Chris@23 169 // double Agent::PRE_MARGIN_FACTOR = 0.15;
Chris@23 170 //
Chris@23 171 // Max Change tells us how much tempo can change - so for
Chris@23 172 // classical we should make it higher
Chris@23 173 //
Chris@23 174 // double Agent::MAX_CHANGE = 0.2;
Chris@23 175 //
Chris@23 176 // The EXPIRY TIME default should be defaulted to 100 (usual cause
Chris@23 177 // of agents dying....) it should also be exposed in order to
Chris@23 178 // troubleshoot eventual problems in songs with big silences in
Chris@23 179 // the beggining/end.
Chris@23 180 //
Chris@23 181 // const double Agent::DEFAULT_EXPIRY_TIME = 10.0;
Chris@23 182
Chris@0 183 return list;
Chris@0 184 }
Chris@0 185
Chris@0 186 float
Chris@0 187 BeatRootVampPlugin::getParameter(string identifier) const
Chris@0 188 {
Chris@23 189 if (identifier == "preMarginFactor") {
Chris@23 190 return m_parameters.preMarginFactor;
Chris@23 191 } else if (identifier == "postMarginFactor") {
Chris@23 192 return m_parameters.postMarginFactor;
Chris@23 193 } else if (identifier == "maxChange") {
Chris@23 194 return m_parameters.maxChange;
Chris@23 195 } else if (identifier == "expiryTime") {
Chris@23 196 return m_parameters.expiryTime;
Chris@23 197 }
Chris@23 198
Chris@0 199 return 0;
Chris@0 200 }
Chris@0 201
Chris@0 202 void
Chris@0 203 BeatRootVampPlugin::setParameter(string identifier, float value)
Chris@0 204 {
Chris@23 205 if (identifier == "preMarginFactor") {
Chris@23 206 m_parameters.preMarginFactor = value;
Chris@23 207 } else if (identifier == "postMarginFactor") {
Chris@23 208 m_parameters.postMarginFactor = value;
Chris@23 209 } else if (identifier == "maxChange") {
Chris@23 210 m_parameters.maxChange = value;
Chris@23 211 } else if (identifier == "expiryTime") {
Chris@23 212 m_parameters.expiryTime = value;
Chris@23 213 }
Chris@0 214 }
Chris@0 215
Chris@0 216 BeatRootVampPlugin::ProgramList
Chris@0 217 BeatRootVampPlugin::getPrograms() const
Chris@0 218 {
Chris@0 219 ProgramList list;
Chris@0 220 return list;
Chris@0 221 }
Chris@0 222
Chris@0 223 string
Chris@0 224 BeatRootVampPlugin::getCurrentProgram() const
Chris@0 225 {
Chris@0 226 return ""; // no programs
Chris@0 227 }
Chris@0 228
Chris@0 229 void
Chris@0 230 BeatRootVampPlugin::selectProgram(string name)
Chris@0 231 {
Chris@0 232 }
Chris@0 233
Chris@0 234 BeatRootVampPlugin::OutputList
Chris@0 235 BeatRootVampPlugin::getOutputDescriptors() const
Chris@0 236 {
Chris@0 237 OutputList list;
Chris@0 238
Chris@0 239 // See OutputDescriptor documentation for the possibilities here.
Chris@0 240 // Every plugin must have at least one output.
Chris@0 241
Chris@0 242 OutputDescriptor d;
Chris@0 243 d.identifier = "beats";
Chris@0 244 d.name = "Beats";
Chris@0 245 d.description = "Estimated beat locations";
Chris@0 246 d.unit = "";
Chris@0 247 d.hasFixedBinCount = true;
Chris@0 248 d.binCount = 0;
Chris@0 249 d.hasKnownExtents = false;
Chris@0 250 d.isQuantized = false;
Chris@0 251 d.sampleType = OutputDescriptor::VariableSampleRate;
Chris@19 252 d.sampleRate = m_inputSampleRate;
Chris@0 253 d.hasDuration = false;
Chris@0 254 list.push_back(d);
Chris@0 255
Chris@0 256 return list;
Chris@0 257 }
Chris@0 258
Chris@0 259 bool
Chris@0 260 BeatRootVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
Chris@0 261 {
Chris@0 262 if (channels < getMinChannelCount() ||
Chris@0 263 channels > getMaxChannelCount()) {
Chris@0 264 std::cerr << "BeatRootVampPlugin::initialise: Unsupported number ("
Chris@0 265 << channels << ") of channels" << std::endl;
Chris@0 266 return false;
Chris@0 267 }
Chris@0 268
Chris@0 269 if (stepSize != getPreferredStepSize()) {
Chris@0 270 std::cerr << "BeatRootVampPlugin::initialise: Unsupported step size "
Chris@0 271 << "for sample rate (" << stepSize << ", required step is "
Chris@0 272 << getPreferredStepSize() << " for rate " << m_inputSampleRate
Chris@0 273 << ")" << std::endl;
Chris@0 274 return false;
Chris@0 275 }
Chris@0 276
Chris@0 277 if (blockSize != getPreferredBlockSize()) {
Chris@0 278 std::cerr << "BeatRootVampPlugin::initialise: Unsupported block size "
Chris@0 279 << "for sample rate (" << blockSize << ", required size is "
Chris@0 280 << getPreferredBlockSize() << " for rate " << m_inputSampleRate
Chris@0 281 << ")" << std::endl;
Chris@0 282 return false;
Chris@0 283 }
Chris@0 284
Chris@23 285 // Delete the processor that was created with default parameters
Chris@23 286 // and used to determine the expected step and block size; replace
Chris@23 287 // with one using the actual parameters we have
Chris@23 288 delete m_processor;
Chris@23 289 m_processor = new BeatRootProcessor(m_inputSampleRate, m_parameters);
Chris@0 290
Chris@0 291 return true;
Chris@0 292 }
Chris@0 293
Chris@0 294 void
Chris@0 295 BeatRootVampPlugin::reset()
Chris@0 296 {
Chris@0 297 m_processor->reset();
Chris@0 298 }
Chris@0 299
Chris@0 300 BeatRootVampPlugin::FeatureSet
Chris@0 301 BeatRootVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
Chris@0 302 {
Chris@10 303 m_processor->processFrame(inputBuffers);
Chris@0 304 return FeatureSet();
Chris@0 305 }
Chris@0 306
Chris@0 307 BeatRootVampPlugin::FeatureSet
Chris@0 308 BeatRootVampPlugin::getRemainingFeatures()
Chris@0 309 {
Chris@10 310 EventList el = m_processor->beatTrack();
Chris@22 311
Chris@10 312 Feature f;
Chris@10 313 f.hasTimestamp = true;
Chris@10 314 f.hasDuration = false;
Chris@10 315 f.label = "";
Chris@10 316 f.values.clear();
Chris@10 317
Chris@10 318 FeatureSet fs;
Chris@10 319
Chris@13 320 for (EventList::const_iterator i = el.begin(); i != el.end(); ++i) {
Chris@13 321 f.timestamp = Vamp::RealTime::fromSeconds(i->time);
Chris@10 322 fs[0].push_back(f);
Chris@10 323 }
Chris@10 324
Chris@10 325 return fs;
Chris@0 326 }
Chris@0 327
Chris@0 328
Chris@0 329 static Vamp::PluginAdapter<BeatRootVampPlugin> brAdapter;
Chris@0 330
Chris@0 331 const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
Chris@0 332 unsigned int index)
Chris@0 333 {
Chris@0 334 if (version < 1) return 0;
Chris@0 335
Chris@0 336 switch (index) {
Chris@0 337 case 0: return brAdapter.getDescriptor();
Chris@0 338 default: return 0;
Chris@0 339 }
Chris@0 340 }
Chris@0 341