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