Skip to content

Commit

Permalink
add first working version of a spectrogram visualization
Browse files Browse the repository at this point in the history
addresses #25
  • Loading branch information
derselbst committed Jan 19, 2019
1 parent 75be874 commit e518da8
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 19 deletions.
4 changes: 2 additions & 2 deletions gui/applets/analyzer/ASCIIAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void ASCIIAnalyzer::resizeGL(int w, int h)
}

drawBackground();
analyze(m_scope);
analyze(m_scope,0);
}

void ASCIIAnalyzer::determineStep()
Expand All @@ -95,7 +95,7 @@ void ASCIIAnalyzer::determineStep()
m_step = double(m_rows * 80) / fallTime; //80 = ~milliseconds between signals with audio data
}

void ASCIIAnalyzer::analyze(const QVector<float> &s)
void ASCIIAnalyzer::analyze(const QVector<float> &s, uint32_t)
{
interpolate(s, m_scope);
}
Expand Down
2 changes: 1 addition & 1 deletion gui/applets/analyzer/ASCIIAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ASCIIAnalyzer : public AnalyzerBase
virtual void initializeGL();
virtual void paintGL();
virtual void resizeGL(int w, int h);
virtual void analyze(const QVector<float> &);
void analyze(const QVector<float> &, uint32_t srate) override;
virtual void paletteChange(const QPalette &);

void drawBackground();
Expand Down
9 changes: 6 additions & 3 deletions gui/applets/analyzer/AnalyzerApplet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "ASCIIAnalyzer.h"
#include "BlockAnalyzer.h"
#include "SpectrogramAnalyzer.h"

#include "Player.h"

Expand Down Expand Up @@ -70,9 +71,6 @@ void AnalyzerApplet::newGeometry()

void AnalyzerApplet::setAnalyzer(AnalyzerType type)
{
// if( m_analyzerName == name )
// return;

if (this->analyzerWidget != nullptr)
{
this->ui->horizontalLayout->removeWidget(this->analyzerWidget);
Expand All @@ -82,11 +80,16 @@ void AnalyzerApplet::setAnalyzer(AnalyzerType type)
switch (type)
{
default:
this->analyzerWidget = nullptr;
[[fallthrough]];
case Block:
this->analyzerWidget = new BlockAnalyzer(this);
this->setWindowTitle("Block Analyzer");
break;
case Spectrogram:
this->analyzerWidget = new SpectrogramAnalyzer(this);
this->setWindowTitle("Spectrogram Analyzer");
break;
case Ascii:
this->analyzerWidget = new ASCIIAnalyzer(this);
this->setWindowTitle("ASCII Analyzer");
Expand Down
3 changes: 2 additions & 1 deletion gui/applets/analyzer/AnalyzerApplet.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class AnalyzerApplet : public QMainWindow
enum AnalyzerType
{
Block,
Ascii
Ascii,
Spectrogram
};

explicit AnalyzerApplet(Player *player, QWidget *parent = 0);
Expand Down
12 changes: 8 additions & 4 deletions gui/applets/analyzer/AnalyzerBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ void AnalyzerBase::disconnectSignals()

void AnalyzerBase::transform(QVector<float> &s)
{
float *front = static_cast<float *>(&s.front());

m_fht->spectrum(front);
m_fht->spectrum(&s.front());
}

// fill the buffer that will be fourier transformed
Expand Down Expand Up @@ -135,7 +133,7 @@ void AnalyzerBase::processData(const Song *s, frame_t playhead)
}

transform(m_fftData);
analyze(m_fftData);
analyze(m_fftData, s->Format.SampleRate);
}

void AnalyzerBase::interpolate(const QVector<float> &inVec, QVector<float> &outVec)
Expand Down Expand Up @@ -169,6 +167,12 @@ void AnalyzerBase::interpolate(const QVector<float> &inVec, QVector<float> &outV

void AnalyzerBase::setFps(int fps)
{
if(fps == 0)
{
m_renderTimer->stop();
return;
}

m_renderTimer->setInterval(1000 / fps);
}

Expand Down
5 changes: 2 additions & 3 deletions gui/applets/analyzer/AnalyzerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class AnalyzerBase : public QGLWidget
template<typename T>
void prepareScope(const Song *s, frame_t playhead, QVector<float> &scope);
virtual void transform(QVector<float> &);
virtual void analyze(const QVector<float> &) = 0;
virtual void analyze(const QVector<float> &, uint32_t srate) = 0;

void setFps(int fps);

Expand All @@ -55,9 +55,8 @@ class AnalyzerBase : public QGLWidget
QTimer *m_renderTimer;

public slots:
void connectSignals();
virtual void connectSignals();
void disconnectSignals();
// void currentDesktopChanged();
void processData(const Song *s, frame_t playhead);
};

Expand Down
4 changes: 2 additions & 2 deletions gui/applets/analyzer/BlockAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void BlockAnalyzer::resizeGL(int w, int h)
}

drawBackground();
analyze(m_scope);
analyze(m_scope, 0);
}

void BlockAnalyzer::determineStep()
Expand All @@ -106,7 +106,7 @@ void BlockAnalyzer::determineStep()
m_step = double(m_rows * 80) / fallTime; //80 = ~milliseconds between signals with audio data
}

void BlockAnalyzer::analyze(const QVector<float> &s)
void BlockAnalyzer::analyze(const QVector<float> &s, uint32_t)
{
interpolate(s, m_scope);
}
Expand Down
2 changes: 1 addition & 1 deletion gui/applets/analyzer/BlockAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class BlockAnalyzer : public AnalyzerBase
virtual void initializeGL();
virtual void paintGL();
virtual void resizeGL(int w, int h);
virtual void analyze(const QVector<float> &);
void analyze(const QVector<float> &, uint32_t srate) override;
virtual void paletteChange(const QPalette &);

void drawBackground();
Expand Down
3 changes: 1 addition & 2 deletions gui/applets/analyzer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(analyzer_SRCS
AnalyzerApplet.cpp
AnalyzerBase.cpp
# BallsAnalyzer.cpp
BlockAnalyzer.cpp
# DiscoAnalyzer.cpp
ASCIIAnalyzer.cpp
SpectrogramAnalyzer.cpp
PaletteHandler.cpp
fht.cpp
)
Expand Down
104 changes: 104 additions & 0 deletions gui/applets/analyzer/SpectrogramAnalyzer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

#include "SpectrogramAnalyzer.h"

#include "PaletteHandler.h"

#include <cmath>

#include <QPainter>
#include <QResizeEvent>


static inline uint myMax(uint v1, uint v2)
{
return v1 > v2 ? v1 : v2;
}

SpectrogramAnalyzer::SpectrogramAnalyzer(QWidget *parent)
: AnalyzerBase(parent), m_spectrogram(0,0,QImage::Format_Invalid)
{
setObjectName("SpectrogramAnalyzer");
this->setAttribute(Qt::WA_OpaquePaintEvent);

setFps(0);
}


void SpectrogramAnalyzer::connectSignals()
{
this->disconnectSignals();
}

void SpectrogramAnalyzer::display(const QImage& img)
{
m_toBeDrawn = img.mirrored();
this->update();
}

void SpectrogramAnalyzer::resizeEvent(QResizeEvent * event)
{
int h = event->size().height(), w = event->size().width();

m_scope.resize(h);
m_logScope.resize(h);
m_xPos = 0;

m_spectrogram = QImage(w,h,QImage::Format_RGB32);
m_spectrogram.fill(Qt::black);
m_currentWidth = w;

event->accept();
}


void SpectrogramAnalyzer::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.drawImage(this->rect(), m_toBeDrawn);

event->accept();
}

void SpectrogramAnalyzer::transform(QVector<float> &s)
{
if (m_logScope.size() == 0 || s.size() == 0)
{
return;
}

m_fht->spectrum(/*&m_logScope.front(), */&s.front());
}

void SpectrogramAnalyzer::analyze(const QVector<float> &s, uint32_t srate)
{
if (m_scope.size() == 0 || s.size() == 0)
{
return;
}

interpolate(s, m_scope);

double w = 1 / sqrt(srate);
auto scopeSize = m_scope.size();
for (int y = 0; y < scopeSize/2; y++)
{
int a = 255*sqrt(w * /*sqrt*/(m_scope[y + 0] * m_scope[y + 0] /*+ m_scope[y + 1] * m_scope[y + 1]*/));
int b = /*(nb_display_channels == 2 ) ? sqrt(w * hypot(data[1][2 * y + 0], data[1][2 * y + 1]))
:*/ a;
a = std::min(a, 255);
b = std::min(b, 255);

for (int i = 0; i < 2; i++)
{
m_spectrogram.setPixel(m_xPos, 2 * y + i, qRgb(a, b, (a + b) >> 1));
m_spectrogram.setPixel(m_xPos+1, 2 * y + i, qRgb(a, b, (a + b) >> 1));
}
}
++m_xPos;
if (++m_xPos >= m_currentWidth)
{
m_xPos = 0;
}

this->display(m_spectrogram);
}
56 changes: 56 additions & 0 deletions gui/applets/analyzer/SpectrogramAnalyzer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/****************************************************************************************
* Copyright (c) 2003-2005 Max Howell <max.howell@methylblue.com> *
* Copyright (c) 2005-2013 Mark Kretschmann <kretschmann@kde.org> *
* *
* 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. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Pulic License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/

#pragma once

#include "AnalyzerBase.h"

#include <QImage>
#include <QPixmap>
#include <QSharedPointer>
#include <QSize>

class QPalette;

class SpectrogramAnalyzer : public AnalyzerBase
{
public:
SpectrogramAnalyzer(QWidget *);

void transform(QVector<float> &s) override;

public slots:
void connectSignals() override;

protected:
void paintEvent(QPaintEvent*) override;
void resizeEvent(QResizeEvent * event) override;
void analyze(const QVector<float> &, uint32_t srate) override;

protected slots:
void display(const QImage&);

private:

std::atomic<int> m_xPos;
std::atomic<int> m_currentWidth;
QVector<float> m_scope, m_logScope; //so we don't create a vector every frame

QImage m_spectrogram;
QImage m_toBeDrawn;
};

1 change: 1 addition & 0 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ MainWindow::MainWindow(QWidget *parent)

connect(this->ui->actionASCII, &QAction::triggered, this, [this] { this->showAnalyzer(AnalyzerApplet::AnalyzerType::Ascii); });
connect(this->ui->actionBlocky, &QAction::triggered, this, [this] { this->showAnalyzer(AnalyzerApplet::AnalyzerType::Block); });
connect(this->ui->actionSpectrogram, &QAction::triggered, this, [this] { this->showAnalyzer(AnalyzerApplet::AnalyzerType::Spectrogram); });

connect(this->ui->actionSettings, &QAction::triggered, this, [this] { this->settingsView->show(); });
connect(this->settingsView, &ConfigDialog::accepted, this, &MainWindow::settingsDialogAccepted);
Expand Down
6 changes: 6 additions & 0 deletions gui/mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
</property>
<addaction name="actionASCII"/>
<addaction name="actionBlocky"/>
<addaction name="actionSpectrogram"/>
</widget>
<addaction name="menuDockWindows"/>
<addaction name="menuVisualization"/>
Expand Down Expand Up @@ -200,6 +201,11 @@
<string>&amp;Block</string>
</property>
</action>
<action name="actionSpectrogram">
<property name="text">
<string>&amp;Spectrogram</string>
</property>
</action>
<action name="actionASCII">
<property name="text">
<string>&amp;ASCII</string>
Expand Down

0 comments on commit e518da8

Please sign in to comment.