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 #include "AdaptiveSpectrogram.h"
|
c@92
|
11
|
c@92
|
12 #include <cstdlib>
|
c@92
|
13 #include <cstring>
|
c@92
|
14
|
c@92
|
15 #include <iostream>
|
c@92
|
16
|
c@92
|
17 #include <dsp/transforms/FFT.h>
|
c@92
|
18
|
c@92
|
19 using std::string;
|
c@92
|
20 using std::vector;
|
c@92
|
21 using std::cerr;
|
c@92
|
22 using std::endl;
|
c@92
|
23
|
c@92
|
24 using Vamp::RealTime;
|
c@92
|
25
|
c@92
|
26 AdaptiveSpectrogram::AdaptiveSpectrogram(float inputSampleRate) :
|
c@92
|
27 Plugin(inputSampleRate),
|
c@92
|
28 m_w(9),
|
c@92
|
29 m_n(2)
|
c@92
|
30 {
|
c@92
|
31 }
|
c@92
|
32
|
c@92
|
33 AdaptiveSpectrogram::~AdaptiveSpectrogram()
|
c@92
|
34 {
|
c@92
|
35 }
|
c@92
|
36
|
c@92
|
37 string
|
c@92
|
38 AdaptiveSpectrogram::getIdentifier() const
|
c@92
|
39 {
|
c@92
|
40 return "adaptivespectrogram";
|
c@92
|
41 }
|
c@92
|
42
|
c@92
|
43 string
|
c@92
|
44 AdaptiveSpectrogram::getName() const
|
c@92
|
45 {
|
c@92
|
46 return "Adaptive Spectrogram";
|
c@92
|
47 }
|
c@92
|
48
|
c@92
|
49 string
|
c@92
|
50 AdaptiveSpectrogram::getDescription() const
|
c@92
|
51 {
|
c@92
|
52 return "Produce an adaptive spectrogram by adaptive selection from spectrograms at multiple resolutions";
|
c@92
|
53 }
|
c@92
|
54
|
c@92
|
55 string
|
c@92
|
56 AdaptiveSpectrogram::getMaker() const
|
c@92
|
57 {
|
c@92
|
58 return "Queen Mary, University of London";
|
c@92
|
59 }
|
c@92
|
60
|
c@92
|
61 int
|
c@92
|
62 AdaptiveSpectrogram::getPluginVersion() const
|
c@92
|
63 {
|
c@92
|
64 return 1;
|
c@92
|
65 }
|
c@92
|
66
|
c@92
|
67 string
|
c@92
|
68 AdaptiveSpectrogram::getCopyright() const
|
c@92
|
69 {
|
c@92
|
70 return "Plugin by Wen Xue and Chris Cannam. Copyright (c) 2009 Wen Xue and QMUL - All Rights Reserved";
|
c@92
|
71 }
|
c@92
|
72
|
c@92
|
73 size_t
|
c@92
|
74 AdaptiveSpectrogram::getPreferredStepSize() const
|
c@92
|
75 {
|
c@92
|
76 return ((2 << m_w) << m_n) / 2;
|
c@92
|
77 }
|
c@92
|
78
|
c@92
|
79 size_t
|
c@92
|
80 AdaptiveSpectrogram::getPreferredBlockSize() const
|
c@92
|
81 {
|
c@92
|
82 return (2 << m_w) << m_n;
|
c@92
|
83 }
|
c@92
|
84
|
c@92
|
85 bool
|
c@92
|
86 AdaptiveSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
c@92
|
87 {
|
c@92
|
88 if (channels < getMinChannelCount() ||
|
c@92
|
89 channels > getMaxChannelCount()) return false;
|
c@92
|
90
|
c@92
|
91 return true;
|
c@92
|
92 }
|
c@92
|
93
|
c@92
|
94 void
|
c@92
|
95 AdaptiveSpectrogram::reset()
|
c@92
|
96 {
|
c@92
|
97
|
c@92
|
98 }
|
c@92
|
99
|
c@92
|
100 AdaptiveSpectrogram::ParameterList
|
c@92
|
101 AdaptiveSpectrogram::getParameterDescriptors() const
|
c@92
|
102 {
|
c@92
|
103 ParameterList list;
|
c@92
|
104
|
c@92
|
105 ParameterDescriptor desc;
|
c@92
|
106 desc.identifier = "n";
|
c@92
|
107 desc.name = "Number of resolutions";
|
c@92
|
108 desc.description = "Number of consecutive powers of two to use as spectrogram resolutions, starting with the minimum resolution specified";
|
c@92
|
109 desc.unit = "";
|
c@92
|
110 desc.minValue = 1;
|
c@92
|
111 desc.maxValue = 10;
|
c@92
|
112 desc.defaultValue = 3;
|
c@92
|
113 desc.isQuantized = true;
|
c@92
|
114 desc.quantizeStep = 1;
|
c@92
|
115 list.push_back(desc);
|
c@92
|
116
|
c@92
|
117 ParameterDescriptor desc2;
|
c@92
|
118 desc2.identifier = "w";
|
c@92
|
119 desc2.name = "Smallest resolution";
|
c@92
|
120 desc2.description = "Smallest of the consecutive powers of two to use as spectrogram resolutions";
|
c@92
|
121 desc2.unit = "";
|
c@92
|
122 desc2.minValue = 1;
|
c@92
|
123 desc2.maxValue = 14;
|
c@92
|
124 desc2.defaultValue = 10;
|
c@92
|
125 desc2.isQuantized = true;
|
c@92
|
126 desc2.quantizeStep = 1;
|
c@92
|
127 // I am so lazy
|
c@92
|
128 desc2.valueNames.push_back("2");
|
c@92
|
129 desc2.valueNames.push_back("4");
|
c@92
|
130 desc2.valueNames.push_back("8");
|
c@92
|
131 desc2.valueNames.push_back("16");
|
c@92
|
132 desc2.valueNames.push_back("32");
|
c@92
|
133 desc2.valueNames.push_back("64");
|
c@92
|
134 desc2.valueNames.push_back("128");
|
c@92
|
135 desc2.valueNames.push_back("256");
|
c@92
|
136 desc2.valueNames.push_back("512");
|
c@92
|
137 desc2.valueNames.push_back("1024");
|
c@92
|
138 desc2.valueNames.push_back("2048");
|
c@92
|
139 desc2.valueNames.push_back("4096");
|
c@92
|
140 desc2.valueNames.push_back("8192");
|
c@92
|
141 desc2.valueNames.push_back("16384");
|
c@92
|
142 list.push_back(desc2);
|
c@92
|
143
|
c@92
|
144 return list;
|
c@92
|
145 }
|
c@92
|
146
|
c@92
|
147 float
|
c@92
|
148 AdaptiveSpectrogram::getParameter(std::string id) const
|
c@92
|
149 {
|
c@92
|
150 if (id == "n") return m_n+1;
|
c@92
|
151 else if (id == "w") return m_w+1;
|
c@92
|
152 return 0.f;
|
c@92
|
153 }
|
c@92
|
154
|
c@92
|
155 void
|
c@92
|
156 AdaptiveSpectrogram::setParameter(std::string id, float value)
|
c@92
|
157 {
|
c@92
|
158 if (id == "n") {
|
c@92
|
159 int n = lrintf(value);
|
c@92
|
160 if (n >= 1 && n <= 10) m_n = n-1;
|
c@92
|
161 } else if (id == "w") {
|
c@92
|
162 int w = lrintf(value);
|
c@92
|
163 if (w >= 1 && w <= 14) m_w = w-1;
|
c@92
|
164 }
|
c@92
|
165 }
|
c@92
|
166
|
c@92
|
167 AdaptiveSpectrogram::OutputList
|
c@92
|
168 AdaptiveSpectrogram::getOutputDescriptors() const
|
c@92
|
169 {
|
c@92
|
170 OutputList list;
|
c@92
|
171
|
c@92
|
172 OutputDescriptor d;
|
c@92
|
173 d.identifier = "output";
|
c@92
|
174 d.name = "Output";
|
c@92
|
175 d.description = "The output of the plugin";
|
c@92
|
176 d.unit = "";
|
c@92
|
177 d.hasFixedBinCount = true;
|
c@92
|
178 d.binCount = ((2 << m_w) << m_n) / 2;
|
c@92
|
179 d.hasKnownExtents = false;
|
c@92
|
180 d.isQuantized = false;
|
c@92
|
181 d.sampleType = OutputDescriptor::FixedSampleRate;
|
c@92
|
182 d.sampleRate = m_inputSampleRate / ((2 << m_w) / 2);
|
c@92
|
183 d.hasDuration = false;
|
c@92
|
184 list.push_back(d);
|
c@92
|
185
|
c@92
|
186 return list;
|
c@92
|
187 }
|
c@92
|
188
|
c@92
|
189 AdaptiveSpectrogram::FeatureSet
|
c@92
|
190 AdaptiveSpectrogram::getRemainingFeatures()
|
c@92
|
191 {
|
c@92
|
192 FeatureSet fs;
|
c@92
|
193 return fs;
|
c@92
|
194 }
|
c@92
|
195
|
c@92
|
196 AdaptiveSpectrogram::FeatureSet
|
c@92
|
197 AdaptiveSpectrogram::process(const float *const *inputBuffers, RealTime ts)
|
c@92
|
198 {
|
c@92
|
199 FeatureSet fs;
|
c@92
|
200
|
c@92
|
201 int wid = (2 << m_w), WID = ((2 << m_w) << m_n);
|
c@92
|
202 int Res = log2(WID/wid)+1;
|
c@92
|
203 double ***specs = new double **[Res];
|
c@92
|
204 int Wid = WID;
|
c@92
|
205 int wi = 0;
|
c@92
|
206
|
c@92
|
207 cerr << "wid = " << wid << ", WID = " << WID << endl;
|
c@92
|
208
|
c@92
|
209 double *tmpin = new double[WID];
|
c@92
|
210 double *tmprout = new double[WID];
|
c@92
|
211 double *tmpiout = new double[WID];
|
c@92
|
212
|
c@92
|
213 while (Wid >= wid) {
|
c@92
|
214 specs[wi] = new double *[WID/Wid];
|
c@92
|
215 for (int i = 0; i < WID/Wid; ++i) {
|
c@92
|
216 specs[wi][i] = new double[Wid/2];
|
c@92
|
217 int origin = WID/4 - Wid/4; // for 50% overlap
|
c@92
|
218 for (int j = 0; j < Wid; ++j) {
|
c@92
|
219 double mul = 0.50 - 0.50 * cos((2 * M_PI * j) / Wid);
|
c@92
|
220 tmpin[j] = inputBuffers[0][origin + i * Wid/2 + j] * mul;
|
c@92
|
221 }
|
c@92
|
222 FFT::process(Wid, false, tmpin, 0, tmprout, tmpiout);
|
c@92
|
223 for (int j = 0; j < Wid/2; ++j) {
|
c@92
|
224 double mag =
|
c@92
|
225 tmprout[j] * tmprout[j] +
|
c@92
|
226 tmpiout[j] * tmpiout[j];
|
c@92
|
227 specs[wi][i][j] = sqrt(mag) / Wid;
|
c@92
|
228 }
|
c@92
|
229 }
|
c@92
|
230 Wid /= 2;
|
c@92
|
231 ++wi;
|
c@92
|
232 }
|
c@92
|
233
|
c@92
|
234 int *spl = new int[WID/2];
|
c@92
|
235 double *spec = new double[WID/2];
|
c@92
|
236
|
c@92
|
237 // This prefill makes it easy to see which elements are actually
|
c@92
|
238 // set by the MixSpectrogramBlock2 call. Turns out that, with
|
c@92
|
239 // 1024, 2048 and 4096 as our widths, the spl array has elements
|
c@92
|
240 // 0-4094 (incl) filled in and the spec array has elements 0-4095
|
c@92
|
241
|
c@92
|
242 for (int i = 0; i < WID/2; ++i) {
|
c@92
|
243 spl[i] = i;
|
c@92
|
244 spec[i] = i;
|
c@92
|
245 }
|
c@92
|
246
|
c@92
|
247 MixSpectrogramBlock2(spl, spec, specs, WID/2, wid/2, false);
|
c@92
|
248
|
c@92
|
249 Wid = WID;
|
c@92
|
250 wi = 0;
|
c@92
|
251 while (Wid >= wid) {
|
c@92
|
252 for (int i = 0; i < WID/Wid; ++i) {
|
c@92
|
253 delete[] specs[wi][i];
|
c@92
|
254 }
|
c@92
|
255 delete[] specs[wi];
|
c@92
|
256 Wid /= 2;
|
c@92
|
257 ++wi;
|
c@92
|
258 }
|
c@92
|
259 delete[] specs;
|
c@92
|
260
|
c@92
|
261 std::cerr << "Results at " << ts << ":" << std::endl;
|
c@92
|
262 /* for (int i = 0; i < WID/2; ++i) {
|
c@92
|
263 if (spl[i] == i || spec[i] == i) {
|
c@92
|
264 std::cerr << "\n***\n";
|
c@92
|
265 }
|
c@92
|
266 std::cerr << "[" << i << "] " << spl[i] << "," << spec[i] << " ";
|
c@92
|
267 }
|
c@92
|
268 std::cerr << std::endl;
|
c@92
|
269 */
|
c@92
|
270 vector<vector<float> > rmat(WID/wid);
|
c@92
|
271 for (int i = 0; i < WID/wid; ++i) {
|
c@92
|
272 rmat[i] = vector<float>(WID/2);
|
c@92
|
273 }
|
c@92
|
274
|
c@92
|
275 int y = 0, h = WID/2;
|
c@92
|
276 int x = 0, w = WID/wid;
|
c@92
|
277 unpackResultMatrix(rmat, x, y, w, h, spl, spec, WID/2, WID);
|
c@92
|
278
|
c@92
|
279 delete[] spec;
|
c@92
|
280 delete[] spl;
|
c@92
|
281
|
c@92
|
282 for (int i = 0; i < rmat.size(); ++i) {
|
c@92
|
283 Feature f;
|
c@92
|
284 f.hasTimestamp = false;
|
c@92
|
285 f.values = rmat[i];
|
c@92
|
286 fs[0].push_back(f);
|
c@92
|
287 }
|
c@92
|
288
|
c@92
|
289 /*
|
c@92
|
290 if (m_stepSize == 0) {
|
c@92
|
291 cerr << "ERROR: AdaptiveSpectrogram::process: "
|
c@92
|
292 << "AdaptiveSpectrogram has not been initialised"
|
c@92
|
293 << endl;
|
c@92
|
294 return fs;
|
c@92
|
295 }
|
c@92
|
296 */
|
c@92
|
297 return fs;
|
c@92
|
298 }
|
c@92
|
299
|
c@92
|
300 void
|
c@92
|
301 AdaptiveSpectrogram::unpackResultMatrix(vector<vector<float> > &rmat,
|
c@92
|
302 int x, int y, int w, int h,
|
c@92
|
303 int *spl,
|
c@92
|
304 double *spec, int sz,
|
c@92
|
305 int res
|
c@92
|
306 )
|
c@92
|
307 {
|
c@92
|
308
|
c@92
|
309 cerr << "x = " << x << ", y = " << y << ", w = " << w << ", h = " << h
|
c@92
|
310 << ", sz = " << sz << ", *spl = " << *spl << ", *spec = " << *spec << ", res = " << res << endl;
|
c@92
|
311
|
c@92
|
312 if (sz <= 1) {
|
c@92
|
313
|
c@92
|
314 for (int i = 0; i < w; ++i) {
|
c@92
|
315 for (int j = 0; j < h; ++j) {
|
c@92
|
316 // rmat[x+i][y+j] = (off ? 0 : *spec);
|
c@92
|
317 if (rmat[x+i][y+j] != 0) {
|
c@92
|
318 cerr << "WARNING: Overwriting value " << rmat[x+i][y+j]
|
c@92
|
319 << " with " << res + i + j << " at " << x+i << "," << y+j << endl;
|
c@92
|
320 }
|
c@92
|
321 // cerr << "[" << x+i << "][" << y+j << "] <= " << res+i+j << endl;
|
c@92
|
322 rmat[x+i][y+j] = *spec;
|
c@92
|
323 }
|
c@92
|
324 }
|
c@92
|
325
|
c@92
|
326 // cerr << " (done)" << endl;
|
c@92
|
327 return;
|
c@92
|
328 }
|
c@92
|
329 // cerr << endl;
|
c@92
|
330
|
c@92
|
331 if (*spl == 0) {
|
c@92
|
332
|
c@92
|
333 unpackResultMatrix(rmat,
|
c@92
|
334 x, y,
|
c@92
|
335 w, h/2,
|
c@92
|
336 spl + 1,
|
c@92
|
337 spec,
|
c@92
|
338 sz/2,
|
c@92
|
339 res);
|
c@92
|
340
|
c@92
|
341 unpackResultMatrix(rmat,
|
c@92
|
342 x, y + h/2,
|
c@92
|
343 w, h/2,
|
c@92
|
344 spl + sz/2,
|
c@92
|
345 spec + sz/2,
|
c@92
|
346 sz/2,
|
c@92
|
347 res);
|
c@92
|
348
|
c@92
|
349 } else if (*spl == 1) {
|
c@92
|
350
|
c@92
|
351 unpackResultMatrix(rmat,
|
c@92
|
352 x, y,
|
c@92
|
353 w/2, h,
|
c@92
|
354 spl + 1,
|
c@92
|
355 spec,
|
c@92
|
356 sz/2,
|
c@92
|
357 res/2);
|
c@92
|
358
|
c@92
|
359 unpackResultMatrix(rmat,
|
c@92
|
360 x + w/2, y,
|
c@92
|
361 w/2, h,
|
c@92
|
362 spl + sz/2,
|
c@92
|
363 spec + sz/2,
|
c@92
|
364 sz/2,
|
c@92
|
365 res/2);
|
c@92
|
366
|
c@92
|
367 } else {
|
c@92
|
368 cerr << "ERROR: *spl = " << *spl << endl;
|
c@92
|
369 }
|
c@92
|
370 }
|
c@92
|
371
|
c@92
|
372 //spl[Y-1]
|
c@92
|
373 //Specs[R0][x0:x0+x-1][Y0:Y0+Y-1]
|
c@92
|
374 //Specs[R0+1][2x0:2x0+2x-1][Y0/2:Y0/2+Y/2-1]
|
c@92
|
375 //...
|
c@92
|
376 //Specs[R0+?][Nx0:Nx0+Nx-1][Y0/N:Y0/N+Y/N-1]
|
c@92
|
377 //N=WID/wid
|
c@92
|
378
|
c@92
|
379 /**
|
c@92
|
380 * DoCutSpectrogramBlock2 finds the optimal "cutting" and returns it in spl.
|
c@92
|
381 */
|
c@92
|
382 double
|
c@92
|
383 AdaptiveSpectrogram::DoCutSpectrogramBlock2(int* spl, double*** Specs, int Y, int R0,
|
c@92
|
384 int x0, int Y0, int N, double& ene)
|
c@92
|
385 {
|
c@92
|
386 double ent = 0;
|
c@92
|
387
|
c@92
|
388 if (Y > N) {
|
c@92
|
389
|
c@92
|
390 spl[0] = 0;
|
c@92
|
391 double ene1, ene2;
|
c@92
|
392
|
c@92
|
393 ent += DoCutSpectrogramBlock2
|
c@92
|
394 (&spl[1], Specs, Y/2, R0, x0, Y0, N, ene1);
|
c@92
|
395
|
c@92
|
396 ent += DoCutSpectrogramBlock2
|
c@92
|
397 (&spl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N, ene2);
|
c@92
|
398
|
c@92
|
399 ene = ene1+ene2;
|
c@92
|
400
|
c@92
|
401 } else if (N == 1) {
|
c@92
|
402
|
c@92
|
403 double tmp = Specs[R0][x0][Y0];
|
c@92
|
404 ene = tmp;
|
c@92
|
405 ent = xlogx(tmp);
|
c@92
|
406
|
c@92
|
407 } else {
|
c@92
|
408 // Y == N, the square case
|
c@92
|
409
|
c@92
|
410 double enel, ener, enet, eneb, entl, entr, entt, entb;
|
c@92
|
411 int* tmpspl = new int[Y];
|
c@92
|
412
|
c@92
|
413 entl = DoCutSpectrogramBlock2
|
c@92
|
414 (&spl[1], Specs, Y/2, R0+1, 2*x0, Y0/2, N/2, enel);
|
c@92
|
415
|
c@92
|
416 entr = DoCutSpectrogramBlock2
|
c@92
|
417 (&spl[Y/2], Specs, Y/2, R0+1, 2*x0+1, Y0/2, N/2, ener);
|
c@92
|
418
|
c@92
|
419 entb = DoCutSpectrogramBlock2
|
c@92
|
420 (&tmpspl[1], Specs, Y/2, R0, x0, Y0, N/2, eneb);
|
c@92
|
421
|
c@92
|
422 entt = DoCutSpectrogramBlock2
|
c@92
|
423 (&tmpspl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N/2, enet);
|
c@92
|
424
|
c@92
|
425 double
|
c@92
|
426 ene0 = enet + eneb,
|
c@92
|
427 ene1 = enel + ener,
|
c@92
|
428 ent0 = entt + entb,
|
c@92
|
429 ent1 = entl + entr;
|
c@92
|
430
|
c@92
|
431 // normalize
|
c@92
|
432
|
c@92
|
433 double eneres = 1 - (ene0+ene1)/2, norment0, norment1;
|
c@92
|
434 double a0 = 1 / (ene0+eneres), a1 = 1 / (ene1+eneres);
|
c@92
|
435
|
c@92
|
436 // quasi-global normalization
|
c@92
|
437
|
c@92
|
438 norment0 = (ent0 - ene0 * log(ene0+eneres)) / (ene0+eneres);
|
c@92
|
439 norment1 = (ent1 - ene1 * log(ene1+eneres)) / (ene1+eneres);
|
c@92
|
440
|
c@92
|
441 // local normalization
|
c@92
|
442
|
c@92
|
443 if (norment1 < norment0) {
|
c@92
|
444 spl[0] = 0;
|
c@92
|
445 ent = ent0, ene = ene0;
|
c@92
|
446 memcpy(&spl[1], &tmpspl[1], sizeof(int)*(Y-2));
|
c@92
|
447 } else {
|
c@92
|
448 spl[0] = 1;
|
c@92
|
449 ent = ent1, ene = ene1;
|
c@92
|
450 }
|
c@92
|
451 }
|
c@92
|
452 return ent;
|
c@92
|
453 }
|
c@92
|
454
|
c@92
|
455 /**
|
c@92
|
456 * DoMixSpectrogramBlock2 collects values from the multiple
|
c@92
|
457 * spectrograms Specs into a linear array Spec.
|
c@92
|
458 */
|
c@92
|
459 double
|
c@92
|
460 AdaptiveSpectrogram::DoMixSpectrogramBlock2(int* spl, double* Spec, double*** Specs, int Y,
|
c@92
|
461 int R0, int x0, int Y0, bool normmix, int res,
|
c@92
|
462 double* e)
|
c@92
|
463 {
|
c@92
|
464 if (Y == 1) {
|
c@92
|
465
|
c@92
|
466 Spec[0] = Specs[R0][x0][Y0]*e[0];
|
c@92
|
467
|
c@92
|
468 } else {
|
c@92
|
469
|
c@92
|
470 double le[32];
|
c@92
|
471
|
c@92
|
472 if (normmix && Y < (1<<res)) {
|
c@92
|
473
|
c@92
|
474 for (int i = 0, j = 1, k = Y;
|
c@92
|
475 i < res;
|
c@92
|
476 i++, j *= 2, k /= 2) {
|
c@92
|
477
|
c@92
|
478 double lle = 0;
|
c@92
|
479
|
c@92
|
480 for (int fr = 0; fr < j; fr++) {
|
c@92
|
481 for (int n = 0; n < k; n++) {
|
c@92
|
482 lle +=
|
c@92
|
483 Specs[i+R0][x0+fr][Y0+n] *
|
c@92
|
484 Specs[i+R0][x0+fr][Y0+n];
|
c@92
|
485 }
|
c@92
|
486 }
|
c@92
|
487
|
c@92
|
488 lle = sqrt(lle)*e[i];
|
c@92
|
489
|
c@92
|
490 if (i == 0) {
|
c@92
|
491 le[0] = lle;
|
c@92
|
492 } else if (lle > le[0]*2) {
|
c@92
|
493 le[i] = e[i]*le[0]*2/lle;
|
c@92
|
494 } else {
|
c@92
|
495 le[i] = e[i];
|
c@92
|
496 }
|
c@92
|
497 }
|
c@92
|
498
|
c@92
|
499 le[0] = e[0];
|
c@92
|
500
|
c@92
|
501 } else {
|
c@92
|
502
|
c@92
|
503 memcpy(le, e, sizeof(double)*res);
|
c@92
|
504 }
|
c@92
|
505
|
c@92
|
506 if (spl[0] == 0) {
|
c@92
|
507
|
c@92
|
508 int newres;
|
c@92
|
509 if (Y >= (1<<res)) newres = res;
|
c@92
|
510 else newres = res-1;
|
c@92
|
511
|
c@92
|
512 DoMixSpectrogramBlock2
|
c@92
|
513 (&spl[1], Spec, Specs, Y/2, R0, x0, Y0,
|
c@92
|
514 normmix, newres, le);
|
c@92
|
515
|
c@92
|
516 DoMixSpectrogramBlock2
|
c@92
|
517 (&spl[Y/2], &Spec[Y/2], Specs, Y/2, R0, x0, Y0+Y/2,
|
c@92
|
518 normmix, newres, le);
|
c@92
|
519
|
c@92
|
520 } else {
|
c@92
|
521
|
c@92
|
522 DoMixSpectrogramBlock2
|
c@92
|
523 (&spl[1], Spec, Specs, Y/2, R0+1, x0*2, Y0/2,
|
c@92
|
524 normmix, res-1, &le[1]);
|
c@92
|
525
|
c@92
|
526 DoMixSpectrogramBlock2
|
c@92
|
527 (&spl[Y/2], &Spec[Y/2], Specs, Y/2, R0+1, x0*2+1, Y0/2,
|
c@92
|
528 normmix, res-1, &le[1]);
|
c@92
|
529 }
|
c@92
|
530 }
|
c@92
|
531
|
c@92
|
532 return 0;
|
c@92
|
533 }
|
c@92
|
534
|
c@92
|
535 /**
|
c@92
|
536 * MixSpectrogramBlock2 calls the two Do...() to do the real work.
|
c@92
|
537 *
|
c@92
|
538 * At this point:
|
c@92
|
539 * spl is... what? the returned "cutting", organised how?
|
c@92
|
540 * Spec is... what? the returned spectrogram, organised how?
|
c@92
|
541 * Specs is an array of input spectrograms
|
c@92
|
542 * WID is the maximum window size
|
c@92
|
543 * wid is the minimum window size
|
c@92
|
544 * normmix is... what?
|
c@92
|
545 */
|
c@92
|
546 double
|
c@92
|
547 AdaptiveSpectrogram::MixSpectrogramBlock2(int* spl, double* Spec, double*** Specs, int
|
c@92
|
548 WID, int wid, bool normmix)
|
c@92
|
549 {
|
c@92
|
550 double ene[32];
|
c@92
|
551
|
c@92
|
552 // find the total energy and normalize
|
c@92
|
553
|
c@92
|
554 for (int i = 0, Fr = 1, Wid = WID; Wid >= wid; i++, Fr *= 2, Wid /= 2) {
|
c@92
|
555
|
c@92
|
556 double lene = 0;
|
c@92
|
557
|
c@92
|
558 for (int fr = 0; fr < Fr; fr++) {
|
c@92
|
559 for (int k = 0; k < Wid; k++) {
|
c@92
|
560 lene += Specs[i][fr][k]*Specs[i][fr][k];
|
c@92
|
561 }
|
c@92
|
562 }
|
c@92
|
563
|
c@92
|
564 ene[i] = lene;
|
c@92
|
565
|
c@92
|
566 if (lene != 0) {
|
c@92
|
567 double ilene = 1.0/lene;
|
c@92
|
568 for (int fr = 0; fr < Fr; fr++) {
|
c@92
|
569 for (int k = 0; k < Wid; k++) {
|
c@92
|
570 Specs[i][fr][k] = Specs[i][fr][k]*Specs[i][fr][k]*ilene;
|
c@92
|
571 }
|
c@92
|
572 }
|
c@92
|
573 }
|
c@92
|
574 }
|
c@92
|
575
|
c@92
|
576
|
c@92
|
577 double result = DoCutSpectrogramBlock2
|
c@92
|
578 (spl, Specs, WID, 0, 0, 0, WID/wid, ene[31]);
|
c@92
|
579
|
c@92
|
580 // de-normalize
|
c@92
|
581
|
c@92
|
582 for (int i = 0, Fr = 1, Wid = WID; Wid >= wid; i++, Fr *= 2, Wid /= 2) {
|
c@92
|
583 double lene = ene[i];
|
c@92
|
584 if (lene != 0) {
|
c@92
|
585 for (int fr = 0; fr < Fr; fr++) {
|
c@92
|
586 for (int k = 0; k < Wid; k++) {
|
c@92
|
587 Specs[i][fr][k] = sqrt(Specs[i][fr][k]*lene);
|
c@92
|
588 }
|
c@92
|
589 }
|
c@92
|
590 }
|
c@92
|
591 }
|
c@92
|
592
|
c@92
|
593 double e[32];
|
c@92
|
594 for (int i = 0; i < 32; i++) e[i] = 1;
|
c@92
|
595
|
c@92
|
596 DoMixSpectrogramBlock2
|
c@92
|
597 (spl, Spec, Specs, WID, 0, 0, 0, normmix, log2(WID/wid)+1, e);
|
c@92
|
598
|
c@92
|
599 return result;
|
c@92
|
600 }
|
c@92
|
601
|
c@92
|
602 /**
|
c@92
|
603 * MixSpectrogram2 does the work for Fr frames (the largest frame),
|
c@92
|
604 * which basically calls MixSpectrogramBlock2 Fr times.
|
c@92
|
605 *
|
c@92
|
606 * the 3-D array Specs is the multiple spectrograms calculated with
|
c@92
|
607 * window sizes between wid and WID, Specs[0] is the 0th spectrogram,
|
c@92
|
608 * etc.
|
c@92
|
609 *
|
c@92
|
610 * spl and Spec for all frames are returned by MixSpectrogram2, each
|
c@92
|
611 * as a 2-D array.
|
c@92
|
612 */
|
c@92
|
613 double
|
c@92
|
614 AdaptiveSpectrogram::MixSpectrogram2(int** spl, double** Spec, double*** Specs, int Fr,
|
c@92
|
615 int WID, int wid, bool norm, bool normmix)
|
c@92
|
616 {
|
c@92
|
617 // totally Fr frames of WID samples
|
c@92
|
618 // each frame is divided into wid VERTICAL parts
|
c@92
|
619
|
c@92
|
620 int Res = log2(WID/wid)+1;
|
c@92
|
621 double*** lSpecs = new double**[Res];
|
c@92
|
622
|
c@92
|
623 for (int i = 0; i < Fr; i++) {
|
c@92
|
624
|
c@92
|
625 for (int j = 0, nfr = 1; j < Res; j++, nfr *= 2) {
|
c@92
|
626 lSpecs[j] = &Specs[j][i*nfr];
|
c@92
|
627 }
|
c@92
|
628
|
c@92
|
629 MixSpectrogramBlock2(spl[i], Spec[i], lSpecs, WID, wid, norm);
|
c@92
|
630 }
|
c@92
|
631
|
c@92
|
632 delete[] lSpecs;
|
c@92
|
633 return 0;
|
c@92
|
634 }
|
c@92
|
635
|