annotate layer/WaveformLayer.cpp @ 1363:bbeffb29bf09

Fix inconsistency between centre frame actually set and centre frame notified as set, which caused the start frame location to creep out of place gradually as you page through
author Chris Cannam
date Tue, 30 Oct 2018 14:00:20 +0000
parents 4949061fcb8c
children c2a3ac0a6688
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "WaveformLayer.h"
Chris@0 17
Chris@0 18 #include "base/AudioLevel.h"
Chris@128 19 #include "view/View.h"
Chris@0 20 #include "base/Profiler.h"
Chris@167 21 #include "base/RangeMapper.h"
Chris@1147 22 #include "base/Strings.h"
Chris@1078 23
Chris@376 24 #include "ColourDatabase.h"
Chris@1078 25 #include "PaintAssistant.h"
Chris@1340 26
Chris@1340 27 #include "data/model/WaveformOversampler.h"
Chris@0 28
Chris@0 29 #include <QPainter>
Chris@0 30 #include <QPixmap>
Chris@316 31 #include <QTextStream>
Chris@0 32
Chris@0 33 #include <iostream>
Chris@0 34 #include <cmath>
Chris@0 35
Chris@1352 36 //#define DEBUG_WAVEFORM_PAINT 1
Chris@1338 37 //#define DEBUG_WAVEFORM_PAINT_BY_PIXEL 1
Chris@4 38
Chris@1333 39 using std::vector;
Chris@682 40
Chris@0 41
Chris@44 42 WaveformLayer::WaveformLayer() :
Chris@287 43 SingleColourLayer(),
Chris@0 44 m_model(0),
Chris@0 45 m_gain(1.0f),
Chris@67 46 m_autoNormalize(false),
Chris@0 47 m_showMeans(true),
Chris@0 48 m_greyscale(true),
Chris@0 49 m_channelMode(SeparateChannels),
Chris@0 50 m_channel(-1),
Chris@0 51 m_scale(LinearScale),
Chris@709 52 m_middleLineHeight(0.5),
Chris@0 53 m_aggressive(false),
Chris@0 54 m_cache(0),
Chris@1325 55 m_cacheValid(false)
Chris@0 56 {
Chris@0 57 }
Chris@0 58
Chris@0 59 WaveformLayer::~WaveformLayer()
Chris@0 60 {
Chris@0 61 delete m_cache;
Chris@0 62 }
Chris@0 63
Chris@0 64 void
Chris@0 65 WaveformLayer::setModel(const RangeSummarisableTimeValueModel *model)
Chris@0 66 {
Chris@69 67 bool channelsChanged = false;
Chris@69 68 if (m_channel == -1) {
Chris@69 69 if (!m_model) {
Chris@69 70 if (model) {
Chris@69 71 channelsChanged = true;
Chris@69 72 }
Chris@69 73 } else {
Chris@69 74 if (model &&
Chris@69 75 m_model->getChannelCount() != model->getChannelCount()) {
Chris@69 76 channelsChanged = true;
Chris@69 77 }
Chris@69 78 }
Chris@69 79 }
Chris@69 80
Chris@0 81 m_model = model;
Chris@0 82 m_cacheValid = false;
Chris@0 83 if (!m_model || !m_model->isOK()) return;
Chris@0 84
Chris@320 85 connectSignals(m_model);
Chris@301 86
Chris@0 87 emit modelReplaced();
Chris@69 88
Chris@69 89 if (channelsChanged) emit layerParametersChanged();
Chris@0 90 }
Chris@0 91
Chris@0 92 Layer::PropertyList
Chris@0 93 WaveformLayer::getProperties() const
Chris@0 94 {
Chris@287 95 PropertyList list = SingleColourLayer::getProperties();
Chris@87 96 list.push_back("Scale");
Chris@87 97 list.push_back("Gain");
Chris@87 98 list.push_back("Normalize Visible Area");
Chris@68 99
Chris@68 100 if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) {
Chris@87 101 list.push_back("Channels");
Chris@68 102 }
Chris@68 103
Chris@0 104 return list;
Chris@0 105 }
Chris@0 106
Chris@87 107 QString
Chris@87 108 WaveformLayer::getPropertyLabel(const PropertyName &name) const
Chris@87 109 {
Chris@87 110 if (name == "Scale") return tr("Scale");
Chris@87 111 if (name == "Gain") return tr("Gain");
Chris@87 112 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
Chris@87 113 if (name == "Channels") return tr("Channels");
Chris@287 114 return SingleColourLayer::getPropertyLabel(name);
Chris@87 115 }
Chris@87 116
Chris@335 117 QString
Chris@335 118 WaveformLayer::getPropertyIconName(const PropertyName &name) const
Chris@335 119 {
Chris@335 120 if (name == "Normalize Visible Area") return "normalise";
Chris@335 121 return "";
Chris@335 122 }
Chris@335 123
Chris@0 124 Layer::PropertyType
Chris@0 125 WaveformLayer::getPropertyType(const PropertyName &name) const
Chris@0 126 {
Chris@87 127 if (name == "Gain") return RangeProperty;
Chris@87 128 if (name == "Normalize Visible Area") return ToggleProperty;
Chris@87 129 if (name == "Channels") return ValueProperty;
Chris@87 130 if (name == "Scale") return ValueProperty;
Chris@287 131 return SingleColourLayer::getPropertyType(name);
Chris@0 132 }
Chris@0 133
Chris@0 134 QString
Chris@0 135 WaveformLayer::getPropertyGroupName(const PropertyName &name) const
Chris@0 136 {
Chris@87 137 if (name == "Gain" ||
Chris@87 138 name == "Normalize Visible Area" ||
Chris@1266 139 name == "Scale") return tr("Scale");
Chris@0 140 return QString();
Chris@0 141 }
Chris@0 142
Chris@0 143 int
Chris@0 144 WaveformLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 145 int *min, int *max, int *deflt) const
Chris@0 146 {
Chris@216 147 int val = 0;
Chris@0 148
Chris@216 149 int garbage0, garbage1, garbage2;
Chris@56 150 if (!min) min = &garbage0;
Chris@56 151 if (!max) max = &garbage1;
Chris@216 152 if (!deflt) deflt = &garbage2;
Chris@10 153
Chris@87 154 if (name == "Gain") {
Chris@0 155
Chris@1266 156 *min = -50;
Chris@1266 157 *max = 50;
Chris@216 158 *deflt = 0;
Chris@0 159
Chris@1266 160 val = int(lrint(log10(m_gain) * 20.0));
Chris@1266 161 if (val < *min) val = *min;
Chris@1266 162 if (val > *max) val = *max;
Chris@0 163
Chris@87 164 } else if (name == "Normalize Visible Area") {
Chris@67 165
Chris@216 166 val = (m_autoNormalize ? 1 : 0);
Chris@216 167 *deflt = 0;
Chris@67 168
Chris@87 169 } else if (name == "Channels") {
Chris@0 170
Chris@67 171 *min = 0;
Chris@67 172 *max = 2;
Chris@216 173 *deflt = 0;
Chris@216 174 if (m_channelMode == MixChannels) val = 1;
Chris@216 175 else if (m_channelMode == MergeChannels) val = 2;
Chris@216 176 else val = 0;
Chris@0 177
Chris@87 178 } else if (name == "Scale") {
Chris@0 179
Chris@1266 180 *min = 0;
Chris@1266 181 *max = 2;
Chris@216 182 *deflt = 0;
Chris@0 183
Chris@1266 184 val = (int)m_scale;
Chris@0 185
Chris@0 186 } else {
Chris@1266 187 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@0 188 }
Chris@0 189
Chris@216 190 return val;
Chris@0 191 }
Chris@0 192
Chris@0 193 QString
Chris@0 194 WaveformLayer::getPropertyValueLabel(const PropertyName &name,
Chris@1266 195 int value) const
Chris@0 196 {
Chris@87 197 if (name == "Scale") {
Chris@1266 198 switch (value) {
Chris@1266 199 default:
Chris@1266 200 case 0: return tr("Linear");
Chris@1266 201 case 1: return tr("Meter");
Chris@1266 202 case 2: return tr("dB");
Chris@1266 203 }
Chris@0 204 }
Chris@87 205 if (name == "Channels") {
Chris@67 206 switch (value) {
Chris@67 207 default:
Chris@67 208 case 0: return tr("Separate");
Chris@67 209 case 1: return tr("Mean");
Chris@67 210 case 2: return tr("Butterfly");
Chris@67 211 }
Chris@67 212 }
Chris@287 213 return SingleColourLayer::getPropertyValueLabel(name, value);
Chris@0 214 }
Chris@0 215
Chris@167 216 RangeMapper *
Chris@167 217 WaveformLayer::getNewPropertyRangeMapper(const PropertyName &name) const
Chris@167 218 {
Chris@167 219 if (name == "Gain") {
Chris@167 220 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
Chris@167 221 }
Chris@167 222 return 0;
Chris@167 223 }
Chris@167 224
Chris@0 225 void
Chris@0 226 WaveformLayer::setProperty(const PropertyName &name, int value)
Chris@0 227 {
Chris@87 228 if (name == "Gain") {
Chris@1266 229 setGain(float(pow(10, float(value)/20.0)));
Chris@87 230 } else if (name == "Normalize Visible Area") {
Chris@67 231 setAutoNormalize(value ? true : false);
Chris@87 232 } else if (name == "Channels") {
Chris@67 233 if (value == 1) setChannelMode(MixChannels);
Chris@67 234 else if (value == 2) setChannelMode(MergeChannels);
Chris@67 235 else setChannelMode(SeparateChannels);
Chris@87 236 } else if (name == "Scale") {
Chris@1266 237 switch (value) {
Chris@1266 238 default:
Chris@1266 239 case 0: setScale(LinearScale); break;
Chris@1266 240 case 1: setScale(MeterScale); break;
Chris@1266 241 case 2: setScale(dBScale); break;
Chris@1266 242 }
Chris@287 243 } else {
Chris@287 244 SingleColourLayer::setProperty(name, value);
Chris@0 245 }
Chris@0 246 }
Chris@0 247
Chris@0 248 void
Chris@67 249 WaveformLayer::setGain(float gain)
Chris@0 250 {
Chris@0 251 if (m_gain == gain) return;
Chris@0 252 m_gain = gain;
Chris@0 253 m_cacheValid = false;
Chris@0 254 emit layerParametersChanged();
Chris@133 255 emit verticalZoomChanged();
Chris@0 256 }
Chris@0 257
Chris@0 258 void
Chris@67 259 WaveformLayer::setAutoNormalize(bool autoNormalize)
Chris@67 260 {
Chris@67 261 if (m_autoNormalize == autoNormalize) return;
Chris@67 262 m_autoNormalize = autoNormalize;
Chris@67 263 m_cacheValid = false;
Chris@67 264 emit layerParametersChanged();
Chris@67 265 }
Chris@67 266
Chris@67 267 void
Chris@0 268 WaveformLayer::setShowMeans(bool showMeans)
Chris@0 269 {
Chris@0 270 if (m_showMeans == showMeans) return;
Chris@0 271 m_showMeans = showMeans;
Chris@0 272 m_cacheValid = false;
Chris@0 273 emit layerParametersChanged();
Chris@0 274 }
Chris@0 275
Chris@0 276 void
Chris@0 277 WaveformLayer::setUseGreyscale(bool useGreyscale)
Chris@0 278 {
Chris@0 279 if (m_greyscale == useGreyscale) return;
Chris@0 280 m_greyscale = useGreyscale;
Chris@0 281 m_cacheValid = false;
Chris@0 282 emit layerParametersChanged();
Chris@0 283 }
Chris@0 284
Chris@0 285 void
Chris@0 286 WaveformLayer::setChannelMode(ChannelMode channelMode)
Chris@0 287 {
Chris@0 288 if (m_channelMode == channelMode) return;
Chris@0 289 m_channelMode = channelMode;
Chris@0 290 m_cacheValid = false;
Chris@0 291 emit layerParametersChanged();
Chris@0 292 }
Chris@0 293
Chris@0 294 void
Chris@0 295 WaveformLayer::setChannel(int channel)
Chris@0 296 {
Chris@587 297 // SVDEBUG << "WaveformLayer::setChannel(" << channel << ")" << endl;
Chris@0 298
Chris@0 299 if (m_channel == channel) return;
Chris@0 300 m_channel = channel;
Chris@0 301 m_cacheValid = false;
Chris@0 302 emit layerParametersChanged();
Chris@0 303 }
Chris@0 304
Chris@0 305 void
Chris@0 306 WaveformLayer::setScale(Scale scale)
Chris@0 307 {
Chris@0 308 if (m_scale == scale) return;
Chris@0 309 m_scale = scale;
Chris@0 310 m_cacheValid = false;
Chris@0 311 emit layerParametersChanged();
Chris@0 312 }
Chris@0 313
Chris@0 314 void
Chris@908 315 WaveformLayer::setMiddleLineHeight(double height)
Chris@709 316 {
Chris@709 317 if (m_middleLineHeight == height) return;
Chris@709 318 m_middleLineHeight = height;
Chris@709 319 m_cacheValid = false;
Chris@709 320 emit layerParametersChanged();
Chris@709 321 }
Chris@709 322
Chris@709 323 void
Chris@0 324 WaveformLayer::setAggressiveCacheing(bool aggressive)
Chris@0 325 {
Chris@0 326 if (m_aggressive == aggressive) return;
Chris@0 327 m_aggressive = aggressive;
Chris@0 328 m_cacheValid = false;
Chris@0 329 emit layerParametersChanged();
Chris@0 330 }
Chris@0 331
Chris@0 332 int
Chris@918 333 WaveformLayer::getCompletion(LayerGeometryProvider *) const
Chris@0 334 {
Chris@0 335 int completion = 100;
Chris@0 336 if (!m_model || !m_model->isOK()) return completion;
Chris@0 337 if (m_model->isReady(&completion)) return 100;
Chris@0 338 return completion;
Chris@0 339 }
Chris@0 340
Chris@79 341 bool
Chris@908 342 WaveformLayer::getValueExtents(double &min, double &max,
Chris@248 343 bool &, QString &unit) const
Chris@79 344 {
Chris@79 345 if (m_scale == LinearScale) {
Chris@79 346 min = 0.0;
Chris@79 347 max = 1.0;
Chris@79 348 unit = "V";
Chris@79 349 } else if (m_scale == MeterScale) {
Chris@79 350 return false; //!!!
Chris@79 351 } else {
Chris@79 352 min = AudioLevel::multiplier_to_dB(0.0);
Chris@79 353 max = AudioLevel::multiplier_to_dB(1.0);
Chris@79 354 unit = "dB";
Chris@79 355 }
Chris@79 356 return true;
Chris@79 357 }
Chris@79 358
Chris@0 359 int
Chris@908 360 WaveformLayer::dBscale(double sample, int m) const
Chris@0 361 {
Chris@67 362 if (sample < 0.0) return dBscale(-sample, m);
Chris@908 363 double dB = AudioLevel::multiplier_to_dB(sample);
Chris@0 364 if (dB < -50.0) return 0;
Chris@0 365 if (dB > 0.0) return m;
Chris@0 366 return int(((dB + 50.0) * m) / 50.0 + 0.1);
Chris@0 367 }
Chris@0 368
Chris@805 369 int
Chris@805 370 WaveformLayer::getChannelArrangement(int &min, int &max,
Chris@67 371 bool &merging, bool &mixing)
Chris@0 372 const
Chris@0 373 {
Chris@0 374 if (!m_model || !m_model->isOK()) return 0;
Chris@0 375
Chris@805 376 int channels = m_model->getChannelCount();
Chris@0 377 if (channels == 0) return 0;
Chris@0 378
Chris@805 379 int rawChannels = channels;
Chris@0 380
Chris@0 381 if (m_channel == -1) {
Chris@1266 382 min = 0;
Chris@1266 383 if (m_channelMode == MergeChannels ||
Chris@67 384 m_channelMode == MixChannels) {
Chris@1266 385 max = 0;
Chris@1266 386 channels = 1;
Chris@1266 387 } else {
Chris@1266 388 max = channels - 1;
Chris@1266 389 }
Chris@0 390 } else {
Chris@1266 391 min = m_channel;
Chris@1266 392 max = m_channel;
Chris@1266 393 rawChannels = 1;
Chris@1266 394 channels = 1;
Chris@0 395 }
Chris@0 396
Chris@0 397 merging = (m_channelMode == MergeChannels && rawChannels > 1);
Chris@67 398 mixing = (m_channelMode == MixChannels && rawChannels > 1);
Chris@0 399
Chris@587 400 // SVDEBUG << "WaveformLayer::getChannelArrangement: min " << min << ", max " << max << ", merging " << merging << ", channels " << channels << endl;
Chris@0 401
Chris@0 402 return channels;
Chris@0 403 }
Chris@0 404
Chris@67 405 bool
Chris@918 406 WaveformLayer::isLayerScrollable(const LayerGeometryProvider *) const
Chris@67 407 {
Chris@67 408 return !m_autoNormalize;
Chris@67 409 }
Chris@67 410
Chris@68 411 static float meterdbs[] = { -40, -30, -20, -15, -10,
Chris@68 412 -5, -3, -2, -1, -0.5, 0 };
Chris@68 413
Chris@365 414 bool
Chris@1336 415 WaveformLayer::getSourceFramesForX(LayerGeometryProvider *v,
Chris@1336 416 int x, int modelZoomLevel,
Chris@908 417 sv_frame_t &f0, sv_frame_t &f1) const
Chris@365 418 {
Chris@908 419 sv_frame_t viewFrame = v->getFrameForX(x);
Chris@365 420 if (viewFrame < 0) {
Chris@365 421 f0 = 0;
Chris@365 422 f1 = 0;
Chris@365 423 return false;
Chris@365 424 }
Chris@365 425
Chris@365 426 f0 = viewFrame;
Chris@365 427 f0 = f0 / modelZoomLevel;
Chris@365 428 f0 = f0 * modelZoomLevel;
Chris@365 429
Chris@1341 430 if (v->getZoomLevel().zone == ZoomLevel::PixelsPerFrame) {
Chris@1341 431 f1 = f0 + 1;
Chris@1341 432 } else {
Chris@1341 433 viewFrame = v->getFrameForX(x + 1);
Chris@1341 434 f1 = viewFrame;
Chris@1341 435 f1 = f1 / modelZoomLevel;
Chris@1341 436 f1 = f1 * modelZoomLevel;
Chris@1341 437 }
Chris@365 438
Chris@365 439 return (f0 < m_model->getEndFrame());
Chris@365 440 }
Chris@365 441
Chris@365 442 float
Chris@918 443 WaveformLayer::getNormalizeGain(LayerGeometryProvider *v, int channel) const
Chris@365 444 {
Chris@908 445 sv_frame_t startFrame = v->getStartFrame();
Chris@908 446 sv_frame_t endFrame = v->getEndFrame();
Chris@365 447
Chris@908 448 sv_frame_t modelStart = m_model->getStartFrame();
Chris@908 449 sv_frame_t modelEnd = m_model->getEndFrame();
Chris@365 450
Chris@908 451 sv_frame_t rangeStart, rangeEnd;
Chris@365 452
Chris@365 453 if (startFrame < modelStart) rangeStart = modelStart;
Chris@365 454 else rangeStart = startFrame;
Chris@365 455
Chris@365 456 if (endFrame < 0) rangeEnd = 0;
Chris@365 457 else if (endFrame > modelEnd) rangeEnd = modelEnd;
Chris@365 458 else rangeEnd = endFrame;
Chris@365 459
Chris@365 460 if (rangeEnd < rangeStart) rangeEnd = rangeStart;
Chris@365 461
Chris@365 462 RangeSummarisableTimeValueModel::Range range =
Chris@365 463 m_model->getSummary(channel, rangeStart, rangeEnd - rangeStart);
Chris@365 464
Chris@805 465 int minChannel = 0, maxChannel = 0;
Chris@365 466 bool mergingChannels = false, mixingChannels = false;
Chris@365 467
Chris@859 468 (void)getChannelArrangement(minChannel, maxChannel,
Chris@859 469 mergingChannels, mixingChannels);
Chris@365 470
Chris@365 471 if (mergingChannels || mixingChannels) {
Chris@365 472 RangeSummarisableTimeValueModel::Range otherRange =
Chris@365 473 m_model->getSummary(1, rangeStart, rangeEnd - rangeStart);
Chris@386 474 range.setMax(std::max(range.max(), otherRange.max()));
Chris@386 475 range.setMin(std::min(range.min(), otherRange.min()));
Chris@386 476 range.setAbsmean(std::min(range.absmean(), otherRange.absmean()));
Chris@365 477 }
Chris@365 478
Chris@908 479 return float(1.0 / std::max(fabs(range.max()), fabs(range.min())));
Chris@365 480 }
Chris@365 481
Chris@0 482 void
Chris@916 483 WaveformLayer::paint(LayerGeometryProvider *v, QPainter &viewPainter, QRect rect) const
Chris@0 484 {
Chris@0 485 if (!m_model || !m_model->isOK()) {
Chris@1266 486 return;
Chris@0 487 }
Chris@0 488
Chris@1325 489 ZoomLevel zoomLevel = v->getZoomLevel();
Chris@0 490
Chris@2 491 #ifdef DEBUG_WAVEFORM_PAINT
Chris@0 492 Profiler profiler("WaveformLayer::paint", true);
Chris@1338 493 SVCERR << "WaveformLayer::paint (" << rect.x() << "," << rect.y()
Chris@1266 494 << ") [" << rect.width() << "x" << rect.height() << "]: zoom " << zoomLevel << endl;
Chris@2 495 #endif
Chris@0 496
Chris@805 497 int channels = 0, minChannel = 0, maxChannel = 0;
Chris@67 498 bool mergingChannels = false, mixingChannels = false;
Chris@0 499
Chris@67 500 channels = getChannelArrangement(minChannel, maxChannel,
Chris@67 501 mergingChannels, mixingChannels);
Chris@0 502 if (channels == 0) return;
Chris@0 503
Chris@915 504 int w = v->getPaintWidth();
Chris@915 505 int h = v->getPaintHeight();
Chris@0 506
Chris@0 507 QPainter *paint;
Chris@0 508
Chris@0 509 if (m_aggressive) {
Chris@0 510
Chris@214 511 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 512 SVCERR << "WaveformLayer::paint: aggressive is true" << endl;
Chris@214 513 #endif
Chris@214 514
Chris@1325 515 using namespace std::rel_ops;
Chris@1325 516
Chris@1266 517 if (m_cacheValid && (zoomLevel != m_cacheZoomLevel)) {
Chris@1266 518 m_cacheValid = false;
Chris@1266 519 }
Chris@0 520
Chris@1266 521 if (!m_cache || m_cache->width() != w || m_cache->height() != h) {
Chris@214 522 #ifdef DEBUG_WAVEFORM_PAINT
Chris@214 523 if (m_cache) {
Chris@1338 524 SVCERR << "WaveformLayer::paint: cache size " << m_cache->width() << "x" << m_cache->height() << " differs from view size " << w << "x" << h << ": regenerating aggressive cache" << endl;
Chris@214 525 }
Chris@214 526 #endif
Chris@1266 527 delete m_cache;
Chris@1266 528 m_cache = new QPixmap(w, h);
Chris@214 529 m_cacheValid = false;
Chris@1266 530 }
Chris@214 531
Chris@1266 532 if (m_cacheValid) {
Chris@1266 533 viewPainter.drawPixmap(rect, *m_cache, rect);
Chris@1266 534 return;
Chris@1266 535 }
Chris@0 536
Chris@1266 537 paint = new QPainter(m_cache);
Chris@0 538
Chris@1266 539 paint->setPen(Qt::NoPen);
Chris@1266 540 paint->setBrush(getBackgroundQColor(v));
Chris@1266 541 paint->drawRect(rect);
Chris@0 542
Chris@1266 543 paint->setPen(getForegroundQColor(v));
Chris@1266 544 paint->setBrush(Qt::NoBrush);
Chris@0 545
Chris@0 546 } else {
Chris@1266 547 paint = &viewPainter;
Chris@0 548 }
Chris@0 549
Chris@28 550 paint->setRenderHint(QPainter::Antialiasing, false);
Chris@28 551
Chris@709 552 if (m_middleLineHeight != 0.5) {
Chris@709 553 paint->save();
Chris@908 554 double space = m_middleLineHeight * 2;
Chris@709 555 if (space > 1.0) space = 2.0 - space;
Chris@908 556 double yt = h * (m_middleLineHeight - space/2);
Chris@709 557 paint->translate(QPointF(0, yt));
Chris@709 558 paint->scale(1.0, space);
Chris@709 559 }
Chris@709 560
Chris@0 561 int x0 = 0, x1 = w - 1;
Chris@0 562
Chris@0 563 x0 = rect.left();
Chris@0 564 x1 = rect.right();
Chris@0 565
Chris@1334 566 if (x0 > 0) {
Chris@1334 567 rect.adjust(-1, 0, 0, 0);
Chris@1334 568 x0 = rect.left();
Chris@1334 569 }
Chris@1334 570
Chris@1334 571 if (x1 < w) {
Chris@1334 572 rect.adjust(0, 0, 1, 0);
Chris@1334 573 x1 = rect.right();
Chris@1334 574 }
Chris@28 575
Chris@365 576 // Our zoom level may differ from that at which the underlying
Chris@365 577 // model has its blocks.
Chris@302 578
Chris@365 579 // Each pixel within our visible range must always draw from
Chris@365 580 // exactly the same set of underlying audio frames, no matter what
Chris@365 581 // the range being drawn is. And that set of underlying frames
Chris@365 582 // must remain the same when we scroll one or more pixels left or
Chris@365 583 // right.
Chris@1325 584
Chris@1325 585 int desiredBlockSize = 1;
Chris@1325 586 if (zoomLevel.zone == ZoomLevel::FramesPerPixel) {
Chris@1325 587 desiredBlockSize = zoomLevel.level;
Chris@1325 588 }
Chris@1325 589 int blockSize = m_model->getSummaryBlockSize(desiredBlockSize);
Chris@365 590
Chris@908 591 sv_frame_t frame0;
Chris@908 592 sv_frame_t frame1;
Chris@908 593 sv_frame_t spare;
Chris@365 594
Chris@1325 595 getSourceFramesForX(v, x0, blockSize, frame0, spare);
Chris@1325 596 getSourceFramesForX(v, x1, blockSize, spare, frame1);
Chris@365 597
Chris@4 598 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 599 SVCERR << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << " and model zoom " << blockSize << ")" << endl;
Chris@4 600 #endif
Chris@0 601
Chris@1338 602 m_effectiveGains.clear();
Chris@805 603 while ((int)m_effectiveGains.size() <= maxChannel) {
Chris@67 604 m_effectiveGains.push_back(m_gain);
Chris@67 605 }
Chris@1337 606 if (m_autoNormalize) {
Chris@1337 607 for (int ch = minChannel; ch <= maxChannel; ++ch) {
Chris@1337 608 m_effectiveGains[ch] = getNormalizeGain(v, ch);
Chris@1337 609 }
Chris@1336 610 }
Chris@67 611
Chris@1338 612 RangeVec ranges;
Chris@1338 613
Chris@1336 614 if (v->getZoomLevel().zone == ZoomLevel::FramesPerPixel) {
Chris@1338 615 getSummaryRanges(minChannel, maxChannel,
Chris@1338 616 mixingChannels || mergingChannels,
Chris@1338 617 frame0, frame1,
Chris@1338 618 blockSize, ranges);
Chris@1338 619 } else {
Chris@1338 620 getOversampledRanges(minChannel, maxChannel,
Chris@1338 621 mixingChannels || mergingChannels,
Chris@1338 622 frame0, frame1,
Chris@1338 623 v->getZoomLevel().level, ranges);
Chris@1338 624 }
Chris@1333 625
Chris@1343 626 if (!ranges.empty()) {
Chris@1343 627 for (int ch = minChannel; ch <= maxChannel; ++ch) {
Chris@1343 628 paintChannel(v, paint, rect, ch, ranges, blockSize,
Chris@1343 629 frame0, frame1);
Chris@1343 630 }
Chris@1333 631 }
Chris@1333 632
Chris@709 633 if (m_middleLineHeight != 0.5) {
Chris@709 634 paint->restore();
Chris@709 635 }
Chris@709 636
Chris@0 637 if (m_aggressive) {
Chris@1332 638 if (m_model->isReady() && rect == v->getPaintRect()) {
Chris@1266 639 m_cacheValid = true;
Chris@1266 640 m_cacheZoomLevel = zoomLevel;
Chris@1266 641 }
Chris@1266 642 paint->end();
Chris@1266 643 delete paint;
Chris@1266 644 viewPainter.drawPixmap(rect, *m_cache, rect);
Chris@0 645 }
Chris@0 646 }
Chris@0 647
Chris@1332 648 void
Chris@1338 649 WaveformLayer::getSummaryRanges(int minChannel, int maxChannel,
Chris@1338 650 bool mixingOrMerging,
Chris@1338 651 sv_frame_t frame0, sv_frame_t frame1,
Chris@1338 652 int blockSize, RangeVec &ranges)
Chris@1338 653 const
Chris@1338 654 {
Chris@1338 655 for (int ch = minChannel; ch <= maxChannel; ++ch) {
Chris@1338 656 ranges.push_back({});
Chris@1338 657 m_model->getSummaries(ch, frame0, frame1 - frame0,
Chris@1338 658 ranges[ch - minChannel], blockSize);
Chris@1338 659 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 660 SVCERR << "channel " << ch << ": " << ranges[ch - minChannel].size() << " ranges from " << frame0 << " to " << frame1 << " at zoom level " << blockSize << endl;
Chris@1338 661 #endif
Chris@1338 662 }
Chris@1338 663
Chris@1338 664 if (mixingOrMerging) {
Chris@1338 665 if (minChannel != 0 || maxChannel != 0) {
Chris@1338 666 SVCERR << "Internal error: min & max channels should be 0 when merging or mixing all channels" << endl;
Chris@1338 667 } else if (m_model->getChannelCount() > 1) {
Chris@1338 668 ranges.push_back({});
Chris@1338 669 m_model->getSummaries
Chris@1338 670 (1, frame0, frame1 - frame0, ranges[1], blockSize);
Chris@1338 671 }
Chris@1338 672 }
Chris@1338 673 }
Chris@1338 674
Chris@1338 675 void
Chris@1338 676 WaveformLayer::getOversampledRanges(int minChannel, int maxChannel,
Chris@1343 677 bool /* mixingOrMerging */,
Chris@1338 678 sv_frame_t frame0, sv_frame_t frame1,
Chris@1338 679 int oversampleBy, RangeVec &ranges)
Chris@1338 680 const
Chris@1338 681 {
Chris@1338 682 // These frame values, tail length, etc variables are at the model
Chris@1338 683 // sample rate, not the oversampled rate
Chris@1338 684
Chris@1338 685 sv_frame_t tail = 16;
Chris@1338 686 sv_frame_t startFrame = m_model->getStartFrame();
Chris@1338 687 sv_frame_t endFrame = m_model->getEndFrame();
Chris@1338 688
Chris@1338 689 sv_frame_t rf0 = frame0 - tail;
Chris@1338 690 if (rf0 < startFrame) {
Chris@1338 691 rf0 = 0;
Chris@1338 692 }
Chris@1338 693
Chris@1338 694 sv_frame_t rf1 = frame1 + tail;
Chris@1338 695 if (rf1 >= endFrame) {
Chris@1338 696 rf1 = endFrame - 1;
Chris@1338 697 }
Chris@1338 698 if (rf1 <= rf0) {
Chris@1338 699 SVCERR << "WARNING: getOversampledRanges: rf1 (" << rf1 << ") <= rf0 ("
Chris@1338 700 << rf0 << ")" << endl;
Chris@1338 701 return;
Chris@1338 702 }
Chris@1338 703
Chris@1338 704 for (int ch = minChannel; ch <= maxChannel; ++ch) {
Chris@1339 705 floatvec_t oversampled = WaveformOversampler::getOversampledData
Chris@1339 706 (m_model, ch, frame0, frame1 - frame0, oversampleBy);
Chris@1338 707 RangeSummarisableTimeValueModel::RangeBlock rr;
Chris@1339 708 for (float v: oversampled) {
Chris@1338 709 RangeSummarisableTimeValueModel::Range r;
Chris@1339 710 r.sample(v);
Chris@1338 711 rr.push_back(r);
Chris@1338 712 }
Chris@1338 713 ranges.push_back(rr);
Chris@1338 714
Chris@1338 715 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 716 SVCERR << "getOversampledRanges: " << frame0 << " -> " << frame1
Chris@1338 717 << " (" << frame1 - frame0 << "-frame range) at ratio "
Chris@1338 718 << oversampleBy << " with tail " << tail
Chris@1338 719 << " -> got " << oversampled.size()
Chris@1338 720 << " oversampled values for channel " << ch
Chris@1338 721 << ", from which returning " << rr.size() << " ranges" << endl;
Chris@1338 722 #endif
Chris@1338 723 }
Chris@1338 724
Chris@1338 725 //!!! + channel modes
Chris@1338 726
Chris@1338 727 return;
Chris@1338 728 }
Chris@1338 729
Chris@1338 730 void
Chris@1338 731 WaveformLayer::paintChannel(LayerGeometryProvider *v,
Chris@1338 732 QPainter *paint,
Chris@1338 733 QRect rect, int ch,
Chris@1338 734 const RangeVec &ranges,
Chris@1338 735 int blockSize,
Chris@1352 736 sv_frame_t frame0,
Chris@1352 737 sv_frame_t frame1)
Chris@1332 738 const
Chris@1332 739 {
Chris@1334 740 int x0 = rect.left();
Chris@1334 741 int y0 = rect.top();
Chris@1334 742
Chris@1334 743 int x1 = rect.right();
Chris@1334 744 int y1 = rect.bottom();
Chris@1334 745
Chris@1332 746 int h = v->getPaintHeight();
Chris@1332 747
Chris@1332 748 int channels = 0, minChannel = 0, maxChannel = 0;
Chris@1332 749 bool mergingChannels = false, mixingChannels = false;
Chris@1332 750
Chris@1332 751 channels = getChannelArrangement(minChannel, maxChannel,
Chris@1332 752 mergingChannels, mixingChannels);
Chris@1332 753 if (channels == 0) return;
Chris@1332 754
Chris@1332 755 QColor baseColour = getBaseQColor();
Chris@1333 756 vector<QColor> greys = getPartialShades(v);
Chris@1332 757
Chris@1332 758 QColor midColour = baseColour;
Chris@1332 759 if (midColour == Qt::black) {
Chris@1332 760 midColour = Qt::gray;
Chris@1332 761 } else if (v->hasLightBackground()) {
Chris@1332 762 midColour = midColour.light(150);
Chris@1332 763 } else {
Chris@1332 764 midColour = midColour.light(50);
Chris@1332 765 }
Chris@1332 766
Chris@1332 767 int prevRangeBottom = -1, prevRangeTop = -1;
Chris@1332 768 QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour;
Chris@1332 769
Chris@1332 770 double gain = m_effectiveGains[ch];
Chris@1332 771
Chris@1332 772 int m = (h / channels) / 2;
Chris@1332 773 int my = m + (((ch - minChannel) * h) / channels);
Chris@1332 774
Chris@1332 775 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 776 SVCERR << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << endl;
Chris@1332 777 #endif
Chris@1332 778
Chris@1332 779 if (my - m > y1 || my + m < y0) return;
Chris@1332 780
Chris@1332 781 if ((m_scale == dBScale || m_scale == MeterScale) &&
Chris@1332 782 m_channelMode != MergeChannels) {
Chris@1332 783 m = (h / channels);
Chris@1332 784 my = m + (((ch - minChannel) * h) / channels);
Chris@1332 785 }
Chris@1332 786
Chris@1332 787 paint->setPen(greys[1]);
Chris@1332 788 paint->drawLine(x0, my, x1, my);
Chris@1332 789
Chris@1335 790 paintChannelScaleGuides(v, paint, rect, ch);
Chris@1332 791
Chris@1333 792 int rangeix = ch - minChannel;
Chris@1338 793
Chris@1338 794 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 795 SVCERR << "paint channel " << ch << ": frame0 = " << frame0 << ", frame1 = " << frame1 << ", blockSize = " << blockSize << ", have " << ranges.size() << " range blocks of which ours is index " << rangeix << " with " << ranges[rangeix].size() << " ranges in it" << endl;
Chris@1352 796 #else
Chris@1352 797 (void)frame1; // not actually used
Chris@1338 798 #endif
Chris@1338 799
Chris@1332 800 for (int x = x0; x <= x1; ++x) {
Chris@1332 801
Chris@1332 802 sv_frame_t f0, f1;
Chris@1338 803 sv_frame_t i0, i1;
Chris@1338 804
Chris@1338 805 bool showIndividualSample = false;
Chris@1338 806
Chris@1338 807 if (v->getZoomLevel().zone == ZoomLevel::FramesPerPixel) {
Chris@1338 808 if (!getSourceFramesForX(v, x, blockSize, f0, f1)) {
Chris@1338 809 continue;
Chris@1338 810 }
Chris@1338 811 f1 = f1 - 1;
Chris@1338 812 i0 = (f0 - frame0) / blockSize;
Chris@1338 813 i1 = (f1 - frame0) / blockSize;
Chris@1338 814 } else {
Chris@1338 815 int oversampleBy = v->getZoomLevel().level;
Chris@1338 816 f0 = f1 = v->getFrameForX(x);
Chris@1338 817 int xf0 = v->getXForFrame(f0);
Chris@1338 818 showIndividualSample = (x == xf0);
Chris@1338 819 i0 = i1 = (f0 - frame0) * oversampleBy + (x - xf0);
Chris@1338 820 }
Chris@1332 821
Chris@1332 822 if (f0 < frame0) {
Chris@1338 823 SVCERR << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << endl;
Chris@1332 824 continue;
Chris@1332 825 }
Chris@1332 826
Chris@1338 827 #ifdef DEBUG_WAVEFORM_PAINT_BY_PIXEL
Chris@1338 828 SVCERR << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << endl;
Chris@1332 829 #endif
Chris@1332 830
Chris@1332 831 if (i1 > i0 + 1) {
Chris@1338 832 SVCERR << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << v->getZoomLevel() << ", model zoom = " << blockSize << ")" << endl;
Chris@1332 833 }
Chris@1332 834
Chris@1333 835 const auto &r = ranges[rangeix];
Chris@1333 836 RangeSummarisableTimeValueModel::Range range;
Chris@1333 837
Chris@1333 838 if (in_range_for(r, i0)) {
Chris@1332 839
Chris@1333 840 range = r[i0];
Chris@1332 841
Chris@1333 842 if (i1 > i0 && in_range_for(r, i1)) {
Chris@1333 843 range.setMax(std::max(range.max(), r[i1].max()));
Chris@1333 844 range.setMin(std::min(range.min(), r[i1].min()));
Chris@1333 845 range.setAbsmean((range.absmean() + r[i1].absmean()) / 2);
Chris@1332 846 }
Chris@1332 847
Chris@1332 848 } else {
Chris@1332 849 #ifdef DEBUG_WAVEFORM_PAINT
Chris@1338 850 SVCERR << "No (or not enough) ranges for index i0 = " << i0 << " (there are " << r.size() << " range(s))" << endl;
Chris@1332 851 #endif
Chris@1332 852 continue;
Chris@1332 853 }
Chris@1332 854
Chris@1332 855 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0;
Chris@1332 856
Chris@1333 857 if (mergingChannels && ranges.size() > 1) {
Chris@1332 858
Chris@1333 859 const auto &other = ranges[1];
Chris@1333 860
Chris@1333 861 if (in_range_for(other, i0)) {
Chris@1332 862
Chris@1332 863 range.setMax(fabsf(range.max()));
Chris@1333 864 range.setMin(-fabsf(other[i0].max()));
Chris@1332 865 range.setAbsmean
Chris@1333 866 ((range.absmean() + other[i0].absmean()) / 2);
Chris@1332 867
Chris@1333 868 if (i1 > i0 && in_range_for(other, i1)) {
Chris@1332 869 // let's not concern ourselves about the mean
Chris@1333 870 range.setMin(std::min(range.min(),
Chris@1333 871 -fabsf(other[i1].max())));
Chris@1332 872 }
Chris@1332 873 }
Chris@1332 874
Chris@1333 875 } else if (mixingChannels && ranges.size() > 1) {
Chris@1332 876
Chris@1333 877 const auto &other = ranges[1];
Chris@1333 878
Chris@1333 879 if (in_range_for(other, i0)) {
Chris@1332 880
Chris@1333 881 range.setMax((range.max() + other[i0].max()) / 2);
Chris@1333 882 range.setMin((range.min() + other[i0].min()) / 2);
Chris@1333 883 range.setAbsmean((range.absmean() + other[i0].absmean()) / 2);
Chris@1332 884 }
Chris@1332 885 }
Chris@1332 886
Chris@1332 887 int greyLevels = 1;
Chris@1332 888 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4;
Chris@1332 889
Chris@1332 890 switch (m_scale) {
Chris@1332 891
Chris@1332 892 case LinearScale:
Chris@1332 893 rangeBottom = int(double(m * greyLevels) * range.min() * gain);
Chris@1332 894 rangeTop = int(double(m * greyLevels) * range.max() * gain);
Chris@1332 895 meanBottom = int(double(-m) * range.absmean() * gain);
Chris@1332 896 meanTop = int(double(m) * range.absmean() * gain);
Chris@1332 897 break;
Chris@1332 898
Chris@1332 899 case dBScale:
Chris@1332 900 if (!mergingChannels) {
Chris@1332 901 int db0 = dBscale(range.min() * gain, m);
Chris@1332 902 int db1 = dBscale(range.max() * gain, m);
Chris@1332 903 rangeTop = std::max(db0, db1);
Chris@1332 904 meanTop = std::min(db0, db1);
Chris@1332 905 if (mixingChannels) rangeBottom = meanTop;
Chris@1332 906 else rangeBottom = dBscale(range.absmean() * gain, m);
Chris@1332 907 meanBottom = rangeBottom;
Chris@1332 908 } else {
Chris@1332 909 rangeBottom = -dBscale(range.min() * gain, m * greyLevels);
Chris@1332 910 rangeTop = dBscale(range.max() * gain, m * greyLevels);
Chris@1332 911 meanBottom = -dBscale(range.absmean() * gain, m);
Chris@1332 912 meanTop = dBscale(range.absmean() * gain, m);
Chris@1332 913 }
Chris@1332 914 break;
Chris@1332 915
Chris@1332 916 case MeterScale:
Chris@1332 917 if (!mergingChannels) {
Chris@1332 918 int r0 = abs(AudioLevel::multiplier_to_preview(range.min() * gain, m));
Chris@1332 919 int r1 = abs(AudioLevel::multiplier_to_preview(range.max() * gain, m));
Chris@1332 920 rangeTop = std::max(r0, r1);
Chris@1332 921 meanTop = std::min(r0, r1);
Chris@1332 922 if (mixingChannels) rangeBottom = meanTop;
Chris@1332 923 else rangeBottom = AudioLevel::multiplier_to_preview(range.absmean() * gain, m);
Chris@1332 924 meanBottom = rangeBottom;
Chris@1332 925 } else {
Chris@1332 926 rangeBottom = -AudioLevel::multiplier_to_preview(range.min() * gain, m * greyLevels);
Chris@1332 927 rangeTop = AudioLevel::multiplier_to_preview(range.max() * gain, m * greyLevels);
Chris@1332 928 meanBottom = -AudioLevel::multiplier_to_preview(range.absmean() * gain, m);
Chris@1332 929 meanTop = AudioLevel::multiplier_to_preview(range.absmean() * gain, m);
Chris@1332 930 }
Chris@1332 931 break;
Chris@1332 932 }
Chris@1332 933
Chris@1332 934 rangeBottom = my * greyLevels - rangeBottom;
Chris@1332 935 rangeTop = my * greyLevels - rangeTop;
Chris@1332 936 meanBottom = my - meanBottom;
Chris@1332 937 meanTop = my - meanTop;
Chris@1332 938
Chris@1332 939 int topFill = (rangeTop % greyLevels);
Chris@1332 940 if (topFill > 0) topFill = greyLevels - topFill;
Chris@1332 941
Chris@1332 942 int bottomFill = (rangeBottom % greyLevels);
Chris@1332 943
Chris@1332 944 rangeTop = rangeTop / greyLevels;
Chris@1332 945 rangeBottom = rangeBottom / greyLevels;
Chris@1332 946
Chris@1332 947 bool clipped = false;
Chris@1332 948
Chris@1332 949 if (rangeTop < my - m) { rangeTop = my - m; }
Chris@1332 950 if (rangeTop > my + m) { rangeTop = my + m; }
Chris@1332 951 if (rangeBottom < my - m) { rangeBottom = my - m; }
Chris@1332 952 if (rangeBottom > my + m) { rangeBottom = my + m; }
Chris@1332 953
Chris@1332 954 if (range.max() <= -1.0 ||
Chris@1332 955 range.max() >= 1.0) clipped = true;
Chris@1332 956
Chris@1332 957 if (meanBottom > rangeBottom) meanBottom = rangeBottom;
Chris@1332 958 if (meanTop < rangeTop) meanTop = rangeTop;
Chris@1332 959
Chris@1332 960 bool drawMean = m_showMeans;
Chris@1332 961 if (meanTop == rangeTop) {
Chris@1332 962 if (meanTop < meanBottom) ++meanTop;
Chris@1332 963 else drawMean = false;
Chris@1332 964 }
Chris@1332 965 if (meanBottom == rangeBottom && m_scale == LinearScale) {
Chris@1332 966 if (meanBottom > meanTop) --meanBottom;
Chris@1332 967 else drawMean = false;
Chris@1332 968 }
Chris@1332 969
Chris@1338 970 if (showIndividualSample) {
Chris@1338 971 paint->setPen(baseColour);
Chris@1344 972 paint->drawRect(x-1, rangeTop-1, 2, 2);
Chris@1338 973 }
Chris@1338 974
Chris@1332 975 if (x != x0 && prevRangeBottom != -1) {
Chris@1332 976 if (prevRangeBottom > rangeBottom + 1 &&
Chris@1332 977 prevRangeTop > rangeBottom + 1) {
Chris@1332 978 // paint->setPen(midColour);
Chris@1332 979 paint->setPen(baseColour);
Chris@1332 980 paint->drawLine(x-1, prevRangeTop, x, rangeBottom + 1);
Chris@1332 981 paint->setPen(prevRangeTopColour);
Chris@1332 982 paint->drawPoint(x-1, prevRangeTop);
Chris@1332 983 } else if (prevRangeBottom < rangeTop - 1 &&
Chris@1332 984 prevRangeTop < rangeTop - 1) {
Chris@1332 985 // paint->setPen(midColour);
Chris@1332 986 paint->setPen(baseColour);
Chris@1332 987 paint->drawLine(x-1, prevRangeBottom, x, rangeTop - 1);
Chris@1332 988 paint->setPen(prevRangeBottomColour);
Chris@1332 989 paint->drawPoint(x-1, prevRangeBottom);
Chris@1332 990 }
Chris@1332 991 }
Chris@1332 992
Chris@1332 993 if (m_model->isReady()) {
Chris@1332 994 if (clipped /*!!! ||
Chris@1332 995 range.min() * gain <= -1.0 ||
Chris@1332 996 range.max() * gain >= 1.0 */) {
Chris@1332 997 paint->setPen(Qt::red); //!!! getContrastingColour
Chris@1332 998 } else {
Chris@1332 999 paint->setPen(baseColour);
Chris@1332 1000 }
Chris@1332 1001 } else {
Chris@1332 1002 paint->setPen(midColour);
Chris@1332 1003 }
Chris@1332 1004
Chris@1338 1005 #ifdef DEBUG_WAVEFORM_PAINT_BY_PIXEL
Chris@1338 1006 SVCERR << "range " << rangeBottom << " -> " << rangeTop << ", means " << meanBottom << " -> " << meanTop << ", raw range " << range.min() << " -> " << range.max() << endl;
Chris@1332 1007 #endif
Chris@1332 1008
Chris@1332 1009 if (rangeTop == rangeBottom) {
Chris@1332 1010 paint->drawPoint(x, rangeTop);
Chris@1332 1011 } else {
Chris@1332 1012 paint->drawLine(x, rangeBottom, x, rangeTop);
Chris@1332 1013 }
Chris@1332 1014
Chris@1332 1015 prevRangeTopColour = baseColour;
Chris@1332 1016 prevRangeBottomColour = baseColour;
Chris@1332 1017
Chris@1332 1018 if (m_greyscale && (m_scale == LinearScale) && m_model->isReady()) {
Chris@1332 1019 if (!clipped) {
Chris@1332 1020 if (rangeTop < rangeBottom) {
Chris@1332 1021 if (topFill > 0 &&
Chris@1332 1022 (!drawMean || (rangeTop < meanTop - 1))) {
Chris@1332 1023 paint->setPen(greys[topFill - 1]);
Chris@1332 1024 paint->drawPoint(x, rangeTop);
Chris@1332 1025 prevRangeTopColour = greys[topFill - 1];
Chris@1332 1026 }
Chris@1332 1027 if (bottomFill > 0 &&
Chris@1332 1028 (!drawMean || (rangeBottom > meanBottom + 1))) {
Chris@1332 1029 paint->setPen(greys[bottomFill - 1]);
Chris@1332 1030 paint->drawPoint(x, rangeBottom);
Chris@1332 1031 prevRangeBottomColour = greys[bottomFill - 1];
Chris@1332 1032 }
Chris@1332 1033 }
Chris@1332 1034 }
Chris@1332 1035 }
Chris@1332 1036
Chris@1332 1037 if (drawMean) {
Chris@1332 1038 paint->setPen(midColour);
Chris@1332 1039 paint->drawLine(x, meanBottom, x, meanTop);
Chris@1332 1040 }
Chris@1332 1041
Chris@1332 1042 prevRangeBottom = rangeBottom;
Chris@1332 1043 prevRangeTop = rangeTop;
Chris@1332 1044 }
Chris@1332 1045 }
Chris@1332 1046
Chris@1335 1047 void
Chris@1335 1048 WaveformLayer::paintChannelScaleGuides(LayerGeometryProvider *v,
Chris@1335 1049 QPainter *paint,
Chris@1335 1050 QRect rect,
Chris@1335 1051 int ch) const
Chris@1335 1052 {
Chris@1335 1053 int x0 = rect.left();
Chris@1335 1054 int x1 = rect.right();
Chris@1335 1055
Chris@1335 1056 int n = 10;
Chris@1335 1057 int py = -1;
Chris@1335 1058
Chris@1335 1059 double gain = m_effectiveGains[ch];
Chris@1335 1060
Chris@1335 1061 if (v->hasLightBackground() &&
Chris@1335 1062 v->getViewManager() &&
Chris@1335 1063 v->getViewManager()->shouldShowScaleGuides()) {
Chris@1335 1064
Chris@1335 1065 paint->setPen(QColor(240, 240, 240));
Chris@1335 1066
Chris@1335 1067 for (int i = 1; i < n; ++i) {
Chris@1335 1068
Chris@1335 1069 double val = 0.0, nval = 0.0;
Chris@1335 1070
Chris@1335 1071 switch (m_scale) {
Chris@1335 1072
Chris@1335 1073 case LinearScale:
Chris@1335 1074 val = (i * gain) / n;
Chris@1335 1075 if (i > 0) nval = -val;
Chris@1335 1076 break;
Chris@1335 1077
Chris@1335 1078 case MeterScale:
Chris@1335 1079 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
Chris@1335 1080 break;
Chris@1335 1081
Chris@1335 1082 case dBScale:
Chris@1335 1083 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
Chris@1335 1084 break;
Chris@1335 1085 }
Chris@1335 1086
Chris@1335 1087 if (val < -1.0 || val > 1.0) continue;
Chris@1335 1088
Chris@1335 1089 int y = getYForValue(v, val, ch);
Chris@1335 1090
Chris@1335 1091 if (py >= 0 && abs(y - py) < 10) continue;
Chris@1335 1092 else py = y;
Chris@1335 1093
Chris@1335 1094 int ny = y;
Chris@1335 1095 if (nval != 0.0) {
Chris@1335 1096 ny = getYForValue(v, nval, ch);
Chris@1335 1097 }
Chris@1335 1098
Chris@1335 1099 paint->drawLine(x0, y, x1, y);
Chris@1335 1100 if (ny != y) {
Chris@1335 1101 paint->drawLine(x0, ny, x1, ny);
Chris@1335 1102 }
Chris@1335 1103 }
Chris@1335 1104 }
Chris@1335 1105 }
Chris@1335 1106
Chris@25 1107 QString
Chris@918 1108 WaveformLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
Chris@25 1109 {
Chris@25 1110 int x = pos.x();
Chris@25 1111
Chris@25 1112 if (!m_model || !m_model->isOK()) return "";
Chris@25 1113
Chris@1325 1114 ZoomLevel zoomLevel = v->getZoomLevel();
Chris@25 1115
Chris@1325 1116 int desiredBlockSize = 1;
Chris@1325 1117 if (zoomLevel.zone == ZoomLevel::FramesPerPixel) {
Chris@1325 1118 desiredBlockSize = zoomLevel.level;
Chris@1325 1119 }
Chris@1325 1120
Chris@1325 1121 int blockSize = m_model->getSummaryBlockSize(desiredBlockSize);
Chris@365 1122
Chris@908 1123 sv_frame_t f0, f1;
Chris@1325 1124 if (!getSourceFramesForX(v, x, blockSize, f0, f1)) return "";
Chris@25 1125
Chris@25 1126 QString text;
Chris@25 1127
Chris@25 1128 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate());
Chris@25 1129 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate());
Chris@25 1130
Chris@25 1131 if (f1 != f0 + 1 && (rt0.sec != rt1.sec || rt0.msec() != rt1.msec())) {
Chris@1266 1132 text += tr("Time:\t%1 - %2")
Chris@1266 1133 .arg(rt0.toText(true).c_str())
Chris@1266 1134 .arg(rt1.toText(true).c_str());
Chris@25 1135 } else {
Chris@1266 1136 text += tr("Time:\t%1")
Chris@1266 1137 .arg(rt0.toText(true).c_str());
Chris@25 1138 }
Chris@25 1139
Chris@805 1140 int channels = 0, minChannel = 0, maxChannel = 0;
Chris@67 1141 bool mergingChannels = false, mixingChannels = false;
Chris@25 1142
Chris@67 1143 channels = getChannelArrangement(minChannel, maxChannel,
Chris@67 1144 mergingChannels, mixingChannels);
Chris@25 1145 if (channels == 0) return "";
Chris@25 1146
Chris@805 1147 for (int ch = minChannel; ch <= maxChannel; ++ch) {
Chris@25 1148
Chris@1266 1149 RangeSummarisableTimeValueModel::RangeBlock ranges;
Chris@302 1150 m_model->getSummaries(ch, f0, f1 - f0, ranges, blockSize);
Chris@25 1151
Chris@1266 1152 if (ranges.empty()) continue;
Chris@1266 1153
Chris@1266 1154 RangeSummarisableTimeValueModel::Range range = ranges[0];
Chris@1266 1155
Chris@1266 1156 QString label = tr("Level:");
Chris@1266 1157 if (minChannel != maxChannel) {
Chris@1266 1158 if (ch == 0) label = tr("Left:");
Chris@1266 1159 else if (ch == 1) label = tr("Right:");
Chris@1266 1160 else label = tr("Channel %1").arg(ch + 1);
Chris@1266 1161 }
Chris@25 1162
Chris@76 1163 bool singleValue = false;
Chris@908 1164 double min, max;
Chris@76 1165
Chris@386 1166 if (fabs(range.min()) < 0.01) {
Chris@386 1167 min = range.min();
Chris@386 1168 max = range.max();
Chris@76 1169 singleValue = (min == max);
Chris@76 1170 } else {
Chris@908 1171 int imin = int(lrint(range.min() * 10000));
Chris@908 1172 int imax = int(lrint(range.max() * 10000));
Chris@76 1173 singleValue = (imin == imax);
Chris@908 1174 min = double(imin)/10000;
Chris@908 1175 max = double(imax)/10000;
Chris@76 1176 }
Chris@76 1177
Chris@1266 1178 int db = int(AudioLevel::multiplier_to_dB(std::max(fabsf(range.min()),
Chris@1266 1179 fabsf(range.max())))
Chris@1266 1180 * 100);
Chris@25 1181
Chris@1266 1182 if (!singleValue) {
Chris@1266 1183 text += tr("\n%1\t%2 - %3 (%4 dB peak)")
Chris@1266 1184 .arg(label).arg(min).arg(max).arg(double(db)/100);
Chris@1266 1185 } else {
Chris@1266 1186 text += tr("\n%1\t%2 (%3 dB peak)")
Chris@1266 1187 .arg(label).arg(min).arg(double(db)/100);
Chris@1266 1188 }
Chris@25 1189 }
Chris@25 1190
Chris@25 1191 return text;
Chris@25 1192 }
Chris@25 1193
Chris@0 1194 int
Chris@918 1195 WaveformLayer::getYForValue(const LayerGeometryProvider *v, double value, int channel) const
Chris@68 1196 {
Chris@805 1197 int channels = 0, minChannel = 0, maxChannel = 0;
Chris@274 1198 bool mergingChannels = false, mixingChannels = false;
Chris@274 1199
Chris@274 1200 channels = getChannelArrangement(minChannel, maxChannel,
Chris@274 1201 mergingChannels, mixingChannels);
Chris@853 1202 if (channels == 0) return 0;
Chris@68 1203 if (maxChannel < minChannel || channel < minChannel) return 0;
Chris@68 1204
Chris@918 1205 int h = v->getPaintHeight();
Chris@68 1206 int m = (h / channels) / 2;
Chris@1266 1207
Chris@68 1208 if ((m_scale == dBScale || m_scale == MeterScale) &&
Chris@68 1209 m_channelMode != MergeChannels) {
Chris@68 1210 m = (h / channels);
Chris@68 1211 }
Chris@68 1212
Chris@274 1213 int my = m + (((channel - minChannel) * h) / channels);
Chris@274 1214
Chris@68 1215 int vy = 0;
Chris@68 1216
Chris@274 1217 switch (m_scale) {
Chris@68 1218
Chris@68 1219 case LinearScale:
Chris@68 1220 vy = int(m * value);
Chris@68 1221 break;
Chris@68 1222
Chris@68 1223 case MeterScale:
Chris@68 1224 vy = AudioLevel::multiplier_to_preview(value, m);
Chris@68 1225 break;
Chris@68 1226
Chris@68 1227 case dBScale:
Chris@68 1228 vy = dBscale(value, m);
Chris@68 1229 break;
Chris@68 1230 }
Chris@68 1231
Chris@1338 1232 // SVCERR << "mergingChannels= " << mergingChannels << ", channel = " << channel << ", value = " << value << ", vy = " << vy << endl;
Chris@324 1233
Chris@68 1234 return my - vy;
Chris@68 1235 }
Chris@68 1236
Chris@908 1237 double
Chris@918 1238 WaveformLayer::getValueForY(const LayerGeometryProvider *v, int y, int &channel) const
Chris@261 1239 {
Chris@805 1240 int channels = 0, minChannel = 0, maxChannel = 0;
Chris@274 1241 bool mergingChannels = false, mixingChannels = false;
Chris@274 1242
Chris@274 1243 channels = getChannelArrangement(minChannel, maxChannel,
Chris@274 1244 mergingChannels, mixingChannels);
Chris@853 1245 if (channels == 0) return 0;
Chris@261 1246 if (maxChannel < minChannel) return 0;
Chris@261 1247
Chris@918 1248 int h = v->getPaintHeight();
Chris@261 1249 int m = (h / channels) / 2;
Chris@261 1250
Chris@261 1251 if ((m_scale == dBScale || m_scale == MeterScale) &&
Chris@261 1252 m_channelMode != MergeChannels) {
Chris@261 1253 m = (h / channels);
Chris@261 1254 }
Chris@274 1255
Chris@274 1256 channel = (y * channels) / h + minChannel;
Chris@261 1257
Chris@261 1258 int my = m + (((channel - minChannel) * h) / channels);
Chris@261 1259
Chris@262 1260 int vy = my - y;
Chris@908 1261 double value = 0;
Chris@908 1262 double thresh = -50.f;
Chris@261 1263
Chris@274 1264 switch (m_scale) {
Chris@261 1265
Chris@261 1266 case LinearScale:
Chris@908 1267 value = double(vy) / m;
Chris@261 1268 break;
Chris@261 1269
Chris@261 1270 case MeterScale:
Chris@261 1271 value = AudioLevel::preview_to_multiplier(vy, m);
Chris@261 1272 break;
Chris@261 1273
Chris@261 1274 case dBScale:
Chris@908 1275 value = (-thresh * double(vy)) / m + thresh;
Chris@274 1276 value = AudioLevel::dB_to_multiplier(value);
Chris@261 1277 break;
Chris@261 1278 }
Chris@261 1279
Chris@274 1280 return value / m_gain;
Chris@261 1281 }
Chris@261 1282
Chris@261 1283 bool
Chris@918 1284 WaveformLayer::getYScaleValue(const LayerGeometryProvider *v, int y,
Chris@908 1285 double &value, QString &unit) const
Chris@261 1286 {
Chris@805 1287 int channel;
Chris@261 1288
Chris@274 1289 value = getValueForY(v, y, channel);
Chris@261 1290
Chris@274 1291 if (m_scale == dBScale || m_scale == MeterScale) {
Chris@261 1292
Chris@908 1293 double thresh = -50.f;
Chris@274 1294
Chris@908 1295 if (value > 0.0) {
Chris@908 1296 value = 10.0 * log10(value);
Chris@274 1297 if (value < thresh) value = thresh;
Chris@274 1298 } else value = thresh;
Chris@274 1299
Chris@274 1300 unit = "dBV";
Chris@274 1301
Chris@274 1302 } else {
Chris@274 1303 unit = "V";
Chris@274 1304 }
Chris@274 1305
Chris@274 1306 return true;
Chris@274 1307 }
Chris@274 1308
Chris@274 1309 bool
Chris@918 1310 WaveformLayer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1,
Chris@908 1311 double &diff, QString &unit) const
Chris@274 1312 {
Chris@805 1313 int c0, c1;
Chris@908 1314 double v0 = getValueForY(v, y0, c0);
Chris@908 1315 double v1 = getValueForY(v, y1, c1);
Chris@274 1316
Chris@274 1317 if (c0 != c1) {
Chris@274 1318 // different channels, not comparable
Chris@908 1319 diff = 0.0;
Chris@274 1320 unit = "";
Chris@274 1321 return false;
Chris@274 1322 }
Chris@274 1323
Chris@274 1324 if (m_scale == dBScale || m_scale == MeterScale) {
Chris@274 1325
Chris@908 1326 double thresh = -50.0;
Chris@274 1327
Chris@274 1328 if (v1 == v0) diff = thresh;
Chris@274 1329 else {
Chris@274 1330 if (v1 > v0) diff = v0 / v1;
Chris@274 1331 else diff = v1 / v0;
Chris@274 1332
Chris@908 1333 diff = 10.0 * log10(diff);
Chris@274 1334 if (diff < thresh) diff = thresh;
Chris@274 1335 }
Chris@274 1336
Chris@274 1337 unit = "dBV";
Chris@274 1338
Chris@274 1339 } else {
Chris@908 1340 diff = fabs(v1 - v0);
Chris@274 1341 unit = "V";
Chris@274 1342 }
Chris@274 1343
Chris@261 1344 return true;
Chris@261 1345 }
Chris@261 1346
Chris@68 1347 int
Chris@918 1348 WaveformLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const
Chris@0 1349 {
Chris@0 1350 if (m_scale == LinearScale) {
Chris@1266 1351 return paint.fontMetrics().width("0.0") + 13;
Chris@0 1352 } else {
Chris@1266 1353 return std::max(paint.fontMetrics().width(tr("0dB")),
Chris@1266 1354 paint.fontMetrics().width(Strings::minus_infinity)) + 13;
Chris@0 1355 }
Chris@0 1356 }
Chris@0 1357
Chris@0 1358 void
Chris@918 1359 WaveformLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect rect) const
Chris@0 1360 {
Chris@0 1361 if (!m_model || !m_model->isOK()) {
Chris@1266 1362 return;
Chris@0 1363 }
Chris@0 1364
Chris@805 1365 int channels = 0, minChannel = 0, maxChannel = 0;
Chris@67 1366 bool mergingChannels = false, mixingChannels = false;
Chris@0 1367
Chris@67 1368 channels = getChannelArrangement(minChannel, maxChannel,
Chris@67 1369 mergingChannels, mixingChannels);
Chris@0 1370 if (channels == 0) return;
Chris@0 1371
Chris@0 1372 int h = rect.height(), w = rect.width();
Chris@0 1373 int textHeight = paint.fontMetrics().height();
Chris@0 1374 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
Chris@0 1375
Chris@908 1376 double gain = m_gain;
Chris@67 1377
Chris@805 1378 for (int ch = minChannel; ch <= maxChannel; ++ch) {
Chris@0 1379
Chris@1266 1380 int lastLabelledY = -1;
Chris@0 1381
Chris@805 1382 if (ch < (int)m_effectiveGains.size()) gain = m_effectiveGains[ch];
Chris@67 1383
Chris@68 1384 int n = 10;
Chris@0 1385
Chris@1266 1386 for (int i = 0; i <= n; ++i) {
Chris@68 1387
Chris@908 1388 double val = 0.0, nval = 0.0;
Chris@1266 1389 QString text = "";
Chris@0 1390
Chris@68 1391 switch (m_scale) {
Chris@68 1392
Chris@68 1393 case LinearScale:
Chris@68 1394 val = (i * gain) / n;
Chris@1266 1395 text = QString("%1").arg(double(i) / n);
Chris@1266 1396 if (i == 0) text = "0.0";
Chris@68 1397 else {
Chris@68 1398 nval = -val;
Chris@68 1399 if (i == n) text = "1.0";
Chris@68 1400 }
Chris@68 1401 break;
Chris@0 1402
Chris@68 1403 case MeterScale:
Chris@68 1404 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
Chris@1266 1405 text = QString("%1").arg(meterdbs[i]);
Chris@1266 1406 if (i == n) text = tr("0dB");
Chris@1266 1407 if (i == 0) {
Chris@1147 1408 text = Strings::minus_infinity;
Chris@68 1409 val = 0.0;
Chris@1266 1410 }
Chris@68 1411 break;
Chris@0 1412
Chris@68 1413 case dBScale:
Chris@68 1414 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
Chris@1266 1415 text = QString("%1").arg(-(10*n) + i * 10);
Chris@1266 1416 if (i == n) text = tr("0dB");
Chris@1266 1417 if (i == 0) {
Chris@1147 1418 text = Strings::minus_infinity;
Chris@68 1419 val = 0.0;
Chris@1266 1420 }
Chris@68 1421 break;
Chris@68 1422 }
Chris@0 1423
Chris@68 1424 if (val < -1.0 || val > 1.0) continue;
Chris@0 1425
Chris@274 1426 int y = getYForValue(v, val, ch);
Chris@0 1427
Chris@68 1428 int ny = y;
Chris@68 1429 if (nval != 0.0) {
Chris@274 1430 ny = getYForValue(v, nval, ch);
Chris@68 1431 }
Chris@0 1432
Chris@68 1433 bool spaceForLabel = (i == 0 ||
Chris@68 1434 abs(y - lastLabelledY) >= textHeight - 1);
Chris@0 1435
Chris@68 1436 if (spaceForLabel) {
Chris@0 1437
Chris@68 1438 int tx = 3;
Chris@68 1439 if (m_scale != LinearScale) {
Chris@68 1440 tx = w - 10 - paint.fontMetrics().width(text);
Chris@68 1441 }
Chris@68 1442
Chris@68 1443 int ty = y;
Chris@68 1444 if (ty < paint.fontMetrics().ascent()) {
Chris@68 1445 ty = paint.fontMetrics().ascent();
Chris@68 1446 } else if (ty > h - paint.fontMetrics().descent()) {
Chris@68 1447 ty = h - paint.fontMetrics().descent();
Chris@68 1448 } else {
Chris@68 1449 ty += toff;
Chris@68 1450 }
Chris@68 1451 paint.drawText(tx, ty, text);
Chris@0 1452
Chris@68 1453 lastLabelledY = ty - toff;
Chris@67 1454
Chris@68 1455 if (ny != y) {
Chris@68 1456 ty = ny;
Chris@68 1457 if (ty < paint.fontMetrics().ascent()) {
Chris@68 1458 ty = paint.fontMetrics().ascent();
Chris@68 1459 } else if (ty > h - paint.fontMetrics().descent()) {
Chris@68 1460 ty = h - paint.fontMetrics().descent();
Chris@68 1461 } else {
Chris@68 1462 ty += toff;
Chris@68 1463 }
Chris@68 1464 paint.drawText(tx, ty, text);
Chris@68 1465 }
Chris@68 1466
Chris@68 1467 paint.drawLine(w - 7, y, w, y);
Chris@68 1468 if (ny != y) paint.drawLine(w - 7, ny, w, ny);
Chris@68 1469
Chris@68 1470 } else {
Chris@68 1471
Chris@68 1472 paint.drawLine(w - 4, y, w, y);
Chris@68 1473 if (ny != y) paint.drawLine(w - 4, ny, w, ny);
Chris@68 1474 }
Chris@1266 1475 }
Chris@0 1476 }
Chris@0 1477 }
Chris@0 1478
Chris@316 1479 void
Chris@316 1480 WaveformLayer::toXml(QTextStream &stream,
Chris@316 1481 QString indent, QString extraAttributes) const
Chris@6 1482 {
Chris@6 1483 QString s;
Chris@6 1484
Chris@285 1485 QString colourName, colourSpec, darkbg;
Chris@285 1486 ColourDatabase::getInstance()->getStringValues
Chris@285 1487 (m_colour, colourName, colourSpec, darkbg);
Chris@285 1488
Chris@6 1489 s += QString("gain=\"%1\" "
Chris@1266 1490 "showMeans=\"%2\" "
Chris@1266 1491 "greyscale=\"%3\" "
Chris@1266 1492 "channelMode=\"%4\" "
Chris@1266 1493 "channel=\"%5\" "
Chris@287 1494 "scale=\"%6\" "
Chris@709 1495 "middleLineHeight=\"%7\" "
Chris@1266 1496 "aggressive=\"%8\" "
Chris@709 1497 "autoNormalize=\"%9\"")
Chris@1266 1498 .arg(m_gain)
Chris@1266 1499 .arg(m_showMeans)
Chris@1266 1500 .arg(m_greyscale)
Chris@1266 1501 .arg(m_channelMode)
Chris@1266 1502 .arg(m_channel)
Chris@1266 1503 .arg(m_scale)
Chris@709 1504 .arg(m_middleLineHeight)
Chris@1266 1505 .arg(m_aggressive)
Chris@67 1506 .arg(m_autoNormalize);
Chris@6 1507
Chris@316 1508 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s);
Chris@6 1509 }
Chris@6 1510
Chris@11 1511 void
Chris@11 1512 WaveformLayer::setProperties(const QXmlAttributes &attributes)
Chris@11 1513 {
Chris@11 1514 bool ok = false;
Chris@11 1515
Chris@287 1516 SingleColourLayer::setProperties(attributes);
Chris@287 1517
Chris@11 1518 float gain = attributes.value("gain").toFloat(&ok);
Chris@11 1519 if (ok) setGain(gain);
Chris@11 1520
Chris@11 1521 bool showMeans = (attributes.value("showMeans") == "1" ||
Chris@1266 1522 attributes.value("showMeans") == "true");
Chris@11 1523 setShowMeans(showMeans);
Chris@11 1524
Chris@11 1525 bool greyscale = (attributes.value("greyscale") == "1" ||
Chris@1266 1526 attributes.value("greyscale") == "true");
Chris@11 1527 setUseGreyscale(greyscale);
Chris@11 1528
Chris@11 1529 ChannelMode channelMode = (ChannelMode)
Chris@1266 1530 attributes.value("channelMode").toInt(&ok);
Chris@11 1531 if (ok) setChannelMode(channelMode);
Chris@11 1532
Chris@11 1533 int channel = attributes.value("channel").toInt(&ok);
Chris@11 1534 if (ok) setChannel(channel);
Chris@11 1535
Chris@709 1536 Scale scale = (Scale)attributes.value("scale").toInt(&ok);
Chris@11 1537 if (ok) setScale(scale);
Chris@11 1538
Chris@709 1539 float middleLineHeight = attributes.value("middleLineHeight").toFloat(&ok);
Chris@709 1540 if (ok) setMiddleLineHeight(middleLineHeight);
Chris@709 1541
Chris@11 1542 bool aggressive = (attributes.value("aggressive") == "1" ||
Chris@1266 1543 attributes.value("aggressive") == "true");
Chris@11 1544 setUseGreyscale(aggressive);
Chris@67 1545
Chris@67 1546 bool autoNormalize = (attributes.value("autoNormalize") == "1" ||
Chris@67 1547 attributes.value("autoNormalize") == "true");
Chris@67 1548 setAutoNormalize(autoNormalize);
Chris@11 1549 }
Chris@11 1550
Chris@133 1551 int
Chris@133 1552 WaveformLayer::getVerticalZoomSteps(int &defaultStep) const
Chris@133 1553 {
Chris@133 1554 defaultStep = 50;
Chris@133 1555 return 100;
Chris@133 1556 }
Chris@0 1557
Chris@133 1558 int
Chris@133 1559 WaveformLayer::getCurrentVerticalZoomStep() const
Chris@133 1560 {
Chris@908 1561 int val = int(lrint(log10(m_gain) * 20.0) + 50);
Chris@133 1562 if (val < 0) val = 0;
Chris@133 1563 if (val > 100) val = 100;
Chris@133 1564 return val;
Chris@133 1565 }
Chris@133 1566
Chris@133 1567 void
Chris@133 1568 WaveformLayer::setVerticalZoomStep(int step)
Chris@133 1569 {
Chris@908 1570 setGain(powf(10, float(step - 50) / 20.f));
Chris@133 1571 }
Chris@133 1572