annotate widgets/WindowShapePreview.cpp @ 1160:a429b2acb45d 3.0-integration

Make SVDEBUG always write to a log file -- formerly this was disabled in NDEBUG builds. I think there's little use to that, it just means that we keep adding more cerr debug output because we aren't getting the log we need. And SVDEBUG logging is not usually used in tight loops, I don't think the performance overhead is too serious. Also update the About box.
author Chris Cannam
date Thu, 03 Nov 2016 14:57:00 +0000
parents e6c798c9bc91
children 6796afa25c88
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@202 25 #include "data/fft/FFTapi.h"
Chris@139 26
Chris@139 27 #include <iostream>
Chris@139 28
Chris@545 29
Chris@139 30 WindowShapePreview::WindowShapePreview(QWidget *parent) :
Chris@139 31 QFrame(parent),
Chris@908 32 m_windowType(HanningWindow)
Chris@139 33 {
Chris@139 34 QHBoxLayout *layout = new QHBoxLayout;
Chris@139 35 layout->setMargin(0);
Chris@139 36 setLayout(layout);
Chris@139 37 m_windowTimeExampleLabel = new QLabel;
Chris@139 38 m_windowFreqExampleLabel = new QLabel;
Chris@139 39 layout->addWidget(m_windowTimeExampleLabel);
Chris@139 40 layout->addWidget(m_windowFreqExampleLabel);
Chris@139 41 }
Chris@139 42
Chris@139 43 WindowShapePreview::~WindowShapePreview()
Chris@139 44 {
Chris@139 45 }
Chris@139 46
Chris@139 47 void
Chris@139 48 WindowShapePreview::updateLabels()
Chris@139 49 {
Chris@1157 50 float scaleRatio = float(QFontMetrics(font()).height()) / 14.f;
Chris@1154 51 if (scaleRatio < 1.f) scaleRatio = 1.f;
Chris@1154 52
Chris@1154 53 int step = int(24 * scaleRatio);
Chris@1157 54 float peak = float(48 * scaleRatio);
Chris@1154 55
Chris@1157 56 int w = step * 4, h = int((peak * 4) / 3);
Chris@1154 57
Chris@139 58 WindowType type = m_windowType;
Chris@139 59 Window<float> windower = Window<float>(type, step * 2);
Chris@1154 60
Chris@139 61 QPixmap timeLabel(w, h + 1);
Chris@139 62 timeLabel.fill(Qt::white);
Chris@139 63 QPainter timePainter(&timeLabel);
Chris@139 64
Chris@139 65 QPainterPath path;
Chris@139 66
Chris@908 67 path.moveTo(0, float(h) - peak + 1);
Chris@908 68 path.lineTo(w, float(h) - peak + 1);
Chris@139 69
Chris@139 70 timePainter.setPen(Qt::gray);
Chris@139 71 timePainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 72 timePainter.drawPath(path);
Chris@139 73
Chris@139 74 path = QPainterPath();
Chris@139 75
Chris@1153 76 float *acc = new float[w];
Chris@139 77 for (int i = 0; i < w; ++i) acc[i] = 0.f;
Chris@139 78 for (int j = 0; j < 3; ++j) {
Chris@139 79 for (int i = 0; i < step * 2; ++i) {
Chris@139 80 acc[j * step + i] += windower.getValue(i);
Chris@139 81 }
Chris@139 82 }
Chris@139 83 for (int i = 0; i < w; ++i) {
Chris@908 84 int y = h - int(peak * acc[i] + 0.001f) + 1;
Chris@139 85 if (i == 0) path.moveTo(i, y);
Chris@139 86 else path.lineTo(i, y);
Chris@139 87 }
Chris@1150 88 delete[] acc;
Chris@139 89
Chris@139 90 timePainter.drawPath(path);
Chris@139 91 timePainter.setRenderHint(QPainter::Antialiasing, false);
Chris@139 92
Chris@139 93 path = QPainterPath();
Chris@139 94
Chris@139 95 timePainter.setPen(Qt::black);
Chris@139 96
Chris@139 97 for (int i = 0; i < step * 2; ++i) {
Chris@139 98 int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
Chris@139 99 if (i == 0) path.moveTo(i + step, float(y));
Chris@139 100 else path.lineTo(i + step, float(y));
Chris@139 101 }
Chris@139 102
Chris@139 103 if (type == RectangularWindow) {
Chris@139 104 timePainter.drawPath(path);
Chris@139 105 path = QPainterPath();
Chris@139 106 }
Chris@139 107
Chris@139 108 timePainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 109 path.addRect(0, 0, w, h + 1);
Chris@139 110 timePainter.drawPath(path);
Chris@139 111
Chris@139 112 QFont font;
Chris@1154 113 font.setPixelSize(int(10 * scaleRatio));
Chris@139 114 font.setItalic(true);
Chris@139 115 timePainter.setFont(font);
Chris@139 116 QString label = tr("V / time");
Chris@139 117 timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
Chris@139 118 timePainter.fontMetrics().ascent() + 1, label);
Chris@139 119
Chris@139 120 m_windowTimeExampleLabel->setPixmap(timeLabel);
Chris@139 121
Chris@1154 122 QPixmap freqLabel(w, h + 1);
Chris@139 123 freqLabel.fill(Qt::white);
Chris@139 124 QPainter freqPainter(&freqLabel);
Chris@139 125 path = QPainterPath();
Chris@139 126
Chris@139 127 int fftsize = 512;
Chris@139 128
Chris@202 129 float *input = (float *)fftf_malloc(fftsize * sizeof(float));
Chris@202 130 fftf_complex *output =
Chris@202 131 (fftf_complex *)fftf_malloc(fftsize * sizeof(fftf_complex));
Chris@202 132 fftf_plan plan = fftf_plan_dft_r2c_1d(fftsize, input, output,
Chris@139 133 FFTW_ESTIMATE);
Chris@139 134 for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
Chris@139 135 for (int i = 0; i < step * 2; ++i) {
Chris@139 136 input[fftsize/2 - step + i] = windower.getValue(i);
Chris@139 137 }
Chris@139 138
Chris@202 139 fftf_execute(plan);
Chris@202 140 fftf_destroy_plan(plan);
Chris@139 141
Chris@139 142 float maxdb = 0.f;
Chris@139 143 float mindb = 0.f;
Chris@139 144 bool first = true;
Chris@139 145 for (int i = 0; i < fftsize/2; ++i) {
Chris@139 146 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
Chris@139 147 float db = mindb;
Chris@139 148 if (power > 0) {
Chris@908 149 db = 20.f * log10f(power);
Chris@139 150 if (first || db > maxdb) maxdb = db;
Chris@139 151 if (first || db < mindb) mindb = db;
Chris@139 152 first = false;
Chris@139 153 }
Chris@139 154 }
Chris@139 155
Chris@139 156 if (mindb > -80.f) mindb = -80.f;
Chris@139 157
Chris@139 158 // -- no, don't use the actual mindb -- it's easier to compare
Chris@139 159 // plots with a fixed min value
Chris@139 160 mindb = -170.f;
Chris@139 161
Chris@139 162 float maxval = maxdb + -mindb;
Chris@139 163
Chris@139 164 // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
Chris@139 165
Chris@908 166 path.moveTo(0, float(h) - peak + 1);
Chris@1154 167 path.lineTo(w, float(h) - peak + 1);
Chris@139 168
Chris@139 169 freqPainter.setPen(Qt::gray);
Chris@139 170 freqPainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 171 freqPainter.drawPath(path);
Chris@139 172
Chris@139 173 path = QPainterPath();
Chris@139 174 freqPainter.setPen(Qt::black);
Chris@139 175
Chris@682 176 // cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << endl;
Chris@139 177
Chris@139 178 for (int i = 0; i < fftsize/2; ++i) {
Chris@139 179 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
Chris@908 180 float db = 20.f * log10f(power);
Chris@139 181 float val = db + -mindb;
Chris@139 182 if (val < 0) val = 0;
Chris@139 183 float norm = val / maxval;
Chris@1154 184 float x = (float(w) / float(fftsize/2)) * float(i);
Chris@908 185 float y = float(h) - norm * peak + 1;
Chris@139 186 if (i == 0) path.moveTo(x, y);
Chris@139 187 else path.lineTo(x, y);
Chris@139 188 }
Chris@139 189
Chris@139 190 freqPainter.setRenderHint(QPainter::Antialiasing, true);
Chris@1154 191 path.addRect(0, 0, w, h + 1);
Chris@139 192 freqPainter.drawPath(path);
Chris@139 193
Chris@202 194 fftf_free(input);
Chris@202 195 fftf_free(output);
Chris@139 196
Chris@139 197 freqPainter.setFont(font);
Chris@139 198 label = tr("dB / freq");
Chris@1154 199 freqPainter.drawText(w - freqPainter.fontMetrics().width(label) - 4,
Chris@139 200 freqPainter.fontMetrics().ascent() + 1, label);
Chris@139 201
Chris@139 202 m_windowFreqExampleLabel->setPixmap(freqLabel);
Chris@139 203 }
Chris@139 204
Chris@139 205 void
Chris@139 206 WindowShapePreview::setWindowType(WindowType type)
Chris@139 207 {
Chris@139 208 m_windowType = type;
Chris@139 209 updateLabels();
Chris@139 210 }
Chris@139 211