annotate layer/Layer.cpp @ 280:3c402c6052f6

* Pull peak-picker out of SpectrumLayer and into FFTModel; use combined peak-picker and frequency estimator for SpectrogramLayer (makes the peak frequency spectrogram a bit quicker) * Add more information to spectrum and spectrogram crosshairs
author Chris Cannam
date Wed, 04 Jul 2007 15:29:16 +0000
parents b9380f679f70
children 86a112b5b319
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@127 16 #include "Layer.h"
Chris@128 17 #include "view/View.h"
Chris@128 18 #include "data/model/Model.h"
Chris@268 19 #include "base/CommandHistory.h"
Chris@127 20
Chris@127 21 #include <iostream>
Chris@127 22
Chris@131 23 #include <QMutexLocker>
Chris@267 24 #include <QMouseEvent>
Chris@131 25
Chris@131 26 #include "LayerFactory.h"
Chris@128 27 #include "base/PlayParameterRepository.h"
Chris@127 28
Chris@272 29 #include <cmath>
Chris@272 30
Chris@267 31 Layer::Layer() :
Chris@267 32 m_haveDraggingRect(false)
Chris@127 33 {
Chris@127 34 }
Chris@127 35
Chris@127 36 Layer::~Layer()
Chris@127 37 {
Chris@127 38 // std::cerr << "Layer::~Layer(" << this << ")" << std::endl;
Chris@127 39 }
Chris@127 40
Chris@127 41 QString
Chris@127 42 Layer::getPropertyContainerIconName() const
Chris@127 43 {
Chris@127 44 return LayerFactory::getInstance()->getLayerIconName
Chris@127 45 (LayerFactory::getInstance()->getLayerType(this));
Chris@127 46 }
Chris@127 47
Chris@127 48 QString
Chris@127 49 Layer::getLayerPresentationName() const
Chris@127 50 {
Chris@203 51 // QString layerName = objectName();
Chris@203 52
Chris@203 53 LayerFactory *factory = LayerFactory::getInstance();
Chris@203 54 QString layerName = factory->getLayerPresentationName
Chris@203 55 (factory->getLayerType(this));
Chris@203 56
Chris@127 57 QString modelName;
Chris@127 58 if (getModel()) modelName = getModel()->objectName();
Chris@127 59
Chris@127 60 QString text;
Chris@127 61 if (modelName != "") {
Chris@127 62 text = QString("%1: %2").arg(modelName).arg(layerName);
Chris@127 63 } else {
Chris@127 64 text = layerName;
Chris@127 65 }
Chris@127 66
Chris@127 67 return text;
Chris@127 68 }
Chris@127 69
Chris@127 70 void
Chris@127 71 Layer::setObjectName(const QString &name)
Chris@127 72 {
Chris@127 73 QObject::setObjectName(name);
Chris@127 74 emit layerNameChanged();
Chris@127 75 }
Chris@127 76
Chris@127 77 PlayParameters *
Chris@127 78 Layer::getPlayParameters()
Chris@127 79 {
Chris@127 80 // std::cerr << "Layer (" << this << ", " << objectName().toStdString() << ")::getPlayParameters: model is "<< getModel() << std::endl;
Chris@127 81 const Model *model = getModel();
Chris@127 82 if (model) {
Chris@127 83 return PlayParameterRepository::getInstance()->getPlayParameters(model);
Chris@127 84 }
Chris@127 85 return 0;
Chris@127 86 }
Chris@127 87
Chris@127 88 void
Chris@131 89 Layer::setLayerDormant(const View *v, bool dormant)
Chris@131 90 {
Chris@131 91 const void *vv = (const void *)v;
Chris@131 92 QMutexLocker locker(&m_dormancyMutex);
Chris@131 93 m_dormancy[vv] = dormant;
Chris@131 94 }
Chris@131 95
Chris@131 96 bool
Chris@131 97 Layer::isLayerDormant(const View *v) const
Chris@131 98 {
Chris@131 99 const void *vv = (const void *)v;
Chris@131 100 QMutexLocker locker(&m_dormancyMutex);
Chris@131 101 if (m_dormancy.find(vv) == m_dormancy.end()) return false;
Chris@131 102 return m_dormancy.find(vv)->second;
Chris@131 103 }
Chris@131 104
Chris@131 105 void
Chris@127 106 Layer::showLayer(View *view, bool show)
Chris@127 107 {
Chris@127 108 setLayerDormant(view, !show);
Chris@127 109 emit layerParametersChanged();
Chris@127 110 }
Chris@127 111
Chris@260 112 bool
Chris@267 113 Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const
Chris@260 114 {
Chris@260 115 if (!hasTimeXAxis()) return false;
Chris@260 116
Chris@260 117 const Model *m = getModel();
Chris@260 118 if (!m) return false;
Chris@260 119
Chris@260 120 value = float(v->getFrameForX(x)) / m->getSampleRate();
Chris@260 121 unit = "s";
Chris@260 122 return true;
Chris@260 123 }
Chris@260 124
Chris@268 125 bool
Chris@274 126 Layer::getYScaleDifference(const View *v, int y0, int y1,
Chris@274 127 float &diff, QString &unit) const
Chris@274 128 {
Chris@274 129 float v0, v1;
Chris@274 130 if (!getYScaleValue(v, y0, v0, unit) ||
Chris@274 131 !getYScaleValue(v, y1, v1, unit)) {
Chris@274 132 diff = 0.f;
Chris@274 133 return false;
Chris@274 134 }
Chris@274 135 diff = fabsf(v1 - v0);
Chris@274 136 return true;
Chris@274 137 }
Chris@274 138
Chris@274 139 bool
Chris@268 140 Layer::MeasureRect::operator<(const MeasureRect &mr) const
Chris@268 141 {
Chris@268 142 if (haveFrames) {
Chris@268 143 if (startFrame == mr.startFrame) {
Chris@268 144 if (endFrame != mr.endFrame) {
Chris@268 145 return endFrame < mr.endFrame;
Chris@268 146 }
Chris@268 147 } else {
Chris@268 148 return startFrame < mr.startFrame;
Chris@268 149 }
Chris@268 150 } else {
Chris@268 151 if (pixrect.x() == mr.pixrect.x()) {
Chris@268 152 if (pixrect.width() != mr.pixrect.width()) {
Chris@268 153 return pixrect.width() < mr.pixrect.width();
Chris@268 154 }
Chris@268 155 } else {
Chris@268 156 return pixrect.x() < mr.pixrect.x();
Chris@268 157 }
Chris@268 158 }
Chris@268 159
Chris@268 160 // the two rects are equal in x and width
Chris@268 161
Chris@268 162 if (pixrect.y() == mr.pixrect.y()) {
Chris@268 163 return pixrect.height() < mr.pixrect.height();
Chris@268 164 } else {
Chris@268 165 return pixrect.y() < mr.pixrect.y();
Chris@268 166 }
Chris@268 167 }
Chris@268 168
Chris@268 169 QString
Chris@269 170 Layer::MeasureRect::toXmlString(QString indent) const
Chris@269 171 {
Chris@269 172 QString s;
Chris@269 173
Chris@269 174 s += indent;
Chris@269 175 s += QString("<measurement ");
Chris@269 176
Chris@269 177 if (haveFrames) {
Chris@269 178 s += QString("startFrame=\"%1\" endFrame=\"%2\" ")
Chris@269 179 .arg(startFrame).arg(endFrame);
Chris@269 180 } else {
Chris@269 181 s += QString("startX=\"%1\" endX=\"%2\" ")
Chris@269 182 .arg(pixrect.x()).arg(pixrect.x() + pixrect.width());
Chris@269 183 }
Chris@269 184
Chris@269 185 s += QString("startY=\"%1\" endY=\"%2\"/>\n")
Chris@273 186 .arg(startY).arg(endY);
Chris@269 187
Chris@269 188 return s;
Chris@269 189 }
Chris@269 190
Chris@269 191 void
Chris@269 192 Layer::addMeasurementRect(const QXmlAttributes &attributes)
Chris@269 193 {
Chris@269 194 MeasureRect rect;
Chris@269 195 QString fs = attributes.value("startFrame");
Chris@273 196 int x0 = 0, x1 = 0;
Chris@269 197 if (fs != "") {
Chris@269 198 rect.startFrame = fs.toLong();
Chris@269 199 rect.endFrame = attributes.value("endFrame").toLong();
Chris@269 200 rect.haveFrames = true;
Chris@269 201 } else {
Chris@269 202 x0 = attributes.value("startX").toInt();
Chris@269 203 x1 = attributes.value("endX").toInt();
Chris@269 204 rect.haveFrames = false;
Chris@269 205 }
Chris@273 206 rect.startY = attributes.value("startY").toDouble();
Chris@273 207 rect.endY = attributes.value("endY").toDouble();
Chris@273 208 rect.pixrect = QRect(x0, 0, x1 - x0, 0);
Chris@269 209 addMeasureRectToSet(rect);
Chris@269 210 }
Chris@269 211
Chris@269 212 QString
Chris@268 213 Layer::AddMeasurementRectCommand::getName() const
Chris@268 214 {
Chris@268 215 return tr("Make Measurement");
Chris@268 216 }
Chris@268 217
Chris@268 218 void
Chris@268 219 Layer::AddMeasurementRectCommand::execute()
Chris@268 220 {
Chris@269 221 m_layer->addMeasureRectToSet(m_rect);
Chris@268 222 }
Chris@268 223
Chris@268 224 void
Chris@268 225 Layer::AddMeasurementRectCommand::unexecute()
Chris@268 226 {
Chris@269 227 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@268 228 }
Chris@268 229
Chris@267 230 void
Chris@267 231 Layer::measureStart(View *v, QMouseEvent *e)
Chris@267 232 {
Chris@267 233 m_draggingRect.pixrect = QRect(e->x(), e->y(), 0, 0);
Chris@267 234 if (hasTimeXAxis()) {
Chris@268 235 m_draggingRect.haveFrames = true;
Chris@267 236 m_draggingRect.startFrame = v->getFrameForX(e->x());
Chris@267 237 m_draggingRect.endFrame = m_draggingRect.startFrame;
Chris@268 238 } else {
Chris@268 239 m_draggingRect.haveFrames = false;
Chris@267 240 }
Chris@273 241 setMeasureRectYCoord(v, m_draggingRect, true, e->y());
Chris@267 242 m_haveDraggingRect = true;
Chris@267 243 }
Chris@267 244
Chris@267 245 void
Chris@267 246 Layer::measureDrag(View *v, QMouseEvent *e)
Chris@267 247 {
Chris@267 248 if (!m_haveDraggingRect) return;
Chris@268 249
Chris@267 250 m_draggingRect.pixrect = QRect(m_draggingRect.pixrect.x(),
Chris@267 251 m_draggingRect.pixrect.y(),
Chris@267 252 e->x() - m_draggingRect.pixrect.x(),
Chris@274 253 e->y() - m_draggingRect.pixrect.y());
Chris@268 254
Chris@273 255 setMeasureRectYCoord(v, m_draggingRect, false, e->y());
Chris@273 256
Chris@267 257 if (hasTimeXAxis()) {
Chris@267 258 m_draggingRect.endFrame = v->getFrameForX(e->x());
Chris@267 259 }
Chris@267 260 }
Chris@267 261
Chris@267 262 void
Chris@267 263 Layer::measureEnd(View *v, QMouseEvent *e)
Chris@267 264 {
Chris@267 265 if (!m_haveDraggingRect) return;
Chris@267 266 measureDrag(v, e);
Chris@268 267
Chris@268 268 CommandHistory::getInstance()->addCommand
Chris@268 269 (new AddMeasurementRectCommand(this, m_draggingRect));
Chris@268 270
Chris@267 271 m_haveDraggingRect = false;
Chris@267 272 }
Chris@267 273
Chris@267 274 void
Chris@280 275 Layer::measureDoubleClick(View *v, QMouseEvent *e)
Chris@280 276 {
Chris@280 277 // nothing
Chris@280 278 }
Chris@280 279
Chris@280 280 void
Chris@272 281 Layer::paintMeasurementRects(View *v, QPainter &paint,
Chris@272 282 bool showFocus, QPoint focusPoint) const
Chris@267 283 {
Chris@273 284 updateMeasurePixrects(v);
Chris@272 285
Chris@272 286 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 287
Chris@267 288 if (m_haveDraggingRect) {
Chris@272 289
Chris@270 290 paintMeasurementRect(v, paint, m_draggingRect, true);
Chris@272 291
Chris@272 292 } else if (showFocus) {
Chris@272 293
Chris@272 294 focusRectItr = findFocusedMeasureRect(focusPoint);
Chris@267 295 }
Chris@267 296
Chris@268 297 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@268 298 i != m_measureRects.end(); ++i) {
Chris@272 299 paintMeasurementRect(v, paint, *i, i == focusRectItr);
Chris@267 300 }
Chris@267 301 }
Chris@267 302
Chris@272 303 bool
Chris@272 304 Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const
Chris@272 305 {
Chris@273 306 updateMeasurePixrects(v);
Chris@272 307
Chris@272 308 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
Chris@272 309 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
Chris@272 310
Chris@272 311 return (i0 != i1);
Chris@272 312 }
Chris@272 313
Chris@272 314 void
Chris@273 315 Layer::updateMeasurePixrects(View *v) const
Chris@272 316 {
Chris@272 317 long sf = v->getStartFrame();
Chris@272 318 long ef = v->getEndFrame();
Chris@272 319
Chris@272 320 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 321 i != m_measureRects.end(); ++i) {
Chris@272 322
Chris@273 323 // This logic depends on the fact that if one measure rect in
Chris@273 324 // a layer has frame values, they all will. That is in fact
Chris@273 325 // the case, because haveFrames is based on whether the layer
Chris@273 326 // hasTimeXAxis() or not. Measure rect ordering in the rect
Chris@273 327 // set wouldn't work correctly either, if haveFrames could
Chris@273 328 // vary.
Chris@272 329
Chris@273 330 if (i->haveFrames) {
Chris@273 331 if (i->startFrame >= ef) break;
Chris@273 332 if (i->endFrame <= sf) continue;
Chris@273 333 }
Chris@272 334
Chris@273 335 int x0 = i->pixrect.x();
Chris@273 336 int x1 = x0 + i->pixrect.width();
Chris@273 337
Chris@273 338 if (i->haveFrames) {
Chris@273 339 if (i->startFrame >= v->getStartFrame()) {
Chris@273 340 x0 = v->getXForFrame(i->startFrame);
Chris@273 341 }
Chris@273 342 if (i->endFrame <= long(v->getEndFrame())) {
Chris@273 343 x1 = v->getXForFrame(i->endFrame);
Chris@273 344 }
Chris@272 345 }
Chris@272 346
Chris@273 347 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
Chris@273 348
Chris@273 349 updateMeasureRectYCoords(v, *i);
Chris@273 350 }
Chris@273 351 }
Chris@273 352
Chris@273 353 void
Chris@273 354 Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const
Chris@273 355 {
Chris@273 356 int y0 = lrint(r.startY * v->height());
Chris@273 357 int y1 = lrint(r.endY * v->height());
Chris@273 358 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
Chris@273 359 }
Chris@273 360
Chris@273 361 void
Chris@273 362 Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const
Chris@273 363 {
Chris@273 364 if (start) {
Chris@273 365 r.startY = double(y) / double(v->height());
Chris@273 366 r.endY = r.startY;
Chris@273 367 } else {
Chris@273 368 r.endY = double(y) / double(v->height());
Chris@272 369 }
Chris@272 370 }
Chris@272 371
Chris@272 372 Layer::MeasureRectSet::const_iterator
Chris@272 373 Layer::findFocusedMeasureRect(QPoint focusPoint) const
Chris@272 374 {
Chris@272 375 float frDist = 0;
Chris@272 376 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 377
Chris@272 378 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 379 i != m_measureRects.end(); ++i) {
Chris@272 380
Chris@272 381 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
Chris@272 382
Chris@272 383 int cx = i->pixrect.x() + i->pixrect.width()/2;
Chris@272 384 int cy = i->pixrect.y() + i->pixrect.height()/2;
Chris@272 385 int xd = focusPoint.x() - cx;
Chris@272 386 int yd = focusPoint.y() - cy;
Chris@272 387
Chris@272 388 float d = sqrt(xd * xd + yd * yd);
Chris@272 389
Chris@272 390 if (focusRectItr == m_measureRects.end() || d < frDist) {
Chris@272 391 focusRectItr = i;
Chris@272 392 frDist = d;
Chris@272 393 }
Chris@272 394 }
Chris@272 395
Chris@272 396 return focusRectItr;
Chris@272 397 }
Chris@272 398
Chris@268 399 void
Chris@270 400 Layer::paintMeasurementRect(View *v, QPainter &paint,
Chris@270 401 const MeasureRect &r, bool focus) const
Chris@268 402 {
Chris@268 403 if (r.haveFrames) {
Chris@268 404
Chris@268 405 int x0 = -1;
Chris@268 406 int x1 = v->width() + 1;
Chris@268 407
Chris@268 408 if (r.startFrame >= v->getStartFrame()) {
Chris@268 409 x0 = v->getXForFrame(r.startFrame);
Chris@268 410 }
Chris@272 411 if (r.endFrame <= long(v->getEndFrame())) {
Chris@268 412 x1 = v->getXForFrame(r.endFrame);
Chris@268 413 }
Chris@268 414
Chris@272 415 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
Chris@268 416 r.pixrect = pr;
Chris@268 417 }
Chris@274 418
Chris@274 419 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
Chris@268 420 }
Chris@268 421
Chris@268 422 QString
Chris@268 423 Layer::toXmlString(QString indent, QString extraAttributes) const
Chris@268 424 {
Chris@268 425 QString s;
Chris@268 426
Chris@268 427 s += indent;
Chris@268 428
Chris@269 429 s += QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
Chris@268 430 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@268 431 (LayerFactory::getInstance()->getLayerType(this))))
Chris@268 432 .arg(getObjectExportId(this))
Chris@268 433 .arg(encodeEntities(objectName()))
Chris@268 434 .arg(getObjectExportId(getModel()))
Chris@268 435 .arg(extraAttributes);
Chris@268 436
Chris@269 437 if (m_measureRects.empty()) {
Chris@269 438 s += QString("/>\n");
Chris@269 439 return s;
Chris@269 440 }
Chris@269 441
Chris@269 442 s += QString(">\n");
Chris@269 443
Chris@269 444 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@269 445 i != m_measureRects.end(); ++i) {
Chris@269 446 s += i->toXmlString(indent + " ");
Chris@269 447 }
Chris@269 448
Chris@269 449 s += QString("</layer>\n");
Chris@269 450
Chris@268 451 return s;
Chris@268 452 }
Chris@269 453
Chris@269 454 QString
Chris@269 455 Layer::toBriefXmlString(QString indent, QString extraAttributes) const
Chris@269 456 {
Chris@269 457 QString s;
Chris@269 458
Chris@269 459 s += indent;
Chris@269 460
Chris@269 461 s += QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
Chris@269 462 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@269 463 (LayerFactory::getInstance()->getLayerType(this))))
Chris@269 464 .arg(getObjectExportId(this))
Chris@269 465 .arg(encodeEntities(objectName()))
Chris@269 466 .arg(getObjectExportId(getModel()))
Chris@269 467 .arg(extraAttributes);
Chris@269 468
Chris@269 469 return s;
Chris@269 470 }
Chris@269 471