Chris@139: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@139: Chris@139: /* Chris@139: Sonic Visualiser Chris@139: An audio file viewer and annotation editor. Chris@139: Centre for Digital Music, Queen Mary, University of London. Chris@139: This file copyright 2006 Chris Cannam. Chris@139: Chris@139: This program is free software; you can redistribute it and/or Chris@139: modify it under the terms of the GNU General Public License as Chris@139: published by the Free Software Foundation; either version 2 of the Chris@139: License, or (at your option) any later version. See the file Chris@139: COPYING included with this distribution for more information. Chris@139: */ Chris@139: Chris@139: #include "WindowShapePreview.h" Chris@139: Chris@139: #include Chris@139: #include Chris@139: #include Chris@139: #include Chris@139: #include Chris@139: #include Chris@139: Chris@1168: #include Chris@139: Chris@1168: #include Chris@1168: #include Chris@139: #include Chris@139: Chris@1168: using namespace std; Chris@1168: Chris@545: Chris@139: WindowShapePreview::WindowShapePreview(QWidget *parent) : Chris@139: QFrame(parent), Chris@908: m_windowType(HanningWindow) Chris@139: { Chris@139: QHBoxLayout *layout = new QHBoxLayout; Chris@139: layout->setMargin(0); Chris@139: setLayout(layout); Chris@139: m_windowTimeExampleLabel = new QLabel; Chris@139: m_windowFreqExampleLabel = new QLabel; Chris@139: layout->addWidget(m_windowTimeExampleLabel); Chris@139: layout->addWidget(m_windowFreqExampleLabel); Chris@139: } Chris@139: Chris@139: WindowShapePreview::~WindowShapePreview() Chris@139: { Chris@139: } Chris@139: Chris@139: void Chris@139: WindowShapePreview::updateLabels() Chris@139: { Chris@1157: float scaleRatio = float(QFontMetrics(font()).height()) / 14.f; Chris@1154: if (scaleRatio < 1.f) scaleRatio = 1.f; Chris@1154: Chris@1154: int step = int(24 * scaleRatio); Chris@1157: float peak = float(48 * scaleRatio); Chris@1154: Chris@1157: int w = step * 4, h = int((peak * 4) / 3); Chris@1154: Chris@139: WindowType type = m_windowType; Chris@139: Window windower = Window(type, step * 2); Chris@1154: Chris@139: QPixmap timeLabel(w, h + 1); Chris@139: timeLabel.fill(Qt::white); Chris@139: QPainter timePainter(&timeLabel); Chris@139: Chris@139: QPainterPath path; Chris@139: Chris@908: path.moveTo(0, float(h) - peak + 1); Chris@908: path.lineTo(w, float(h) - peak + 1); Chris@139: Chris@139: timePainter.setPen(Qt::gray); Chris@139: timePainter.setRenderHint(QPainter::Antialiasing, true); Chris@139: timePainter.drawPath(path); Chris@139: Chris@139: path = QPainterPath(); Chris@139: Chris@1153: float *acc = new float[w]; Chris@139: for (int i = 0; i < w; ++i) acc[i] = 0.f; Chris@139: for (int j = 0; j < 3; ++j) { Chris@139: for (int i = 0; i < step * 2; ++i) { Chris@139: acc[j * step + i] += windower.getValue(i); Chris@139: } Chris@139: } Chris@139: for (int i = 0; i < w; ++i) { Chris@908: int y = h - int(peak * acc[i] + 0.001f) + 1; Chris@139: if (i == 0) path.moveTo(i, y); Chris@139: else path.lineTo(i, y); Chris@139: } Chris@1150: delete[] acc; Chris@139: Chris@139: timePainter.drawPath(path); Chris@139: timePainter.setRenderHint(QPainter::Antialiasing, false); Chris@139: Chris@139: path = QPainterPath(); Chris@139: Chris@139: timePainter.setPen(Qt::black); Chris@139: Chris@139: for (int i = 0; i < step * 2; ++i) { Chris@139: int y = h - int(peak * windower.getValue(i) + 0.001) + 1; Chris@139: if (i == 0) path.moveTo(i + step, float(y)); Chris@139: else path.lineTo(i + step, float(y)); Chris@139: } Chris@139: Chris@139: if (type == RectangularWindow) { Chris@139: timePainter.drawPath(path); Chris@139: path = QPainterPath(); Chris@139: } Chris@139: Chris@139: timePainter.setRenderHint(QPainter::Antialiasing, true); Chris@139: path.addRect(0, 0, w, h + 1); Chris@139: timePainter.drawPath(path); Chris@139: Chris@1478: // Qt 5.13 deprecates QFontMetrics::width(), but its suggested Chris@1478: // replacement (horizontalAdvance) was only added in Qt 5.11 Chris@1478: // which is too new for us Chris@1478: #pragma GCC diagnostic ignored "-Wdeprecated-declarations" Chris@1478: Chris@139: QFont font; Chris@1154: font.setPixelSize(int(10 * scaleRatio)); Chris@139: font.setItalic(true); Chris@139: timePainter.setFont(font); Chris@139: QString label = tr("V / time"); Chris@139: timePainter.drawText(w - timePainter.fontMetrics().width(label) - 4, Chris@139: timePainter.fontMetrics().ascent() + 1, label); Chris@139: Chris@139: m_windowTimeExampleLabel->setPixmap(timeLabel); Chris@139: Chris@1154: QPixmap freqLabel(w, h + 1); Chris@139: freqLabel.fill(Qt::white); Chris@139: QPainter freqPainter(&freqLabel); Chris@139: path = QPainterPath(); Chris@139: Chris@139: int fftsize = 512; Chris@139: Chris@1168: breakfastquay::FFT fft(fftsize); Chris@1168: Chris@1168: vector input(fftsize); Chris@1168: vector> output(fftsize/2 + 1); Chris@1168: Chris@139: for (int i = 0; i < fftsize; ++i) input[i] = 0.f; Chris@139: for (int i = 0; i < step * 2; ++i) { Chris@139: input[fftsize/2 - step + i] = windower.getValue(i); Chris@139: } Chris@1168: Chris@1168: fft.forwardInterleaved(input.data(), reinterpret_cast(output.data())); Chris@139: Chris@139: float maxdb = 0.f; Chris@139: float mindb = 0.f; Chris@139: bool first = true; Chris@139: for (int i = 0; i < fftsize/2; ++i) { Chris@1168: float power = Chris@1168: output[i].real() * output[i].real() + Chris@1168: output[i].imag() * output[i].imag(); Chris@139: float db = mindb; Chris@139: if (power > 0) { Chris@908: db = 20.f * log10f(power); Chris@139: if (first || db > maxdb) maxdb = db; Chris@139: if (first || db < mindb) mindb = db; Chris@139: first = false; Chris@139: } Chris@139: } Chris@139: Chris@139: if (mindb > -80.f) mindb = -80.f; Chris@139: Chris@139: // -- no, don't use the actual mindb -- it's easier to compare Chris@139: // plots with a fixed min value Chris@139: mindb = -170.f; Chris@139: Chris@139: float maxval = maxdb + -mindb; Chris@139: Chris@139: // float ly = h - ((-80.f + -mindb) / maxval) * peak + 1; Chris@139: Chris@908: path.moveTo(0, float(h) - peak + 1); Chris@1154: path.lineTo(w, float(h) - peak + 1); Chris@139: Chris@139: freqPainter.setPen(Qt::gray); Chris@139: freqPainter.setRenderHint(QPainter::Antialiasing, true); Chris@139: freqPainter.drawPath(path); Chris@139: Chris@139: path = QPainterPath(); Chris@139: freqPainter.setPen(Qt::black); Chris@139: Chris@682: // cerr << "maxdb = " << maxdb << ", mindb = " << mindb << ", maxval = " <setPixmap(freqLabel); Chris@139: } Chris@139: Chris@139: void Chris@139: WindowShapePreview::setWindowType(WindowType type) Chris@139: { Chris@139: m_windowType = type; Chris@139: updateLabels(); Chris@139: } Chris@139: