Mercurial > hg > qm-vamp-plugins
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 |