Skip to content

Commit

Permalink
Finished implementing waveform plotting.
Browse files Browse the repository at this point in the history
  • Loading branch information
bastibe committed May 2, 2013
1 parent c5dc346 commit 57e9d8c
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 35 deletions.
6 changes: 4 additions & 2 deletions Speqtrogram.pro
Expand Up @@ -17,13 +17,15 @@ SOURCES += main.cpp\
mainwindow.cpp \
devicelist.cpp \
hostapilist.cpp \
paplayback.cpp
paplayback.cpp \
waveformwidget.cpp

HEADERS += mainwindow.h\
portaudio.h \
devicelist.h \
hostapilist.h \
paplayback.h
paplayback.h \
waveformwidget.h

FORMS += mainwindow.ui

Expand Down
34 changes: 2 additions & 32 deletions mainwindow.cpp
Expand Up @@ -13,6 +13,7 @@ MainWindow::MainWindow(QWidget *parent) :
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->waveformView->setMinimumHeight(20);
ui->hostApiList->setModel(new HostApiList());
ui->deviceList->setModel(new DeviceList());

Expand Down Expand Up @@ -63,38 +64,7 @@ void MainWindow::open()
tr("Sound Files (*.wav *.flac *.aiff *.ogg)"));
QDir::setCurrent(QFileInfo(fileName).absolutePath());
player.openSoundFile(fileName.toStdString());

QGraphicsScene *waveformNavigatorScene = new QGraphicsScene();
QPainterPath waveformMax(QPointF(0,0));
QPainterPath waveformMin(QPointF(0,0));
SndfileHandle soundFile(fileName.toStdString());
if (soundFile.error()) {
qDebug() << soundFile.strError();
}
sf_count_t framesPerPixel = soundFile.frames()/ui->waveformNavigator->width();
float samples[framesPerPixel*soundFile.channels()];
sf_count_t totalFrames = 0;
while (soundFile.readf(samples, framesPerPixel) != 0) {
float maximum = 0;
float minimum = 0;
for (int f=0; f<framesPerPixel; f++) {
for (int c=0; c<soundFile.channels(); c++) {
maximum = samples[f*c+c] > maximum ? samples[f*c+c] : maximum;
minimum = samples[f*c+c] < minimum ? samples[f*c+c] : minimum;
}
}
waveformMax.lineTo(totalFrames/framesPerPixel, maximum*ui->waveformNavigator->height()*0.5);
waveformMin.lineTo(totalFrames/framesPerPixel, minimum*ui->waveformNavigator->height()*0.5);
totalFrames += framesPerPixel;
}
QColor lightBlue = QColor(Qt::blue);
lightBlue.setAlphaF(0.5);
waveformNavigatorScene->addPath(waveformMax, QPen(Qt::blue), QBrush(lightBlue));
waveformNavigatorScene->addPath(waveformMin, QPen(Qt::blue), QBrush(lightBlue));
ui->waveformNavigator->setScene(waveformNavigatorScene);
ui->waveformNavigator->setRenderHint(QPainter::Antialiasing, true);

qDebug() << ui->waveformNavigator->sceneRect();
ui->waveformView->setSoundFile(fileName);
}

void MainWindow::changePlayButtonState(bool isPlaying)
Expand Down
10 changes: 9 additions & 1 deletion mainwindow.ui
Expand Up @@ -39,7 +39,7 @@
</layout>
</item>
<item>
<widget class="QGraphicsView" name="waveformNavigator"/>
<widget class="WaveformWidget" name="waveformView" native="true"/>
</item>
<item>
<widget class="QWidget" name="spectrogram" native="true"/>
Expand Down Expand Up @@ -135,6 +135,14 @@
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>WaveformWidget</class>
<extends>QWidget</extends>
<header>waveformwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
60 changes: 60 additions & 0 deletions waveformwidget.cpp
@@ -0,0 +1,60 @@
#include "waveformwidget.h"
#include <QPainter>
#include <QApplication>
#include <QDesktopWidget>
#include "sndfile.hh"
#include <QDebug>

WaveformWidget::WaveformWidget(QWidget *parent) :
QWidget(parent)
{
}

void WaveformWidget::setSoundFile(QString filename)
{
QPainterPath waveformMax(QPointF(0,0));
QPainterPath waveformMin(QPointF(0,0));
SndfileHandle soundFile(filename.toStdString());
if (soundFile.error()) qDebug() << soundFile.strError();

QDesktopWidget *desk = QApplication::desktop();
int totalPixelCount = (desk->screenGeometry().width()*desk->screenCount());
sf_count_t framesPerPixel = soundFile.frames()/totalPixelCount;
Q_ASSERT(framesPerPixel >= 1);
float samples[framesPerPixel*soundFile.channels()];
sf_count_t totalFrames = 0;
while (soundFile.readf(samples, framesPerPixel) != 0) {
float maximum = 0;
float minimum = 0;
for (int f=0; f<framesPerPixel; f++) {
for (int c=0; c<soundFile.channels(); c++) {
maximum = samples[f*c+c] > maximum ? samples[f*c+c] : maximum;
minimum = samples[f*c+c] < minimum ? samples[f*c+c] : minimum;
}
}
waveformMax.lineTo(double(totalFrames)/(framesPerPixel*totalPixelCount), maximum);
waveformMin.lineTo(double(totalFrames)/(framesPerPixel*totalPixelCount), minimum);
totalFrames += framesPerPixel;
}
maxWave.swap(waveformMax);
minWave.swap(waveformMin);
}

void WaveformWidget::paintEvent(QPaintEvent *event)
{
(void)event;
QPainter painter(this);
painter.setBrush(Qt::white);
painter.drawRect(QRect(QPoint(),this->size()));

QColor lightBlue = QColor(Qt::blue);
lightBlue.setAlphaF(0.5);
painter.setBrush(QBrush(lightBlue));
painter.setPen(QPen(QBrush(Qt::blue), 0));

painter.scale(width(), height()/2);
painter.translate(0,1);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.drawPath(maxWave);
painter.drawPath(minWave);
}
23 changes: 23 additions & 0 deletions waveformwidget.h
@@ -0,0 +1,23 @@
#ifndef WAVEFORMWIDGET_H
#define WAVEFORMWIDGET_H

#include <QWidget>
#include <QUrl>

class WaveformWidget : public QWidget
{
Q_OBJECT
public:
explicit WaveformWidget(QWidget *parent = 0);
void paintEvent(QPaintEvent* event);
void setSoundFile(QString filename);
signals:

public slots:

private:
QPainterPath maxWave;
QPainterPath minWave;
};

#endif // WAVEFORMWIDGET_H

0 comments on commit 57e9d8c

Please sign in to comment.