annotate layer/SliceLayer.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents be6d31baecb9
children
rev   line source
lbajardsilogic@0 1
lbajardsilogic@0 2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 3
lbajardsilogic@0 4 /*
lbajardsilogic@0 5 Sonic Visualiser
lbajardsilogic@0 6 An audio file viewer and annotation editor.
lbajardsilogic@0 7 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 8 This file copyright 2006-2007 QMUL.
lbajardsilogic@0 9
lbajardsilogic@0 10 This program is free software; you can redistribute it and/or
lbajardsilogic@0 11 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 12 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 13 License, or (at your option) any later version. See the file
lbajardsilogic@0 14 COPYING included with this distribution for more information.
lbajardsilogic@0 15 */
lbajardsilogic@0 16
lbajardsilogic@0 17 #include "SliceLayer.h"
lbajardsilogic@0 18
lbajardsilogic@0 19 #include "system/System.h"
lbajardsilogic@0 20 #include "view/View.h"
lbajardsilogic@0 21 #include "base/AudioLevel.h"
lbajardsilogic@0 22 #include "base/RangeMapper.h"
lbajardsilogic@0 23 #include "base/RealTime.h"
lbajardsilogic@0 24
lbajardsilogic@0 25 #include "ColourMapper.h"
lbajardsilogic@0 26 #include "PaintAssistant.h"
lbajardsilogic@0 27
lbajardsilogic@0 28 #include <QPainter>
lbajardsilogic@0 29 #include <QPainterPath>
lbajardsilogic@0 30
lbajardsilogic@0 31 SliceLayer::SliceLayer() :
lbajardsilogic@0 32 m_sliceableModel(0),
lbajardsilogic@0 33 m_colour(Qt::darkBlue),
lbajardsilogic@0 34 m_colourMap(0),
lbajardsilogic@0 35 m_energyScale(dBScale),
lbajardsilogic@0 36 m_samplingMode(SampleMean),
lbajardsilogic@0 37 m_plotStyle(PlotSteps),
lbajardsilogic@0 38 m_binScale(LinearBins),
lbajardsilogic@0 39 m_normalize(false),
lbajardsilogic@0 40 m_bias(false),
lbajardsilogic@0 41 m_gain(1.0),
lbajardsilogic@0 42 m_currentf0(0),
lbajardsilogic@0 43 m_currentf1(0)
lbajardsilogic@0 44 {
lbajardsilogic@0 45 }
lbajardsilogic@0 46
lbajardsilogic@0 47 SliceLayer::~SliceLayer()
lbajardsilogic@0 48 {
lbajardsilogic@0 49
lbajardsilogic@0 50 }
lbajardsilogic@0 51
lbajardsilogic@0 52 void
lbajardsilogic@0 53 SliceLayer::setSliceableModel(const Model *model)
lbajardsilogic@0 54 {
lbajardsilogic@0 55 const DenseThreeDimensionalModel *sliceable =
lbajardsilogic@0 56 dynamic_cast<const DenseThreeDimensionalModel *>(model);
lbajardsilogic@0 57
lbajardsilogic@0 58 if (model && !sliceable) {
lbajardsilogic@0 59 std::cerr << "WARNING: SliceLayer::setSliceableModel(" << model
lbajardsilogic@0 60 << "): model is not a DenseThreeDimensionalModel" << std::endl;
lbajardsilogic@0 61 }
lbajardsilogic@0 62
lbajardsilogic@0 63 if (m_sliceableModel == sliceable) return;
lbajardsilogic@0 64
lbajardsilogic@0 65 m_sliceableModel = sliceable;
lbajardsilogic@0 66
lbajardsilogic@0 67 connect(m_sliceableModel, SIGNAL(modelChanged()),
lbajardsilogic@0 68 this, SIGNAL(modelChanged()));
lbajardsilogic@0 69
lbajardsilogic@0 70 connect(m_sliceableModel, SIGNAL(modelChanged(size_t, size_t)),
lbajardsilogic@0 71 this, SIGNAL(modelChanged(size_t, size_t)));
lbajardsilogic@0 72
lbajardsilogic@0 73 connect(m_sliceableModel, SIGNAL(completionChanged()),
lbajardsilogic@0 74 this, SIGNAL(modelCompletionChanged()));
lbajardsilogic@0 75
lbajardsilogic@0 76 emit modelReplaced();
lbajardsilogic@0 77 }
lbajardsilogic@0 78
lbajardsilogic@0 79 void
lbajardsilogic@0 80 SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement)
lbajardsilogic@0 81 {
lbajardsilogic@0 82 std::cerr << "SliceLayer::sliceableModelReplaced(" << orig << ", " << replacement << ")" << std::endl;
lbajardsilogic@0 83
lbajardsilogic@0 84 if (orig == m_sliceableModel) {
lbajardsilogic@0 85 setSliceableModel
lbajardsilogic@0 86 (dynamic_cast<const DenseThreeDimensionalModel *>(replacement));
lbajardsilogic@0 87 }
lbajardsilogic@0 88 }
lbajardsilogic@0 89
lbajardsilogic@0 90 void
lbajardsilogic@0 91 SliceLayer::modelAboutToBeDeleted(Model *m)
lbajardsilogic@0 92 {
lbajardsilogic@0 93 std::cerr << "SliceLayer::modelAboutToBeDeleted(" << m << ")" << std::endl;
lbajardsilogic@0 94
lbajardsilogic@0 95 if (m == m_sliceableModel) {
lbajardsilogic@0 96 setSliceableModel(0);
lbajardsilogic@0 97 }
lbajardsilogic@0 98 }
lbajardsilogic@0 99
lbajardsilogic@0 100 QString
lbajardsilogic@0 101 SliceLayer::getFeatureDescription(View *v, QPoint &p) const
lbajardsilogic@0 102 {
lbajardsilogic@0 103 int minbin, maxbin, range;
lbajardsilogic@0 104 return getFeatureDescription(v, p, true, minbin, maxbin, range);
lbajardsilogic@0 105 }
lbajardsilogic@0 106
lbajardsilogic@0 107 QString
lbajardsilogic@0 108 SliceLayer::getFeatureDescription(View *v, QPoint &p,
lbajardsilogic@0 109 bool includeBinDescription,
lbajardsilogic@0 110 int &minbin, int &maxbin, int &range) const
lbajardsilogic@0 111 {
lbajardsilogic@0 112 minbin = 0;
lbajardsilogic@0 113 maxbin = 0;
lbajardsilogic@0 114 if (!m_sliceableModel) return "";
lbajardsilogic@0 115
lbajardsilogic@0 116 int xorigin = m_xorigins[v];
lbajardsilogic@0 117 int w = v->width() - xorigin - 1;
lbajardsilogic@0 118
lbajardsilogic@0 119 int mh = m_sliceableModel->getHeight();
lbajardsilogic@0 120 minbin = getBinForX(p.x() - xorigin, mh, w);
lbajardsilogic@0 121 maxbin = getBinForX(p.x() - xorigin + 1, mh, w);
lbajardsilogic@0 122
lbajardsilogic@0 123 if (minbin >= mh) minbin = mh - 1;
lbajardsilogic@0 124 if (maxbin >= mh) maxbin = mh - 1;
lbajardsilogic@0 125 if (minbin < 0) minbin = 0;
lbajardsilogic@0 126 if (maxbin < 0) maxbin = 0;
lbajardsilogic@0 127
lbajardsilogic@0 128 int sampleRate = m_sliceableModel->getSampleRate();
lbajardsilogic@0 129
lbajardsilogic@0 130 size_t f0 = m_currentf0;
lbajardsilogic@0 131 size_t f1 = m_currentf1;
lbajardsilogic@0 132
lbajardsilogic@0 133 RealTime rt0 = RealTime::frame2RealTime(f0, sampleRate);
lbajardsilogic@0 134 RealTime rt1 = RealTime::frame2RealTime(f1, sampleRate);
lbajardsilogic@0 135
lbajardsilogic@0 136 range = f1 - f0 + 1;
lbajardsilogic@0 137
lbajardsilogic@0 138 if (includeBinDescription) {
lbajardsilogic@0 139
lbajardsilogic@0 140 float minvalue = 0.f;
lbajardsilogic@0 141 if (minbin < int(m_values.size())) minvalue = m_values[minbin];
lbajardsilogic@0 142
lbajardsilogic@0 143 float maxvalue = minvalue;
lbajardsilogic@0 144 if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin];
lbajardsilogic@0 145
lbajardsilogic@0 146 if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
lbajardsilogic@0 147
lbajardsilogic@0 148 QString binstr;
lbajardsilogic@0 149 if (maxbin != minbin) {
lbajardsilogic@0 150 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1);
lbajardsilogic@0 151 } else {
lbajardsilogic@0 152 binstr = QString("%1").arg(minbin+1);
lbajardsilogic@0 153 }
lbajardsilogic@0 154
lbajardsilogic@0 155 QString valuestr;
lbajardsilogic@0 156 if (maxvalue != minvalue) {
lbajardsilogic@0 157 valuestr = tr("%1 - %2").arg(minvalue).arg(maxvalue);
lbajardsilogic@0 158 } else {
lbajardsilogic@0 159 valuestr = QString("%1").arg(minvalue);
lbajardsilogic@0 160 }
lbajardsilogic@0 161
lbajardsilogic@0 162 QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples\nBin:\t%4\n%5 value:\t%6")
lbajardsilogic@0 163 .arg(QString::fromStdString(rt0.toText(true)))
lbajardsilogic@0 164 .arg(QString::fromStdString(rt1.toText(true)))
lbajardsilogic@0 165 .arg(range)
lbajardsilogic@0 166 .arg(binstr)
lbajardsilogic@0 167 .arg(m_samplingMode == NearestSample ? tr("First") :
lbajardsilogic@0 168 m_samplingMode == SampleMean ? tr("Mean") : tr("Peak"))
lbajardsilogic@0 169 .arg(valuestr);
lbajardsilogic@0 170
lbajardsilogic@0 171 return description;
lbajardsilogic@0 172
lbajardsilogic@0 173 } else {
lbajardsilogic@0 174
lbajardsilogic@0 175 QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples")
lbajardsilogic@0 176 .arg(QString::fromStdString(rt0.toText(true)))
lbajardsilogic@0 177 .arg(QString::fromStdString(rt1.toText(true)))
lbajardsilogic@0 178 .arg(range);
lbajardsilogic@0 179
lbajardsilogic@0 180 return description;
lbajardsilogic@0 181 }
lbajardsilogic@0 182 }
lbajardsilogic@0 183
lbajardsilogic@0 184 float
lbajardsilogic@0 185 SliceLayer::getXForBin(int bin, int count, float w) const
lbajardsilogic@0 186 {
lbajardsilogic@0 187 float x = 0;
lbajardsilogic@0 188
lbajardsilogic@0 189 switch (m_binScale) {
lbajardsilogic@0 190
lbajardsilogic@0 191 case LinearBins:
lbajardsilogic@0 192 x = (float(w) * bin) / count;
lbajardsilogic@0 193 break;
lbajardsilogic@0 194
lbajardsilogic@0 195 case LogBins:
lbajardsilogic@0 196 x = (float(w) * log10f(bin + 1)) / log10f(count + 1);
lbajardsilogic@0 197 break;
lbajardsilogic@0 198
lbajardsilogic@0 199 case InvertedLogBins:
lbajardsilogic@0 200 x = w - (float(w) * log10f(count - bin - 1)) / log10f(count);
lbajardsilogic@0 201 break;
lbajardsilogic@0 202 }
lbajardsilogic@0 203
lbajardsilogic@0 204 return x;
lbajardsilogic@0 205 }
lbajardsilogic@0 206
lbajardsilogic@0 207 int
lbajardsilogic@0 208 SliceLayer::getBinForX(float x, int count, float w) const
lbajardsilogic@0 209 {
lbajardsilogic@0 210 int bin = 0;
lbajardsilogic@0 211
lbajardsilogic@0 212 switch (m_binScale) {
lbajardsilogic@0 213
lbajardsilogic@0 214 case LinearBins:
lbajardsilogic@0 215 bin = int((x * count) / w + 0.0001);
lbajardsilogic@0 216 break;
lbajardsilogic@0 217
lbajardsilogic@0 218 case LogBins:
lbajardsilogic@0 219 bin = int(powf(10.f, (x * log10f(count + 1)) / w) - 1 + 0.0001);
lbajardsilogic@0 220 break;
lbajardsilogic@0 221
lbajardsilogic@0 222 case InvertedLogBins:
lbajardsilogic@0 223 bin = count + 1 - int(powf(10.f, (log10f(count) * (w - x)) / float(w)) + 0.0001);
lbajardsilogic@0 224 break;
lbajardsilogic@0 225 }
lbajardsilogic@0 226
lbajardsilogic@0 227 return bin;
lbajardsilogic@0 228 }
lbajardsilogic@0 229
lbajardsilogic@0 230 void
lbajardsilogic@0 231 SliceLayer::paint(View *v, QPainter &paint, QRect rect) const
lbajardsilogic@0 232 {
lbajardsilogic@0 233 if (!m_sliceableModel) return;
lbajardsilogic@0 234
lbajardsilogic@0 235 paint.save();
lbajardsilogic@0 236 paint.setRenderHint(QPainter::Antialiasing, false);
lbajardsilogic@0 237
lbajardsilogic@0 238 if (v->getViewManager() && v->getViewManager()->shouldShowScaleGuides()) {
lbajardsilogic@0 239 if (!m_scalePoints.empty()) {
lbajardsilogic@0 240 paint.setPen(QColor(240, 240, 240)); //!!! and dark background?
lbajardsilogic@0 241 for (size_t i = 0; i < m_scalePoints.size(); ++i) {
lbajardsilogic@0 242 paint.drawLine(0, m_scalePoints[i], rect.width(), m_scalePoints[i]);
lbajardsilogic@0 243 }
lbajardsilogic@0 244 }
lbajardsilogic@0 245 }
lbajardsilogic@0 246
lbajardsilogic@0 247 paint.setPen(m_colour);
lbajardsilogic@0 248
lbajardsilogic@0 249 // int w = (v->width() * 2) / 3;
lbajardsilogic@0 250 int xorigin = getVerticalScaleWidth(v, paint) + 1; //!!! (v->width() / 2) - (w / 2);
lbajardsilogic@0 251 int w = v->width() - xorigin - 1;
lbajardsilogic@0 252
lbajardsilogic@0 253 m_xorigins[v] = xorigin; // for use in getFeatureDescription
lbajardsilogic@0 254
lbajardsilogic@0 255 int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7;
lbajardsilogic@0 256 int h = yorigin - paint.fontMetrics().height() - 8;
lbajardsilogic@0 257 if (h < 0) return;
lbajardsilogic@0 258
lbajardsilogic@0 259 // int h = (v->height() * 3) / 4;
lbajardsilogic@0 260 // int yorigin = (v->height() / 2) + (h / 2);
lbajardsilogic@0 261
lbajardsilogic@0 262 QPainterPath path;
lbajardsilogic@0 263 float thresh = -80.f;
lbajardsilogic@0 264
lbajardsilogic@0 265 size_t mh = m_sliceableModel->getHeight();
lbajardsilogic@0 266
lbajardsilogic@0 267 int divisor = 0;
lbajardsilogic@0 268
lbajardsilogic@0 269 m_values.clear();
lbajardsilogic@0 270 for (size_t bin = 0; bin < mh; ++bin) {
lbajardsilogic@0 271 m_values.push_back(0.f);
lbajardsilogic@0 272 }
lbajardsilogic@0 273
lbajardsilogic@0 274 size_t f0 = v->getCentreFrame();
lbajardsilogic@0 275 int f0x = v->getXForFrame(f0);
lbajardsilogic@0 276 f0 = v->getFrameForX(f0x);
lbajardsilogic@0 277 size_t f1 = v->getFrameForX(f0x + 1);
lbajardsilogic@0 278 if (f1 > f0) --f1;
lbajardsilogic@0 279
lbajardsilogic@0 280 size_t col0 = f0 / m_sliceableModel->getResolution();
lbajardsilogic@0 281 size_t col1 = col0;
lbajardsilogic@0 282 if (m_samplingMode != NearestSample) {
lbajardsilogic@0 283 col1 = f1 / m_sliceableModel->getResolution();
lbajardsilogic@0 284 }
lbajardsilogic@0 285 f0 = col0 * m_sliceableModel->getResolution();
lbajardsilogic@0 286 f1 = (col1 + 1) * m_sliceableModel->getResolution() - 1;
lbajardsilogic@0 287
lbajardsilogic@0 288 m_currentf0 = f0;
lbajardsilogic@0 289 m_currentf1 = f1;
lbajardsilogic@0 290
lbajardsilogic@0 291 for (size_t col = col0; col <= col1; ++col) {
lbajardsilogic@0 292 for (size_t bin = 0; bin < mh; ++bin) {
lbajardsilogic@0 293 float value = m_sliceableModel->getValueAt(col, bin);
lbajardsilogic@0 294 if (m_bias) value *= bin + 1;
lbajardsilogic@0 295 if (m_samplingMode == SamplePeak) {
lbajardsilogic@0 296 if (value > m_values[bin]) m_values[bin] = value;
lbajardsilogic@0 297 } else {
lbajardsilogic@0 298 m_values[bin] += value;
lbajardsilogic@0 299 }
lbajardsilogic@0 300 }
lbajardsilogic@0 301 ++divisor;
lbajardsilogic@0 302 }
lbajardsilogic@0 303
lbajardsilogic@0 304 float max = 0.f;
lbajardsilogic@0 305 for (size_t bin = 0; bin < mh; ++bin) {
lbajardsilogic@0 306 if (m_samplingMode == SampleMean) m_values[bin] /= divisor;
lbajardsilogic@0 307 if (m_values[bin] > max) max = m_values[bin];
lbajardsilogic@0 308 }
lbajardsilogic@0 309 if (max != 0.f && m_normalize) {
lbajardsilogic@0 310 for (size_t bin = 0; bin < mh; ++bin) {
lbajardsilogic@0 311 m_values[bin] /= max;
lbajardsilogic@0 312 }
lbajardsilogic@0 313 }
lbajardsilogic@0 314
lbajardsilogic@0 315 float py = 0;
lbajardsilogic@0 316 float nx = xorigin;
lbajardsilogic@0 317
lbajardsilogic@0 318 ColourMapper mapper(m_colourMap, 0, 1);
lbajardsilogic@0 319
lbajardsilogic@0 320 for (size_t bin = 0; bin < mh; ++bin) {
lbajardsilogic@0 321
lbajardsilogic@0 322 float x = nx;
lbajardsilogic@0 323 nx = xorigin + getXForBin(bin + 1, mh, w);
lbajardsilogic@0 324
lbajardsilogic@0 325 float value = m_values[bin];
lbajardsilogic@0 326
lbajardsilogic@0 327 value *= m_gain;
lbajardsilogic@0 328 float norm = 0.f;
lbajardsilogic@0 329 float y = 0.f;
lbajardsilogic@0 330
lbajardsilogic@0 331 switch (m_energyScale) {
lbajardsilogic@0 332
lbajardsilogic@0 333 case dBScale:
lbajardsilogic@0 334 {
lbajardsilogic@0 335 float db = thresh;
lbajardsilogic@0 336 if (value > 0.f) db = 10.f * log10f(value);
lbajardsilogic@0 337 if (db < thresh) db = thresh;
lbajardsilogic@0 338 norm = (db - thresh) / -thresh;
lbajardsilogic@0 339 y = yorigin - (float(h) * norm);
lbajardsilogic@0 340 break;
lbajardsilogic@0 341 }
lbajardsilogic@0 342
lbajardsilogic@0 343 case MeterScale:
lbajardsilogic@0 344 y = AudioLevel::multiplier_to_preview(value, h);
lbajardsilogic@0 345 norm = float(y) / float(h);
lbajardsilogic@0 346 y = yorigin - y;
lbajardsilogic@0 347 break;
lbajardsilogic@0 348
lbajardsilogic@0 349 default:
lbajardsilogic@0 350 norm = value;
lbajardsilogic@0 351 y = yorigin - (float(h) * value);
lbajardsilogic@0 352 break;
lbajardsilogic@0 353 }
lbajardsilogic@0 354
lbajardsilogic@0 355 if (m_plotStyle == PlotLines) {
lbajardsilogic@0 356
lbajardsilogic@0 357 if (bin == 0) {
lbajardsilogic@0 358 path.moveTo(x, y);
lbajardsilogic@0 359 } else {
lbajardsilogic@0 360 path.lineTo(x, y);
lbajardsilogic@0 361 }
lbajardsilogic@0 362
lbajardsilogic@0 363 } else if (m_plotStyle == PlotSteps) {
lbajardsilogic@0 364
lbajardsilogic@0 365 if (bin == 0) {
lbajardsilogic@0 366 path.moveTo(x, y);
lbajardsilogic@0 367 } else {
lbajardsilogic@0 368 path.lineTo(x, y);
lbajardsilogic@0 369 }
lbajardsilogic@0 370 path.lineTo(nx, y);
lbajardsilogic@0 371
lbajardsilogic@0 372 } else if (m_plotStyle == PlotBlocks) {
lbajardsilogic@0 373
lbajardsilogic@0 374 path.moveTo(x, yorigin);
lbajardsilogic@0 375 path.lineTo(x, y);
lbajardsilogic@0 376 path.lineTo(nx, y);
lbajardsilogic@0 377 path.lineTo(nx, yorigin);
lbajardsilogic@0 378 path.lineTo(x, yorigin);
lbajardsilogic@0 379
lbajardsilogic@0 380 } else if (m_plotStyle == PlotFilledBlocks) {
lbajardsilogic@0 381
lbajardsilogic@0 382 paint.fillRect(QRectF(x, y, nx - x, yorigin - y), mapper.map(norm));
lbajardsilogic@0 383 }
lbajardsilogic@0 384
lbajardsilogic@0 385 py = y;
lbajardsilogic@0 386 }
lbajardsilogic@0 387
lbajardsilogic@0 388 if (m_plotStyle != PlotFilledBlocks) {
lbajardsilogic@0 389 paint.drawPath(path);
lbajardsilogic@0 390 }
lbajardsilogic@0 391 paint.restore();
lbajardsilogic@0 392 /*
lbajardsilogic@0 393 QPoint discard;
lbajardsilogic@0 394
lbajardsilogic@0 395 if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() &&
lbajardsilogic@0 396 v->shouldIlluminateLocalFeatures(this, discard)) {
lbajardsilogic@0 397
lbajardsilogic@0 398 int sampleRate = m_sliceableModel->getSampleRate();
lbajardsilogic@0 399
lbajardsilogic@0 400 QString startText = QString("%1 / %2")
lbajardsilogic@0 401 .arg(QString::fromStdString
lbajardsilogic@0 402 (RealTime::frame2RealTime
lbajardsilogic@0 403 (f0, sampleRate).toText(true)))
lbajardsilogic@0 404 .arg(f0);
lbajardsilogic@0 405
lbajardsilogic@0 406 QString endText = QString(" %1 / %2")
lbajardsilogic@0 407 .arg(QString::fromStdString
lbajardsilogic@0 408 (RealTime::frame2RealTime
lbajardsilogic@0 409 (f1, sampleRate).toText(true)))
lbajardsilogic@0 410 .arg(f1);
lbajardsilogic@0 411
lbajardsilogic@0 412 QString durationText = QString("(%1 / %2) ")
lbajardsilogic@0 413 .arg(QString::fromStdString
lbajardsilogic@0 414 (RealTime::frame2RealTime
lbajardsilogic@0 415 (f1 - f0 + 1, sampleRate).toText(true)))
lbajardsilogic@0 416 .arg(f1 - f0 + 1);
lbajardsilogic@0 417
lbajardsilogic@0 418 v->drawVisibleText
lbajardsilogic@0 419 (paint, xorigin + 5,
lbajardsilogic@0 420 paint.fontMetrics().ascent() + 5,
lbajardsilogic@0 421 startText, View::OutlinedText);
lbajardsilogic@0 422
lbajardsilogic@0 423 v->drawVisibleText
lbajardsilogic@0 424 (paint, xorigin + 5,
lbajardsilogic@0 425 paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10,
lbajardsilogic@0 426 endText, View::OutlinedText);
lbajardsilogic@0 427
lbajardsilogic@0 428 v->drawVisibleText
lbajardsilogic@0 429 (paint, xorigin + 5,
lbajardsilogic@0 430 paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15,
lbajardsilogic@0 431 durationText, View::OutlinedText);
lbajardsilogic@0 432 }
lbajardsilogic@0 433 */
lbajardsilogic@0 434 }
lbajardsilogic@0 435
lbajardsilogic@0 436 int
lbajardsilogic@0 437 SliceLayer::getVerticalScaleWidth(View *, QPainter &paint) const
lbajardsilogic@0 438 {
lbajardsilogic@0 439 if (m_energyScale == LinearScale) {
lbajardsilogic@191 440 return MAX(paint.fontMetrics().width("0.0") + 13,
lbajardsilogic@0 441 paint.fontMetrics().width("x10-10"));
lbajardsilogic@0 442 } else {
lbajardsilogic@191 443 return MAX(paint.fontMetrics().width(tr("0dB")),
lbajardsilogic@0 444 paint.fontMetrics().width(tr("-Inf"))) + 13;
lbajardsilogic@0 445 }
lbajardsilogic@0 446 }
lbajardsilogic@0 447
lbajardsilogic@0 448 void
lbajardsilogic@0 449 SliceLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const
lbajardsilogic@0 450 {
lbajardsilogic@0 451 float thresh = 0;
lbajardsilogic@0 452 if (m_energyScale != LinearScale) {
lbajardsilogic@0 453 thresh = AudioLevel::dB_to_multiplier(-80); //!!! thresh
lbajardsilogic@0 454 }
lbajardsilogic@0 455
lbajardsilogic@0 456 // int h = (rect.height() * 3) / 4;
lbajardsilogic@0 457 // int y = (rect.height() / 2) - (h / 2);
lbajardsilogic@0 458
lbajardsilogic@0 459 int yorigin = v->height() - 20 - paint.fontMetrics().height() - 6;
lbajardsilogic@0 460 int h = yorigin - paint.fontMetrics().height() - 8;
lbajardsilogic@0 461 if (h < 0) return;
lbajardsilogic@0 462
lbajardsilogic@0 463 QRect actual(rect.x(), rect.y() + yorigin - h, rect.width(), h);
lbajardsilogic@0 464
lbajardsilogic@0 465 int mult = 1;
lbajardsilogic@0 466
lbajardsilogic@0 467 PaintAssistant::paintVerticalLevelScale
lbajardsilogic@0 468 (paint, actual, thresh, 1.0 / m_gain,
lbajardsilogic@0 469 PaintAssistant::Scale(m_energyScale),
lbajardsilogic@0 470 mult,
lbajardsilogic@0 471 const_cast<std::vector<int> *>(&m_scalePoints));
lbajardsilogic@0 472
lbajardsilogic@0 473 if (mult != 1 && mult != 0) {
lbajardsilogic@0 474 int log = lrintf(log10f(mult));
lbajardsilogic@0 475 QString a = tr("x10");
lbajardsilogic@0 476 QString b = QString("%1").arg(-log);
lbajardsilogic@0 477 paint.drawText(3, 8 + paint.fontMetrics().ascent(), a);
lbajardsilogic@0 478 paint.drawText(3 + paint.fontMetrics().width(a),
lbajardsilogic@0 479 3 + paint.fontMetrics().ascent(), b);
lbajardsilogic@0 480 }
lbajardsilogic@0 481 }
lbajardsilogic@0 482
lbajardsilogic@0 483 Layer::PropertyList
lbajardsilogic@0 484 SliceLayer::getProperties() const
lbajardsilogic@0 485 {
lbajardsilogic@0 486 PropertyList list;
lbajardsilogic@0 487 list.push_back("Colour");
lbajardsilogic@0 488 list.push_back("Plot Type");
lbajardsilogic@0 489 // list.push_back("Sampling Mode");
lbajardsilogic@0 490 list.push_back("Scale");
lbajardsilogic@0 491 list.push_back("Normalize");
lbajardsilogic@0 492 list.push_back("Gain");
lbajardsilogic@0 493 list.push_back("Bin Scale");
lbajardsilogic@0 494
lbajardsilogic@0 495 return list;
lbajardsilogic@0 496 }
lbajardsilogic@0 497
lbajardsilogic@0 498 QString
lbajardsilogic@0 499 SliceLayer::getPropertyLabel(const PropertyName &name) const
lbajardsilogic@0 500 {
lbajardsilogic@0 501 if (name == "Colour") return tr("Colour");
lbajardsilogic@0 502 if (name == "Plot Type") return tr("Plot Type");
lbajardsilogic@0 503 if (name == "Energy Scale") return tr("Scale");
lbajardsilogic@0 504 if (name == "Normalize") return tr("Normalize");
lbajardsilogic@0 505 if (name == "Gain") return tr("Gain");
lbajardsilogic@0 506 if (name == "Sampling Mode") return tr("Sampling Mode");
lbajardsilogic@0 507 if (name == "Bin Scale") return tr("Plot X Scale");
lbajardsilogic@0 508 return "";
lbajardsilogic@0 509 }
lbajardsilogic@0 510
lbajardsilogic@0 511 Layer::PropertyType
lbajardsilogic@0 512 SliceLayer::getPropertyType(const PropertyName &name) const
lbajardsilogic@0 513 {
lbajardsilogic@0 514 if (name == "Gain") return RangeProperty;
lbajardsilogic@0 515 if (name == "Normalize") return ToggleProperty;
lbajardsilogic@0 516 return ValueProperty;
lbajardsilogic@0 517 }
lbajardsilogic@0 518
lbajardsilogic@0 519 QString
lbajardsilogic@0 520 SliceLayer::getPropertyGroupName(const PropertyName &name) const
lbajardsilogic@0 521 {
lbajardsilogic@0 522 if (name == "Scale" ||
lbajardsilogic@0 523 name == "Normalize" ||
lbajardsilogic@0 524 name == "Sampling Mode" ||
lbajardsilogic@0 525 name == "Gain") return tr("Scale");
lbajardsilogic@0 526 if (name == "Plot Type" ||
lbajardsilogic@0 527 name == "Bin Scale") return tr("Plot Type");
lbajardsilogic@0 528 return QString();
lbajardsilogic@0 529 }
lbajardsilogic@0 530
lbajardsilogic@0 531 int
lbajardsilogic@0 532 SliceLayer::getPropertyRangeAndValue(const PropertyName &name,
lbajardsilogic@0 533 int *min, int *max, int *deflt) const
lbajardsilogic@0 534 {
lbajardsilogic@0 535 int val = 0;
lbajardsilogic@0 536
lbajardsilogic@0 537 int garbage0, garbage1, garbage2;
lbajardsilogic@0 538 if (!min) min = &garbage0;
lbajardsilogic@0 539 if (!max) max = &garbage1;
lbajardsilogic@0 540 if (!deflt) deflt = &garbage2;
lbajardsilogic@0 541
lbajardsilogic@0 542 if (name == "Gain") {
lbajardsilogic@0 543
lbajardsilogic@0 544 *min = -50;
lbajardsilogic@0 545 *max = 50;
lbajardsilogic@0 546 *deflt = 0;
lbajardsilogic@0 547
lbajardsilogic@0 548 std::cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << std::endl;
lbajardsilogic@0 549
lbajardsilogic@0 550 val = lrint(log10(m_gain) * 20.0);
lbajardsilogic@0 551 if (val < *min) val = *min;
lbajardsilogic@0 552 if (val > *max) val = *max;
lbajardsilogic@0 553
lbajardsilogic@0 554 } else if (name == "Normalize") {
lbajardsilogic@0 555
lbajardsilogic@0 556 val = (m_normalize ? 1 : 0);
lbajardsilogic@0 557 *deflt = 0;
lbajardsilogic@0 558
lbajardsilogic@0 559 } else if (name == "Colour") {
lbajardsilogic@0 560
lbajardsilogic@0 561 if (m_plotStyle == PlotFilledBlocks) {
lbajardsilogic@0 562
lbajardsilogic@0 563 *min = 0;
lbajardsilogic@0 564 *max = ColourMapper::getColourMapCount() - 1;
lbajardsilogic@0 565 *deflt = 0;
lbajardsilogic@0 566
lbajardsilogic@0 567 val = m_colourMap;
lbajardsilogic@0 568
lbajardsilogic@0 569 } else {
lbajardsilogic@0 570
lbajardsilogic@0 571 *min = 0;
lbajardsilogic@0 572 *max = 5;
lbajardsilogic@0 573 *deflt = 0;
lbajardsilogic@0 574
lbajardsilogic@0 575 if (m_colour == Qt::black) val = 0;
lbajardsilogic@0 576 else if (m_colour == Qt::darkRed) val = 1;
lbajardsilogic@0 577 else if (m_colour == Qt::darkBlue) val = 2;
lbajardsilogic@0 578 else if (m_colour == Qt::darkGreen) val = 3;
lbajardsilogic@0 579 else if (m_colour == QColor(200, 50, 255)) val = 4;
lbajardsilogic@0 580 else if (m_colour == QColor(255, 150, 50)) val = 5;
lbajardsilogic@0 581 }
lbajardsilogic@0 582
lbajardsilogic@0 583 } else if (name == "Scale") {
lbajardsilogic@0 584
lbajardsilogic@0 585 *min = 0;
lbajardsilogic@0 586 *max = 2;
lbajardsilogic@0 587 *deflt = (int)dBScale;
lbajardsilogic@0 588
lbajardsilogic@0 589 val = (int)m_energyScale;
lbajardsilogic@0 590
lbajardsilogic@0 591 } else if (name == "Sampling Mode") {
lbajardsilogic@0 592
lbajardsilogic@0 593 *min = 0;
lbajardsilogic@0 594 *max = 2;
lbajardsilogic@0 595 *deflt = (int)SampleMean;
lbajardsilogic@0 596
lbajardsilogic@0 597 val = (int)m_samplingMode;
lbajardsilogic@0 598
lbajardsilogic@0 599 } else if (name == "Plot Type") {
lbajardsilogic@0 600
lbajardsilogic@0 601 *min = 0;
lbajardsilogic@0 602 *max = 3;
lbajardsilogic@0 603 *deflt = (int)PlotSteps;
lbajardsilogic@0 604
lbajardsilogic@0 605 val = (int)m_plotStyle;
lbajardsilogic@0 606
lbajardsilogic@0 607 } else if (name == "Bin Scale") {
lbajardsilogic@0 608
lbajardsilogic@0 609 *min = 0;
lbajardsilogic@0 610 *max = 2;
lbajardsilogic@0 611 *deflt = (int)LinearBins;
lbajardsilogic@0 612 // *max = 1; // I don't think we really do want to offer inverted log
lbajardsilogic@0 613
lbajardsilogic@0 614 val = (int)m_binScale;
lbajardsilogic@0 615
lbajardsilogic@0 616 } else {
lbajardsilogic@0 617 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
lbajardsilogic@0 618 }
lbajardsilogic@0 619
lbajardsilogic@0 620 return val;
lbajardsilogic@0 621 }
lbajardsilogic@0 622
lbajardsilogic@0 623 QString
lbajardsilogic@0 624 SliceLayer::getPropertyValueLabel(const PropertyName &name,
lbajardsilogic@0 625 int value) const
lbajardsilogic@0 626 {
lbajardsilogic@0 627 if (name == "Colour") {
lbajardsilogic@0 628 if (m_plotStyle == PlotFilledBlocks) {
lbajardsilogic@0 629 return ColourMapper::getColourMapName(value);
lbajardsilogic@0 630 } else {
lbajardsilogic@0 631 switch (value) {
lbajardsilogic@0 632 default:
lbajardsilogic@0 633 case 0: return tr("Black");
lbajardsilogic@0 634 case 1: return tr("Red");
lbajardsilogic@0 635 case 2: return tr("Blue");
lbajardsilogic@0 636 case 3: return tr("Green");
lbajardsilogic@0 637 case 4: return tr("Purple");
lbajardsilogic@0 638 case 5: return tr("Orange");
lbajardsilogic@0 639 }
lbajardsilogic@0 640 }
lbajardsilogic@0 641 }
lbajardsilogic@0 642 if (name == "Scale") {
lbajardsilogic@0 643 switch (value) {
lbajardsilogic@0 644 default:
lbajardsilogic@0 645 case 0: return tr("Linear");
lbajardsilogic@0 646 case 1: return tr("Meter");
lbajardsilogic@0 647 case 2: return tr("dB");
lbajardsilogic@0 648 }
lbajardsilogic@0 649 }
lbajardsilogic@0 650 if (name == "Sampling Mode") {
lbajardsilogic@0 651 switch (value) {
lbajardsilogic@0 652 default:
lbajardsilogic@0 653 case 0: return tr("Any");
lbajardsilogic@0 654 case 1: return tr("Mean");
lbajardsilogic@0 655 case 2: return tr("Peak");
lbajardsilogic@0 656 }
lbajardsilogic@0 657 }
lbajardsilogic@0 658 if (name == "Plot Type") {
lbajardsilogic@0 659 switch (value) {
lbajardsilogic@0 660 default:
lbajardsilogic@0 661 case 0: return tr("Lines");
lbajardsilogic@0 662 case 1: return tr("Steps");
lbajardsilogic@0 663 case 2: return tr("Blocks");
lbajardsilogic@0 664 case 3: return tr("Colours");
lbajardsilogic@0 665 }
lbajardsilogic@0 666 }
lbajardsilogic@0 667 if (name == "Bin Scale") {
lbajardsilogic@0 668 switch (value) {
lbajardsilogic@0 669 default:
lbajardsilogic@0 670 case 0: return tr("Linear Bins");
lbajardsilogic@0 671 case 1: return tr("Log Bins");
lbajardsilogic@0 672 case 2: return tr("Rev Log Bins");
lbajardsilogic@0 673 }
lbajardsilogic@0 674 }
lbajardsilogic@0 675 return tr("<unknown>");
lbajardsilogic@0 676 }
lbajardsilogic@0 677
lbajardsilogic@0 678 RangeMapper *
lbajardsilogic@0 679 SliceLayer::getNewPropertyRangeMapper(const PropertyName &name) const
lbajardsilogic@0 680 {
lbajardsilogic@0 681 if (name == "Gain") {
lbajardsilogic@0 682 return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
lbajardsilogic@0 683 }
lbajardsilogic@0 684 return 0;
lbajardsilogic@0 685 }
lbajardsilogic@0 686
lbajardsilogic@0 687 void
lbajardsilogic@0 688 SliceLayer::setProperty(const PropertyName &name, int value)
lbajardsilogic@0 689 {
lbajardsilogic@0 690 if (name == "Gain") {
lbajardsilogic@0 691 setGain(pow(10, float(value)/20.0));
lbajardsilogic@0 692 } else if (name == "Colour") {
lbajardsilogic@0 693 if (m_plotStyle == PlotFilledBlocks) {
lbajardsilogic@0 694 setFillColourMap(value);
lbajardsilogic@0 695 } else {
lbajardsilogic@0 696 switch (value) {
lbajardsilogic@0 697 default:
lbajardsilogic@0 698 case 0: setBaseColour(Qt::black); break;
lbajardsilogic@0 699 case 1: setBaseColour(Qt::darkRed); break;
lbajardsilogic@0 700 case 2: setBaseColour(Qt::darkBlue); break;
lbajardsilogic@0 701 case 3: setBaseColour(Qt::darkGreen); break;
lbajardsilogic@0 702 case 4: setBaseColour(QColor(200, 50, 255)); break;
lbajardsilogic@0 703 case 5: setBaseColour(QColor(255, 150, 50)); break;
lbajardsilogic@0 704 }
lbajardsilogic@0 705 }
lbajardsilogic@0 706 } else if (name == "Scale") {
lbajardsilogic@0 707 switch (value) {
lbajardsilogic@0 708 default:
lbajardsilogic@0 709 case 0: setEnergyScale(LinearScale); break;
lbajardsilogic@0 710 case 1: setEnergyScale(MeterScale); break;
lbajardsilogic@0 711 case 2: setEnergyScale(dBScale); break;
lbajardsilogic@0 712 }
lbajardsilogic@0 713 } else if (name == "Plot Type") {
lbajardsilogic@0 714 setPlotStyle(PlotStyle(value));
lbajardsilogic@0 715 } else if (name == "Sampling Mode") {
lbajardsilogic@0 716 switch (value) {
lbajardsilogic@0 717 default:
lbajardsilogic@0 718 case 0: setSamplingMode(NearestSample); break;
lbajardsilogic@0 719 case 1: setSamplingMode(SampleMean); break;
lbajardsilogic@0 720 case 2: setSamplingMode(SamplePeak); break;
lbajardsilogic@0 721 }
lbajardsilogic@0 722 } else if (name == "Bin Scale") {
lbajardsilogic@0 723 switch (value) {
lbajardsilogic@0 724 default:
lbajardsilogic@0 725 case 0: setBinScale(LinearBins); break;
lbajardsilogic@0 726 case 1: setBinScale(LogBins); break;
lbajardsilogic@0 727 case 2: setBinScale(InvertedLogBins); break;
lbajardsilogic@0 728 }
lbajardsilogic@0 729 } else if (name == "Normalize") {
lbajardsilogic@0 730 setNormalize(value ? true : false);
lbajardsilogic@0 731 }
lbajardsilogic@0 732 }
lbajardsilogic@0 733
lbajardsilogic@0 734 void
lbajardsilogic@0 735 SliceLayer::setBaseColour(QColor colour)
lbajardsilogic@0 736 {
lbajardsilogic@0 737 if (m_colour == colour) return;
lbajardsilogic@0 738 m_colour = colour;
lbajardsilogic@0 739 emit layerParametersChanged();
lbajardsilogic@0 740 }
lbajardsilogic@0 741
lbajardsilogic@0 742 void
lbajardsilogic@0 743 SliceLayer::setFillColourMap(int map)
lbajardsilogic@0 744 {
lbajardsilogic@0 745 if (m_colourMap == map) return;
lbajardsilogic@0 746 m_colourMap = map;
lbajardsilogic@0 747 emit layerParametersChanged();
lbajardsilogic@0 748 }
lbajardsilogic@0 749
lbajardsilogic@0 750 void
lbajardsilogic@0 751 SliceLayer::setEnergyScale(EnergyScale scale)
lbajardsilogic@0 752 {
lbajardsilogic@0 753 if (m_energyScale == scale) return;
lbajardsilogic@0 754 m_energyScale = scale;
lbajardsilogic@0 755 emit layerParametersChanged();
lbajardsilogic@0 756 }
lbajardsilogic@0 757
lbajardsilogic@0 758 void
lbajardsilogic@0 759 SliceLayer::setSamplingMode(SamplingMode mode)
lbajardsilogic@0 760 {
lbajardsilogic@0 761 if (m_samplingMode == mode) return;
lbajardsilogic@0 762 m_samplingMode = mode;
lbajardsilogic@0 763 emit layerParametersChanged();
lbajardsilogic@0 764 }
lbajardsilogic@0 765
lbajardsilogic@0 766 void
lbajardsilogic@0 767 SliceLayer::setPlotStyle(PlotStyle style)
lbajardsilogic@0 768 {
lbajardsilogic@0 769 if (m_plotStyle == style) return;
lbajardsilogic@0 770 bool colourTypeChanged = (style == PlotFilledBlocks ||
lbajardsilogic@0 771 m_plotStyle == PlotFilledBlocks);
lbajardsilogic@0 772 m_plotStyle = style;
lbajardsilogic@0 773 if (colourTypeChanged) {
lbajardsilogic@0 774 emit layerParameterRangesChanged();
lbajardsilogic@0 775 }
lbajardsilogic@0 776 emit layerParametersChanged();
lbajardsilogic@0 777 }
lbajardsilogic@0 778
lbajardsilogic@0 779 void
lbajardsilogic@0 780 SliceLayer::setBinScale(BinScale scale)
lbajardsilogic@0 781 {
lbajardsilogic@0 782 if (m_binScale == scale) return;
lbajardsilogic@0 783 m_binScale = scale;
lbajardsilogic@0 784 emit layerParametersChanged();
lbajardsilogic@0 785 }
lbajardsilogic@0 786
lbajardsilogic@0 787 void
lbajardsilogic@0 788 SliceLayer::setNormalize(bool n)
lbajardsilogic@0 789 {
lbajardsilogic@0 790 if (m_normalize == n) return;
lbajardsilogic@0 791 m_normalize = n;
lbajardsilogic@0 792 emit layerParametersChanged();
lbajardsilogic@0 793 }
lbajardsilogic@0 794
lbajardsilogic@0 795 void
lbajardsilogic@0 796 SliceLayer::setGain(float gain)
lbajardsilogic@0 797 {
lbajardsilogic@0 798 if (m_gain == gain) return;
lbajardsilogic@0 799 m_gain = gain;
lbajardsilogic@0 800 emit layerParametersChanged();
lbajardsilogic@0 801 }
lbajardsilogic@0 802
lbajardsilogic@0 803 QString
lbajardsilogic@0 804 SliceLayer::toXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@0 805 {
lbajardsilogic@0 806 QString s;
lbajardsilogic@0 807
lbajardsilogic@0 808 s += QString("colour=\"%1\" "
lbajardsilogic@0 809 "colourScheme=\"%2\" "
lbajardsilogic@0 810 "energyScale=\"%3\" "
lbajardsilogic@0 811 "samplingMode=\"%4\" "
lbajardsilogic@0 812 "gain=\"%5\" "
lbajardsilogic@0 813 "normalize=\"%6\"")
lbajardsilogic@0 814 .arg(encodeColour(m_colour))
lbajardsilogic@0 815 .arg(m_colourMap)
lbajardsilogic@0 816 .arg(m_energyScale)
lbajardsilogic@0 817 .arg(m_samplingMode)
lbajardsilogic@0 818 .arg(m_gain)
lbajardsilogic@0 819 .arg(m_normalize ? "true" : "false");
lbajardsilogic@0 820
lbajardsilogic@0 821 return Layer::toXmlString(indent, extraAttributes + " " + s);
lbajardsilogic@0 822 }
lbajardsilogic@0 823
lbajardsilogic@0 824 void
lbajardsilogic@0 825 SliceLayer::setProperties(const QXmlAttributes &attributes)
lbajardsilogic@0 826 {
lbajardsilogic@0 827 bool ok = false;
lbajardsilogic@0 828
lbajardsilogic@0 829 QString colourSpec = attributes.value("colour");
lbajardsilogic@0 830 if (colourSpec != "") {
lbajardsilogic@0 831 QColor colour(colourSpec);
lbajardsilogic@0 832 if (colour.isValid()) {
lbajardsilogic@0 833 setBaseColour(QColor(colourSpec));
lbajardsilogic@0 834 }
lbajardsilogic@0 835 }
lbajardsilogic@0 836
lbajardsilogic@0 837 EnergyScale scale = (EnergyScale)
lbajardsilogic@0 838 attributes.value("energyScale").toInt(&ok);
lbajardsilogic@0 839 if (ok) setEnergyScale(scale);
lbajardsilogic@0 840
lbajardsilogic@0 841 SamplingMode mode = (SamplingMode)
lbajardsilogic@0 842 attributes.value("samplingMode").toInt(&ok);
lbajardsilogic@0 843 if (ok) setSamplingMode(mode);
lbajardsilogic@0 844
lbajardsilogic@0 845 int colourMap = attributes.value("colourScheme").toInt(&ok);
lbajardsilogic@0 846 if (ok) setFillColourMap(colourMap);
lbajardsilogic@0 847
lbajardsilogic@0 848 float gain = attributes.value("gain").toFloat(&ok);
lbajardsilogic@0 849 if (ok) setGain(gain);
lbajardsilogic@0 850
lbajardsilogic@0 851 bool normalize = (attributes.value("normalize").trimmed() == "true");
lbajardsilogic@0 852 setNormalize(normalize);
lbajardsilogic@0 853 }
lbajardsilogic@0 854
lbajardsilogic@0 855 bool
lbajardsilogic@0 856 SliceLayer::getValueExtents(float &, float &, bool &, QString &) const
lbajardsilogic@0 857 {
lbajardsilogic@0 858 return false;
lbajardsilogic@0 859 }
lbajardsilogic@0 860