svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006-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