Merge pull request #2 from neuron303/master
Update to experimental state in master :D
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -27,6 +27,7 @@ Makefile*
|
|||||||
*.prl
|
*.prl
|
||||||
*.app
|
*.app
|
||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
|
moc_*.h
|
||||||
ui_*.h
|
ui_*.h
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
@@ -70,4 +71,5 @@ Thumbs.db
|
|||||||
# --------
|
# --------
|
||||||
*.dll
|
*.dll
|
||||||
*.exe
|
*.exe
|
||||||
|
oscilloscope
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
os: linux
|
os: linux
|
||||||
sudo: false
|
sudo: false
|
||||||
dist: trusty
|
dist: bionic
|
||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
@@ -12,6 +12,11 @@ cache:
|
|||||||
- ~/.ccache
|
- ~/.ccache
|
||||||
- qt5
|
- qt5
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev
|
||||||
|
- sudo apt-get install -y libasound2-dev
|
||||||
|
- sudo apt-get install -y libpulse-dev
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- mkdir -p qt5
|
- mkdir -p qt5
|
||||||
- if [ ! -d qt5/.git ] ; then rm qt5 -Rf ; git clone --branch=5.12.5 git://code.qt.io/qt/qt5.git ; fi
|
- if [ ! -d qt5/.git ] ; then rm qt5 -Rf ; git clone --branch=5.12.5 git://code.qt.io/qt/qt5.git ; fi
|
||||||
|
@@ -4,7 +4,6 @@
|
|||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <QAudioInput>
|
#include <QAudioInput>
|
||||||
|
|
||||||
namespace {
|
|
||||||
//! private helper to allow QAudioInput to write to a io device
|
//! private helper to allow QAudioInput to write to a io device
|
||||||
class AudioDeviceHelper : public QIODevice
|
class AudioDeviceHelper : public QIODevice
|
||||||
{
|
{
|
||||||
@@ -18,14 +17,13 @@ private:
|
|||||||
AudioDevice &m_audioDevice;
|
AudioDevice &m_audioDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioDevicePrivate {
|
class AudioDevice::AudioDevicePrivate {
|
||||||
public:
|
public:
|
||||||
AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format);
|
AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format);
|
||||||
|
|
||||||
AudioDeviceHelper helper;
|
AudioDeviceHelper helper;
|
||||||
QAudioInput input;
|
QAudioInput input;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
AudioDevice::AudioDevice(QObject *parent) :
|
AudioDevice::AudioDevice(QObject *parent) :
|
||||||
BaseDevice{parent}
|
BaseDevice{parent}
|
||||||
@@ -58,9 +56,6 @@ void AudioDevice::stop()
|
|||||||
m_private = nullptr;
|
m_private = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
AudioDeviceHelper::AudioDeviceHelper(AudioDevice &audioDevice, QObject *parent) :
|
AudioDeviceHelper::AudioDeviceHelper(AudioDevice &audioDevice, QObject *parent) :
|
||||||
QIODevice{parent}, m_audioDevice(audioDevice)
|
QIODevice{parent}, m_audioDevice(audioDevice)
|
||||||
{
|
{
|
||||||
@@ -84,8 +79,7 @@ qint64 AudioDeviceHelper::writeData(const char *data, qint64 len)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevicePrivate::AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
AudioDevice::AudioDevicePrivate::AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
||||||
helper{audioDevice}, input{audioDeviceInfo, format}
|
helper{audioDevice}, input{audioDeviceInfo, format}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// forward declares
|
// forward declares
|
||||||
namespace { class AudioDevicePrivate; }
|
|
||||||
class QAudioInput;
|
class QAudioInput;
|
||||||
|
|
||||||
class AudioDevice : public BaseDevice
|
class AudioDevice : public BaseDevice
|
||||||
@@ -31,6 +30,7 @@ public:
|
|||||||
void setDevice(const QAudioDeviceInfo &device) { Q_ASSERT(!running()); m_device = device; }
|
void setDevice(const QAudioDeviceInfo &device) { Q_ASSERT(!running()); m_device = device; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class AudioDevicePrivate;
|
||||||
std::unique_ptr<AudioDevicePrivate> m_private;
|
std::unique_ptr<AudioDevicePrivate> m_private;
|
||||||
|
|
||||||
int m_samplerate;
|
int m_samplerate;
|
||||||
|
@@ -3,8 +3,6 @@
|
|||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QAudioOutput>
|
#include <QAudioOutput>
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
//! private helper to allow QAudioOutput to read from a io device
|
//! private helper to allow QAudioOutput to read from a io device
|
||||||
class BaseToneGeneratorHelper : public QIODevice
|
class BaseToneGeneratorHelper : public QIODevice
|
||||||
{
|
{
|
||||||
@@ -18,7 +16,7 @@ private:
|
|||||||
BaseToneGenerator &m_generator;
|
BaseToneGenerator &m_generator;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BaseToneGeneratorPrivate
|
class BaseToneGenerator::BaseToneGeneratorPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format);
|
BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format);
|
||||||
@@ -28,8 +26,6 @@ public:
|
|||||||
QAudioOutput output;
|
QAudioOutput output;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseToneGenerator::BaseToneGenerator() = default;
|
BaseToneGenerator::BaseToneGenerator() = default;
|
||||||
|
|
||||||
BaseToneGenerator::~BaseToneGenerator() = default;
|
BaseToneGenerator::~BaseToneGenerator() = default;
|
||||||
@@ -58,7 +54,6 @@ void BaseToneGenerator::stop()
|
|||||||
m_private = nullptr;
|
m_private = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
BaseToneGeneratorHelper::BaseToneGeneratorHelper(BaseToneGenerator &generator, QObject *parent) :
|
BaseToneGeneratorHelper::BaseToneGeneratorHelper(BaseToneGenerator &generator, QObject *parent) :
|
||||||
QIODevice{parent}, m_generator{generator}
|
QIODevice{parent}, m_generator{generator}
|
||||||
{
|
{
|
||||||
@@ -80,8 +75,7 @@ qint64 BaseToneGeneratorHelper::writeData(const char *data, qint64 len)
|
|||||||
qFatal("writing is not allowed!");
|
qFatal("writing is not allowed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseToneGeneratorPrivate::BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
BaseToneGenerator::BaseToneGeneratorPrivate::BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
||||||
helper{generator}, output{audioDeviceInfo, format}
|
helper{generator}, output{audioDeviceInfo, format}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@@ -9,9 +9,6 @@
|
|||||||
// local includes
|
// local includes
|
||||||
#include "oscicommon.h"
|
#include "oscicommon.h"
|
||||||
|
|
||||||
// forward declares
|
|
||||||
namespace { class BaseToneGeneratorPrivate; }
|
|
||||||
|
|
||||||
class BaseToneGenerator
|
class BaseToneGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -31,6 +28,7 @@ public:
|
|||||||
virtual std::size_t fill(SamplePair *begin, SamplePair *end) = 0;
|
virtual std::size_t fill(SamplePair *begin, SamplePair *end) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class BaseToneGeneratorPrivate;
|
||||||
std::unique_ptr<BaseToneGeneratorPrivate> m_private;
|
std::unique_ptr<BaseToneGeneratorPrivate> m_private;
|
||||||
|
|
||||||
int m_samplerate;
|
int m_samplerate;
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
// system includes
|
// local includes
|
||||||
#include <stdexcept>
|
#include "audiodevice.h"
|
||||||
|
#include "debugtonegenerator.h"
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -11,14 +12,13 @@
|
|||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
// local includes
|
// system includes
|
||||||
#include "audiodevice.h"
|
#include <stdexcept>
|
||||||
#include "debugtonegenerator.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int samplerates[] = { 44100, 48000, 96000, 192000 };
|
constexpr int samplerates[] = { 44100, 48000, 96000, 192000 };
|
||||||
|
|
||||||
constexpr int refreshrates[] = { 15, 30, 50, 60 };
|
constexpr int refreshrates[] = { 1, 15, 30, 50, 60 };
|
||||||
|
|
||||||
constexpr int zoomlevels[] = { 50, 75, 100, 200, 400, 800 };
|
constexpr int zoomlevels[] = { 50, 75, 100, 200, 400, 800 };
|
||||||
|
|
||||||
@@ -117,17 +117,18 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
connect(&m_zoomlevelsGroup, &QActionGroup::triggered, this, &MainWindow::zoomChanged);
|
connect(&m_zoomlevelsGroup, &QActionGroup::triggered, this, &MainWindow::zoomChanged);
|
||||||
|
|
||||||
//setting up menu Debug
|
//setting up menu Debug
|
||||||
connect(m_ui->actionToneGenerator, &QAction::triggered, this, &MainWindow::startGenerator);
|
connect(m_ui->actionToneGenerator, &QAction::triggered, this, &MainWindow::startStopGenerator);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto widgetAction = new QWidgetAction(this);
|
auto widgetAction = new QWidgetAction(this);
|
||||||
auto widget = new QWidget;
|
auto widget = new QWidget;
|
||||||
auto layout = new QFormLayout(widget);
|
auto layout = new QFormLayout(widget);
|
||||||
{
|
{
|
||||||
auto input = new QSpinBox;
|
auto input = new QDoubleSpinBox;
|
||||||
input->setRange(0, 255);
|
input->setRange(0, 10000.0);
|
||||||
|
input->setSingleStep(1.0);
|
||||||
input->setValue(m_ui->widget->afterglow());
|
input->setValue(m_ui->widget->afterglow());
|
||||||
connect(input, qOverload<int>(&QSpinBox::valueChanged), m_ui->widget, &OsciWidget::setAfterglow);
|
connect(input, qOverload<double>(&QDoubleSpinBox::valueChanged), m_ui->widget, &OsciWidget::setAfterglow);
|
||||||
layout->addRow(tr("Afterglow:"), input);
|
layout->addRow(tr("Afterglow:"), input);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -199,9 +200,13 @@ void MainWindow::zoomChanged()
|
|||||||
m_ui->widget->setFactor(zoomlevel/100.f);
|
m_ui->widget->setFactor(zoomlevel/100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::startGenerator()
|
void MainWindow::startStopGenerator()
|
||||||
{
|
{
|
||||||
m_generator = nullptr;
|
if(m_generator){
|
||||||
|
m_generator = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_generator = std::make_unique<DebugToneGenerator>();
|
m_generator = std::make_unique<DebugToneGenerator>();
|
||||||
m_generator->setDevice(m_outputDevices.at(m_outputDeviceGroup.actions().indexOf(m_outputDeviceGroup.checkedAction())));
|
m_generator->setDevice(m_outputDevices.at(m_outputDeviceGroup.actions().indexOf(m_outputDeviceGroup.checkedAction())));
|
||||||
m_generator->setSamplerate(samplerate());
|
m_generator->setSamplerate(samplerate());
|
||||||
|
@@ -28,7 +28,7 @@ private slots:
|
|||||||
void stop();
|
void stop();
|
||||||
void refreshRateChanged();
|
void refreshRateChanged();
|
||||||
void zoomChanged();
|
void zoomChanged();
|
||||||
void startGenerator();
|
void startStopGenerator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int samplerate() const;
|
int samplerate() const;
|
||||||
|
193
osciwidget.cpp
193
osciwidget.cpp
@@ -1,19 +1,27 @@
|
|||||||
#include "osciwidget.h"
|
#include "osciwidget.h"
|
||||||
|
|
||||||
// system includes
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QLineF>
|
#include <QLineF>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QTimerEvent>
|
#include <QTimerEvent>
|
||||||
|
|
||||||
OsciWidget::OsciWidget(QWidget *parent) :
|
// system includes
|
||||||
QOpenGLWidget{parent},
|
#include <cmath>
|
||||||
m_redrawTimerId(startTimer(1000/m_fps))
|
|
||||||
|
qint32 framesForDuration(qint64 duration){
|
||||||
|
return qint32(44100 * duration / 1000000LL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OsciWidget::OsciWidget(QWidget *parent)
|
||||||
|
: QOpenGLWidget{parent}
|
||||||
|
, m_bufferOffset{m_buffer.begin()}
|
||||||
|
, m_lastBufferUpdate{0}
|
||||||
|
, m_redrawTimerId(startTimer(1000/m_fps, Qt::PreciseTimer))
|
||||||
{
|
{
|
||||||
m_statsTimer.start();
|
m_statsTimer.start();
|
||||||
|
m_globalTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int OsciWidget::lightspeed() const
|
int OsciWidget::lightspeed() const
|
||||||
@@ -27,10 +35,20 @@ void OsciWidget::setFps(int fps)
|
|||||||
|
|
||||||
m_fps = fps;
|
m_fps = fps;
|
||||||
|
|
||||||
m_redrawTimerId = startTimer(1000/m_fps);
|
m_redrawTimerId = startTimer(1000/m_fps, Qt::PreciseTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OsciWidget::setLightspeed(int lightspeed) {
|
void OsciWidget::setAfterglow(float afterglow)
|
||||||
|
{
|
||||||
|
m_decayTime = afterglow;
|
||||||
|
// percentage of the image that should be visible after one second
|
||||||
|
// i.e. factor^fps=afterglow -> factor = afterglow^(1/fps)
|
||||||
|
// i.e. factor^(fps*persistence)=1/e -> factor = 1/e^(1/(fps*persistence/1000.0))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OsciWidget::setLightspeed(int lightspeed)
|
||||||
|
{
|
||||||
const auto temp = (float(lightspeed)/20.f);
|
const auto temp = (float(lightspeed)/20.f);
|
||||||
m_lightspeed = temp*temp*temp;
|
m_lightspeed = temp*temp*temp;
|
||||||
qDebug() << m_lightspeed;
|
qDebug() << m_lightspeed;
|
||||||
@@ -42,7 +60,26 @@ void OsciWidget::renderSamples(const SamplePair *begin, const SamplePair *end)
|
|||||||
|
|
||||||
m_samplesCounter += std::distance(begin, end);
|
m_samplesCounter += std::distance(begin, end);
|
||||||
|
|
||||||
|
auto offset = std::distance(m_buffer.begin(), m_bufferOffset);
|
||||||
|
|
||||||
|
if(m_globalTimer.elapsed()-m_lastBufferUpdate > 5000)
|
||||||
|
{
|
||||||
|
//qDebug() << "deleting: " << m_bufferOffset - m_buffer.begin() << m_buffer.size();
|
||||||
|
// Delete drawn frames
|
||||||
|
//m_buffer.erase(m_buffer.begin(), m_bufferOffset);
|
||||||
|
|
||||||
|
// TODO improve by drawing remaining(undrawn) buffer instead
|
||||||
|
drawBuffer(m_bufferOffset, m_buffer.end(), QColor(0, 255, 0));
|
||||||
|
m_buffer.clear();
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
m_lastBufferUpdate = m_globalTimer.elapsed();
|
||||||
|
}
|
||||||
|
//qDebug () << " inserting " << std::distance(begin, end);
|
||||||
m_buffer.insert(m_buffer.end(), begin, end);
|
m_buffer.insert(m_buffer.end(), begin, end);
|
||||||
|
m_bufferOffset = m_buffer.begin() + offset;
|
||||||
|
//m_bufferTimer.restart();
|
||||||
|
//qDebug() << m_statsTimer.elapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OsciWidget::paintEvent(QPaintEvent *event)
|
void OsciWidget::paintEvent(QPaintEvent *event)
|
||||||
@@ -52,75 +89,115 @@ void OsciWidget::paintEvent(QPaintEvent *event)
|
|||||||
m_frameCounter++;
|
m_frameCounter++;
|
||||||
if (m_statsTimer.hasExpired(1000))
|
if (m_statsTimer.hasExpired(1000))
|
||||||
{
|
{
|
||||||
emit statusUpdate(QString("%0FPS (%1 callbacks, %2 samples, %3 avg per callback)").arg(m_frameCounter).arg(m_callbacksCounter).arg(m_samplesCounter).arg(m_callbacksCounter>0?m_samplesCounter/m_callbacksCounter:0));
|
emit statusUpdate(QString("%0FPS (%1 callbacks, %2 samples, %3 avg per callback, bufferSize %4, elapsed %5)").arg(m_frameCounter).arg(m_callbacksCounter).arg(m_samplesCounter).arg(m_callbacksCounter>0?m_samplesCounter/m_callbacksCounter:0).arg(m_buffer.size()).arg(m_globalTimer.elapsed()));
|
||||||
m_frameCounter = 0;
|
m_frameCounter = 0;
|
||||||
m_callbacksCounter = 0;
|
m_callbacksCounter = 0;
|
||||||
m_samplesCounter = 0;
|
m_samplesCounter = 0;
|
||||||
m_statsTimer.restart();
|
m_statsTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.drawPixmap(0, 0, m_pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OsciWidget::darkenFrame()
|
||||||
|
{
|
||||||
|
QPainter painter(&m_pixmap);
|
||||||
|
|
||||||
|
|
||||||
|
//auto afterglowColor = 255 * pow(m_decayTime, 1.0/m_fps);
|
||||||
|
auto afterglowFactor = pow(exp(-1), 1000.0/m_decayTime/m_fps);
|
||||||
|
auto afterglowColor = static_cast<int>(255*afterglowFactor);
|
||||||
|
//qDebug() << afterglowFactor;
|
||||||
|
//QColor blendColor;
|
||||||
|
//black.setAlpha(afterglowColor);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
|
||||||
|
painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor));
|
||||||
|
painter.drawRect(m_pixmap.rect());
|
||||||
|
//m_pixmap.fill(Qt::black);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OsciWidget::drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffer::iterator &end, QColor color)
|
||||||
|
{
|
||||||
|
QPainter painter(&m_pixmap);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter.translate(m_pixmap.width()/2, m_pixmap.height()/2);
|
||||||
|
painter.scale(m_factor * m_pixmap.width() / 2.0, m_factor * m_pixmap.height() / 2.0);
|
||||||
|
|
||||||
|
QPen pen;
|
||||||
|
pen.setCosmetic(true); // let pen be scale invariant
|
||||||
|
pen.setWidth(2);
|
||||||
|
// This prevents most of the overlapping when drawing lines from and to the same points
|
||||||
|
pen.setCapStyle(Qt::FlatCap);
|
||||||
|
|
||||||
|
for (;bufferPos < end; ++bufferPos)
|
||||||
|
{
|
||||||
|
const auto &frame = *bufferPos;
|
||||||
|
|
||||||
|
const QPointF p{
|
||||||
|
float(frame.first) / std::numeric_limits<qint16>::max(),
|
||||||
|
float(-frame.second) / std::numeric_limits<qint16>::max()
|
||||||
|
};
|
||||||
|
|
||||||
|
const QLineF line(m_lastPoint, p);
|
||||||
|
|
||||||
|
auto beamBrightness = std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1));
|
||||||
|
|
||||||
|
// time from bufferPos to end in ms
|
||||||
|
double time = 1000.0 * std::distance(bufferPos, end) / 44100.0;
|
||||||
|
|
||||||
|
auto beamDecay = exp(-time/m_decayTime);
|
||||||
|
// HACK: gamma rolloff the brightness to make it look better (make configurable?)
|
||||||
|
auto beamVisibility = pow(beamBrightness, 2.0)*beamDecay;
|
||||||
|
|
||||||
|
QColor drawColor(color);
|
||||||
|
drawColor.setAlphaF(beamVisibility);
|
||||||
|
//QColor drawColor(color.red()*beamVisibility, color.green()*beamVisibility, color.blue()*beamVisibility);
|
||||||
|
|
||||||
|
pen.setColor(drawColor);
|
||||||
|
painter.setPen(pen);
|
||||||
|
//painter.setOpacity(beamVisibility);
|
||||||
|
painter.drawLine(m_lastPoint, p);
|
||||||
|
//painter.drawLine(m_lastPoint, m_lastPoint);
|
||||||
|
//painter.setPen(pen);
|
||||||
|
//painter.drawPoint(m_lastPoint);
|
||||||
|
|
||||||
|
m_lastPoint = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OsciWidget::resizeDrawBuffer()
|
||||||
|
{
|
||||||
if (m_pixmap.size() != size())
|
if (m_pixmap.size() != size())
|
||||||
{
|
{
|
||||||
m_pixmap = QPixmap(size());
|
m_pixmap = QPixmap(size());
|
||||||
m_pixmap.fill(Qt::black);
|
m_pixmap.fill(Qt::black);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QPainter painter;
|
void OsciWidget::updateDrawBuffer()
|
||||||
painter.begin(&m_pixmap);
|
{
|
||||||
|
// If there is no new data do not update
|
||||||
|
if(m_buffer.empty()) return;
|
||||||
|
|
||||||
// darkening last frame
|
resizeDrawBuffer();
|
||||||
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
|
darkenFrame();
|
||||||
painter.setPen({});
|
// decay time is the time it needs to decay to 1/e ~ 36,7%
|
||||||
painter.setBrush(QColor(m_afterglow, m_afterglow, m_afterglow));
|
|
||||||
painter.drawRect(m_pixmap.rect());
|
|
||||||
|
|
||||||
// drawing new lines ontop
|
auto duration = 1000*(m_globalTimer.elapsed()-m_lastBufferUpdate);
|
||||||
QPen pen;
|
size_t framesOffset = framesForDuration(duration);
|
||||||
pen.setWidth(2);
|
//qDebug() << framesOffset << m_buffer.size()-framesOffset << m_bufferOffset - m_buffer.begin();
|
||||||
pen.setColor(QColor(0, 255, 0));
|
|
||||||
painter.setPen(pen);
|
|
||||||
painter.translate(m_pixmap.width()/2, m_pixmap.height()/2);
|
|
||||||
painter.setCompositionMode(QPainter::CompositionMode_Plus);
|
|
||||||
|
|
||||||
const auto pointToCoordinates = [width=m_pixmap.width()/2,height=m_pixmap.height()/2,factor=m_factor](const QPointF &point)
|
auto bufferEnd = m_buffer.begin() + std::min(framesOffset, m_buffer.size());
|
||||||
{
|
drawBuffer(m_bufferOffset, bufferEnd, QColor(0, 255, 0));
|
||||||
return QPoint{
|
|
||||||
int(point.x() * factor * width),
|
|
||||||
int(point.y() * factor * height)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto &i : m_buffer)
|
|
||||||
{
|
|
||||||
const QPointF p{
|
|
||||||
float(i.first) / std::numeric_limits<qint16>::max(),
|
|
||||||
float(-i.second) / std::numeric_limits<qint16>::max()
|
|
||||||
};
|
|
||||||
|
|
||||||
const QLineF line(m_lastPoint, p);
|
|
||||||
|
|
||||||
painter.setOpacity(std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1)));
|
|
||||||
|
|
||||||
painter.drawLine(pointToCoordinates(m_lastPoint), pointToCoordinates(p));
|
|
||||||
|
|
||||||
m_lastPoint = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
painter.setOpacity(1);
|
|
||||||
painter.resetTransform();
|
|
||||||
|
|
||||||
painter.end();
|
|
||||||
|
|
||||||
painter.begin(this);
|
|
||||||
painter.drawPixmap(0, 0, m_pixmap);
|
|
||||||
painter.end();
|
|
||||||
|
|
||||||
m_buffer.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OsciWidget::timerEvent(QTimerEvent *event)
|
void OsciWidget::timerEvent(QTimerEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::timerEvent(event);
|
QWidget::timerEvent(event);
|
||||||
if (event->timerId() == m_redrawTimerId)
|
if (event->timerId() == m_redrawTimerId){
|
||||||
|
updateDrawBuffer();
|
||||||
repaint();
|
repaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
23
osciwidget.h
23
osciwidget.h
@@ -21,7 +21,7 @@ public:
|
|||||||
|
|
||||||
float factor() const { return m_factor; }
|
float factor() const { return m_factor; }
|
||||||
int fps() const { return m_fps; }
|
int fps() const { return m_fps; }
|
||||||
int afterglow() const { return m_afterglow; }
|
float afterglow() const { return m_decayTime; }
|
||||||
int lightspeed() const;
|
int lightspeed() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -30,7 +30,7 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
void setFactor(float factor) { m_factor = factor; }
|
void setFactor(float factor) { m_factor = factor; }
|
||||||
void setFps(int fps);
|
void setFps(int fps);
|
||||||
void setAfterglow(int afterglow) { m_afterglow = afterglow; }
|
void setAfterglow(float afterglow);
|
||||||
void setLightspeed(int lightspeed);
|
void setLightspeed(int lightspeed);
|
||||||
|
|
||||||
void renderSamples(const SamplePair *begin, const SamplePair *end);
|
void renderSamples(const SamplePair *begin, const SamplePair *end);
|
||||||
@@ -40,16 +40,27 @@ protected:
|
|||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float m_factor{2.f};
|
void updateDrawBuffer();
|
||||||
int m_fps{30}, m_afterglow{175};
|
|
||||||
float m_lightspeed{35.f};
|
|
||||||
|
|
||||||
std::vector<SamplePair> m_buffer;
|
private:
|
||||||
|
float m_factor{1.f};
|
||||||
|
int m_fps{60};
|
||||||
|
float m_decayTime{29.0};
|
||||||
|
float m_lightspeed{18.f};
|
||||||
|
|
||||||
|
typedef std::vector<SamplePair> SampleBuffer;
|
||||||
|
SampleBuffer m_buffer;
|
||||||
|
SampleBuffer::iterator m_bufferOffset;
|
||||||
|
|
||||||
int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0};
|
int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0};
|
||||||
QElapsedTimer m_statsTimer;
|
QElapsedTimer m_statsTimer;
|
||||||
|
QElapsedTimer m_globalTimer;
|
||||||
|
qint64 m_lastBufferUpdate;
|
||||||
|
|
||||||
int m_redrawTimerId;
|
int m_redrawTimerId;
|
||||||
QPointF m_lastPoint;
|
QPointF m_lastPoint;
|
||||||
QPixmap m_pixmap;
|
QPixmap m_pixmap;
|
||||||
|
void darkenFrame();
|
||||||
|
void drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffer::iterator &end, QColor color);
|
||||||
|
void resizeDrawBuffer();
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user