First try
This commit is contained in:
73
.gitignore
vendored
Normal file
73
.gitignore
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
47
device.cpp
Normal file
47
device.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "device.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QTimerEvent>
|
||||
|
||||
Device::Device(QObject *parent) :
|
||||
QIODevice(parent)
|
||||
{
|
||||
setOpenMode(QIODevice::WriteOnly);
|
||||
}
|
||||
|
||||
qint64 Device::readData(char *data, qint64 maxlen)
|
||||
{
|
||||
qFatal("oida");
|
||||
}
|
||||
|
||||
qint64 Device::writeData(const char *data, qint64 len)
|
||||
{
|
||||
Q_ASSERT(len % sizeof(SamplePair) == 0);
|
||||
emit samplesReceived(reinterpret_cast<const SamplePair*>(data),
|
||||
reinterpret_cast<const SamplePair*>(data + (len/sizeof(SamplePair))));
|
||||
return len;
|
||||
}
|
||||
|
||||
FakeDevice::FakeDevice(QObject *parent) :
|
||||
QObject(parent), m_timerId(startTimer(1000/60))
|
||||
{
|
||||
}
|
||||
|
||||
void FakeDevice::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == m_timerId)
|
||||
{
|
||||
std::array<SamplePair, 44100/60> samples;
|
||||
for (SamplePair &pair : samples)
|
||||
{
|
||||
pair.x = std::sin(m_dingsDesHaltHochZaehlt) * std::numeric_limits<qint16>::max();
|
||||
pair.y = std::cos(m_dingsDesHaltHochZaehlt) * std::numeric_limits<qint16>::max();
|
||||
m_dingsDesHaltHochZaehlt += 0.05;
|
||||
}
|
||||
|
||||
emit samplesReceived(samples.begin(), samples.end());
|
||||
}
|
||||
else
|
||||
QObject::timerEvent(event);
|
||||
}
|
43
device.h
Normal file
43
device.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QDebug>
|
||||
|
||||
#define qvoid void
|
||||
|
||||
struct SamplePair {
|
||||
qint16 x, y;
|
||||
};
|
||||
|
||||
class Device : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Device(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxlen) override;
|
||||
qint64 writeData(const char *data, qint64 len) override;
|
||||
};
|
||||
|
||||
class FakeDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FakeDevice(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
||||
|
||||
protected:
|
||||
qvoid timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
double m_dingsDesHaltHochZaehlt;
|
||||
const int m_timerId;
|
||||
};
|
40
main.cpp
Normal file
40
main.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <QApplication>
|
||||
#include <QAudioInput>
|
||||
|
||||
#include "device.h"
|
||||
#include "osciwidget.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
const auto info = []() -> const QAudioDeviceInfo {
|
||||
for (const auto &info : QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
|
||||
if (info.deviceName() == "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor")
|
||||
return info;
|
||||
Q_UNREACHABLE();
|
||||
}();
|
||||
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(44100);
|
||||
format.setChannelCount(2);
|
||||
format.setSampleSize(16);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
format.setCodec("audio/pcm");
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
|
||||
QAudioInput input(info, format);
|
||||
input.setBufferSize(44100/60*4);
|
||||
|
||||
OsciWidget widget;
|
||||
widget.show();
|
||||
|
||||
Device device;
|
||||
input.start(&device);
|
||||
QObject::connect(&device, &Device::samplesReceived, &widget, &OsciWidget::samplesReceived);
|
||||
|
||||
//FakeDevice fake;
|
||||
//QObject::connect(&fake, &FakeDevice::samplesReceived, &widget, &OsciWidget::samplesReceived);
|
||||
|
||||
return a.exec();
|
||||
}
|
15
oscilloscope.pro
Normal file
15
oscilloscope.pro
Normal file
@@ -0,0 +1,15 @@
|
||||
QT = core gui widgets multimedia
|
||||
|
||||
CONFIG += c++17
|
||||
DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
|
||||
|
||||
SOURCES += \
|
||||
device.cpp \
|
||||
main.cpp \
|
||||
osciwidget.cpp
|
||||
|
||||
HEADERS += \
|
||||
device.h \
|
||||
osciwidget.h
|
||||
|
||||
STATECHARTS +=
|
108
osciwidget.cpp
Normal file
108
osciwidget.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "osciwidget.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QLine>
|
||||
|
||||
namespace {
|
||||
constexpr auto framerate = 60;
|
||||
constexpr auto blend = 190;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto pythagoras(const T &dx, const T &dy)
|
||||
{
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
auto pythagoras(const QLine &line)
|
||||
{
|
||||
return pythagoras(line.dx(), line.dy());
|
||||
}
|
||||
|
||||
OsciWidget::OsciWidget(QWidget *parent) :
|
||||
QWidget(parent), m_timerId(startTimer(1000/framerate))
|
||||
{
|
||||
resizePixmap();
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
void OsciWidget::samplesReceived(const SamplePair *begin, const SamplePair *end)
|
||||
{
|
||||
QPainter painter;
|
||||
painter.begin(&m_pixmap);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Plus);
|
||||
|
||||
QPen pen;
|
||||
pen.setWidth(2);
|
||||
|
||||
for (auto i = begin; i < end; i++)
|
||||
{
|
||||
const qint32 x = (float(i->x) / std::numeric_limits<qint16>::max() / 2 * width() * 2) + (width() / 2);
|
||||
const qint32 y = (float(-i->y) / std::numeric_limits<qint16>::max() / 2 * height() * 2) + (height() / 2);
|
||||
const QPoint p{x,y};
|
||||
|
||||
if (Q_LIKELY(m_lastPoint.has_value()))
|
||||
{
|
||||
auto dist = pythagoras(QLine(*m_lastPoint, p));
|
||||
if (dist < 1)
|
||||
dist = 1;
|
||||
|
||||
pen.setColor(QColor(0, 1./dist*255, 0));
|
||||
painter.setPen(pen);
|
||||
|
||||
painter.drawLine(*m_lastPoint, p);
|
||||
}
|
||||
|
||||
m_lastPoint = p;
|
||||
}
|
||||
|
||||
painter.end();
|
||||
|
||||
if (m_timer.hasExpired(1000/framerate))
|
||||
{
|
||||
repaint();
|
||||
m_timer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
void OsciWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
painter.drawPixmap(0, 0, m_pixmap);
|
||||
painter.end();
|
||||
|
||||
painter.begin(&m_pixmap);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
|
||||
painter.drawPixmap(0, 0, m_fadeoutPixmap);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void OsciWidget::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == m_timerId)
|
||||
{
|
||||
//repaint();
|
||||
}
|
||||
else
|
||||
QWidget::timerEvent(event);
|
||||
}
|
||||
|
||||
void OsciWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
resizePixmap();
|
||||
}
|
||||
|
||||
void OsciWidget::resizePixmap()
|
||||
{
|
||||
m_pixmap = QPixmap(size());
|
||||
m_pixmap.fill(QColor());
|
||||
|
||||
m_fadeoutPixmap = QPixmap(size());
|
||||
m_fadeoutPixmap.fill(QColor(blend, blend, blend));
|
||||
}
|
40
osciwidget.h
Normal file
40
osciwidget.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QTimerEvent>
|
||||
#include <QPoint>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "device.h"
|
||||
|
||||
class OsciWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OsciWidget(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
void resizePixmap();
|
||||
|
||||
const int m_timerId;
|
||||
QPixmap m_pixmap;
|
||||
QPixmap m_fadeoutPixmap;
|
||||
|
||||
std::optional<QPoint> m_lastPoint;
|
||||
|
||||
QElapsedTimer m_timer;
|
||||
};
|
Reference in New Issue
Block a user