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