svgui  1.9
WindowShapePreview.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "WindowShapePreview.h"
17 
18 #include <QHBoxLayout>
19 #include <QLabel>
20 #include <QPainter>
21 #include <QPainterPath>
22 #include <QFont>
23 #include <QString>
24 
25 #include "data/fft/FFTapi.h"
26 
27 #include <iostream>
28 
29 #ifndef __GNUC__
30 #include <alloca.h>
31 #endif
32 
34  QFrame(parent),
35  m_windowType(WindowType(999))
36 {
37  QHBoxLayout *layout = new QHBoxLayout;
38  layout->setMargin(0);
39  setLayout(layout);
40  m_windowTimeExampleLabel = new QLabel;
41  m_windowFreqExampleLabel = new QLabel;
42  layout->addWidget(m_windowTimeExampleLabel);
43  layout->addWidget(m_windowFreqExampleLabel);
44 }
45 
47 {
48 }
49 
50 void
52 {
53  int step = 24;
54  int peak = 48;
55  int w = step * 4, h = 64;
56  WindowType type = m_windowType;
57  Window<float> windower = Window<float>(type, step * 2);
58 
59  QPixmap timeLabel(w, h + 1);
60  timeLabel.fill(Qt::white);
61  QPainter timePainter(&timeLabel);
62 
63  QPainterPath path;
64 
65  path.moveTo(0, h - peak + 1);
66  path.lineTo(w, h - peak + 1);
67 
68  timePainter.setPen(Qt::gray);
69  timePainter.setRenderHint(QPainter::Antialiasing, true);
70  timePainter.drawPath(path);
71 
72  path = QPainterPath();
73 
74 #ifdef __GNUC__
75  float acc[w];
76 #else
77  float *acc = (float *)alloca(w * sizeof(float));
78 #endif
79 
80  for (int i = 0; i < w; ++i) acc[i] = 0.f;
81  for (int j = 0; j < 3; ++j) {
82  for (int i = 0; i < step * 2; ++i) {
83  acc[j * step + i] += windower.getValue(i);
84  }
85  }
86  for (int i = 0; i < w; ++i) {
87  int y = h - int(peak * acc[i] + 0.001) + 1;
88  if (i == 0) path.moveTo(i, y);
89  else path.lineTo(i, y);
90  }
91 
92  timePainter.drawPath(path);
93  timePainter.setRenderHint(QPainter::Antialiasing, false);
94 
95  path = QPainterPath();
96 
97  timePainter.setPen(Qt::black);
98 
99  for (int i = 0; i < step * 2; ++i) {
100  int y = h - int(peak * windower.getValue(i) + 0.001) + 1;
101  if (i == 0) path.moveTo(i + step, float(y));
102  else path.lineTo(i + step, float(y));
103  }
104 
105  if (type == RectangularWindow) {
106  timePainter.drawPath(path);
107  path = QPainterPath();
108  }
109 
110  timePainter.setRenderHint(QPainter::Antialiasing, true);
111  path.addRect(0, 0, w, h + 1);
112  timePainter.drawPath(path);
113 
114  QFont font;
115  font.setPixelSize(10);
116  font.setItalic(true);
117  timePainter.setFont(font);
118  QString label = tr("V / time");
119  timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4,
120  timePainter.fontMetrics().ascent() + 1, label);
121 
122  m_windowTimeExampleLabel->setPixmap(timeLabel);
123 
124  int fw = 100;
125 
126  QPixmap freqLabel(fw, h + 1);
127  freqLabel.fill(Qt::white);
128  QPainter freqPainter(&freqLabel);
129  path = QPainterPath();
130 
131  int fftsize = 512;
132 
133  float *input = (float *)fftf_malloc(fftsize * sizeof(float));
134  fftf_complex *output =
135  (fftf_complex *)fftf_malloc(fftsize * sizeof(fftf_complex));
136  fftf_plan plan = fftf_plan_dft_r2c_1d(fftsize, input, output,
137  FFTW_ESTIMATE);
138  for (int i = 0; i < fftsize; ++i) input[i] = 0.f;
139  for (int i = 0; i < step * 2; ++i) {
140  input[fftsize/2 - step + i] = windower.getValue(i);
141  }
142 
143  fftf_execute(plan);
144  fftf_destroy_plan(plan);
145 
146  float maxdb = 0.f;
147  float mindb = 0.f;
148  bool first = true;
149  for (int i = 0; i < fftsize/2; ++i) {
150  float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
151  float db = mindb;
152  if (power > 0) {
153  db = 20 * log10(power);
154  if (first || db > maxdb) maxdb = db;
155  if (first || db < mindb) mindb = db;
156  first = false;
157  }
158  }
159 
160  if (mindb > -80.f) mindb = -80.f;
161 
162  // -- no, don't use the actual mindb -- it's easier to compare
163  // plots with a fixed min value
164  mindb = -170.f;
165 
166  float maxval = maxdb + -mindb;
167 
168 // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1;
169 
170  path.moveTo(0, h - peak + 1);
171  path.lineTo(fw, h - peak + 1);
172 
173  freqPainter.setPen(Qt::gray);
174  freqPainter.setRenderHint(QPainter::Antialiasing, true);
175  freqPainter.drawPath(path);
176 
177  path = QPainterPath();
178  freqPainter.setPen(Qt::black);
179 
180 // cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <<maxval << endl;
181 
182  for (int i = 0; i < fftsize/2; ++i) {
183  float power = output[i][0] * output[i][0] + output[i][1] * output[i][1];
184  float db = 20 * log10(power);
185  float val = db + -mindb;
186  if (val < 0) val = 0;
187  float norm = val / maxval;
188  float x = (fw / float(fftsize/2)) * i;
189  float y = h - norm * peak + 1;
190  if (i == 0) path.moveTo(x, y);
191  else path.lineTo(x, y);
192  }
193 
194  freqPainter.setRenderHint(QPainter::Antialiasing, true);
195  path.addRect(0, 0, fw, h + 1);
196  freqPainter.drawPath(path);
197 
198  fftf_free(input);
199  fftf_free(output);
200 
201  freqPainter.setFont(font);
202  label = tr("dB / freq");
203  freqPainter.drawText(fw - freqPainter.fontMetrics().width(label) - 4,
204  freqPainter.fontMetrics().ascent() + 1, label);
205 
206  m_windowFreqExampleLabel->setPixmap(freqLabel);
207 }
208 
209 void
211 {
212  if (m_windowType == type) return;
213  m_windowType = type;
214  updateLabels();
215 }
216 
WindowShapePreview(QWidget *parent=0)
QLabel * m_windowTimeExampleLabel
void setWindowType(WindowType type)
QLabel * m_windowFreqExampleLabel