annotate widgets/WindowShapePreview.cpp @ 1496:d09345e578a7

Separate out handling of alignment progress bar from the layer progress bars and fix tendency to have them hanging around even when alignment has completed
author Chris Cannam
date Wed, 14 Aug 2019 10:58:24 +0100
parents d39db4673676
children
rev   line source
Chris@139 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@139 2
Chris@139 3 /*
Chris@139 4 Sonic Visualiser
Chris@139 5 An audio file viewer and annotation editor.
Chris@139 6 Centre for Digital Music, Queen Mary, University of London.
Chris@139 7 This file copyright 2006 Chris Cannam.
Chris@139 8
Chris@139 9 This program is free software; you can redistribute it and/or
Chris@139 10 modify it under the terms of the GNU General Public License as
Chris@139 11 published by the Free Software Foundation; either version 2 of the
Chris@139 12 License, or (at your option) any later version. See the file
Chris@139 13 COPYING included with this distribution for more information.
Chris@139 14 */
Chris@139 15
Chris@139 16 #include "WindowShapePreview.h"
Chris@139 17
Chris@139 18 #include <QHBoxLayout>
Chris@139 19 #include <QLabel>
Chris@139 20 #include <QPainter>
Chris@139 21 #include <QPainterPath>
Chris@139 22 #include <QFont>
Chris@139 23 #include <QString>
Chris@139 24
Chris@1168 25 #include <bqfft/FFT.h>
Chris@139 26
Chris@1168 27 #include <vector>
Chris@1168 28 #include <complex>
Chris@139 29 #include <iostream>
Chris@139 30
Chris@1168 31 using namespace std;
Chris@1168 32
Chris@545 33
Chris@139 34 WindowShapePreview::WindowShapePreview(QWidget *parent) :
Chris@139 35 QFrame(parent),
Chris@908 36 m_windowType(HanningWindow)
Chris@139 37 {
Chris@139 38 QHBoxLayout *layout = new QHBoxLayout;
Chris@139 39 layout->setMargin(0);
Chris@139 40 setLayout(layout);
Chris@139 41 m_windowTimeExampleLabel = new QLabel;
Chris@139 42 m_windowFreqExampleLabel = new QLabel;
Chris@139 43 layout->addWidget(m_windowTimeExampleLabel);
Chris@139 44 layout->addWidget(m_windowFreqExampleLabel);
Chris@139 45 }
Chris@139 46
Chris@139 47 WindowShapePreview::~WindowShapePreview()
Chris@139 48 {
Chris@139 49 }
Chris@139 50
Chris@139 51 void
Chris@139 52 WindowShapePreview::updateLabels()
Chris@139 53 {
Chris@1157 54 float scaleRatio = float(QFontMetrics(font()).height()) / 14.f;
Chris@1154 55 if (scaleRatio < 1.f) scaleRatio = 1.f;
Chris@1154 56
Chris@1154 57 int step = int(24 * scaleRatio);
Chris@1157 58 float peak = float(48 * scaleRatio);
Chris@1154 59
Chris@1157 60 int w = step * 4, h = int((peak * 4) / 3);
Chris@1154 61
Chris@139 62 WindowType type = m_windowType;
Chris@139 63 Window<float> windower = Window<float>(type, step * 2);
Chris@1154 64
Chris@139 65 QPixmap timeLabel(w, h + 1);
Chris@139 66 timeLabel.fill(Qt::white);
Chris@139 67 QPainter timePainter(&timeLabel);
Chris@139 68
Chris@139 69 QPainterPath path;
Chris@139 70
Chris@908 71 path.moveTo(0, float(h) - peak + 1);
Chris@908 72 path.lineTo(w, float(h) - peak + 1);
Chris@139 73
Chris@139 74 timePainter.setPen(Qt::gray);
Chris@139 75 timePainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 76 timePainter.drawPath(path);
Chris@139 77
Chris@139 78 path = QPainterPath();
Chris@139 79
Chris@1153 80 float *acc = new float[w];
Chris@139 81 for (int i = 0; i < w; ++i) acc[i] = 0.f;
Chris@139 82 for (int j = 0; j < 3; ++j) {
Chris@139 83 for (int i = 0; i < step * 2; ++i) {
Chris@139 84 acc[j * step + i] += windower.getValue(i);
Chris@139 85 }
Chris@139 86 }
Chris@139 87 for (int i = 0; i < w; ++i) {
Chris@908 88 int y = h - int(peak * acc[i] + 0.001f) + 1;
Chris@139 89 if (i == 0) path.moveTo(i, y);
Chris@139 90 else path.lineTo(i, y);
Chris@139 91 }
Chris@1150 92 delete[] acc;
Chris@139 93
Chris@139 94 timePainter.drawPath(path);
Chris@139 95 timePainter.setRenderHint(QPainter::Antialiasing, false);
Chris@139 96
Chris@139 97 path = QPainterPath();
Chris@139 98
Chris@139 99 timePainter.setPen(Qt::black);
Chris@139 100
Chris@139 101 for (int i = 0; i < step * 2; ++i) {
Chris@139 102 int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
Chris@139 103 if (i == 0) path.moveTo(i + step, float(y));
Chris@139 104 else path.lineTo(i + step, float(y));
Chris@139 105 }
Chris@139 106
Chris@139 107 if (type == RectangularWindow) {
Chris@139 108 timePainter.drawPath(path);
Chris@139 109 path = QPainterPath();
Chris@139 110 }
Chris@139 111
Chris@139 112 timePainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 113 path.addRect(0, 0, w, h + 1);
Chris@139 114 timePainter.drawPath(path);
Chris@139 115
Chris@1478 116 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested
Chris@1478 117 // replacement (horizontalAdvance) was only added in Qt 5.11
Chris@1478 118 // which is too new for us
Chris@1478 119 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Chris@1478 120
Chris@139 121 QFont font;
Chris@1154 122 font.setPixelSize(int(10 * scaleRatio));
Chris@139 123 font.setItalic(true);
Chris@139 124 timePainter.setFont(font);
Chris@139 125 QString label = tr("V / time");
Chris@139 126 timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
Chris@139 127 timePainter.fontMetrics().ascent() + 1, label);
Chris@139 128
Chris@139 129 m_windowTimeExampleLabel->setPixmap(timeLabel);
Chris@139 130
Chris@1154 131 QPixmap freqLabel(w, h + 1);
Chris@139 132 freqLabel.fill(Qt::white);
Chris@139 133 QPainter freqPainter(&freqLabel);
Chris@139 134 path = QPainterPath();
Chris@139 135
Chris@139 136 int fftsize = 512;
Chris@139 137
Chris@1168 138 breakfastquay::FFT fft(fftsize);
Chris@1168 139
Chris@1168 140 vector<float> input(fftsize);
Chris@1168 141 vector<complex<float>> output(fftsize/2 + 1);
Chris@1168 142
Chris@139 143 for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
Chris@139 144 for (int i = 0; i < step * 2; ++i) {
Chris@139 145 input[fftsize/2 - step + i] = windower.getValue(i);
Chris@139 146 }
Chris@1168 147
Chris@1168 148 fft.forwardInterleaved(input.data(), reinterpret_cast<float *>(output.data()));
Chris@139 149
Chris@139 150 float maxdb = 0.f;
Chris@139 151 float mindb = 0.f;
Chris@139 152 bool first = true;
Chris@139 153 for (int i = 0; i < fftsize/2; ++i) {
Chris@1168 154 float power =
Chris@1168 155 output[i].real() * output[i].real() +
Chris@1168 156 output[i].imag() * output[i].imag();
Chris@139 157 float db = mindb;
Chris@139 158 if (power > 0) {
Chris@908 159 db = 20.f * log10f(power);
Chris@139 160 if (first || db > maxdb) maxdb = db;
Chris@139 161 if (first || db < mindb) mindb = db;
Chris@139 162 first = false;
Chris@139 163 }
Chris@139 164 }
Chris@139 165
Chris@139 166 if (mindb > -80.f) mindb = -80.f;
Chris@139 167
Chris@139 168 // -- no, don't use the actual mindb -- it's easier to compare
Chris@139 169 // plots with a fixed min value
Chris@139 170 mindb = -170.f;
Chris@139 171
Chris@139 172 float maxval = maxdb + -mindb;
Chris@139 173
Chris@139 174 // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
Chris@139 175
Chris@908 176 path.moveTo(0, float(h) - peak + 1);
Chris@1154 177 path.lineTo(w, float(h) - peak + 1);
Chris@139 178
Chris@139 179 freqPainter.setPen(Qt::gray);
Chris@139 180 freqPainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 181 freqPainter.drawPath(path);
Chris@139 182
Chris@139 183 path = QPainterPath();
Chris@139 184 freqPainter.setPen(Qt::black);
Chris@139 185
Chris@682 186 // cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << endl;
Chris@139 187
Chris@139 188 for (int i = 0; i < fftsize/2; ++i) {
Chris@1168 189 float power =
Chris@1168 190 output[i].real() * output[i].real() +
Chris@1168 191 output[i].imag() * output[i].imag();
Chris@908 192 float db = 20.f * log10f(power);
Chris@139 193 float val = db + -mindb;
Chris@139 194 if (val < 0) val = 0;
Chris@139 195 float norm = val / maxval;
Chris@1154 196 float x = (float(w) / float(fftsize/2)) * float(i);
Chris@908 197 float y = float(h) - norm * peak + 1;
Chris@139 198 if (i == 0) path.moveTo(x, y);
Chris@139 199 else path.lineTo(x, y);
Chris@139 200 }
Chris@139 201
Chris@139 202 freqPainter.setRenderHint(QPainter::Antialiasing, true);
Chris@1154 203 path.addRect(0, 0, w, h + 1);
Chris@139 204 freqPainter.drawPath(path);
Chris@139 205
Chris@139 206 freqPainter.setFont(font);
Chris@139 207 label = tr("dB / freq");
Chris@1154 208 freqPainter.drawText(w - freqPainter.fontMetrics().width(label) - 4,
Chris@139 209 freqPainter.fontMetrics().ascent() + 1, label);
Chris@139 210
Chris@139 211 m_windowFreqExampleLabel->setPixmap(freqLabel);
Chris@139 212 }
Chris@139 213
Chris@139 214 void
Chris@139 215 WindowShapePreview::setWindowType(WindowType type)
Chris@139 216 {
Chris@139 217 m_windowType = type;
Chris@139 218 updateLabels();
Chris@139 219 }
Chris@139 220