annotate layer/TimeRulerLayer.cpp @ 162:f32212631b9c

* Handle generator transforms (plugins whose channel count isn't dependent on number of audio inputs, as they have none) * Be less keen to suspend writing FFT data in spectrogram repaint -- only do it if we find we actually need to query the FFT data (i.e. we aren't repainting an area that hasn't been generated at all yet)
author Chris Cannam
date Tue, 10 Oct 2006 19:04:57 +0000
parents 33929e0c3c6b
children 6969f21da18a
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@59 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "TimeRulerLayer.h"
Chris@0 17
Chris@128 18 #include "data/model/Model.h"
Chris@0 19 #include "base/RealTime.h"
Chris@128 20 #include "view/View.h"
Chris@0 21
Chris@0 22 #include <QPainter>
Chris@0 23
Chris@0 24 #include <iostream>
Chris@0 25
Chris@0 26 using std::cerr;
Chris@0 27 using std::endl;
Chris@0 28
Chris@44 29 TimeRulerLayer::TimeRulerLayer() :
Chris@44 30 Layer(),
Chris@0 31 m_model(0),
Chris@0 32 m_colour(Qt::black),
Chris@0 33 m_labelHeight(LabelTop)
Chris@0 34 {
Chris@44 35
Chris@0 36 }
Chris@0 37
Chris@0 38 void
Chris@0 39 TimeRulerLayer::setModel(Model *model)
Chris@0 40 {
Chris@0 41 if (m_model == model) return;
Chris@0 42 m_model = model;
Chris@0 43 emit modelReplaced();
Chris@0 44 }
Chris@0 45
Chris@0 46 void
Chris@0 47 TimeRulerLayer::setBaseColour(QColor colour)
Chris@0 48 {
Chris@0 49 if (m_colour == colour) return;
Chris@0 50 m_colour = colour;
Chris@0 51 emit layerParametersChanged();
Chris@0 52 }
Chris@0 53
Chris@0 54 Layer::PropertyList
Chris@0 55 TimeRulerLayer::getProperties() const
Chris@0 56 {
Chris@0 57 PropertyList list;
Chris@87 58 list.push_back("Colour");
Chris@0 59 return list;
Chris@0 60 }
Chris@0 61
Chris@87 62 QString
Chris@87 63 TimeRulerLayer::getPropertyLabel(const PropertyName &name) const
Chris@87 64 {
Chris@87 65 if (name == "Colour") return tr("Colour");
Chris@87 66 return "";
Chris@87 67 }
Chris@87 68
Chris@0 69 Layer::PropertyType
Chris@0 70 TimeRulerLayer::getPropertyType(const PropertyName &name) const
Chris@0 71 {
Chris@0 72 return ValueProperty;
Chris@0 73 }
Chris@0 74
Chris@0 75 int
Chris@0 76 TimeRulerLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@0 77 int *min, int *max) const
Chris@0 78 {
Chris@0 79 int deft = 0;
Chris@0 80
Chris@87 81 if (name == "Colour") {
Chris@0 82
Chris@10 83 if (min) *min = 0;
Chris@10 84 if (max) *max = 5;
Chris@0 85
Chris@0 86 if (m_colour == Qt::black) deft = 0;
Chris@0 87 else if (m_colour == Qt::darkRed) deft = 1;
Chris@0 88 else if (m_colour == Qt::darkBlue) deft = 2;
Chris@0 89 else if (m_colour == Qt::darkGreen) deft = 3;
Chris@0 90 else if (m_colour == QColor(200, 50, 255)) deft = 4;
Chris@0 91 else if (m_colour == QColor(255, 150, 50)) deft = 5;
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 TimeRulerLayer::getPropertyValueLabel(const PropertyName &name,
Chris@0 103 int value) const
Chris@0 104 {
Chris@87 105 if (name == "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 }
Chris@0 116 return tr("<unknown>");
Chris@0 117 }
Chris@0 118
Chris@0 119 void
Chris@0 120 TimeRulerLayer::setProperty(const PropertyName &name, int value)
Chris@0 121 {
Chris@87 122 if (name == "Colour") {
Chris@0 123 switch (value) {
Chris@0 124 default:
Chris@0 125 case 0: setBaseColour(Qt::black); break;
Chris@0 126 case 1: setBaseColour(Qt::darkRed); break;
Chris@0 127 case 2: setBaseColour(Qt::darkBlue); break;
Chris@0 128 case 3: setBaseColour(Qt::darkGreen); break;
Chris@0 129 case 4: setBaseColour(QColor(200, 50, 255)); break;
Chris@0 130 case 5: setBaseColour(QColor(255, 150, 50)); break;
Chris@0 131 }
Chris@0 132 }
Chris@0 133 }
Chris@0 134
Chris@0 135 void
Chris@44 136 TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@0 137 {
Chris@0 138 // std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y()
Chris@0 139 // << ") [" << rect.width() << "x" << rect.height() << "]" << std::endl;
Chris@0 140
Chris@0 141 if (!m_model || !m_model->isOK()) return;
Chris@0 142
Chris@0 143 int sampleRate = m_model->getSampleRate();
Chris@0 144 if (!sampleRate) return;
Chris@0 145
Chris@44 146 long startFrame = v->getStartFrame();
Chris@44 147 long endFrame = v->getEndFrame();
Chris@0 148
Chris@44 149 int zoomLevel = v->getZoomLevel();
Chris@0 150
Chris@0 151 long rectStart = startFrame + (rect.x() - 100) * zoomLevel;
Chris@0 152 long rectEnd = startFrame + (rect.x() + rect.width() + 100) * zoomLevel;
Chris@55 153 // if (rectStart < startFrame) rectStart = startFrame;
Chris@55 154 // if (rectEnd > endFrame) rectEnd = endFrame;
Chris@0 155
Chris@0 156 // std::cerr << "TimeRulerLayer::paint: calling paint.save()" << std::endl;
Chris@0 157 paint.save();
Chris@44 158 //!!! paint.setClipRect(v->rect());
Chris@0 159
Chris@0 160 int minPixelSpacing = 50;
Chris@0 161
Chris@0 162 RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate);
Chris@0 163 RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate);
Chris@44 164 // cerr << "startFrame " << startFrame << ", endFrame " << v->getEndFrame() << ", rtStart " << rtStart << ", rtEnd " << rtEnd << endl;
Chris@44 165 int count = v->width() / minPixelSpacing;
Chris@0 166 if (count < 1) count = 1;
Chris@0 167 RealTime rtGap = (rtEnd - rtStart) / count;
Chris@0 168 // cerr << "rtGap is " << rtGap << endl;
Chris@0 169
Chris@0 170 int incms;
Chris@0 171 bool quarter = false;
Chris@0 172
Chris@0 173 if (rtGap.sec > 0) {
Chris@0 174 incms = 1000;
Chris@0 175 int s = rtGap.sec;
Chris@0 176 if (s > 0) { incms *= 5; s /= 5; }
Chris@0 177 if (s > 0) { incms *= 2; s /= 2; }
Chris@0 178 if (s > 0) { incms *= 6; s /= 6; quarter = true; }
Chris@0 179 if (s > 0) { incms *= 5; s /= 5; quarter = false; }
Chris@0 180 if (s > 0) { incms *= 2; s /= 2; }
Chris@0 181 if (s > 0) { incms *= 6; s /= 6; quarter = true; }
Chris@0 182 while (s > 0) {
Chris@0 183 incms *= 10;
Chris@0 184 s /= 10;
Chris@0 185 quarter = false;
Chris@0 186 }
Chris@0 187 } else {
Chris@0 188 incms = 1;
Chris@0 189 int ms = rtGap.msec();
Chris@0 190 if (ms > 0) { incms *= 10; ms /= 10; }
Chris@0 191 if (ms > 0) { incms *= 10; ms /= 10; }
Chris@0 192 if (ms > 0) { incms *= 5; ms /= 5; }
Chris@0 193 if (ms > 0) { incms *= 2; ms /= 2; }
Chris@0 194 }
Chris@0 195 // cerr << "incms is " << incms << endl;
Chris@0 196
Chris@0 197 RealTime rt = RealTime::frame2RealTime(rectStart, sampleRate);
Chris@0 198 long ms = rt.sec * 1000 + rt.msec();
Chris@0 199 ms = (ms / incms) * incms - incms;
Chris@0 200
Chris@30 201 RealTime incRt = RealTime::fromMilliseconds(incms);
Chris@0 202 long incFrame = RealTime::realTime2Frame(incRt, sampleRate);
Chris@0 203 int incX = incFrame / zoomLevel;
Chris@0 204 int ticks = 10;
Chris@0 205 if (incX < minPixelSpacing * 2) {
Chris@0 206 ticks = quarter ? 4 : 5;
Chris@0 207 }
Chris@0 208
Chris@0 209 QRect oldClipRect = rect;
Chris@0 210 QRect newClipRect(oldClipRect.x() - 25, oldClipRect.y(),
Chris@0 211 oldClipRect.width() + 50, oldClipRect.height());
Chris@0 212 paint.setClipRect(newClipRect);
Chris@55 213 paint.setClipRect(rect);
Chris@0 214
Chris@0 215 QColor greyColour(m_colour);
Chris@0 216 if (m_colour == Qt::black) {
Chris@0 217 greyColour = QColor(200,200,200);
Chris@0 218 } else {
Chris@0 219 greyColour = m_colour.light(150);
Chris@0 220 }
Chris@0 221
Chris@0 222 while (1) {
Chris@0 223
Chris@30 224 rt = RealTime::fromMilliseconds(ms);
Chris@0 225 ms += incms;
Chris@0 226
Chris@0 227 long frame = RealTime::realTime2Frame(rt, sampleRate);
Chris@0 228 if (frame >= rectEnd) break;
Chris@0 229
Chris@0 230 int x = (frame - startFrame) / zoomLevel;
Chris@0 231 if (x < rect.x() || x >= rect.x() + rect.width()) continue;
Chris@0 232
Chris@0 233 paint.setPen(greyColour);
Chris@44 234 paint.drawLine(x, 0, x, v->height());
Chris@0 235
Chris@0 236 paint.setPen(m_colour);
Chris@0 237 paint.drawLine(x, 0, x, 5);
Chris@44 238 paint.drawLine(x, v->height() - 6, x, v->height() - 1);
Chris@0 239
Chris@0 240 QString text(QString::fromStdString(rt.toText()));
Chris@0 241
Chris@0 242 int y;
Chris@0 243 QFontMetrics metrics = paint.fontMetrics();
Chris@0 244 switch (m_labelHeight) {
Chris@0 245 default:
Chris@0 246 case LabelTop:
Chris@0 247 y = 6 + metrics.ascent();
Chris@0 248 break;
Chris@0 249 case LabelMiddle:
Chris@44 250 y = v->height() / 2 - metrics.height() / 2 + metrics.ascent();
Chris@0 251 break;
Chris@0 252 case LabelBottom:
Chris@44 253 y = v->height() - metrics.height() + metrics.ascent() - 6;
Chris@0 254 }
Chris@0 255
Chris@0 256 int tw = metrics.width(text);
Chris@0 257
Chris@70 258 if (v->getViewManager() && v->getViewManager()->getOverlayMode() !=
Chris@70 259 ViewManager::NoOverlays) {
Chris@70 260
Chris@70 261 if (v->getLayer(0) == this) {
Chris@70 262 // backmost layer, don't worry about outlining the text
Chris@70 263 paint.drawText(x+2 - tw/2, y, text);
Chris@70 264 } else {
Chris@70 265 v->drawVisibleText(paint, x+2 - tw/2, y, text, View::OutlinedText);
Chris@70 266 }
Chris@70 267 }
Chris@0 268
Chris@0 269 paint.setPen(greyColour);
Chris@0 270
Chris@0 271 for (int i = 1; i < ticks; ++i) {
Chris@0 272 rt = rt + (incRt / ticks);
Chris@0 273 frame = RealTime::realTime2Frame(rt, sampleRate);
Chris@0 274 x = (frame - startFrame) / zoomLevel;
Chris@0 275 int sz = 5;
Chris@0 276 if (ticks == 10) {
Chris@0 277 if ((i % 2) == 1) {
Chris@0 278 if (i == 5) {
Chris@44 279 paint.drawLine(x, 0, x, v->height());
Chris@0 280 } else sz = 3;
Chris@0 281 } else {
Chris@0 282 sz = 7;
Chris@0 283 }
Chris@0 284 }
Chris@0 285 paint.drawLine(x, 0, x, sz);
Chris@44 286 paint.drawLine(x, v->height() - sz - 1, x, v->height() - 1);
Chris@0 287 }
Chris@0 288 }
Chris@0 289
Chris@0 290 paint.restore();
Chris@0 291 }
Chris@0 292
Chris@6 293 QString
Chris@6 294 TimeRulerLayer::toXmlString(QString indent, QString extraAttributes) const
Chris@6 295 {
Chris@6 296 return Layer::toXmlString(indent, extraAttributes +
Chris@6 297 QString(" colour=\"%1\"").arg(encodeColour(m_colour)));
Chris@6 298 }
Chris@6 299
Chris@11 300 void
Chris@11 301 TimeRulerLayer::setProperties(const QXmlAttributes &attributes)
Chris@11 302 {
Chris@11 303 QString colourSpec = attributes.value("colour");
Chris@11 304 if (colourSpec != "") {
Chris@11 305 QColor colour(colourSpec);
Chris@11 306 if (colour.isValid()) {
Chris@11 307 setBaseColour(QColor(colourSpec));
Chris@11 308 }
Chris@11 309 }
Chris@11 310 }
Chris@11 311
Chris@0 312
Chris@0 313 #ifdef INCLUDE_MOCFILES
Chris@0 314 #include "TimeRulerLayer.moc.cpp"
Chris@0 315 #endif
Chris@0 316