comparison layer/SpectrogramLayer.cpp @ 1324:13d9b422f7fe zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:31 +0100
parents 6e724c81f18f
children d79e21855aef
comparison
equal deleted inserted replaced
1183:57d192e26331 1324:13d9b422f7fe
23 #include "base/Preferences.h" 23 #include "base/Preferences.h"
24 #include "base/RangeMapper.h" 24 #include "base/RangeMapper.h"
25 #include "base/LogRange.h" 25 #include "base/LogRange.h"
26 #include "base/ColumnOp.h" 26 #include "base/ColumnOp.h"
27 #include "base/Strings.h" 27 #include "base/Strings.h"
28 #include "base/StorageAdviser.h"
29 #include "base/Exceptions.h"
28 #include "widgets/CommandHistory.h" 30 #include "widgets/CommandHistory.h"
29 #include "data/model/Dense3DModelPeakCache.h" 31 #include "data/model/Dense3DModelPeakCache.h"
30 32
31 #include "ColourMapper.h" 33 #include "ColourMapper.h"
32 #include "PianoScale.h" 34 #include "PianoScale.h"
78 m_lastEmittedZoomStep(-1), 80 m_lastEmittedZoomStep(-1),
79 m_synchronous(false), 81 m_synchronous(false),
80 m_haveDetailedScale(false), 82 m_haveDetailedScale(false),
81 m_exiting(false), 83 m_exiting(false),
82 m_fftModel(0), 84 m_fftModel(0),
85 m_wholeCache(0),
83 m_peakCache(0), 86 m_peakCache(0),
84 m_peakCacheDivisor(8) 87 m_peakCacheDivisor(8)
85 { 88 {
86 QString colourConfigName = "spectrogram-colour"; 89 QString colourConfigName = "spectrogram-colour";
87 int colourConfigDefault = int(ColourMapper::Green); 90 int colourConfigDefault = int(ColourMapper::Green);
88 91
89 if (config == FullRangeDb) { 92 if (config == FullRangeDb) {
90 m_initialMaxFrequency = 0; 93 m_initialMaxFrequency = 0;
91 setMaxFrequency(0); 94 setMaxFrequency(0);
92 } else if (config == MelodicRange) { 95 } else if (config == MelodicRange) {
93 setWindowSize(8192); 96 setWindowSize(8192);
94 setWindowHopLevel(4); 97 setWindowHopLevel(4);
95 m_initialMaxFrequency = 1500; 98 m_initialMaxFrequency = 1500;
96 setMaxFrequency(1500); 99 setMaxFrequency(1500);
97 setMinFrequency(40); 100 setMinFrequency(40);
98 setColourScale(ColourScaleType::Linear); 101 setColourScale(ColourScaleType::Linear);
99 setColourMap(ColourMapper::Sunset); 102 setColourMap(ColourMapper::Sunset);
100 setBinScale(BinScale::Log); 103 setBinScale(BinScale::Log);
101 colourConfigName = "spectrogram-melodic-colour"; 104 colourConfigName = "spectrogram-melodic-colour";
102 colourConfigDefault = int(ColourMapper::Sunset); 105 colourConfigDefault = int(ColourMapper::Sunset);
103 // setGain(20); 106 // setGain(20);
104 } else if (config == MelodicPeaks) { 107 } else if (config == MelodicPeaks) {
105 setWindowSize(4096); 108 setWindowSize(4096);
106 setWindowHopLevel(5); 109 setWindowHopLevel(5);
107 m_initialMaxFrequency = 2000; 110 m_initialMaxFrequency = 2000;
108 setMaxFrequency(2000); 111 setMaxFrequency(2000);
109 setMinFrequency(40); 112 setMinFrequency(40);
110 setBinScale(BinScale::Log); 113 setBinScale(BinScale::Log);
111 setColourScale(ColourScaleType::Linear); 114 setColourScale(ColourScaleType::Linear);
112 setBinDisplay(BinDisplay::PeakFrequencies); 115 setBinDisplay(BinDisplay::PeakFrequencies);
113 setNormalization(ColumnNormalization::Max1); 116 setNormalization(ColumnNormalization::Max1);
114 colourConfigName = "spectrogram-melodic-colour"; 117 colourConfigName = "spectrogram-melodic-colour";
115 colourConfigDefault = int(ColourMapper::Sunset); 118 colourConfigDefault = int(ColourMapper::Sunset);
116 } 119 }
117 120
127 } 130 }
128 131
129 SpectrogramLayer::~SpectrogramLayer() 132 SpectrogramLayer::~SpectrogramLayer()
130 { 133 {
131 invalidateRenderers(); 134 invalidateRenderers();
132 invalidateFFTModel(); 135 deleteDerivedModels();
136 }
137
138 void
139 SpectrogramLayer::deleteDerivedModels()
140 {
141 if (m_fftModel) m_fftModel->aboutToDelete();
142 if (m_peakCache) m_peakCache->aboutToDelete();
143 if (m_wholeCache) m_wholeCache->aboutToDelete();
144
145 delete m_fftModel;
146 delete m_peakCache;
147 delete m_wholeCache;
148
149 m_fftModel = 0;
150 m_peakCache = 0;
151 m_wholeCache = 0;
133 } 152 }
134 153
135 pair<ColourScaleType, double> 154 pair<ColourScaleType, double>
136 SpectrogramLayer::convertToColourScale(int value) 155 SpectrogramLayer::convertToColourScale(int value)
137 { 156 {
179 case ColumnNormalization::None: return 0; 198 case ColumnNormalization::None: return 0;
180 case ColumnNormalization::Max1: return 1; 199 case ColumnNormalization::Max1: return 1;
181 case ColumnNormalization::Hybrid: return 3; 200 case ColumnNormalization::Hybrid: return 3;
182 201
183 case ColumnNormalization::Sum1: 202 case ColumnNormalization::Sum1:
203 case ColumnNormalization::Range01:
184 default: return 0; 204 default: return 0;
185 } 205 }
186 } 206 }
187 207
188 void 208 void
191 // cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << endl; 211 // cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << endl;
192 212
193 if (model == m_model) return; 213 if (model == m_model) return;
194 214
195 m_model = model; 215 m_model = model;
196 invalidateFFTModel(); 216
217 recreateFFTModel();
197 218
198 if (!m_model || !m_model->isOK()) return; 219 if (!m_model || !m_model->isOK()) return;
199 220
200 connectSignals(m_model); 221 connectSignals(m_model);
201 222
202 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid())); 223 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid()));
203 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), 224 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
204 this, SLOT(cacheInvalid(sv_frame_t, sv_frame_t))); 225 this, SLOT(cacheInvalid(sv_frame_t, sv_frame_t)));
205 226
206 emit modelReplaced(); 227 emit modelReplaced();
207 } 228 }
208 229
209 Layer::PropertyList 230 Layer::PropertyList
253 SpectrogramLayer::getPropertyType(const PropertyName &name) const 274 SpectrogramLayer::getPropertyType(const PropertyName &name) const
254 { 275 {
255 if (name == "Gain") return RangeProperty; 276 if (name == "Gain") return RangeProperty;
256 if (name == "Colour Rotation") return RangeProperty; 277 if (name == "Colour Rotation") return RangeProperty;
257 if (name == "Threshold") return RangeProperty; 278 if (name == "Threshold") return RangeProperty;
279 if (name == "Colour") return ColourMapProperty;
258 return ValueProperty; 280 return ValueProperty;
259 } 281 }
260 282
261 QString 283 QString
262 SpectrogramLayer::getPropertyGroupName(const PropertyName &name) const 284 SpectrogramLayer::getPropertyGroupName(const PropertyName &name) const
263 { 285 {
264 if (name == "Bin Display" || 286 if (name == "Bin Display" ||
265 name == "Frequency Scale") return tr("Bins"); 287 name == "Frequency Scale") return tr("Bins");
266 if (name == "Window Size" || 288 if (name == "Window Size" ||
267 name == "Window Increment") return tr("Window"); 289 name == "Window Increment") return tr("Window");
268 if (name == "Colour" || 290 if (name == "Colour" ||
269 name == "Threshold" || 291 name == "Threshold" ||
270 name == "Colour Rotation") return tr("Colour"); 292 name == "Colour Rotation") return tr("Colour");
271 if (name == "Normalization" || 293 if (name == "Normalization" ||
272 name == "Gain" || 294 name == "Gain" ||
273 name == "Colour Scale") return tr("Scale"); 295 name == "Colour Scale") return tr("Scale");
274 return QString(); 296 return QString();
275 } 297 }
276 298
277 int 299 int
278 SpectrogramLayer::getPropertyRangeAndValue(const PropertyName &name, 300 SpectrogramLayer::getPropertyRangeAndValue(const PropertyName &name,
279 int *min, int *max, int *deflt) const 301 int *min, int *max, int *deflt) const
280 { 302 {
281 int val = 0; 303 int val = 0;
282 304
283 int garbage0, garbage1, garbage2; 305 int garbage0, garbage1, garbage2;
284 if (!min) min = &garbage0; 306 if (!min) min = &garbage0;
285 if (!max) max = &garbage1; 307 if (!max) max = &garbage1;
286 if (!deflt) deflt = &garbage2; 308 if (!deflt) deflt = &garbage2;
287 309
288 if (name == "Gain") { 310 if (name == "Gain") {
289 311
290 *min = -50; 312 *min = -50;
291 *max = 50; 313 *max = 50;
292 314
293 *deflt = int(lrint(log10(m_initialGain) * 20.0)); 315 *deflt = int(lrint(log10(m_initialGain) * 20.0));
294 if (*deflt < *min) *deflt = *min; 316 if (*deflt < *min) *deflt = *min;
295 if (*deflt > *max) *deflt = *max; 317 if (*deflt > *max) *deflt = *max;
296 318
297 val = int(lrint(log10(m_gain) * 20.0)); 319 val = int(lrint(log10(m_gain) * 20.0));
298 if (val < *min) val = *min; 320 if (val < *min) val = *min;
299 if (val > *max) val = *max; 321 if (val > *max) val = *max;
300 322
301 } else if (name == "Threshold") { 323 } else if (name == "Threshold") {
302 324
303 *min = -81; 325 *min = -81;
304 *max = -1; 326 *max = -1;
305 327
306 *deflt = int(lrint(AudioLevel::multiplier_to_dB(m_initialThreshold))); 328 *deflt = int(lrint(AudioLevel::multiplier_to_dB(m_initialThreshold)));
307 if (*deflt < *min) *deflt = *min; 329 if (*deflt < *min) *deflt = *min;
308 if (*deflt > *max) *deflt = *max; 330 if (*deflt > *max) *deflt = *max;
309 331
310 val = int(lrint(AudioLevel::multiplier_to_dB(m_threshold))); 332 val = int(lrint(AudioLevel::multiplier_to_dB(m_threshold)));
311 if (val < *min) val = *min; 333 if (val < *min) val = *min;
312 if (val > *max) val = *max; 334 if (val > *max) val = *max;
313 335
314 } else if (name == "Colour Rotation") { 336 } else if (name == "Colour Rotation") {
315 337
316 *min = 0; 338 *min = 0;
317 *max = 256; 339 *max = 256;
318 *deflt = m_initialRotation; 340 *deflt = m_initialRotation;
319 341
320 val = m_colourRotation; 342 val = m_colourRotation;
321 343
322 } else if (name == "Colour Scale") { 344 } else if (name == "Colour Scale") {
323 345
324 // linear, meter, db^2, db, phase 346 // linear, meter, db^2, db, phase
325 *min = 0; 347 *min = 0;
326 *max = 4; 348 *max = 4;
327 *deflt = 2; 349 *deflt = 2;
328 350
329 val = convertFromColourScale(m_colourScale, m_colourScaleMultiple); 351 val = convertFromColourScale(m_colourScale, m_colourScaleMultiple);
330 352
331 } else if (name == "Colour") { 353 } else if (name == "Colour") {
332 354
333 *min = 0; 355 *min = 0;
334 *max = ColourMapper::getColourMapCount() - 1; 356 *max = ColourMapper::getColourMapCount() - 1;
335 *deflt = 0; 357 *deflt = 0;
336 358
337 val = m_colourMap; 359 val = m_colourMap;
338 360
339 } else if (name == "Window Size") { 361 } else if (name == "Window Size") {
340 362
341 *min = 0; 363 *min = 0;
342 *max = 10; 364 *max = 10;
343 *deflt = 5; 365 *deflt = 5;
344 366
345 val = 0; 367 val = 0;
346 int ws = m_windowSize; 368 int ws = m_windowSize;
347 while (ws > 32) { ws >>= 1; val ++; } 369 while (ws > 32) { ws >>= 1; val ++; }
348 370
349 } else if (name == "Window Increment") { 371 } else if (name == "Window Increment") {
350 372
351 *min = 0; 373 *min = 0;
352 *max = 5; 374 *max = 5;
353 *deflt = 2; 375 *deflt = 2;
354 376
355 val = m_windowHopLevel; 377 val = m_windowHopLevel;
356 378
357 } else if (name == "Min Frequency") { 379 } else if (name == "Min Frequency") {
358 380
359 *min = 0; 381 *min = 0;
360 *max = 9; 382 *max = 9;
361 *deflt = 1; 383 *deflt = 1;
362 384
363 switch (m_minFrequency) { 385 switch (m_minFrequency) {
364 case 0: default: val = 0; break; 386 case 0: default: val = 0; break;
365 case 10: val = 1; break; 387 case 10: val = 1; break;
366 case 20: val = 2; break; 388 case 20: val = 2; break;
367 case 40: val = 3; break; 389 case 40: val = 3; break;
368 case 100: val = 4; break; 390 case 100: val = 4; break;
369 case 250: val = 5; break; 391 case 250: val = 5; break;
370 case 500: val = 6; break; 392 case 500: val = 6; break;
371 case 1000: val = 7; break; 393 case 1000: val = 7; break;
372 case 4000: val = 8; break; 394 case 4000: val = 8; break;
373 case 10000: val = 9; break; 395 case 10000: val = 9; break;
374 } 396 }
375 397
376 } else if (name == "Max Frequency") { 398 } else if (name == "Max Frequency") {
377 399
378 *min = 0; 400 *min = 0;
379 *max = 9; 401 *max = 9;
380 *deflt = 6; 402 *deflt = 6;
381 403
382 switch (m_maxFrequency) { 404 switch (m_maxFrequency) {
383 case 500: val = 0; break; 405 case 500: val = 0; break;
384 case 1000: val = 1; break; 406 case 1000: val = 1; break;
385 case 1500: val = 2; break; 407 case 1500: val = 2; break;
386 case 2000: val = 3; break; 408 case 2000: val = 3; break;
387 case 4000: val = 4; break; 409 case 4000: val = 4; break;
388 case 6000: val = 5; break; 410 case 6000: val = 5; break;
389 case 8000: val = 6; break; 411 case 8000: val = 6; break;
390 case 12000: val = 7; break; 412 case 12000: val = 7; break;
391 case 16000: val = 8; break; 413 case 16000: val = 8; break;
392 default: val = 9; break; 414 default: val = 9; break;
393 } 415 }
394 416
395 } else if (name == "Frequency Scale") { 417 } else if (name == "Frequency Scale") {
396 418
397 *min = 0; 419 *min = 0;
398 *max = 1; 420 *max = 1;
399 *deflt = int(BinScale::Linear); 421 *deflt = int(BinScale::Linear);
400 val = (int)m_binScale; 422 val = (int)m_binScale;
401 423
402 } else if (name == "Bin Display") { 424 } else if (name == "Bin Display") {
403 425
404 *min = 0; 426 *min = 0;
405 *max = 2; 427 *max = 2;
406 *deflt = int(BinDisplay::AllBins); 428 *deflt = int(BinDisplay::AllBins);
407 val = (int)m_binDisplay; 429 val = (int)m_binDisplay;
408 430
409 } else if (name == "Normalization") { 431 } else if (name == "Normalization") {
410 432
411 *min = 0; 433 *min = 0;
412 *max = 3; 434 *max = 3;
413 *deflt = 0; 435 *deflt = 0;
414 436
415 val = convertFromColumnNorm(m_normalization, m_normalizeVisibleArea); 437 val = convertFromColumnNorm(m_normalization, m_normalizeVisibleArea);
416 438
417 } else { 439 } else {
418 val = Layer::getPropertyRangeAndValue(name, min, max, deflt); 440 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
419 } 441 }
420 442
421 return val; 443 return val;
422 } 444 }
423 445
424 QString 446 QString
425 SpectrogramLayer::getPropertyValueLabel(const PropertyName &name, 447 SpectrogramLayer::getPropertyValueLabel(const PropertyName &name,
426 int value) const 448 int value) const
427 { 449 {
428 if (name == "Colour") { 450 if (name == "Colour") {
429 return ColourMapper::getColourMapName(value); 451 return ColourMapper::getColourMapName(value);
430 } 452 }
431 if (name == "Colour Scale") { 453 if (name == "Colour Scale") {
432 switch (value) { 454 switch (value) {
433 default: 455 default:
434 case 0: return tr("Linear"); 456 case 0: return tr("Linear");
435 case 1: return tr("Meter"); 457 case 1: return tr("Meter");
436 case 2: return tr("dBV^2"); 458 case 2: return tr("dBV^2");
437 case 3: return tr("dBV"); 459 case 3: return tr("dBV");
438 case 4: return tr("Phase"); 460 case 4: return tr("Phase");
439 } 461 }
440 } 462 }
441 if (name == "Normalization") { 463 if (name == "Normalization") {
442 return ""; // icon only 464 switch(value) {
465 default:
466 case 0: return tr("None");
467 case 1: return tr("Col");
468 case 2: return tr("View");
469 case 3: return tr("Hybrid");
470 }
471 // return ""; // icon only
443 } 472 }
444 if (name == "Window Size") { 473 if (name == "Window Size") {
445 return QString("%1").arg(32 << value); 474 return QString("%1").arg(32 << value);
446 } 475 }
447 if (name == "Window Increment") { 476 if (name == "Window Increment") {
448 switch (value) { 477 switch (value) {
449 default: 478 default:
450 case 0: return tr("None"); 479 case 0: return tr("None");
451 case 1: return tr("25 %"); 480 case 1: return tr("25 %");
452 case 2: return tr("50 %"); 481 case 2: return tr("50 %");
453 case 3: return tr("75 %"); 482 case 3: return tr("75 %");
454 case 4: return tr("87.5 %"); 483 case 4: return tr("87.5 %");
455 case 5: return tr("93.75 %"); 484 case 5: return tr("93.75 %");
456 } 485 }
457 } 486 }
458 if (name == "Min Frequency") { 487 if (name == "Min Frequency") {
459 switch (value) { 488 switch (value) {
460 default: 489 default:
461 case 0: return tr("No min"); 490 case 0: return tr("No min");
462 case 1: return tr("10 Hz"); 491 case 1: return tr("10 Hz");
463 case 2: return tr("20 Hz"); 492 case 2: return tr("20 Hz");
464 case 3: return tr("40 Hz"); 493 case 3: return tr("40 Hz");
465 case 4: return tr("100 Hz"); 494 case 4: return tr("100 Hz");
466 case 5: return tr("250 Hz"); 495 case 5: return tr("250 Hz");
467 case 6: return tr("500 Hz"); 496 case 6: return tr("500 Hz");
468 case 7: return tr("1 KHz"); 497 case 7: return tr("1 KHz");
469 case 8: return tr("4 KHz"); 498 case 8: return tr("4 KHz");
470 case 9: return tr("10 KHz"); 499 case 9: return tr("10 KHz");
471 } 500 }
472 } 501 }
473 if (name == "Max Frequency") { 502 if (name == "Max Frequency") {
474 switch (value) { 503 switch (value) {
475 default: 504 default:
476 case 0: return tr("500 Hz"); 505 case 0: return tr("500 Hz");
477 case 1: return tr("1 KHz"); 506 case 1: return tr("1 KHz");
478 case 2: return tr("1.5 KHz"); 507 case 2: return tr("1.5 KHz");
479 case 3: return tr("2 KHz"); 508 case 3: return tr("2 KHz");
480 case 4: return tr("4 KHz"); 509 case 4: return tr("4 KHz");
481 case 5: return tr("6 KHz"); 510 case 5: return tr("6 KHz");
482 case 6: return tr("8 KHz"); 511 case 6: return tr("8 KHz");
483 case 7: return tr("12 KHz"); 512 case 7: return tr("12 KHz");
484 case 8: return tr("16 KHz"); 513 case 8: return tr("16 KHz");
485 case 9: return tr("No max"); 514 case 9: return tr("No max");
486 } 515 }
487 } 516 }
488 if (name == "Frequency Scale") { 517 if (name == "Frequency Scale") {
489 switch (value) { 518 switch (value) {
490 default: 519 default:
491 case 0: return tr("Linear"); 520 case 0: return tr("Linear");
492 case 1: return tr("Log"); 521 case 1: return tr("Log");
493 } 522 }
494 } 523 }
495 if (name == "Bin Display") { 524 if (name == "Bin Display") {
496 switch (value) { 525 switch (value) {
497 default: 526 default:
498 case 0: return tr("All Bins"); 527 case 0: return tr("All Bins");
499 case 1: return tr("Peak Bins"); 528 case 1: return tr("Peak Bins");
500 case 2: return tr("Frequencies"); 529 case 2: return tr("Frequencies");
501 } 530 }
502 } 531 }
503 return tr("<unknown>"); 532 return tr("<unknown>");
504 } 533 }
505 534
506 QString 535 QString
534 563
535 void 564 void
536 SpectrogramLayer::setProperty(const PropertyName &name, int value) 565 SpectrogramLayer::setProperty(const PropertyName &name, int value)
537 { 566 {
538 if (name == "Gain") { 567 if (name == "Gain") {
539 setGain(float(pow(10, float(value)/20.0))); 568 setGain(float(pow(10, float(value)/20.0)));
540 } else if (name == "Threshold") { 569 } else if (name == "Threshold") {
541 if (value == -81) setThreshold(0.0); 570 if (value == -81) setThreshold(0.0);
542 else setThreshold(float(AudioLevel::dB_to_multiplier(value))); 571 else setThreshold(float(AudioLevel::dB_to_multiplier(value)));
543 } else if (name == "Colour Rotation") { 572 } else if (name == "Colour Rotation") {
544 setColourRotation(value); 573 setColourRotation(value);
545 } else if (name == "Colour") { 574 } else if (name == "Colour") {
546 setColourMap(value); 575 setColourMap(value);
547 } else if (name == "Window Size") { 576 } else if (name == "Window Size") {
548 setWindowSize(32 << value); 577 setWindowSize(32 << value);
549 } else if (name == "Window Increment") { 578 } else if (name == "Window Increment") {
550 setWindowHopLevel(value); 579 setWindowHopLevel(value);
551 } else if (name == "Min Frequency") { 580 } else if (name == "Min Frequency") {
552 switch (value) { 581 switch (value) {
553 default: 582 default:
554 case 0: setMinFrequency(0); break; 583 case 0: setMinFrequency(0); break;
555 case 1: setMinFrequency(10); break; 584 case 1: setMinFrequency(10); break;
556 case 2: setMinFrequency(20); break; 585 case 2: setMinFrequency(20); break;
557 case 3: setMinFrequency(40); break; 586 case 3: setMinFrequency(40); break;
558 case 4: setMinFrequency(100); break; 587 case 4: setMinFrequency(100); break;
559 case 5: setMinFrequency(250); break; 588 case 5: setMinFrequency(250); break;
560 case 6: setMinFrequency(500); break; 589 case 6: setMinFrequency(500); break;
561 case 7: setMinFrequency(1000); break; 590 case 7: setMinFrequency(1000); break;
562 case 8: setMinFrequency(4000); break; 591 case 8: setMinFrequency(4000); break;
563 case 9: setMinFrequency(10000); break; 592 case 9: setMinFrequency(10000); break;
564 } 593 }
565 int vs = getCurrentVerticalZoomStep(); 594 int vs = getCurrentVerticalZoomStep();
566 if (vs != m_lastEmittedZoomStep) { 595 if (vs != m_lastEmittedZoomStep) {
567 emit verticalZoomChanged(); 596 emit verticalZoomChanged();
568 m_lastEmittedZoomStep = vs; 597 m_lastEmittedZoomStep = vs;
569 } 598 }
570 } else if (name == "Max Frequency") { 599 } else if (name == "Max Frequency") {
571 switch (value) { 600 switch (value) {
572 case 0: setMaxFrequency(500); break; 601 case 0: setMaxFrequency(500); break;
573 case 1: setMaxFrequency(1000); break; 602 case 1: setMaxFrequency(1000); break;
574 case 2: setMaxFrequency(1500); break; 603 case 2: setMaxFrequency(1500); break;
575 case 3: setMaxFrequency(2000); break; 604 case 3: setMaxFrequency(2000); break;
576 case 4: setMaxFrequency(4000); break; 605 case 4: setMaxFrequency(4000); break;
577 case 5: setMaxFrequency(6000); break; 606 case 5: setMaxFrequency(6000); break;
578 case 6: setMaxFrequency(8000); break; 607 case 6: setMaxFrequency(8000); break;
579 case 7: setMaxFrequency(12000); break; 608 case 7: setMaxFrequency(12000); break;
580 case 8: setMaxFrequency(16000); break; 609 case 8: setMaxFrequency(16000); break;
581 default: 610 default:
582 case 9: setMaxFrequency(0); break; 611 case 9: setMaxFrequency(0); break;
583 } 612 }
584 int vs = getCurrentVerticalZoomStep(); 613 int vs = getCurrentVerticalZoomStep();
585 if (vs != m_lastEmittedZoomStep) { 614 if (vs != m_lastEmittedZoomStep) {
586 emit verticalZoomChanged(); 615 emit verticalZoomChanged();
587 m_lastEmittedZoomStep = vs; 616 m_lastEmittedZoomStep = vs;
588 } 617 }
589 } else if (name == "Colour Scale") { 618 } else if (name == "Colour Scale") {
590 setColourScaleMultiple(1.0); 619 setColourScaleMultiple(1.0);
591 switch (value) { 620 switch (value) {
592 default: 621 default:
593 case 0: setColourScale(ColourScaleType::Linear); break; 622 case 0: setColourScale(ColourScaleType::Linear); break;
594 case 1: setColourScale(ColourScaleType::Meter); break; 623 case 1: setColourScale(ColourScaleType::Meter); break;
595 case 2: 624 case 2:
596 setColourScale(ColourScaleType::Log); 625 setColourScale(ColourScaleType::Log);
597 setColourScaleMultiple(2.0); 626 setColourScaleMultiple(2.0);
598 break; 627 break;
599 case 3: setColourScale(ColourScaleType::Log); break; 628 case 3: setColourScale(ColourScaleType::Log); break;
600 case 4: setColourScale(ColourScaleType::Phase); break; 629 case 4: setColourScale(ColourScaleType::Phase); break;
601 } 630 }
602 } else if (name == "Frequency Scale") { 631 } else if (name == "Frequency Scale") {
603 switch (value) { 632 switch (value) {
604 default: 633 default:
605 case 0: setBinScale(BinScale::Linear); break; 634 case 0: setBinScale(BinScale::Linear); break;
606 case 1: setBinScale(BinScale::Log); break; 635 case 1: setBinScale(BinScale::Log); break;
607 } 636 }
608 } else if (name == "Bin Display") { 637 } else if (name == "Bin Display") {
609 switch (value) { 638 switch (value) {
610 default: 639 default:
611 case 0: setBinDisplay(BinDisplay::AllBins); break; 640 case 0: setBinDisplay(BinDisplay::AllBins); break;
612 case 1: setBinDisplay(BinDisplay::PeakBins); break; 641 case 1: setBinDisplay(BinDisplay::PeakBins); break;
613 case 2: setBinDisplay(BinDisplay::PeakFrequencies); break; 642 case 2: setBinDisplay(BinDisplay::PeakFrequencies); break;
614 } 643 }
615 } else if (name == "Normalization") { 644 } else if (name == "Normalization") {
616 auto n = convertToColumnNorm(value); 645 auto n = convertToColumnNorm(value);
617 setNormalization(n.first); 646 setNormalization(n.first);
618 setNormalizeVisibleArea(n.second); 647 setNormalizeVisibleArea(n.second);
619 } 648 }
663 { 692 {
664 if (m_channel == ch) return; 693 if (m_channel == ch) return;
665 694
666 invalidateRenderers(); 695 invalidateRenderers();
667 m_channel = ch; 696 m_channel = ch;
668 invalidateFFTModel(); 697 recreateFFTModel();
669 698
670 emit layerParametersChanged(); 699 emit layerParametersChanged();
671 } 700 }
672 701
673 int 702 int
707 736
708 invalidateRenderers(); 737 invalidateRenderers();
709 738
710 m_windowSize = ws; 739 m_windowSize = ws;
711 740
712 invalidateFFTModel(); 741 recreateFFTModel();
713 742
714 emit layerParametersChanged(); 743 emit layerParametersChanged();
715 } 744 }
716 745
717 int 746 int
727 756
728 invalidateRenderers(); 757 invalidateRenderers();
729 758
730 m_windowHopLevel = v; 759 m_windowHopLevel = v;
731 760
732 invalidateFFTModel(); 761 recreateFFTModel();
733 762
734 emit layerParametersChanged(); 763 emit layerParametersChanged();
735
736 // fillCache();
737 } 764 }
738 765
739 int 766 int
740 SpectrogramLayer::getWindowHopLevel() const 767 SpectrogramLayer::getWindowHopLevel() const
741 { 768 {
749 776
750 invalidateRenderers(); 777 invalidateRenderers();
751 778
752 m_windowType = w; 779 m_windowType = w;
753 780
754 invalidateFFTModel(); 781 recreateFFTModel();
755 782
756 emit layerParametersChanged(); 783 emit layerParametersChanged();
757 } 784 }
758 785
759 WindowType 786 WindowType
764 791
765 void 792 void
766 SpectrogramLayer::setGain(float gain) 793 SpectrogramLayer::setGain(float gain)
767 { 794 {
768 // SVDEBUG << "SpectrogramLayer::setGain(" << gain << ") (my gain is now " 795 // SVDEBUG << "SpectrogramLayer::setGain(" << gain << ") (my gain is now "
769 // << m_gain << ")" << endl; 796 // << m_gain << ")" << endl;
770 797
771 if (m_gain == gain) return; 798 if (m_gain == gain) return;
772 799
773 invalidateRenderers(); 800 invalidateRenderers();
774 801
849 if (r < 0) r = 0; 876 if (r < 0) r = 0;
850 if (r > 256) r = 256; 877 if (r > 256) r = 256;
851 int distance = r - m_colourRotation; 878 int distance = r - m_colourRotation;
852 879
853 if (distance != 0) { 880 if (distance != 0) {
854 m_colourRotation = r; 881 m_colourRotation = r;
855 } 882 }
856 883
857 // Initially the idea with colour rotation was that we would just 884 // Initially the idea with colour rotation was that we would just
858 // rotate the palette of an already-generated cache. That's not 885 // rotate the palette of an already-generated cache. That's not
859 // really practical now that cacheing is handled in a separate 886 // really practical now that cacheing is handled in a separate
1001 return; 1028 return;
1002 } 1029 }
1003 1030
1004 Layer::setLayerDormant(v, true); 1031 Layer::setLayerDormant(v, true);
1005 1032
1006 invalidateRenderers(); 1033 invalidateRenderers();
1007 1034
1008 } else { 1035 } else {
1009 1036
1010 Layer::setLayerDormant(v, false); 1037 Layer::setLayerDormant(v, false);
1011 } 1038 }
1039 }
1040
1041 bool
1042 SpectrogramLayer::isLayerScrollable(const LayerGeometryProvider *) const
1043 {
1044 return false;
1012 } 1045 }
1013 1046
1014 void 1047 void
1015 SpectrogramLayer::cacheInvalid() 1048 SpectrogramLayer::cacheInvalid()
1016 { 1049 {
1056 { 1089 {
1057 sv_samplerate_t sr = m_model->getSampleRate(); 1090 sv_samplerate_t sr = m_model->getSampleRate();
1058 double minf = double(sr) / getFFTSize(); 1091 double minf = double(sr) / getFFTSize();
1059 1092
1060 if (m_minFrequency > 0.0) { 1093 if (m_minFrequency > 0.0) {
1061 int minbin = int((double(m_minFrequency) * getFFTSize()) / sr + 0.01); 1094 int minbin = int((double(m_minFrequency) * getFFTSize()) / sr + 0.01);
1062 if (minbin < 1) minbin = 1; 1095 if (minbin < 1) minbin = 1;
1063 minf = minbin * sr / getFFTSize(); 1096 minf = minbin * sr / getFFTSize();
1064 } 1097 }
1065 1098
1066 return minf; 1099 return minf;
1067 } 1100 }
1068 1101
1071 { 1104 {
1072 sv_samplerate_t sr = m_model->getSampleRate(); 1105 sv_samplerate_t sr = m_model->getSampleRate();
1073 double maxf = double(sr) / 2; 1106 double maxf = double(sr) / 2;
1074 1107
1075 if (m_maxFrequency > 0.0) { 1108 if (m_maxFrequency > 0.0) {
1076 int maxbin = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1); 1109 int maxbin = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1);
1077 if (maxbin > getFFTSize() / 2) maxbin = getFFTSize() / 2; 1110 if (maxbin > getFFTSize() / 2) maxbin = getFFTSize() / 2;
1078 maxf = maxbin * sr / getFFTSize(); 1111 maxf = maxbin * sr / getFFTSize();
1079 } 1112 }
1080 1113
1081 return maxf; 1114 return maxf;
1082 } 1115 }
1083 1116
1133 // Each pixel column covers an exact range of sample frames: 1166 // Each pixel column covers an exact range of sample frames:
1134 sv_frame_t f0 = v->getFrameForX(x) - modelStart; 1167 sv_frame_t f0 = v->getFrameForX(x) - modelStart;
1135 sv_frame_t f1 = v->getFrameForX(x + 1) - modelStart - 1; 1168 sv_frame_t f1 = v->getFrameForX(x + 1) - modelStart - 1;
1136 1169
1137 if (f1 < int(modelStart) || f0 > int(modelEnd)) { 1170 if (f1 < int(modelStart) || f0 > int(modelEnd)) {
1138 return false; 1171 return false;
1139 } 1172 }
1140 1173
1141 // And that range may be drawn from a possibly non-integral 1174 // And that range may be drawn from a possibly non-integral
1142 // range of spectrogram windows: 1175 // range of spectrogram windows:
1143 1176
1158 int s1i = int(s1); 1191 int s1i = int(s1);
1159 1192
1160 int windowIncrement = getWindowIncrement(); 1193 int windowIncrement = getWindowIncrement();
1161 int w0 = s0i * windowIncrement - (m_windowSize - windowIncrement)/2; 1194 int w0 = s0i * windowIncrement - (m_windowSize - windowIncrement)/2;
1162 int w1 = s1i * windowIncrement + windowIncrement + 1195 int w1 = s1i * windowIncrement + windowIncrement +
1163 (m_windowSize - windowIncrement)/2 - 1; 1196 (m_windowSize - windowIncrement)/2 - 1;
1164 1197
1165 min = RealTime::frame2RealTime(w0, m_model->getSampleRate()); 1198 min = RealTime::frame2RealTime(w0, m_model->getSampleRate());
1166 max = RealTime::frame2RealTime(w1, m_model->getSampleRate()); 1199 max = RealTime::frame2RealTime(w1, m_model->getSampleRate());
1167 return true; 1200 return true;
1168 } 1201 }
1178 int q1i = int(q1); 1211 int q1i = int(q1);
1179 1212
1180 sv_samplerate_t sr = m_model->getSampleRate(); 1213 sv_samplerate_t sr = m_model->getSampleRate();
1181 1214
1182 for (int q = q0i; q <= q1i; ++q) { 1215 for (int q = q0i; q <= q1i; ++q) {
1183 if (q == q0i) freqMin = (sr * q) / getFFTSize(); 1216 if (q == q0i) freqMin = (sr * q) / getFFTSize();
1184 if (q == q1i) freqMax = (sr * (q+1)) / getFFTSize(); 1217 if (q == q1i) freqMax = (sr * (q+1)) / getFFTSize();
1185 } 1218 }
1186 return true; 1219 return true;
1187 } 1220 }
1188 1221
1189 bool 1222 bool
1190 SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, 1223 SpectrogramLayer::getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y,
1191 double &freqMin, double &freqMax, 1224 double &freqMin, double &freqMax,
1192 double &adjFreqMin, double &adjFreqMax) 1225 double &adjFreqMin, double &adjFreqMax)
1193 const 1226 const
1194 { 1227 {
1195 if (!m_model || !m_model->isOK() || !m_model->isReady()) { 1228 if (!m_model || !m_model->isOK() || !m_model->isReady()) {
1196 return false; 1229 return false;
1197 } 1230 }
1198 1231
1199 FFTModel *fft = getFFTModel(); 1232 FFTModel *fft = getFFTModel();
1200 if (!fft) return false; 1233 if (!fft) return false;
1201 1234
1214 sv_samplerate_t sr = m_model->getSampleRate(); 1247 sv_samplerate_t sr = m_model->getSampleRate();
1215 1248
1216 bool haveAdj = false; 1249 bool haveAdj = false;
1217 1250
1218 bool peaksOnly = (m_binDisplay == BinDisplay::PeakBins || 1251 bool peaksOnly = (m_binDisplay == BinDisplay::PeakBins ||
1219 m_binDisplay == BinDisplay::PeakFrequencies); 1252 m_binDisplay == BinDisplay::PeakFrequencies);
1220 1253
1221 for (int q = q0i; q <= q1i; ++q) { 1254 for (int q = q0i; q <= q1i; ++q) {
1222 1255
1223 for (int s = s0i; s <= s1i; ++s) { 1256 for (int s = s0i; s <= s1i; ++s) {
1224 1257
1225 double binfreq = (double(sr) * q) / m_windowSize; 1258 double binfreq = (double(sr) * q) / m_windowSize;
1226 if (q == q0i) freqMin = binfreq; 1259 if (q == q0i) freqMin = binfreq;
1227 if (q == q1i) freqMax = binfreq; 1260 if (q == q1i) freqMax = binfreq;
1228 1261
1229 if (peaksOnly && !fft->isLocalPeak(s, q)) continue; 1262 if (peaksOnly && !fft->isLocalPeak(s, q)) continue;
1230 1263
1231 if (!fft->isOverThreshold 1264 if (!fft->isOverThreshold
1232 (s, q, float(m_threshold * double(getFFTSize())/2.0))) { 1265 (s, q, float(m_threshold * double(getFFTSize())/2.0))) {
1233 continue; 1266 continue;
1234 } 1267 }
1235 1268
1236 double freq = binfreq; 1269 double freq = binfreq;
1237 1270
1238 if (s < int(fft->getWidth()) - 1) { 1271 if (s < int(fft->getWidth()) - 1) {
1239 1272
1240 fft->estimateStableFrequency(s, q, freq); 1273 fft->estimateStableFrequency(s, q, freq);
1241 1274
1242 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq; 1275 if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq;
1243 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq; 1276 if (!haveAdj || freq > adjFreqMax) adjFreqMax = freq;
1244 1277
1245 haveAdj = true; 1278 haveAdj = true;
1246 } 1279 }
1247 } 1280 }
1248 } 1281 }
1249 1282
1250 if (!haveAdj) { 1283 if (!haveAdj) {
1251 adjFreqMin = adjFreqMax = 0.0; 1284 adjFreqMin = adjFreqMax = 0.0;
1252 } 1285 }
1253 1286
1254 return haveAdj; 1287 return haveAdj;
1255 } 1288 }
1256 1289
1257 bool 1290 bool
1258 SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, 1291 SpectrogramLayer::getXYBinSourceRange(LayerGeometryProvider *v, int x, int y,
1259 double &min, double &max, 1292 double &min, double &max,
1260 double &phaseMin, double &phaseMax) const 1293 double &phaseMin, double &phaseMax) const
1261 { 1294 {
1262 if (!m_model || !m_model->isOK() || !m_model->isReady()) { 1295 if (!m_model || !m_model->isOK() || !m_model->isReady()) {
1263 return false; 1296 return false;
1264 } 1297 }
1265 1298
1266 double q0 = 0, q1 = 0; 1299 double q0 = 0, q1 = 0;
1267 if (!getYBinRange(v, y, q0, q1)) return false; 1300 if (!getYBinRange(v, y, q0, q1)) return false;
1268 1301
1303 value = fft->getMagnitudeAt(s, q) / (getFFTSize()/2.0); 1336 value = fft->getMagnitudeAt(s, q) / (getFFTSize()/2.0);
1304 if (!have || value < min) { min = value; } 1337 if (!have || value < min) { min = value; }
1305 if (!have || value > max) { max = value; } 1338 if (!have || value > max) { max = value; }
1306 1339
1307 have = true; 1340 have = true;
1308 } 1341 }
1309 } 1342 }
1310 } 1343 }
1311 1344
1312 if (have) { 1345 if (have) {
1313 rv = true; 1346 rv = true;
1314 } 1347 }
1315 } 1348 }
1316 1349
1317 return rv; 1350 return rv;
1318 } 1351 }
1319 1352
1320 FFTModel * 1353 void
1321 SpectrogramLayer::getFFTModel() const 1354 SpectrogramLayer::recreateFFTModel()
1322 { 1355 {
1323 if (!m_model) return 0; 1356 SVDEBUG << "SpectrogramLayer::recreateFFTModel called" << endl;
1324 1357
1325 int fftSize = getFFTSize(); 1358 if (!m_model || !m_model->isOK()) {
1326 1359 emit sliceableModelReplaced(m_fftModel, 0);
1327 //!!! it is now surely slower to do this on every getFFTModel() 1360 deleteDerivedModels();
1328 //!!! request than it would be to recreate the model immediately 1361 return;
1329 //!!! when something changes instead of just invalidating it 1362 }
1330 1363
1331 if (m_fftModel && 1364 if (m_fftModel) m_fftModel->aboutToDelete();
1332 m_fftModel->getHeight() == fftSize / 2 + 1 && 1365
1333 m_fftModel->getWindowIncrement() == getWindowIncrement()) { 1366 if (m_peakCache) m_peakCache->aboutToDelete();
1334 return m_fftModel;
1335 }
1336
1337 delete m_peakCache; 1367 delete m_peakCache;
1338 m_peakCache = 0; 1368 m_peakCache = 0;
1339 1369
1340 delete m_fftModel; 1370 if (m_wholeCache) m_wholeCache->aboutToDelete();
1341 m_fftModel = new FFTModel(m_model, 1371 delete m_wholeCache;
1342 m_channel, 1372 m_wholeCache = 0;
1343 m_windowType, 1373
1344 m_windowSize, 1374 FFTModel *newModel = new FFTModel(m_model,
1345 getWindowIncrement(), 1375 m_channel,
1346 fftSize); 1376 m_windowType,
1347 1377 m_windowSize,
1348 if (!m_fftModel->isOK()) { 1378 getWindowIncrement(),
1379 getFFTSize());
1380
1381 if (!newModel->isOK()) {
1349 QMessageBox::critical 1382 QMessageBox::critical
1350 (0, tr("FFT cache failed"), 1383 (0, tr("FFT cache failed"),
1351 tr("Failed to create the FFT model for this spectrogram.\n" 1384 tr("Failed to create the FFT model for this spectrogram.\n"
1352 "There may be insufficient memory or disc space to continue.")); 1385 "There may be insufficient memory or disc space to continue."));
1386 delete newModel;
1353 delete m_fftModel; 1387 delete m_fftModel;
1354 m_fftModel = 0; 1388 m_fftModel = 0;
1355 return 0; 1389 return;
1356 } 1390 }
1357 1391
1358 ((SpectrogramLayer *)this)->sliceableModelReplaced(0, m_fftModel); 1392 FFTModel *oldModel = m_fftModel;
1359 1393 m_fftModel = newModel;
1360 return m_fftModel; 1394
1361 } 1395 if (canStoreWholeCache()) { // i.e. if enough memory
1362 1396 m_wholeCache = new Dense3DModelPeakCache(m_fftModel, 1);
1363 Dense3DModelPeakCache * 1397 m_peakCache = new Dense3DModelPeakCache(m_wholeCache, m_peakCacheDivisor);
1364 SpectrogramLayer::getPeakCache() const 1398 } else {
1365 { 1399 m_peakCache = new Dense3DModelPeakCache(m_fftModel, m_peakCacheDivisor);
1366 //!!! see comment in getFFTModel 1400 }
1367 1401
1368 if (!m_peakCache) { 1402 emit sliceableModelReplaced(oldModel, m_fftModel);
1369 FFTModel *f = getFFTModel(); 1403 delete oldModel;
1370 if (!f) return 0; 1404 }
1371 m_peakCache = new Dense3DModelPeakCache(f, m_peakCacheDivisor); 1405
1372 } 1406 bool
1373 return m_peakCache; 1407 SpectrogramLayer::canStoreWholeCache() const
1408 {
1409 if (!m_fftModel) {
1410 return false; // or true, doesn't really matter
1411 }
1412
1413 size_t sz =
1414 size_t(m_fftModel->getWidth()) *
1415 size_t(m_fftModel->getHeight()) *
1416 sizeof(float);
1417
1418 try {
1419 SVDEBUG << "Requesting advice from StorageAdviser on whether to create whole-model cache" << endl;
1420 StorageAdviser::Recommendation recommendation =
1421 StorageAdviser::recommend
1422 (StorageAdviser::Criteria(StorageAdviser::SpeedCritical |
1423 StorageAdviser::PrecisionCritical |
1424 StorageAdviser::FrequentLookupLikely),
1425 sz / 1024, sz / 1024);
1426 if ((recommendation & StorageAdviser::UseDisc) ||
1427 (recommendation & StorageAdviser::ConserveSpace)) {
1428 SVDEBUG << "Seems inadvisable to create whole-model cache" << endl;
1429 return false;
1430 } else {
1431 SVDEBUG << "Seems fine to create whole-model cache" << endl;
1432 return true;
1433 }
1434 } catch (const InsufficientDiscSpace &) {
1435 SVDEBUG << "Seems like a terrible idea to create whole-model cache" << endl;
1436 return false;
1437 }
1374 } 1438 }
1375 1439
1376 const Model * 1440 const Model *
1377 SpectrogramLayer::getSliceableModel() const 1441 SpectrogramLayer::getSliceableModel() const
1378 { 1442 {
1379 return m_fftModel; 1443 return m_fftModel;
1380 }
1381
1382 void
1383 SpectrogramLayer::invalidateFFTModel()
1384 {
1385 #ifdef DEBUG_SPECTROGRAM
1386 cerr << "SpectrogramLayer::invalidateFFTModel called" << endl;
1387 #endif
1388
1389 emit sliceableModelReplaced(m_fftModel, 0);
1390
1391 delete m_fftModel;
1392 delete m_peakCache;
1393
1394 m_fftModel = 0;
1395 m_peakCache = 0;
1396 } 1444 }
1397 1445
1398 void 1446 void
1399 SpectrogramLayer::invalidateMagnitudes() 1447 SpectrogramLayer::invalidateMagnitudes()
1400 { 1448 {
1419 1467
1420 Colour3DPlotRenderer::Sources sources; 1468 Colour3DPlotRenderer::Sources sources;
1421 sources.verticalBinLayer = this; 1469 sources.verticalBinLayer = this;
1422 sources.fft = getFFTModel(); 1470 sources.fft = getFFTModel();
1423 sources.source = sources.fft; 1471 sources.source = sources.fft;
1424 sources.peakCache = getPeakCache(); 1472 if (m_peakCache) sources.peakCaches.push_back(m_peakCache);
1473 if (m_wholeCache) sources.peakCaches.push_back(m_wholeCache);
1425 1474
1426 ColourScale::Parameters cparams; 1475 ColourScale::Parameters cparams;
1427 cparams.colourMap = m_colourMap; 1476 cparams.colourMap = m_colourMap;
1428 cparams.scaleType = m_colourScale; 1477 cparams.scaleType = m_colourScale;
1429 cparams.multiple = m_colourScaleMultiple; 1478 cparams.multiple = m_colourScaleMultiple;
1431 if (m_colourScale != ColourScaleType::Phase) { 1480 if (m_colourScale != ColourScaleType::Phase) {
1432 cparams.gain = m_gain; 1481 cparams.gain = m_gain;
1433 cparams.threshold = m_threshold; 1482 cparams.threshold = m_threshold;
1434 } 1483 }
1435 1484
1436 float minValue = 0.0f; 1485 double minValue = 0.0f;
1437 float maxValue = 1.0f; 1486 double maxValue = 1.0f;
1438 1487
1439 if (m_normalizeVisibleArea && m_viewMags[viewId].isSet()) { 1488 if (m_normalizeVisibleArea && m_viewMags[viewId].isSet()) {
1440 minValue = m_viewMags[viewId].getMin(); 1489 minValue = m_viewMags[viewId].getMin();
1441 maxValue = m_viewMags[viewId].getMax(); 1490 maxValue = m_viewMags[viewId].getMax();
1442 } else if (m_colourScale == ColourScaleType::Linear && 1491 } else if (m_colourScale == ColourScaleType::Linear &&
1452 } 1501 }
1453 1502
1454 cparams.minValue = minValue; 1503 cparams.minValue = minValue;
1455 cparams.maxValue = maxValue; 1504 cparams.maxValue = maxValue;
1456 1505
1457 m_lastRenderedMags[viewId] = MagnitudeRange(minValue, maxValue); 1506 m_lastRenderedMags[viewId] = MagnitudeRange(float(minValue),
1507 float(maxValue));
1458 1508
1459 Colour3DPlotRenderer::Parameters params; 1509 Colour3DPlotRenderer::Parameters params;
1460 params.colourScale = ColourScale(cparams); 1510 params.colourScale = ColourScale(cparams);
1461 params.normalization = m_normalization; 1511 params.normalization = m_normalization;
1462 params.binDisplay = m_binDisplay; 1512 params.binDisplay = m_binDisplay;
1475 Preferences::getInstance()->getSpectrogramSmoothing(); 1525 Preferences::getInstance()->getSpectrogramSmoothing();
1476 params.interpolate = 1526 params.interpolate =
1477 (smoothing == Preferences::SpectrogramInterpolated || 1527 (smoothing == Preferences::SpectrogramInterpolated ||
1478 smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated); 1528 smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated);
1479 1529
1480 m_renderers[v->getId()] = new Colour3DPlotRenderer(sources, params); 1530 m_renderers[viewId] = new Colour3DPlotRenderer(sources, params);
1481 } 1531
1482 1532 m_crosshairColour =
1483 return m_renderers[v->getId()]; 1533 ColourMapper(m_colourMap, 1.f, 255.f).getContrastingColour();
1534 }
1535
1536 return m_renderers[viewId];
1484 } 1537 }
1485 1538
1486 void 1539 void
1487 SpectrogramLayer::paintWithRenderer(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 1540 SpectrogramLayer::paintWithRenderer(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
1488 { 1541 {
1552 1605
1553 cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl; 1606 cerr << "SpectrogramLayer::paint(): rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
1554 #endif 1607 #endif
1555 1608
1556 if (!m_model || !m_model->isOK() || !m_model->isReady()) { 1609 if (!m_model || !m_model->isOK() || !m_model->isReady()) {
1557 return; 1610 return;
1558 }
1559
1560 if (isLayerDormant(v)) {
1561 SVDEBUG << "SpectrogramLayer::paint(): Layer is dormant, making it undormant again" << endl;
1562 } 1611 }
1563 1612
1564 paintWithRenderer(v, paint, rect); 1613 paintWithRenderer(v, paint, rect);
1565 1614
1566 illuminateLocalFeatures(v, paint); 1615 illuminateLocalFeatures(v, paint);
1611 1660
1612 double 1661 double
1613 SpectrogramLayer::getYForFrequency(const LayerGeometryProvider *v, double frequency) const 1662 SpectrogramLayer::getYForFrequency(const LayerGeometryProvider *v, double frequency) const
1614 { 1663 {
1615 return v->getYForFrequency(frequency, 1664 return v->getYForFrequency(frequency,
1616 getEffectiveMinFrequency(), 1665 getEffectiveMinFrequency(),
1617 getEffectiveMaxFrequency(), 1666 getEffectiveMaxFrequency(),
1618 m_binScale == BinScale::Log); 1667 m_binScale == BinScale::Log);
1619 } 1668 }
1620 1669
1621 double 1670 double
1622 SpectrogramLayer::getFrequencyForY(const LayerGeometryProvider *v, int y) const 1671 SpectrogramLayer::getFrequencyForY(const LayerGeometryProvider *v, int y) const
1623 { 1672 {
1624 return v->getFrequencyForY(y, 1673 return v->getFrequencyForY(y,
1625 getEffectiveMinFrequency(), 1674 getEffectiveMinFrequency(),
1626 getEffectiveMaxFrequency(), 1675 getEffectiveMaxFrequency(),
1627 m_binScale == BinScale::Log); 1676 m_binScale == BinScale::Log);
1628 } 1677 }
1629 1678
1630 int 1679 int
1631 SpectrogramLayer::getCompletion(LayerGeometryProvider *) const 1680 SpectrogramLayer::getCompletion(LayerGeometryProvider *) const
1632 { 1681 {
1712 } 1761 }
1713 1762
1714 bool 1763 bool
1715 SpectrogramLayer::snapToFeatureFrame(LayerGeometryProvider *, 1764 SpectrogramLayer::snapToFeatureFrame(LayerGeometryProvider *,
1716 sv_frame_t &frame, 1765 sv_frame_t &frame,
1717 int &resolution, 1766 int &resolution,
1718 SnapType snap) const 1767 SnapType snap) const
1719 { 1768 {
1720 resolution = getWindowIncrement(); 1769 resolution = getWindowIncrement();
1721 sv_frame_t left = (frame / resolution) * resolution; 1770 sv_frame_t left = (frame / resolution) * resolution;
1722 sv_frame_t right = left + resolution; 1771 sv_frame_t right = left + resolution;
1723 1772
1724 switch (snap) { 1773 switch (snap) {
1725 case SnapLeft: frame = left; break; 1774 case SnapLeft: frame = left; break;
1726 case SnapRight: frame = right; break; 1775 case SnapRight: frame = right; break;
1727 case SnapNearest: 1776 case SnapNearest:
1728 case SnapNeighbouring: 1777 case SnapNeighbouring:
1729 if (frame - left > right - frame) frame = right; 1778 if (frame - left > right - frame) frame = right;
1730 else frame = left; 1779 else frame = left;
1731 break; 1780 break;
1732 } 1781 }
1733 1782
1734 return true; 1783 return true;
1735 } 1784 }
1736 1785
1882 RealTime rtMin, rtMax; 1931 RealTime rtMin, rtMax;
1883 1932
1884 bool haveValues = false; 1933 bool haveValues = false;
1885 1934
1886 if (!getXBinSourceRange(v, x, rtMin, rtMax)) { 1935 if (!getXBinSourceRange(v, x, rtMin, rtMax)) {
1887 return ""; 1936 return "";
1888 } 1937 }
1889 if (getXYBinSourceRange(v, x, y, magMin, magMax, phaseMin, phaseMax)) { 1938 if (getXYBinSourceRange(v, x, y, magMin, magMax, phaseMin, phaseMax)) {
1890 haveValues = true; 1939 haveValues = true;
1891 } 1940 }
1892 1941
1893 QString adjFreqText = "", adjPitchText = ""; 1942 QString adjFreqText = "", adjPitchText = "";
1894 1943
1895 if (m_binDisplay == BinDisplay::PeakFrequencies) { 1944 if (m_binDisplay == BinDisplay::PeakFrequencies) {
1896 1945
1897 if (!getAdjustedYBinSourceRange(v, x, y, freqMin, freqMax, 1946 if (!getAdjustedYBinSourceRange(v, x, y, freqMin, freqMax,
1898 adjFreqMin, adjFreqMax)) { 1947 adjFreqMin, adjFreqMax)) {
1899 return ""; 1948 return "";
1900 } 1949 }
1901 1950
1902 if (adjFreqMin != adjFreqMax) { 1951 if (adjFreqMin != adjFreqMax) {
1903 adjFreqText = tr("Peak Frequency:\t%1 - %2 Hz\n") 1952 adjFreqText = tr("Peak Frequency:\t%1 - %2 Hz\n")
1904 .arg(adjFreqMin).arg(adjFreqMax); 1953 .arg(adjFreqMin).arg(adjFreqMax);
1905 } else { 1954 } else {
1906 adjFreqText = tr("Peak Frequency:\t%1 Hz\n") 1955 adjFreqText = tr("Peak Frequency:\t%1 Hz\n")
1907 .arg(adjFreqMin); 1956 .arg(adjFreqMin);
1908 } 1957 }
1909 1958
1910 QString pmin = Pitch::getPitchLabelForFrequency(adjFreqMin); 1959 QString pmin = Pitch::getPitchLabelForFrequency(adjFreqMin);
1911 QString pmax = Pitch::getPitchLabelForFrequency(adjFreqMax); 1960 QString pmax = Pitch::getPitchLabelForFrequency(adjFreqMax);
1912 1961
1913 if (pmin != pmax) { 1962 if (pmin != pmax) {
1914 adjPitchText = tr("Peak Pitch:\t%3 - %4\n").arg(pmin).arg(pmax); 1963 adjPitchText = tr("Peak Pitch:\t%3 - %4\n").arg(pmin).arg(pmax);
1915 } else { 1964 } else {
1916 adjPitchText = tr("Peak Pitch:\t%2\n").arg(pmin); 1965 adjPitchText = tr("Peak Pitch:\t%2\n").arg(pmin);
1917 } 1966 }
1918 1967
1919 } else { 1968 } else {
1920 1969
1921 if (!getYBinSourceRange(v, y, freqMin, freqMax)) return ""; 1970 if (!getYBinSourceRange(v, y, freqMin, freqMax)) return "";
1922 } 1971 }
1923 1972
1924 QString text; 1973 QString text;
1925 1974
1926 if (rtMin != rtMax) { 1975 if (rtMin != rtMax) {
1927 text += tr("Time:\t%1 - %2\n") 1976 text += tr("Time:\t%1 - %2\n")
1928 .arg(rtMin.toText(true).c_str()) 1977 .arg(rtMin.toText(true).c_str())
1929 .arg(rtMax.toText(true).c_str()); 1978 .arg(rtMax.toText(true).c_str());
1930 } else { 1979 } else {
1931 text += tr("Time:\t%1\n") 1980 text += tr("Time:\t%1\n")
1932 .arg(rtMin.toText(true).c_str()); 1981 .arg(rtMin.toText(true).c_str());
1933 } 1982 }
1934 1983
1935 if (freqMin != freqMax) { 1984 if (freqMin != freqMax) {
1936 text += tr("%1Bin Frequency:\t%2 - %3 Hz\n%4Bin Pitch:\t%5 - %6\n") 1985 text += tr("%1Bin Frequency:\t%2 - %3 Hz\n%4Bin Pitch:\t%5 - %6\n")
1937 .arg(adjFreqText) 1986 .arg(adjFreqText)
1938 .arg(freqMin) 1987 .arg(freqMin)
1939 .arg(freqMax) 1988 .arg(freqMax)
1940 .arg(adjPitchText) 1989 .arg(adjPitchText)
1941 .arg(Pitch::getPitchLabelForFrequency(freqMin)) 1990 .arg(Pitch::getPitchLabelForFrequency(freqMin))
1942 .arg(Pitch::getPitchLabelForFrequency(freqMax)); 1991 .arg(Pitch::getPitchLabelForFrequency(freqMax));
1943 } else { 1992 } else {
1944 text += tr("%1Bin Frequency:\t%2 Hz\n%3Bin Pitch:\t%4\n") 1993 text += tr("%1Bin Frequency:\t%2 Hz\n%3Bin Pitch:\t%4\n")
1945 .arg(adjFreqText) 1994 .arg(adjFreqText)
1946 .arg(freqMin) 1995 .arg(freqMin)
1947 .arg(adjPitchText) 1996 .arg(adjPitchText)
1948 .arg(Pitch::getPitchLabelForFrequency(freqMin)); 1997 .arg(Pitch::getPitchLabelForFrequency(freqMin));
1949 } 1998 }
1950 1999
1951 if (haveValues) { 2000 if (haveValues) {
1952 double dbMin = AudioLevel::multiplier_to_dB(magMin); 2001 double dbMin = AudioLevel::multiplier_to_dB(magMin);
1953 double dbMax = AudioLevel::multiplier_to_dB(magMax); 2002 double dbMax = AudioLevel::multiplier_to_dB(magMax);
1954 QString dbMinString; 2003 QString dbMinString;
1955 QString dbMaxString; 2004 QString dbMaxString;
1956 if (dbMin == AudioLevel::DB_FLOOR) { 2005 if (dbMin == AudioLevel::DB_FLOOR) {
1957 dbMinString = Strings::minus_infinity; 2006 dbMinString = Strings::minus_infinity;
1958 } else { 2007 } else {
1959 dbMinString = QString("%1").arg(lrint(dbMin)); 2008 dbMinString = QString("%1").arg(lrint(dbMin));
1960 } 2009 }
1961 if (dbMax == AudioLevel::DB_FLOOR) { 2010 if (dbMax == AudioLevel::DB_FLOOR) {
1962 dbMaxString = Strings::minus_infinity; 2011 dbMaxString = Strings::minus_infinity;
1963 } else { 2012 } else {
1964 dbMaxString = QString("%1").arg(lrint(dbMax)); 2013 dbMaxString = QString("%1").arg(lrint(dbMax));
1965 } 2014 }
1966 if (lrint(dbMin) != lrint(dbMax)) { 2015 if (lrint(dbMin) != lrint(dbMax)) {
1967 text += tr("dB:\t%1 - %2").arg(dbMinString).arg(dbMaxString); 2016 text += tr("dB:\t%1 - %2").arg(dbMinString).arg(dbMaxString);
1968 } else { 2017 } else {
1969 text += tr("dB:\t%1").arg(dbMinString); 2018 text += tr("dB:\t%1").arg(dbMinString);
1970 } 2019 }
1971 if (phaseMin != phaseMax) { 2020 if (phaseMin != phaseMax) {
1972 text += tr("\nPhase:\t%1 - %2").arg(phaseMin).arg(phaseMax); 2021 text += tr("\nPhase:\t%1 - %2").arg(phaseMin).arg(phaseMax);
1973 } else { 2022 } else {
1974 text += tr("\nPhase:\t%1").arg(phaseMin); 2023 text += tr("\nPhase:\t%1").arg(phaseMin);
1975 } 2024 }
1976 } 2025 }
1977 2026
1978 return text; 2027 return text;
1979 } 2028 }
1980 2029
1995 2044
1996 int cw = 0; 2045 int cw = 0;
1997 if (detailed) cw = getColourScaleWidth(paint); 2046 if (detailed) cw = getColourScaleWidth(paint);
1998 2047
1999 int tw = paint.fontMetrics().width(QString("%1") 2048 int tw = paint.fontMetrics().width(QString("%1")
2000 .arg(m_maxFrequency > 0 ? 2049 .arg(m_maxFrequency > 0 ?
2001 m_maxFrequency - 1 : 2050 m_maxFrequency - 1 :
2002 m_model->getSampleRate() / 2)); 2051 m_model->getSampleRate() / 2));
2003 2052
2004 int fw = paint.fontMetrics().width(tr("43Hz")); 2053 int fw = paint.fontMetrics().width(tr("43Hz"));
2005 if (tw < fw) tw = fw; 2054 if (tw < fw) tw = fw;
2006 2055
2007 int tickw = (m_binScale == BinScale::Log ? 10 : 4); 2056 int tickw = (m_binScale == BinScale::Log ? 10 : 4);
2012 void 2061 void
2013 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed, 2062 SpectrogramLayer::paintVerticalScale(LayerGeometryProvider *v, bool detailed,
2014 QPainter &paint, QRect rect) const 2063 QPainter &paint, QRect rect) const
2015 { 2064 {
2016 if (!m_model || !m_model->isOK()) { 2065 if (!m_model || !m_model->isOK()) {
2017 return; 2066 return;
2018 } 2067 }
2019 2068
2020 Profiler profiler("SpectrogramLayer::paintVerticalScale"); 2069 Profiler profiler("SpectrogramLayer::paintVerticalScale");
2021 2070
2022 //!!! cache this? 2071 //!!! cache this?
2034 2083
2035 int bins = getFFTSize() / 2; 2084 int bins = getFFTSize() / 2;
2036 sv_samplerate_t sr = m_model->getSampleRate(); 2085 sv_samplerate_t sr = m_model->getSampleRate();
2037 2086
2038 if (m_maxFrequency > 0) { 2087 if (m_maxFrequency > 0) {
2039 bins = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1); 2088 bins = int((double(m_maxFrequency) * getFFTSize()) / sr + 0.1);
2040 if (bins > getFFTSize() / 2) bins = getFFTSize() / 2; 2089 if (bins > getFFTSize() / 2) bins = getFFTSize() / 2;
2041 } 2090 }
2042 2091
2043 int cw = 0; 2092 int cw = 0;
2044 if (detailed) cw = getColourScaleWidth(paint); 2093 if (detailed) cw = getColourScaleWidth(paint);
2045 2094
2050 2099
2051 int bin = -1; 2100 int bin = -1;
2052 2101
2053 for (int y = 0; y < v->getPaintHeight(); ++y) { 2102 for (int y = 0; y < v->getPaintHeight(); ++y) {
2054 2103
2055 double q0, q1; 2104 double q0, q1;
2056 if (!getYBinRange(v, v->getPaintHeight() - y, q0, q1)) continue; 2105 if (!getYBinRange(v, v->getPaintHeight() - y, q0, q1)) continue;
2057 2106
2058 int vy; 2107 int vy;
2059 2108
2060 if (int(q0) > bin) { 2109 if (int(q0) > bin) {
2061 vy = y; 2110 vy = y;
2062 bin = int(q0); 2111 bin = int(q0);
2063 } else { 2112 } else {
2064 continue; 2113 continue;
2065 } 2114 }
2066 2115
2067 int freq = int((sr * bin) / getFFTSize()); 2116 int freq = int((sr * bin) / getFFTSize());
2068 2117
2069 if (py >= 0 && (vy - py) < textHeight - 1) { 2118 if (py >= 0 && (vy - py) < textHeight - 1) {
2070 if (m_binScale == BinScale::Linear) { 2119 if (m_binScale == BinScale::Linear) {
2071 paint.drawLine(w - tickw, h - vy, w, h - vy); 2120 paint.drawLine(w - tickw, h - vy, w, h - vy);
2072 } 2121 }
2073 continue; 2122 continue;
2074 } 2123 }
2075 2124
2076 QString text = QString("%1").arg(freq); 2125 QString text = QString("%1").arg(freq);
2077 if (bin == 1) text = tr("%1Hz").arg(freq); // bin 0 is DC 2126 if (bin == 1) text = tr("%1Hz").arg(freq); // bin 0 is DC
2078 paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy); 2127 paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy);
2079 2128
2080 if (h - vy - textHeight >= -2) { 2129 if (h - vy - textHeight >= -2) {
2081 int tx = w - 3 - paint.fontMetrics().width(text) - max(tickw, pkw); 2130 int tx = w - 3 - paint.fontMetrics().width(text) - max(tickw, pkw);
2082 paint.drawText(tx, h - vy + toff, text); 2131 paint.drawText(tx, h - vy + toff, text);
2083 } 2132 }
2084 2133
2085 py = vy; 2134 py = vy;
2086 } 2135 }
2087 2136
2088 if (m_binScale == BinScale::Log) { 2137 if (m_binScale == BinScale::Log) {
2089 2138
2090 // piano keyboard 2139 // piano keyboard
2116 int cbw = paint.fontMetrics().width("dB"); 2165 int cbw = paint.fontMetrics().width("dB");
2117 2166
2118 int topLines = 2; 2167 int topLines = 2;
2119 2168
2120 int ch = h - textHeight * (topLines + 1) - 8; 2169 int ch = h - textHeight * (topLines + 1) - 8;
2121 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); 2170 // paint.drawRect(4, textHeight + 4, cw - 1, ch + 1);
2122 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1); 2171 paint.drawRect(4 + cw - cbw, textHeight * topLines + 4, cbw - 1, ch + 1);
2123 2172
2124 QString top, bottom; 2173 QString top, bottom;
2125 double min = m_viewMags[v->getId()].getMin(); 2174 double min = m_viewMags[v->getId()].getMin();
2126 double max = m_viewMags[v->getId()].getMax(); 2175 double max = m_viewMags[v->getId()].getMax();
2444 QString indent, QString extraAttributes) const 2493 QString indent, QString extraAttributes) const
2445 { 2494 {
2446 QString s; 2495 QString s;
2447 2496
2448 s += QString("channel=\"%1\" " 2497 s += QString("channel=\"%1\" "
2449 "windowSize=\"%2\" " 2498 "windowSize=\"%2\" "
2450 "windowHopLevel=\"%3\" " 2499 "windowHopLevel=\"%3\" "
2451 "gain=\"%4\" " 2500 "gain=\"%4\" "
2452 "threshold=\"%5\" ") 2501 "threshold=\"%5\" ")
2453 .arg(m_channel) 2502 .arg(m_channel)
2454 .arg(m_windowSize) 2503 .arg(m_windowSize)
2455 .arg(m_windowHopLevel) 2504 .arg(m_windowHopLevel)
2456 .arg(m_gain) 2505 .arg(m_gain)
2457 .arg(m_threshold); 2506 .arg(m_threshold);
2458 2507
2459 s += QString("minFrequency=\"%1\" " 2508 s += QString("minFrequency=\"%1\" "
2460 "maxFrequency=\"%2\" " 2509 "maxFrequency=\"%2\" "
2461 "colourScale=\"%3\" " 2510 "colourScale=\"%3\" "
2462 "colourScheme=\"%4\" " 2511 "colourScheme=\"%4\" "
2463 "colourRotation=\"%5\" " 2512 "colourRotation=\"%5\" "
2464 "frequencyScale=\"%6\" " 2513 "frequencyScale=\"%6\" "
2465 "binDisplay=\"%7\" ") 2514 "binDisplay=\"%7\" ")
2466 .arg(m_minFrequency) 2515 .arg(m_minFrequency)
2467 .arg(m_maxFrequency) 2516 .arg(m_maxFrequency)
2468 .arg(convertFromColourScale(m_colourScale, m_colourScaleMultiple)) 2517 .arg(convertFromColourScale(m_colourScale, m_colourScaleMultiple))
2469 .arg(m_colourMap) 2518 .arg(m_colourMap)
2470 .arg(m_colourRotation) 2519 .arg(m_colourRotation)
2471 .arg(int(m_binScale)) 2520 .arg(int(m_binScale))
2472 .arg(int(m_binDisplay)); 2521 .arg(int(m_binDisplay));
2473 2522
2474 // New-style normalization attributes, allowing for more types of 2523 // New-style normalization attributes, allowing for more types of
2475 // normalization in future: write out the column normalization 2524 // normalization in future: write out the column normalization
2476 // type separately, and then whether we are normalizing visible 2525 // type separately, and then whether we are normalizing visible
2477 // area as well afterwards 2526 // area as well afterwards
2485 // it (Tony v1.0) has a totally different scale factor for 2534 // it (Tony v1.0) has a totally different scale factor for
2486 // it. We'll just have to accept that session files from Tony 2535 // it. We'll just have to accept that session files from Tony
2487 // v2.0+ will look odd in Tony v1.0 2536 // v2.0+ will look odd in Tony v1.0
2488 2537
2489 s += QString("normalizeColumns=\"%1\" ") 2538 s += QString("normalizeColumns=\"%1\" ")
2490 .arg(m_normalization == ColumnNormalization::Max1 ? "true" : "false"); 2539 .arg(m_normalization == ColumnNormalization::Max1 ? "true" : "false");
2491 2540
2492 // And this applies to both old- and new-style attributes 2541 // And this applies to both old- and new-style attributes
2493 2542
2494 s += QString("normalizeVisibleArea=\"%1\" ") 2543 s += QString("normalizeVisibleArea=\"%1\" ")
2495 .arg(m_normalizeVisibleArea ? "true" : "false"); 2544 .arg(m_normalizeVisibleArea ? "true" : "false");
2552 2601
2553 int colourRotation = attributes.value("colourRotation").toInt(&ok); 2602 int colourRotation = attributes.value("colourRotation").toInt(&ok);
2554 if (ok) setColourRotation(colourRotation); 2603 if (ok) setColourRotation(colourRotation);
2555 2604
2556 BinScale binScale = (BinScale) 2605 BinScale binScale = (BinScale)
2557 attributes.value("frequencyScale").toInt(&ok); 2606 attributes.value("frequencyScale").toInt(&ok);
2558 if (ok) setBinScale(binScale); 2607 if (ok) setBinScale(binScale);
2559 2608
2560 BinDisplay binDisplay = (BinDisplay) 2609 BinDisplay binDisplay = (BinDisplay)
2561 attributes.value("binDisplay").toInt(&ok); 2610 attributes.value("binDisplay").toInt(&ok);
2562 if (ok) setBinDisplay(binDisplay); 2611 if (ok) setBinDisplay(binDisplay);
2563 2612
2564 bool haveNewStyleNormalization = false; 2613 bool haveNewStyleNormalization = false;
2565 2614
2566 QString columnNormalization = attributes.value("columnNormalization"); 2615 QString columnNormalization = attributes.value("columnNormalization");
2574 } else if (columnNormalization == "hybrid") { 2623 } else if (columnNormalization == "hybrid") {
2575 setNormalization(ColumnNormalization::Hybrid); 2624 setNormalization(ColumnNormalization::Hybrid);
2576 } else if (columnNormalization == "none") { 2625 } else if (columnNormalization == "none") {
2577 setNormalization(ColumnNormalization::None); 2626 setNormalization(ColumnNormalization::None);
2578 } else { 2627 } else {
2579 cerr << "NOTE: Unknown or unsupported columnNormalization attribute \"" 2628 SVCERR << "NOTE: Unknown or unsupported columnNormalization attribute \""
2580 << columnNormalization << "\"" << endl; 2629 << columnNormalization << "\"" << endl;
2581 } 2630 }
2582 } 2631 }
2583 2632
2584 if (!haveNewStyleNormalization) { 2633 if (!haveNewStyleNormalization) {