svgui  1.9
SliceLayer.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-2007 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 "SliceLayer.h"
00017 
00018 #include "view/View.h"
00019 #include "base/AudioLevel.h"
00020 #include "base/RangeMapper.h"
00021 #include "base/RealTime.h"
00022 #include "ColourMapper.h"
00023 #include "ColourDatabase.h"
00024 
00025 #include "PaintAssistant.h"
00026 
00027 #include <QPainter>
00028 #include <QPainterPath>
00029 #include <QTextStream>
00030 
00031 
00032 SliceLayer::SliceLayer() :
00033     m_sliceableModel(0),
00034     m_colourMap(0),
00035     m_energyScale(dBScale),
00036     m_samplingMode(SampleMean),
00037     m_plotStyle(PlotSteps),
00038     m_binScale(LinearBins),
00039     m_normalize(false),
00040     m_threshold(0.0),
00041     m_initialThreshold(0.0),
00042     m_gain(1.0),
00043     m_currentf0(0),
00044     m_currentf1(0)
00045 {
00046 }
00047 
00048 SliceLayer::~SliceLayer()
00049 {
00050 
00051 }
00052 
00053 void
00054 SliceLayer::setSliceableModel(const Model *model)
00055 {
00056     const DenseThreeDimensionalModel *sliceable =
00057         dynamic_cast<const DenseThreeDimensionalModel *>(model);
00058 
00059     if (model && !sliceable) {
00060         cerr << "WARNING: SliceLayer::setSliceableModel(" << model
00061                   << "): model is not a DenseThreeDimensionalModel" << endl;
00062     }
00063 
00064     if (m_sliceableModel == sliceable) return;
00065 
00066     m_sliceableModel = sliceable;
00067 
00068     connectSignals(m_sliceableModel);
00069 
00070     emit modelReplaced();
00071 }
00072 
00073 void
00074 SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement)
00075 {
00076     SVDEBUG << "SliceLayer::sliceableModelReplaced(" << orig << ", " << replacement << ")" << endl;
00077 
00078     if (orig == m_sliceableModel) {
00079         setSliceableModel
00080             (dynamic_cast<const DenseThreeDimensionalModel *>(replacement));
00081     }
00082 }
00083 
00084 void
00085 SliceLayer::modelAboutToBeDeleted(Model *m)
00086 {
00087     SVDEBUG << "SliceLayer::modelAboutToBeDeleted(" << m << ")" << endl;
00088 
00089     if (m == m_sliceableModel) {
00090         setSliceableModel(0);
00091     }
00092 }
00093 
00094 QString
00095 SliceLayer::getFeatureDescription(View *v, QPoint &p) const
00096 {
00097     int minbin, maxbin, range;
00098     return getFeatureDescriptionAux(v, p, true, minbin, maxbin, range);
00099 }
00100 
00101 QString
00102 SliceLayer::getFeatureDescriptionAux(View *v, QPoint &p,
00103                                      bool includeBinDescription,
00104                                      int &minbin, int &maxbin, int &range) const
00105 {
00106     minbin = 0;
00107     maxbin = 0;
00108     if (!m_sliceableModel) return "";
00109 
00110     int xorigin = m_xorigins[v];
00111     int w = v->width() - xorigin - 1;
00112     
00113     int mh = m_sliceableModel->getHeight();
00114     minbin = getBinForX(p.x() - xorigin, mh, w);
00115     maxbin = getBinForX(p.x() - xorigin + 1, mh, w);
00116 
00117     if (minbin >= mh) minbin = mh - 1;
00118     if (maxbin >= mh) maxbin = mh - 1;
00119     if (minbin < 0) minbin = 0;
00120     if (maxbin < 0) maxbin = 0;
00121     
00122     int sampleRate = m_sliceableModel->getSampleRate();
00123 
00124     int f0 = m_currentf0;
00125     int f1 = m_currentf1;
00126 
00127     RealTime rt0 = RealTime::frame2RealTime(f0, sampleRate);
00128     RealTime rt1 = RealTime::frame2RealTime(f1, sampleRate);
00129     
00130     range = f1 - f0 + 1;
00131 
00132     QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str());
00133 
00134     if (includeBinDescription) {
00135 
00136         float minvalue = 0.f;
00137         if (minbin < int(m_values.size())) minvalue = m_values[minbin];
00138 
00139         float maxvalue = minvalue;
00140         if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin];
00141         
00142         if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
00143         
00144         QString binstr;
00145         if (maxbin != minbin) {
00146             binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1);
00147         } else {
00148             binstr = QString("%1").arg(minbin+1);
00149         }
00150 
00151         QString valuestr;
00152         if (maxvalue != minvalue) {
00153             valuestr = tr("%1 - %2").arg(minvalue).arg(maxvalue);
00154         } else {
00155             valuestr = QString("%1").arg(minvalue);
00156         }
00157 
00158         QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples (%4)\nBin:\t%5\n%6 value:\t%7")
00159             .arg(QString::fromStdString(rt0.toText(true)))
00160             .arg(QString::fromStdString(rt1.toText(true)))
00161             .arg(range)
00162             .arg(rtrangestr)
00163             .arg(binstr)
00164             .arg(m_samplingMode == NearestSample ? tr("First") :
00165                  m_samplingMode == SampleMean ? tr("Mean") : tr("Peak"))
00166             .arg(valuestr);
00167         
00168         return description;
00169     
00170     } else {
00171 
00172         QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples (%4)")
00173             .arg(QString::fromStdString(rt0.toText(true)))
00174             .arg(QString::fromStdString(rt1.toText(true)))
00175             .arg(range)
00176             .arg(rtrangestr);
00177         
00178         return description;
00179     }
00180 }
00181 
00182 float
00183 SliceLayer::getXForBin(int bin, int count, float w) const
00184 {
00185     float x = 0;
00186 
00187     switch (m_binScale) {
00188 
00189     case LinearBins:
00190         x = (float(w) * bin) / count;
00191         break;
00192         
00193     case LogBins:
00194         x = (float(w) * log10f(bin + 1)) / log10f(count + 1);
00195         break;
00196         
00197     case InvertedLogBins:
00198         x = w - (float(w) * log10f(count - bin - 1)) / log10f(count);
00199         break;
00200     }
00201 
00202     return x;
00203 }
00204 
00205 int
00206 SliceLayer::getBinForX(float x, int count, float w) const
00207 {
00208     int bin = 0;
00209 
00210     switch (m_binScale) {
00211 
00212     case LinearBins:
00213         bin = int((x * count) / w + 0.0001);
00214         break;
00215         
00216     case LogBins:
00217         bin = int(powf(10.f, (x * log10f(count + 1)) / w) - 1 + 0.0001);
00218         break;
00219 
00220     case InvertedLogBins:
00221         bin = count + 1 - int(powf(10.f, (log10f(count) * (w - x)) / float(w)) + 0.0001);
00222         break;
00223     }
00224 
00225     return bin;
00226 }
00227 
00228 float
00229 SliceLayer::getYForValue(float value, const View *v, float &norm) const
00230 {
00231     norm = 0.f;
00232 
00233     if (m_yorigins.find(v) == m_yorigins.end()) return 0;
00234 
00235     value *= m_gain;
00236 
00237     int yorigin = m_yorigins[v];
00238     int h = m_heights[v];
00239     float thresh = getThresholdDb();
00240 
00241     float y = 0.f;
00242 
00243     if (h <= 0) return y;
00244 
00245     switch (m_energyScale) {
00246 
00247     case dBScale:
00248     {
00249         float db = thresh;
00250         if (value > 0.f) db = 10.f * log10f(fabsf(value));
00251         if (db < thresh) db = thresh;
00252         norm = (db - thresh) / -thresh;
00253         y = yorigin - (float(h) * norm);
00254         break;
00255     }
00256     
00257     case MeterScale:
00258         y = AudioLevel::multiplier_to_preview(value, h);
00259         norm = float(y) / float(h);
00260         y = yorigin - y;
00261         break;
00262         
00263     case AbsoluteScale:
00264         value = fabsf(value);
00265         // and fall through
00266         
00267     case LinearScale:
00268     default:
00269         norm = (value - m_threshold);
00270         if (norm < 0) norm = 0;
00271         y = yorigin - (float(h) * norm);
00272         break;
00273     }
00274     
00275     return y;
00276 }
00277 
00278 float
00279 SliceLayer::getValueForY(float y, const View *v) const
00280 {
00281     float value = 0.f;
00282 
00283     if (m_yorigins.find(v) == m_yorigins.end()) return value;
00284 
00285     int yorigin = m_yorigins[v];
00286     int h = m_heights[v];
00287     float thresh = getThresholdDb();
00288 
00289     if (h <= 0) return value;
00290 
00291     y = yorigin - y;
00292 
00293     switch (m_energyScale) {
00294 
00295     case dBScale:
00296     {
00297         float db = ((y / h) * -thresh) + thresh;
00298         value = powf(10.f, db/10.f);
00299         break;
00300     }
00301 
00302     case MeterScale:
00303         value = AudioLevel::preview_to_multiplier(lrintf(y), h);
00304         break;
00305 
00306     case LinearScale:
00307     case AbsoluteScale:
00308     default:
00309         value = y / h + m_threshold;
00310     }
00311 
00312     return value / m_gain;
00313 }
00314 
00315 void
00316 SliceLayer::paint(View *v, QPainter &paint, QRect rect) const
00317 {
00318     if (!m_sliceableModel || !m_sliceableModel->isOK() ||
00319         !m_sliceableModel->isReady()) return;
00320 
00321     paint.save();
00322     paint.setRenderHint(QPainter::Antialiasing, false);
00323     paint.setBrush(Qt::NoBrush);
00324 
00325     if (v->getViewManager() && v->getViewManager()->shouldShowScaleGuides()) {
00326         if (!m_scalePoints.empty()) {
00327             paint.setPen(QColor(240, 240, 240)); 
00328             for (int i = 0; i < (int)m_scalePoints.size(); ++i) {
00329                 paint.drawLine(0, m_scalePoints[i], rect.width(), m_scalePoints[i]);
00330             }
00331         }
00332     }
00333 
00334     paint.setPen(getBaseQColor());
00335 
00336     int xorigin = getVerticalScaleWidth(v, true, paint) + 1;
00337     int w = v->width() - xorigin - 1;
00338 
00339     m_xorigins[v] = xorigin; // for use in getFeatureDescription
00340     
00341     int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7;
00342     int h = yorigin - paint.fontMetrics().height() - 8;
00343 
00344     m_yorigins[v] = yorigin; // for getYForValue etc
00345     m_heights[v] = h;
00346 
00347     if (h <= 0) return;
00348 
00349     QPainterPath path;
00350 
00351     int mh = m_sliceableModel->getHeight();
00352 
00353     int divisor = 0;
00354 
00355     m_values.clear();
00356     for (int bin = 0; bin < mh; ++bin) {
00357         m_values.push_back(0.f);
00358     }
00359 
00360     int f0 = v->getCentreFrame();
00361     int f0x = v->getXForFrame(f0);
00362     f0 = v->getFrameForX(f0x);
00363     int f1 = v->getFrameForX(f0x + 1);
00364     if (f1 > f0) --f1;
00365 
00366 //    cerr << "centre frame " << v->getCentreFrame() << ", x " << f0x << ", f0 " << f0 << ", f1 " << f1 << endl;
00367 
00368     int res = m_sliceableModel->getResolution();
00369     int col0 = f0 / res;
00370     int col1 = col0;
00371     if (m_samplingMode != NearestSample) col1 = f1 / res;
00372     f0 = col0 * res;
00373     f1 = (col1 + 1) * res - 1;
00374 
00375 //    cerr << "resolution " << res << ", col0 " << col0 << ", col1 " << col1 << ", f0 " << f0 << ", f1 " << f1 << endl;
00376 
00377     m_currentf0 = f0;
00378     m_currentf1 = f1;
00379 
00380     BiasCurve curve;
00381     getBiasCurve(curve);
00382     int cs = curve.size();
00383 
00384     for (int col = col0; col <= col1; ++col) {
00385         for (int bin = 0; bin < mh; ++bin) {
00386             float value = m_sliceableModel->getValueAt(col, bin);
00387             if (bin < cs) value *= curve[bin];
00388             if (m_samplingMode == SamplePeak) {
00389                 if (value > m_values[bin]) m_values[bin] = value;
00390             } else {
00391                 m_values[bin] += value;
00392             }
00393         }
00394         ++divisor;
00395     }
00396 
00397     float max = 0.f;
00398     for (int bin = 0; bin < mh; ++bin) {
00399         if (m_samplingMode == SampleMean && divisor > 0) {
00400             m_values[bin] /= divisor;
00401         }
00402         if (m_values[bin] > max) max = m_values[bin];
00403     }
00404     if (max != 0.f && m_normalize) {
00405         for (int bin = 0; bin < mh; ++bin) {
00406             m_values[bin] /= max;
00407         }
00408     }
00409 
00410     float nx = xorigin;
00411 
00412     ColourMapper mapper(m_colourMap, 0, 1);
00413 
00414     for (int bin = 0; bin < mh; ++bin) {
00415 
00416         float x = nx;
00417         nx = xorigin + getXForBin(bin + 1, mh, w);
00418 
00419         float value = m_values[bin];
00420         float norm = 0.f;
00421         float y = getYForValue(value, v, norm);
00422 
00423         if (m_plotStyle == PlotLines) {
00424 
00425             if (bin == 0) {
00426                 path.moveTo(x, y);
00427             } else {
00428                 path.lineTo(x, y);
00429             }
00430 
00431         } else if (m_plotStyle == PlotSteps) {
00432 
00433             if (bin == 0) {
00434                 path.moveTo(x, y);
00435             } else {
00436                 path.lineTo(x, y);
00437             }
00438             path.lineTo(nx, y);
00439 
00440         } else if (m_plotStyle == PlotBlocks) {
00441 
00442             path.moveTo(x, yorigin);
00443             path.lineTo(x, y);
00444             path.lineTo(nx, y);
00445             path.lineTo(nx, yorigin);
00446             path.lineTo(x, yorigin);
00447 
00448         } else if (m_plotStyle == PlotFilledBlocks) {
00449 
00450             paint.fillRect(QRectF(x, y, nx - x, yorigin - y), mapper.map(norm));
00451         }
00452 
00453     }
00454 
00455     if (m_plotStyle != PlotFilledBlocks) {
00456         paint.drawPath(path);
00457     }
00458     paint.restore();
00459 /*
00460     QPoint discard;
00461 
00462     if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() &&
00463         v->shouldIlluminateLocalFeatures(this, discard)) {
00464 
00465         int sampleRate = m_sliceableModel->getSampleRate();
00466 
00467         QString startText = QString("%1 / %2")
00468             .arg(QString::fromStdString
00469                  (RealTime::frame2RealTime
00470                   (f0, sampleRate).toText(true)))
00471             .arg(f0);
00472 
00473         QString endText = QString(" %1 / %2")
00474             .arg(QString::fromStdString
00475                  (RealTime::frame2RealTime
00476                   (f1, sampleRate).toText(true)))
00477             .arg(f1);
00478 
00479         QString durationText = QString("(%1 / %2) ")
00480             .arg(QString::fromStdString
00481                  (RealTime::frame2RealTime
00482                   (f1 - f0 + 1, sampleRate).toText(true)))
00483             .arg(f1 - f0 + 1);
00484 
00485         v->drawVisibleText
00486             (paint, xorigin + 5,
00487              paint.fontMetrics().ascent() + 5,
00488              startText, View::OutlinedText);
00489         
00490         v->drawVisibleText
00491             (paint, xorigin + 5,
00492              paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10,
00493              endText, View::OutlinedText);
00494         
00495         v->drawVisibleText
00496             (paint, xorigin + 5,
00497              paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15,
00498              durationText, View::OutlinedText);
00499     }
00500 */
00501 }
00502 
00503 int
00504 SliceLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const
00505 {
00506     if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) {
00507         return std::max(paint.fontMetrics().width("0.0") + 13,
00508                         paint.fontMetrics().width("x10-10"));
00509     } else {
00510         return std::max(paint.fontMetrics().width(tr("0dB")),
00511                         paint.fontMetrics().width(tr("-Inf"))) + 13;
00512     }
00513 }
00514 
00515 void
00516 SliceLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const
00517 {
00518     float thresh = m_threshold;
00519     if (m_energyScale != LinearScale && m_energyScale != AbsoluteScale) {
00520         thresh = AudioLevel::dB_to_multiplier(getThresholdDb());
00521     }
00522     
00523 //    int h = (rect.height() * 3) / 4;
00524 //    int y = (rect.height() / 2) - (h / 2);
00525     
00526     int yorigin = v->height() - 20 - paint.fontMetrics().height() - 6;
00527     int h = yorigin - paint.fontMetrics().height() - 8;
00528     if (h < 0) return;
00529 
00530     QRect actual(rect.x(), rect.y() + yorigin - h, rect.width(), h);
00531 
00532     int mult = 1;
00533 
00534     PaintAssistant::paintVerticalLevelScale
00535         (paint, actual, thresh, 1.0 / m_gain,
00536          PaintAssistant::Scale(m_energyScale),
00537          mult,
00538          const_cast<std::vector<int> *>(&m_scalePoints));
00539 
00540     if (mult != 1 && mult != 0) {
00541         int log = lrintf(log10f(mult));
00542         QString a = tr("x10");
00543         QString b = QString("%1").arg(-log);
00544         paint.drawText(3, 8 + paint.fontMetrics().ascent(), a);
00545         paint.drawText(3 + paint.fontMetrics().width(a),
00546                        3 + paint.fontMetrics().ascent(), b);
00547     }
00548 }
00549 
00550 Layer::PropertyList
00551 SliceLayer::getProperties() const
00552 {
00553     PropertyList list = SingleColourLayer::getProperties();
00554     list.push_back("Bin Scale");
00555     list.push_back("Plot Type");
00556     list.push_back("Scale");
00557     list.push_back("Normalize");
00558     list.push_back("Threshold");
00559     list.push_back("Gain");
00560 
00561     return list;
00562 }
00563 
00564 QString
00565 SliceLayer::getPropertyLabel(const PropertyName &name) const
00566 {
00567     if (name == "Plot Type") return tr("Plot Type");
00568     if (name == "Scale") return tr("Scale");
00569     if (name == "Normalize") return tr("Normalize");
00570     if (name == "Threshold") return tr("Threshold");
00571     if (name == "Gain") return tr("Gain");
00572     if (name == "Sampling Mode") return tr("Sampling Mode");
00573     if (name == "Bin Scale") return tr("Bin Scale");
00574     return SingleColourLayer::getPropertyLabel(name);
00575 }
00576 
00577 QString
00578 SliceLayer::getPropertyIconName(const PropertyName &name) const
00579 {
00580     if (name == "Normalize") return "normalise";
00581     return "";
00582 }
00583 
00584 Layer::PropertyType
00585 SliceLayer::getPropertyType(const PropertyName &name) const
00586 {
00587     if (name == "Gain") return RangeProperty;
00588     if (name == "Normalize") return ToggleProperty;
00589     if (name == "Threshold") return RangeProperty;
00590     if (name == "Plot Type") return ValueProperty;
00591     if (name == "Scale") return ValueProperty;
00592     if (name == "Sampling Mode") return ValueProperty;
00593     if (name == "Bin Scale") return ValueProperty;
00594     if (name == "Colour" && m_plotStyle == PlotFilledBlocks) return ValueProperty;
00595     return SingleColourLayer::getPropertyType(name);
00596 }
00597 
00598 QString
00599 SliceLayer::getPropertyGroupName(const PropertyName &name) const
00600 {
00601     if (name == "Scale" ||
00602         name == "Normalize" ||
00603         name == "Sampling Mode" ||
00604         name == "Threshold" ||
00605         name == "Gain") return tr("Scale");
00606     if (name == "Plot Type" ||
00607         name == "Bin Scale") return tr("Bins");
00608     return SingleColourLayer::getPropertyGroupName(name);
00609 }
00610 
00611 int
00612 SliceLayer::getPropertyRangeAndValue(const PropertyName &name,
00613                                      int *min, int *max, int *deflt) const
00614 {
00615     int val = 0;
00616 
00617     int garbage0, garbage1, garbage2;
00618     if (!min) min = &garbage0;
00619     if (!max) max = &garbage1;
00620     if (!deflt) deflt = &garbage2;
00621 
00622     if (name == "Gain") {
00623 
00624         *min = -50;
00625         *max = 50;
00626         *deflt = 0;
00627 
00628         cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl;
00629 
00630         val = lrint(log10(m_gain) * 20.0);
00631         if (val < *min) val = *min;
00632         if (val > *max) val = *max;
00633 
00634     } else if (name == "Threshold") {
00635         
00636         *min = -80;
00637         *max = 0;
00638 
00639         *deflt = lrintf(AudioLevel::multiplier_to_dB(m_initialThreshold));
00640         if (*deflt < *min) *deflt = *min;
00641         if (*deflt > *max) *deflt = *max;
00642 
00643         val = lrintf(AudioLevel::multiplier_to_dB(m_threshold));
00644         if (val < *min) val = *min;
00645         if (val > *max) val = *max;
00646 
00647     } else if (name == "Normalize") {
00648         
00649         val = (m_normalize ? 1 : 0);
00650         *deflt = 0;
00651 
00652     } else if (name == "Colour" && m_plotStyle == PlotFilledBlocks) {
00653             
00654         *min = 0;
00655         *max = ColourMapper::getColourMapCount() - 1;
00656         *deflt = 0;
00657         
00658         val = m_colourMap;
00659 
00660     } else if (name == "Scale") {
00661 
00662         *min = 0;
00663         *max = 3;
00664         *deflt = (int)dBScale;
00665 
00666         val = (int)m_energyScale;
00667 
00668     } else if (name == "Sampling Mode") {
00669 
00670         *min = 0;
00671         *max = 2;
00672         *deflt = (int)SampleMean;
00673         
00674         val = (int)m_samplingMode;
00675 
00676     } else if (name == "Plot Type") {
00677         
00678         *min = 0;
00679         *max = 3;
00680         *deflt = (int)PlotSteps;
00681 
00682         val = (int)m_plotStyle;
00683 
00684     } else if (name == "Bin Scale") {
00685         
00686         *min = 0;
00687         *max = 2;
00688         *deflt = (int)LinearBins;
00689 //        *max = 1; // I don't think we really do want to offer inverted log
00690 
00691         val = (int)m_binScale;
00692 
00693     } else {
00694         val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
00695     }
00696 
00697     return val;
00698 }
00699 
00700 QString
00701 SliceLayer::getPropertyValueLabel(const PropertyName &name,
00702                                     int value) const
00703 {
00704     if (name == "Colour" && m_plotStyle == PlotFilledBlocks) {
00705         return ColourMapper::getColourMapName(value);
00706     }
00707     if (name == "Scale") {
00708         switch (value) {
00709         default:
00710         case 0: return tr("Linear");
00711         case 1: return tr("Meter");
00712         case 2: return tr("Log");
00713         case 3: return tr("Absolute");
00714         }
00715     }
00716     if (name == "Sampling Mode") {
00717         switch (value) {
00718         default:
00719         case 0: return tr("Any");
00720         case 1: return tr("Mean");
00721         case 2: return tr("Peak");
00722         }
00723     }
00724     if (name == "Plot Type") {
00725         switch (value) {
00726         default:
00727         case 0: return tr("Lines");
00728         case 1: return tr("Steps");
00729         case 2: return tr("Blocks");
00730         case 3: return tr("Colours");
00731         }
00732     }
00733     if (name == "Bin Scale") {
00734         switch (value) {
00735         default:
00736         case 0: return tr("Linear");
00737         case 1: return tr("Log");
00738         case 2: return tr("Rev Log");
00739         }
00740     }
00741     return SingleColourLayer::getPropertyValueLabel(name, value);
00742 }
00743 
00744 RangeMapper *
00745 SliceLayer::getNewPropertyRangeMapper(const PropertyName &name) const
00746 {
00747     if (name == "Gain") {
00748         return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
00749     }
00750     if (name == "Threshold") {
00751         return new LinearRangeMapper(-80, 0, -80, 0, tr("dB"));
00752     }
00753     return SingleColourLayer::getNewPropertyRangeMapper(name);
00754 }
00755 
00756 void
00757 SliceLayer::setProperty(const PropertyName &name, int value)
00758 {
00759     if (name == "Gain") {
00760         setGain(pow(10, float(value)/20.0));
00761     } else if (name == "Threshold") {
00762         if (value == -80) setThreshold(0.0);
00763         else setThreshold(AudioLevel::dB_to_multiplier(value));
00764     } else if (name == "Colour" && m_plotStyle == PlotFilledBlocks) {
00765         setFillColourMap(value);
00766     } else if (name == "Scale") {
00767         switch (value) {
00768         default:
00769         case 0: setEnergyScale(LinearScale); break;
00770         case 1: setEnergyScale(MeterScale); break;
00771         case 2: setEnergyScale(dBScale); break;
00772         case 3: setEnergyScale(AbsoluteScale); break;
00773         }
00774     } else if (name == "Plot Type") {
00775         setPlotStyle(PlotStyle(value));
00776     } else if (name == "Sampling Mode") {
00777         switch (value) {
00778         default:
00779         case 0: setSamplingMode(NearestSample); break;
00780         case 1: setSamplingMode(SampleMean); break;
00781         case 2: setSamplingMode(SamplePeak); break;
00782         }
00783     } else if (name == "Bin Scale") {
00784         switch (value) {
00785         default:
00786         case 0: setBinScale(LinearBins); break;
00787         case 1: setBinScale(LogBins); break;
00788         case 2: setBinScale(InvertedLogBins); break;
00789         }
00790     } else if (name == "Normalize") {
00791         setNormalize(value ? true : false);
00792     } else {
00793         SingleColourLayer::setProperty(name, value);
00794     }
00795 }
00796 
00797 void
00798 SliceLayer::setFillColourMap(int map)
00799 {
00800     if (m_colourMap == map) return;
00801     m_colourMap = map;
00802     emit layerParametersChanged();
00803 }
00804 
00805 void
00806 SliceLayer::setEnergyScale(EnergyScale scale)
00807 {
00808     if (m_energyScale == scale) return;
00809     m_energyScale = scale;
00810     emit layerParametersChanged();
00811 }
00812 
00813 void
00814 SliceLayer::setSamplingMode(SamplingMode mode)
00815 {
00816     if (m_samplingMode == mode) return;
00817     m_samplingMode = mode;
00818     emit layerParametersChanged();
00819 }
00820 
00821 void
00822 SliceLayer::setPlotStyle(PlotStyle style)
00823 {
00824     if (m_plotStyle == style) return;
00825     bool colourTypeChanged = (style == PlotFilledBlocks ||
00826                               m_plotStyle == PlotFilledBlocks);
00827     m_plotStyle = style;
00828     if (colourTypeChanged) {
00829         emit layerParameterRangesChanged();
00830     }
00831     emit layerParametersChanged();
00832 }
00833 
00834 void
00835 SliceLayer::setBinScale(BinScale scale)
00836 {
00837     if (m_binScale == scale) return;
00838     m_binScale = scale;
00839     emit layerParametersChanged();
00840 }
00841 
00842 void
00843 SliceLayer::setNormalize(bool n)
00844 {
00845     if (m_normalize == n) return;
00846     m_normalize = n;
00847     emit layerParametersChanged();
00848 }
00849 
00850 void
00851 SliceLayer::setThreshold(float thresh)
00852 {
00853     if (m_threshold == thresh) return;
00854     m_threshold = thresh;
00855     emit layerParametersChanged();
00856 }
00857 
00858 void
00859 SliceLayer::setGain(float gain)
00860 {
00861     if (m_gain == gain) return;
00862     m_gain = gain;
00863     emit layerParametersChanged();
00864 }
00865 
00866 float
00867 SliceLayer::getThresholdDb() const
00868 {
00869     if (m_threshold == 0.0) return -80.f;
00870     float db = AudioLevel::multiplier_to_dB(m_threshold);
00871     return db;
00872 }
00873 
00874 int
00875 SliceLayer::getDefaultColourHint(bool darkbg, bool &impose)
00876 {
00877     impose = false;
00878     return ColourDatabase::getInstance()->getColourIndex
00879         (QString(darkbg ? "Bright Blue" : "Blue"));
00880 }
00881 
00882 void
00883 SliceLayer::toXml(QTextStream &stream,
00884                   QString indent, QString extraAttributes) const
00885 {
00886     QString s;
00887     
00888     s += QString("colourScheme=\"%1\" "
00889                  "energyScale=\"%2\" "
00890                  "samplingMode=\"%3\" "
00891                  "plotStyle=\"%4\" "
00892                  "binScale=\"%5\" "
00893                  "gain=\"%6\" "
00894                  "threshold=\"%7\" "
00895                  "normalize=\"%8\"")
00896         .arg(m_colourMap)
00897         .arg(m_energyScale)
00898         .arg(m_samplingMode)
00899         .arg(m_plotStyle)
00900         .arg(m_binScale)
00901         .arg(m_gain)
00902         .arg(m_threshold)
00903         .arg(m_normalize ? "true" : "false");
00904 
00905     SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s);
00906 }
00907 
00908 void
00909 SliceLayer::setProperties(const QXmlAttributes &attributes)
00910 {
00911     bool ok = false;
00912 
00913     SingleColourLayer::setProperties(attributes);
00914 
00915     EnergyScale scale = (EnergyScale)
00916         attributes.value("energyScale").toInt(&ok);
00917     if (ok) setEnergyScale(scale);
00918 
00919     SamplingMode mode = (SamplingMode)
00920         attributes.value("samplingMode").toInt(&ok);
00921     if (ok) setSamplingMode(mode);
00922 
00923     int colourMap = attributes.value("colourScheme").toInt(&ok);
00924     if (ok) setFillColourMap(colourMap);
00925 
00926     PlotStyle s = (PlotStyle)
00927         attributes.value("plotStyle").toInt(&ok);
00928     if (ok) setPlotStyle(s);
00929 
00930     BinScale b = (BinScale)
00931         attributes.value("binScale").toInt(&ok);
00932     if (ok) setBinScale(b);
00933 
00934     float gain = attributes.value("gain").toFloat(&ok);
00935     if (ok) setGain(gain);
00936 
00937     float threshold = attributes.value("threshold").toFloat(&ok);
00938     if (ok) setThreshold(threshold);
00939 
00940     bool normalize = (attributes.value("normalize").trimmed() == "true");
00941     setNormalize(normalize);
00942 }
00943 
00944 bool
00945 SliceLayer::getValueExtents(float &, float &, bool &, QString &) const
00946 {
00947     return false;
00948 }
00949