annotate view/Overview.cpp @ 1127:9fb8dfd7ce4c spectrogram-minor-refactor

Fix threshold in spectrogram -- it wasn't working in the last release. There is a new protocol for this. Formerly the threshold parameter had a range from -50dB to 0 with the default at -50, and -50 treated internally as "no threshold". However, there was a hardcoded, hidden internal threshold for spectrogram colour mapping at -80dB with anything below this being rounded to zero. Now the threshold parameter has range -81 to -1 with the default at -80, -81 is treated internally as "no threshold", and there is no hidden internal threshold. So the default behaviour is the same as before, an effective -80dB threshold, but it is now possible to change this in both directions. Sessions reloaded from prior versions may look slightly different because, if the session says there should be no threshold, there will now actually be no threshold instead of having the hidden internal one. Still need to do something in the UI to make it apparent that the -81dB setting removes the threshold entirely. This is at least no worse than the previous, also obscured, magic -50dB setting.
author Chris Cannam
date Mon, 01 Aug 2016 16:21:01 +0100
parents 73b0dc7d6ec1
children 57d192e26331 97d0c798c2ac
rev   line source
Chris@173 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@173 2
Chris@173 3 /*
Chris@173 4 Sonic Visualiser
Chris@173 5 An audio file viewer and annotation editor.
Chris@173 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@173 8
Chris@173 9 This program is free software; you can redistribute it and/or
Chris@173 10 modify it under the terms of the GNU General Public License as
Chris@173 11 published by the Free Software Foundation; either version 2 of the
Chris@173 12 License, or (at your option) any later version. See the file
Chris@173 13 COPYING included with this distribution for more information.
Chris@173 14 */
Chris@173 15
Chris@173 16 #include "Overview.h"
Chris@173 17 #include "layer/Layer.h"
Chris@173 18 #include "data/model/Model.h"
Chris@173 19 #include "base/ZoomConstraint.h"
Chris@173 20
Chris@173 21 #include <QPaintEvent>
Chris@173 22 #include <QPainter>
Chris@173 23 #include <iostream>
Chris@173 24
Chris@643 25 //#define DEBUG_OVERVIEW 1
Chris@642 26
Chris@682 27
Chris@173 28 Overview::Overview(QWidget *w) :
Chris@173 29 View(w, false),
Chris@854 30 m_clickedInRange(false),
Chris@854 31 m_dragCentreFrame(0)
Chris@173 32 {
Chris@173 33 setObjectName(tr("Overview"));
Chris@173 34 m_followPan = false;
Chris@173 35 m_followZoom = false;
Chris@211 36 setPlaybackFollow(PlaybackIgnore);
Chris@274 37 m_modelTestTime.start();
Chris@965 38
Chris@965 39 bool light = hasLightBackground();
Chris@965 40 if (light) m_boxColour = Qt::darkGray;
Chris@965 41 else m_boxColour = Qt::lightGray;
Chris@173 42 }
Chris@173 43
Chris@173 44 void
Chris@908 45 Overview::modelChangedWithin(sv_frame_t startFrame, sv_frame_t endFrame)
Chris@173 46 {
Chris@253 47 bool zoomChanged = false;
Chris@253 48
Chris@908 49 sv_frame_t frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@908 50 int zoomLevel = int(frameCount / width());
Chris@253 51 if (zoomLevel < 1) zoomLevel = 1;
Chris@253 52 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@253 53 ZoomConstraint::RoundUp);
Chris@253 54 if (zoomLevel != m_zoomLevel) {
Chris@253 55 zoomChanged = true;
Chris@253 56 }
Chris@253 57
Chris@253 58 if (!zoomChanged) {
Chris@274 59 if (m_modelTestTime.elapsed() < 1000) {
Chris@835 60 for (LayerList::const_iterator i = m_layerStack.begin();
Chris@835 61 i != m_layerStack.end(); ++i) {
Chris@274 62 if ((*i)->getModel() &&
Chris@389 63 (!(*i)->getModel()->isOK() ||
Chris@389 64 !(*i)->getModel()->isReady())) {
Chris@274 65 return;
Chris@274 66 }
Chris@253 67 }
Chris@274 68 } else {
Chris@274 69 m_modelTestTime.restart();
Chris@253 70 }
Chris@253 71 }
Chris@253 72
Chris@806 73 View::modelChangedWithin(startFrame, endFrame);
Chris@173 74 }
Chris@173 75
Chris@173 76 void
Chris@173 77 Overview::modelReplaced()
Chris@173 78 {
Chris@339 79 m_playPointerFrame = getAlignedPlaybackFrame();
Chris@173 80 View::modelReplaced();
Chris@173 81 }
Chris@173 82
Chris@173 83 void
Chris@211 84 Overview::registerView(View *view)
Chris@173 85 {
Chris@211 86 m_views.insert(view);
Chris@173 87 update();
Chris@173 88 }
Chris@173 89
Chris@173 90 void
Chris@211 91 Overview::unregisterView(View *view)
Chris@173 92 {
Chris@211 93 m_views.erase(view);
Chris@173 94 update();
Chris@173 95 }
Chris@173 96
Chris@173 97 void
Chris@908 98 Overview::globalCentreFrameChanged(sv_frame_t
Chris@806 99 #ifdef DEBUG_OVERVIEW
Chris@806 100 f
Chris@806 101 #endif
Chris@806 102 )
Chris@173 103 {
Chris@642 104 #ifdef DEBUG_OVERVIEW
Chris@682 105 cerr << "Overview::globalCentreFrameChanged: " << f << endl;
Chris@642 106 #endif
Chris@211 107 update();
Chris@211 108 }
Chris@173 109
Chris@211 110 void
Chris@908 111 Overview::viewCentreFrameChanged(View *v, sv_frame_t
Chris@806 112 #ifdef DEBUG_OVERVIEW
Chris@806 113 f
Chris@806 114 #endif
Chris@806 115 )
Chris@211 116 {
Chris@642 117 #ifdef DEBUG_OVERVIEW
Chris@682 118 cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
Chris@642 119 #endif
Chris@211 120 if (m_views.find(v) != m_views.end()) {
Chris@173 121 update();
Chris@173 122 }
Chris@211 123 }
Chris@173 124
Chris@173 125 void
Chris@806 126 Overview::viewZoomLevelChanged(View *v, int, bool)
Chris@173 127 {
Chris@222 128 if (v == this) return;
Chris@211 129 if (m_views.find(v) != m_views.end()) {
Chris@173 130 update();
Chris@173 131 }
Chris@173 132 }
Chris@173 133
Chris@173 134 void
Chris@908 135 Overview::viewManagerPlaybackFrameChanged(sv_frame_t f)
Chris@173 136 {
Chris@642 137 #ifdef DEBUG_OVERVIEW
Chris@682 138 cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
Chris@642 139 #endif
Chris@642 140
Chris@173 141 bool changed = false;
Chris@173 142
Chris@339 143 f = getAlignedPlaybackFrame();
Chris@339 144
Chris@173 145 if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
Chris@173 146 m_playPointerFrame = f;
Chris@173 147
Chris@173 148 if (changed) update();
Chris@173 149 }
Chris@173 150
Chris@871 151 QColor
Chris@871 152 Overview::getFillWithin() const
Chris@871 153 {
Chris@871 154 return Qt::transparent;
Chris@871 155 }
Chris@871 156
Chris@871 157 QColor
Chris@871 158 Overview::getFillWithout() const
Chris@871 159 {
Chris@871 160 QColor c = palette().window().color();
Chris@871 161 c.setAlpha(100);
Chris@871 162 return c;
Chris@871 163 }
Chris@871 164
Chris@173 165 void
Chris@965 166 Overview::setBoxColour(QColor c)
Chris@965 167 {
Chris@965 168 m_boxColour = c;
Chris@965 169 }
Chris@965 170
Chris@965 171 void
Chris@173 172 Overview::paintEvent(QPaintEvent *e)
Chris@173 173 {
Chris@173 174 // Recalculate zoom in case the size of the widget has changed.
Chris@173 175
Chris@642 176 #ifdef DEBUG_OVERVIEW
Chris@682 177 cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
Chris@642 178 #endif
Chris@214 179
Chris@908 180 sv_frame_t startFrame = getModelsStartFrame();
Chris@908 181 sv_frame_t frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@908 182 int zoomLevel = int(frameCount / width());
Chris@173 183 if (zoomLevel < 1) zoomLevel = 1;
Chris@173 184 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@173 185 ZoomConstraint::RoundUp);
Chris@173 186 if (zoomLevel != m_zoomLevel) {
Chris@173 187 m_zoomLevel = zoomLevel;
Chris@222 188 emit zoomLevelChanged(m_zoomLevel, m_followZoom);
Chris@173 189 }
Chris@253 190
Chris@908 191 sv_frame_t centreFrame = startFrame + m_zoomLevel * (width() / 2);
Chris@173 192 if (centreFrame > (startFrame + getModelsEndFrame())/2) {
Chris@173 193 centreFrame = (startFrame + getModelsEndFrame())/2;
Chris@173 194 }
Chris@173 195 if (centreFrame != m_centreFrame) {
Chris@642 196 #ifdef DEBUG_OVERVIEW
Chris@682 197 cerr << "Overview::paintEvent: Centre frame changed from "
Chris@642 198 << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
Chris@642 199 #endif
Chris@173 200 m_centreFrame = centreFrame;
Chris@642 201 #ifdef DEBUG_OVERVIEW
Chris@682 202 cerr << " to " << getStartFrame() << endl;
Chris@642 203 #endif
Chris@211 204 emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore);
Chris@173 205 }
Chris@173 206
Chris@173 207 View::paintEvent(e);
Chris@173 208
Chris@173 209 QPainter paint;
Chris@173 210 paint.begin(this);
Chris@871 211 paint.setClipRegion(e->region());
Chris@871 212 paint.setRenderHints(QPainter::Antialiasing);
Chris@871 213
Chris@173 214 QRect r(rect());
Chris@173 215
Chris@871 216 // We paint a rounded rect for each distinct set of view extents,
Chris@871 217 // and we colour in the inside and outside of the rect that
Chris@871 218 // corresponds to the current view. (One small caveat -- we don't
Chris@871 219 // know which rect that is yet. We'll have to figure it out
Chris@871 220 // somehow...)
Chris@173 221
Chris@871 222 std::set<std::pair<int, int> > extents;
Chris@871 223 std::vector<QRect> rects;
Chris@871 224 QRect primary;
Chris@173 225
Chris@173 226 int y = 0;
Chris@173 227
Chris@211 228 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@173 229 if (!*i) continue;
Chris@173 230
Chris@173 231 View *w = (View *)*i;
Chris@173 232
Chris@908 233 sv_frame_t f0 = w->getFrameForX(0);
Chris@908 234 sv_frame_t f1 = w->getFrameForX(w->width());
Chris@173 235
Chris@339 236 if (f0 >= 0) {
Chris@908 237 sv_frame_t rf0 = w->alignToReference(f0);
Chris@339 238 f0 = alignFromReference(rf0);
Chris@339 239 }
Chris@339 240 if (f1 >= 0) {
Chris@908 241 sv_frame_t rf1 = w->alignToReference(f1);
Chris@339 242 f1 = alignFromReference(rf1);
Chris@339 243 }
Chris@339 244
Chris@173 245 int x0 = getXForFrame(f0);
Chris@173 246 int x1 = getXForFrame(f1);
Chris@173 247
matthiasm@935 248
Chris@871 249 if (x1 <= x0) x1 = x0 + 1;
Chris@871 250
Chris@871 251 std::pair<int, int> extent(x0, x1);
Chris@871 252
Chris@871 253 if (extents.find(extent) == extents.end()) {
Chris@871 254
matthiasm@935 255 y += height() / 10 + 1;
Chris@871 256 extents.insert(extent);
Chris@173 257
Chris@871 258 QRect vr(x0, y, x1 - x0, height() - 2 * y);
Chris@871 259 rects.push_back(vr);
Chris@871 260 primary = vr; //!!! for now
Chris@871 261 }
Chris@871 262 }
Chris@871 263
Chris@871 264 QPainterPath without;
matthiasm@935 265 without.addRoundedRect(primary, 4, 4);
Chris@871 266 without.addRect(rect());
Chris@871 267 paint.setPen(Qt::NoPen);
Chris@871 268 paint.setBrush(getFillWithout());
Chris@871 269 paint.drawPath(without);
Chris@871 270
Chris@871 271 paint.setBrush(getFillWithin());
matthiasm@935 272 paint.drawRoundedRect(primary, 4, 4);
Chris@871 273
Chris@871 274 foreach (QRect vr, rects) {
Chris@871 275 paint.setBrush(Qt::NoBrush);
Chris@965 276 paint.setPen(QPen(m_boxColour, 2));
matthiasm@935 277 paint.drawRoundedRect(vr, 4, 4);
Chris@173 278 }
Chris@173 279
Chris@173 280 paint.end();
Chris@173 281 }
Chris@173 282
Chris@173 283 void
Chris@173 284 Overview::mousePressEvent(QMouseEvent *e)
Chris@173 285 {
Chris@173 286 m_clickPos = e->pos();
Chris@908 287 sv_frame_t clickFrame = getFrameForX(m_clickPos.x());
Chris@339 288 if (clickFrame > 0) m_dragCentreFrame = clickFrame;
Chris@339 289 else m_dragCentreFrame = 0;
Chris@339 290 m_clickedInRange = true;
Chris@339 291
Chris@211 292 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@339 293 if (*i && (*i)->getAligningModel() == getAligningModel()) {
Chris@339 294 m_dragCentreFrame = (*i)->getCentreFrame();
Chris@339 295 break;
Chris@339 296 }
Chris@173 297 }
Chris@173 298 }
Chris@173 299
Chris@173 300 void
Chris@173 301 Overview::mouseReleaseEvent(QMouseEvent *e)
Chris@173 302 {
Chris@173 303 if (m_clickedInRange) {
Chris@173 304 mouseMoveEvent(e);
Chris@173 305 }
Chris@173 306 m_clickedInRange = false;
Chris@173 307 }
Chris@173 308
Chris@173 309 void
Chris@173 310 Overview::mouseMoveEvent(QMouseEvent *e)
Chris@173 311 {
Chris@173 312 if (!m_clickedInRange) return;
Chris@173 313
Chris@806 314 int xoff = int(e->x()) - int(m_clickPos.x());
Chris@908 315 sv_frame_t frameOff = xoff * m_zoomLevel;
Chris@173 316
Chris@908 317 sv_frame_t newCentreFrame = m_dragCentreFrame;
Chris@173 318 if (frameOff > 0) {
Chris@173 319 newCentreFrame += frameOff;
Chris@908 320 } else if (newCentreFrame >= -frameOff) {
Chris@173 321 newCentreFrame += frameOff;
Chris@173 322 } else {
Chris@173 323 newCentreFrame = 0;
Chris@173 324 }
Chris@173 325
Chris@173 326 if (newCentreFrame >= getModelsEndFrame()) {
Chris@173 327 newCentreFrame = getModelsEndFrame();
Chris@173 328 if (newCentreFrame > 0) --newCentreFrame;
Chris@173 329 }
Chris@173 330
Chris@173 331 if (std::max(m_centreFrame, newCentreFrame) -
Chris@908 332 std::min(m_centreFrame, newCentreFrame) > m_zoomLevel) {
Chris@908 333 sv_frame_t rf = alignToReference(newCentreFrame);
Chris@643 334 #ifdef DEBUG_OVERVIEW
Chris@682 335 cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
Chris@643 336 #endif
Chris@817 337 if (m_followPlay == PlaybackScrollContinuous ||
Chris@817 338 m_followPlay == PlaybackScrollPageWithCentre) {
Chris@817 339 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@817 340 } else {
Chris@817 341 emit centreFrameChanged(rf, true, PlaybackIgnore);
Chris@817 342 }
Chris@173 343 }
Chris@173 344 }
Chris@173 345
Chris@189 346 void
Chris@189 347 Overview::mouseDoubleClickEvent(QMouseEvent *e)
Chris@189 348 {
Chris@908 349 sv_frame_t frame = getFrameForX(e->x());
Chris@908 350 sv_frame_t rf = 0;
Chris@339 351 if (frame > 0) rf = alignToReference(frame);
Chris@643 352 #ifdef DEBUG_OVERVIEW
Chris@682 353 cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
Chris@643 354 #endif
Chris@643 355 m_clickedInRange = false; // we're not starting a drag with the second click
Chris@339 356 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@189 357 }
Chris@173 358
Chris@189 359 void
Chris@189 360 Overview::enterEvent(QEvent *)
Chris@189 361 {
Chris@189 362 emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
Chris@189 363 }
Chris@189 364
Chris@189 365 void
Chris@189 366 Overview::leaveEvent(QEvent *)
Chris@189 367 {
Chris@189 368 emit contextHelpChanged("");
Chris@189 369 }
Chris@189 370
Chris@189 371