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