annotate layer/WaveformLayer.cpp @ 101:0f36cdf407a6 sv1-v0.9rc1

* Make vertical scale alignment modes work in note layer as well as time-value layer, and several significant fixes to it * Make it possible to draw notes properly on the note layer * Show units (and frequencies etc in note layer's case) in the time-value and note layer description boxes * Minor fix to item edit dialog layout * Some minor menu rearrangement * Comment out a lot of debug output * Add SV website and reference URLs to Help menu, and add code to (attempt to) open them in the user's preferred browser
author Chris Cannam
date Fri, 12 May 2006 14:40:43 +0000
parents 4b98bda7e94d
children 47cb32bb35ab
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@59 7 This file copyright 2006 Chris Cannam.
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@0 19 #include "base/View.h"
Chris@0 20 #include "base/Profiler.h"
Chris@0 21
Chris@0 22 #include <QPainter>
Chris@0 23 #include <QPixmap>
Chris@0 24
Chris@0 25 #include <iostream>
Chris@0 26 #include <cmath>
Chris@0 27
Chris@4 28 //#define DEBUG_WAVEFORM_PAINT 1
Chris@4 29
Chris@0 30 using std::cerr;
Chris@0 31 using std::endl;
Chris@0 32
Chris@44 33 WaveformLayer::WaveformLayer() :
Chris@44 34 Layer(),
Chris@0 35 m_model(0),
Chris@0 36 m_gain(1.0f),
Chris@67 37 m_autoNormalize(false),
Chris@0 38 m_colour(Qt::black),
Chris@0 39 m_showMeans(true),
Chris@0 40 m_greyscale(true),
Chris@0 41 m_channelMode(SeparateChannels),
Chris@0 42 m_channel(-1),
Chris@0 43 m_scale(LinearScale),
Chris@0 44 m_aggressive(false),
Chris@0 45 m_cache(0),
Chris@0 46 m_cacheValid(false)
Chris@0 47 {
Chris@44 48
Chris@0 49 }
Chris@0 50
Chris@0 51 WaveformLayer::~WaveformLayer()
Chris@0 52 {
Chris@0 53 delete m_cache;
Chris@0 54 }
Chris@0 55
Chris@0 56 void
Chris@0 57 WaveformLayer::setModel(const RangeSummarisableTimeValueModel *model)
Chris@0 58 {
Chris@69 59 bool channelsChanged = false;
Chris@69 60 if (m_channel == -1) {
Chris@69 61 if (!m_model) {
Chris@69 62 if (model) {
Chris@69 63 channelsChanged = true;
Chris@69 64 }
Chris@69 65 } else {
Chris@69 66 if (model &&
Chris@69 67 m_model->getChannelCount() != model->getChannelCount()) {
Chris@69 68 channelsChanged = true;
Chris@69 69 }
Chris@69 70 }
Chris@69 71 }
Chris@69 72
Chris@0 73 m_model = model;
Chris@0 74 m_cacheValid = false;
Chris@0 75 if (!m_model || !m_model->isOK()) return;
Chris@0 76
Chris@0 77 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@0 78 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 79 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@0 80
Chris@0 81 connect(m_model, SIGNAL(completionChanged()),
Chris@0 82 this, SIGNAL(modelCompletionChanged()));
Chris@0 83
Chris@0 84 emit modelReplaced();
Chris@69 85
Chris@69 86 if (channelsChanged) emit layerParametersChanged();
Chris@0 87 }
Chris@0 88
Chris@0 89 Layer::PropertyList
Chris@0 90 WaveformLayer::getProperties() const
Chris@0 91 {
Chris@0 92 PropertyList list;
Chris@87 93 list.push_back("Colour");
Chris@87 94 list.push_back("Scale");
Chris@87 95 list.push_back("Gain");
Chris@87 96 list.push_back("Normalize Visible Area");
Chris@68 97
Chris@68 98 if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) {
Chris@87 99 list.push_back("Channels");
Chris@68 100 }
Chris@68 101
Chris@0 102 return list;
Chris@0 103 }
Chris@0 104
Chris@87 105 QString
Chris@87 106 WaveformLayer::getPropertyLabel(const PropertyName &name) const
Chris@87 107 {
Chris@87 108 if (name == "Colour") return tr("Colour");
Chris@87 109 if (name == "Scale") return tr("Scale");
Chris@87 110 if (name == "Gain") return tr("Gain");
Chris@87 111 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
Chris@87 112 if (name == "Channels") return tr("Channels");
Chris@87 113 return "";
Chris@87 114 }
Chris@87 115
Chris@0 116 Layer::PropertyType
Chris@0 117 WaveformLayer::getPropertyType(const PropertyName &name) const
Chris@0 118 {
Chris@87 119 if (name == "Gain") return RangeProperty;
Chris@87 120 if (name == "Normalize Visible Area") return ToggleProperty;
Chris@87 121 if (name == "Colour") return ValueProperty;
Chris@87 122 if (name == "Channels") return ValueProperty;
Chris@87 123 if (name == "Scale") return ValueProperty;
Chris@0 124 return InvalidProperty;
Chris@0 125 }
Chris@0 126
Chris@0 127 QString
Chris@0 128 WaveformLayer::getPropertyGroupName(const PropertyName &name) const
Chris@0 129 {
Chris@87 130 if (name == "Gain" ||
Chris@87 131 name == "Normalize Visible Area" ||
Chris@87 132 name == "Scale") return tr("Scale");
Chris@0 133 return QString();
Chris@0 134 }
Chris@0 135
Chris@0 136 int
Chris@0 137 WaveformLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@67 138 int *min, int *max) const
Chris@0 139 {
Chris@0 140 int deft = 0;
Chris@0 141
Chris@56 142 int garbage0, garbage1;
Chris@56 143 if (!min) min = &garbage0;
Chris@56 144 if (!max) max = &garbage1;
Chris@10 145
Chris@87 146 if (name == "Gain") {
Chris@0 147
Chris@0 148 *min = -50;
Chris@0 149 *max = 50;
Chris@0 150
Chris@34 151 deft = lrint(log10(m_gain) * 20.0);
Chris@0 152 if (deft < *min) deft = *min;
Chris@0 153 if (deft > *max) deft = *max;
Chris@0 154
Chris@87 155 } else if (name == "Normalize Visible Area") {
Chris@67 156
Chris@67 157 deft = (m_autoNormalize ? 1 : 0);
Chris@67 158
Chris@87 159 } else if (name == "Colour") {
Chris@0 160
Chris@0 161 *min = 0;
Chris@0 162 *max = 5;
Chris@0 163
Chris@0 164 if (m_colour == Qt::black) deft = 0;
Chris@0 165 else if (m_colour == Qt::darkRed) deft = 1;
Chris@0 166 else if (m_colour == Qt::darkBlue) deft = 2;
Chris@0 167 else if (m_colour == Qt::darkGreen) deft = 3;
Chris@0 168 else if (m_colour == QColor(200, 50, 255)) deft = 4;
Chris@0 169 else if (m_colour == QColor(255, 150, 50)) deft = 5;
Chris@0 170
Chris@87 171 } else if (name == "Channels") {
Chris@0 172
Chris@67 173 *min = 0;
Chris@67 174 *max = 2;
Chris@67 175 if (m_channelMode == MixChannels) deft = 1;
Chris@67 176 else if (m_channelMode == MergeChannels) deft = 2;
Chris@67 177 else deft = 0;
Chris@0 178
Chris@87 179 } else if (name == "Scale") {
Chris@0 180
Chris@0 181 *min = 0;
Chris@0 182 *max = 2;
Chris@0 183
Chris@0 184 deft = (int)m_scale;
Chris@0 185
Chris@0 186 } else {
Chris@0 187 deft = Layer::getPropertyRangeAndValue(name, min, max);
Chris@0 188 }
Chris@0 189
Chris@0 190 return deft;
Chris@0 191 }
Chris@0 192
Chris@0 193 QString
Chris@0 194 WaveformLayer::getPropertyValueLabel(const PropertyName &name,
Chris@0 195 int value) const
Chris@0 196 {
Chris@87 197 if (name == "Colour") {
Chris@0 198 switch (value) {
Chris@0 199 default:
Chris@0 200 case 0: return tr("Black");
Chris@0 201 case 1: return tr("Red");
Chris@0 202 case 2: return tr("Blue");
Chris@0 203 case 3: return tr("Green");
Chris@0 204 case 4: return tr("Purple");
Chris@0 205 case 5: return tr("Orange");
Chris@0 206 }
Chris@0 207 }
Chris@87 208 if (name == "Scale") {
Chris@0 209 switch (value) {
Chris@0 210 default:
Chris@0 211 case 0: return tr("Linear");
Chris@0 212 case 1: return tr("Meter");
Chris@0 213 case 2: return tr("dB");
Chris@0 214 }
Chris@0 215 }
Chris@87 216 if (name == "Channels") {
Chris@67 217 switch (value) {
Chris@67 218 default:
Chris@67 219 case 0: return tr("Separate");
Chris@67 220 case 1: return tr("Mean");
Chris@67 221 case 2: return tr("Butterfly");
Chris@67 222 }
Chris@67 223 }
Chris@0 224 return tr("<unknown>");
Chris@0 225 }
Chris@0 226
Chris@0 227 void
Chris@0 228 WaveformLayer::setProperty(const PropertyName &name, int value)
Chris@0 229 {
Chris@87 230 if (name == "Gain") {
Chris@0 231 setGain(pow(10, float(value)/20.0));
Chris@87 232 } else if (name == "Normalize Visible Area") {
Chris@67 233 setAutoNormalize(value ? true : false);
Chris@87 234 } else if (name == "Colour") {
Chris@0 235 switch (value) {
Chris@0 236 default:
Chris@0 237 case 0: setBaseColour(Qt::black); break;
Chris@0 238 case 1: setBaseColour(Qt::darkRed); break;
Chris@0 239 case 2: setBaseColour(Qt::darkBlue); break;
Chris@0 240 case 3: setBaseColour(Qt::darkGreen); break;
Chris@0 241 case 4: setBaseColour(QColor(200, 50, 255)); break;
Chris@0 242 case 5: setBaseColour(QColor(255, 150, 50)); break;
Chris@0 243 }
Chris@87 244 } else if (name == "Channels") {
Chris@67 245 if (value == 1) setChannelMode(MixChannels);
Chris@67 246 else if (value == 2) setChannelMode(MergeChannels);
Chris@67 247 else setChannelMode(SeparateChannels);
Chris@87 248 } else if (name == "Scale") {
Chris@0 249 switch (value) {
Chris@0 250 default:
Chris@0 251 case 0: setScale(LinearScale); break;
Chris@0 252 case 1: setScale(MeterScale); break;
Chris@0 253 case 2: setScale(dBScale); break;
Chris@0 254 }
Chris@0 255 }
Chris@0 256 }
Chris@0 257
Chris@0 258 void
Chris@67 259 WaveformLayer::setGain(float gain)
Chris@0 260 {
Chris@0 261 if (m_gain == gain) return;
Chris@0 262 m_gain = gain;
Chris@0 263 m_cacheValid = false;
Chris@0 264 emit layerParametersChanged();
Chris@0 265 }
Chris@0 266
Chris@0 267 void
Chris@67 268 WaveformLayer::setAutoNormalize(bool autoNormalize)
Chris@67 269 {
Chris@67 270 if (m_autoNormalize == autoNormalize) return;
Chris@67 271 m_autoNormalize = autoNormalize;
Chris@67 272 m_cacheValid = false;
Chris@67 273 emit layerParametersChanged();
Chris@67 274 }
Chris@67 275
Chris@67 276 void
Chris@0 277 WaveformLayer::setBaseColour(QColor colour)
Chris@0 278 {
Chris@0 279 if (m_colour == colour) return;
Chris@0 280 m_colour = colour;
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::setShowMeans(bool showMeans)
Chris@0 287 {
Chris@0 288 if (m_showMeans == showMeans) return;
Chris@0 289 m_showMeans = showMeans;
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::setUseGreyscale(bool useGreyscale)
Chris@0 296 {
Chris@0 297 if (m_greyscale == useGreyscale) return;
Chris@0 298 m_greyscale = useGreyscale;
Chris@0 299 m_cacheValid = false;
Chris@0 300 emit layerParametersChanged();
Chris@0 301 }
Chris@0 302
Chris@0 303 void
Chris@0 304 WaveformLayer::setChannelMode(ChannelMode channelMode)
Chris@0 305 {
Chris@0 306 if (m_channelMode == channelMode) return;
Chris@0 307 m_channelMode = channelMode;
Chris@0 308 m_cacheValid = false;
Chris@0 309 emit layerParametersChanged();
Chris@0 310 }
Chris@0 311
Chris@0 312 void
Chris@0 313 WaveformLayer::setChannel(int channel)
Chris@0 314 {
Chris@101 315 // std::cerr << "WaveformLayer::setChannel(" << channel << ")" << std::endl;
Chris@0 316
Chris@0 317 if (m_channel == channel) return;
Chris@0 318 m_channel = channel;
Chris@0 319 m_cacheValid = false;
Chris@0 320 emit layerParametersChanged();
Chris@0 321 }
Chris@0 322
Chris@0 323 void
Chris@0 324 WaveformLayer::setScale(Scale scale)
Chris@0 325 {
Chris@0 326 if (m_scale == scale) return;
Chris@0 327 m_scale = scale;
Chris@0 328 m_cacheValid = false;
Chris@0 329 emit layerParametersChanged();
Chris@0 330 }
Chris@0 331
Chris@0 332 void
Chris@0 333 WaveformLayer::setAggressiveCacheing(bool aggressive)
Chris@0 334 {
Chris@0 335 if (m_aggressive == aggressive) return;
Chris@0 336 m_aggressive = aggressive;
Chris@0 337 m_cacheValid = false;
Chris@0 338 emit layerParametersChanged();
Chris@0 339 }
Chris@0 340
Chris@0 341 int
Chris@0 342 WaveformLayer::getCompletion() const
Chris@0 343 {
Chris@0 344 int completion = 100;
Chris@0 345 if (!m_model || !m_model->isOK()) return completion;
Chris@0 346 if (m_model->isReady(&completion)) return 100;
Chris@0 347 return completion;
Chris@0 348 }
Chris@0 349
Chris@79 350 bool
Chris@101 351 WaveformLayer::getValueExtents(float &min, float &max,
Chris@101 352 bool &log, QString &unit) const
Chris@79 353 {
Chris@79 354 if (m_scale == LinearScale) {
Chris@79 355 min = 0.0;
Chris@79 356 max = 1.0;
Chris@79 357 unit = "V";
Chris@79 358 } else if (m_scale == MeterScale) {
Chris@79 359 return false; //!!!
Chris@79 360 } else {
Chris@79 361 min = AudioLevel::multiplier_to_dB(0.0);
Chris@79 362 max = AudioLevel::multiplier_to_dB(1.0);
Chris@79 363 unit = "dB";
Chris@79 364 }
Chris@79 365 return true;
Chris@79 366 }
Chris@79 367
Chris@0 368 int
Chris@0 369 WaveformLayer::dBscale(float sample, int m) const
Chris@0 370 {
Chris@67 371 //!!! if (sample < 0.0) return -dBscale(-sample, m);
Chris@67 372 if (sample < 0.0) return dBscale(-sample, m);
Chris@0 373 float dB = AudioLevel::multiplier_to_dB(sample);
Chris@0 374 if (dB < -50.0) return 0;
Chris@0 375 if (dB > 0.0) return m;
Chris@0 376 return int(((dB + 50.0) * m) / 50.0 + 0.1);
Chris@0 377 }
Chris@0 378
Chris@0 379 size_t
Chris@67 380 WaveformLayer::getChannelArrangement(size_t &min, size_t &max,
Chris@67 381 bool &merging, bool &mixing)
Chris@0 382 const
Chris@0 383 {
Chris@0 384 if (!m_model || !m_model->isOK()) return 0;
Chris@0 385
Chris@0 386 size_t channels = m_model->getChannelCount();
Chris@0 387 if (channels == 0) return 0;
Chris@0 388
Chris@0 389 size_t rawChannels = channels;
Chris@0 390
Chris@0 391 if (m_channel == -1) {
Chris@0 392 min = 0;
Chris@67 393 if (m_channelMode == MergeChannels ||
Chris@67 394 m_channelMode == MixChannels) {
Chris@0 395 max = 0;
Chris@0 396 channels = 1;
Chris@0 397 } else {
Chris@0 398 max = channels - 1;
Chris@0 399 }
Chris@0 400 } else {
Chris@0 401 min = m_channel;
Chris@0 402 max = m_channel;
Chris@0 403 rawChannels = 1;
Chris@0 404 channels = 1;
Chris@0 405 }
Chris@0 406
Chris@0 407 merging = (m_channelMode == MergeChannels && rawChannels > 1);
Chris@67 408 mixing = (m_channelMode == MixChannels && rawChannels > 1);
Chris@0 409
Chris@0 410 // std::cerr << "WaveformLayer::getChannelArrangement: min " << min << ", max " << max << ", merging " << merging << ", channels " << channels << std::endl;
Chris@0 411
Chris@0 412 return channels;
Chris@0 413 }
Chris@0 414
Chris@67 415 bool
Chris@67 416 WaveformLayer::isLayerScrollable(const View *) const
Chris@67 417 {
Chris@67 418 return !m_autoNormalize;
Chris@67 419 }
Chris@67 420
Chris@68 421 static float meterdbs[] = { -40, -30, -20, -15, -10,
Chris@68 422 -5, -3, -2, -1, -0.5, 0 };
Chris@68 423
Chris@0 424 void
Chris@44 425 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const
Chris@0 426 {
Chris@0 427 if (!m_model || !m_model->isOK()) {
Chris@0 428 return;
Chris@0 429 }
Chris@0 430
Chris@44 431 long startFrame = v->getStartFrame();
Chris@44 432 int zoomLevel = v->getZoomLevel();
Chris@0 433
Chris@2 434 #ifdef DEBUG_WAVEFORM_PAINT
Chris@0 435 Profiler profiler("WaveformLayer::paint", true);
Chris@0 436 std::cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y()
Chris@0 437 << ") [" << rect.width() << "x" << rect.height() << "]: zoom " << zoomLevel << ", start " << startFrame << std::endl;
Chris@2 438 #endif
Chris@0 439
Chris@0 440 size_t channels = 0, minChannel = 0, maxChannel = 0;
Chris@67 441 bool mergingChannels = false, mixingChannels = false;
Chris@0 442
Chris@67 443 channels = getChannelArrangement(minChannel, maxChannel,
Chris@67 444 mergingChannels, mixingChannels);
Chris@0 445 if (channels == 0) return;
Chris@0 446
Chris@44 447 int w = v->width();
Chris@44 448 int h = v->height();
Chris@0 449
Chris@0 450 bool ready = m_model->isReady();
Chris@0 451 QPainter *paint;
Chris@0 452
Chris@0 453 if (m_aggressive) {
Chris@0 454
Chris@0 455 if (m_cacheValid && (zoomLevel != m_cacheZoomLevel)) {
Chris@0 456 m_cacheValid = false;
Chris@0 457 }
Chris@0 458
Chris@0 459 if (m_cacheValid) {
Chris@0 460 viewPainter.drawPixmap(rect, *m_cache, rect);
Chris@0 461 return;
Chris@0 462 }
Chris@0 463
Chris@0 464 if (!m_cache || m_cache->width() != w || m_cache->height() != h) {
Chris@0 465 delete m_cache;
Chris@0 466 m_cache = new QPixmap(w, h);
Chris@0 467 }
Chris@0 468
Chris@0 469 paint = new QPainter(m_cache);
Chris@0 470
Chris@0 471 paint->setPen(Qt::NoPen);
Chris@44 472 paint->setBrush(v->palette().background());
Chris@0 473 paint->drawRect(rect);
Chris@0 474
Chris@0 475 paint->setPen(Qt::black);
Chris@0 476 paint->setBrush(Qt::NoBrush);
Chris@0 477
Chris@0 478 } else {
Chris@0 479 paint = &viewPainter;
Chris@0 480 }
Chris@0 481
Chris@28 482 paint->setRenderHint(QPainter::Antialiasing, false);
Chris@28 483
Chris@0 484 int x0 = 0, x1 = w - 1;
Chris@0 485 int y0 = 0, y1 = h - 1;
Chris@0 486
Chris@0 487 x0 = rect.left();
Chris@0 488 x1 = rect.right();
Chris@0 489 y0 = rect.top();
Chris@0 490 y1 = rect.bottom();
Chris@0 491
Chris@28 492 if (x0 > 0) --x0;
Chris@44 493 if (x1 < v->width()) ++x1;
Chris@28 494
Chris@44 495 long frame0 = v->getFrameForX(x0);
Chris@44 496 long frame1 = v->getFrameForX(x1 + 1);
Chris@0 497
Chris@4 498 #ifdef DEBUG_WAVEFORM_PAINT
Chris@4 499 std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << ")" << std::endl;
Chris@4 500 #endif
Chris@0 501
Chris@0 502 RangeSummarisableTimeValueModel::RangeBlock ranges;
Chris@0 503 RangeSummarisableTimeValueModel::RangeBlock otherChannelRanges;
Chris@0 504 RangeSummarisableTimeValueModel::Range range;
Chris@0 505
Chris@0 506 QColor greys[3];
Chris@0 507 if (m_colour == Qt::black) {
Chris@27 508 for (int i = 0; i < 3; ++i) { // 0 lightest, 2 darkest
Chris@0 509 int level = 192 - 64 * i;
Chris@0 510 greys[i] = QColor(level, level, level);
Chris@0 511 }
Chris@0 512 } else {
Chris@44 513 int hue, sat, val;
Chris@44 514 m_colour.getHsv(&hue, &sat, &val);
Chris@27 515 for (int i = 0; i < 3; ++i) { // 0 lightest, 2 darkest
Chris@44 516 if (v->hasLightBackground()) {
Chris@44 517 greys[i] = QColor::fromHsv(hue, sat * (i + 1) / 4, val);
Chris@27 518 } else {
Chris@44 519 greys[i] = QColor::fromHsv(hue, sat * (3 - i) / 4, val);
Chris@27 520 }
Chris@27 521 }
Chris@0 522 }
Chris@0 523
Chris@0 524 QColor midColour = m_colour;
Chris@0 525 if (midColour == Qt::black) {
Chris@0 526 midColour = Qt::gray;
Chris@44 527 } else if (v->hasLightBackground()) {
Chris@0 528 midColour = midColour.light(150);
Chris@0 529 } else {
Chris@0 530 midColour = midColour.light(50);
Chris@0 531 }
Chris@0 532
Chris@67 533 while (m_effectiveGains.size() <= maxChannel) {
Chris@67 534 m_effectiveGains.push_back(m_gain);
Chris@67 535 }
Chris@67 536
Chris@0 537 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
Chris@0 538
Chris@0 539 int prevRangeBottom = -1, prevRangeTop = -1;
Chris@28 540 QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour;
Chris@0 541
Chris@67 542 m_effectiveGains[ch] = m_gain;
Chris@67 543
Chris@67 544 if (m_autoNormalize) {
Chris@67 545 RangeSummarisableTimeValueModel::Range range =
Chris@67 546 m_model->getRange(ch, startFrame < 0 ? 0 : startFrame,
Chris@67 547 v->getEndFrame());
Chris@67 548 if (mergingChannels || mixingChannels) {
Chris@67 549 RangeSummarisableTimeValueModel::Range otherRange =
Chris@67 550 m_model->getRange(1, startFrame < 0 ? 0 : startFrame,
Chris@67 551 v->getEndFrame());
Chris@67 552 range.max = std::max(range.max, otherRange.max);
Chris@67 553 range.min = std::min(range.min, otherRange.min);
Chris@67 554 range.absmean = std::min(range.absmean, otherRange.absmean);
Chris@67 555 }
Chris@67 556 m_effectiveGains[ch] = 1.0 / std::max(fabsf(range.max),
Chris@67 557 fabsf(range.min));
Chris@67 558 }
Chris@67 559
Chris@67 560 float gain = m_effectiveGains[ch];
Chris@67 561
Chris@68 562 int m = (h / channels) / 2;
Chris@68 563 int my = m + (((ch - minChannel) * h) / channels);
Chris@68 564
Chris@68 565 // std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl;
Chris@68 566
Chris@68 567 if (my - m > y1 || my + m < y0) continue;
Chris@68 568
Chris@68 569 if ((m_scale == dBScale || m_scale == MeterScale) &&
Chris@68 570 m_channelMode != MergeChannels) {
Chris@68 571 m = (h / channels);
Chris@68 572 my = m + (((ch - minChannel) * h) / channels);
Chris@68 573 }
Chris@68 574
Chris@68 575 paint->setPen(greys[0]);
Chris@68 576 paint->drawLine(x0, my, x1, my);
Chris@68 577
Chris@68 578 int n = 10;
Chris@68 579 int py = -1;
Chris@68 580
Chris@68 581 if (v->hasLightBackground()) {
Chris@68 582
Chris@68 583 paint->setPen(QColor(240, 240, 240));
Chris@68 584
Chris@68 585 for (int i = 1; i < n; ++i) {
Chris@68 586
Chris@68 587 float val = 0.0, nval = 0.0;
Chris@68 588
Chris@68 589 switch (m_scale) {
Chris@68 590
Chris@68 591 case LinearScale:
Chris@68 592 val = (i * gain) / n;
Chris@68 593 if (i > 0) nval = -val;
Chris@68 594 break;
Chris@68 595
Chris@68 596 case MeterScale:
Chris@68 597 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
Chris@68 598 break;
Chris@68 599
Chris@68 600 case dBScale:
Chris@68 601 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
Chris@68 602 break;
Chris@68 603 }
Chris@68 604
Chris@68 605 if (val < -1.0 || val > 1.0) continue;
Chris@68 606
Chris@68 607 int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
Chris@68 608
Chris@68 609 if (py >= 0 && abs(y - py) < 10) continue;
Chris@68 610 else py = y;
Chris@68 611
Chris@68 612 int ny = y;
Chris@68 613 if (nval != 0.0) {
Chris@68 614 ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
Chris@68 615 }
Chris@68 616
Chris@68 617 paint->drawLine(x0, y, x1, y);
Chris@68 618 if (ny != y) {
Chris@68 619 paint->drawLine(x0, ny, x1, ny);
Chris@68 620 }
Chris@68 621 }
Chris@68 622 }
Chris@68 623
Chris@68 624 if (frame1 <= 0) continue;
Chris@68 625
Chris@68 626 size_t modelZoomLevel = zoomLevel;
Chris@68 627
Chris@68 628 ranges = m_model->getRanges
Chris@68 629 (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
Chris@68 630
Chris@68 631 if (mergingChannels || mixingChannels) {
Chris@71 632 if (m_model->getChannelCount() > 1) {
Chris@71 633 otherChannelRanges = m_model->getRanges
Chris@71 634 (1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel);
Chris@71 635 } else {
Chris@71 636 otherChannelRanges = ranges;
Chris@71 637 }
Chris@68 638 }
Chris@68 639
Chris@0 640 for (int x = x0; x <= x1; ++x) {
Chris@0 641
Chris@0 642 range = RangeSummarisableTimeValueModel::Range();
Chris@0 643 size_t index = x - x0;
Chris@0 644 size_t maxIndex = index;
Chris@0 645
Chris@0 646 if (frame0 < 0) {
Chris@0 647 if (index < size_t(-frame0 / zoomLevel)) {
Chris@0 648 continue;
Chris@0 649 } else {
Chris@0 650 index -= -frame0 / zoomLevel;
Chris@0 651 maxIndex = index;
Chris@0 652 }
Chris@0 653 }
Chris@0 654
Chris@0 655 if (int(modelZoomLevel) != zoomLevel) {
Chris@0 656
Chris@0 657 index = size_t((double(index) * zoomLevel) / modelZoomLevel);
Chris@0 658
Chris@0 659 if (int(modelZoomLevel) < zoomLevel) {
Chris@0 660 // Peaks may be missed! The model should avoid
Chris@0 661 // this by rounding zoom levels up rather than
Chris@0 662 // down, but we'd better cope in case it doesn't
Chris@0 663 maxIndex = index;
Chris@0 664 } else {
Chris@0 665 maxIndex = size_t((double(index + 1) * zoomLevel)
Chris@0 666 / modelZoomLevel) - 1;
Chris@0 667 }
Chris@0 668 }
Chris@0 669
Chris@0 670 if (index < ranges.size()) {
Chris@0 671
Chris@0 672 range = ranges[index];
Chris@0 673
Chris@0 674 if (maxIndex > index && maxIndex < ranges.size()) {
Chris@0 675 range.max = std::max(range.max, ranges[maxIndex].max);
Chris@0 676 range.min = std::min(range.min, ranges[maxIndex].min);
Chris@0 677 range.absmean = (range.absmean +
Chris@0 678 ranges[maxIndex].absmean) / 2;
Chris@0 679 }
Chris@0 680
Chris@0 681 } else {
Chris@0 682 continue;
Chris@0 683 }
Chris@0 684
Chris@0 685 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0;
Chris@0 686
Chris@0 687 if (mergingChannels) {
Chris@0 688
Chris@0 689 if (index < otherChannelRanges.size()) {
Chris@0 690
Chris@0 691 range.max = fabsf(range.max);
Chris@0 692 range.min = -fabsf(otherChannelRanges[index].max);
Chris@0 693 range.absmean = (range.absmean +
Chris@0 694 otherChannelRanges[index].absmean) / 2;
Chris@0 695
Chris@0 696 if (maxIndex > index && maxIndex < ranges.size()) {
Chris@0 697 // let's not concern ourselves about the mean
Chris@0 698 range.min = std::min
Chris@0 699 (range.min,
Chris@0 700 -fabsf(otherChannelRanges[maxIndex].max));
Chris@0 701 }
Chris@0 702 }
Chris@67 703
Chris@67 704 } else if (mixingChannels) {
Chris@67 705
Chris@67 706 if (index < otherChannelRanges.size()) {
Chris@67 707
Chris@67 708 range.max = (range.max + otherChannelRanges[index].max) / 2;
Chris@67 709 range.min = (range.min + otherChannelRanges[index].min) / 2;
Chris@67 710 range.absmean = (range.absmean + otherChannelRanges[index].absmean) / 2;
Chris@67 711 }
Chris@67 712 }
Chris@0 713
Chris@0 714 int greyLevels = 1;
Chris@0 715 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4;
Chris@0 716
Chris@0 717 switch (m_scale) {
Chris@0 718
Chris@0 719 case LinearScale:
Chris@67 720 rangeBottom = int( m * greyLevels * range.min * gain);
Chris@67 721 rangeTop = int( m * greyLevels * range.max * gain);
Chris@67 722 meanBottom = int(-m * range.absmean * gain);
Chris@67 723 meanTop = int( m * range.absmean * gain);
Chris@0 724 break;
Chris@0 725
Chris@0 726 case dBScale:
Chris@67 727 if (!mergingChannels) {
Chris@67 728 int db0 = dBscale(range.min * gain, m);
Chris@67 729 int db1 = dBscale(range.max * gain, m);
Chris@67 730 rangeTop = std::max(db0, db1);
Chris@67 731 meanTop = std::min(db0, db1);
Chris@67 732 if (mixingChannels) rangeBottom = meanTop;
Chris@67 733 else rangeBottom = dBscale(range.absmean * gain, m);
Chris@67 734 meanBottom = rangeBottom;
Chris@67 735 } else {
Chris@67 736 rangeBottom = -dBscale(range.min * gain, m * greyLevels);
Chris@67 737 rangeTop = dBscale(range.max * gain, m * greyLevels);
Chris@67 738 meanBottom = -dBscale(range.absmean * gain, m);
Chris@67 739 meanTop = dBscale(range.absmean * gain, m);
Chris@67 740 }
Chris@0 741 break;
Chris@0 742
Chris@0 743 case MeterScale:
Chris@67 744 if (!mergingChannels) {
Chris@67 745 int r0 = abs(AudioLevel::multiplier_to_preview(range.min * gain, m));
Chris@67 746 int r1 = abs(AudioLevel::multiplier_to_preview(range.max * gain, m));
Chris@67 747 rangeTop = std::max(r0, r1);
Chris@67 748 meanTop = std::min(r0, r1);
Chris@67 749 if (mixingChannels) rangeBottom = meanTop;
Chris@67 750 else rangeBottom = AudioLevel::multiplier_to_preview(range.absmean * gain, m);
Chris@67 751 meanBottom = rangeBottom;
Chris@67 752 } else {
Chris@67 753 rangeBottom = AudioLevel::multiplier_to_preview(range.min * gain, m * greyLevels);
Chris@67 754 rangeTop = AudioLevel::multiplier_to_preview(range.max * gain, m * greyLevels);
Chris@67 755 meanBottom = -AudioLevel::multiplier_to_preview(range.absmean * gain, m);
Chris@67 756 meanTop = AudioLevel::multiplier_to_preview(range.absmean * gain, m);
Chris@67 757 }
Chris@67 758 break;
Chris@0 759 }
Chris@0 760
Chris@27 761 rangeBottom = my * greyLevels - rangeBottom;
Chris@27 762 rangeTop = my * greyLevels - rangeTop;
Chris@27 763 meanBottom = my - meanBottom;
Chris@27 764 meanTop = my - meanTop;
Chris@27 765
Chris@27 766 int topFill = (rangeTop % greyLevels);
Chris@27 767 if (topFill > 0) topFill = greyLevels - topFill;
Chris@27 768
Chris@27 769 int bottomFill = (rangeBottom % greyLevels);
Chris@27 770
Chris@0 771 rangeTop = rangeTop / greyLevels;
Chris@0 772 rangeBottom = rangeBottom / greyLevels;
Chris@0 773
Chris@0 774 bool clipped = false;
Chris@27 775
Chris@27 776 if (rangeTop < my - m) { rangeTop = my - m; }
Chris@27 777 if (rangeTop > my + m) { rangeTop = my + m; }
Chris@27 778 if (rangeBottom < my - m) { rangeBottom = my - m; }
Chris@27 779 if (rangeBottom > my + m) { rangeBottom = my + m; }
Chris@27 780
Chris@67 781 if (range.max <= -1.0 ||
Chris@67 782 range.max >= 1.0) clipped = true;
Chris@0 783
Chris@0 784 if (meanBottom > rangeBottom) meanBottom = rangeBottom;
Chris@0 785 if (meanTop < rangeTop) meanTop = rangeTop;
Chris@0 786
Chris@0 787 bool drawMean = m_showMeans;
Chris@0 788 if (meanTop == rangeTop) {
Chris@0 789 if (meanTop < meanBottom) ++meanTop;
Chris@0 790 else drawMean = false;
Chris@0 791 }
Chris@67 792 if (meanBottom == rangeBottom && m_scale == LinearScale) {
Chris@0 793 if (meanBottom > meanTop) --meanBottom;
Chris@0 794 else drawMean = false;
Chris@0 795 }
Chris@0 796
Chris@0 797 if (x != x0 && prevRangeBottom != -1) {
Chris@0 798 if (prevRangeBottom > rangeBottom &&
Chris@0 799 prevRangeTop > rangeBottom) {
Chris@28 800 // paint->setPen(midColour);
Chris@28 801 paint->setPen(m_colour);
Chris@0 802 paint->drawLine(x-1, prevRangeTop, x, rangeBottom);
Chris@28 803 paint->setPen(prevRangeTopColour);
Chris@0 804 paint->drawPoint(x-1, prevRangeTop);
Chris@0 805 } else if (prevRangeBottom < rangeTop &&
Chris@0 806 prevRangeTop < rangeTop) {
Chris@28 807 // paint->setPen(midColour);
Chris@28 808 paint->setPen(m_colour);
Chris@0 809 paint->drawLine(x-1, prevRangeBottom, x, rangeTop);
Chris@28 810 paint->setPen(prevRangeBottomColour);
Chris@0 811 paint->drawPoint(x-1, prevRangeBottom);
Chris@0 812 }
Chris@0 813 }
Chris@0 814
Chris@0 815 if (ready) {
Chris@67 816 if (clipped /*!!! ||
Chris@67 817 range.min * gain <= -1.0 ||
Chris@67 818 range.max * gain >= 1.0 */) {
Chris@0 819 paint->setPen(Qt::red);
Chris@0 820 } else {
Chris@0 821 paint->setPen(m_colour);
Chris@0 822 }
Chris@0 823 } else {
Chris@0 824 paint->setPen(midColour);
Chris@0 825 }
Chris@0 826
Chris@0 827 paint->drawLine(x, rangeBottom, x, rangeTop);
Chris@0 828
Chris@28 829 prevRangeTopColour = m_colour;
Chris@28 830 prevRangeBottomColour = m_colour;
Chris@28 831
Chris@0 832 if (m_greyscale && (m_scale == LinearScale) && ready) {
Chris@0 833 if (!clipped) {
Chris@0 834 if (rangeTop < rangeBottom) {
Chris@0 835 if (topFill > 0 &&
Chris@0 836 (!drawMean || (rangeTop < meanTop - 1))) {
Chris@0 837 paint->setPen(greys[topFill - 1]);
Chris@27 838 paint->drawPoint(x, rangeTop);
Chris@28 839 prevRangeTopColour = greys[topFill - 1];
Chris@0 840 }
Chris@0 841 if (bottomFill > 0 &&
Chris@0 842 (!drawMean || (rangeBottom > meanBottom + 1))) {
Chris@0 843 paint->setPen(greys[bottomFill - 1]);
Chris@27 844 paint->drawPoint(x, rangeBottom);
Chris@28 845 prevRangeBottomColour = greys[bottomFill - 1];
Chris@0 846 }
Chris@0 847 }
Chris@0 848 }
Chris@0 849 }
Chris@0 850
Chris@0 851 if (drawMean) {
Chris@0 852 paint->setPen(midColour);
Chris@0 853 paint->drawLine(x, meanBottom, x, meanTop);
Chris@0 854 }
Chris@0 855
Chris@0 856 prevRangeBottom = rangeBottom;
Chris@0 857 prevRangeTop = rangeTop;
Chris@0 858 }
Chris@0 859 }
Chris@0 860
Chris@0 861 if (m_aggressive) {
Chris@41 862
Chris@44 863 if (ready && rect == v->rect()) {
Chris@0 864 m_cacheValid = true;
Chris@0 865 m_cacheZoomLevel = zoomLevel;
Chris@0 866 }
Chris@0 867 paint->end();
Chris@0 868 delete paint;
Chris@0 869 viewPainter.drawPixmap(rect, *m_cache, rect);
Chris@0 870 }
Chris@0 871 }
Chris@0 872
Chris@25 873 QString
Chris@44 874 WaveformLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@25 875 {
Chris@25 876 int x = pos.x();
Chris@25 877
Chris@25 878 if (!m_model || !m_model->isOK()) return "";
Chris@25 879
Chris@44 880 long f0 = v->getFrameForX(x);
Chris@44 881 long f1 = v->getFrameForX(x + 1);
Chris@25 882
Chris@25 883 if (f0 < 0) f0 = 0;
Chris@25 884 if (f1 <= f0) return "";
Chris@25 885
Chris@25 886 QString text;
Chris@25 887
Chris@25 888 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate());
Chris@25 889 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate());
Chris@25 890
Chris@25 891 if (f1 != f0 + 1 && (rt0.sec != rt1.sec || rt0.msec() != rt1.msec())) {
Chris@25 892 text += tr("Time:\t%1 - %2")
Chris@25 893 .arg(rt0.toText(true).c_str())
Chris@25 894 .arg(rt1.toText(true).c_str());
Chris@25 895 } else {
Chris@25 896 text += tr("Time:\t%1")
Chris@25 897 .arg(rt0.toText(true).c_str());
Chris@25 898 }
Chris@25 899
Chris@25 900 size_t channels = 0, minChannel = 0, maxChannel = 0;
Chris@67 901 bool mergingChannels = false, mixingChannels = false;
Chris@25 902
Chris@67 903 channels = getChannelArrangement(minChannel, maxChannel,
Chris@67 904 mergingChannels, mixingChannels);
Chris@25 905 if (channels == 0) return "";
Chris@25 906
Chris@25 907 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
Chris@25 908
Chris@44 909 size_t blockSize = v->getZoomLevel();
Chris@25 910 RangeSummarisableTimeValueModel::RangeBlock ranges =
Chris@25 911 m_model->getRanges(ch, f0, f1, blockSize);
Chris@25 912
Chris@25 913 if (ranges.empty()) continue;
Chris@25 914
Chris@25 915 RangeSummarisableTimeValueModel::Range range = ranges[0];
Chris@25 916
Chris@25 917 QString label = tr("Level:");
Chris@25 918 if (minChannel != maxChannel) {
Chris@25 919 if (ch == 0) label = tr("Left:");
Chris@25 920 else if (ch == 1) label = tr("Right:");
Chris@25 921 else label = tr("Channel %1").arg(ch + 1);
Chris@25 922 }
Chris@25 923
Chris@76 924 bool singleValue = false;
Chris@76 925 float min, max;
Chris@76 926
Chris@76 927 if (fabs(range.min) < 0.01) {
Chris@76 928 min = range.min;
Chris@76 929 max = range.max;
Chris@76 930 singleValue = (min == max);
Chris@76 931 } else {
Chris@76 932 int imin = int(range.min * 1000);
Chris@76 933 int imax = int(range.max * 1000);
Chris@76 934 singleValue = (imin == imax);
Chris@76 935 min = float(imin)/1000;
Chris@76 936 max = float(imax)/1000;
Chris@76 937 }
Chris@76 938
Chris@25 939 int db = int(AudioLevel::multiplier_to_dB(std::max(fabsf(range.min),
Chris@25 940 fabsf(range.max)))
Chris@25 941 * 100);
Chris@25 942
Chris@76 943 if (!singleValue) {
Chris@25 944 text += tr("\n%1\t%2 - %3 (%4 dB peak)")
Chris@76 945 .arg(label).arg(min).arg(max).arg(float(db)/100);
Chris@25 946 } else {
Chris@25 947 text += tr("\n%1\t%2 (%3 dB peak)")
Chris@76 948 .arg(label).arg(min).arg(float(db)/100);
Chris@25 949 }
Chris@25 950 }
Chris@25 951
Chris@25 952 return text;
Chris@25 953 }
Chris@25 954
Chris@0 955 int
Chris@68 956 WaveformLayer::getYForValue(View *v, Scale scale, float value, size_t channel,
Chris@68 957 size_t minChannel, size_t maxChannel) const
Chris@68 958 {
Chris@68 959 if (maxChannel < minChannel || channel < minChannel) return 0;
Chris@68 960
Chris@68 961 int w = v->width();
Chris@68 962 int h = v->height();
Chris@68 963
Chris@68 964 int channels = maxChannel - minChannel + 1;
Chris@68 965 int m = (h / channels) / 2;
Chris@68 966 int my = m + (((channel - minChannel) * h) / channels);
Chris@68 967
Chris@68 968 if ((m_scale == dBScale || m_scale == MeterScale) &&
Chris@68 969 m_channelMode != MergeChannels) {
Chris@68 970 m = (h / channels);
Chris@68 971 my = m + (((channel - minChannel) * h) / channels);
Chris@68 972 }
Chris@68 973
Chris@68 974 int vy = 0;
Chris@68 975
Chris@68 976 switch (scale) {
Chris@68 977
Chris@68 978 case LinearScale:
Chris@68 979 vy = int(m * value);
Chris@68 980 break;
Chris@68 981
Chris@68 982 case MeterScale:
Chris@68 983 vy = AudioLevel::multiplier_to_preview(value, m);
Chris@68 984 break;
Chris@68 985
Chris@68 986 case dBScale:
Chris@68 987 vy = dBscale(value, m);
Chris@68 988 break;
Chris@68 989 }
Chris@68 990
Chris@68 991 return my - vy;
Chris@68 992 }
Chris@68 993
Chris@68 994 int
Chris@44 995 WaveformLayer::getVerticalScaleWidth(View *v, QPainter &paint) const
Chris@0 996 {
Chris@0 997 if (m_scale == LinearScale) {
Chris@0 998 return paint.fontMetrics().width("0.0") + 13;
Chris@0 999 } else {
Chris@0 1000 return std::max(paint.fontMetrics().width(tr("0dB")),
Chris@0 1001 paint.fontMetrics().width(tr("-Inf"))) + 13;
Chris@0 1002 }
Chris@0 1003 }
Chris@0 1004
Chris@0 1005 void
Chris@44 1006 WaveformLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
Chris@0 1007 {
Chris@0 1008 if (!m_model || !m_model->isOK()) {
Chris@0 1009 return;
Chris@0 1010 }
Chris@0 1011
Chris@0 1012 size_t channels = 0, minChannel = 0, maxChannel = 0;
Chris@67 1013 bool mergingChannels = false, mixingChannels = false;
Chris@0 1014
Chris@67 1015 channels = getChannelArrangement(minChannel, maxChannel,
Chris@67 1016 mergingChannels, mixingChannels);
Chris@0 1017 if (channels == 0) return;
Chris@0 1018
Chris@0 1019 int h = rect.height(), w = rect.width();
Chris@0 1020 int textHeight = paint.fontMetrics().height();
Chris@0 1021 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
Chris@0 1022
Chris@67 1023 float gain = m_gain;
Chris@67 1024
Chris@0 1025 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
Chris@0 1026
Chris@68 1027 int lastLabelledY = -1;
Chris@0 1028
Chris@67 1029 if (ch < m_effectiveGains.size()) gain = m_effectiveGains[ch];
Chris@67 1030
Chris@68 1031 int n = 10;
Chris@0 1032
Chris@68 1033 for (int i = 0; i <= n; ++i) {
Chris@68 1034
Chris@68 1035 float val = 0.0, nval = 0.0;
Chris@0 1036 QString text = "";
Chris@0 1037
Chris@68 1038 switch (m_scale) {
Chris@68 1039
Chris@68 1040 case LinearScale:
Chris@68 1041 val = (i * gain) / n;
Chris@68 1042 text = QString("%1").arg(float(i) / n);
Chris@68 1043 if (i == 0) text = "0.0";
Chris@68 1044 else {
Chris@68 1045 nval = -val;
Chris@68 1046 if (i == n) text = "1.0";
Chris@68 1047 }
Chris@68 1048 break;
Chris@0 1049
Chris@68 1050 case MeterScale:
Chris@68 1051 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
Chris@68 1052 text = QString("%1").arg(meterdbs[i]);
Chris@68 1053 if (i == n) text = tr("0dB");
Chris@68 1054 if (i == 0) {
Chris@68 1055 text = tr("-Inf");
Chris@68 1056 val = 0.0;
Chris@68 1057 }
Chris@68 1058 break;
Chris@0 1059
Chris@68 1060 case dBScale:
Chris@68 1061 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
Chris@68 1062 text = QString("%1").arg(-(10*n) + i * 10);
Chris@68 1063 if (i == n) text = tr("0dB");
Chris@68 1064 if (i == 0) {
Chris@68 1065 text = tr("-Inf");
Chris@68 1066 val = 0.0;
Chris@68 1067 }
Chris@68 1068 break;
Chris@68 1069 }
Chris@0 1070
Chris@68 1071 if (val < -1.0 || val > 1.0) continue;
Chris@0 1072
Chris@68 1073 int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
Chris@0 1074
Chris@68 1075 int ny = y;
Chris@68 1076 if (nval != 0.0) {
Chris@68 1077 ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
Chris@68 1078 }
Chris@0 1079
Chris@68 1080 bool spaceForLabel = (i == 0 ||
Chris@68 1081 abs(y - lastLabelledY) >= textHeight - 1);
Chris@0 1082
Chris@68 1083 if (spaceForLabel) {
Chris@0 1084
Chris@68 1085 int tx = 3;
Chris@68 1086 if (m_scale != LinearScale) {
Chris@68 1087 tx = w - 10 - paint.fontMetrics().width(text);
Chris@68 1088 }
Chris@68 1089
Chris@68 1090 int ty = y;
Chris@68 1091 if (ty < paint.fontMetrics().ascent()) {
Chris@68 1092 ty = paint.fontMetrics().ascent();
Chris@68 1093 } else if (ty > h - paint.fontMetrics().descent()) {
Chris@68 1094 ty = h - paint.fontMetrics().descent();
Chris@68 1095 } else {
Chris@68 1096 ty += toff;
Chris@68 1097 }
Chris@68 1098 paint.drawText(tx, ty, text);
Chris@0 1099
Chris@68 1100 lastLabelledY = ty - toff;
Chris@67 1101
Chris@68 1102 if (ny != y) {
Chris@68 1103 ty = ny;
Chris@68 1104 if (ty < paint.fontMetrics().ascent()) {
Chris@68 1105 ty = paint.fontMetrics().ascent();
Chris@68 1106 } else if (ty > h - paint.fontMetrics().descent()) {
Chris@68 1107 ty = h - paint.fontMetrics().descent();
Chris@68 1108 } else {
Chris@68 1109 ty += toff;
Chris@68 1110 }
Chris@68 1111 paint.drawText(tx, ty, text);
Chris@68 1112 }
Chris@68 1113
Chris@68 1114 paint.drawLine(w - 7, y, w, y);
Chris@68 1115 if (ny != y) paint.drawLine(w - 7, ny, w, ny);
Chris@68 1116
Chris@68 1117 } else {
Chris@68 1118
Chris@68 1119 paint.drawLine(w - 4, y, w, y);
Chris@68 1120 if (ny != y) paint.drawLine(w - 4, ny, w, ny);
Chris@68 1121 }
Chris@0 1122 }
Chris@0 1123 }
Chris@0 1124 }
Chris@0 1125
Chris@6 1126 QString
Chris@6 1127 WaveformLayer::toXmlString(QString indent, QString extraAttributes) const
Chris@6 1128 {
Chris@6 1129 QString s;
Chris@6 1130
Chris@6 1131 s += QString("gain=\"%1\" "
Chris@6 1132 "colour=\"%2\" "
Chris@6 1133 "showMeans=\"%3\" "
Chris@6 1134 "greyscale=\"%4\" "
Chris@6 1135 "channelMode=\"%5\" "
Chris@6 1136 "channel=\"%6\" "
Chris@6 1137 "scale=\"%7\" "
Chris@67 1138 "aggressive=\"%8\" "
Chris@67 1139 "autoNormalize=\"%9\"")
Chris@6 1140 .arg(m_gain)
Chris@6 1141 .arg(encodeColour(m_colour))
Chris@6 1142 .arg(m_showMeans)
Chris@6 1143 .arg(m_greyscale)
Chris@6 1144 .arg(m_channelMode)
Chris@6 1145 .arg(m_channel)
Chris@6 1146 .arg(m_scale)
Chris@67 1147 .arg(m_aggressive)
Chris@67 1148 .arg(m_autoNormalize);
Chris@6 1149
Chris@6 1150 return Layer::toXmlString(indent, extraAttributes + " " + s);
Chris@6 1151 }
Chris@6 1152
Chris@11 1153 void
Chris@11 1154 WaveformLayer::setProperties(const QXmlAttributes &attributes)
Chris@11 1155 {
Chris@11 1156 bool ok = false;
Chris@11 1157
Chris@11 1158 float gain = attributes.value("gain").toFloat(&ok);
Chris@11 1159 if (ok) setGain(gain);
Chris@11 1160
Chris@11 1161 QString colourSpec = attributes.value("colour");
Chris@11 1162 if (colourSpec != "") {
Chris@11 1163 QColor colour(colourSpec);
Chris@11 1164 if (colour.isValid()) {
Chris@11 1165 setBaseColour(QColor(colourSpec));
Chris@11 1166 }
Chris@11 1167 }
Chris@11 1168
Chris@11 1169 bool showMeans = (attributes.value("showMeans") == "1" ||
Chris@11 1170 attributes.value("showMeans") == "true");
Chris@11 1171 setShowMeans(showMeans);
Chris@11 1172
Chris@11 1173 bool greyscale = (attributes.value("greyscale") == "1" ||
Chris@11 1174 attributes.value("greyscale") == "true");
Chris@11 1175 setUseGreyscale(greyscale);
Chris@11 1176
Chris@11 1177 ChannelMode channelMode = (ChannelMode)
Chris@11 1178 attributes.value("channelMode").toInt(&ok);
Chris@11 1179 if (ok) setChannelMode(channelMode);
Chris@11 1180
Chris@11 1181 int channel = attributes.value("channel").toInt(&ok);
Chris@11 1182 if (ok) setChannel(channel);
Chris@11 1183
Chris@11 1184 Scale scale = (Scale)
Chris@11 1185 attributes.value("scale").toInt(&ok);
Chris@11 1186 if (ok) setScale(scale);
Chris@11 1187
Chris@11 1188 bool aggressive = (attributes.value("aggressive") == "1" ||
Chris@11 1189 attributes.value("aggressive") == "true");
Chris@11 1190 setUseGreyscale(aggressive);
Chris@67 1191
Chris@67 1192 bool autoNormalize = (attributes.value("autoNormalize") == "1" ||
Chris@67 1193 attributes.value("autoNormalize") == "true");
Chris@67 1194 setAutoNormalize(autoNormalize);
Chris@11 1195 }
Chris@11 1196
Chris@0 1197 #ifdef INCLUDE_MOCFILES
Chris@0 1198 #include "WaveformLayer.moc.cpp"
Chris@0 1199 #endif
Chris@0 1200