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 "base/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 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 //    std::cerr << "WaveformLayer::setChannel(" << channel << ")" << std::endl;
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 //    std::cerr << "WaveformLayer::getChannelArrangement: min " << min << ", max " << max << ", merging " << merging << ", channels " << channels << std::endl;
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     // Although a long for purposes of comparison against the view
00431     // start and end frames, these are known to be non-negative
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     // Our zoom level may differ from that at which the underlying
00547     // model has its blocks.
00548 
00549     // Each pixel within our visible range must always draw from
00550     // exactly the same set of underlying audio frames, no matter what
00551     // the range being drawn is.  And that set of underlying frames
00552     // must remain the same when we scroll one or more pixels left or
00553     // right.
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 //      std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl;
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                         // let's not concern ourselves about the mean
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 //                  paint->setPen(midColour);
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 //                  paint->setPen(midColour);
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 //    std::cerr << "mergingChannels= " << mergingChannels << ", channel  = " << channel << ", value = " << value << ", vy = " << vy << std::endl;
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         // different channels, not comparable
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 

Generated on Wed Feb 20 15:45:30 2008 for SonicVisualiser by  doxygen 1.5.1