annotate plugins/AdaptiveSpectrogram.h @ 114:496e6d6eb413

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