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