c@97
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@97
|
2
|
c@97
|
3 /*
|
c@97
|
4 QM Vamp Plugin Set
|
c@97
|
5
|
c@97
|
6 Centre for Digital Music, Queen Mary, University of London.
|
c@97
|
7 This file copyright 2009 Thomas Wilmering.
|
c@135
|
8
|
c@135
|
9 This program is free software; you can redistribute it and/or
|
c@135
|
10 modify it under the terms of the GNU General Public License as
|
c@135
|
11 published by the Free Software Foundation; either version 2 of the
|
c@135
|
12 License, or (at your option) any later version. See the file
|
c@135
|
13 COPYING included with this distribution for more information.
|
c@97
|
14 */
|
c@97
|
15
|
c@97
|
16 #include "DWT.h"
|
c@97
|
17
|
c@97
|
18 #include <cmath>
|
c@97
|
19
|
c@97
|
20 using std::string;
|
c@97
|
21 using std::vector;
|
c@97
|
22 using std::cerr;
|
c@97
|
23 using std::endl;
|
c@97
|
24
|
c@97
|
25 DWT::DWT(float inputSampleRate) :
|
c@97
|
26 Plugin(inputSampleRate),
|
c@97
|
27 m_stepSize(0),
|
c@97
|
28 m_blockSize(0)
|
c@97
|
29 {
|
c@97
|
30 m_scales = 10;
|
c@97
|
31 m_flength = 0;
|
c@97
|
32 m_wavelet = Wavelet::Haar;
|
c@97
|
33 m_threshold = 0;
|
c@97
|
34 m_absolute = 0;
|
c@97
|
35 }
|
c@97
|
36
|
c@97
|
37 DWT::~DWT()
|
c@97
|
38 {
|
c@97
|
39 }
|
c@97
|
40
|
c@97
|
41 string
|
c@97
|
42 DWT::getIdentifier() const
|
c@97
|
43 {
|
c@98
|
44 return "qm-dwt";
|
c@97
|
45 }
|
c@97
|
46
|
c@97
|
47 string
|
c@97
|
48 DWT::getName() const
|
c@97
|
49 {
|
c@97
|
50 return "Discrete Wavelet Transform";
|
c@97
|
51 }
|
c@97
|
52
|
c@97
|
53 string
|
c@97
|
54 DWT::getDescription() const
|
c@97
|
55 {
|
c@97
|
56 return "Visualisation by scalogram";
|
c@97
|
57 }
|
c@97
|
58
|
c@97
|
59 string
|
c@97
|
60 DWT::getMaker() const
|
c@97
|
61 {
|
c@97
|
62 return "Queen Mary, University of London";
|
c@97
|
63 }
|
c@97
|
64
|
c@97
|
65 int
|
c@97
|
66 DWT::getPluginVersion() const
|
c@97
|
67 {
|
c@97
|
68 return 1;
|
c@97
|
69 }
|
c@97
|
70
|
c@97
|
71 string
|
c@97
|
72 DWT::getCopyright() const
|
c@97
|
73 {
|
c@97
|
74 return "Plugin by Thomas Wilmering. Copyright (c) 2009 Thomas Wilmering and QMUL - All Rights Reserved";
|
c@97
|
75 }
|
c@97
|
76
|
c@97
|
77 size_t
|
c@129
|
78 DWT::getPreferredBlockSize() const
|
c@129
|
79 {
|
c@129
|
80 size_t s = (1 << m_scales);
|
c@129
|
81 while (s < 1024) s *= 2;
|
c@129
|
82 return s;
|
c@129
|
83 }
|
c@129
|
84
|
c@129
|
85 size_t
|
c@97
|
86 DWT::getPreferredStepSize() const
|
c@97
|
87 {
|
c@97
|
88 return 0;
|
c@97
|
89 }
|
c@97
|
90
|
c@97
|
91 bool
|
c@97
|
92 DWT::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
c@97
|
93 {
|
c@97
|
94 if (channels < getMinChannelCount() ||
|
c@97
|
95 channels > getMaxChannelCount()) return false;
|
c@97
|
96
|
c@129
|
97 if ((1 << m_scales) > blockSize) {
|
c@129
|
98 std::cerr << "DWT::initialise: ERROR: Block size must be at least 2^scales (specified block size " << blockSize << " < " << (1 << m_scales) << ")" << std::endl;
|
c@129
|
99 return false;
|
c@129
|
100 }
|
c@129
|
101
|
c@97
|
102 m_stepSize = stepSize;
|
c@97
|
103 m_blockSize = blockSize;
|
c@97
|
104
|
c@97
|
105 Wavelet::createDecompositionFilters(m_wavelet, m_lpd, m_hpd);
|
c@97
|
106
|
c@97
|
107 m_flength = m_lpd.size(); // or m_hpd.size()
|
c@97
|
108
|
c@97
|
109 m_samplePass.resize(m_scales); // resize buffer for samples to pass to next block
|
c@97
|
110
|
c@97
|
111 for (int i=0; i<m_scales; ++i) {
|
c@97
|
112 m_samplePass[i].resize(m_flength-2, 0.0);
|
c@97
|
113 }
|
c@97
|
114
|
c@97
|
115 return true;
|
c@97
|
116 }
|
c@97
|
117
|
c@97
|
118 void
|
c@97
|
119 DWT::reset()
|
c@97
|
120 {
|
c@97
|
121 m_samplePass.clear();
|
c@97
|
122
|
c@97
|
123 m_samplePass.resize(m_scales);
|
c@97
|
124
|
c@97
|
125 for (int i=0; i<m_scales; ++i) {
|
c@97
|
126 m_samplePass[i].resize(m_flength-2, 0.0);
|
c@97
|
127 }
|
c@97
|
128 }
|
c@97
|
129
|
c@97
|
130 DWT::OutputList
|
c@97
|
131 DWT::getOutputDescriptors() const
|
c@97
|
132 {
|
c@97
|
133 OutputList list;
|
c@97
|
134
|
c@97
|
135 OutputDescriptor sg;
|
c@97
|
136 sg.identifier = "wcoeff";
|
c@97
|
137 sg.name = "Wavelet Coefficients";
|
c@97
|
138 sg.description = "Wavelet coefficients";
|
c@97
|
139 sg.unit = "";
|
c@97
|
140 sg.hasFixedBinCount = true; // depends on block size
|
c@97
|
141 sg.binCount = m_scales; // number of scales
|
c@97
|
142 sg.hasKnownExtents = false;
|
c@97
|
143 sg.isQuantized = false;
|
c@97
|
144 sg.sampleType = OutputDescriptor::FixedSampleRate;
|
c@97
|
145 sg.sampleRate = .5 * m_inputSampleRate;
|
c@97
|
146
|
c@97
|
147 list.push_back(sg);
|
c@97
|
148
|
c@97
|
149 return list;
|
c@97
|
150 }
|
c@97
|
151
|
c@97
|
152
|
c@97
|
153 DWT::ParameterList
|
c@97
|
154 DWT::getParameterDescriptors() const
|
c@97
|
155 {
|
c@97
|
156 ParameterList list;
|
c@97
|
157
|
c@97
|
158 ParameterDescriptor d;
|
c@97
|
159 d.identifier = "scales";
|
c@97
|
160 d.name = "Scales";
|
c@97
|
161 d.description = "Scale depth";
|
c@97
|
162 d.unit = "";
|
c@97
|
163 d.minValue = 1.0f;
|
c@97
|
164 d.maxValue = 16.0f;
|
c@97
|
165 d.defaultValue = 10.0f;
|
c@97
|
166 d.isQuantized = true;
|
c@97
|
167 d.quantizeStep = 1.0f;
|
c@97
|
168 list.push_back(d);
|
c@97
|
169
|
c@97
|
170 d.identifier = "wavelet";
|
c@97
|
171 d.name = "Wavelet";
|
c@119
|
172 d.description = "Wavelet type to use";
|
c@97
|
173 d.unit = "";
|
c@97
|
174 d.minValue = 0.f;
|
c@97
|
175 d.maxValue = int(Wavelet::LastType);
|
c@97
|
176 d.defaultValue = int(Wavelet::Haar);
|
c@97
|
177 d.isQuantized = true;
|
c@97
|
178 d.quantizeStep = 1.0f;
|
c@97
|
179
|
c@97
|
180 for (int i = 0; i <= int(Wavelet::LastType); ++i) {
|
c@97
|
181 d.valueNames.push_back(Wavelet::getWaveletName(Wavelet::Type(i)));
|
c@97
|
182 }
|
c@97
|
183 list.push_back(d);
|
c@97
|
184 d.valueNames.clear();
|
c@97
|
185
|
c@97
|
186 d.identifier = "threshold";
|
c@97
|
187 d.name = "Threshold";
|
c@97
|
188 d.description = "Wavelet coefficient threshold";
|
c@97
|
189 d.unit = "";
|
c@97
|
190 d.minValue = 0.0f;
|
c@97
|
191 d.maxValue = 0.01f;
|
c@97
|
192 d.defaultValue = 0.0f;
|
c@97
|
193 d.isQuantized = false;
|
c@97
|
194 list.push_back(d);
|
c@97
|
195
|
c@97
|
196 d.identifier = "absolute";
|
c@97
|
197 d.name = "Absolute values";
|
c@97
|
198 d.description = "Return absolute values";
|
c@97
|
199 d.unit = "";
|
c@97
|
200 d.minValue = 0.0f;
|
c@97
|
201 d.maxValue = 1.00f;
|
c@97
|
202 d.defaultValue = 0.0f;
|
c@97
|
203 d.isQuantized = true;
|
c@97
|
204 d.quantizeStep = 1.0f;
|
c@97
|
205 list.push_back(d);
|
c@97
|
206
|
c@97
|
207 return list;
|
c@97
|
208 }
|
c@97
|
209
|
c@97
|
210 void DWT::setParameter(std::string paramid, float newval)
|
c@97
|
211 {
|
c@97
|
212 if (paramid == "scales") {
|
c@97
|
213 m_scales = newval;
|
c@97
|
214 }
|
c@97
|
215 else if (paramid == "wavelet") {
|
c@97
|
216 m_wavelet = (Wavelet::Type)(int(newval + 0.1));
|
c@97
|
217 }
|
c@97
|
218 else if (paramid == "threshold") {
|
c@97
|
219 m_threshold = newval;
|
c@97
|
220 }
|
c@97
|
221 else if (paramid == "absolute") {
|
c@97
|
222 m_absolute = newval;
|
c@97
|
223 }
|
c@97
|
224 }
|
c@97
|
225
|
c@97
|
226 float DWT::getParameter(std::string paramid) const
|
c@97
|
227 {
|
c@97
|
228 if (paramid == "scales") {
|
c@97
|
229 return m_scales;
|
c@97
|
230 }
|
c@97
|
231 else if (paramid == "wavelet") {
|
c@97
|
232 return int(m_wavelet);
|
c@97
|
233 }
|
c@97
|
234 else if (paramid == "threshold") {
|
c@97
|
235 return m_threshold;
|
c@97
|
236 }
|
c@97
|
237 else if (paramid == "absolute") {
|
c@97
|
238 return m_absolute;
|
c@97
|
239 }
|
c@97
|
240
|
c@97
|
241 return 0.0f;
|
c@97
|
242 }
|
c@97
|
243
|
c@97
|
244
|
c@97
|
245 DWT::FeatureSet
|
c@97
|
246 DWT::process(const float *const *inputBuffers,
|
c@97
|
247 Vamp::RealTime)
|
c@97
|
248 {
|
c@97
|
249 FeatureSet fs;
|
c@97
|
250
|
c@97
|
251 if (m_blockSize == 0) {
|
c@97
|
252 cerr << "ERROR: DWT::process: Not initialised" << endl;
|
c@97
|
253 return fs;
|
c@97
|
254 }
|
c@97
|
255
|
c@97
|
256 int s = m_scales;
|
c@97
|
257 int b = m_blockSize;
|
c@97
|
258 int b_init = b;
|
c@97
|
259
|
c@97
|
260 if ((1 << s) > b) b = 1 << s; // correct blocksize if smaller than 2^(max scale)
|
c@97
|
261
|
c@97
|
262 //--------------------------------------------------------------------------------------------------
|
c@97
|
263
|
c@97
|
264 float tempDet;
|
c@127
|
265 float aTempDet;
|
c@97
|
266 int outloc;
|
c@97
|
267 int halfblocksize = int(.5 * b);
|
c@97
|
268 int fbufloc;
|
c@97
|
269 int fbufloc2;
|
c@97
|
270
|
c@97
|
271 vector< vector<float> > wCoefficients(m_scales); // result
|
c@97
|
272 vector<float> tempAprx(halfblocksize,0.0); // approximation
|
c@97
|
273 vector<float> fbuf(b+m_flength-2,0.0); // input buffer
|
c@97
|
274
|
c@97
|
275 for (int n=m_flength-2; n<b+m_flength-2; n++) // copy input buffer to dwt input
|
c@97
|
276 fbuf[n] = inputBuffers[0][n-m_flength+2];
|
c@97
|
277
|
c@97
|
278 for (int scale=0; scale<m_scales; ++scale) // do for each scale
|
c@97
|
279 {
|
c@97
|
280 for (int n=0; n<m_flength-2; ++n) // get samples from previous block
|
c@97
|
281 fbuf[n] = m_samplePass[scale][n];
|
c@97
|
282
|
c@97
|
283
|
c@97
|
284 if ((m_flength-2)<b) // pass samples to next block
|
c@97
|
285 for (int n=0; n<m_flength-2; ++n)
|
c@97
|
286 m_samplePass[scale][n] = fbuf[b+n];
|
c@97
|
287 else {
|
c@97
|
288 for (int n=0; n<b; ++n) // if number of samples to pass > blocksize
|
c@97
|
289 m_samplePass[scale].push_back(fbuf[m_flength-2+n]);
|
c@97
|
290 m_samplePass[scale].erase (m_samplePass[scale].begin(),m_samplePass[scale].begin()+b);
|
c@97
|
291 }
|
c@97
|
292
|
c@97
|
293 for (int n=0; n<halfblocksize; ++n) { // do for every other sample of the input buffer
|
c@97
|
294 tempDet = 0;
|
c@97
|
295 fbufloc = 2*n+m_flength-1;
|
c@97
|
296 for (int m=0; m<m_flength; ++m) { // Convolve the sample with filter coefficients
|
c@97
|
297 fbufloc2 = fbufloc - m;
|
c@97
|
298 tempAprx[n] += fbuf[fbufloc2] * m_lpd[m]; // approximation
|
c@97
|
299 tempDet += fbuf[fbufloc2] * m_hpd[m]; // detail
|
c@97
|
300 }
|
c@97
|
301
|
c@127
|
302 aTempDet = fabs(tempDet);
|
c@127
|
303 if (m_absolute == 1) tempDet = aTempDet;
|
c@97
|
304
|
c@97
|
305
|
c@127
|
306 if (aTempDet < m_threshold) tempDet = 0; // simple hard thresholding, same for each scale
|
c@97
|
307 wCoefficients[scale].push_back(tempDet);
|
c@97
|
308 }
|
c@97
|
309
|
c@97
|
310 if (scale+1<m_scales) { // prepare variables for next scale
|
c@97
|
311 b = b >> 1; // the approximation in tmpfwd is stored as
|
c@97
|
312 halfblocksize = halfblocksize >> 1; // input for next level
|
c@97
|
313
|
c@97
|
314 for (int n=m_flength-2; n<b+m_flength-2; n++) // copy approximation to dwt input
|
c@97
|
315 fbuf[n] = tempAprx[n-m_flength+2];
|
c@97
|
316
|
c@97
|
317 //vector<float>(b+m_flength-2).swap(fbuf);
|
c@97
|
318 vector<float>(halfblocksize).swap(tempAprx); // set new size with zeros
|
c@97
|
319 }
|
c@97
|
320 }
|
c@97
|
321
|
c@97
|
322
|
c@97
|
323 //-----------------------------------------------------------------------------------------
|
c@97
|
324
|
c@97
|
325 halfblocksize = int(.5 * b_init);
|
c@97
|
326
|
c@97
|
327 for (int m = 0; m<halfblocksize; m++) {
|
c@97
|
328
|
c@97
|
329 Feature feature;
|
c@97
|
330 feature.hasTimestamp = false;
|
c@97
|
331
|
c@97
|
332 for (int j = 0; j < s; j++) {
|
c@130
|
333 outloc = m / (1 << j); // This one pushes a single result bin
|
c@97
|
334 // onto the top of a feature column
|
c@97
|
335 feature.values.push_back(wCoefficients[j][outloc]); // each coefficient on higher scales need
|
c@97
|
336 } // to be copied multiple times to feature columns
|
c@97
|
337 fs[0].push_back(feature);
|
c@97
|
338 }
|
c@97
|
339 return fs;
|
c@97
|
340 }
|
c@97
|
341
|
c@97
|
342
|
c@97
|
343
|
c@97
|
344 DWT::FeatureSet
|
c@97
|
345 DWT::getRemainingFeatures()
|
c@97
|
346 {
|
c@97
|
347 int s = m_scales;
|
c@97
|
348
|
c@97
|
349 FeatureSet fs;
|
c@97
|
350
|
c@97
|
351 /*
|
c@97
|
352 int b = 1;
|
c@97
|
353 while (b<((m_flength-1) * (1 << s))) { //set blocksize to tail length
|
c@97
|
354 b= (b << 1);
|
c@97
|
355 }
|
c@97
|
356 int b_init = b;
|
c@97
|
357
|
c@97
|
358 */
|
c@97
|
359 int b = m_blockSize;
|
c@97
|
360 int b_init = b;
|
c@97
|
361 int tailIterations = int(((m_flength-1) * (1 << s)) / b) + 1; // number of iterations for tail
|
c@97
|
362
|
c@97
|
363
|
c@97
|
364 for(int m=0; m<tailIterations; ++m)
|
c@97
|
365 {
|
c@97
|
366
|
c@97
|
367 b = b_init;
|
c@97
|
368
|
c@97
|
369 //-------------------------------------------------------------------------------------------
|
c@97
|
370 float tempDet;
|
c@127
|
371 float aTempDet;
|
c@97
|
372 int outloc;
|
c@97
|
373 int halfblocksize = int(.5 * b);
|
c@97
|
374 int fbufloc;
|
c@97
|
375 int fbufloc2;
|
c@97
|
376 int len = m_flength;
|
c@97
|
377
|
c@97
|
378 vector< vector<float> > wCoefficients(m_scales); // result
|
c@97
|
379 vector<float> tempAprx(halfblocksize,0.0); // approximation
|
c@97
|
380 vector<float> fbuf(b+len-2,0.0); // input buffer
|
c@97
|
381
|
c@97
|
382 //for (int n=len-2; n<b+len-2; n++) // copy input buffer to dwt input
|
c@97
|
383 // fbuf[n] = 0; //inputBuffers[0][n-len+2];
|
c@97
|
384
|
c@97
|
385 for (int scale=0; scale<m_scales; ++scale) // do for each scale
|
c@97
|
386 {
|
c@97
|
387 for (int n=0; n<len-2; ++n) // get samples from previous block
|
c@97
|
388 fbuf[n] = m_samplePass[scale][n];
|
c@97
|
389
|
c@97
|
390
|
c@97
|
391 if ((len-2)<b) // pass samples to next block
|
c@97
|
392 for (int n=0; n<len-2; ++n)
|
c@97
|
393 m_samplePass[scale][n] = fbuf[b+n];
|
c@97
|
394 else {
|
c@97
|
395 for (int n=0; n<b; ++n) // if number of samples to pass > blocksize
|
c@97
|
396 m_samplePass[scale].push_back(fbuf[len-2+n]);
|
c@97
|
397 m_samplePass[scale].erase (m_samplePass[scale].begin(),m_samplePass[scale].begin()+b);
|
c@97
|
398 }
|
c@97
|
399
|
c@97
|
400 for (int n=0; n<halfblocksize; ++n) { // do for every other sample of the input buffer
|
c@97
|
401 tempDet = 0;
|
c@97
|
402 fbufloc = 2*n+len-1;
|
c@97
|
403 for (int m=0; m<len; ++m) { // Convolve the sample with filter coefficients
|
c@97
|
404 fbufloc2 = fbufloc - m;
|
c@97
|
405 tempAprx[n] += fbuf[fbufloc2] * m_lpd[m]; // approximation
|
c@97
|
406 tempDet += fbuf[fbufloc2] * m_hpd[m]; // detail
|
c@97
|
407 }
|
c@127
|
408
|
c@127
|
409 aTempDet = fabs(tempDet);
|
c@127
|
410 if (m_absolute == 1) tempDet = aTempDet;
|
c@127
|
411 if (aTempDet < m_threshold) tempDet = 0; // simple hard thresholding, same for each scale
|
c@97
|
412 wCoefficients[scale].push_back(tempDet);
|
c@97
|
413 }
|
c@97
|
414
|
c@97
|
415 if (scale+1<m_scales) { // prepare variables for next scale
|
c@97
|
416 b = b >> 1; // the approximation in tmpfwd is stored as
|
c@97
|
417 halfblocksize = halfblocksize >> 1; // input for next level
|
c@97
|
418
|
c@97
|
419 for (int n=len-2; n<b+len-2; n++) // copy approximation to dwt input
|
c@97
|
420 fbuf[n] = tempAprx[n-len+2];
|
c@97
|
421
|
c@97
|
422 //vector<float>(b+len-2).swap(fbuf);
|
c@97
|
423 vector<float>(halfblocksize).swap(tempAprx); // set new size with zeros
|
c@97
|
424 }
|
c@97
|
425
|
c@97
|
426 }
|
c@97
|
427
|
c@97
|
428 //-----------------------------------------------------------------------------------------
|
c@97
|
429
|
c@97
|
430 halfblocksize = int(.5 * b_init + 0.1);
|
c@97
|
431
|
c@97
|
432 for (int m = 0; m<halfblocksize; m++) {
|
c@97
|
433
|
c@97
|
434 Feature feature;
|
c@97
|
435 feature.hasTimestamp = false;
|
c@97
|
436
|
c@97
|
437 for (int j = 0; j < s; j++) {
|
c@130
|
438 outloc = m / (1 << j); // This one pushes a single result bin
|
c@97
|
439 // onto the top of a feature column
|
c@97
|
440 feature.values.push_back(wCoefficients[j][outloc]); // each coefficient on higher scales need
|
c@97
|
441 } // to be copied multiple times to feature columns
|
c@97
|
442 fs[0].push_back(feature);
|
c@97
|
443 }
|
c@97
|
444 }
|
c@97
|
445 return fs;
|
c@97
|
446
|
c@97
|
447 }
|
c@97
|
448
|