Mercurial > hg > svgui
changeset 139:5ec6b60658d8
* Pull window type selector and shape preview out into their own widgets
(from the preferences dialog)
author | Chris Cannam |
---|---|
date | Mon, 11 Sep 2006 15:32:49 +0000 |
parents | 0f1ac9562c76 |
children | b9235b62fe31 |
files | widgets/WindowShapePreview.cpp widgets/WindowShapePreview.h widgets/WindowTypeSelector.cpp widgets/WindowTypeSelector.h widgets/widgets.pro |
diffstat | 5 files changed, 417 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/WindowShapePreview.cpp Mon Sep 11 15:32:49 2006 +0000 @@ -0,0 +1,207 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "WindowShapePreview.h" + +#include <QHBoxLayout> +#include <QLabel> +#include <QPainter> +#include <QPainterPath> +#include <QFont> +#include <QString> + +#include <fftw3.h> + +#include <iostream> + +WindowShapePreview::WindowShapePreview(QWidget *parent) : + QFrame(parent), + m_windowType(WindowType(999)) +{ + QHBoxLayout *layout = new QHBoxLayout; + layout->setMargin(0); + setLayout(layout); + m_windowTimeExampleLabel = new QLabel; + m_windowFreqExampleLabel = new QLabel; + layout->addWidget(m_windowTimeExampleLabel); + layout->addWidget(m_windowFreqExampleLabel); +} + +WindowShapePreview::~WindowShapePreview() +{ +} + +void +WindowShapePreview::updateLabels() +{ + int step = 24; + int peak = 48; + int w = step * 4, h = 64; + WindowType type = m_windowType; + Window<float> windower = Window<float>(type, step * 2); + + QPixmap timeLabel(w, h + 1); + timeLabel.fill(Qt::white); + QPainter timePainter(&timeLabel); + + QPainterPath path; + + path.moveTo(0, h - peak + 1); + path.lineTo(w, h - peak + 1); + + timePainter.setPen(Qt::gray); + timePainter.setRenderHint(QPainter::Antialiasing, true); + timePainter.drawPath(path); + + path = QPainterPath(); + + float acc[w]; + for (int i = 0; i < w; ++i) acc[i] = 0.f; + for (int j = 0; j < 3; ++j) { + for (int i = 0; i < step * 2; ++i) { + acc[j * step + i] += windower.getValue(i); + } + } + for (int i = 0; i < w; ++i) { + int y = h - int(peak * acc[i] + 0.001) + 1; + if (i == 0) path.moveTo(i, y); + else path.lineTo(i, y); + } + + timePainter.drawPath(path); + timePainter.setRenderHint(QPainter::Antialiasing, false); + + path = QPainterPath(); + + timePainter.setPen(Qt::black); + + for (int i = 0; i < step * 2; ++i) { + int y = h - int(peak * windower.getValue(i) + 0.001) + 1; + if (i == 0) path.moveTo(i + step, float(y)); + else path.lineTo(i + step, float(y)); + } + + if (type == RectangularWindow) { + timePainter.drawPath(path); + path = QPainterPath(); + } + + timePainter.setRenderHint(QPainter::Antialiasing, true); + path.addRect(0, 0, w, h + 1); + timePainter.drawPath(path); + + QFont font; + font.setPixelSize(10); + font.setItalic(true); + timePainter.setFont(font); + QString label = tr("V / time"); + timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4, + timePainter.fontMetrics().ascent() + 1, label); + + m_windowTimeExampleLabel->setPixmap(timeLabel); + + int fw = 100; + + QPixmap freqLabel(fw, h + 1); + freqLabel.fill(Qt::white); + QPainter freqPainter(&freqLabel); + path = QPainterPath(); + + int fftsize = 512; + + float *input = (float *)fftwf_malloc(fftsize * sizeof(float)); + fftwf_complex *output = + (fftwf_complex *)fftwf_malloc(fftsize * sizeof(fftwf_complex)); + fftwf_plan plan = fftwf_plan_dft_r2c_1d(fftsize, input, output, + FFTW_ESTIMATE); + for (int i = 0; i < fftsize; ++i) input[i] = 0.f; + for (int i = 0; i < step * 2; ++i) { + input[fftsize/2 - step + i] = windower.getValue(i); + } + + fftwf_execute(plan); + fftwf_destroy_plan(plan); + + float maxdb = 0.f; + float mindb = 0.f; + bool first = true; + for (int i = 0; i < fftsize/2; ++i) { + float power = output[i][0] * output[i][0] + output[i][1] * output[i][1]; + float db = mindb; + if (power > 0) { + db = 20 * log10(power); + if (first || db > maxdb) maxdb = db; + if (first || db < mindb) mindb = db; + first = false; + } + } + + if (mindb > -80.f) mindb = -80.f; + + // -- no, don't use the actual mindb -- it's easier to compare + // plots with a fixed min value + mindb = -170.f; + + float maxval = maxdb + -mindb; + +// float ly = h - ((-80.f + -mindb) / maxval) * peak + 1; + + path.moveTo(0, h - peak + 1); + path.lineTo(fw, h - peak + 1); + + freqPainter.setPen(Qt::gray); + freqPainter.setRenderHint(QPainter::Antialiasing, true); + freqPainter.drawPath(path); + + path = QPainterPath(); + freqPainter.setPen(Qt::black); + +// std::cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << std::endl; + + for (int i = 0; i < fftsize/2; ++i) { + float power = output[i][0] * output[i][0] + output[i][1] * output[i][1]; + float db = 20 * log10(power); + float val = db + -mindb; + if (val < 0) val = 0; + float norm = val / maxval; + float x = (fw / float(fftsize/2)) * i; + float y = h - norm * peak + 1; + if (i == 0) path.moveTo(x, y); + else path.lineTo(x, y); + } + + freqPainter.setRenderHint(QPainter::Antialiasing, true); + path.addRect(0, 0, fw, h + 1); + freqPainter.drawPath(path); + + fftwf_free(input); + fftwf_free(output); + + freqPainter.setFont(font); + label = tr("dB / freq"); + freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4, + freqPainter.fontMetrics().ascent() + 1, label); + + m_windowFreqExampleLabel->setPixmap(freqLabel); +} + +void +WindowShapePreview::setWindowType(WindowType type) +{ + if (m_windowType == type) return; + m_windowType = type; + updateLabels(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/WindowShapePreview.h Mon Sep 11 15:32:49 2006 +0000 @@ -0,0 +1,44 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _WINDOW_SHAPE_PREVIEW_H_ +#define _WINDOW_SHAPE_PREVIEW_H_ + +#include <QFrame> + +#include "base/Window.h" + +class QLabel; + +class WindowShapePreview : public QFrame +{ + Q_OBJECT + +public: + WindowShapePreview(QWidget *parent = 0); + virtual ~WindowShapePreview(); + +public slots: + void setWindowType(WindowType type); + +protected: + QLabel *m_windowTimeExampleLabel; + QLabel *m_windowFreqExampleLabel; + WindowType m_windowType; + + void updateLabels(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/WindowTypeSelector.cpp Mon Sep 11 15:32:49 2006 +0000 @@ -0,0 +1,107 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "WindowTypeSelector.h" + +#include "WindowShapePreview.h" + +#include <QVBoxLayout> +#include <QComboBox> + +#include "base/Preferences.h" + +WindowTypeSelector::WindowTypeSelector(WindowType defaultType, QWidget *parent) : + QFrame(parent), + m_windowType(WindowType(999)) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + setLayout(layout); + + // The WindowType enum is in rather a ragbag order -- reorder it here + // in a more sensible order + m_windows = new WindowType[9]; + m_windows[0] = HanningWindow; + m_windows[1] = HammingWindow; + m_windows[2] = BlackmanWindow; + m_windows[3] = BlackmanHarrisWindow; + m_windows[4] = NuttallWindow; + m_windows[5] = GaussianWindow; + m_windows[6] = ParzenWindow; + m_windows[7] = BartlettWindow; + m_windows[8] = RectangularWindow; + + Preferences *prefs = Preferences::getInstance(); + + m_windowShape = new WindowShapePreview; + + m_windowCombo = new QComboBox; + int min = 0, max = 0, i = 0; + int window = int(defaultType); + if (window == 999) { + window = prefs->getPropertyRangeAndValue("Window Type", &min, &max); + } + int index = 0; + + for (i = 0; i <= 8; ++i) { + m_windowCombo->addItem(prefs->getPropertyValueLabel("Window Type", + m_windows[i])); + if (m_windows[i] == window) index = i; + } + + m_windowCombo->setCurrentIndex(index); + + layout->addWidget(m_windowShape); + layout->addWidget(m_windowCombo); + + connect(m_windowCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(windowIndexChanged(int))); + windowIndexChanged(index); +} + +WindowTypeSelector::~WindowTypeSelector() +{ + delete[] m_windows; +} + +WindowType +WindowTypeSelector::getWindowType() const +{ + return m_windowType; +} + +void +WindowTypeSelector::setWindowType(WindowType type) +{ + if (type == m_windowType) return; + int index; + for (index = 0; index <= 8; ++index) { + if (m_windows[index] == type) break; + } + if (index <= 8) m_windowCombo->setCurrentIndex(index); + m_windowType = type; + m_windowShape->setWindowType(m_windowType); +} + +void +WindowTypeSelector::windowIndexChanged(int index) +{ + WindowType type = m_windows[index]; + if (type == m_windowType) return; + m_windowType = type; + m_windowShape->setWindowType(m_windowType); + emit windowTypeChanged(type); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/WindowTypeSelector.h Mon Sep 11 15:32:49 2006 +0000 @@ -0,0 +1,53 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _WINDOW_TYPE_SELECTOR_H_ +#define _WINDOW_TYPE_SELECTOR_H_ + +#include <QFrame> + +#include "base/Window.h" + +class WindowShapePreview; +class QComboBox; + +class WindowTypeSelector : public QFrame +{ + Q_OBJECT + +public: + WindowTypeSelector(WindowType defaultType = WindowType(999), // 999 -> get from preferences + QWidget *parent = 0); + virtual ~WindowTypeSelector(); + + WindowType getWindowType() const; + +signals: + void windowTypeChanged(WindowType type); + +public slots: + void setWindowType(WindowType type); + +protected slots: + void windowIndexChanged(int index); + +protected: + QComboBox *m_windowCombo; + WindowShapePreview *m_windowShape; + WindowType *m_windows; + WindowType m_windowType; +}; + +#endif
--- a/widgets/widgets.pro Tue Sep 05 16:34:54 2006 +0000 +++ b/widgets/widgets.pro Mon Sep 11 15:32:49 2006 +0000 @@ -24,7 +24,9 @@ PluginParameterDialog.h \ PropertyBox.h \ PropertyStack.h \ - Thumbwheel.h + Thumbwheel.h \ + WindowShapePreview.h \ + WindowTypeSelector.h SOURCES += AudioDial.cpp \ Fader.cpp \ ItemEditDialog.cpp \ @@ -35,4 +37,6 @@ PluginParameterDialog.cpp \ PropertyBox.cpp \ PropertyStack.cpp \ - Thumbwheel.cpp + Thumbwheel.cpp \ + WindowShapePreview.cpp \ + WindowTypeSelector.cpp