svgui
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "WindowShapePreview.h" 00017 00018 #include <QHBoxLayout> 00019 #include <QLabel> 00020 #include <QPainter> 00021 #include <QPainterPath> 00022 #include <QFont> 00023 #include <QString> 00024 00025 #include "data/fft/FFTapi.h" 00026 00027 #include <iostream> 00028 00029 #ifndef __GNUC__ 00030 #include <alloca.h> 00031 #endif 00032 00033 WindowShapePreview::WindowShapePreview(QWidget *parent) : 00034 QFrame(parent), 00035 m_windowType(WindowType(999)) 00036 { 00037 QHBoxLayout *layout = new QHBoxLayout; 00038 layout->setMargin(0); 00039 setLayout(layout); 00040 m_windowTimeExampleLabel = new QLabel; 00041 m_windowFreqExampleLabel = new QLabel; 00042 layout->addWidget(m_windowTimeExampleLabel); 00043 layout->addWidget(m_windowFreqExampleLabel); 00044 } 00045 00046 WindowShapePreview::~WindowShapePreview() 00047 { 00048 } 00049 00050 void 00051 WindowShapePreview::updateLabels() 00052 { 00053 int step = 24; 00054 int peak = 48; 00055 int w = step * 4, h = 64; 00056 WindowType type = m_windowType; 00057 Window<float> windower = Window<float>(type, step * 2); 00058 00059 QPixmap timeLabel(w, h + 1); 00060 timeLabel.fill(Qt::white); 00061 QPainter timePainter(&timeLabel); 00062 00063 QPainterPath path; 00064 00065 path.moveTo(0, h - peak + 1); 00066 path.lineTo(w, h - peak + 1); 00067 00068 timePainter.setPen(Qt::gray); 00069 timePainter.setRenderHint(QPainter::Antialiasing, true); 00070 timePainter.drawPath(path); 00071 00072 path = QPainterPath(); 00073 00074 #ifdef __GNUC__ 00075 float acc[w]; 00076 #else 00077 float *acc = (float *)alloca(w * sizeof(float)); 00078 #endif 00079 00080 for (int i = 0; i < w; ++i) acc[i] = 0.f; 00081 for (int j = 0; j < 3; ++j) { 00082 for (int i = 0; i < step * 2; ++i) { 00083 acc[j * step + i] += windower.getValue(i); 00084 } 00085 } 00086 for (int i = 0; i < w; ++i) { 00087 int y = h - int(peak * acc[i] + 0.001) + 1; 00088 if (i == 0) path.moveTo(i, y); 00089 else path.lineTo(i, y); 00090 } 00091 00092 timePainter.drawPath(path); 00093 timePainter.setRenderHint(QPainter::Antialiasing, false); 00094 00095 path = QPainterPath(); 00096 00097 timePainter.setPen(Qt::black); 00098 00099 for (int i = 0; i < step * 2; ++i) { 00100 int y = h - int(peak * windower.getValue(i) + 0.001) + 1; 00101 if (i == 0) path.moveTo(i + step, float(y)); 00102 else path.lineTo(i + step, float(y)); 00103 } 00104 00105 if (type == RectangularWindow) { 00106 timePainter.drawPath(path); 00107 path = QPainterPath(); 00108 } 00109 00110 timePainter.setRenderHint(QPainter::Antialiasing, true); 00111 path.addRect(0, 0, w, h + 1); 00112 timePainter.drawPath(path); 00113 00114 QFont font; 00115 font.setPixelSize(10); 00116 font.setItalic(true); 00117 timePainter.setFont(font); 00118 QString label = tr("V / time"); 00119 timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4, 00120 timePainter.fontMetrics().ascent() + 1, label); 00121 00122 m_windowTimeExampleLabel->setPixmap(timeLabel); 00123 00124 int fw = 100; 00125 00126 QPixmap freqLabel(fw, h + 1); 00127 freqLabel.fill(Qt::white); 00128 QPainter freqPainter(&freqLabel); 00129 path = QPainterPath(); 00130 00131 int fftsize = 512; 00132 00133 float *input = (float *)fftf_malloc(fftsize * sizeof(float)); 00134 fftf_complex *output = 00135 (fftf_complex *)fftf_malloc(fftsize * sizeof(fftf_complex)); 00136 fftf_plan plan = fftf_plan_dft_r2c_1d(fftsize, input, output, 00137 FFTW_ESTIMATE); 00138 for (int i = 0; i < fftsize; ++i) input[i] = 0.f; 00139 for (int i = 0; i < step * 2; ++i) { 00140 input[fftsize/2 - step + i] = windower.getValue(i); 00141 } 00142 00143 fftf_execute(plan); 00144 fftf_destroy_plan(plan); 00145 00146 float maxdb = 0.f; 00147 float mindb = 0.f; 00148 bool first = true; 00149 for (int i = 0; i < fftsize/2; ++i) { 00150 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1]; 00151 float db = mindb; 00152 if (power > 0) { 00153 db = 20 * log10(power); 00154 if (first || db > maxdb) maxdb = db; 00155 if (first || db < mindb) mindb = db; 00156 first = false; 00157 } 00158 } 00159 00160 if (mindb > -80.f) mindb = -80.f; 00161 00162 // -- no, don't use the actual mindb -- it's easier to compare 00163 // plots with a fixed min value 00164 mindb = -170.f; 00165 00166 float maxval = maxdb + -mindb; 00167 00168 // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1; 00169 00170 path.moveTo(0, h - peak + 1); 00171 path.lineTo(fw, h - peak + 1); 00172 00173 freqPainter.setPen(Qt::gray); 00174 freqPainter.setRenderHint(QPainter::Antialiasing, true); 00175 freqPainter.drawPath(path); 00176 00177 path = QPainterPath(); 00178 freqPainter.setPen(Qt::black); 00179 00180 // cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << endl; 00181 00182 for (int i = 0; i < fftsize/2; ++i) { 00183 float power = output[i][0] * output[i][0] + output[i][1] * output[i][1]; 00184 float db = 20 * log10(power); 00185 float val = db + -mindb; 00186 if (val < 0) val = 0; 00187 float norm = val / maxval; 00188 float x = (fw / float(fftsize/2)) * i; 00189 float y = h - norm * peak + 1; 00190 if (i == 0) path.moveTo(x, y); 00191 else path.lineTo(x, y); 00192 } 00193 00194 freqPainter.setRenderHint(QPainter::Antialiasing, true); 00195 path.addRect(0, 0, fw, h + 1); 00196 freqPainter.drawPath(path); 00197 00198 fftf_free(input); 00199 fftf_free(output); 00200 00201 freqPainter.setFont(font); 00202 label = tr("dB / freq"); 00203 freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4, 00204 freqPainter.fontMetrics().ascent() + 1, label); 00205 00206 m_windowFreqExampleLabel->setPixmap(freqLabel); 00207 } 00208 00209 void 00210 WindowShapePreview::setWindowType(WindowType type) 00211 { 00212 if (m_windowType == type) return; 00213 m_windowType = type; 00214 updateLabels(); 00215 } 00216