svgui  1.9
WaveformLayer.cpp
Go to the documentation of this file.
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