annotate plugins/DWT.cpp @ 266:d04675d44928 tip master

Refer to SDK from Github
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 02 Jun 2021 14:41:26 +0100
parents 4697db8b91f8
children
rev   line source
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