Implemented very basic tone generator
This commit is contained in:
@@ -3,15 +3,13 @@
|
|||||||
// 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
|
||||||
class AudioDeviceHelper : public QIODevice
|
class AudioDeviceHelper : public QIODevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AudioDeviceHelper(AudioDevice &audioDevice);
|
explicit AudioDeviceHelper(AudioDevice &audioDevice, QObject *parent = nullptr);
|
||||||
~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;
|
||||||
@@ -20,17 +18,9 @@ private:
|
|||||||
AudioDevice &m_audioDevice;
|
AudioDevice &m_audioDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AudioDevicePrivate {
|
class AudioDevicePrivate {
|
||||||
AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
public:
|
||||||
helper(audioDevice), input(audioDeviceInfo, format)
|
AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format);
|
||||||
{
|
|
||||||
qDebug() << audioDeviceInfo.deviceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
~AudioDevicePrivate()
|
|
||||||
{
|
|
||||||
qDebug() << "called";
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioDeviceHelper helper;
|
AudioDeviceHelper helper;
|
||||||
QAudioInput input;
|
QAudioInput input;
|
||||||
@@ -46,12 +36,12 @@ AudioDevice::~AudioDevice() = default;
|
|||||||
|
|
||||||
void AudioDevice::start()
|
void AudioDevice::start()
|
||||||
{
|
{
|
||||||
qDebug() << m_device.deviceName();
|
Q_ASSERT(!running());
|
||||||
|
|
||||||
QAudioFormat format;
|
QAudioFormat format;
|
||||||
format.setSampleRate(m_samplerate);
|
format.setSampleRate(m_samplerate);
|
||||||
format.setChannelCount(2);
|
format.setChannelCount(2);
|
||||||
format.setSampleSize(16);
|
format.setSampleSize(sizeof(SamplePair::Type) * 8);
|
||||||
format.setSampleType(QAudioFormat::SignedInt);
|
format.setSampleType(QAudioFormat::SignedInt);
|
||||||
format.setCodec("audio/pcm");
|
format.setCodec("audio/pcm");
|
||||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
@@ -63,26 +53,20 @@ void AudioDevice::start()
|
|||||||
|
|
||||||
void AudioDevice::stop()
|
void AudioDevice::stop()
|
||||||
{
|
{
|
||||||
qDebug() << "called";
|
Q_ASSERT(running());
|
||||||
|
|
||||||
m_private = nullptr;
|
m_private = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
AudioDeviceHelper::AudioDeviceHelper(AudioDevice &audioDevice) :
|
AudioDeviceHelper::AudioDeviceHelper(AudioDevice &audioDevice, QObject *parent) :
|
||||||
QIODevice(&audioDevice),
|
QIODevice{parent}, 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)
|
||||||
@@ -93,8 +77,15 @@ qint64 AudioDeviceHelper::readData(char *data, qint64 maxlen)
|
|||||||
qint64 AudioDeviceHelper::writeData(const char *data, qint64 len)
|
qint64 AudioDeviceHelper::writeData(const char *data, qint64 len)
|
||||||
{
|
{
|
||||||
Q_ASSERT(len % sizeof(SamplePair) == 0);
|
Q_ASSERT(len % sizeof(SamplePair) == 0);
|
||||||
emit m_audioDevice.samplesReceived(reinterpret_cast<const SamplePair*>(data),
|
|
||||||
reinterpret_cast<const SamplePair*>(data + (len/sizeof(SamplePair))));
|
m_audioDevice.emitSamples(reinterpret_cast<const SamplePair*>(data),
|
||||||
|
reinterpret_cast<const SamplePair*>(data) + (len/sizeof(SamplePair)));
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioDevicePrivate::AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
||||||
|
helper{audioDevice}, input{audioDeviceInfo, format}
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
// local includes
|
||||||
#include "oscicommon.h"
|
#include "oscicommon.h"
|
||||||
|
|
||||||
class BaseDevice : public QObject
|
class BaseDevice : public QObject
|
||||||
@@ -18,6 +20,8 @@ public:
|
|||||||
virtual int samplerate() const = 0;
|
virtual int samplerate() const = 0;
|
||||||
virtual void setSamplerate(int samplerate) = 0;
|
virtual void setSamplerate(int samplerate) = 0;
|
||||||
|
|
||||||
|
void emitSamples(const SamplePair *begin, const SamplePair *end) { emit samplesReceived(begin, end); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
void samplesReceived(const SamplePair *begin, const SamplePair *end);
|
||||||
};
|
};
|
||||||
|
87
basetonegenerator.cpp
Normal file
87
basetonegenerator.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "basetonegenerator.h"
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QAudioOutput>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
//! private helper to allow QAudioOutput to read from a io device
|
||||||
|
class BaseToneGeneratorHelper : public QIODevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseToneGeneratorHelper(BaseToneGenerator &generator, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
qint64 readData(char *data, qint64 maxlen) override;
|
||||||
|
qint64 writeData(const char *data, qint64 len) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BaseToneGenerator &m_generator;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseToneGeneratorPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format);
|
||||||
|
~BaseToneGeneratorPrivate() { output.stop(); }
|
||||||
|
|
||||||
|
BaseToneGeneratorHelper helper;
|
||||||
|
QAudioOutput output;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseToneGenerator::BaseToneGenerator() = default;
|
||||||
|
|
||||||
|
BaseToneGenerator::~BaseToneGenerator() = default;
|
||||||
|
|
||||||
|
void BaseToneGenerator::start()
|
||||||
|
{
|
||||||
|
Q_ASSERT(!running());
|
||||||
|
|
||||||
|
QAudioFormat format;
|
||||||
|
format.setSampleRate(m_samplerate);
|
||||||
|
format.setChannelCount(2);
|
||||||
|
format.setSampleSize(sizeof(SamplePair::Type) * 8);
|
||||||
|
format.setSampleType(QAudioFormat::SignedInt);
|
||||||
|
format.setCodec("audio/pcm");
|
||||||
|
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
|
|
||||||
|
m_private = std::make_unique<BaseToneGeneratorPrivate>(*this, m_device, format);
|
||||||
|
m_private->output.start(&m_private->helper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseToneGenerator::stop()
|
||||||
|
{
|
||||||
|
Q_ASSERT(running());
|
||||||
|
|
||||||
|
m_private = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
BaseToneGeneratorHelper::BaseToneGeneratorHelper(BaseToneGenerator &generator, QObject *parent) :
|
||||||
|
QIODevice{parent}, m_generator{generator}
|
||||||
|
{
|
||||||
|
setOpenMode(QIODevice::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 BaseToneGeneratorHelper::readData(char *data, qint64 maxlen)
|
||||||
|
{
|
||||||
|
Q_ASSERT(maxlen % sizeof(SamplePair) == 0);
|
||||||
|
|
||||||
|
return m_generator.fill(reinterpret_cast<SamplePair*>(data),
|
||||||
|
reinterpret_cast<SamplePair*>(data) + (maxlen/sizeof(SamplePair))) * sizeof(SamplePair);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 BaseToneGeneratorHelper::writeData(const char *data, qint64 len)
|
||||||
|
{
|
||||||
|
Q_UNUSED(data)
|
||||||
|
Q_UNUSED(len)
|
||||||
|
qFatal("writing is not allowed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseToneGeneratorPrivate::BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format) :
|
||||||
|
helper{generator}, output{audioDeviceInfo, format}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
39
basetonegenerator.h
Normal file
39
basetonegenerator.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QAudioDeviceInfo>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "oscicommon.h"
|
||||||
|
|
||||||
|
// forward declares
|
||||||
|
namespace { class BaseToneGeneratorPrivate; }
|
||||||
|
|
||||||
|
class BaseToneGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BaseToneGenerator();
|
||||||
|
virtual ~BaseToneGenerator();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
bool running() const { return static_cast<bool>(m_private); }
|
||||||
|
|
||||||
|
int samplerate() const { return m_samplerate; }
|
||||||
|
void setSamplerate(int samplerate) { Q_ASSERT(!running()); m_samplerate = samplerate; }
|
||||||
|
|
||||||
|
const auto &device() const { return m_device; }
|
||||||
|
void setDevice(const QAudioDeviceInfo &device) { Q_ASSERT(!running()); m_device = device; }
|
||||||
|
|
||||||
|
virtual std::size_t fill(SamplePair *begin, SamplePair *end) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<BaseToneGeneratorPrivate> m_private;
|
||||||
|
|
||||||
|
int m_samplerate;
|
||||||
|
|
||||||
|
QAudioDeviceInfo m_device;
|
||||||
|
};
|
24
debugtonegenerator.cpp
Normal file
24
debugtonegenerator.cpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#include "debugtonegenerator.h"
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
std::size_t DebugToneGenerator::fill(SamplePair *begin, SamplePair *end)
|
||||||
|
{
|
||||||
|
for (auto iter = begin; iter != end; iter++)
|
||||||
|
{
|
||||||
|
Q_ASSERT(iter <= end);
|
||||||
|
iter->first = std::sin(m_counter) * std::numeric_limits<SamplePair::Type>::max() / 2;
|
||||||
|
iter->second = std::sin((m_counter*8.f) + std::sin(m_offset)*10.) *(0.5 * (.7f + (std::sin(m_counter - M_PI/2) * .3f))) * std::numeric_limits<SamplePair::Type>::max() / 2;
|
||||||
|
|
||||||
|
m_counter+= 1. / samplerate() * (1000. + (std::sin(m_freq) * 500.));
|
||||||
|
m_offset+=0.00001f;
|
||||||
|
m_freq+=1. / samplerate() * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_counter >= M_PI * 2)
|
||||||
|
m_counter -= M_PI * 2;
|
||||||
|
|
||||||
|
return std::distance(begin, end);
|
||||||
|
}
|
14
debugtonegenerator.h
Normal file
14
debugtonegenerator.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "basetonegenerator.h"
|
||||||
|
|
||||||
|
class DebugToneGenerator : public BaseToneGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using BaseToneGenerator::BaseToneGenerator;
|
||||||
|
|
||||||
|
std::size_t fill(SamplePair *begin, SamplePair *end) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_counter{0.f};
|
||||||
|
float m_offset{0.};
|
||||||
|
float m_freq{0.};
|
||||||
|
};
|
@@ -1,46 +0,0 @@
|
|||||||
#include "fakedevice.h"
|
|
||||||
|
|
||||||
// Qt includes
|
|
||||||
#include <QTimerEvent>
|
|
||||||
|
|
||||||
// system includes
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
void FakeDevice::start()
|
|
||||||
{
|
|
||||||
Q_ASSERT(!running());
|
|
||||||
m_bufferSize = m_samplerate/m_framerate;
|
|
||||||
m_buffer = std::make_unique<SamplePair[]>(m_bufferSize);
|
|
||||||
m_timerId = startTimer(1000/m_framerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FakeDevice::stop()
|
|
||||||
{
|
|
||||||
Q_ASSERT(running());
|
|
||||||
killTimer(m_timerId);
|
|
||||||
m_buffer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FakeDevice::running() const
|
|
||||||
{
|
|
||||||
return m_timerId != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FakeDevice::timerEvent(QTimerEvent *event)
|
|
||||||
{
|
|
||||||
if (event->timerId() == m_timerId)
|
|
||||||
{
|
|
||||||
for (SamplePair *pair = m_buffer.get();
|
|
||||||
pair != m_buffer.get() + m_bufferSize;
|
|
||||||
pair++)
|
|
||||||
{
|
|
||||||
pair->first = std::sin(m_dingsDesHaltHochZaehlt) * std::numeric_limits<qint16>::max();
|
|
||||||
pair->second = std::cos(m_dingsDesHaltHochZaehlt) * std::numeric_limits<qint16>::max();
|
|
||||||
m_dingsDesHaltHochZaehlt += 0.05;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit samplesReceived(m_buffer.get(), m_buffer.get() + m_bufferSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
QObject::timerEvent(event);
|
|
||||||
}
|
|
37
fakedevice.h
37
fakedevice.h
@@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "basedevice.h"
|
|
||||||
|
|
||||||
// system includes
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class FakeDevice : public BaseDevice
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
using BaseDevice::BaseDevice;
|
|
||||||
|
|
||||||
void start() override;
|
|
||||||
void stop() override;
|
|
||||||
bool running() const override;
|
|
||||||
|
|
||||||
int samplerate() const override { return m_samplerate; }
|
|
||||||
void setSamplerate(int samplerate) override { Q_ASSERT(!running()); m_samplerate = samplerate; }
|
|
||||||
|
|
||||||
int framerate() const { return m_framerate; }
|
|
||||||
void setFramerate(int framerate) { Q_ASSERT(!running()); m_framerate = framerate; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void timerEvent(QTimerEvent *event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
double m_dingsDesHaltHochZaehlt{0.};
|
|
||||||
int m_timerId{-1};
|
|
||||||
|
|
||||||
std::unique_ptr<SamplePair[]> m_buffer;
|
|
||||||
std::size_t m_bufferSize;
|
|
||||||
|
|
||||||
int m_samplerate{44100};
|
|
||||||
int m_framerate{15};
|
|
||||||
};
|
|
2
main.cpp
2
main.cpp
@@ -1,6 +1,8 @@
|
|||||||
|
// Qt includes
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
// local includes
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QWidgetAction>
|
#include <QWidgetAction>
|
||||||
@@ -10,7 +13,7 @@
|
|||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "audiodevice.h"
|
#include "audiodevice.h"
|
||||||
#include "fakedevice.h"
|
#include "debugtonegenerator.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int samplerates[] = { 44100, 48000, 96000, 192000 };
|
constexpr int samplerates[] = { 44100, 48000, 96000, 192000 };
|
||||||
@@ -30,7 +33,8 @@ void setActionsEnabled(const T &actions, bool 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_inputDevices{QAudioDeviceInfo::availableDevices(QAudio::AudioInput)},
|
||||||
|
m_outputDevices{QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)},
|
||||||
m_statusLabel{*new QLabel}
|
m_statusLabel{*new QLabel}
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
@@ -44,19 +48,32 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
connect(m_ui->actionStop, &QAction::triggered, this, &MainWindow::stop);
|
connect(m_ui->actionStop, &QAction::triggered, this, &MainWindow::stop);
|
||||||
m_ui->actionQuit->setShortcut(QKeySequence::Quit);
|
m_ui->actionQuit->setShortcut(QKeySequence::Quit);
|
||||||
|
|
||||||
// setting up menu Devices
|
// setting up menu InputDevices
|
||||||
for (const auto &device : m_audioDevices)
|
for (const auto &device : m_inputDevices)
|
||||||
{
|
{
|
||||||
auto name = device.deviceName();
|
auto name = device.deviceName();
|
||||||
const auto action = m_ui->menuDevice->addAction(name);
|
const auto action = m_ui->menuInputDevice->addAction(name);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
m_deviceGroup.addAction(action);
|
m_inputDeviceGroup.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);
|
action->setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setting up menu OutputDevices
|
||||||
|
for (const auto &device : m_outputDevices)
|
||||||
|
{
|
||||||
|
auto name = device.deviceName();
|
||||||
|
const auto action = m_ui->menuOutputDevice->addAction(name);
|
||||||
|
action->setCheckable(true);
|
||||||
|
m_outputDeviceGroup.addAction(action);
|
||||||
|
|
||||||
|
// Select last element containing analog-stereo if available
|
||||||
|
if(name.contains("analog-stereo"))
|
||||||
|
action->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
// setting up menu Samplerates
|
// setting up menu Samplerates
|
||||||
for (const auto samplerate : samplerates)
|
for (const auto samplerate : samplerates)
|
||||||
{
|
{
|
||||||
@@ -100,6 +117,8 @@ 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);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto widgetAction = new QWidgetAction(this);
|
auto widgetAction = new QWidgetAction(this);
|
||||||
auto widget = new QWidget;
|
auto widget = new QWidget;
|
||||||
@@ -123,7 +142,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
// autostart
|
// autostart
|
||||||
if (m_audioDevices.isEmpty())
|
if (m_inputDevices.isEmpty())
|
||||||
{
|
{
|
||||||
m_ui->actionStart->setEnabled(false);
|
m_ui->actionStart->setEnabled(false);
|
||||||
m_ui->actionStop->setEnabled(false);
|
m_ui->actionStop->setEnabled(false);
|
||||||
@@ -134,28 +153,20 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
|
|
||||||
void MainWindow::start()
|
void MainWindow::start()
|
||||||
{
|
{
|
||||||
m_input = std::make_unique<AudioDevice>();
|
|
||||||
//m_input = std::make_unique<FakeDevice>();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto *checked = m_samplerateGroup.checkedAction();
|
auto input = std::make_unique<AudioDevice>();
|
||||||
const auto index = m_samplerateGroup.actions().indexOf(checked);
|
// setDevice is AudioDevice specific API
|
||||||
const auto samplerate = samplerates[index];
|
input->setDevice(m_inputDevices.at(m_inputDeviceGroup.actions().indexOf(m_inputDeviceGroup.checkedAction())));
|
||||||
qDebug() << "samplerate: checked =" << checked << "index =" << index << "value =" << samplerate;
|
m_input = std::move(input);
|
||||||
m_input->setSamplerate(samplerate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_input->setSamplerate(samplerate());
|
||||||
|
|
||||||
connect(m_input.get(), &BaseDevice::samplesReceived, m_ui->widget, &OsciWidget::renderSamples);
|
connect(m_input.get(), &BaseDevice::samplesReceived, m_ui->widget, &OsciWidget::renderSamples);
|
||||||
|
|
||||||
if (auto audioDevice = dynamic_cast<AudioDevice*>(m_input.get()))
|
|
||||||
{
|
|
||||||
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();
|
||||||
|
|
||||||
setActionsEnabled(m_deviceGroup.actions(), false);
|
setActionsEnabled(m_inputDeviceGroup.actions(), false);
|
||||||
setActionsEnabled(m_samplerateGroup.actions(), false);
|
setActionsEnabled(m_samplerateGroup.actions(), false);
|
||||||
m_ui->actionStart->setEnabled(false);
|
m_ui->actionStart->setEnabled(false);
|
||||||
m_ui->actionStop->setEnabled(true);
|
m_ui->actionStop->setEnabled(true);
|
||||||
@@ -164,7 +175,7 @@ void MainWindow::start()
|
|||||||
void MainWindow::stop()
|
void MainWindow::stop()
|
||||||
{
|
{
|
||||||
m_input = nullptr;
|
m_input = nullptr;
|
||||||
setActionsEnabled(m_deviceGroup.actions(), true);
|
setActionsEnabled(m_inputDeviceGroup.actions(), true);
|
||||||
setActionsEnabled(m_samplerateGroup.actions(), true);
|
setActionsEnabled(m_samplerateGroup.actions(), true);
|
||||||
m_ui->actionStart->setEnabled(true);
|
m_ui->actionStart->setEnabled(true);
|
||||||
m_ui->actionStop->setEnabled(false);
|
m_ui->actionStop->setEnabled(false);
|
||||||
@@ -188,4 +199,29 @@ void MainWindow::zoomChanged()
|
|||||||
m_ui->widget->setFactor(zoomlevel/100.f);
|
m_ui->widget->setFactor(zoomlevel/100.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::startGenerator()
|
||||||
|
{
|
||||||
|
m_generator = nullptr;
|
||||||
|
m_generator = std::make_unique<DebugToneGenerator>();
|
||||||
|
m_generator->setDevice(m_outputDevices.at(m_outputDeviceGroup.actions().indexOf(m_outputDeviceGroup.checkedAction())));
|
||||||
|
m_generator->setSamplerate(samplerate());
|
||||||
|
m_generator->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MainWindow::samplerate() const
|
||||||
|
{
|
||||||
|
auto *checked = m_samplerateGroup.checkedAction();
|
||||||
|
if (!checked)
|
||||||
|
throw std::runtime_error(tr("No samplerate selected!").toStdString());
|
||||||
|
|
||||||
|
const auto index = m_samplerateGroup.actions().indexOf(checked);
|
||||||
|
if (index < 0)
|
||||||
|
throw std::runtime_error(tr("Unknown samplerate selected!").toStdString());
|
||||||
|
|
||||||
|
if (index >= std::distance(std::begin(samplerates), std::end(samplerates)))
|
||||||
|
throw std::runtime_error(tr("Index out of range!").toStdString());
|
||||||
|
|
||||||
|
return samplerates[index];
|
||||||
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() = default;
|
MainWindow::~MainWindow() = default;
|
||||||
|
11
mainwindow.h
11
mainwindow.h
@@ -13,6 +13,8 @@ class QLabel;
|
|||||||
namespace Ui { class MainWindow; }
|
namespace Ui { class MainWindow; }
|
||||||
class BaseDevice;
|
class BaseDevice;
|
||||||
|
|
||||||
|
class BaseToneGenerator;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -26,15 +28,20 @@ private slots:
|
|||||||
void stop();
|
void stop();
|
||||||
void refreshRateChanged();
|
void refreshRateChanged();
|
||||||
void zoomChanged();
|
void zoomChanged();
|
||||||
|
void startGenerator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int samplerate() const;
|
||||||
|
|
||||||
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_inputDevices, m_outputDevices;
|
||||||
|
|
||||||
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};
|
QActionGroup m_inputDeviceGroup{this}, m_outputDeviceGroup{this}, m_samplerateGroup{this}, m_refreshrateGroup{this}, m_zoomlevelsGroup{this};
|
||||||
|
|
||||||
QLabel &m_statusLabel;
|
QLabel &m_statusLabel;
|
||||||
|
|
||||||
|
std::unique_ptr<BaseToneGenerator> m_generator;
|
||||||
};
|
};
|
||||||
|
@@ -32,9 +32,9 @@
|
|||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionQuit"/>
|
<addaction name="actionQuit"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuDevice">
|
<widget class="QMenu" name="menuInputDevice">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Device</string>
|
<string>&Input device</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuSamplerate">
|
<widget class="QMenu" name="menuSamplerate">
|
||||||
@@ -56,9 +56,16 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Debug</string>
|
<string>Debug</string>
|
||||||
</property>
|
</property>
|
||||||
|
<addaction name="actionToneGenerator"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuOutputDevice">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Output device</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuDevice"/>
|
<addaction name="menuInputDevice"/>
|
||||||
|
<addaction name="menuOutputDevice"/>
|
||||||
<addaction name="menuSamplerate"/>
|
<addaction name="menuSamplerate"/>
|
||||||
<addaction name="menuRefreshrate"/>
|
<addaction name="menuRefreshrate"/>
|
||||||
<addaction name="menuZoom"/>
|
<addaction name="menuZoom"/>
|
||||||
@@ -80,6 +87,11 @@
|
|||||||
<string>Stop</string>
|
<string>Stop</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionToneGenerator">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Tone generator</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
@@ -6,7 +6,8 @@ DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
audiodevice.cpp \
|
audiodevice.cpp \
|
||||||
basedevice.cpp \
|
basedevice.cpp \
|
||||||
fakedevice.cpp \
|
basetonegenerator.cpp \
|
||||||
|
debugtonegenerator.cpp \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
mainwindow.cpp \
|
mainwindow.cpp \
|
||||||
osciwidget.cpp
|
osciwidget.cpp
|
||||||
@@ -14,7 +15,8 @@ SOURCES += \
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
audiodevice.h \
|
audiodevice.h \
|
||||||
basedevice.h \
|
basedevice.h \
|
||||||
fakedevice.h \
|
basetonegenerator.h \
|
||||||
|
debugtonegenerator.h \
|
||||||
mainwindow.h \
|
mainwindow.h \
|
||||||
oscicommon.h \
|
oscicommon.h \
|
||||||
osciwidget.h
|
osciwidget.h
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
#include "osciwidget.h"
|
#include "osciwidget.h"
|
||||||
|
|
||||||
|
// system includes
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
#include <QLineF>
|
#include <QLineF>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@@ -41,7 +41,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
float m_factor{2.f};
|
float m_factor{2.f};
|
||||||
int m_fps{15}, m_afterglow{175};
|
int m_fps{30}, m_afterglow{175};
|
||||||
float m_lightspeed{35.f};
|
float m_lightspeed{35.f};
|
||||||
|
|
||||||
std::vector<SamplePair> m_buffer;
|
std::vector<SamplePair> m_buffer;
|
||||||
|
Reference in New Issue
Block a user