annotate layer/TimeValueLayer.cpp @ 1:ab83c415a6cd

* Backed out partially complete changes to make the spectrogram only store results up to the requested max frequency. The speed improvement was minimal at the expense of annoyance when changing frequency limit, and although it did save memory, it wasn't yet reliable and fixing it is not a high enough priority.
author Chris Cannam
date Tue, 10 Jan 2006 17:04:02 +0000
parents 2a4f26e85b4c
children 7af44e8578c8
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@0 5 Chris Cannam, Queen Mary University of London, 2005
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "TimeValueLayer.h"
Chris@0 11
Chris@0 12 #include "base/Model.h"
Chris@0 13 #include "base/RealTime.h"
Chris@0 14 #include "base/Profiler.h"
Chris@0 15 #include "base/View.h"
Chris@0 16
Chris@0 17 #include "model/SparseTimeValueModel.h"
Chris@0 18
Chris@0 19 #include <QPainter>
Chris@0 20
Chris@0 21 #include <iostream>
Chris@0 22 #include <cmath>
Chris@0 23
Chris@0 24 TimeValueLayer::TimeValueLayer(View *w) :
Chris@0 25 Layer(w),
Chris@0 26 m_model(0),
Chris@0 27 m_colour(Qt::black),
Chris@0 28 m_plotStyle(PlotLines)
Chris@0 29 {
Chris@0 30 m_view->addLayer(this);
Chris@0 31 }
Chris@0 32
Chris@0 33 void
Chris@0 34 TimeValueLayer::setModel(SparseTimeValueModel *model)
Chris@0 35 {
Chris@0 36 if (m_model == model) return;
Chris@0 37 m_model = model;
Chris@0 38
Chris@0 39 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@0 40 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 41 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@0 42
Chris@0 43 connect(m_model, SIGNAL(completionChanged()),
Chris@0 44 this, SIGNAL(modelCompletionChanged()));
Chris@0 45
Chris@0 46 std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl;
Chris@0 47
Chris@0 48 emit modelReplaced();
Chris@0 49 }
Chris@0 50
Chris@0 51 Layer::PropertyList
Chris@0 52 TimeValueLayer::getProperties() const
Chris@0 53 {
Chris@0 54 PropertyList list;
Chris@0 55 list.push_back(tr("Colour"));
Chris@0 56 list.push_back(tr("Plot Type"));
Chris@0 57 return list;
Chris@0 58 }
Chris@0 59
Chris@0 60 Layer::PropertyType
Chris@0 61 TimeValueLayer::getPropertyType(const PropertyName &name) const
Chris@0 62 {
Chris@0 63 return ValueProperty;
Chris@0 64 }
Chris@0 65
Chris@0 66 int
Chris@0 67 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@0 68 int *min, int *max) const
Chris@0 69 {
Chris@0 70 //!!! factor this colour handling stuff out into a colour manager class
Chris@0 71
Chris@0 72 int deft = 0;
Chris@0 73
Chris@0 74 if (name == tr("Colour")) {
Chris@0 75
Chris@0 76 *min = 0;
Chris@0 77 *max = 5;
Chris@0 78
Chris@0 79 if (m_colour == Qt::black) deft = 0;
Chris@0 80 else if (m_colour == Qt::darkRed) deft = 1;
Chris@0 81 else if (m_colour == Qt::darkBlue) deft = 2;
Chris@0 82 else if (m_colour == Qt::darkGreen) deft = 3;
Chris@0 83 else if (m_colour == QColor(200, 50, 255)) deft = 4;
Chris@0 84 else if (m_colour == QColor(255, 150, 50)) deft = 5;
Chris@0 85
Chris@0 86 } else if (name == tr("Plot Type")) {
Chris@0 87
Chris@0 88 *min = 0;
Chris@0 89 *max = 2;
Chris@0 90
Chris@0 91 deft = int(m_plotStyle);
Chris@0 92
Chris@0 93 } else {
Chris@0 94
Chris@0 95 deft = Layer::getPropertyRangeAndValue(name, min, max);
Chris@0 96 }
Chris@0 97
Chris@0 98 return deft;
Chris@0 99 }
Chris@0 100
Chris@0 101 QString
Chris@0 102 TimeValueLayer::getPropertyValueLabel(const PropertyName &name,
Chris@0 103 int value) const
Chris@0 104 {
Chris@0 105 if (name == tr("Colour")) {
Chris@0 106 switch (value) {
Chris@0 107 default:
Chris@0 108 case 0: return tr("Black");
Chris@0 109 case 1: return tr("Red");
Chris@0 110 case 2: return tr("Blue");
Chris@0 111 case 3: return tr("Green");
Chris@0 112 case 4: return tr("Purple");
Chris@0 113 case 5: return tr("Orange");
Chris@0 114 }
Chris@0 115 } else if (name == tr("Plot Type")) {
Chris@0 116 switch (value) {
Chris@0 117 default:
Chris@0 118 case 0: return tr("Points");
Chris@0 119 case 1: return tr("Stems");
Chris@0 120 case 2: return tr("Lines");
Chris@0 121 }
Chris@0 122 }
Chris@0 123 return tr("<unknown>");
Chris@0 124 }
Chris@0 125
Chris@0 126 void
Chris@0 127 TimeValueLayer::setProperty(const PropertyName &name, int value)
Chris@0 128 {
Chris@0 129 if (name == tr("Colour")) {
Chris@0 130 switch (value) {
Chris@0 131 default:
Chris@0 132 case 0: setBaseColour(Qt::black); break;
Chris@0 133 case 1: setBaseColour(Qt::darkRed); break;
Chris@0 134 case 2: setBaseColour(Qt::darkBlue); break;
Chris@0 135 case 3: setBaseColour(Qt::darkGreen); break;
Chris@0 136 case 4: setBaseColour(QColor(200, 50, 255)); break;
Chris@0 137 case 5: setBaseColour(QColor(255, 150, 50)); break;
Chris@0 138 }
Chris@0 139 } else if (name == tr("Plot Type")) {
Chris@0 140 setPlotStyle(PlotStyle(value));
Chris@0 141 }
Chris@0 142 }
Chris@0 143
Chris@0 144 void
Chris@0 145 TimeValueLayer::setBaseColour(QColor colour)
Chris@0 146 {
Chris@0 147 if (m_colour == colour) return;
Chris@0 148 m_colour = colour;
Chris@0 149 emit layerParametersChanged();
Chris@0 150 }
Chris@0 151
Chris@0 152 void
Chris@0 153 TimeValueLayer::setPlotStyle(PlotStyle style)
Chris@0 154 {
Chris@0 155 if (m_plotStyle == style) return;
Chris@0 156 m_plotStyle = style;
Chris@0 157 emit layerParametersChanged();
Chris@0 158 }
Chris@0 159
Chris@0 160 bool
Chris@0 161 TimeValueLayer::isLayerScrollable() const
Chris@0 162 {
Chris@0 163 QPoint discard;
Chris@0 164 return !m_view->shouldIlluminateLocalFeatures(this, discard);
Chris@0 165 }
Chris@0 166
Chris@0 167 QRect
Chris@0 168 TimeValueLayer::getFeatureDescriptionRect(QPainter &paint, QPoint pos) const
Chris@0 169 {
Chris@0 170 return QRect(0, 0,
Chris@0 171 std::max(100, paint.fontMetrics().width(tr("No local points"))),
Chris@0 172 70); //!!!
Chris@0 173 }
Chris@0 174
Chris@0 175 //!!! too much in common with TimeInstantLayer
Chris@0 176
Chris@0 177 SparseTimeValueModel::PointList
Chris@0 178 TimeValueLayer::getLocalPoints(int x) const
Chris@0 179 {
Chris@0 180 if (!m_model) return SparseTimeValueModel::PointList();
Chris@0 181
Chris@0 182 long startFrame = m_view->getStartFrame();
Chris@0 183 long endFrame = m_view->getEndFrame();
Chris@0 184 int zoomLevel = m_view->getZoomLevel();
Chris@0 185 long frame = startFrame + x * zoomLevel;
Chris@0 186
Chris@0 187 SparseTimeValueModel::PointList onPoints =
Chris@0 188 m_model->getPoints(frame);
Chris@0 189
Chris@0 190 if (!onPoints.empty()) {
Chris@0 191 return onPoints;
Chris@0 192 }
Chris@0 193
Chris@0 194 SparseTimeValueModel::PointList prevPoints =
Chris@0 195 m_model->getPreviousPoints(frame);
Chris@0 196 SparseTimeValueModel::PointList nextPoints =
Chris@0 197 m_model->getNextPoints(frame);
Chris@0 198
Chris@0 199 SparseTimeValueModel::PointList usePoints = prevPoints;
Chris@0 200
Chris@0 201 if (prevPoints.empty()) {
Chris@0 202 usePoints = nextPoints;
Chris@0 203 } else if (prevPoints.begin()->frame < startFrame &&
Chris@0 204 !(nextPoints.begin()->frame > endFrame)) {
Chris@0 205 usePoints = nextPoints;
Chris@0 206 } else if (nextPoints.begin()->frame - frame <
Chris@0 207 frame - prevPoints.begin()->frame) {
Chris@0 208 usePoints = nextPoints;
Chris@0 209 }
Chris@0 210
Chris@0 211 return usePoints;
Chris@0 212 }
Chris@0 213
Chris@0 214 void
Chris@0 215 TimeValueLayer::paintLocalFeatureDescription(QPainter &paint, QRect rect,
Chris@0 216 QPoint pos) const
Chris@0 217 {
Chris@0 218 //!!! bleagh
Chris@0 219
Chris@0 220 int x = pos.x();
Chris@0 221
Chris@0 222 if (!m_model || !m_model->getSampleRate()) return;
Chris@0 223
Chris@0 224 SparseTimeValueModel::PointList points = getLocalPoints(x);
Chris@0 225
Chris@0 226 QFontMetrics metrics = paint.fontMetrics();
Chris@0 227 int xbase = rect.x() + 5;
Chris@0 228 int ybase = rect.y() + 5;
Chris@0 229
Chris@0 230 if (points.empty()) {
Chris@0 231 QString label = tr("No local points");
Chris@0 232 if (!m_model->isReady()) {
Chris@0 233 label = tr("In progress");
Chris@0 234 }
Chris@0 235 paint.drawText(xbase + 5, ybase + 5 + metrics.ascent(), label);
Chris@0 236 return;
Chris@0 237 }
Chris@0 238
Chris@0 239 long useFrame = points.begin()->frame;
Chris@0 240
Chris@0 241 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
Chris@0 242 QString timeText = QString("%1").arg(rt.toText(true).c_str());
Chris@0 243 QString valueText = QString("%1").arg(points.begin()->value);
Chris@0 244
Chris@0 245 int timewidth = metrics.width(timeText);
Chris@0 246 int valuewidth = metrics.width(valueText);
Chris@0 247 int labelwidth = metrics.width(points.begin()->label);
Chris@0 248
Chris@0 249 int boxheight = metrics.height() * 3 + 4;
Chris@0 250 int boxwidth = std::max(std::max(timewidth, labelwidth), valuewidth);
Chris@0 251
Chris@0 252 paint.drawRect(xbase, ybase, boxwidth + 10,
Chris@0 253 boxheight + 10 - metrics.descent() + 1);
Chris@0 254
Chris@0 255 paint.drawText(xbase + 5, ybase + 5 + metrics.ascent(), timeText);
Chris@0 256 paint.drawText(xbase + 5, ybase + 7 + metrics.ascent() + metrics.height(),
Chris@0 257 valueText);
Chris@0 258 paint.drawText(xbase + 5, ybase + 9 + metrics.ascent() + 2*metrics.height(),
Chris@0 259 points.begin()->label);
Chris@0 260 }
Chris@0 261
Chris@0 262 void
Chris@0 263 TimeValueLayer::paint(QPainter &paint, QRect rect) const
Chris@0 264 {
Chris@0 265 if (!m_model || !m_model->isOK()) return;
Chris@0 266
Chris@0 267 int sampleRate = m_model->getSampleRate();
Chris@0 268 if (!sampleRate) return;
Chris@0 269
Chris@0 270 // Profiler profiler("TimeValueLayer::paint", true);
Chris@0 271
Chris@0 272 long startFrame = m_view->getStartFrame();
Chris@0 273 int zoomLevel = m_view->getZoomLevel();
Chris@0 274
Chris@0 275 int x0 = rect.left(), x1 = rect.right();
Chris@0 276 long frame0 = startFrame + x0 * zoomLevel;
Chris@0 277 long frame1 = startFrame + x1 * zoomLevel;
Chris@0 278
Chris@0 279 SparseTimeValueModel::PointList points(m_model->getPoints
Chris@0 280 (frame0, frame1));
Chris@0 281
Chris@0 282 paint.setPen(m_colour);
Chris@0 283
Chris@0 284 QColor brushColour(m_colour);
Chris@0 285 brushColour.setAlpha(80);
Chris@0 286 paint.setBrush(brushColour);
Chris@0 287
Chris@0 288 // std::cerr << "TimeValueLayer::paint: resolution is "
Chris@0 289 // << m_model->getResolution() << " frames" << std::endl;
Chris@0 290
Chris@0 291 float min = m_model->getValueMinimum();
Chris@0 292 float max = m_model->getValueMaximum();
Chris@0 293 if (max == min) max = min + 1.0;
Chris@0 294
Chris@0 295 int origin = int(nearbyint(m_view->height() -
Chris@0 296 (-min * m_view->height()) / (max - min)));
Chris@0 297
Chris@0 298 QPoint localPos;
Chris@0 299 long illuminateFrame = -1;
Chris@0 300
Chris@0 301 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@0 302 SparseTimeValueModel::PointList localPoints =
Chris@0 303 getLocalPoints(localPos.x());
Chris@0 304 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
Chris@0 305 }
Chris@0 306
Chris@0 307 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@0 308 i != points.end(); ++i) {
Chris@0 309
Chris@0 310 const SparseTimeValueModel::Point &p(*i);
Chris@0 311
Chris@0 312 int x = (p.frame - startFrame) / zoomLevel;
Chris@0 313 int y = int(nearbyint(m_view->height() -
Chris@0 314 ((p.value - min) * m_view->height()) /
Chris@0 315 (max - min)));
Chris@0 316 int w = m_model->getResolution() / zoomLevel;
Chris@0 317
Chris@0 318 if (w < 1) w = 1;
Chris@0 319
Chris@0 320 paint.setPen(m_colour);
Chris@0 321 paint.setBrush(brushColour);
Chris@0 322
Chris@0 323 if (m_plotStyle == PlotStems) {
Chris@0 324 paint.setPen(brushColour);
Chris@0 325 if (y < origin - 1) {
Chris@0 326 paint.drawRect(x + w/2, y + 1, 1, origin - y);
Chris@0 327 } else if (y > origin + 1) {
Chris@0 328 paint.drawRect(x + w/2, origin, 1, y - origin - 1);
Chris@0 329 }
Chris@0 330 paint.setPen(m_colour);
Chris@0 331 }
Chris@0 332
Chris@0 333 if (illuminateFrame == p.frame) {
Chris@0 334 //!!! aside from the problem of choosing a colour, it'd be
Chris@0 335 //better to save the highlighted rects and draw them at
Chris@0 336 //the end perhaps
Chris@0 337 paint.setPen(Qt::black);//!!!
Chris@0 338 paint.setBrush(Qt::black);//!!!
Chris@0 339 }
Chris@0 340
Chris@0 341 paint.drawRect(x, y - 1, w, 2);
Chris@0 342
Chris@0 343 // if (w > 1) {
Chris@0 344 // paint.setPen(brushColour);
Chris@0 345 // paint.drawRect(x, y - 1, w - 1, 2);
Chris@0 346 // paint.setPen(m_colour);
Chris@0 347 // }
Chris@0 348 // paint.drawLine(x, 0, x, m_view->height());
Chris@0 349
Chris@0 350 if (m_plotStyle == PlotLines) {
Chris@0 351
Chris@0 352 paint.setPen(brushColour);
Chris@0 353 SparseTimeValueModel::PointList::const_iterator j = i;
Chris@0 354 ++j;
Chris@0 355 if (j != points.end()) {
Chris@0 356 const SparseTimeValueModel::Point &q(*j);
Chris@0 357 int nx = (q.frame - startFrame) / zoomLevel;
Chris@0 358 int ny = int(nearbyint(m_view->height() -
Chris@0 359 ((q.value - min) * m_view->height()) /
Chris@0 360 (max - min)));
Chris@0 361 paint.drawLine(x + w, y, nx, ny);
Chris@0 362 }
Chris@0 363 }
Chris@0 364
Chris@0 365
Chris@0 366 /// if (p.label != "") {
Chris@0 367 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
Chris@0 368 /// }
Chris@0 369 }
Chris@0 370
Chris@0 371
Chris@0 372 }
Chris@0 373
Chris@0 374
Chris@0 375 #ifdef INCLUDE_MOCFILES
Chris@0 376 #include "TimeValueLayer.moc.cpp"
Chris@0 377 #endif
Chris@0 378