annotate plugins/AdaptiveSpectrogram.h @ 109:0dd97d053053

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