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 WindowShapePreview::WindowShapePreview(QWidget *parent) :
00030     QFrame(parent),
00031     m_windowType(WindowType(999))
00032 {
00033     QHBoxLayout *layout = new QHBoxLayout;
00034     layout->setMargin(0);
00035     setLayout(layout);
00036     m_windowTimeExampleLabel = new QLabel;
00037     m_windowFreqExampleLabel = new QLabel;
00038     layout->addWidget(m_windowTimeExampleLabel);
00039     layout->addWidget(m_windowFreqExampleLabel);
00040 }
00041 
00042 WindowShapePreview::~WindowShapePreview()
00043 {
00044 }
00045 
00046 void
00047 WindowShapePreview::updateLabels()
00048 {
00049     int step = 24;
00050     int peak = 48;
00051     int w = step * 4, h = 64;
00052     WindowType type = m_windowType;
00053     Window<float> windower = Window<float>(type, step * 2);
00054 
00055     QPixmap timeLabel(w, h + 1);
00056     timeLabel.fill(Qt::white);
00057     QPainter timePainter(&timeLabel);
00058 
00059     QPainterPath path;
00060 
00061     path.moveTo(0, h - peak + 1);
00062     path.lineTo(w, h - peak + 1);
00063 
00064     timePainter.setPen(Qt::gray);
00065     timePainter.setRenderHint(QPainter::Antialiasing, true);
00066     timePainter.drawPath(path);
00067     
00068     path = QPainterPath();
00069 
00070     float acc[w];
00071     for (int i = 0; i < w; ++i) acc[i] = 0.f;
00072     for (int j = 0; j < 3; ++j) {
00073         for (int i = 0; i < step * 2; ++i) {
00074             acc[j * step + i] += windower.getValue(i);
00075         }
00076     }
00077     for (int i = 0; i < w; ++i) {
00078         int y = h - int(peak * acc[i] + 0.001) + 1;
00079         if (i == 0) path.moveTo(i, y);
00080         else path.lineTo(i, y);
00081     }
00082 
00083     timePainter.drawPath(path);
00084     timePainter.setRenderHint(QPainter::Antialiasing, false);
00085 
00086     path = QPainterPath();
00087 
00088     timePainter.setPen(Qt::black);
00089     
00090     for (int i = 0; i < step * 2; ++i) {
00091         int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
00092         if (i == 0) path.moveTo(i + step, float(y));
00093         else path.lineTo(i + step, float(y));
00094     }
00095 
00096     if (type == RectangularWindow) {
00097         timePainter.drawPath(path);
00098         path = QPainterPath();
00099     }
00100 
00101     timePainter.setRenderHint(QPainter::Antialiasing, true);
00102     path.addRect(0, 0, w, h + 1);
00103     timePainter.drawPath(path);
00104 
00105     QFont font;
00106     font.setPixelSize(10);
00107     font.setItalic(true);
00108     timePainter.setFont(font);
00109     QString label = tr("V / time");
00110     timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
00111                          timePainter.fontMetrics().ascent() + 1, label);
00112 
00113     m_windowTimeExampleLabel->setPixmap(timeLabel);
00114     
00115     int fw = 100;
00116 
00117     QPixmap freqLabel(fw, h + 1);
00118     freqLabel.fill(Qt::white);
00119     QPainter freqPainter(&freqLabel);
00120     path = QPainterPath();
00121 
00122     int fftsize = 512;
00123 
00124     float *input = (float *)fftf_malloc(fftsize * sizeof(float));
00125     fftf_complex *output =
00126         (fftf_complex *)fftf_malloc(fftsize * sizeof(fftf_complex));
00127     fftf_plan plan = fftf_plan_dft_r2c_1d(fftsize, input, output,
00128                                             FFTW_ESTIMATE);
00129     for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
00130     for (int i = 0; i < step * 2; ++i) {
00131         input[fftsize/2 - step + i] = windower.getValue(i);
00132     }
00133     
00134     fftf_execute(plan);
00135     fftf_destroy_plan(plan);
00136 
00137     float maxdb = 0.f;
00138     float mindb = 0.f;
00139     bool first = true;
00140     for (int i = 0; i < fftsize/2; ++i) {
00141         float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
00142         float db = mindb;
00143         if (power > 0) {
00144             db = 20 * log10(power);
00145             if (first || db > maxdb) maxdb = db;
00146             if (first || db < mindb) mindb = db;
00147             first = false;
00148         }
00149     }
00150 
00151     if (mindb > -80.f) mindb = -80.f;
00152 
00153     // -- no, don't use the actual mindb -- it's easier to compare
00154     // plots with a fixed min value
00155     mindb = -170.f;
00156 
00157     float maxval = maxdb + -mindb;
00158 
00159 //    float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
00160 
00161     path.moveTo(0, h - peak + 1);
00162     path.lineTo(fw, h - peak + 1);
00163 
00164     freqPainter.setPen(Qt::gray);
00165     freqPainter.setRenderHint(QPainter::Antialiasing, true);
00166     freqPainter.drawPath(path);
00167     
00168     path = QPainterPath();
00169     freqPainter.setPen(Qt::black);
00170 
00171 //    std::cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << std::endl;
00172 
00173     for (int i = 0; i < fftsize/2; ++i) {
00174         float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
00175         float db = 20 * log10(power);
00176         float val = db + -mindb;
00177         if (val < 0) val = 0;
00178         float norm = val / maxval;
00179         float x = (fw / float(fftsize/2)) * i;
00180         float y = h - norm * peak + 1;
00181         if (i == 0) path.moveTo(x, y);
00182         else path.lineTo(x, y);
00183     }
00184 
00185     freqPainter.setRenderHint(QPainter::Antialiasing, true);
00186     path.addRect(0, 0, fw, h + 1);
00187     freqPainter.drawPath(path);
00188 
00189     fftf_free(input);
00190     fftf_free(output);
00191 
00192     freqPainter.setFont(font);
00193     label = tr("dB / freq");
00194     freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4,
00195                          freqPainter.fontMetrics().ascent() + 1, label);
00196 
00197     m_windowFreqExampleLabel->setPixmap(freqLabel);
00198 }
00199 
00200 void
00201 WindowShapePreview::setWindowType(WindowType type)
00202 {
00203     if (m_windowType == type) return;
00204     m_windowType = type;
00205     updateLabels();
00206 }
00207 

Generated on Wed Feb 20 15:45:30 2008 for SonicVisualiser by  doxygen 1.5.1