annotate layer/ScrollableImageCache.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 94370157b265
children c53ed1a6fcbd
rev   line source
Chris@1033 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1033 2
Chris@1033 3 /*
Chris@1033 4 Sonic Visualiser
Chris@1033 5 An audio file viewer and annotation editor.
Chris@1033 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1033 7
Chris@1033 8 This program is free software; you can redistribute it and/or
Chris@1033 9 modify it under the terms of the GNU General Public License as
Chris@1033 10 published by the Free Software Foundation; either version 2 of the
Chris@1033 11 License, or (at your option) any later version. See the file
Chris@1033 12 COPYING included with this distribution for more information.
Chris@1033 13 */
Chris@1033 14
Chris@1033 15 #include "ScrollableImageCache.h"
Chris@1033 16
Chris@1033 17 #include <iostream>
Chris@1033 18 using namespace std;
Chris@1033 19
Chris@1090 20 #define DEBUG_SCROLLABLE_IMAGE_CACHE 1
Chris@1033 21
Chris@1033 22 void
Chris@1113 23 ScrollableImageCache::scrollTo(const LayerGeometryProvider *v,
Chris@1113 24 sv_frame_t newStartFrame)
Chris@1033 25 {
Chris@1122 26 int dx = (v->getXForFrame(m_startFrame) -
Chris@1122 27 v->getXForFrame(newStartFrame));
Chris@1122 28
Chris@1122 29 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1122 30 cerr << "ScrollableImageCache::scrollTo: start frame " << m_startFrame
Chris@1122 31 << " -> " << newStartFrame << ", dx = " << dx << endl;
Chris@1122 32 #endif
Chris@1122 33
Chris@1079 34 if (m_startFrame == newStartFrame) {
Chris@1079 35 // haven't moved
Chris@1079 36 return;
Chris@1079 37 }
Chris@1033 38
Chris@1033 39 m_startFrame = newStartFrame;
Chris@1033 40
Chris@1033 41 if (!isValid()) {
Chris@1033 42 return;
Chris@1033 43 }
Chris@1033 44
Chris@1033 45 int w = m_image.width();
Chris@1033 46
Chris@1033 47 if (dx == 0) {
Chris@1118 48 // haven't moved visibly (even though start frame may have changed)
Chris@1033 49 return;
Chris@1033 50 }
Chris@1033 51
Chris@1033 52 if (dx <= -w || dx >= w) {
Chris@1033 53 // scrolled entirely off
Chris@1033 54 invalidate();
Chris@1033 55 return;
Chris@1033 56 }
Chris@1033 57
Chris@1033 58 // dx is in range, cache is scrollable
Chris@1033 59
Chris@1033 60 int dxp = dx;
Chris@1033 61 if (dxp < 0) dxp = -dxp;
Chris@1033 62
Chris@1033 63 int copylen = (w - dxp) * int(sizeof(QRgb));
Chris@1033 64 for (int y = 0; y < m_image.height(); ++y) {
Chris@1033 65 QRgb *line = (QRgb *)m_image.scanLine(y);
Chris@1033 66 if (dx < 0) {
Chris@1033 67 memmove(line, line + dxp, copylen);
Chris@1033 68 } else {
Chris@1033 69 memmove(line + dxp, line, copylen);
Chris@1033 70 }
Chris@1033 71 }
Chris@1033 72
Chris@1033 73 // update valid area
Chris@1033 74
Chris@1118 75 int px = m_validLeft;
Chris@1118 76 int pw = m_validWidth;
Chris@1033 77
Chris@1033 78 px += dx;
Chris@1033 79
Chris@1033 80 if (dx < 0) {
Chris@1033 81 // we scrolled left
Chris@1033 82 if (px < 0) {
Chris@1033 83 pw += px;
Chris@1033 84 px = 0;
Chris@1033 85 if (pw < 0) {
Chris@1033 86 pw = 0;
Chris@1033 87 }
Chris@1033 88 }
Chris@1033 89 } else {
Chris@1033 90 // we scrolled right
Chris@1033 91 if (px + pw > w) {
Chris@1033 92 pw = w - px;
Chris@1033 93 if (pw < 0) {
Chris@1033 94 pw = 0;
Chris@1033 95 }
Chris@1033 96 }
Chris@1033 97 }
Chris@1033 98
Chris@1118 99 m_validLeft = px;
Chris@1118 100 m_validWidth = pw;
Chris@1033 101 }
Chris@1033 102
Chris@1033 103 void
Chris@1033 104 ScrollableImageCache::adjustToTouchValidArea(int &left, int &width,
Chris@1033 105 bool &isLeftOfValidArea) const
Chris@1033 106 {
Chris@1036 107 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1036 108 cerr << "ScrollableImageCache::adjustToTouchValidArea: left " << left
Chris@1036 109 << ", width " << width << endl;
Chris@1118 110 cerr << "ScrollableImageCache: my left " << m_validLeft
Chris@1118 111 << ", width " << m_validWidth << " so right " << (m_validLeft + m_validWidth) << endl;
Chris@1036 112 #endif
Chris@1118 113 if (left < m_validLeft) {
Chris@1033 114 isLeftOfValidArea = true;
Chris@1118 115 if (left + width <= m_validLeft + m_validWidth) {
Chris@1118 116 width = m_validLeft - left;
Chris@1033 117 }
Chris@1036 118 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1036 119 cerr << "ScrollableImageCache: we're left of valid area, adjusted width to " << width << endl;
Chris@1036 120 #endif
Chris@1033 121 } else {
Chris@1033 122 isLeftOfValidArea = false;
Chris@1118 123 width = left + width - (m_validLeft + m_validWidth);
Chris@1118 124 left = m_validLeft + m_validWidth;
Chris@1033 125 if (width < 0) width = 0;
Chris@1036 126 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1036 127 cerr << "ScrollableImageCache: we're right of valid area, adjusted left to " << left << ", width to " << width << endl;
Chris@1036 128 #endif
Chris@1033 129 }
Chris@1033 130 }
Chris@1033 131
Chris@1033 132 void
Chris@1033 133 ScrollableImageCache::drawImage(int left,
Chris@1033 134 int width,
Chris@1033 135 QImage image,
Chris@1033 136 int imageLeft,
Chris@1033 137 int imageWidth)
Chris@1033 138 {
Chris@1033 139 if (image.height() != m_image.height()) {
Chris@1033 140 cerr << "ScrollableImageCache::drawImage: ERROR: Supplied image height "
Chris@1033 141 << image.height() << " does not match cache height "
Chris@1033 142 << m_image.height() << endl;
Chris@1033 143 throw std::logic_error("Image height must match cache height in ScrollableImageCache::drawImage");
Chris@1033 144 }
Chris@1033 145 if (left < 0 || width < 0 || left + width > m_image.width()) {
Chris@1033 146 cerr << "ScrollableImageCache::drawImage: ERROR: Target area (left = "
Chris@1040 147 << left << ", width = " << width << ", so right = " << left + width
Chris@1040 148 << ") out of bounds for cache of width " << m_image.width() << endl;
Chris@1033 149 throw std::logic_error("Target area out of bounds in ScrollableImageCache::drawImage");
Chris@1033 150 }
Chris@1033 151 if (imageLeft < 0 || imageWidth < 0 ||
Chris@1033 152 imageLeft + imageWidth > image.width()) {
Chris@1033 153 cerr << "ScrollableImageCache::drawImage: ERROR: Source area (left = "
Chris@1040 154 << imageLeft << ", width = " << imageWidth << ", so right = "
Chris@1040 155 << imageLeft + imageWidth << ") out of bounds for image of "
Chris@1033 156 << "width " << image.width() << endl;
Chris@1033 157 throw std::logic_error("Source area out of bounds in ScrollableImageCache::drawImage");
Chris@1033 158 }
Chris@1033 159
Chris@1033 160 QPainter painter(&m_image);
Chris@1033 161 painter.drawImage(QRect(left, 0, width, m_image.height()),
Chris@1033 162 image,
Chris@1033 163 QRect(imageLeft, 0, imageWidth, image.height()));
Chris@1033 164 painter.end();
Chris@1033 165
Chris@1033 166 if (!isValid()) {
Chris@1118 167 m_validLeft = left;
Chris@1118 168 m_validWidth = width;
Chris@1033 169 return;
Chris@1033 170 }
Chris@1033 171
Chris@1118 172 if (left < m_validLeft) {
Chris@1118 173 if (left + width > m_validLeft + m_validWidth) {
Chris@1033 174 // new image completely contains the old valid area --
Chris@1033 175 // use the new area as is
Chris@1118 176 m_validLeft = left;
Chris@1118 177 m_validWidth = width;
Chris@1118 178 } else if (left + width < m_validLeft) {
Chris@1033 179 // new image completely off left of old valid area --
Chris@1033 180 // we can't extend the valid area because the bit in
Chris@1033 181 // between is not valid, so must use the new area only
Chris@1118 182 m_validLeft = left;
Chris@1118 183 m_validWidth = width;
Chris@1033 184 } else {
Chris@1033 185 // new image overlaps old valid area on left side --
Chris@1033 186 // use new left edge, and extend width to existing
Chris@1033 187 // right edge
Chris@1118 188 m_validWidth = (m_validLeft + m_validWidth) - left;
Chris@1118 189 m_validLeft = left;
Chris@1033 190 }
Chris@1033 191 } else {
Chris@1118 192 if (left > m_validLeft + m_validWidth) {
Chris@1033 193 // new image completely off right of old valid area --
Chris@1033 194 // we can't extend the valid area because the bit in
Chris@1033 195 // between is not valid, so must use the new area only
Chris@1118 196 m_validLeft = left;
Chris@1118 197 m_validWidth = width;
Chris@1118 198 } else if (left + width > m_validLeft + m_validWidth) {
Chris@1033 199 // new image overlaps old valid area on right side --
Chris@1033 200 // use existing left edge, and extend width to new
Chris@1033 201 // right edge
Chris@1118 202 m_validWidth = (left + width) - m_validLeft;
Chris@1118 203 // (m_validLeft unchanged)
Chris@1033 204 } else {
Chris@1033 205 // new image completely contained within old valid
Chris@1033 206 // area -- leave the old area unchanged
Chris@1033 207 }
Chris@1033 208 }
Chris@1033 209 }
Chris@1033 210