comparison plugins/ConstantQSpectrogram.cpp @ 9:507f923a93e8

* Add Constant-Q Spectrogram plugin
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 15 May 2006 19:56:21 +0000
parents
children 74ce5b481132
comparison
equal deleted inserted replaced
8:a8215973f030 9:507f923a93e8
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 All rights reserved.
8 */
9
10 #include "ConstantQSpectrogram.h"
11
12 #include <base/Pitch.h>
13 #include <dsp/chromagram/ConstantQ.h>
14
15 using std::string;
16 using std::vector;
17 using std::cerr;
18 using std::endl;
19
20 ConstantQSpectrogram::ConstantQSpectrogram(float inputSampleRate) :
21 Vamp::Plugin(inputSampleRate),
22 m_cq(0),
23 m_step(0),
24 m_block(0),
25 m_bins(1)
26 {
27 m_minMIDIPitch = 12;
28 m_maxMIDIPitch = 96;
29 m_tuningFrequency = 440;
30 m_normalized = true;
31 m_bpo = 12;
32
33 setupConfig();
34 }
35
36 void
37 ConstantQSpectrogram::setupConfig()
38 {
39 m_config.FS = lrintf(m_inputSampleRate);
40 m_config.min = Pitch::getFrequencyForPitch
41 (m_minMIDIPitch, 0, m_tuningFrequency);
42 m_config.max = Pitch::getFrequencyForPitch
43 (m_maxMIDIPitch, 0, m_tuningFrequency);
44 m_config.BPO = m_bpo;
45 m_config.CQThresh = 0.0054;
46
47 m_step = 0;
48 m_block = 0;
49 }
50
51 ConstantQSpectrogram::~ConstantQSpectrogram()
52 {
53 delete m_cq;
54 }
55
56 string
57 ConstantQSpectrogram::getName() const
58 {
59 return "qm-constantq";
60 }
61
62 string
63 ConstantQSpectrogram::getDescription() const
64 {
65 return "Constant-Q Spectrogram";
66 }
67
68 string
69 ConstantQSpectrogram::getMaker() const
70 {
71 return "Queen Mary, University of London";
72 }
73
74 int
75 ConstantQSpectrogram::getPluginVersion() const
76 {
77 return 1;
78 }
79
80 string
81 ConstantQSpectrogram::getCopyright() const
82 {
83 return "Copyright (c) 2006 - All Rights Reserved";
84 }
85
86 ConstantQSpectrogram::ParameterList
87 ConstantQSpectrogram::getParameterDescriptors() const
88 {
89 ParameterList list;
90
91 ParameterDescriptor desc;
92 desc.name = "minpitch";
93 desc.description = "Minimum Pitch";
94 desc.unit = "MIDI units";
95 desc.minValue = 0;
96 desc.maxValue = 127;
97 desc.defaultValue = 36;
98 desc.isQuantized = true;
99 desc.quantizeStep = 1;
100 list.push_back(desc);
101
102 desc.name = "maxpitch";
103 desc.description = "Maximum Pitch";
104 desc.unit = "MIDI units";
105 desc.minValue = 0;
106 desc.maxValue = 127;
107 desc.defaultValue = 84;
108 desc.isQuantized = true;
109 desc.quantizeStep = 1;
110 list.push_back(desc);
111
112 desc.name = "tuning";
113 desc.description = "Tuning Frequency";
114 desc.unit = "Hz";
115 desc.minValue = 420;
116 desc.maxValue = 460;
117 desc.defaultValue = 440;
118 desc.isQuantized = false;
119 list.push_back(desc);
120
121 desc.name = "bpo";
122 desc.description = "Bins per Octave";
123 desc.unit = "bins";
124 desc.minValue = 2;
125 desc.maxValue = 36;
126 desc.defaultValue = 12;
127 desc.isQuantized = true;
128 desc.quantizeStep = 1;
129 list.push_back(desc);
130
131 desc.name = "normalized";
132 desc.description = "Normalized";
133 desc.unit = "";
134 desc.minValue = 0;
135 desc.maxValue = 1;
136 desc.defaultValue = 1;
137 desc.isQuantized = true;
138 desc.quantizeStep = 1;
139 list.push_back(desc);
140
141 return list;
142 }
143
144 float
145 ConstantQSpectrogram::getParameter(std::string param) const
146 {
147 if (param == "minpitch") {
148 return m_minMIDIPitch;
149 }
150 if (param == "maxpitch") {
151 return m_maxMIDIPitch;
152 }
153 if (param == "tuning") {
154 return m_tuningFrequency;
155 }
156 if (param == "bpo") {
157 return m_bpo;
158 }
159 if (param == "normalized") {
160 return m_normalized;
161 }
162 std::cerr << "WARNING: ConstantQSpectrogram::getParameter: unknown parameter \""
163 << param << "\"" << std::endl;
164 return 0.0;
165 }
166
167 void
168 ConstantQSpectrogram::setParameter(std::string param, float value)
169 {
170 if (param == "minpitch") {
171 m_minMIDIPitch = lrintf(value);
172 } else if (param == "maxpitch") {
173 m_maxMIDIPitch = lrintf(value);
174 } else if (param == "tuning") {
175 m_tuningFrequency = value;
176 } else if (param == "bpo") {
177 m_bpo = lrintf(value);
178 } else if (param == "normalized") {
179 m_normalized = (value > 0.0001);
180 } else {
181 std::cerr << "WARNING: ConstantQSpectrogram::setParameter: unknown parameter \""
182 << param << "\"" << std::endl;
183 }
184
185 setupConfig();
186 }
187
188
189 bool
190 ConstantQSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
191 {
192 if (m_cq) {
193 delete m_cq;
194 m_cq = 0;
195 }
196
197 if (channels < getMinChannelCount() ||
198 channels > getMaxChannelCount()) return false;
199
200 if (stepSize != m_step) return false;
201 if (blockSize != m_block) return false;
202
203 std::cerr << "ConstantQSpectrogram::initialise: step " << stepSize << ", block "
204 << blockSize << std::endl;
205
206 m_cq = new ConstantQ(m_config);
207 m_bins = (int)ceil(m_bpo * log(m_config.max / m_config.min) / log(2.0));
208 m_cq->sparsekernel();
209
210 return true;
211 }
212
213 void
214 ConstantQSpectrogram::reset()
215 {
216 if (m_cq) {
217 delete m_cq;
218 m_cq = new ConstantQ(m_config);
219 }
220 }
221
222 size_t
223 ConstantQSpectrogram::getPreferredStepSize() const
224 {
225 if (!m_step) {
226 ConstantQ cq(m_config);
227 m_step = cq.gethop();
228 m_block = cq.getfftlength();
229 }
230
231 return m_step;
232 }
233
234 size_t
235 ConstantQSpectrogram::getPreferredBlockSize() const
236 {
237 if (!m_block) {
238 ConstantQ cq(m_config);
239 m_step = cq.gethop();
240 m_block = cq.getfftlength();
241 }
242
243 return m_block;
244 }
245
246 ConstantQSpectrogram::OutputList
247 ConstantQSpectrogram::getOutputDescriptors() const
248 {
249 OutputList list;
250
251 OutputDescriptor d;
252 d.name = "constantq";
253 d.unit = "";
254 d.description = "Constant-Q Spectrogram";
255 d.hasFixedBinCount = true;
256 d.binCount = m_bins;
257
258 std::cerr << "Bin count " << d.binCount << std::endl;
259
260 const char *names[] =
261 { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
262
263 if (m_bpo == 12) {
264 for (int i = 0; i < d.binCount; ++i) {
265 int ipc = m_minMIDIPitch % 12;
266 int index = (i + ipc) % 12;
267 d.binNames.push_back(names[index]);
268 }
269 } else {
270 d.binNames.push_back(names[m_minMIDIPitch % 12]);
271 }
272
273 d.hasKnownExtents = m_normalized;
274 d.minValue = 0.0;
275 d.maxValue = (m_normalized ? 1.0 : 0.0);
276 d.isQuantized = false;
277 d.sampleType = OutputDescriptor::OneSamplePerStep;
278 list.push_back(d);
279
280 return list;
281 }
282
283 ConstantQSpectrogram::Feature
284 ConstantQSpectrogram::normalize(const Feature &feature)
285 {
286 float min = 0.0, max = 0.0;
287
288 for (size_t i = 0; i < feature.values.size(); ++i) {
289 if (i == 0 || feature.values[i] < min) min = feature.values[i];
290 if (i == 0 || feature.values[i] > max) max = feature.values[i];
291 }
292
293 if (max == 0.0 || max == min) return feature;
294
295 Feature normalized;
296 normalized.hasTimestamp = false;
297
298 for (size_t i = 0; i < feature.values.size(); ++i) {
299 normalized.values.push_back((feature.values[i] - min) / (max - min));
300 }
301
302 return normalized;
303 }
304
305 ConstantQSpectrogram::FeatureSet
306 ConstantQSpectrogram::process(float **inputBuffers, Vamp::RealTime /* timestamp */)
307 {
308 if (!m_cq) {
309 cerr << "ERROR: ConstantQSpectrogram::process: "
310 << "Constant-Q has not been initialised"
311 << endl;
312 return FeatureSet();
313 }
314
315 double *real = new double[m_block];
316 double *imag = new double[m_block];
317 double *cqre = new double[m_bins];
318 double *cqim = new double[m_bins];
319
320 for (size_t i = 0; i < m_block/2; ++i) {
321 real[i] = inputBuffers[0][i*2];
322 real[m_block - i] = real[i];
323 imag[i] = inputBuffers[0][i*2+1];
324 imag[m_block - i] = imag[i];
325 }
326
327 m_cq->process(real, imag, cqre, cqim);
328
329 delete[] real;
330 delete[] imag;
331
332 Feature feature;
333 feature.hasTimestamp = false;
334 for (size_t i = 0; i < m_bins; ++i) {
335 feature.values.push_back(sqrt(cqre[i] * cqre[i] +
336 cqim[i] * cqim[i]));
337 }
338 feature.label = "";
339
340 delete[] cqre;
341 delete[] cqim;
342
343 FeatureSet returnFeatures;
344 if (m_normalized) returnFeatures[0].push_back(normalize(feature));
345 else returnFeatures[0].push_back(feature);
346 return returnFeatures;
347 }
348
349 ConstantQSpectrogram::FeatureSet
350 ConstantQSpectrogram::getRemainingFeatures()
351 {
352 return FeatureSet();
353 }
354