annotate plugins/AdaptiveSpectrogram.h @ 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 93355d263f8e
children
rev   line source
c@92 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@92 2
c@92 3 /*
c@92 4 QM Vamp Plugin Set
c@92 5
c@92 6 Centre for Digital Music, Queen Mary, University of London.
c@135 7
c@135 8 This program is free software; you can redistribute it and/or
c@135 9 modify it under the terms of the GNU General Public License as
c@135 10 published by the Free Software Foundation; either version 2 of the
c@135 11 License, or (at your option) any later version. See the file
c@135 12 COPYING included with this distribution for more information.
c@92 13 */
c@92 14
c@92 15 #ifndef _ADAPTIVE_SPECTROGRAM_H_
c@92 16 #define _ADAPTIVE_SPECTROGRAM_H_
c@92 17
c@92 18 #include <vamp-sdk/Plugin.h>
c@92 19 #include <cmath>
c@92 20 #include <vector>
c@92 21
c@108 22 #include <dsp/transforms/FFT.h>
c@107 23 #include <base/Window.h>
c@105 24
c@156 25 #include <thread/Thread.h>
c@156 26 #include <thread/AsynchronousTask.h>
c@156 27 #include <thread/BlockAllocator.h>
c@156 28
c@156 29 class Decimator;
c@104 30
c@92 31 class AdaptiveSpectrogram : public Vamp::Plugin
c@92 32 {
c@92 33 public:
c@92 34 AdaptiveSpectrogram(float inputSampleRate);
c@92 35 virtual ~AdaptiveSpectrogram();
c@92 36
c@92 37 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
c@92 38 void reset();
c@92 39
c@92 40 InputDomain getInputDomain() const { return TimeDomain; }
c@92 41
c@92 42 std::string getIdentifier() const;
c@92 43 std::string getName() const;
c@92 44 std::string getDescription() const;
c@92 45 std::string getMaker() const;
c@92 46 int getPluginVersion() const;
c@92 47 std::string getCopyright() const;
c@92 48
c@92 49 size_t getPreferredStepSize() const;
c@92 50 size_t getPreferredBlockSize() const;
c@92 51
c@92 52 ParameterList getParameterDescriptors() const;
c@92 53 float getParameter(std::string id) const;
c@92 54 void setParameter(std::string id, float value);
c@92 55
c@92 56 OutputList getOutputDescriptors() const;
c@92 57
c@92 58 FeatureSet process(const float *const *inputBuffers,
c@92 59 Vamp::RealTime timestamp);
c@92 60
c@92 61 FeatureSet getRemainingFeatures();
c@92 62
c@92 63 protected:
c@92 64 int m_w;
c@92 65 int m_n;
c@114 66 bool m_coarse;
c@109 67 bool m_threaded;
c@156 68 int m_decFactor;
c@156 69 float *m_buffer;
c@156 70 int m_buflen;
c@156 71 Decimator *m_decimator;
c@92 72
c@100 73 struct Spectrogram
c@100 74 {
c@100 75 int resolution;
c@100 76 int width;
c@100 77 double **data;
c@100 78
c@100 79 Spectrogram(int r, int w) :
c@100 80 resolution(r), width(w) {
c@100 81 data = new double *[width];
c@100 82 for (int i = 0; i < width; ++i) data[i] = new double[resolution];
c@100 83 }
c@100 84
c@100 85 ~Spectrogram() {
c@100 86 for (int i = 0; i < width; ++i) delete[] data[i];
c@100 87 delete[] data;
c@100 88 }
c@100 89 };
c@100 90
c@100 91 struct Spectrograms
c@100 92 {
c@100 93 int minres;
c@100 94 int maxres;
c@100 95 int n;
c@100 96 Spectrogram **spectrograms;
c@100 97
c@100 98 Spectrograms(int mn, int mx, int widthofmax) :
c@100 99 minres(mn), maxres(mx) {
c@100 100 n = log2(maxres/minres) + 1;
c@100 101 spectrograms = new Spectrogram *[n];
c@100 102 int r = mn;
c@100 103 for (int i = 0; i < n; ++i) {
c@100 104 spectrograms[i] = new Spectrogram(r, widthofmax * (mx / r));
c@100 105 r = r * 2;
c@100 106 }
c@100 107 }
c@100 108 ~Spectrograms() {
c@100 109 for (int i = 0; i < n; ++i) {
c@100 110 delete spectrograms[i];
c@100 111 }
c@100 112 delete[] spectrograms;
c@100 113 }
c@100 114 };
c@100 115
c@100 116 struct Cutting
c@100 117 {
c@100 118 enum Cut { Horizontal, Vertical, Finished };
c@100 119 Cut cut;
c@100 120 Cutting *first;
c@100 121 Cutting *second;
c@100 122 double cost;
c@100 123 double value;
c@110 124 BlockAllocator *allocator;
c@100 125
c@100 126 ~Cutting() {
c@110 127 if (first) first->erase();
c@110 128 if (second) second->erase();
c@110 129 }
c@110 130
c@110 131 void erase() {
c@110 132 if (allocator) {
c@110 133 if (first) first->erase();
c@110 134 if (second) second->erase();
c@110 135 allocator->deallocate(this);
c@110 136 } else {
c@110 137 delete this;
c@110 138 }
c@100 139 }
c@100 140 };
c@100 141
c@105 142 class FFTThread : public AsynchronousTask
c@104 143 {
c@104 144 public:
c@107 145 FFTThread(int w) :
c@107 146 m_window(HanningWindow, w) {
c@106 147 m_w = w;
c@106 148 m_fft = new FFTReal(m_w);
c@106 149 m_rin = new double[m_w];
c@106 150 m_rout = new double[m_w];
c@106 151 m_iout = new double[m_w];
c@106 152 }
c@106 153 ~FFTThread() {
c@106 154 delete[] m_rin;
c@106 155 delete[] m_rout;
c@106 156 delete[] m_iout;
c@106 157 delete m_fft;
c@106 158 }
c@106 159
c@106 160 int getW() const { return m_w; }
c@105 161
c@109 162 void startCalculation(const float *timeDomain, Spectrograms &s,
c@109 163 int res, int maxwidth) {
c@109 164 setParameters(timeDomain, s, res, maxwidth);
c@105 165 startTask();
c@105 166 }
c@105 167
c@105 168 void await() {
c@105 169 awaitTask();
c@105 170 }
c@105 171
c@109 172 void setParameters(const float *timeDomain, Spectrograms &s,
c@109 173 int res, int maxwidth) {
c@109 174 m_in = timeDomain;
c@109 175 m_s = &s;
c@109 176 m_res = res;
c@109 177 m_maxwid = maxwidth;
c@109 178 }
c@109 179
c@105 180 void performTask() {
c@105 181 for (int i = 0; i < m_maxwid / m_w; ++i) {
c@105 182 int origin = m_maxwid/4 - m_w/4; // for 50% overlap
c@105 183 for (int j = 0; j < m_w; ++j) {
c@109 184 m_rin[j] = m_in[origin + i * m_w/2 + j];
c@105 185 }
c@107 186 m_window.cut(m_rin);
c@153 187 m_fft->forward(m_rin, m_rout, m_iout);
c@105 188 for (int j = 0; j < m_w/2; ++j) {
c@105 189 int k = j+1; // include Nyquist but not DC
c@106 190 double mag = sqrt(m_rout[k] * m_rout[k] +
c@106 191 m_iout[k] * m_iout[k]);
c@105 192 double scaled = mag / (m_w/2);
c@105 193 m_s->spectrograms[m_res]->data[i][j] = scaled;
c@105 194 }
c@105 195 }
c@105 196 }
c@105 197
c@105 198 private:
c@107 199 Window<double> m_window;
c@106 200 FFTReal *m_fft;
c@105 201 const float *m_in;
c@106 202 double *m_rin;
c@106 203 double *m_rout;
c@106 204 double *m_iout;
c@105 205 Spectrograms *m_s;
c@105 206 int m_res;
c@105 207 int m_w;
c@105 208 int m_maxwid;
c@105 209 };
c@105 210
c@106 211 typedef std::map<int, FFTThread *> FFTMap;
c@106 212 FFTMap m_fftThreads;
c@105 213
c@105 214 class CutThread : public AsynchronousTask
c@105 215 {
c@105 216 public:
c@110 217 CutThread(const AdaptiveSpectrogram *as) : m_as(as), m_result(0) {
c@110 218 m_allocator = new BlockAllocator(sizeof(Cutting));
c@110 219 }
c@110 220 ~CutThread() {
c@110 221 delete m_allocator;
c@110 222 }
c@105 223
c@104 224 void cut(const Spectrograms &s, int res, int x, int y, int h) {
c@104 225 m_s = &s;
c@104 226 m_res = res;
c@104 227 m_x = x;
c@104 228 m_y = y;
c@104 229 m_h = h;
c@105 230 startTask();
c@104 231 }
c@104 232
c@104 233 Cutting *get() {
c@105 234 awaitTask();
c@105 235 return m_result;
c@104 236 }
c@104 237
c@104 238 protected:
c@105 239 void performTask() {
c@110 240 m_result = m_as->cut(*m_s, m_res, m_x, m_y, m_h, m_allocator);
c@104 241 }
c@104 242
c@105 243 private:
c@104 244 const AdaptiveSpectrogram *m_as;
c@110 245 BlockAllocator *m_allocator;
c@104 246 const Spectrograms *m_s;
c@104 247 int m_res;
c@104 248 int m_x;
c@104 249 int m_y;
c@104 250 int m_h;
c@104 251 Cutting *m_result;
c@104 252 };
c@105 253
c@109 254 mutable std::vector<CutThread *> m_cutThreads;
c@109 255 mutable bool m_threadsInUse;
c@104 256
c@110 257 inline double xlogx(double x) const {
c@104 258 if (x == 0.0) return 0.0;
c@104 259 else return x * log(x);
c@104 260 }
c@104 261
c@110 262 inline double cost(const Spectrogram &s, int x, int y) const {
c@100 263 return xlogx(s.data[x][y]);
c@100 264 }
c@100 265
c@110 266 inline double value(const Spectrogram &s, int x, int y) const {
c@100 267 return s.data[x][y];
c@100 268 }
c@100 269
c@114 270 inline double normalize(double vcost, double venergy) const {
c@114 271 return (vcost + (venergy * log(venergy))) / venergy;
c@114 272 }
c@114 273
c@114 274 inline bool isResolutionWanted(const Spectrograms &s, int res) const {
c@114 275 if (!m_coarse) return true;
c@114 276 if (res == s.minres || res == s.maxres) return true;
c@114 277 int n = 0;
c@114 278 for (int r = res; r > s.minres; r >>= 1) ++n;
c@114 279 return ((n & 0x1) == 0);
c@114 280 }
c@114 281
c@110 282 Cutting *cut(const Spectrograms &, int res, int x, int y, int h,
c@110 283 BlockAllocator *allocator) const;
c@100 284
c@104 285 void getSubCuts(const Spectrograms &, int res, int x, int y, int h,
c@114 286 Cutting **top, Cutting **bottom,
c@114 287 Cutting **left, Cutting **right,
c@113 288 BlockAllocator *allocator) const;
c@100 289
c@104 290 void printCutting(Cutting *, std::string) const;
c@104 291
c@104 292 void assemble(const Spectrograms &, const Cutting *,
c@104 293 std::vector<std::vector<float> > &,
c@104 294 int x, int y, int w, int h) const;
c@156 295 };
c@92 296
c@92 297
c@92 298 #endif