Improved controls with menus
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <QAudioInput>
|
#include <QAudioInput>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
//! private helper to allow QAudioInput to write to a io device
|
//! private helper to allow QAudioInput to write to a io device
|
||||||
@@ -10,6 +11,7 @@ class AudioDeviceHelper : public QIODevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AudioDeviceHelper(AudioDevice &audioDevice);
|
explicit AudioDeviceHelper(AudioDevice &audioDevice);
|
||||||
|
~AudioDeviceHelper();
|
||||||
|
|
||||||
qint64 readData(char *data, qint64 maxlen) override;
|
qint64 readData(char *data, qint64 maxlen) override;
|
||||||
qint64 writeData(const char *data, qint64 len) override;
|
qint64 writeData(const char *data, qint64 len) override;
|
||||||
@@ -17,11 +19,26 @@ public:
|
|||||||
private:
|
private:
|
||||||
AudioDevice &m_audioDevice;
|
AudioDevice &m_audioDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AudioDevicePrivate {
|
||||||
|
AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
||||||
|
helper(audioDevice), input(audioDeviceInfo, format)
|
||||||
|
{
|
||||||
|
qDebug() << audioDeviceInfo.deviceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
~AudioDevicePrivate()
|
||||||
|
{
|
||||||
|
qDebug() << "called";
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDeviceHelper helper;
|
||||||
|
QAudioInput input;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevice::AudioDevice(QObject *parent) :
|
AudioDevice::AudioDevice(QObject *parent) :
|
||||||
BaseDevice{parent},
|
BaseDevice{parent}
|
||||||
m_helper(std::make_unique<AudioDeviceHelper>(*this))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +46,8 @@ AudioDevice::~AudioDevice() = default;
|
|||||||
|
|
||||||
void AudioDevice::start()
|
void AudioDevice::start()
|
||||||
{
|
{
|
||||||
|
qDebug() << m_device.deviceName();
|
||||||
|
|
||||||
QAudioFormat format;
|
QAudioFormat format;
|
||||||
format.setSampleRate(m_samplerate);
|
format.setSampleRate(m_samplerate);
|
||||||
format.setChannelCount(2);
|
format.setChannelCount(2);
|
||||||
@@ -37,14 +56,15 @@ void AudioDevice::start()
|
|||||||
format.setCodec("audio/pcm");
|
format.setCodec("audio/pcm");
|
||||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
|
|
||||||
m_input = std::make_unique<QAudioInput>(m_device, format);
|
m_private = std::make_unique<AudioDevicePrivate>(*this, m_device, format);
|
||||||
m_input->start(m_helper.get());
|
m_private->input.start(&m_private->helper);
|
||||||
m_input->setBufferSize(m_samplerate/m_framerate*sizeof(qint16)*2);
|
//m_private->input.setBufferSize(m_samplerate/m_framerate*sizeof(qint16)*2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevice::stop()
|
void AudioDevice::stop()
|
||||||
{
|
{
|
||||||
m_input = nullptr;
|
qDebug() << "called";
|
||||||
|
m_private = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -54,9 +74,15 @@ AudioDeviceHelper::AudioDeviceHelper(AudioDevice &audioDevice) :
|
|||||||
QIODevice(&audioDevice),
|
QIODevice(&audioDevice),
|
||||||
m_audioDevice(audioDevice)
|
m_audioDevice(audioDevice)
|
||||||
{
|
{
|
||||||
|
qDebug() << "called";
|
||||||
setOpenMode(QIODevice::WriteOnly);
|
setOpenMode(QIODevice::WriteOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioDeviceHelper::~AudioDeviceHelper()
|
||||||
|
{
|
||||||
|
qDebug() << "called";
|
||||||
|
}
|
||||||
|
|
||||||
qint64 AudioDeviceHelper::readData(char *data, qint64 maxlen)
|
qint64 AudioDeviceHelper::readData(char *data, qint64 maxlen)
|
||||||
{
|
{
|
||||||
Q_UNUSED(data)
|
Q_UNUSED(data)
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// forward declares
|
// forward declares
|
||||||
namespace { class AudioDeviceHelper; }
|
namespace { class AudioDevicePrivate; }
|
||||||
class QAudioInput;
|
class QAudioInput;
|
||||||
|
|
||||||
class AudioDevice : public BaseDevice
|
class AudioDevice : public BaseDevice
|
||||||
@@ -22,24 +22,18 @@ public:
|
|||||||
|
|
||||||
void start() override;
|
void start() override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
bool running() const override { return m_input != nullptr; }
|
bool running() const override { return m_private != nullptr; }
|
||||||
|
|
||||||
int samplerate() const override { return m_samplerate; }
|
int samplerate() const override { return m_samplerate; }
|
||||||
void setSamplerate(int samplerate) override { Q_ASSERT(!running()); m_samplerate = samplerate; }
|
void setSamplerate(int samplerate) override { Q_ASSERT(!running()); m_samplerate = samplerate; }
|
||||||
|
|
||||||
int framerate() const override { return m_framerate; }
|
|
||||||
void setFramerate(int framerate) override { Q_ASSERT(!running()); m_framerate = framerate; }
|
|
||||||
|
|
||||||
const auto &device() const { return m_device; }
|
const auto &device() const { return m_device; }
|
||||||
void setDevice(const QAudioDeviceInfo &device) { Q_ASSERT(!running()); m_device = device; }
|
void setDevice(const QAudioDeviceInfo &device) { Q_ASSERT(!running()); m_device = device; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::unique_ptr<AudioDeviceHelper> m_helper;
|
std::unique_ptr<AudioDevicePrivate> m_private;
|
||||||
|
|
||||||
std::unique_ptr<QAudioInput> m_input;
|
|
||||||
|
|
||||||
int m_samplerate;
|
int m_samplerate;
|
||||||
int m_framerate;
|
|
||||||
|
|
||||||
QAudioDeviceInfo m_device;
|
QAudioDeviceInfo m_device;
|
||||||
};
|
};
|
||||||
|
@@ -18,9 +18,6 @@ public:
|
|||||||
virtual int samplerate() const = 0;
|
virtual int samplerate() const = 0;
|
||||||
virtual void setSamplerate(int samplerate) = 0;
|
virtual void setSamplerate(int samplerate) = 0;
|
||||||
|
|
||||||
virtual int framerate() const = 0;
|
|
||||||
virtual void setFramerate(int framerate) = 0;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
||||||
};
|
};
|
||||||
|
@@ -19,8 +19,8 @@ public:
|
|||||||
int samplerate() const override { return m_samplerate; }
|
int samplerate() const override { return m_samplerate; }
|
||||||
void setSamplerate(int samplerate) override { Q_ASSERT(!running()); m_samplerate = samplerate; }
|
void setSamplerate(int samplerate) override { Q_ASSERT(!running()); m_samplerate = samplerate; }
|
||||||
|
|
||||||
int framerate() const override { return m_framerate; }
|
int framerate() const { return m_framerate; }
|
||||||
void setFramerate(int framerate) override { Q_ASSERT(!running()); m_framerate = framerate; }
|
void setFramerate(int framerate) { Q_ASSERT(!running()); m_framerate = framerate; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
170
mainwindow.cpp
170
mainwindow.cpp
@@ -6,88 +6,164 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "audiodevice.h"
|
#include "audiodevice.h"
|
||||||
#include "fakedevice.h"
|
#include "fakedevice.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int samplerates[] = { 44100, 48000, 96000, 192000 };
|
||||||
|
|
||||||
|
constexpr int refreshrates[] = { 15, 30, 50, 60 };
|
||||||
|
|
||||||
|
constexpr int zoomlevels[] = { 50, 75, 100, 200, 400, 800 };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void setActionsEnabled(const T &actions, bool enabled)
|
||||||
|
{
|
||||||
|
for(auto action : actions)
|
||||||
|
action->setEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow{parent},
|
QMainWindow{parent},
|
||||||
m_ui{std::make_unique<Ui::MainWindow>()},
|
m_ui{std::make_unique<Ui::MainWindow>()},
|
||||||
m_audioDevices{QAudioDeviceInfo::availableDevices(QAudio::AudioInput)},
|
m_audioDevices{QAudioDeviceInfo::availableDevices(QAudio::AudioInput)},
|
||||||
m_input{std::make_unique<AudioDevice>()}
|
m_statusLabel{*new QLabel}
|
||||||
//m_input{std::make_unique<FakeDevice>()}
|
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
connect(m_input.get(), &BaseDevice::samplesReceived, m_ui->widget, &OsciWidget::renderSamples);
|
m_ui->statusbar->addWidget(&m_statusLabel);
|
||||||
|
|
||||||
|
connect(m_ui->widget, &OsciWidget::statusUpdate, &m_statusLabel, &QLabel::setText);
|
||||||
|
|
||||||
|
// setting up menu File
|
||||||
|
connect(m_ui->actionStart, &QAction::triggered, this, &MainWindow::start);
|
||||||
|
connect(m_ui->actionStop, &QAction::triggered, this, &MainWindow::stop);
|
||||||
|
m_ui->action_Quit->setShortcut(QKeySequence::Quit);
|
||||||
|
|
||||||
|
// setting up menu Devices
|
||||||
for (const auto &device : m_audioDevices)
|
for (const auto &device : m_audioDevices)
|
||||||
{
|
{
|
||||||
auto name = device.deviceName();
|
auto name = device.deviceName();
|
||||||
m_ui->comboBoxDevices->addItem(name);
|
const auto action = m_ui->menu_Device->addAction(name);
|
||||||
|
action->setCheckable(true);
|
||||||
|
m_deviceGroup.addAction(action);
|
||||||
|
|
||||||
// Select last element containing monitor if available
|
// Select last element containing monitor if available
|
||||||
if(name.contains("monitor"))
|
if(name.contains("monitor"))
|
||||||
{
|
action->setChecked(true);
|
||||||
m_ui->comboBoxDevices->setCurrentIndex(m_ui->comboBoxDevices->count()-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto samplerate : { 44100, 48000, 96000, 192000 })
|
// setting up menu Samplerates
|
||||||
m_ui->comboBoxSamplerate->addItem(tr("%0").arg(samplerate), samplerate);
|
for (const auto samplerate : samplerates)
|
||||||
|
|
||||||
connect(m_ui->pushButtonToggle, &QAbstractButton::pressed, this, &MainWindow::toggle);
|
|
||||||
|
|
||||||
for (const auto framerate : {15, 30, 50, 60})
|
|
||||||
m_ui->comboBoxFps->addItem(tr("%0 FPS").arg(framerate), framerate);
|
|
||||||
|
|
||||||
connect(m_ui->comboBoxFps, qOverload<int>(&QComboBox::currentIndexChanged), m_ui->widget, [this](){
|
|
||||||
m_ui->widget->setFps(m_ui->comboBoxFps->currentData().toInt());
|
|
||||||
});
|
|
||||||
|
|
||||||
auto buttonGroup = new QButtonGroup;
|
|
||||||
buttonGroup->setExclusive(true);
|
|
||||||
for (auto factor : { .5f, 1.f, 2.f, 4.f, 8.f })
|
|
||||||
{
|
{
|
||||||
auto radioButton = new QRadioButton(QString::number(factor));
|
auto action = m_ui->menu_Samplerate->addAction(tr("%0").arg(samplerate));
|
||||||
connect(radioButton, &QRadioButton::pressed, this, [factor,&widget=*m_ui->widget](){
|
action->setCheckable(true);
|
||||||
widget.setFactor(factor);
|
m_samplerateGroup.addAction(action);
|
||||||
});
|
|
||||||
m_ui->horizontalLayout->addWidget(radioButton);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ui->comboBoxDevices->count())
|
m_samplerateGroup.actions().first()->setChecked(true);
|
||||||
toggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::toggle()
|
// setting up menu Refreshrates
|
||||||
{
|
for (const auto refreshrate : refreshrates)
|
||||||
if (!m_ui->comboBoxDevices->count())
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Failed to start!"), tr("Failed to start!") % "\n\n" % tr("No audio devices available!"));
|
auto action = m_ui->menu_Refreshrate->addAction(tr("%0FPS").arg(refreshrate));
|
||||||
return;
|
action->setCheckable(true);
|
||||||
|
m_refreshrateGroup.addAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_input->running())
|
|
||||||
{
|
{
|
||||||
m_input->stop();
|
const auto index = std::find(std::begin(refreshrates), std::end(refreshrates), m_ui->widget->fps());
|
||||||
m_ui->comboBoxDevices->setEnabled(true);
|
if (index != std::end(refreshrates))
|
||||||
m_ui->comboBoxSamplerate->setEnabled(true);
|
m_refreshrateGroup.actions().at(std::distance(std::begin(refreshrates), index))->setChecked(true);
|
||||||
m_ui->pushButtonToggle->setText("▶");
|
}
|
||||||
|
|
||||||
|
connect(&m_refreshrateGroup, &QActionGroup::triggered, this, &MainWindow::refreshRateChanged);
|
||||||
|
|
||||||
|
// setting up menu Zoom
|
||||||
|
for (const auto zoomlevel : zoomlevels)
|
||||||
|
{
|
||||||
|
auto action = m_ui->menu_Zoom->addAction(tr("%0%").arg(zoomlevel));
|
||||||
|
action->setCheckable(true);
|
||||||
|
m_zoomlevelsGroup.addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto index = std::find(std::begin(zoomlevels), std::end(zoomlevels), m_ui->widget->factor()*100);
|
||||||
|
if (index != std::end(zoomlevels))
|
||||||
|
m_zoomlevelsGroup.actions().at(std::distance(std::begin(zoomlevels), index))->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(&m_zoomlevelsGroup, &QActionGroup::triggered, this, &MainWindow::zoomChanged);
|
||||||
|
|
||||||
|
// autostart
|
||||||
|
if (m_audioDevices.isEmpty())
|
||||||
|
{
|
||||||
|
m_ui->actionStart->setEnabled(false);
|
||||||
|
m_ui->actionStop->setEnabled(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::start()
|
||||||
|
{
|
||||||
|
m_input = std::make_unique<AudioDevice>();
|
||||||
|
//m_input = std::make_unique<FakeDevice>();
|
||||||
|
|
||||||
{
|
{
|
||||||
m_input->setSamplerate(m_ui->comboBoxSamplerate->currentData().toInt());
|
auto *checked = m_samplerateGroup.checkedAction();
|
||||||
m_input->setFramerate(60);
|
const auto index = m_samplerateGroup.actions().indexOf(checked);
|
||||||
|
const auto samplerate = samplerates[index];
|
||||||
|
qDebug() << "samplerate: checked =" << checked << "index =" << index << "value =" << samplerate;
|
||||||
|
m_input->setSamplerate(samplerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_input.get(), &BaseDevice::samplesReceived, m_ui->widget, &OsciWidget::renderSamples);
|
||||||
|
|
||||||
if (auto audioDevice = dynamic_cast<AudioDevice*>(m_input.get()))
|
if (auto audioDevice = dynamic_cast<AudioDevice*>(m_input.get()))
|
||||||
audioDevice->setDevice(m_audioDevices.at(m_ui->comboBoxDevices->currentIndex()));
|
{
|
||||||
|
const auto device = m_audioDevices.at(m_deviceGroup.actions().indexOf(m_deviceGroup.checkedAction()));
|
||||||
|
qDebug() << "setDevice" << device.deviceName();
|
||||||
|
audioDevice->setDevice(device);
|
||||||
|
}
|
||||||
m_input->start();
|
m_input->start();
|
||||||
|
|
||||||
m_ui->comboBoxDevices->setEnabled(false);
|
setActionsEnabled(m_deviceGroup.actions(), false);
|
||||||
m_ui->comboBoxSamplerate->setEnabled(false);
|
setActionsEnabled(m_samplerateGroup.actions(), false);
|
||||||
m_ui->pushButtonToggle->setText("▮▮");
|
m_ui->actionStart->setEnabled(false);
|
||||||
}
|
m_ui->actionStop->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::stop()
|
||||||
|
{
|
||||||
|
m_input = nullptr;
|
||||||
|
setActionsEnabled(m_deviceGroup.actions(), true);
|
||||||
|
setActionsEnabled(m_samplerateGroup.actions(), true);
|
||||||
|
m_ui->actionStart->setEnabled(true);
|
||||||
|
m_ui->actionStop->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshRateChanged()
|
||||||
|
{
|
||||||
|
auto *checked = m_refreshrateGroup.checkedAction();
|
||||||
|
const auto index = m_refreshrateGroup.actions().indexOf(checked);
|
||||||
|
const auto refreshrate = refreshrates[index];
|
||||||
|
qDebug() << "refreshrate: checked =" << checked << "index =" << index << "value =" << refreshrate;
|
||||||
|
m_ui->widget->setFps(refreshrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::zoomChanged()
|
||||||
|
{
|
||||||
|
auto *checked = m_zoomlevelsGroup.checkedAction();
|
||||||
|
const auto index = m_zoomlevelsGroup.actions().indexOf(checked);
|
||||||
|
const auto zoomlevel = zoomlevels[index];
|
||||||
|
qDebug() << "zoomlevel: checked =" << checked << "index =" << index << "value =" << zoomlevel;
|
||||||
|
m_ui->widget->setFactor(zoomlevel/100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() = default;
|
MainWindow::~MainWindow() = default;
|
||||||
|
13
mainwindow.h
13
mainwindow.h
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QActionGroup>
|
||||||
|
|
||||||
// system includes
|
// system includes
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// forward declares
|
// forward declares
|
||||||
class QAudioDeviceInfo;
|
class QAudioDeviceInfo;
|
||||||
|
class QLabel;
|
||||||
namespace Ui { class MainWindow; }
|
namespace Ui { class MainWindow; }
|
||||||
class BaseDevice;
|
class BaseDevice;
|
||||||
|
|
||||||
@@ -20,12 +22,19 @@ public:
|
|||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void toggle();
|
void start();
|
||||||
|
void stop();
|
||||||
|
void refreshRateChanged();
|
||||||
|
void zoomChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::unique_ptr<Ui::MainWindow> m_ui;
|
const std::unique_ptr<Ui::MainWindow> m_ui;
|
||||||
|
|
||||||
const QList<QAudioDeviceInfo> m_audioDevices;
|
const QList<QAudioDeviceInfo> m_audioDevices;
|
||||||
|
|
||||||
const std::unique_ptr<BaseDevice> m_input;
|
std::unique_ptr<BaseDevice> m_input;
|
||||||
|
|
||||||
|
QActionGroup m_deviceGroup{this}, m_samplerateGroup{this}, m_refreshrateGroup{this}, m_zoomlevelsGroup{this};
|
||||||
|
|
||||||
|
QLabel &m_statusLabel;
|
||||||
};
|
};
|
||||||
|
137
mainwindow.ui
137
mainwindow.ui
@@ -13,65 +13,7 @@
|
|||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>MainWindow</string>
|
<string>MainWindow</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="OsciWidget" name="widget"/>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="labelDevice">
|
|
||||||
<property name="text">
|
|
||||||
<string>Device:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboBoxDevices"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboBoxSamplerate"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="comboBoxFps"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButtonToggle">
|
|
||||||
<property name="text">
|
|
||||||
<string>PushButton</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="OsciWidget" name="widget" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenuBar" name="menubar">
|
<widget class="QMenuBar" name="menubar">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
@@ -81,19 +23,57 @@
|
|||||||
<height>20</height>
|
<height>20</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QMenu" name="menu_File">
|
||||||
|
<property name="title">
|
||||||
|
<string>&File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionStart"/>
|
||||||
|
<addaction name="actionStop"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="action_Quit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Device">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Device</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Samplerate">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Samplerate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Refreshrate">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Refreshrate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Zoom">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Zoom</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menu_File"/>
|
||||||
|
<addaction name="menu_Device"/>
|
||||||
|
<addaction name="menu_Samplerate"/>
|
||||||
|
<addaction name="menu_Refreshrate"/>
|
||||||
|
<addaction name="menu_Zoom"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
<widget class="QToolBar" name="toolBar">
|
<action name="action_Quit">
|
||||||
<property name="windowTitle">
|
<property name="text">
|
||||||
<string>toolBar</string>
|
<string>&Quit</string>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="toolBarArea">
|
</action>
|
||||||
<enum>TopToolBarArea</enum>
|
<action name="actionStart">
|
||||||
</attribute>
|
<property name="text">
|
||||||
<attribute name="toolBarBreak">
|
<string>Start</string>
|
||||||
<bool>false</bool>
|
</property>
|
||||||
</attribute>
|
</action>
|
||||||
</widget>
|
<action name="actionStop">
|
||||||
|
<property name="text">
|
||||||
|
<string>Stop</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
@@ -104,5 +84,22 @@
|
|||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>action_Quit</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>399</x>
|
||||||
|
<y>429</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct SamplePairT {
|
struct SamplePairT {
|
||||||
|
typedef T Type;
|
||||||
T first, second;
|
T first, second;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ OsciWidget::OsciWidget(QWidget *parent) :
|
|||||||
QOpenGLWidget{parent},
|
QOpenGLWidget{parent},
|
||||||
m_redrawTimerId(startTimer(1000/m_fps))
|
m_redrawTimerId(startTimer(1000/m_fps))
|
||||||
{
|
{
|
||||||
m_fpsTimer.start();
|
m_statsTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OsciWidget::setFps(int fps)
|
void OsciWidget::setFps(int fps)
|
||||||
@@ -35,30 +35,35 @@ void OsciWidget::paintEvent(QPaintEvent *event)
|
|||||||
QWidget::paintEvent(event);
|
QWidget::paintEvent(event);
|
||||||
|
|
||||||
m_frameCounter++;
|
m_frameCounter++;
|
||||||
if (m_fpsTimer.hasExpired(1000))
|
if (m_statsTimer.hasExpired(1000))
|
||||||
{
|
{
|
||||||
m_statsDisplay = QString("%0FPS (%1 callbacks)").arg(m_frameCounter).arg(m_callbacksCounter);
|
emit statusUpdate(QString("%0FPS (%1 audio callbacks)").arg(m_frameCounter).arg(m_callbacksCounter));
|
||||||
m_frameCounter = 0;
|
m_frameCounter = 0;
|
||||||
m_callbacksCounter = 0;
|
m_callbacksCounter = 0;
|
||||||
m_fpsTimer.restart();
|
m_statsTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainter painter;
|
if (m_pixmap.size() != size())
|
||||||
painter.begin(this);
|
m_pixmap = QPixmap(size());
|
||||||
|
|
||||||
// draw background
|
QPainter painter;
|
||||||
painter.setBrush(Qt::black);
|
painter.begin(&m_pixmap);
|
||||||
painter.drawRect(rect());
|
|
||||||
|
// darkening last frame
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
|
||||||
|
painter.setPen({});
|
||||||
|
painter.setBrush(QColor(150,150,150 ));
|
||||||
|
painter.drawRect(m_pixmap.rect());
|
||||||
|
|
||||||
// drawing new lines ontop
|
// drawing new lines ontop
|
||||||
QPen pen;
|
QPen pen;
|
||||||
pen.setWidth(2);
|
pen.setWidth(2);
|
||||||
pen.setColor(QColor(0, 255, 0));
|
pen.setColor(QColor(0, 255, 0));
|
||||||
painter.setPen(pen);
|
painter.setPen(pen);
|
||||||
painter.translate(width()/2, height()/2);
|
painter.translate(m_pixmap.width()/2, m_pixmap.height()/2);
|
||||||
painter.setCompositionMode(QPainter::CompositionMode_Plus);
|
painter.setCompositionMode(QPainter::CompositionMode_Plus);
|
||||||
|
|
||||||
const auto pointToCoordinates = [width=width()/2,height=height()/2,factor=m_factor](const QPointF &point)
|
const auto pointToCoordinates = [width=m_pixmap.width()/2,height=m_pixmap.height()/2,factor=m_factor](const QPointF &point)
|
||||||
{
|
{
|
||||||
return QPoint{
|
return QPoint{
|
||||||
int(point.x() * factor * width),
|
int(point.x() * factor * width),
|
||||||
@@ -75,26 +80,23 @@ void OsciWidget::paintEvent(QPaintEvent *event)
|
|||||||
|
|
||||||
const QLineF line(m_lastPoint, p);
|
const QLineF line(m_lastPoint, p);
|
||||||
|
|
||||||
painter.setOpacity(std::min(1.0, 1. / ((line.length() * 100) + 1)));
|
painter.setOpacity(std::min(1.0, 1. / ((line.length() * 75) + 1)));
|
||||||
|
|
||||||
painter.drawLine(pointToCoordinates(m_lastPoint), pointToCoordinates(p));
|
painter.drawLine(pointToCoordinates(m_lastPoint), pointToCoordinates(p));
|
||||||
|
|
||||||
m_lastPoint = p;
|
m_lastPoint = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
painter.resetTransform();
|
|
||||||
painter.setOpacity(1);
|
painter.setOpacity(1);
|
||||||
|
painter.resetTransform();
|
||||||
m_buffer.clear();
|
|
||||||
|
|
||||||
// draw stats
|
|
||||||
painter.setPen(Qt::white);
|
|
||||||
painter.setBrush(Qt::white);
|
|
||||||
QFont font;
|
|
||||||
font.setPixelSize(24);
|
|
||||||
painter.drawText(20, 20, m_statsDisplay);
|
|
||||||
|
|
||||||
painter.end();
|
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)
|
||||||
|
@@ -22,6 +22,9 @@ 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; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void statusUpdate(const QString &status);
|
||||||
|
|
||||||
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);
|
||||||
@@ -38,11 +41,12 @@ private:
|
|||||||
QPointF m_lastPoint;
|
QPointF m_lastPoint;
|
||||||
|
|
||||||
int m_frameCounter{0}, m_callbacksCounter{0};
|
int m_frameCounter{0}, m_callbacksCounter{0};
|
||||||
QString m_statsDisplay;
|
QElapsedTimer m_statsTimer;
|
||||||
QElapsedTimer m_fpsTimer;
|
|
||||||
|
|
||||||
int m_fps{15};
|
int m_fps{15};
|
||||||
int m_redrawTimerId;
|
int m_redrawTimerId;
|
||||||
|
|
||||||
std::vector<SamplePair> m_buffer;
|
std::vector<SamplePair> m_buffer;
|
||||||
|
|
||||||
|
QPixmap m_pixmap;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user