svgui  1.9
WindowShapePreview.cpp
Go to the documentation of this file.
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