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 #include "AdaptiveSpectrogram.h"
|
c@92
|
16
|
c@92
|
17 #include <cstdlib>
|
c@133
|
18 #include <cstdio>
|
c@92
|
19 #include <cstring>
|
c@114
|
20 #include <cfloat>
|
c@92
|
21
|
c@92
|
22 #include <iostream>
|
c@92
|
23
|
c@92
|
24 #include <dsp/transforms/FFT.h>
|
c@92
|
25
|
c@92
|
26 using std::string;
|
c@92
|
27 using std::vector;
|
c@92
|
28 using std::cerr;
|
c@92
|
29 using std::endl;
|
c@92
|
30
|
c@92
|
31 using Vamp::RealTime;
|
c@92
|
32
|
c@99
|
33 //#define DEBUG_VERBOSE 1
|
c@99
|
34
|
c@92
|
35 AdaptiveSpectrogram::AdaptiveSpectrogram(float inputSampleRate) :
|
c@92
|
36 Plugin(inputSampleRate),
|
c@104
|
37 m_w(8),
|
c@114
|
38 m_n(2),
|
c@114
|
39 m_coarse(false),
|
c@109
|
40 m_threaded(true),
|
c@109
|
41 m_threadsInUse(false)
|
c@92
|
42 {
|
c@92
|
43 }
|
c@92
|
44
|
c@92
|
45 AdaptiveSpectrogram::~AdaptiveSpectrogram()
|
c@92
|
46 {
|
c@104
|
47 for (int i = 0; i < m_cutThreads.size(); ++i) {
|
c@104
|
48 delete m_cutThreads[i];
|
c@104
|
49 }
|
c@104
|
50 m_cutThreads.clear();
|
c@105
|
51
|
c@110
|
52 for (FFTMap::iterator i = m_fftThreads.begin();
|
c@110
|
53 i != m_fftThreads.end(); ++i) {
|
c@106
|
54 delete i->second;
|
c@105
|
55 }
|
c@105
|
56 m_fftThreads.clear();
|
c@92
|
57 }
|
c@92
|
58
|
c@92
|
59 string
|
c@92
|
60 AdaptiveSpectrogram::getIdentifier() const
|
c@92
|
61 {
|
c@93
|
62 return "qm-adaptivespectrogram";
|
c@92
|
63 }
|
c@92
|
64
|
c@92
|
65 string
|
c@92
|
66 AdaptiveSpectrogram::getName() const
|
c@92
|
67 {
|
c@92
|
68 return "Adaptive Spectrogram";
|
c@92
|
69 }
|
c@92
|
70
|
c@92
|
71 string
|
c@92
|
72 AdaptiveSpectrogram::getDescription() const
|
c@92
|
73 {
|
c@92
|
74 return "Produce an adaptive spectrogram by adaptive selection from spectrograms at multiple resolutions";
|
c@92
|
75 }
|
c@92
|
76
|
c@92
|
77 string
|
c@92
|
78 AdaptiveSpectrogram::getMaker() const
|
c@92
|
79 {
|
c@92
|
80 return "Queen Mary, University of London";
|
c@92
|
81 }
|
c@92
|
82
|
c@92
|
83 int
|
c@92
|
84 AdaptiveSpectrogram::getPluginVersion() const
|
c@92
|
85 {
|
c@92
|
86 return 1;
|
c@92
|
87 }
|
c@92
|
88
|
c@92
|
89 string
|
c@92
|
90 AdaptiveSpectrogram::getCopyright() const
|
c@92
|
91 {
|
c@92
|
92 return "Plugin by Wen Xue and Chris Cannam. Copyright (c) 2009 Wen Xue and QMUL - All Rights Reserved";
|
c@92
|
93 }
|
c@92
|
94
|
c@92
|
95 size_t
|
c@92
|
96 AdaptiveSpectrogram::getPreferredStepSize() const
|
c@92
|
97 {
|
c@92
|
98 return ((2 << m_w) << m_n) / 2;
|
c@92
|
99 }
|
c@92
|
100
|
c@92
|
101 size_t
|
c@92
|
102 AdaptiveSpectrogram::getPreferredBlockSize() const
|
c@92
|
103 {
|
c@92
|
104 return (2 << m_w) << m_n;
|
c@92
|
105 }
|
c@92
|
106
|
c@92
|
107 bool
|
c@92
|
108 AdaptiveSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
c@92
|
109 {
|
c@92
|
110 if (channels < getMinChannelCount() ||
|
c@92
|
111 channels > getMaxChannelCount()) return false;
|
c@92
|
112
|
c@92
|
113 return true;
|
c@92
|
114 }
|
c@92
|
115
|
c@92
|
116 void
|
c@92
|
117 AdaptiveSpectrogram::reset()
|
c@92
|
118 {
|
c@92
|
119
|
c@92
|
120 }
|
c@92
|
121
|
c@92
|
122 AdaptiveSpectrogram::ParameterList
|
c@92
|
123 AdaptiveSpectrogram::getParameterDescriptors() const
|
c@92
|
124 {
|
c@92
|
125 ParameterList list;
|
c@92
|
126
|
c@92
|
127 ParameterDescriptor desc;
|
c@92
|
128 desc.identifier = "n";
|
c@92
|
129 desc.name = "Number of resolutions";
|
c@114
|
130 desc.description = "Number of consecutive powers of two in the range to be used as spectrogram resolutions, starting with the minimum resolution specified";
|
c@92
|
131 desc.unit = "";
|
c@114
|
132 desc.minValue = 2;
|
c@92
|
133 desc.maxValue = 10;
|
c@114
|
134 desc.defaultValue = 3;
|
c@92
|
135 desc.isQuantized = true;
|
c@92
|
136 desc.quantizeStep = 1;
|
c@92
|
137 list.push_back(desc);
|
c@92
|
138
|
c@92
|
139 ParameterDescriptor desc2;
|
c@92
|
140 desc2.identifier = "w";
|
c@92
|
141 desc2.name = "Smallest resolution";
|
c@92
|
142 desc2.description = "Smallest of the consecutive powers of two to use as spectrogram resolutions";
|
c@92
|
143 desc2.unit = "";
|
c@92
|
144 desc2.minValue = 1;
|
c@92
|
145 desc2.maxValue = 14;
|
c@104
|
146 desc2.defaultValue = 9;
|
c@92
|
147 desc2.isQuantized = true;
|
c@92
|
148 desc2.quantizeStep = 1;
|
c@92
|
149 // I am so lazy
|
c@92
|
150 desc2.valueNames.push_back("2");
|
c@92
|
151 desc2.valueNames.push_back("4");
|
c@92
|
152 desc2.valueNames.push_back("8");
|
c@92
|
153 desc2.valueNames.push_back("16");
|
c@92
|
154 desc2.valueNames.push_back("32");
|
c@92
|
155 desc2.valueNames.push_back("64");
|
c@92
|
156 desc2.valueNames.push_back("128");
|
c@92
|
157 desc2.valueNames.push_back("256");
|
c@92
|
158 desc2.valueNames.push_back("512");
|
c@92
|
159 desc2.valueNames.push_back("1024");
|
c@92
|
160 desc2.valueNames.push_back("2048");
|
c@92
|
161 desc2.valueNames.push_back("4096");
|
c@92
|
162 desc2.valueNames.push_back("8192");
|
c@92
|
163 desc2.valueNames.push_back("16384");
|
c@92
|
164 list.push_back(desc2);
|
c@92
|
165
|
c@109
|
166 ParameterDescriptor desc3;
|
c@114
|
167 desc3.identifier = "coarse";
|
c@114
|
168 desc3.name = "Omit alternate resolutions";
|
c@114
|
169 desc3.description = "Generate a coarser spectrogram faster by excluding every alternate resolution (first and last resolution are always retained)";
|
c@114
|
170 desc3.unit = "";
|
c@114
|
171 desc3.minValue = 0;
|
c@114
|
172 desc3.maxValue = 1;
|
c@114
|
173 desc3.defaultValue = 0;
|
c@114
|
174 desc3.isQuantized = true;
|
c@114
|
175 desc3.quantizeStep = 1;
|
c@114
|
176 list.push_back(desc3);
|
c@114
|
177
|
c@109
|
178 desc3.identifier = "threaded";
|
c@109
|
179 desc3.name = "Multi-threaded processing";
|
c@110
|
180 desc3.description = "Perform calculations using several threads in parallel";
|
c@109
|
181 desc3.unit = "";
|
c@109
|
182 desc3.minValue = 0;
|
c@109
|
183 desc3.maxValue = 1;
|
c@109
|
184 desc3.defaultValue = 1;
|
c@109
|
185 desc3.isQuantized = true;
|
c@109
|
186 desc3.quantizeStep = 1;
|
c@109
|
187 list.push_back(desc3);
|
c@109
|
188
|
c@92
|
189 return list;
|
c@92
|
190 }
|
c@92
|
191
|
c@92
|
192 float
|
c@92
|
193 AdaptiveSpectrogram::getParameter(std::string id) const
|
c@92
|
194 {
|
c@92
|
195 if (id == "n") return m_n+1;
|
c@92
|
196 else if (id == "w") return m_w+1;
|
c@109
|
197 else if (id == "threaded") return (m_threaded ? 1 : 0);
|
c@114
|
198 else if (id == "coarse") return (m_coarse ? 1 : 0);
|
c@92
|
199 return 0.f;
|
c@92
|
200 }
|
c@92
|
201
|
c@92
|
202 void
|
c@92
|
203 AdaptiveSpectrogram::setParameter(std::string id, float value)
|
c@92
|
204 {
|
c@92
|
205 if (id == "n") {
|
c@92
|
206 int n = lrintf(value);
|
c@92
|
207 if (n >= 1 && n <= 10) m_n = n-1;
|
c@92
|
208 } else if (id == "w") {
|
c@92
|
209 int w = lrintf(value);
|
c@92
|
210 if (w >= 1 && w <= 14) m_w = w-1;
|
c@109
|
211 } else if (id == "threaded") {
|
c@109
|
212 m_threaded = (value > 0.5);
|
c@114
|
213 } else if (id == "coarse") {
|
c@114
|
214 m_coarse = (value > 0.5);
|
c@109
|
215 }
|
c@92
|
216 }
|
c@92
|
217
|
c@92
|
218 AdaptiveSpectrogram::OutputList
|
c@92
|
219 AdaptiveSpectrogram::getOutputDescriptors() const
|
c@92
|
220 {
|
c@92
|
221 OutputList list;
|
c@92
|
222
|
c@92
|
223 OutputDescriptor d;
|
c@92
|
224 d.identifier = "output";
|
c@92
|
225 d.name = "Output";
|
c@92
|
226 d.description = "The output of the plugin";
|
c@92
|
227 d.unit = "";
|
c@92
|
228 d.hasFixedBinCount = true;
|
c@114
|
229 d.binCount = getPreferredBlockSize() / 2;
|
c@92
|
230 d.hasKnownExtents = false;
|
c@92
|
231 d.isQuantized = false;
|
c@92
|
232 d.sampleType = OutputDescriptor::FixedSampleRate;
|
c@92
|
233 d.sampleRate = m_inputSampleRate / ((2 << m_w) / 2);
|
c@92
|
234 d.hasDuration = false;
|
c@112
|
235 char name[20];
|
c@112
|
236 for (int i = 0; i < d.binCount; ++i) {
|
c@114
|
237 float freq = (m_inputSampleRate / (d.binCount * 2)) * (i + 1); // no DC bin
|
c@112
|
238 sprintf(name, "%d Hz", int(freq));
|
c@112
|
239 d.binNames.push_back(name);
|
c@112
|
240 }
|
c@92
|
241 list.push_back(d);
|
c@92
|
242
|
c@92
|
243 return list;
|
c@92
|
244 }
|
c@92
|
245
|
c@92
|
246 AdaptiveSpectrogram::FeatureSet
|
c@92
|
247 AdaptiveSpectrogram::getRemainingFeatures()
|
c@92
|
248 {
|
c@92
|
249 FeatureSet fs;
|
c@92
|
250 return fs;
|
c@92
|
251 }
|
c@92
|
252
|
c@100
|
253 AdaptiveSpectrogram::FeatureSet
|
c@100
|
254 AdaptiveSpectrogram::process(const float *const *inputBuffers, RealTime ts)
|
c@100
|
255 {
|
c@100
|
256 FeatureSet fs;
|
c@100
|
257
|
c@100
|
258 int minwid = (2 << m_w), maxwid = ((2 << m_w) << m_n);
|
c@100
|
259
|
c@101
|
260 #ifdef DEBUG_VERBOSE
|
c@100
|
261 cerr << "widths from " << minwid << " to " << maxwid << " ("
|
c@100
|
262 << minwid/2 << " to " << maxwid/2 << " in real parts)" << endl;
|
c@101
|
263 #endif
|
c@100
|
264
|
c@100
|
265 Spectrograms s(minwid/2, maxwid/2, 1);
|
c@100
|
266
|
c@100
|
267 int w = minwid;
|
c@100
|
268 int index = 0;
|
c@100
|
269
|
c@100
|
270 while (w <= maxwid) {
|
c@114
|
271
|
c@114
|
272 if (!isResolutionWanted(s, w/2)) {
|
c@114
|
273 w *= 2;
|
c@114
|
274 ++index;
|
c@114
|
275 continue;
|
c@114
|
276 }
|
c@114
|
277
|
c@106
|
278 if (m_fftThreads.find(w) == m_fftThreads.end()) {
|
c@106
|
279 m_fftThreads[w] = new FFTThread(w);
|
c@106
|
280 }
|
c@109
|
281 if (m_threaded) {
|
c@114
|
282 m_fftThreads[w]->startCalculation
|
c@114
|
283 (inputBuffers[0], s, index, maxwid);
|
c@109
|
284 } else {
|
c@114
|
285 m_fftThreads[w]->setParameters
|
c@114
|
286 (inputBuffers[0], s, index, maxwid);
|
c@109
|
287 m_fftThreads[w]->performTask();
|
c@109
|
288 }
|
c@100
|
289 w *= 2;
|
c@100
|
290 ++index;
|
c@100
|
291 }
|
c@100
|
292
|
c@109
|
293 if (m_threaded) {
|
c@109
|
294 w = minwid;
|
c@114
|
295 index = 0;
|
c@109
|
296 while (w <= maxwid) {
|
c@114
|
297 if (!isResolutionWanted(s, w/2)) {
|
c@114
|
298 w *= 2;
|
c@114
|
299 ++index;
|
c@114
|
300 continue;
|
c@114
|
301 }
|
c@109
|
302 m_fftThreads[w]->await();
|
c@109
|
303 w *= 2;
|
c@114
|
304 ++index;
|
c@109
|
305 }
|
c@105
|
306 }
|
c@102
|
307
|
c@109
|
308 m_threadsInUse = false;
|
c@104
|
309
|
c@114
|
310 // std::cerr << "maxwid/2 = " << maxwid/2 << ", minwid/2 = " << minwid/2 << ", n+1 = " << m_n+1 << ", 2^(n+1) = " << (2<<m_n) << std::endl;
|
c@110
|
311
|
c@114
|
312 int cutwid = maxwid/2;
|
c@114
|
313 Cutting *cutting = cut(s, cutwid, 0, 0, cutwid, 0);
|
c@100
|
314
|
c@101
|
315 #ifdef DEBUG_VERBOSE
|
c@100
|
316 printCutting(cutting, " ");
|
c@101
|
317 #endif
|
c@100
|
318
|
c@100
|
319 vector<vector<float> > rmat(maxwid/minwid);
|
c@100
|
320 for (int i = 0; i < maxwid/minwid; ++i) {
|
c@100
|
321 rmat[i] = vector<float>(maxwid/2);
|
c@100
|
322 }
|
c@100
|
323
|
c@114
|
324 assemble(s, cutting, rmat, 0, 0, maxwid/minwid, cutwid);
|
c@100
|
325
|
c@110
|
326 cutting->erase();
|
c@100
|
327
|
c@100
|
328 for (int i = 0; i < rmat.size(); ++i) {
|
c@100
|
329 Feature f;
|
c@100
|
330 f.hasTimestamp = false;
|
c@100
|
331 f.values = rmat[i];
|
c@100
|
332 fs[0].push_back(f);
|
c@100
|
333 }
|
c@100
|
334
|
c@104
|
335 // std::cerr << "process returning!\n" << std::endl;
|
c@104
|
336
|
c@100
|
337 return fs;
|
c@100
|
338 }
|
c@100
|
339
|
c@100
|
340 void
|
c@104
|
341 AdaptiveSpectrogram::printCutting(Cutting *c, string pfx) const
|
c@100
|
342 {
|
c@100
|
343 if (c->first) {
|
c@100
|
344 if (c->cut == Cutting::Horizontal) {
|
c@100
|
345 cerr << pfx << "H" << endl;
|
c@100
|
346 } else if (c->cut == Cutting::Vertical) {
|
c@100
|
347 cerr << pfx << "V" << endl;
|
c@100
|
348 }
|
c@100
|
349 printCutting(c->first, pfx + " ");
|
c@100
|
350 printCutting(c->second, pfx + " ");
|
c@100
|
351 } else {
|
c@100
|
352 cerr << pfx << "* " << c->value << endl;
|
c@100
|
353 }
|
c@100
|
354 }
|
c@100
|
355
|
c@104
|
356 void
|
c@104
|
357 AdaptiveSpectrogram::getSubCuts(const Spectrograms &s,
|
c@104
|
358 int res,
|
c@104
|
359 int x, int y, int h,
|
c@114
|
360 Cutting **top, Cutting **bottom,
|
c@114
|
361 Cutting **left, Cutting **right,
|
c@113
|
362 BlockAllocator *allocator) const
|
c@104
|
363 {
|
c@109
|
364 if (m_threaded && !m_threadsInUse) {
|
c@104
|
365
|
c@109
|
366 m_threadsInUse = true;
|
c@104
|
367
|
c@104
|
368 if (m_cutThreads.empty()) {
|
c@104
|
369 for (int i = 0; i < 4; ++i) {
|
c@104
|
370 CutThread *t = new CutThread(this);
|
c@104
|
371 m_cutThreads.push_back(t);
|
c@104
|
372 }
|
c@104
|
373 }
|
c@104
|
374
|
c@109
|
375 // Cut threads 0 and 1 calculate the top and bottom halves;
|
c@110
|
376 // threads 2 and 3 calculate left and right. See notes in
|
c@110
|
377 // unthreaded code below for more information.
|
c@104
|
378
|
c@114
|
379 if (top) m_cutThreads[0]->cut(s, res, x, y + h/2, h/2);
|
c@114
|
380 if (bottom) m_cutThreads[1]->cut(s, res, x, y, h/2);
|
c@104
|
381
|
c@114
|
382 if (left) m_cutThreads[2]->cut(s, res/2, 2 * x, y/2, h/2);
|
c@114
|
383 if (right) m_cutThreads[3]->cut(s, res/2, 2 * x + 1, y/2, h/2);
|
c@114
|
384
|
c@114
|
385 if (top) *top = m_cutThreads[0]->get();
|
c@114
|
386 if (bottom) *bottom = m_cutThreads[1]->get();
|
c@114
|
387 if (left) *left = m_cutThreads[2]->get();
|
c@114
|
388 if (right) *right = m_cutThreads[3]->get();
|
c@104
|
389
|
c@104
|
390 } else {
|
c@104
|
391
|
c@110
|
392 // Unthreaded version
|
c@104
|
393
|
c@104
|
394 // The "vertical" division is a top/bottom split.
|
c@104
|
395 // Splitting this way keeps us in the same resolution,
|
c@104
|
396 // but with two vertical subregions of height h/2.
|
c@104
|
397
|
c@114
|
398 if (top) *top = cut(s, res, x, y + h/2, h/2, allocator);
|
c@114
|
399 if (bottom) *bottom = cut(s, res, x, y, h/2, allocator);
|
c@104
|
400
|
c@104
|
401 // The "horizontal" division is a left/right split. Splitting
|
c@104
|
402 // this way places us in resolution res/2, which has lower
|
c@104
|
403 // vertical resolution but higher horizontal resolution. We
|
c@104
|
404 // need to double x accordingly.
|
c@104
|
405
|
c@114
|
406 if (left) *left = cut(s, res/2, 2 * x, y/2, h/2, allocator);
|
c@114
|
407 if (right) *right = cut(s, res/2, 2 * x + 1, y/2, h/2, allocator);
|
c@104
|
408 }
|
c@104
|
409 }
|
c@104
|
410
|
c@100
|
411 AdaptiveSpectrogram::Cutting *
|
c@100
|
412 AdaptiveSpectrogram::cut(const Spectrograms &s,
|
c@100
|
413 int res,
|
c@110
|
414 int x, int y, int h,
|
c@110
|
415 BlockAllocator *allocator) const
|
c@100
|
416 {
|
c@100
|
417 // cerr << "res = " << res << ", x = " << x << ", y = " << y << ", h = " << h << endl;
|
c@100
|
418
|
c@110
|
419 Cutting *cutting;
|
c@110
|
420 if (allocator) {
|
c@110
|
421 cutting = (Cutting *)(allocator->allocate());
|
c@110
|
422 cutting->allocator = allocator;
|
c@110
|
423 } else {
|
c@110
|
424 cutting = new Cutting;
|
c@110
|
425 cutting->allocator = 0;
|
c@110
|
426 }
|
c@110
|
427
|
c@100
|
428 if (h > 1 && res > s.minres) {
|
c@100
|
429
|
c@114
|
430 if (!isResolutionWanted(s, res)) {
|
c@100
|
431
|
c@114
|
432 Cutting *left = 0, *right = 0;
|
c@114
|
433 getSubCuts(s, res, x, y, h, 0, 0, &left, &right, allocator);
|
c@114
|
434
|
c@114
|
435 double hcost = left->cost + right->cost;
|
c@101
|
436 double henergy = left->value + right->value;
|
c@114
|
437 hcost = normalize(hcost, henergy);
|
c@114
|
438
|
c@100
|
439 cutting->cut = Cutting::Horizontal;
|
c@100
|
440 cutting->first = left;
|
c@100
|
441 cutting->second = right;
|
c@100
|
442 cutting->cost = hcost;
|
c@111
|
443 cutting->value = left->value + right->value;
|
c@100
|
444
|
c@114
|
445 } else if (h == 2 && !isResolutionWanted(s, res/2)) {
|
c@100
|
446
|
c@114
|
447 Cutting *top = 0, *bottom = 0;
|
c@114
|
448 getSubCuts(s, res, x, y, h, &top, &bottom, 0, 0, allocator);
|
c@114
|
449
|
c@114
|
450 double vcost = top->cost + bottom->cost;
|
c@114
|
451 double venergy = top->value + bottom->value;
|
c@114
|
452 vcost = normalize(vcost, venergy);
|
c@114
|
453
|
c@100
|
454 cutting->cut = Cutting::Vertical;
|
c@100
|
455 cutting->first = top;
|
c@100
|
456 cutting->second = bottom;
|
c@100
|
457 cutting->cost = vcost;
|
c@111
|
458 cutting->value = top->value + bottom->value;
|
c@114
|
459
|
c@114
|
460 } else {
|
c@114
|
461
|
c@114
|
462 Cutting *top = 0, *bottom = 0, *left = 0, *right = 0;
|
c@114
|
463 getSubCuts(s, res, x, y, h, &top, &bottom, &left, &right, allocator);
|
c@114
|
464
|
c@114
|
465 double vcost = top->cost + bottom->cost;
|
c@114
|
466 double venergy = top->value + bottom->value;
|
c@114
|
467 vcost = normalize(vcost, venergy);
|
c@114
|
468
|
c@114
|
469 double hcost = left->cost + right->cost;
|
c@114
|
470 double henergy = left->value + right->value;
|
c@114
|
471 hcost = normalize(hcost, henergy);
|
c@114
|
472
|
c@114
|
473 if (vcost > hcost) {
|
c@114
|
474 cutting->cut = Cutting::Horizontal;
|
c@114
|
475 cutting->first = left;
|
c@114
|
476 cutting->second = right;
|
c@114
|
477 cutting->cost = hcost;
|
c@114
|
478 cutting->value = left->value + right->value;
|
c@114
|
479 top->erase();
|
c@114
|
480 bottom->erase();
|
c@114
|
481 return cutting;
|
c@114
|
482 } else {
|
c@114
|
483 cutting->cut = Cutting::Vertical;
|
c@114
|
484 cutting->first = top;
|
c@114
|
485 cutting->second = bottom;
|
c@114
|
486 cutting->cost = vcost;
|
c@114
|
487 cutting->value = top->value + bottom->value;
|
c@114
|
488 left->erase();
|
c@114
|
489 right->erase();
|
c@114
|
490 return cutting;
|
c@114
|
491 }
|
c@100
|
492 }
|
c@100
|
493
|
c@100
|
494 } else {
|
c@100
|
495
|
c@100
|
496 // no cuts possible from this level
|
c@100
|
497
|
c@100
|
498 cutting->cut = Cutting::Finished;
|
c@100
|
499 cutting->first = 0;
|
c@100
|
500 cutting->second = 0;
|
c@100
|
501
|
c@100
|
502 int n = 0;
|
c@114
|
503 for (int r = res; r > s.minres; r >>= 1) ++n;
|
c@100
|
504 const Spectrogram *spectrogram = s.spectrograms[n];
|
c@100
|
505 cutting->cost = cost(*spectrogram, x, y);
|
c@100
|
506 cutting->value = value(*spectrogram, x, y);
|
c@114
|
507 }
|
c@100
|
508
|
c@114
|
509 return cutting;
|
c@100
|
510 }
|
c@100
|
511
|
c@100
|
512 void
|
c@100
|
513 AdaptiveSpectrogram::assemble(const Spectrograms &s,
|
c@100
|
514 const Cutting *cutting,
|
c@100
|
515 vector<vector<float> > &rmat,
|
c@104
|
516 int x, int y, int w, int h) const
|
c@100
|
517 {
|
c@100
|
518 switch (cutting->cut) {
|
c@100
|
519
|
c@100
|
520 case Cutting::Finished:
|
c@100
|
521 for (int i = 0; i < w; ++i) {
|
c@100
|
522 for (int j = 0; j < h; ++j) {
|
c@114
|
523 rmat[x+i][y+j] = cutting->value;
|
c@100
|
524 }
|
c@100
|
525 }
|
c@100
|
526 return;
|
c@100
|
527
|
c@100
|
528 case Cutting::Horizontal:
|
c@100
|
529 assemble(s, cutting->first, rmat, x, y, w/2, h);
|
c@100
|
530 assemble(s, cutting->second, rmat, x+w/2, y, w/2, h);
|
c@100
|
531 break;
|
c@100
|
532
|
c@100
|
533 case Cutting::Vertical:
|
c@100
|
534 assemble(s, cutting->first, rmat, x, y+h/2, w, h/2);
|
c@100
|
535 assemble(s, cutting->second, rmat, x, y, w, h/2);
|
c@100
|
536 break;
|
c@100
|
537 }
|
c@100
|
538 }
|
c@100
|
539
|