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