00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "WaveformLayer.h"
00017
00018 #include "base/AudioLevel.h"
00019 #include "view/View.h"
00020 #include "base/Profiler.h"
00021 #include "base/RangeMapper.h"
00022 #include "base/ColourDatabase.h"
00023
00024 #include <QPainter>
00025 #include <QPixmap>
00026 #include <QTextStream>
00027
00028 #include <iostream>
00029 #include <cmath>
00030
00031
00032
00033 using std::cerr;
00034 using std::endl;
00035
00036 WaveformLayer::WaveformLayer() :
00037 SingleColourLayer(),
00038 m_model(0),
00039 m_gain(1.0f),
00040 m_autoNormalize(false),
00041 m_showMeans(true),
00042 m_greyscale(true),
00043 m_channelMode(SeparateChannels),
00044 m_channel(-1),
00045 m_scale(LinearScale),
00046 m_aggressive(false),
00047 m_cache(0),
00048 m_cacheValid(false)
00049 {
00050
00051 }
00052
00053 WaveformLayer::~WaveformLayer()
00054 {
00055 delete m_cache;
00056 }
00057
00058 void
00059 WaveformLayer::setModel(const RangeSummarisableTimeValueModel *model)
00060 {
00061 bool channelsChanged = false;
00062 if (m_channel == -1) {
00063 if (!m_model) {
00064 if (model) {
00065 channelsChanged = true;
00066 }
00067 } else {
00068 if (model &&
00069 m_model->getChannelCount() != model->getChannelCount()) {
00070 channelsChanged = true;
00071 }
00072 }
00073 }
00074
00075 m_model = model;
00076 m_cacheValid = false;
00077 if (!m_model || !m_model->isOK()) return;
00078
00079 connectSignals(m_model);
00080
00081 emit modelReplaced();
00082
00083 if (channelsChanged) emit layerParametersChanged();
00084 }
00085
00086 Layer::PropertyList
00087 WaveformLayer::getProperties() const
00088 {
00089 PropertyList list = SingleColourLayer::getProperties();
00090 list.push_back("Scale");
00091 list.push_back("Gain");
00092 list.push_back("Normalize Visible Area");
00093
00094 if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) {
00095 list.push_back("Channels");
00096 }
00097
00098 return list;
00099 }
00100
00101 QString
00102 WaveformLayer::getPropertyLabel(const PropertyName &name) const
00103 {
00104 if (name == "Scale") return tr("Scale");
00105 if (name == "Gain") return tr("Gain");
00106 if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
00107 if (name == "Channels") return tr("Channels");
00108 return SingleColourLayer::getPropertyLabel(name);
00109 }
00110
00111 QString
00112 WaveformLayer::getPropertyIconName(const PropertyName &name) const
00113 {
00114 if (name == "Normalize Visible Area") return "normalise";
00115 return "";
00116 }
00117
00118 Layer::PropertyType
00119 WaveformLayer::getPropertyType(const PropertyName &name) const
00120 {
00121 if (name == "Gain") return RangeProperty;
00122 if (name == "Normalize Visible Area") return ToggleProperty;
00123 if (name == "Channels") return ValueProperty;
00124 if (name == "Scale") return ValueProperty;
00125 return SingleColourLayer::getPropertyType(name);
00126 }
00127
00128 QString
00129 WaveformLayer::getPropertyGroupName(const PropertyName &name) const
00130 {
00131 if (name == "Gain" ||
00132 name == "Normalize Visible Area" ||
00133 name == "Scale") return tr("Scale");
00134 return QString();
00135 }
00136
00137 int
00138 WaveformLayer::getPropertyRangeAndValue(const PropertyName &name,
00139 int *min, int *max, int *deflt) const
00140 {
00141 int val = 0;
00142
00143 int garbage0, garbage1, garbage2;
00144 if (!min) min = &garbage0;
00145 if (!max) max = &garbage1;
00146 if (!deflt) deflt = &garbage2;
00147
00148 if (name == "Gain") {
00149
00150 *min = -50;
00151 *max = 50;
00152 *deflt = 0;
00153
00154 val = lrint(log10(m_gain) * 20.0);
00155 if (val < *min) val = *min;
00156 if (val > *max) val = *max;
00157
00158 } else if (name == "Normalize Visible Area") {
00159
00160 val = (m_autoNormalize ? 1 : 0);
00161 *deflt = 0;
00162
00163 } else if (name == "Channels") {
00164
00165 *min = 0;
00166 *max = 2;
00167 *deflt = 0;
00168 if (m_channelMode == MixChannels) val = 1;
00169 else if (m_channelMode == MergeChannels) val = 2;
00170 else val = 0;
00171
00172 } else if (name == "Scale") {
00173
00174 *min = 0;
00175 *max = 2;
00176 *deflt = 0;
00177
00178 val = (int)m_scale;
00179
00180 } else {
00181 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
00182 }
00183
00184 return val;
00185 }
00186
00187 QString
00188 WaveformLayer::getPropertyValueLabel(const PropertyName &name,
00189 int value) const
00190 {
00191 if (name == "Scale") {
00192 switch (value) {
00193 default:
00194 case 0: return tr("Linear");
00195 case 1: return tr("Meter");
00196 case 2: return tr("dB");
00197 }
00198 }
00199 if (name == "Channels") {
00200 switch (value) {
00201 default:
00202 case 0: return tr("Separate");
00203 case 1: return tr("Mean");
00204 case 2: return tr("Butterfly");
00205 }
00206 }
00207 return SingleColourLayer::getPropertyValueLabel(name, value);
00208 }
00209
00210 RangeMapper *
00211 WaveformLayer::getNewPropertyRangeMapper(const PropertyName &name) const
00212 {
00213 if (name == "Gain") {
00214 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
00215 }
00216 return 0;
00217 }
00218
00219 void
00220 WaveformLayer::setProperty(const PropertyName &name, int value)
00221 {
00222 if (name == "Gain") {
00223 setGain(pow(10, float(value)/20.0));
00224 } else if (name == "Normalize Visible Area") {
00225 setAutoNormalize(value ? true : false);
00226 } else if (name == "Channels") {
00227 if (value == 1) setChannelMode(MixChannels);
00228 else if (value == 2) setChannelMode(MergeChannels);
00229 else setChannelMode(SeparateChannels);
00230 } else if (name == "Scale") {
00231 switch (value) {
00232 default:
00233 case 0: setScale(LinearScale); break;
00234 case 1: setScale(MeterScale); break;
00235 case 2: setScale(dBScale); break;
00236 }
00237 } else {
00238 SingleColourLayer::setProperty(name, value);
00239 }
00240 }
00241
00242 void
00243 WaveformLayer::setGain(float gain)
00244 {
00245 if (m_gain == gain) return;
00246 m_gain = gain;
00247 m_cacheValid = false;
00248 emit layerParametersChanged();
00249 emit verticalZoomChanged();
00250 }
00251
00252 void
00253 WaveformLayer::setAutoNormalize(bool autoNormalize)
00254 {
00255 if (m_autoNormalize == autoNormalize) return;
00256 m_autoNormalize = autoNormalize;
00257 m_cacheValid = false;
00258 emit layerParametersChanged();
00259 }
00260
00261 void
00262 WaveformLayer::setShowMeans(bool showMeans)
00263 {
00264 if (m_showMeans == showMeans) return;
00265 m_showMeans = showMeans;
00266 m_cacheValid = false;
00267 emit layerParametersChanged();
00268 }
00269
00270 void
00271 WaveformLayer::setUseGreyscale(bool useGreyscale)
00272 {
00273 if (m_greyscale == useGreyscale) return;
00274 m_greyscale = useGreyscale;
00275 m_cacheValid = false;
00276 emit layerParametersChanged();
00277 }
00278
00279 void
00280 WaveformLayer::setChannelMode(ChannelMode channelMode)
00281 {
00282 if (m_channelMode == channelMode) return;
00283 m_channelMode = channelMode;
00284 m_cacheValid = false;
00285 emit layerParametersChanged();
00286 }
00287
00288 void
00289 WaveformLayer::setChannel(int channel)
00290 {
00291
00292
00293 if (m_channel == channel) return;
00294 m_channel = channel;
00295 m_cacheValid = false;
00296 emit layerParametersChanged();
00297 }
00298
00299 void
00300 WaveformLayer::setScale(Scale scale)
00301 {
00302 if (m_scale == scale) return;
00303 m_scale = scale;
00304 m_cacheValid = false;
00305 emit layerParametersChanged();
00306 }
00307
00308 void
00309 WaveformLayer::setAggressiveCacheing(bool aggressive)
00310 {
00311 if (m_aggressive == aggressive) return;
00312 m_aggressive = aggressive;
00313 m_cacheValid = false;
00314 emit layerParametersChanged();
00315 }
00316
00317 int
00318 WaveformLayer::getCompletion(View *) const
00319 {
00320 int completion = 100;
00321 if (!m_model || !m_model->isOK()) return completion;
00322 if (m_model->isReady(&completion)) return 100;
00323 return completion;
00324 }
00325
00326 bool
00327 WaveformLayer::getValueExtents(float &min, float &max,
00328 bool &, QString &unit) const
00329 {
00330 if (m_scale == LinearScale) {
00331 min = 0.0;
00332 max = 1.0;
00333 unit = "V";
00334 } else if (m_scale == MeterScale) {
00335 return false;
00336 } else {
00337 min = AudioLevel::multiplier_to_dB(0.0);
00338 max = AudioLevel::multiplier_to_dB(1.0);
00339 unit = "dB";
00340 }
00341 return true;
00342 }
00343
00344 int
00345 WaveformLayer::dBscale(float sample, int m) const
00346 {
00347 if (sample < 0.0) return dBscale(-sample, m);
00348 float dB = AudioLevel::multiplier_to_dB(sample);
00349 if (dB < -50.0) return 0;
00350 if (dB > 0.0) return m;
00351 return int(((dB + 50.0) * m) / 50.0 + 0.1);
00352 }
00353
00354 size_t
00355 WaveformLayer::getChannelArrangement(size_t &min, size_t &max,
00356 bool &merging, bool &mixing)
00357 const
00358 {
00359 if (!m_model || !m_model->isOK()) return 0;
00360
00361 size_t channels = m_model->getChannelCount();
00362 if (channels == 0) return 0;
00363
00364 size_t rawChannels = channels;
00365
00366 if (m_channel == -1) {
00367 min = 0;
00368 if (m_channelMode == MergeChannels ||
00369 m_channelMode == MixChannels) {
00370 max = 0;
00371 channels = 1;
00372 } else {
00373 max = channels - 1;
00374 }
00375 } else {
00376 min = m_channel;
00377 max = m_channel;
00378 rawChannels = 1;
00379 channels = 1;
00380 }
00381
00382 merging = (m_channelMode == MergeChannels && rawChannels > 1);
00383 mixing = (m_channelMode == MixChannels && rawChannels > 1);
00384
00385
00386
00387 return channels;
00388 }
00389
00390 bool
00391 WaveformLayer::isLayerScrollable(const View *) const
00392 {
00393 return !m_autoNormalize;
00394 }
00395
00396 static float meterdbs[] = { -40, -30, -20, -15, -10,
00397 -5, -3, -2, -1, -0.5, 0 };
00398
00399 bool
00400 WaveformLayer::getSourceFramesForX(View *v, int x, size_t modelZoomLevel,
00401 size_t &f0, size_t &f1) const
00402 {
00403 long viewFrame = v->getFrameForX(x);
00404 if (viewFrame < 0) {
00405 f0 = 0;
00406 f1 = 0;
00407 return false;
00408 }
00409
00410 f0 = viewFrame;
00411
00412 f0 = f0 / modelZoomLevel;
00413 f0 = f0 * modelZoomLevel;
00414
00415 viewFrame = v->getFrameForX(x + 1);
00416
00417 f1 = viewFrame;
00418 f1 = f1 / modelZoomLevel;
00419 f1 = f1 * modelZoomLevel;
00420
00421 return (f0 < m_model->getEndFrame());
00422 }
00423
00424 float
00425 WaveformLayer::getNormalizeGain(View *v, int channel) const
00426 {
00427 long startFrame = v->getStartFrame();
00428 long endFrame = v->getEndFrame();
00429
00430
00431
00432 long modelStart = long(m_model->getStartFrame());
00433 long modelEnd = long(m_model->getEndFrame());
00434
00435 size_t rangeStart, rangeEnd;
00436
00437 if (startFrame < modelStart) rangeStart = modelStart;
00438 else rangeStart = startFrame;
00439
00440 if (endFrame < 0) rangeEnd = 0;
00441 else if (endFrame > modelEnd) rangeEnd = modelEnd;
00442 else rangeEnd = endFrame;
00443
00444 if (rangeEnd < rangeStart) rangeEnd = rangeStart;
00445
00446 RangeSummarisableTimeValueModel::Range range =
00447 m_model->getSummary(channel, rangeStart, rangeEnd - rangeStart);
00448
00449 size_t minChannel = 0, maxChannel = 0;
00450 bool mergingChannels = false, mixingChannels = false;
00451
00452 getChannelArrangement(minChannel, maxChannel,
00453 mergingChannels, mixingChannels);
00454
00455 if (mergingChannels || mixingChannels) {
00456 RangeSummarisableTimeValueModel::Range otherRange =
00457 m_model->getSummary(1, rangeStart, rangeEnd - rangeStart);
00458 range.max = std::max(range.max, otherRange.max);
00459 range.min = std::min(range.min, otherRange.min);
00460 range.absmean = std::min(range.absmean, otherRange.absmean);
00461 }
00462
00463 return 1.0 / std::max(fabsf(range.max), fabsf(range.min));
00464 }
00465
00466 void
00467 WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const
00468 {
00469 if (!m_model || !m_model->isOK()) {
00470 return;
00471 }
00472
00473 int zoomLevel = v->getZoomLevel();
00474
00475 #ifdef DEBUG_WAVEFORM_PAINT
00476 Profiler profiler("WaveformLayer::paint", true);
00477 std::cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y()
00478 << ") [" << rect.width() << "x" << rect.height() << "]: zoom " << zoomLevel << ", start " << startFrame << std::endl;
00479 #endif
00480
00481 size_t channels = 0, minChannel = 0, maxChannel = 0;
00482 bool mergingChannels = false, mixingChannels = false;
00483
00484 channels = getChannelArrangement(minChannel, maxChannel,
00485 mergingChannels, mixingChannels);
00486 if (channels == 0) return;
00487
00488 int w = v->width();
00489 int h = v->height();
00490
00491 bool ready = m_model->isReady();
00492 QPainter *paint;
00493
00494 if (m_aggressive) {
00495
00496 #ifdef DEBUG_WAVEFORM_PAINT
00497 std::cerr << "WaveformLayer::paint: aggressive is true" << std::endl;
00498 #endif
00499
00500 if (m_cacheValid && (zoomLevel != m_cacheZoomLevel)) {
00501 m_cacheValid = false;
00502 }
00503
00504 if (!m_cache || m_cache->width() != w || m_cache->height() != h) {
00505 #ifdef DEBUG_WAVEFORM_PAINT
00506 if (m_cache) {
00507 std::cerr << "WaveformLayer::paint: cache size " << m_cache->width() << "x" << m_cache->height() << " differs from view size " << w << "x" << h << ": regenerating aggressive cache" << std::endl;
00508 }
00509 #endif
00510 delete m_cache;
00511 m_cache = new QPixmap(w, h);
00512 m_cacheValid = false;
00513 }
00514
00515 if (m_cacheValid) {
00516 viewPainter.drawPixmap(rect, *m_cache, rect);
00517 return;
00518 }
00519
00520 paint = new QPainter(m_cache);
00521
00522 paint->setPen(Qt::NoPen);
00523 paint->setBrush(getBackgroundQColor(v));
00524 paint->drawRect(rect);
00525
00526 paint->setPen(getForegroundQColor(v));
00527 paint->setBrush(Qt::NoBrush);
00528
00529 } else {
00530 paint = &viewPainter;
00531 }
00532
00533 paint->setRenderHint(QPainter::Antialiasing, false);
00534
00535 int x0 = 0, x1 = w - 1;
00536 int y0 = 0, y1 = h - 1;
00537
00538 x0 = rect.left();
00539 x1 = rect.right();
00540 y0 = rect.top();
00541 y1 = rect.bottom();
00542
00543 if (x0 > 0) --x0;
00544 if (x1 < v->width()) ++x1;
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel);
00556
00557 size_t frame0;
00558 size_t frame1;
00559 size_t spare;
00560
00561 getSourceFramesForX(v, x0, modelZoomLevel, frame0, spare);
00562 getSourceFramesForX(v, x1, modelZoomLevel, spare, frame1);
00563
00564 #ifdef DEBUG_WAVEFORM_PAINT
00565 std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << " and model zoom " << modelZoomLevel << ")" << std::endl;
00566 #endif
00567
00568 RangeSummarisableTimeValueModel::RangeBlock *ranges =
00569 new RangeSummarisableTimeValueModel::RangeBlock;
00570
00571 RangeSummarisableTimeValueModel::RangeBlock *otherChannelRanges = 0;
00572 RangeSummarisableTimeValueModel::Range range;
00573
00574 QColor baseColour = getBaseQColor();
00575 std::vector<QColor> greys = getPartialShades(v);
00576
00577 QColor midColour = baseColour;
00578 if (midColour == Qt::black) {
00579 midColour = Qt::gray;
00580 } else if (v->hasLightBackground()) {
00581 midColour = midColour.light(150);
00582 } else {
00583 midColour = midColour.light(50);
00584 }
00585
00586 while (m_effectiveGains.size() <= maxChannel) {
00587 m_effectiveGains.push_back(m_gain);
00588 }
00589
00590 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
00591
00592 int prevRangeBottom = -1, prevRangeTop = -1;
00593 QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour;
00594
00595 m_effectiveGains[ch] = m_gain;
00596
00597 if (m_autoNormalize) {
00598 m_effectiveGains[ch] = getNormalizeGain(v, ch);
00599 }
00600
00601 float gain = m_effectiveGains[ch];
00602
00603 int m = (h / channels) / 2;
00604 int my = m + (((ch - minChannel) * h) / channels);
00605
00606
00607
00608 if (my - m > y1 || my + m < y0) continue;
00609
00610 if ((m_scale == dBScale || m_scale == MeterScale) &&
00611 m_channelMode != MergeChannels) {
00612 m = (h / channels);
00613 my = m + (((ch - minChannel) * h) / channels);
00614 }
00615
00616 paint->setPen(greys[1]);
00617 paint->drawLine(x0, my, x1, my);
00618
00619 int n = 10;
00620 int py = -1;
00621
00622 if (v->hasLightBackground() &&
00623 v->getViewManager() &&
00624 v->getViewManager()->shouldShowScaleGuides()) {
00625
00626 paint->setPen(QColor(240, 240, 240));
00627
00628 for (int i = 1; i < n; ++i) {
00629
00630 float val = 0.0, nval = 0.0;
00631
00632 switch (m_scale) {
00633
00634 case LinearScale:
00635 val = (i * gain) / n;
00636 if (i > 0) nval = -val;
00637 break;
00638
00639 case MeterScale:
00640 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
00641 break;
00642
00643 case dBScale:
00644 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
00645 break;
00646 }
00647
00648 if (val < -1.0 || val > 1.0) continue;
00649
00650 int y = getYForValue(v, val, ch);
00651
00652 if (py >= 0 && abs(y - py) < 10) continue;
00653 else py = y;
00654
00655 int ny = y;
00656 if (nval != 0.0) {
00657 ny = getYForValue(v, nval, ch);
00658 }
00659
00660 paint->drawLine(x0, y, x1, y);
00661 if (ny != y) {
00662 paint->drawLine(x0, ny, x1, ny);
00663 }
00664 }
00665 }
00666
00667 m_model->getSummaries(ch, frame0, frame1 - frame0,
00668 *ranges, modelZoomLevel);
00669
00670 #ifdef DEBUG_WAVEFORM_PAINT
00671 std::cerr << ranges->size() << " ranges from " << frame0 << " to " << frame1 << std::endl;
00672 #endif
00673
00674 if (mergingChannels || mixingChannels) {
00675 if (m_model->getChannelCount() > 1) {
00676 if (!otherChannelRanges) {
00677 otherChannelRanges =
00678 new RangeSummarisableTimeValueModel::RangeBlock;
00679 }
00680 m_model->getSummaries
00681 (1, frame0, frame1 - frame0, *otherChannelRanges,
00682 modelZoomLevel);
00683 } else {
00684 if (otherChannelRanges != ranges) delete otherChannelRanges;
00685 otherChannelRanges = ranges;
00686 }
00687 }
00688
00689 for (int x = x0; x <= x1; ++x) {
00690
00691 range = RangeSummarisableTimeValueModel::Range();
00692
00693 size_t f0, f1;
00694 if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) continue;
00695 f1 = f1 - 1;
00696
00697 if (f0 < frame0) {
00698 std::cerr << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << std::endl;
00699 continue;
00700 }
00701
00702 size_t i0 = (f0 - frame0) / modelZoomLevel;
00703 size_t i1 = (f1 - frame0) / modelZoomLevel;
00704
00705 #ifdef DEBUG_WAVEFORM_PAINT
00706 std::cerr << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << std::endl;
00707 #endif
00708
00709 if (i1 > i0 + 1) {
00710 std::cerr << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << zoomLevel << ", model zoom = " << modelZoomLevel << ")" << std::endl;
00711 }
00712
00713 if (ranges && i0 < ranges->size()) {
00714
00715 range = (*ranges)[i0];
00716
00717 if (i1 > i0 && i1 < ranges->size()) {
00718 range.max = std::max(range.max, (*ranges)[i1].max);
00719 range.min = std::min(range.min, (*ranges)[i1].min);
00720 range.absmean = (range.absmean + (*ranges)[i1].absmean) / 2;
00721 }
00722
00723 } else {
00724 continue;
00725 }
00726
00727 int rangeBottom = 0, rangeTop = 0, meanBottom = 0, meanTop = 0;
00728
00729 if (mergingChannels) {
00730
00731 if (otherChannelRanges && i0 < otherChannelRanges->size()) {
00732
00733 range.max = fabsf(range.max);
00734 range.min = -fabsf((*otherChannelRanges)[i0].max);
00735 range.absmean = (range.absmean +
00736 (*otherChannelRanges)[i0].absmean) / 2;
00737
00738 if (i1 > i0 && i1 < otherChannelRanges->size()) {
00739
00740 range.min = std::min
00741 (range.min,
00742 -fabsf((*otherChannelRanges)[i1].max));
00743 }
00744 }
00745
00746 } else if (mixingChannels) {
00747
00748 if (otherChannelRanges && i0 < otherChannelRanges->size()) {
00749
00750 range.max = (range.max + (*otherChannelRanges)[i0].max) / 2;
00751 range.min = (range.min + (*otherChannelRanges)[i0].min) / 2;
00752 range.absmean = (range.absmean + (*otherChannelRanges)[i0].absmean) / 2;
00753 }
00754 }
00755
00756 int greyLevels = 1;
00757 if (m_greyscale && (m_scale == LinearScale)) greyLevels = 4;
00758
00759 switch (m_scale) {
00760
00761 case LinearScale:
00762 rangeBottom = int( m * greyLevels * range.min * gain);
00763 rangeTop = int( m * greyLevels * range.max * gain);
00764 meanBottom = int(-m * range.absmean * gain);
00765 meanTop = int( m * range.absmean * gain);
00766 break;
00767
00768 case dBScale:
00769 if (!mergingChannels) {
00770 int db0 = dBscale(range.min * gain, m);
00771 int db1 = dBscale(range.max * gain, m);
00772 rangeTop = std::max(db0, db1);
00773 meanTop = std::min(db0, db1);
00774 if (mixingChannels) rangeBottom = meanTop;
00775 else rangeBottom = dBscale(range.absmean * gain, m);
00776 meanBottom = rangeBottom;
00777 } else {
00778 rangeBottom = -dBscale(range.min * gain, m * greyLevels);
00779 rangeTop = dBscale(range.max * gain, m * greyLevels);
00780 meanBottom = -dBscale(range.absmean * gain, m);
00781 meanTop = dBscale(range.absmean * gain, m);
00782 }
00783 break;
00784
00785 case MeterScale:
00786 if (!mergingChannels) {
00787 int r0 = abs(AudioLevel::multiplier_to_preview(range.min * gain, m));
00788 int r1 = abs(AudioLevel::multiplier_to_preview(range.max * gain, m));
00789 rangeTop = std::max(r0, r1);
00790 meanTop = std::min(r0, r1);
00791 if (mixingChannels) rangeBottom = meanTop;
00792 else rangeBottom = AudioLevel::multiplier_to_preview(range.absmean * gain, m);
00793 meanBottom = rangeBottom;
00794 } else {
00795 rangeBottom = -AudioLevel::multiplier_to_preview(range.min * gain, m * greyLevels);
00796 rangeTop = AudioLevel::multiplier_to_preview(range.max * gain, m * greyLevels);
00797 meanBottom = -AudioLevel::multiplier_to_preview(range.absmean * gain, m);
00798 meanTop = AudioLevel::multiplier_to_preview(range.absmean * gain, m);
00799 }
00800 break;
00801 }
00802
00803 rangeBottom = my * greyLevels - rangeBottom;
00804 rangeTop = my * greyLevels - rangeTop;
00805 meanBottom = my - meanBottom;
00806 meanTop = my - meanTop;
00807
00808 int topFill = (rangeTop % greyLevels);
00809 if (topFill > 0) topFill = greyLevels - topFill;
00810
00811 int bottomFill = (rangeBottom % greyLevels);
00812
00813 rangeTop = rangeTop / greyLevels;
00814 rangeBottom = rangeBottom / greyLevels;
00815
00816 bool clipped = false;
00817
00818 if (rangeTop < my - m) { rangeTop = my - m; }
00819 if (rangeTop > my + m) { rangeTop = my + m; }
00820 if (rangeBottom < my - m) { rangeBottom = my - m; }
00821 if (rangeBottom > my + m) { rangeBottom = my + m; }
00822
00823 if (range.max <= -1.0 ||
00824 range.max >= 1.0) clipped = true;
00825
00826 if (meanBottom > rangeBottom) meanBottom = rangeBottom;
00827 if (meanTop < rangeTop) meanTop = rangeTop;
00828
00829 bool drawMean = m_showMeans;
00830 if (meanTop == rangeTop) {
00831 if (meanTop < meanBottom) ++meanTop;
00832 else drawMean = false;
00833 }
00834 if (meanBottom == rangeBottom && m_scale == LinearScale) {
00835 if (meanBottom > meanTop) --meanBottom;
00836 else drawMean = false;
00837 }
00838
00839 if (x != x0 && prevRangeBottom != -1) {
00840 if (prevRangeBottom > rangeBottom &&
00841 prevRangeTop > rangeBottom) {
00842
00843 paint->setPen(baseColour);
00844 paint->drawLine(x-1, prevRangeTop, x, rangeBottom);
00845 paint->setPen(prevRangeTopColour);
00846 paint->drawPoint(x-1, prevRangeTop);
00847 } else if (prevRangeBottom < rangeTop &&
00848 prevRangeTop < rangeTop) {
00849
00850 paint->setPen(baseColour);
00851 paint->drawLine(x-1, prevRangeBottom, x, rangeTop);
00852 paint->setPen(prevRangeBottomColour);
00853 paint->drawPoint(x-1, prevRangeBottom);
00854 }
00855 }
00856
00857 if (ready) {
00858 if (clipped ) {
00861 paint->setPen(Qt::red);
00862 } else {
00863 paint->setPen(baseColour);
00864 }
00865 } else {
00866 paint->setPen(midColour);
00867 }
00868
00869 paint->drawLine(x, rangeBottom, x, rangeTop);
00870
00871 prevRangeTopColour = baseColour;
00872 prevRangeBottomColour = baseColour;
00873
00874 if (m_greyscale && (m_scale == LinearScale) && ready) {
00875 if (!clipped) {
00876 if (rangeTop < rangeBottom) {
00877 if (topFill > 0 &&
00878 (!drawMean || (rangeTop < meanTop - 1))) {
00879 paint->setPen(greys[topFill - 1]);
00880 paint->drawPoint(x, rangeTop);
00881 prevRangeTopColour = greys[topFill - 1];
00882 }
00883 if (bottomFill > 0 &&
00884 (!drawMean || (rangeBottom > meanBottom + 1))) {
00885 paint->setPen(greys[bottomFill - 1]);
00886 paint->drawPoint(x, rangeBottom);
00887 prevRangeBottomColour = greys[bottomFill - 1];
00888 }
00889 }
00890 }
00891 }
00892
00893 if (drawMean) {
00894 paint->setPen(midColour);
00895 paint->drawLine(x, meanBottom, x, meanTop);
00896 }
00897
00898 prevRangeBottom = rangeBottom;
00899 prevRangeTop = rangeTop;
00900 }
00901 }
00902
00903 if (m_aggressive) {
00904
00905 if (ready && rect == v->rect()) {
00906 m_cacheValid = true;
00907 m_cacheZoomLevel = zoomLevel;
00908 }
00909 paint->end();
00910 delete paint;
00911 viewPainter.drawPixmap(rect, *m_cache, rect);
00912 }
00913
00914 if (otherChannelRanges != ranges) delete otherChannelRanges;
00915 delete ranges;
00916 }
00917
00918 QString
00919 WaveformLayer::getFeatureDescription(View *v, QPoint &pos) const
00920 {
00921 int x = pos.x();
00922
00923 if (!m_model || !m_model->isOK()) return "";
00924
00925 int zoomLevel = v->getZoomLevel();
00926
00927 size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel);
00928
00929 size_t f0, f1;
00930 if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) return "";
00931
00932 QString text;
00933
00934 RealTime rt0 = RealTime::frame2RealTime(f0, m_model->getSampleRate());
00935 RealTime rt1 = RealTime::frame2RealTime(f1, m_model->getSampleRate());
00936
00937 if (f1 != f0 + 1 && (rt0.sec != rt1.sec || rt0.msec() != rt1.msec())) {
00938 text += tr("Time:\t%1 - %2")
00939 .arg(rt0.toText(true).c_str())
00940 .arg(rt1.toText(true).c_str());
00941 } else {
00942 text += tr("Time:\t%1")
00943 .arg(rt0.toText(true).c_str());
00944 }
00945
00946 size_t channels = 0, minChannel = 0, maxChannel = 0;
00947 bool mergingChannels = false, mixingChannels = false;
00948
00949 channels = getChannelArrangement(minChannel, maxChannel,
00950 mergingChannels, mixingChannels);
00951 if (channels == 0) return "";
00952
00953 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
00954
00955 size_t blockSize = v->getZoomLevel();
00956 RangeSummarisableTimeValueModel::RangeBlock ranges;
00957 m_model->getSummaries(ch, f0, f1 - f0, ranges, blockSize);
00958
00959 if (ranges.empty()) continue;
00960
00961 RangeSummarisableTimeValueModel::Range range = ranges[0];
00962
00963 QString label = tr("Level:");
00964 if (minChannel != maxChannel) {
00965 if (ch == 0) label = tr("Left:");
00966 else if (ch == 1) label = tr("Right:");
00967 else label = tr("Channel %1").arg(ch + 1);
00968 }
00969
00970 bool singleValue = false;
00971 float min, max;
00972
00973 if (fabs(range.min) < 0.01) {
00974 min = range.min;
00975 max = range.max;
00976 singleValue = (min == max);
00977 } else {
00978 int imin = int(range.min * 1000);
00979 int imax = int(range.max * 1000);
00980 singleValue = (imin == imax);
00981 min = float(imin)/1000;
00982 max = float(imax)/1000;
00983 }
00984
00985 int db = int(AudioLevel::multiplier_to_dB(std::max(fabsf(range.min),
00986 fabsf(range.max)))
00987 * 100);
00988
00989 if (!singleValue) {
00990 text += tr("\n%1\t%2 - %3 (%4 dB peak)")
00991 .arg(label).arg(min).arg(max).arg(float(db)/100);
00992 } else {
00993 text += tr("\n%1\t%2 (%3 dB peak)")
00994 .arg(label).arg(min).arg(float(db)/100);
00995 }
00996 }
00997
00998 return text;
00999 }
01000
01001 int
01002 WaveformLayer::getYForValue(const View *v, float value, size_t channel) const
01003 {
01004 size_t channels = 0, minChannel = 0, maxChannel = 0;
01005 bool mergingChannels = false, mixingChannels = false;
01006
01007 channels = getChannelArrangement(minChannel, maxChannel,
01008 mergingChannels, mixingChannels);
01009
01010 if (maxChannel < minChannel || channel < minChannel) return 0;
01011
01012 int h = v->height();
01013 int m = (h / channels) / 2;
01014
01015 if ((m_scale == dBScale || m_scale == MeterScale) &&
01016 m_channelMode != MergeChannels) {
01017 m = (h / channels);
01018 }
01019
01020 int my = m + (((channel - minChannel) * h) / channels);
01021
01022 int vy = 0;
01023
01024 switch (m_scale) {
01025
01026 case LinearScale:
01027 vy = int(m * value);
01028 break;
01029
01030 case MeterScale:
01031 vy = AudioLevel::multiplier_to_preview(value, m);
01032 break;
01033
01034 case dBScale:
01035 vy = dBscale(value, m);
01036 break;
01037 }
01038
01039
01040
01041 return my - vy;
01042 }
01043
01044 float
01045 WaveformLayer::getValueForY(const View *v, int y, size_t &channel) const
01046 {
01047 size_t channels = 0, minChannel = 0, maxChannel = 0;
01048 bool mergingChannels = false, mixingChannels = false;
01049
01050 channels = getChannelArrangement(minChannel, maxChannel,
01051 mergingChannels, mixingChannels);
01052
01053 if (maxChannel < minChannel) return 0;
01054
01055 int h = v->height();
01056 int m = (h / channels) / 2;
01057
01058 if ((m_scale == dBScale || m_scale == MeterScale) &&
01059 m_channelMode != MergeChannels) {
01060 m = (h / channels);
01061 }
01062
01063 channel = (y * channels) / h + minChannel;
01064
01065 int my = m + (((channel - minChannel) * h) / channels);
01066
01067 int vy = my - y;
01068 float value = 0;
01069 float thresh = -50.f;
01070
01071 switch (m_scale) {
01072
01073 case LinearScale:
01074 value = float(vy) / m;
01075 break;
01076
01077 case MeterScale:
01078 value = AudioLevel::preview_to_multiplier(vy, m);
01079 break;
01080
01081 case dBScale:
01082 value = (-thresh * float(vy)) / m + thresh;
01083 value = AudioLevel::dB_to_multiplier(value);
01084 break;
01085 }
01086
01087 return value / m_gain;
01088 }
01089
01090 bool
01091 WaveformLayer::getYScaleValue(const View *v, int y,
01092 float &value, QString &unit) const
01093 {
01094 size_t channel;
01095
01096 value = getValueForY(v, y, channel);
01097
01098 if (m_scale == dBScale || m_scale == MeterScale) {
01099
01100 float thresh = -50.f;
01101
01102 if (value > 0.f) {
01103 value = 10.f * log10f(value);
01104 if (value < thresh) value = thresh;
01105 } else value = thresh;
01106
01107 unit = "dBV";
01108
01109 } else {
01110 unit = "V";
01111 }
01112
01113 return true;
01114 }
01115
01116 bool
01117 WaveformLayer::getYScaleDifference(const View *v, int y0, int y1,
01118 float &diff, QString &unit) const
01119 {
01120 size_t c0, c1;
01121 float v0 = getValueForY(v, y0, c0);
01122 float v1 = getValueForY(v, y1, c1);
01123
01124 if (c0 != c1) {
01125
01126 diff = 0.f;
01127 unit = "";
01128 return false;
01129 }
01130
01131 if (m_scale == dBScale || m_scale == MeterScale) {
01132
01133 float thresh = -50.f;
01134
01135 if (v1 == v0) diff = thresh;
01136 else {
01137 if (v1 > v0) diff = v0 / v1;
01138 else diff = v1 / v0;
01139
01140 diff = 10.f * log10f(diff);
01141 if (diff < thresh) diff = thresh;
01142 }
01143
01144 unit = "dBV";
01145
01146 } else {
01147 diff = fabsf(v1 - v0);
01148 unit = "V";
01149 }
01150
01151 return true;
01152 }
01153
01154 int
01155 WaveformLayer::getVerticalScaleWidth(View *, QPainter &paint) const
01156 {
01157 if (m_scale == LinearScale) {
01158 return paint.fontMetrics().width("0.0") + 13;
01159 } else {
01160 return std::max(paint.fontMetrics().width(tr("0dB")),
01161 paint.fontMetrics().width(tr("-Inf"))) + 13;
01162 }
01163 }
01164
01165 void
01166 WaveformLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
01167 {
01168 if (!m_model || !m_model->isOK()) {
01169 return;
01170 }
01171
01172 size_t channels = 0, minChannel = 0, maxChannel = 0;
01173 bool mergingChannels = false, mixingChannels = false;
01174
01175 channels = getChannelArrangement(minChannel, maxChannel,
01176 mergingChannels, mixingChannels);
01177 if (channels == 0) return;
01178
01179 int h = rect.height(), w = rect.width();
01180 int textHeight = paint.fontMetrics().height();
01181 int toff = -textHeight/2 + paint.fontMetrics().ascent() + 1;
01182
01183 float gain = m_gain;
01184
01185 for (size_t ch = minChannel; ch <= maxChannel; ++ch) {
01186
01187 int lastLabelledY = -1;
01188
01189 if (ch < m_effectiveGains.size()) gain = m_effectiveGains[ch];
01190
01191 int n = 10;
01192
01193 for (int i = 0; i <= n; ++i) {
01194
01195 float val = 0.0, nval = 0.0;
01196 QString text = "";
01197
01198 switch (m_scale) {
01199
01200 case LinearScale:
01201 val = (i * gain) / n;
01202 text = QString("%1").arg(float(i) / n);
01203 if (i == 0) text = "0.0";
01204 else {
01205 nval = -val;
01206 if (i == n) text = "1.0";
01207 }
01208 break;
01209
01210 case MeterScale:
01211 val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain;
01212 text = QString("%1").arg(meterdbs[i]);
01213 if (i == n) text = tr("0dB");
01214 if (i == 0) {
01215 text = tr("-Inf");
01216 val = 0.0;
01217 }
01218 break;
01219
01220 case dBScale:
01221 val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain;
01222 text = QString("%1").arg(-(10*n) + i * 10);
01223 if (i == n) text = tr("0dB");
01224 if (i == 0) {
01225 text = tr("-Inf");
01226 val = 0.0;
01227 }
01228 break;
01229 }
01230
01231 if (val < -1.0 || val > 1.0) continue;
01232
01233 int y = getYForValue(v, val, ch);
01234
01235 int ny = y;
01236 if (nval != 0.0) {
01237 ny = getYForValue(v, nval, ch);
01238 }
01239
01240 bool spaceForLabel = (i == 0 ||
01241 abs(y - lastLabelledY) >= textHeight - 1);
01242
01243 if (spaceForLabel) {
01244
01245 int tx = 3;
01246 if (m_scale != LinearScale) {
01247 tx = w - 10 - paint.fontMetrics().width(text);
01248 }
01249
01250 int ty = y;
01251 if (ty < paint.fontMetrics().ascent()) {
01252 ty = paint.fontMetrics().ascent();
01253 } else if (ty > h - paint.fontMetrics().descent()) {
01254 ty = h - paint.fontMetrics().descent();
01255 } else {
01256 ty += toff;
01257 }
01258 paint.drawText(tx, ty, text);
01259
01260 lastLabelledY = ty - toff;
01261
01262 if (ny != y) {
01263 ty = ny;
01264 if (ty < paint.fontMetrics().ascent()) {
01265 ty = paint.fontMetrics().ascent();
01266 } else if (ty > h - paint.fontMetrics().descent()) {
01267 ty = h - paint.fontMetrics().descent();
01268 } else {
01269 ty += toff;
01270 }
01271 paint.drawText(tx, ty, text);
01272 }
01273
01274 paint.drawLine(w - 7, y, w, y);
01275 if (ny != y) paint.drawLine(w - 7, ny, w, ny);
01276
01277 } else {
01278
01279 paint.drawLine(w - 4, y, w, y);
01280 if (ny != y) paint.drawLine(w - 4, ny, w, ny);
01281 }
01282 }
01283 }
01284 }
01285
01286 void
01287 WaveformLayer::toXml(QTextStream &stream,
01288 QString indent, QString extraAttributes) const
01289 {
01290 QString s;
01291
01292 QString colourName, colourSpec, darkbg;
01293 ColourDatabase::getInstance()->getStringValues
01294 (m_colour, colourName, colourSpec, darkbg);
01295
01296 s += QString("gain=\"%1\" "
01297 "showMeans=\"%2\" "
01298 "greyscale=\"%3\" "
01299 "channelMode=\"%4\" "
01300 "channel=\"%5\" "
01301 "scale=\"%6\" "
01302 "aggressive=\"%7\" "
01303 "autoNormalize=\"%8\"")
01304 .arg(m_gain)
01305 .arg(m_showMeans)
01306 .arg(m_greyscale)
01307 .arg(m_channelMode)
01308 .arg(m_channel)
01309 .arg(m_scale)
01310 .arg(m_aggressive)
01311 .arg(m_autoNormalize);
01312
01313 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s);
01314 }
01315
01316 void
01317 WaveformLayer::setProperties(const QXmlAttributes &attributes)
01318 {
01319 bool ok = false;
01320
01321 SingleColourLayer::setProperties(attributes);
01322
01323 float gain = attributes.value("gain").toFloat(&ok);
01324 if (ok) setGain(gain);
01325
01326 bool showMeans = (attributes.value("showMeans") == "1" ||
01327 attributes.value("showMeans") == "true");
01328 setShowMeans(showMeans);
01329
01330 bool greyscale = (attributes.value("greyscale") == "1" ||
01331 attributes.value("greyscale") == "true");
01332 setUseGreyscale(greyscale);
01333
01334 ChannelMode channelMode = (ChannelMode)
01335 attributes.value("channelMode").toInt(&ok);
01336 if (ok) setChannelMode(channelMode);
01337
01338 int channel = attributes.value("channel").toInt(&ok);
01339 if (ok) setChannel(channel);
01340
01341 Scale scale = (Scale)
01342 attributes.value("scale").toInt(&ok);
01343 if (ok) setScale(scale);
01344
01345 bool aggressive = (attributes.value("aggressive") == "1" ||
01346 attributes.value("aggressive") == "true");
01347 setUseGreyscale(aggressive);
01348
01349 bool autoNormalize = (attributes.value("autoNormalize") == "1" ||
01350 attributes.value("autoNormalize") == "true");
01351 setAutoNormalize(autoNormalize);
01352 }
01353
01354 int
01355 WaveformLayer::getVerticalZoomSteps(int &defaultStep) const
01356 {
01357 defaultStep = 50;
01358 return 100;
01359 }
01360
01361 int
01362 WaveformLayer::getCurrentVerticalZoomStep() const
01363 {
01364 int val = lrint(log10(m_gain) * 20.0) + 50;
01365 if (val < 0) val = 0;
01366 if (val > 100) val = 100;
01367 return val;
01368 }
01369
01370 void
01371 WaveformLayer::setVerticalZoomStep(int step)
01372 {
01373 setGain(pow(10, float(step - 50) / 20.0));
01374 }
01375