annotate widgets/WindowShapePreview.cpp @ 202:cec1f78fbfca

* Add non-fftw3 fft alternative
author Chris Cannam
date Fri, 09 Feb 2007 11:32:34 +0000
parents 5ec6b60658d8
children be5c35d3f409
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@139 29 WindowShapePreview::WindowShapePreview(QWidget *parent) :
Chris@139 30 QFrame(parent),
Chris@139 31 m_windowType(WindowType(999))
Chris@139 32 {
Chris@139 33 QHBoxLayout *layout = new QHBoxLayout;
Chris@139 34 layout->setMargin(0);
Chris@139 35 setLayout(layout);
Chris@139 36 m_windowTimeExampleLabel = new QLabel;
Chris@139 37 m_windowFreqExampleLabel = new QLabel;
Chris@139 38 layout->addWidget(m_windowTimeExampleLabel);
Chris@139 39 layout->addWidget(m_windowFreqExampleLabel);
Chris@139 40 }
Chris@139 41
Chris@139 42 WindowShapePreview::~WindowShapePreview()
Chris@139 43 {
Chris@139 44 }
Chris@139 45
Chris@139 46 void
Chris@139 47 WindowShapePreview::updateLabels()
Chris@139 48 {
Chris@139 49 int step = 24;
Chris@139 50 int peak = 48;
Chris@139 51 int w = step * 4, h = 64;
Chris@139 52 WindowType type = m_windowType;
Chris@139 53 Window<float> windower = Window<float>(type, step * 2);
Chris@139 54
Chris@139 55 QPixmap timeLabel(w, h + 1);
Chris@139 56 timeLabel.fill(Qt::white);
Chris@139 57 QPainter timePainter(&timeLabel);
Chris@139 58
Chris@139 59 QPainterPath path;
Chris@139 60
Chris@139 61 path.moveTo(0, h - peak + 1);
Chris@139 62 path.lineTo(w, h - peak + 1);
Chris@139 63
Chris@139 64 timePainter.setPen(Qt::gray);
Chris@139 65 timePainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 66 timePainter.drawPath(path);
Chris@139 67
Chris@139 68 path = QPainterPath();
Chris@139 69
Chris@139 70 float acc[w];
Chris@139 71 for (int i = 0; i < w; ++i) acc[i] = 0.f;
Chris@139 72 for (int j = 0; j < 3; ++j) {
Chris@139 73 for (int i = 0; i < step * 2; ++i) {
Chris@139 74 acc[j * step + i] += windower.getValue(i);
Chris@139 75 }
Chris@139 76 }
Chris@139 77 for (int i = 0; i < w; ++i) {
Chris@139 78 int y = h - int(peak * acc[i] + 0.001) + 1;
Chris@139 79 if (i == 0) path.moveTo(i, y);
Chris@139 80 else path.lineTo(i, y);
Chris@139 81 }
Chris@139 82
Chris@139 83 timePainter.drawPath(path);
Chris@139 84 timePainter.setRenderHint(QPainter::Antialiasing, false);
Chris@139 85
Chris@139 86 path = QPainterPath();
Chris@139 87
Chris@139 88 timePainter.setPen(Qt::black);
Chris@139 89
Chris@139 90 for (int i = 0; i < step * 2; ++i) {
Chris@139 91 int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
Chris@139 92 if (i == 0) path.moveTo(i + step, float(y));
Chris@139 93 else path.lineTo(i + step, float(y));
Chris@139 94 }
Chris@139 95
Chris@139 96 if (type == RectangularWindow) {
Chris@139 97 timePainter.drawPath(path);
Chris@139 98 path = QPainterPath();
Chris@139 99 }
Chris@139 100
Chris@139 101 timePainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 102 path.addRect(0, 0, w, h + 1);
Chris@139 103 timePainter.drawPath(path);
Chris@139 104
Chris@139 105 QFont font;
Chris@139 106 font.setPixelSize(10);
Chris@139 107 font.setItalic(true);
Chris@139 108 timePainter.setFont(font);
Chris@139 109 QString label = tr("V / time");
Chris@139 110 timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
Chris@139 111 timePainter.fontMetrics().ascent() + 1, label);
Chris@139 112
Chris@139 113 m_windowTimeExampleLabel->setPixmap(timeLabel);
Chris@139 114
Chris@139 115 int fw = 100;
Chris@139 116
Chris@139 117 QPixmap freqLabel(fw, h + 1);
Chris@139 118 freqLabel.fill(Qt::white);
Chris@139 119 QPainter freqPainter(&freqLabel);
Chris@139 120 path = QPainterPath();
Chris@139 121
Chris@139 122 int fftsize = 512;
Chris@139 123
Chris@202 124 float *input = (float *)fftf_malloc(fftsize * sizeof(float));
Chris@202 125 fftf_complex *output =
Chris@202 126 (fftf_complex *)fftf_malloc(fftsize * sizeof(fftf_complex));
Chris@202 127 fftf_plan plan = fftf_plan_dft_r2c_1d(fftsize, input, output,
Chris@139 128 FFTW_ESTIMATE);
Chris@139 129 for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
Chris@139 130 for (int i = 0; i < step * 2; ++i) {
Chris@139 131 input[fftsize/2 - step + i] = windower.getValue(i);
Chris@139 132 }
Chris@139 133
Chris@202 134 fftf_execute(plan);
Chris@202 135 fftf_destroy_plan(plan);
Chris@139 136
Chris@139 137 float maxdb = 0.f;
Chris@139 138 float mindb = 0.f;
Chris@139 139 bool first = true;
Chris@139 140 for (int i = 0; i < fftsize/2; ++i) {
Chris@139 141 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
Chris@139 142 float db = mindb;
Chris@139 143 if (power > 0) {
Chris@139 144 db = 20 * log10(power);
Chris@139 145 if (first || db > maxdb) maxdb = db;
Chris@139 146 if (first || db < mindb) mindb = db;
Chris@139 147 first = false;
Chris@139 148 }
Chris@139 149 }
Chris@139 150
Chris@139 151 if (mindb > -80.f) mindb = -80.f;
Chris@139 152
Chris@139 153 // -- no, don't use the actual mindb -- it's easier to compare
Chris@139 154 // plots with a fixed min value
Chris@139 155 mindb = -170.f;
Chris@139 156
Chris@139 157 float maxval = maxdb + -mindb;
Chris@139 158
Chris@139 159 // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
Chris@139 160
Chris@139 161 path.moveTo(0, h - peak + 1);
Chris@139 162 path.lineTo(fw, h - peak + 1);
Chris@139 163
Chris@139 164 freqPainter.setPen(Qt::gray);
Chris@139 165 freqPainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 166 freqPainter.drawPath(path);
Chris@139 167
Chris@139 168 path = QPainterPath();
Chris@139 169 freqPainter.setPen(Qt::black);
Chris@139 170
Chris@139 171 // std::cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << std::endl;
Chris@139 172
Chris@139 173 for (int i = 0; i < fftsize/2; ++i) {
Chris@139 174 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
Chris@139 175 float db = 20 * log10(power);
Chris@139 176 float val = db + -mindb;
Chris@139 177 if (val < 0) val = 0;
Chris@139 178 float norm = val / maxval;
Chris@139 179 float x = (fw / float(fftsize/2)) * i;
Chris@139 180 float y = h - norm * peak + 1;
Chris@139 181 if (i == 0) path.moveTo(x, y);
Chris@139 182 else path.lineTo(x, y);
Chris@139 183 }
Chris@139 184
Chris@139 185 freqPainter.setRenderHint(QPainter::Antialiasing, true);
Chris@139 186 path.addRect(0, 0, fw, h + 1);
Chris@139 187 freqPainter.drawPath(path);
Chris@139 188
Chris@202 189 fftf_free(input);
Chris@202 190 fftf_free(output);
Chris@139 191
Chris@139 192 freqPainter.setFont(font);
Chris@139 193 label = tr("dB / freq");
Chris@139 194 freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4,
Chris@139 195 freqPainter.fontMetrics().ascent() + 1, label);
Chris@139 196
Chris@139 197 m_windowFreqExampleLabel->setPixmap(freqLabel);
Chris@139 198 }
Chris@139 199
Chris@139 200 void
Chris@139 201 WindowShapePreview::setWindowType(WindowType type)
Chris@139 202 {
Chris@139 203 if (m_windowType == type) return;
Chris@139 204 m_windowType = type;
Chris@139 205 updateLabels();
Chris@139 206 }
Chris@139 207