annotate plugins/KeyDetect.cpp @ 45:5d7ce1d87301

* Add MFCC plugin * Add means output to Chromagram plugin * Update similarity plugin for MFCC changes
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 18 Jan 2008 13:30:56 +0000
parents 9a2edd83775f
children 3b4572153ce3
rev   line source
c@21 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@21 2
c@21 3 /*
c@38 4 QM Vamp Plugin Set
c@21 5
c@21 6 Centre for Digital Music, Queen Mary, University of London.
c@38 7 All rights reserved.
c@21 8 */
c@21 9
c@21 10 #include "KeyDetect.h"
c@21 11
c@21 12 using std::string;
c@21 13 using std::vector;
c@21 14 //using std::cerr;
c@21 15 using std::endl;
c@21 16
c@21 17 #include <cmath>
c@21 18
c@21 19
c@21 20 KeyDetector::KeyDetector(float inputSampleRate) :
c@21 21 Plugin(inputSampleRate),
c@21 22 m_stepSize(0),
c@21 23 m_blockSize(0),
c@21 24 m_tuningFrequency(440),
c@21 25 m_length(10),
c@21 26 m_getKeyMode(0),
c@21 27 m_inputFrame(0),
c@21 28 m_prevKey(-1)
c@21 29 {
c@21 30 }
c@21 31
c@21 32 KeyDetector::~KeyDetector()
c@21 33 {
c@21 34 delete m_getKeyMode;
c@21 35 if ( m_inputFrame ) {
c@21 36 delete [] m_inputFrame;
c@21 37 }
c@21 38 }
c@21 39
c@21 40 string
c@22 41 KeyDetector::getIdentifier() const
c@21 42 {
c@21 43 return "qm-keydetector";
c@21 44 }
c@21 45
c@21 46 string
c@22 47 KeyDetector::getName() const
c@22 48 {
c@22 49 return "Key Detector";
c@22 50 }
c@22 51
c@22 52 string
c@21 53 KeyDetector::getDescription() const
c@21 54 {
c@22 55 //!!!
c@22 56 return "";
c@21 57 }
c@21 58
c@21 59 string
c@21 60 KeyDetector::getMaker() const
c@21 61 {
c@21 62 return "Katy Noland and Christian Landone, Queen Mary, University of London";
c@21 63 }
c@21 64
c@21 65 int
c@21 66 KeyDetector::getPluginVersion() const
c@21 67 {
c@35 68 return 3;
c@21 69 }
c@21 70
c@21 71 string
c@21 72 KeyDetector::getCopyright() const
c@21 73 {
c@38 74 return "Copyright (c) 2006-2008 - All Rights Reserved";
c@21 75 }
c@21 76
c@21 77 KeyDetector::ParameterList
c@21 78 KeyDetector::getParameterDescriptors() const
c@21 79 {
c@21 80 ParameterList list;
c@21 81
c@21 82 ParameterDescriptor desc;
c@22 83 desc.identifier = "tuning";
c@22 84 desc.name = "Tuning Frequency";
c@21 85 desc.unit = "Hz";
c@21 86 desc.minValue = 420;
c@21 87 desc.maxValue = 460;
c@21 88 desc.defaultValue = 440;
c@21 89 desc.isQuantized = false;
c@21 90 list.push_back(desc);
c@21 91
c@22 92 desc.identifier = "length";
c@22 93 desc.name = "Window Length";
c@21 94 desc.unit = "chroma frames";
c@21 95 desc.minValue = 1;
c@21 96 desc.maxValue = 30;
c@21 97 desc.defaultValue = 10;
c@21 98 desc.isQuantized = true;
c@21 99 desc.quantizeStep = 1;
c@21 100 list.push_back(desc);
c@21 101
c@21 102 return list;
c@21 103 }
c@21 104
c@21 105 float
c@21 106 KeyDetector::getParameter(std::string param) const
c@21 107 {
c@21 108 if (param == "tuning") {
c@21 109 return m_tuningFrequency;
c@21 110 }
c@21 111 if (param == "length") {
c@21 112 return m_length;
c@21 113 }
c@21 114 std::cerr << "WARNING: KeyDetect::getParameter: unknown parameter \""
c@21 115 << param << "\"" << std::endl;
c@21 116 return 0.0;
c@21 117 }
c@21 118
c@21 119 void
c@21 120 KeyDetector::setParameter(std::string param, float value)
c@21 121 {
c@21 122 if (param == "tuning") {
c@21 123 m_tuningFrequency = value;
c@21 124 } else if (param == "length") {
c@21 125 m_length = int(value + 0.1);
c@21 126 } else {
c@21 127 std::cerr << "WARNING: KeyDetect::setParameter: unknown parameter \""
c@21 128 << param << "\"" << std::endl;
c@21 129 }
c@21 130 }
c@21 131
c@21 132 bool
c@21 133 KeyDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@21 134 {
c@21 135 if (m_getKeyMode) {
c@21 136 delete m_getKeyMode;
c@21 137 m_getKeyMode = 0;
c@21 138 }
c@21 139
c@21 140 if (channels < getMinChannelCount() ||
c@21 141 channels > getMaxChannelCount()) return false;
c@21 142
c@21 143 m_getKeyMode = new GetKeyMode(int(m_inputSampleRate + 0.1),
c@21 144 m_tuningFrequency,
c@21 145 m_length, m_length);
c@21 146
c@21 147 m_stepSize = m_getKeyMode->getHopSize();
c@21 148 m_blockSize = m_getKeyMode->getBlockSize();
c@21 149
c@21 150 if (stepSize != m_stepSize || blockSize != m_blockSize) {
c@21 151 std::cerr << "KeyDetector::initialise: step/block sizes "
c@21 152 << stepSize << "/" << blockSize << " differ from required "
c@21 153 << m_stepSize << "/" << m_blockSize << std::endl;
c@21 154 delete m_getKeyMode;
c@21 155 m_getKeyMode = 0;
c@21 156 return false;
c@21 157 }
c@21 158
c@21 159 m_inputFrame = new double[m_blockSize];
c@21 160
c@21 161 m_prevKey = -1;
c@21 162
c@21 163 return true;
c@21 164 }
c@21 165
c@21 166 void
c@21 167 KeyDetector::reset()
c@21 168 {
c@21 169 if (m_getKeyMode) {
c@21 170 delete m_getKeyMode;
c@21 171 m_getKeyMode = new GetKeyMode(int(m_inputSampleRate + 0.1),
c@21 172 m_tuningFrequency,
c@21 173 m_length, m_length);
c@21 174 }
c@21 175
c@21 176 if (m_inputFrame) {
c@21 177 for( unsigned int i = 0; i < m_blockSize; i++ ) {
c@21 178 m_inputFrame[ i ] = 0.0;
c@21 179 }
c@21 180 }
c@21 181
c@21 182 m_prevKey = -1;
c@21 183 }
c@21 184
c@21 185
c@21 186 KeyDetector::OutputList
c@21 187 KeyDetector::getOutputDescriptors() const
c@21 188 {
c@21 189 OutputList list;
c@21 190
c@21 191 OutputDescriptor d;
c@22 192 d.identifier = "tonic";
c@22 193 d.name = "Tonic Pitch";
c@21 194 d.unit = "";
c@21 195 d.hasFixedBinCount = true;
c@21 196 d.binCount = 1;
c@21 197 d.hasKnownExtents = true;
c@21 198 d.isQuantized = true;
c@21 199 d.minValue = 0;
c@21 200 d.maxValue = 11;
c@21 201 d.quantizeStep = 1;
c@21 202 d.sampleType = OutputDescriptor::OneSamplePerStep;
c@21 203 list.push_back(d);
c@21 204
c@22 205 d.identifier = "mode";
c@22 206 d.name = "Key Mode";
c@21 207 d.unit = "";
c@21 208 d.hasFixedBinCount = true;
c@21 209 d.binCount = 1;
c@21 210 d.hasKnownExtents = true;
c@21 211 d.isQuantized = true;
c@21 212 d.minValue = 0;
c@21 213 d.maxValue = 1;
c@21 214 d.quantizeStep = 1;
c@21 215 d.binNames.push_back("Major = 0, Minor = 1");
c@21 216 d.sampleType = OutputDescriptor::OneSamplePerStep;
c@21 217 list.push_back(d);
c@21 218
c@22 219 d.identifier = "key";
c@22 220 d.name = "Key";
c@21 221 d.unit = "";
c@21 222 d.hasFixedBinCount = true;
c@21 223 d.binCount = 1;
c@21 224 d.hasKnownExtents = true;
c@21 225 d.isQuantized = true;
c@21 226 d.minValue = 0;
c@21 227 d.maxValue = 23;
c@21 228 d.quantizeStep = 1;
devnull@34 229 d.binNames.erase(d.binNames.begin(),d.binNames.end());
c@21 230 d.sampleType = OutputDescriptor::OneSamplePerStep;
c@21 231 list.push_back(d);
c@21 232
c@21 233 return list;
c@21 234 }
c@21 235
c@21 236 KeyDetector::FeatureSet
c@21 237 KeyDetector::process(const float *const *inputBuffers,
c@21 238 Vamp::RealTime now)
c@21 239 {
c@21 240 if (m_stepSize == 0) {
c@21 241 return FeatureSet();
c@21 242 }
c@21 243
c@21 244 FeatureSet returnFeatures;
c@21 245
c@21 246 for ( unsigned int i = 0 ; i < m_blockSize; i++ ) {
c@21 247 m_inputFrame[i] = (double)inputBuffers[0][i];
c@21 248 }
c@21 249
c@21 250 // int key = (m_getKeyMode->process(m_inputFrame) % 24);
c@21 251 int key = m_getKeyMode->process(m_inputFrame);
c@21 252 int minor = m_getKeyMode->isModeMinor(key);
c@21 253 int tonic = key;
c@21 254 if (tonic > 12) tonic -= 12;
c@21 255
devnull@33 256
c@21 257 int prevTonic = m_prevKey;
c@21 258 if (prevTonic > 12) prevTonic -= 12;
c@21 259
c@21 260 if (tonic != prevTonic) {
c@21 261 Feature feature;
c@21 262 feature.hasTimestamp = false;
c@21 263 // feature.timestamp = now;
c@21 264 feature.values.push_back((float)tonic);
c@21 265 feature.label = getKeyName(tonic);
c@21 266 returnFeatures[0].push_back(feature); // tonic
c@21 267 }
c@21 268
c@21 269 if (minor != (m_getKeyMode->isModeMinor(m_prevKey))) {
c@21 270 Feature feature;
c@21 271 feature.hasTimestamp = false;
c@21 272 feature.values.push_back((float)minor);
c@21 273 feature.label = (minor ? "Minor" : "Major");
c@21 274 returnFeatures[1].push_back(feature); // mode
c@21 275 }
c@21 276
c@21 277 if (key != m_prevKey) {
c@21 278 Feature feature;
c@21 279 // feature.hasTimestamp = true;
c@21 280 feature.hasTimestamp = false;
c@21 281 // feature.timestamp = now;
c@21 282 feature.values.push_back((float)key);
c@21 283 feature.label = std::string(getKeyName(tonic));
c@21 284 if (minor) feature.label += " minor";
c@21 285 else feature.label += " major";
c@21 286 returnFeatures[2].push_back(feature); // key
c@38 287 // cerr << "int key = "<<key<<endl;
c@38 288 // cerr << "int tonic = "<<tonic<<endl;
c@38 289 // cerr << "feature label = "<<feature.label<<endl;
c@21 290 }
c@21 291
c@21 292 m_prevKey = key;
c@21 293
c@21 294 return returnFeatures;
c@21 295 }
c@21 296
c@21 297 KeyDetector::FeatureSet
c@21 298 KeyDetector::getRemainingFeatures()
c@21 299 {
c@21 300 return FeatureSet();
c@21 301 }
c@21 302
c@21 303
c@21 304 size_t
c@21 305 KeyDetector::getPreferredStepSize() const
c@21 306 {
c@21 307 if (!m_stepSize) {
c@21 308 GetKeyMode gkm(int(m_inputSampleRate + 0.1),
c@21 309 m_tuningFrequency, m_length, m_length);
c@21 310 m_stepSize = gkm.getHopSize();
c@21 311 m_blockSize = gkm.getBlockSize();
c@21 312 }
c@21 313 return m_stepSize;
c@21 314 }
c@21 315
c@21 316 size_t
c@21 317 KeyDetector::getPreferredBlockSize() const
c@21 318 {
c@21 319 if (!m_blockSize) {
c@21 320 GetKeyMode gkm(int(m_inputSampleRate + 0.1),
c@21 321 m_tuningFrequency, m_length, m_length);
c@21 322 m_stepSize = gkm.getHopSize();
c@21 323 m_blockSize = gkm.getBlockSize();
c@21 324 }
c@21 325 return m_blockSize;
c@21 326 }
c@21 327
c@21 328 const char *
c@21 329 KeyDetector::getKeyName(int index)
c@21 330 {
devnull@33 331 // Keys are numbered with 1 => C, 12 => B
devnull@33 332 // This is based on chromagram base set to a C in qm-dsp's GetKeyMode.cpp
c@21 333 static const char *names[] = {
c@21 334 "C", "C# / Db", "D", "D# / Eb",
c@21 335 "E", "F", "F# / Gb", "G",
c@21 336 "G# / Ab", "A", "A# / Bb", "B"
c@21 337 };
c@21 338 if (index < 1 || index > 12) {
c@21 339 return "(unknown)";
c@21 340 }
devnull@33 341 return names[index - 1]; //'-1' because our names array starts from 0
c@21 342 }
c@21 343