annotate layer/Colour3DPlotLayer.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 37b110168acf
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 "Colour3DPlotLayer.h"
Chris@0 11
Chris@0 12 #include "base/View.h"
Chris@0 13 #include "base/Profiler.h"
Chris@0 14
Chris@0 15 #include <QPainter>
Chris@0 16 #include <QImage>
Chris@0 17 #include <QRect>
Chris@0 18
Chris@0 19 #include <iostream>
Chris@0 20
Chris@0 21 #include <cassert>
Chris@0 22
Chris@0 23
Chris@0 24 Colour3DPlotLayer::Colour3DPlotLayer(View *w) :
Chris@0 25 Layer(w),
Chris@0 26 m_model(0),
Chris@0 27 m_cache(0)
Chris@0 28 {
Chris@0 29 m_view->addLayer(this);
Chris@0 30 }
Chris@0 31
Chris@0 32 Colour3DPlotLayer::~Colour3DPlotLayer()
Chris@0 33 {
Chris@0 34 }
Chris@0 35
Chris@0 36 void
Chris@0 37 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
Chris@0 38 {
Chris@0 39 m_model = model;
Chris@0 40 if (!m_model || !m_model->isOK()) return;
Chris@0 41
Chris@0 42 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@0 43 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 44 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@0 45
Chris@0 46 connect(m_model, SIGNAL(completionChanged()),
Chris@0 47 this, SIGNAL(modelCompletionChanged()));
Chris@0 48
Chris@0 49 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid()));
Chris@0 50 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 51 this, SLOT(cacheInvalid(size_t, size_t)));
Chris@0 52
Chris@0 53 emit modelReplaced();
Chris@0 54 }
Chris@0 55
Chris@0 56 void
Chris@0 57 Colour3DPlotLayer::cacheInvalid()
Chris@0 58 {
Chris@0 59 delete m_cache;
Chris@0 60 m_cache = 0;
Chris@0 61 }
Chris@0 62
Chris@0 63 void
Chris@0 64 Colour3DPlotLayer::cacheInvalid(size_t, size_t)
Chris@0 65 {
Chris@0 66 cacheInvalid();
Chris@0 67 }
Chris@0 68
Chris@0 69 void
Chris@0 70 Colour3DPlotLayer::paint(QPainter &paint, QRect rect) const
Chris@0 71 {
Chris@0 72 // Profiler profiler("Colour3DPlotLayer::paint");
Chris@0 73 // std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << m_view->getZoomLevel() << std::endl;
Chris@0 74
Chris@0 75 //!!! This doesn't yet accommodate the fact that the model may
Chris@0 76 //have a different sample rate from an underlying model. At the
Chris@0 77 //moment our paint mechanism assumes all models have the same
Chris@0 78 //sample rate. If that isn't the case, they won't align and the
Chris@0 79 //time ruler will match whichever model was used to construct it.
Chris@0 80 //Obviously it is not going to be the case in general that models
Chris@0 81 //will have the same samplerate, so we need a pane samplerate as
Chris@0 82 //well which we trivially realign to. (We can probably require
Chris@0 83 //the waveform and spectrogram layers to display at the pane
Chris@0 84 //samplerate.)
Chris@0 85
Chris@0 86 int completion = 0;
Chris@0 87 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
Chris@0 88 if (completion > 0) {
Chris@0 89 paint.fillRect(0, 10, m_view->width() * completion / 100,
Chris@0 90 10, QColor(120, 120, 120));
Chris@0 91 }
Chris@0 92 return;
Chris@0 93 }
Chris@0 94
Chris@0 95 long startFrame = m_view->getStartFrame();
Chris@0 96 int zoomLevel = m_view->getZoomLevel();
Chris@0 97
Chris@0 98 size_t modelStart = m_model->getStartFrame();
Chris@0 99 size_t modelEnd = m_model->getEndFrame();
Chris@0 100 size_t modelWindow = m_model->getWindowSize();
Chris@0 101
Chris@0 102 if (!m_cache) {
Chris@0 103
Chris@0 104 m_cache = new QImage((modelEnd - modelStart) / modelWindow + 1,
Chris@0 105 m_model->getYBinCount(),
Chris@0 106 QImage::Format_Indexed8);
Chris@0 107
Chris@0 108 m_cache->setNumColors(256);
Chris@0 109 DenseThreeDimensionalModel::BinValueSet values;
Chris@0 110 /*
Chris@0 111 for (int pixel = 0; pixel < 256; ++pixel) {
Chris@0 112 int hue = 256 - pixel;
Chris@0 113 // int hue = 220 - pixel;
Chris@0 114 // if (hue < 0) hue += 360;
Chris@0 115 QColor color = QColor::fromHsv(hue, pixel/2 + 128, pixel);
Chris@0 116 m_cache->setColor(pixel, qRgb(color.red(), color.green(), color.blue()));
Chris@0 117 }
Chris@0 118 */
Chris@0 119
Chris@0 120 float min = m_model->getMinimumLevel();
Chris@0 121 float max = m_model->getMaximumLevel();
Chris@0 122
Chris@0 123 if (max == min) max = min + 1.0;
Chris@0 124
Chris@0 125 // int min = lrintf(m_model->getMinimumLevel());
Chris@0 126 // int max = lrintf(m_model->getMaximumLevel());
Chris@0 127 for (int value = 0; value < 256; ++value) {
Chris@0 128 // int spread = ((value - min) * 256) / (max - min);
Chris@0 129 // int hue = 256 - spread;
Chris@0 130 // QColor color = QColor::fromHsv(hue, spread/2 + 128, spread);
Chris@0 131 int hue = 256 - value;
Chris@0 132 QColor color = QColor::fromHsv(hue, value/2 + 128, value);
Chris@0 133 m_cache->setColor(value, qRgba(color.red(), color.green(), color.blue(), 80));
Chris@0 134 // std::cerr << "Colour3DPlotLayer: Index " << value << ": hue " << hue << std::endl;
Chris@0 135 }
Chris@0 136
Chris@0 137 m_cache->fill(min);
Chris@0 138
Chris@0 139 for (size_t f = modelStart; f <= modelEnd; f += modelWindow) {
Chris@0 140
Chris@0 141 values.clear();
Chris@0 142 m_model->getBinValues(f, values);
Chris@0 143
Chris@0 144 for (size_t y = 0; y < m_model->getYBinCount(); ++y) {
Chris@0 145
Chris@0 146 float value = min;
Chris@0 147 if (y < values.size()) value = values[y];
Chris@0 148
Chris@0 149 //!!! divide-by-zero!
Chris@0 150 int pixel = int(((value - min) * 256) / (max - min));
Chris@0 151
Chris@0 152 m_cache->setPixel(f / modelWindow, y, pixel);
Chris@0 153 }
Chris@0 154 }
Chris@0 155 }
Chris@0 156
Chris@0 157 int x0 = rect.left();
Chris@0 158 int x1 = rect.right() + 1;
Chris@0 159
Chris@0 160 // int y0 = rect.top();
Chris@0 161 // int y1 = rect.bottom();
Chris@0 162 int w = x1 - x0;
Chris@0 163 int h = m_view->height();
Chris@0 164
Chris@0 165 // The cache is from the model's start frame to the model's end
Chris@0 166 // frame at the model's window increment frames per pixel. We
Chris@0 167 // want to draw from our start frame + x0 * zoomLevel to our start
Chris@0 168 // frame + x1 * zoomLevel at zoomLevel frames per pixel.
Chris@0 169
Chris@0 170 //!!! Strictly speaking we want quite different paint mechanisms
Chris@0 171 //for models that have more than one bin per pixel in either
Chris@0 172 //direction. This one is only really appropriate for models with
Chris@0 173 //far fewer bins in both directions.
Chris@0 174
Chris@0 175 int sx0 = ((startFrame + x0 * zoomLevel) - int(modelStart)) /
Chris@0 176 int(modelWindow);
Chris@0 177 int sx1 = ((startFrame + x1 * zoomLevel) - int(modelStart)) /
Chris@0 178 int(modelWindow);
Chris@0 179 int sw = sx1 - sx0;
Chris@0 180 int sh = m_model->getYBinCount();
Chris@0 181
Chris@0 182 /*
Chris@0 183 std::cerr << "Colour3DPlotLayer::paint: w " << w << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sw << ", sh " << sh << std::endl;
Chris@0 184 std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", window size " << m_model->getWindowSize() << std::endl;
Chris@0 185 */
Chris@0 186
Chris@0 187 for (int sx = sx0 - 1; sx <= sx1; ++sx) {
Chris@0 188
Chris@0 189 int fx = sx * int(modelWindow);
Chris@0 190
Chris@0 191 if (fx + modelWindow < int(modelStart) ||
Chris@0 192 fx > int(modelEnd)) continue;
Chris@0 193
Chris@0 194 for (int sy = 0; sy < sh; ++sy) {
Chris@0 195
Chris@0 196 int rx0 = ((fx + int(modelStart))
Chris@0 197 - int(startFrame)) / zoomLevel;
Chris@0 198 int rx1 = ((fx + int(modelWindow) + int(modelStart))
Chris@0 199 - int(startFrame)) / zoomLevel;
Chris@0 200
Chris@0 201 int ry0 = h - (sy * h) / sh - 1;
Chris@0 202 int ry1 = h - ((sy + 1) * h) / sh - 2;
Chris@0 203 QRgb pixel = qRgb(255, 255, 255);
Chris@0 204 if (sx >= 0 && sx < m_cache->width() &&
Chris@0 205 sy >= 0 && sy < m_cache->height()) {
Chris@0 206 pixel = m_cache->pixel(sx, sy);
Chris@0 207 }
Chris@0 208
Chris@0 209 QColor pen(255, 255, 255, 80);
Chris@0 210 // QColor pen(pixel);
Chris@0 211 QColor brush(pixel);
Chris@0 212 brush.setAlpha(160);
Chris@0 213 // paint.setPen(pen);
Chris@0 214 paint.setPen(Qt::NoPen);
Chris@0 215 paint.setBrush(brush);
Chris@0 216
Chris@0 217 int w = rx1 - rx0;
Chris@0 218 if (w < 1) w = 1;
Chris@0 219 paint.drawRect(rx0, ry0 - h / sh - 1, w, h / sh + 1);
Chris@0 220
Chris@0 221 if (sx >= 0 && sx < m_cache->width() &&
Chris@0 222 sy >= 0 && sy < m_cache->height()) {
Chris@0 223 int dv = m_cache->pixelIndex(sx, sy);
Chris@0 224 if (dv != 0 && paint.fontMetrics().height() < (h / sh)) {
Chris@0 225 QString text = QString("%1").arg(dv);
Chris@0 226 if (paint.fontMetrics().width(text) < w - 3) {
Chris@0 227 paint.setPen(Qt::white);
Chris@0 228 paint.drawText(rx0 + 2,
Chris@0 229 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
Chris@0 230 QString("%1").arg(dv));
Chris@0 231 }
Chris@0 232 }
Chris@0 233 }
Chris@0 234 }
Chris@0 235 }
Chris@0 236
Chris@0 237 /*
Chris@0 238 QRect targetRect(x0, 0, w, h);
Chris@0 239 QRect sourceRect(sx0, 0, sw, sh);
Chris@0 240
Chris@0 241 QImage scaled(w, h, QImage::Format_RGB32);
Chris@0 242
Chris@0 243 for (int x = 0; x < w; ++x) {
Chris@0 244 for (int y = 0; y < h; ++y) {
Chris@0 245
Chris@0 246
Chris@0 247
Chris@0 248 int sx = sx0 + (x * sw) / w;
Chris@0 249 int sy = sh - (y * sh) / h - 1;
Chris@0 250 // std::cerr << "Colour3DPlotLayer::paint: sx " << sx << ", sy " << sy << ", cache w " << m_cache->width() << ", cache h " << m_cache->height() << std::endl;
Chris@0 251 if (sx >= 0 && sy >= 0 &&
Chris@0 252 sx < m_cache->width() && sy < m_cache->height()) {
Chris@0 253 scaled.setPixel(x, y, m_cache->pixel(sx, sy));
Chris@0 254 } else {
Chris@0 255 scaled.setPixel(x, y, qRgba(255, 255, 255, 80));
Chris@0 256 }
Chris@0 257 }
Chris@0 258 }
Chris@0 259
Chris@0 260 paint.drawImage(x0, 0, scaled);
Chris@0 261 */
Chris@0 262 }
Chris@0 263
Chris@0 264 #ifdef INCLUDE_MOCFILES
Chris@0 265 #include "Colour3DPlotLayer.moc.cpp"
Chris@0 266 #endif
Chris@0 267
Chris@0 268