fix crash during first-run configuration of the application, caused by using an incom...
[ardour.git] / libs / vamp-plugins / KeyDetect.cpp
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3 /*
4     QM Vamp Plugin Set
5
6     Centre for Digital Music, Queen Mary, University of London.
7
8     This program is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License as
10     published by the Free Software Foundation; either version 2 of the
11     License, or (at your option) any later version.  See the file
12     COPYING included with this distribution for more information.
13 */
14
15 #include "KeyDetect.h"
16
17 using std::string;
18 using std::vector;
19 //using std::cerr;
20 using std::endl;
21
22 #include <cmath>
23
24
25 // Order for circle-of-5ths plotting
26 static int conversion[24] =
27 { 7, 12, 5, 10, 3, 8, 1, 6, 11, 4, 9, 2,
28   16, 21, 14, 19, 24, 17, 22, 15, 20, 13, 18, 23 };
29
30
31 KeyDetector::KeyDetector(float inputSampleRate) :
32     Plugin(inputSampleRate),
33     m_stepSize(0),
34     m_blockSize(0),
35     m_tuningFrequency(440),
36     m_length(10),
37     m_getKeyMode(0),
38     m_inputFrame(0),
39     m_prevKey(-1)
40 {
41 }
42
43 KeyDetector::~KeyDetector()
44 {
45     delete m_getKeyMode;
46     if ( m_inputFrame ) {
47         delete [] m_inputFrame;
48     }
49 }
50
51 string
52 KeyDetector::getIdentifier() const
53 {
54     return "qm-keydetector";
55 }
56
57 string
58 KeyDetector::getName() const
59 {
60     return "Key Detector";
61 }
62
63 string
64 KeyDetector::getDescription() const
65 {
66     return "Estimate the key of the music";
67 }
68
69 string
70 KeyDetector::getMaker() const
71 {
72     return "Queen Mary, University of London";
73 }
74
75 int
76 KeyDetector::getPluginVersion() const
77 {
78     return 4;
79 }
80
81 string
82 KeyDetector::getCopyright() const
83 {
84     return "Plugin by Katy Noland and Christian Landone.  Copyright (c) 2006-2009 QMUL - All Rights Reserved";
85 }
86
87 KeyDetector::ParameterList
88 KeyDetector::getParameterDescriptors() const
89 {
90     ParameterList list;
91
92     ParameterDescriptor desc;
93     desc.identifier = "tuning";
94     desc.name = "Tuning Frequency";
95     desc.description = "Frequency of concert A";
96     desc.unit = "Hz";
97     desc.minValue = 420;
98     desc.maxValue = 460;
99     desc.defaultValue = 440;
100     desc.isQuantized = false;
101     list.push_back(desc);
102     
103     desc.identifier = "length";
104     desc.name = "Window Length";
105     desc.unit = "chroma frames";
106     desc.description = "Number of chroma analysis frames per key estimation";
107     desc.minValue = 1;
108     desc.maxValue = 30;
109     desc.defaultValue = 10;
110     desc.isQuantized = true;
111     desc.quantizeStep = 1;
112     list.push_back(desc);
113
114     return list;
115 }
116
117 float
118 KeyDetector::getParameter(std::string param) const
119 {
120     if (param == "tuning") {
121         return m_tuningFrequency;
122     }
123     if (param == "length") {
124         return m_length;
125     }
126     std::cerr << "WARNING: KeyDetector::getParameter: unknown parameter \""
127               << param << "\"" << std::endl;
128     return 0.0;
129 }
130
131 void
132 KeyDetector::setParameter(std::string param, float value)
133 {
134     if (param == "tuning") {
135         m_tuningFrequency = value;
136     } else if (param == "length") {
137         m_length = int(value + 0.1);
138     } else {
139         std::cerr << "WARNING: KeyDetector::setParameter: unknown parameter \""
140                   << param << "\"" << std::endl;
141     }
142 }
143
144 bool
145 KeyDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
146 {
147     if (m_getKeyMode) {
148         delete m_getKeyMode;
149         m_getKeyMode = 0;
150     }
151
152     if (channels < getMinChannelCount() ||
153         channels > getMaxChannelCount()) return false;
154
155     m_getKeyMode = new GetKeyMode(int(m_inputSampleRate + 0.1),
156                                   m_tuningFrequency,
157                                   m_length, m_length);
158
159     m_stepSize = m_getKeyMode->getHopSize();
160     m_blockSize = m_getKeyMode->getBlockSize();
161
162     if (stepSize != m_stepSize || blockSize != m_blockSize) {
163         std::cerr << "KeyDetector::initialise: ERROR: step/block sizes "
164                   << stepSize << "/" << blockSize << " differ from required "
165                   << m_stepSize << "/" << m_blockSize << std::endl;
166         delete m_getKeyMode;
167         m_getKeyMode = 0;
168         return false;
169     }
170
171     m_inputFrame = new double[m_blockSize];
172
173     m_prevKey = -1;
174     m_first = true;
175
176     return true;
177 }
178
179 void
180 KeyDetector::reset()
181 {
182     if (m_getKeyMode) {
183         delete m_getKeyMode;
184         m_getKeyMode = new GetKeyMode(int(m_inputSampleRate + 0.1),
185                                       m_tuningFrequency,
186                                       m_length, m_length);
187     }
188
189     if (m_inputFrame) {
190         for( unsigned int i = 0; i < m_blockSize; i++ ) {
191             m_inputFrame[ i ] = 0.0;
192         }
193     }
194
195     m_prevKey = -1;
196     m_first = true;
197 }
198
199
200 KeyDetector::OutputList
201 KeyDetector::getOutputDescriptors() const
202 {
203     OutputList list;
204
205     float osr = 0.0f;
206     if (m_stepSize == 0) (void)getPreferredStepSize();
207     osr = m_inputSampleRate / m_stepSize;
208
209     OutputDescriptor d;
210     d.identifier = "tonic";
211     d.name = "Tonic Pitch";
212     d.unit = "";
213     d.description = "Tonic of the estimated key (from C = 1 to B = 12)";
214     d.hasFixedBinCount = true;
215     d.binCount = 1;
216     d.hasKnownExtents = true;
217     d.isQuantized = true;
218     d.minValue = 1;
219     d.maxValue = 12;
220     d.quantizeStep = 1;
221     d.sampleRate = osr;
222     d.sampleType = OutputDescriptor::VariableSampleRate;
223     list.push_back(d);
224
225     d.identifier = "mode";
226     d.name = "Key Mode";
227     d.unit = "";
228     d.description = "Major or minor mode of the estimated key (major = 0, minor = 1)";
229     d.hasFixedBinCount = true;
230     d.binCount = 1;
231     d.hasKnownExtents = true;
232     d.isQuantized = true;
233     d.minValue = 0;
234     d.maxValue = 1;
235     d.quantizeStep = 1;
236     d.sampleRate = osr;
237     d.sampleType = OutputDescriptor::VariableSampleRate;
238     list.push_back(d);
239
240     d.identifier = "key";
241     d.name = "Key";
242     d.unit = "";
243     d.description = "Estimated key (from C major = 1 to B major = 12 and C minor = 13 to B minor = 24)";
244     d.hasFixedBinCount = true;
245     d.binCount = 1;
246     d.hasKnownExtents = true;
247     d.isQuantized = true;
248     d.minValue = 1;
249     d.maxValue = 24;
250     d.quantizeStep = 1;
251     d.sampleRate = osr;
252     d.sampleType = OutputDescriptor::VariableSampleRate;
253     list.push_back(d);
254
255     d.identifier = "keystrength";
256     d.name = "Key Strength Plot";
257     d.unit = "";
258     d.description = "Correlation of the chroma vector with stored key profile for each major and minor key";
259     d.hasFixedBinCount = true;
260     d.binCount = 25;
261     d.hasKnownExtents = false;
262     d.isQuantized = false;
263     d.sampleType = OutputDescriptor::OneSamplePerStep;
264     for (int i = 0; i < 24; ++i) {
265         if (i == 12) d.binNames.push_back(" ");
266         int idx = conversion[i];
267         std::string label = getKeyName(idx > 12 ? idx-12 : idx, 
268                                        i >= 12,
269                                        true);
270         d.binNames.push_back(label);
271     }
272     list.push_back(d);
273
274     return list;
275 }
276
277 KeyDetector::FeatureSet
278 KeyDetector::process(const float *const *inputBuffers,
279                      Vamp::RealTime now)
280 {
281     if (m_stepSize == 0) {
282         return FeatureSet();
283     }
284
285     FeatureSet returnFeatures;
286
287     for ( unsigned int i = 0 ; i < m_blockSize; i++ ) {
288         m_inputFrame[i] = (double)inputBuffers[0][i];
289     }
290
291 //    int key = (m_getKeyMode->process(m_inputFrame) % 24);
292     int key = m_getKeyMode->process(m_inputFrame);
293     bool minor = m_getKeyMode->isModeMinor(key);
294     int tonic = key;
295     if (tonic > 12) tonic -= 12;
296
297     int prevTonic = m_prevKey;
298     if (prevTonic > 12) prevTonic -= 12;
299
300     if (m_first || (tonic != prevTonic)) {
301         Feature feature;
302         feature.hasTimestamp = true;
303         feature.timestamp = now;
304 //        feature.timestamp = now;
305         feature.values.push_back((float)tonic);
306         feature.label = getKeyName(tonic, minor, false);
307         returnFeatures[0].push_back(feature); // tonic
308     }
309
310     if (m_first || (minor != (m_getKeyMode->isModeMinor(m_prevKey)))) {
311         Feature feature;
312         feature.hasTimestamp = true;
313         feature.timestamp = now;
314         feature.values.push_back(minor ? 1.f : 0.f);
315         feature.label = (minor ? "Minor" : "Major");
316         returnFeatures[1].push_back(feature); // mode
317     }
318
319     if (m_first || (key != m_prevKey)) {
320         Feature feature;
321         feature.hasTimestamp = true;
322         feature.timestamp = now;
323         feature.values.push_back((float)key);
324         feature.label = getKeyName(tonic, minor, true);
325         returnFeatures[2].push_back(feature); // key
326     }
327
328     m_prevKey = key;
329     m_first = false;
330
331     Feature ksf;
332     ksf.values.reserve(25);
333     double *keystrengths = m_getKeyMode->getKeyStrengths();
334     for (int i = 0; i < 24; ++i) {
335         if (i == 12) ksf.values.push_back(-1);
336         ksf.values.push_back(keystrengths[conversion[i]-1]);
337     }
338     ksf.hasTimestamp = false;
339     returnFeatures[3].push_back(ksf);
340
341     return returnFeatures;
342 }
343
344 KeyDetector::FeatureSet
345 KeyDetector::getRemainingFeatures()
346 {
347     return FeatureSet();
348 }
349
350
351 size_t
352 KeyDetector::getPreferredStepSize() const
353 {
354     if (!m_stepSize) {
355         GetKeyMode gkm(int(m_inputSampleRate + 0.1),
356                        m_tuningFrequency, m_length, m_length);
357         m_stepSize = gkm.getHopSize();
358         m_blockSize = gkm.getBlockSize();
359     }
360     return m_stepSize;
361 }
362
363 size_t
364 KeyDetector::getPreferredBlockSize() const
365 {
366     if (!m_blockSize) {
367         GetKeyMode gkm(int(m_inputSampleRate + 0.1),
368                        m_tuningFrequency, m_length, m_length);
369         m_stepSize = gkm.getHopSize();
370         m_blockSize = gkm.getBlockSize();
371     }
372     return m_blockSize;
373 }
374
375 std::string
376 KeyDetector::getKeyName(int index, bool minor, bool includeMajMin) const
377 {
378     // Keys are numbered with 1 => C, 12 => B
379     // This is based on chromagram base set to a C in qm-dsp's GetKeyMode.cpp
380
381     static const char *namesMajor[] = {
382         "C", "Db", "D", "Eb",
383         "E", "F", "F# / Gb", "G",
384         "Ab", "A", "Bb", "B"
385     };
386
387     static const char *namesMinor[] = {
388         "C", "C#", "D", "Eb / D#",
389         "E", "F", "F#", "G",
390         "G#", "A", "Bb", "B"
391     };
392
393     if (index < 1 || index > 12) {
394         return "(unknown)";
395     }
396
397     std::string base;
398
399     if (minor) base = namesMinor[index - 1];
400     else base = namesMajor[index - 1];
401
402     if (!includeMajMin) return base;
403
404     if (minor) return base + " minor";
405     else return base + " major";
406 }
407