From ab2853475f9a03fa01a05548bd49fe884ece61a5 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 16 Sep 2019 18:09:44 +0200 Subject: [PATCH 01/23] Reorder includes (local to system) Include local include first so that dependencies on external includes are less likely overlooked --- mainwindow.cpp | 10 +++++----- osciwidget.cpp | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 680b789..afc8970 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,8 +1,9 @@ #include "mainwindow.h" #include "ui_mainwindow.h" -// system includes -#include +// local includes +#include "audiodevice.h" +#include "debugtonegenerator.h" // Qt includes #include @@ -11,9 +12,8 @@ #include #include -// local includes -#include "audiodevice.h" -#include "debugtonegenerator.h" +// system includes +#include namespace { constexpr int samplerates[] = { 44100, 48000, 96000, 192000 }; diff --git a/osciwidget.cpp b/osciwidget.cpp index b55ece1..2b8d675 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -1,14 +1,14 @@ #include "osciwidget.h" -// system includes -#include - // Qt includes #include #include #include #include +// system includes +#include + OsciWidget::OsciWidget(QWidget *parent) : QOpenGLWidget{parent}, m_redrawTimerId(startTimer(1000/m_fps)) From f5d6995d98b2c74e238af6669c96a57360e3d941 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 16 Sep 2019 18:50:37 +0200 Subject: [PATCH 02/23] Fix warnings by moving class declaration into class Original warning: --- audiodevice.cpp | 10 ++-------- audiodevice.h | 2 +- basetonegenerator.cpp | 10 ++-------- basetonegenerator.h | 4 +--- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/audiodevice.cpp b/audiodevice.cpp index 88443b2..d71b850 100644 --- a/audiodevice.cpp +++ b/audiodevice.cpp @@ -4,7 +4,6 @@ #include #include -namespace { //! private helper to allow QAudioInput to write to a io device class AudioDeviceHelper : public QIODevice { @@ -18,14 +17,13 @@ private: AudioDevice &m_audioDevice; }; -class AudioDevicePrivate { +class AudioDevice::AudioDevicePrivate { public: AudioDevicePrivate(AudioDevice &audioDevice, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format); AudioDeviceHelper helper; QAudioInput input; }; -} AudioDevice::AudioDevice(QObject *parent) : BaseDevice{parent} @@ -58,9 +56,6 @@ void AudioDevice::stop() m_private = nullptr; } - - -namespace { AudioDeviceHelper::AudioDeviceHelper(AudioDevice &audioDevice, QObject *parent) : QIODevice{parent}, m_audioDevice(audioDevice) { @@ -84,8 +79,7 @@ qint64 AudioDeviceHelper::writeData(const char *data, qint64 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} { } -} diff --git a/audiodevice.h b/audiodevice.h index bcd319b..656cb0b 100644 --- a/audiodevice.h +++ b/audiodevice.h @@ -9,7 +9,6 @@ #include // forward declares -namespace { class AudioDevicePrivate; } class QAudioInput; class AudioDevice : public BaseDevice @@ -31,6 +30,7 @@ public: void setDevice(const QAudioDeviceInfo &device) { Q_ASSERT(!running()); m_device = device; } private: + class AudioDevicePrivate; std::unique_ptr m_private; int m_samplerate; diff --git a/basetonegenerator.cpp b/basetonegenerator.cpp index 94e65be..163f488 100644 --- a/basetonegenerator.cpp +++ b/basetonegenerator.cpp @@ -3,8 +3,6 @@ // Qt includes #include -namespace -{ //! private helper to allow QAudioOutput to read from a io device class BaseToneGeneratorHelper : public QIODevice { @@ -18,7 +16,7 @@ private: BaseToneGenerator &m_generator; }; -class BaseToneGeneratorPrivate +class BaseToneGenerator::BaseToneGeneratorPrivate { public: BaseToneGeneratorPrivate(BaseToneGenerator &generator, const QAudioDeviceInfo &audioDeviceInfo, const QAudioFormat &format); @@ -28,8 +26,6 @@ public: QAudioOutput output; }; -} - BaseToneGenerator::BaseToneGenerator() = default; BaseToneGenerator::~BaseToneGenerator() = default; @@ -58,7 +54,6 @@ void BaseToneGenerator::stop() m_private = nullptr; } -namespace { BaseToneGeneratorHelper::BaseToneGeneratorHelper(BaseToneGenerator &generator, QObject *parent) : QIODevice{parent}, m_generator{generator} { @@ -80,8 +75,7 @@ qint64 BaseToneGeneratorHelper::writeData(const char *data, qint64 len) 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} { } -} diff --git a/basetonegenerator.h b/basetonegenerator.h index 1c8b25f..b3d2397 100644 --- a/basetonegenerator.h +++ b/basetonegenerator.h @@ -9,9 +9,6 @@ // local includes #include "oscicommon.h" -// forward declares -namespace { class BaseToneGeneratorPrivate; } - class BaseToneGenerator { public: @@ -31,6 +28,7 @@ public: virtual std::size_t fill(SamplePair *begin, SamplePair *end) = 0; private: + class BaseToneGeneratorPrivate; std::unique_ptr m_private; int m_samplerate; From 1fb31a4ec26a73dc4b87c2a4a12b6f12523cfb81 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 16 Sep 2019 18:53:03 +0200 Subject: [PATCH 03/23] Adds gitignores for moc_predef.h and linux default binary name --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index fab7372..547207e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ Makefile* *.prl *.app moc_*.cpp +moc_*.h ui_*.h qrc_*.cpp Thumbs.db @@ -70,4 +71,5 @@ Thumbs.db # -------- *.dll *.exe +oscilloscope From 86b99ab8d25945239d4f75c0e85d429d2e8c2e3f Mon Sep 17 00:00:00 2001 From: Gitea Date: Tue, 17 Sep 2019 19:46:48 +0200 Subject: [PATCH 04/23] Moves painting of frame into helper function --- osciwidget.cpp | 22 ++++++++++------------ osciwidget.h | 3 +++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index 2b8d675..6e00692 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -56,11 +56,16 @@ void OsciWidget::paintEvent(QPaintEvent *event) m_statsTimer.restart(); } + QPainter painter(this); + painter.drawPixmap(0, 0, m_pixmap); +} + +void OsciWidget::updateFrameBuffer() +{ if (m_pixmap.size() != size()) m_pixmap = QPixmap(size()); - QPainter painter; - painter.begin(&m_pixmap); + QPainter painter(&m_pixmap); // darkening last frame painter.setCompositionMode(QPainter::CompositionMode_Multiply); @@ -100,21 +105,14 @@ void OsciWidget::paintEvent(QPaintEvent *event) 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) { QWidget::timerEvent(event); - if (event->timerId() == m_redrawTimerId) + if (event->timerId() == m_redrawTimerId){ + updateFrameBuffer(); repaint(); + } } diff --git a/osciwidget.h b/osciwidget.h index 6a596cb..810c92e 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -39,6 +39,9 @@ protected: void paintEvent(QPaintEvent *event) override; void timerEvent(QTimerEvent *event) override; +private: + void updateFrameBuffer(); + private: float m_factor{2.f}; int m_fps{30}, m_afterglow{175}; From e6249131ff415f7ff899b47f1dc6095da0dcdf25 Mon Sep 17 00:00:00 2001 From: Gitea Date: Tue, 17 Sep 2019 19:48:44 +0200 Subject: [PATCH 05/23] Workaround updating frame (and thus darkening the image) by only updating when there is new data. This essentially limits the frame rate to the buffer update rate This will be fixed when painting is done in smaller chunks of the buffer --- osciwidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osciwidget.cpp b/osciwidget.cpp index 6e00692..91d1b1d 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -62,6 +62,9 @@ void OsciWidget::paintEvent(QPaintEvent *event) void OsciWidget::updateFrameBuffer() { + // Workaround for flickering (do not update, when there is no new data) + if(m_buffer.empty()) return; + if (m_pixmap.size() != size()) m_pixmap = QPixmap(size()); From 9c573faba15001488b8c8a32ea2844f2a6216f63 Mon Sep 17 00:00:00 2001 From: Daniel Brunner Date: Tue, 17 Sep 2019 21:56:57 +0200 Subject: [PATCH 06/23] qt 5.10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit edit on phone 🤣 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b86e2d0..e7a3db6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ cache: install: - 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.10 git://code.qt.io/qt/qt5.git ; fi - pushd qt5 - if [ ! -d qtbase/.git ] ; then perl init-repository --module-subset=qtbase,qtimageformats,qtmultimedia,qttools ; fi - if [ ! -f config.summary ] ; then ./configure -prefix `pwd`/build -opensource -confirm-license -nomake examples -nomake tests ; fi From 6c550abaafb25a2a0cff63870fd2809fe28d1e82 Mon Sep 17 00:00:00 2001 From: Gitea Date: Tue, 17 Sep 2019 22:06:55 +0200 Subject: [PATCH 07/23] Calculates afterglow from a value 0.0 to 1.0 which is the factor the screen will be after 1 second (provided it draws at the set FPS rate) --- mainwindow.cpp | 7 ++++--- osciwidget.cpp | 9 ++++++++- osciwidget.h | 7 ++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index afc8970..29b0ede 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -124,10 +124,11 @@ MainWindow::MainWindow(QWidget *parent) : auto widget = new QWidget; auto layout = new QFormLayout(widget); { - auto input = new QSpinBox; - input->setRange(0, 255); + auto input = new QDoubleSpinBox; + input->setRange(0, 1.0); + input->setSingleStep(0.1); input->setValue(m_ui->widget->afterglow()); - connect(input, qOverload(&QSpinBox::valueChanged), m_ui->widget, &OsciWidget::setAfterglow); + connect(input, qOverload(&QDoubleSpinBox::valueChanged), m_ui->widget, &OsciWidget::setAfterglow); layout->addRow(tr("Afterglow:"), input); } { diff --git a/osciwidget.cpp b/osciwidget.cpp index 91d1b1d..6a049eb 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -30,6 +30,13 @@ void OsciWidget::setFps(int fps) m_redrawTimerId = startTimer(1000/m_fps); } +void OsciWidget::setAfterglow(float afterglow){ + m_afterglow = afterglow; + // percentage of the image that should be visible after one second + // i.e. factor^fps=afterglow -> factor = afterglow^(1/fps) + m_afterglowColor = 255 * pow(afterglow, 1.0/m_fps); +} + void OsciWidget::setLightspeed(int lightspeed) { const auto temp = (float(lightspeed)/20.f); m_lightspeed = temp*temp*temp; @@ -73,7 +80,7 @@ void OsciWidget::updateFrameBuffer() // darkening last frame painter.setCompositionMode(QPainter::CompositionMode_Multiply); painter.setPen({}); - painter.setBrush(QColor(m_afterglow, m_afterglow, m_afterglow)); + painter.setBrush(QColor(m_afterglowColor, m_afterglowColor, m_afterglowColor)); painter.drawRect(m_pixmap.rect()); // drawing new lines ontop diff --git a/osciwidget.h b/osciwidget.h index 810c92e..9403099 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -21,7 +21,7 @@ public: float factor() const { return m_factor; } int fps() const { return m_fps; } - int afterglow() const { return m_afterglow; } + float afterglow() const { return m_afterglow; } int lightspeed() const; signals: @@ -30,7 +30,7 @@ signals: public slots: void setFactor(float factor) { m_factor = factor; } void setFps(int fps); - void setAfterglow(int afterglow) { m_afterglow = afterglow; } + void setAfterglow(float afterglow); void setLightspeed(int lightspeed); void renderSamples(const SamplePair *begin, const SamplePair *end); @@ -44,7 +44,8 @@ private: private: float m_factor{2.f}; - int m_fps{30}, m_afterglow{175}; + int m_fps{30}, m_afterglowColor{175}; + float m_afterglow{0.2}; float m_lightspeed{35.f}; std::vector m_buffer; From 00cd74295c81089252914363939a7727bb0bafc2 Mon Sep 17 00:00:00 2001 From: Gitea Date: Tue, 17 Sep 2019 22:13:28 +0200 Subject: [PATCH 08/23] Allow to stop DebugToneGenerator --- mainwindow.cpp | 10 +++++++--- mainwindow.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 29b0ede..400eb7b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -117,7 +117,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(&m_zoomlevelsGroup, &QActionGroup::triggered, this, &MainWindow::zoomChanged); //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); @@ -200,9 +200,13 @@ void MainWindow::zoomChanged() 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(); m_generator->setDevice(m_outputDevices.at(m_outputDeviceGroup.actions().indexOf(m_outputDeviceGroup.checkedAction()))); m_generator->setSamplerate(samplerate()); diff --git a/mainwindow.h b/mainwindow.h index 1ba9e91..9d5dd90 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -28,7 +28,7 @@ private slots: void stop(); void refreshRateChanged(); void zoomChanged(); - void startGenerator(); + void startStopGenerator(); private: int samplerate() const; From 09e1d1ff16d690c30d71935908ff276e1a6454ec Mon Sep 17 00:00:00 2001 From: Gitea Date: Tue, 17 Sep 2019 23:20:56 +0200 Subject: [PATCH 09/23] Store only one value for afterglow --- osciwidget.cpp | 4 ++-- osciwidget.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index 9193440..e8d7bf4 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -34,7 +34,6 @@ void OsciWidget::setAfterglow(float afterglow){ m_afterglow = afterglow; // percentage of the image that should be visible after one second // i.e. factor^fps=afterglow -> factor = afterglow^(1/fps) - m_afterglowColor = 255 * pow(afterglow, 1.0/m_fps); } void OsciWidget::setLightspeed(int lightspeed) { @@ -86,7 +85,8 @@ void OsciWidget::updateFrameBuffer() // darkening last frame painter.setCompositionMode(QPainter::CompositionMode_Multiply); painter.setPen({}); - painter.setBrush(QColor(m_afterglowColor, m_afterglowColor, m_afterglowColor)); + auto afterglowColor = 255 * pow(m_afterglow, 1.0/m_fps); + painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor)); painter.drawRect(m_pixmap.rect()); // drawing new lines ontop diff --git a/osciwidget.h b/osciwidget.h index 7b32068..31f6362 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -44,7 +44,7 @@ private: private: float m_factor{2.f}; - int m_fps{30}, m_afterglowColor{175}; + int m_fps{30}; float m_afterglow{0.2}; float m_lightspeed{35.f}; From 7d26cf4387014deabef5d224be0a4e261338ccc8 Mon Sep 17 00:00:00 2001 From: Gitea Date: Tue, 17 Sep 2019 23:21:19 +0200 Subject: [PATCH 10/23] Change default zoom factor to 100% --- osciwidget.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osciwidget.h b/osciwidget.h index 31f6362..63e044e 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -43,7 +43,7 @@ private: void updateFrameBuffer(); private: - float m_factor{2.f}; + float m_factor{1.f}; int m_fps{30}; float m_afterglow{0.2}; float m_lightspeed{35.f}; From 1481a33326fca265e2066e82335b5d85981ecacd Mon Sep 17 00:00:00 2001 From: Gitea Date: Wed, 18 Sep 2019 00:04:50 +0200 Subject: [PATCH 11/23] Scales using QPainter::scale --- osciwidget.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index e8d7bf4..9ec2263 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -90,20 +90,15 @@ void OsciWidget::updateFrameBuffer() painter.drawRect(m_pixmap.rect()); // drawing new lines ontop + 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); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + QPen pen; + pen.setCosmetic(true); // let pen be scale invariant pen.setWidth(2); 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) - { - return QPoint{ - int(point.x() * factor * width), - int(point.y() * factor * height) - }; - }; for (const auto &i : m_buffer) { @@ -116,7 +111,7 @@ void OsciWidget::updateFrameBuffer() painter.setOpacity(std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1))); - painter.drawLine(pointToCoordinates(m_lastPoint), pointToCoordinates(p)); + painter.drawLine(m_lastPoint, p); m_lastPoint = p; } From f7cb80007fcfe9bf870bffdf2b21bc3c4bd5dc28 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sat, 21 Sep 2019 09:38:39 +0200 Subject: [PATCH 12/23] Prepare rendering in smaller batches (per screen frame) --- osciwidget.cpp | 76 ++++++++++++++++++++++++++++++++++---------------- osciwidget.h | 7 +++-- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index 9ec2263..6891231 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -9,10 +9,17 @@ // system includes #include -OsciWidget::OsciWidget(QWidget *parent) : - QOpenGLWidget{parent}, - m_redrawTimerId(startTimer(1000/m_fps)) +qint32 framesForDuration(qint64 duration){ + return qint32(44100 * duration / 1000000LL); +} + + +OsciWidget::OsciWidget(QWidget *parent) + : QOpenGLWidget{parent} + , m_redrawTimerId(startTimer(1000/m_fps, Qt::PreciseTimer)) + , m_lastFrame{0} { + m_bufferTimer.start(); m_statsTimer.start(); } @@ -27,16 +34,18 @@ void OsciWidget::setFps(int fps) m_fps = fps; - m_redrawTimerId = startTimer(1000/m_fps); + m_redrawTimerId = startTimer(1000/m_fps, Qt::PreciseTimer); } -void OsciWidget::setAfterglow(float afterglow){ +void OsciWidget::setAfterglow(float afterglow) +{ m_afterglow = afterglow; // percentage of the image that should be visible after one second // i.e. factor^fps=afterglow -> factor = afterglow^(1/fps) } -void OsciWidget::setLightspeed(int lightspeed) { +void OsciWidget::setLightspeed(int lightspeed) +{ const auto temp = (float(lightspeed)/20.f); m_lightspeed = temp*temp*temp; qDebug() << m_lightspeed; @@ -49,6 +58,8 @@ void OsciWidget::renderSamples(const SamplePair *begin, const SamplePair *end) m_samplesCounter += std::distance(begin, end); m_buffer.insert(m_buffer.end(), begin, end); + //m_bufferTimer.restart(); + //qDebug() << m_statsTimer.elapsed(); } void OsciWidget::paintEvent(QPaintEvent *event) @@ -69,10 +80,21 @@ void OsciWidget::paintEvent(QPaintEvent *event) painter.drawPixmap(0, 0, m_pixmap); } -void OsciWidget::updateFrameBuffer() +void OsciWidget::darkenFrame() +{ + QPainter painter(&m_pixmap); + + painter.setCompositionMode(QPainter::CompositionMode_Multiply); + painter.setPen({}); + auto afterglowColor = 255 * pow(m_afterglow, 1.0/m_fps); + painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor)); + painter.drawRect(m_pixmap.rect()); +} + +void OsciWidget::updateDrawBuffer() { // Workaround for flickering (do not update, when there is no new data) - if(m_buffer.empty()) return; + //if(m_buffer.empty()) return; if (m_pixmap.size() != size()) { @@ -80,19 +102,11 @@ void OsciWidget::updateFrameBuffer() m_pixmap.fill(Qt::black); } + darkenFrame(); + QPainter painter(&m_pixmap); - - // darkening last frame - painter.setCompositionMode(QPainter::CompositionMode_Multiply); - painter.setPen({}); - auto afterglowColor = 255 * pow(m_afterglow, 1.0/m_fps); - painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor)); - painter.drawRect(m_pixmap.rect()); - - // drawing new lines ontop 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); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); QPen pen; pen.setCosmetic(true); // let pen be scale invariant @@ -100,30 +114,44 @@ void OsciWidget::updateFrameBuffer() pen.setColor(QColor(0, 255, 0)); painter.setPen(pen); - for (const auto &i : m_buffer) + qint64 samplesUsed = 0; + double timeConstant = log(m_afterglow); + + auto duration = m_bufferTimer.elapsed()*1000; + qint32 framesCnt = framesForDuration(duration); + //qDebug() << framesCnt << duration; + + for (size_t idx = 0; idx < framesCnt && idx < m_buffer.size(); ++idx) { + const auto &frame = m_buffer[idx]; + double time = (m_buffer.size() - samplesUsed) / 44100.0; + const QPointF p{ - float(i.first) / std::numeric_limits::max(), - float(-i.second) / std::numeric_limits::max() + float(frame.first) / std::numeric_limits::max(), + float(-frame.second) / std::numeric_limits::max() }; const QLineF line(m_lastPoint, p); + auto beamOpacity = std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1)); + auto beamDecay = exp(time*timeConstant); + //qDebug() << time << beamDecay; - painter.setOpacity(std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1))); + painter.setOpacity(beamDecay*beamOpacity); painter.drawLine(m_lastPoint, p); m_lastPoint = p; + ++samplesUsed; } - m_buffer.clear(); + //m_buffer.clear(); } void OsciWidget::timerEvent(QTimerEvent *event) { QWidget::timerEvent(event); if (event->timerId() == m_redrawTimerId){ - updateFrameBuffer(); + updateDrawBuffer(); repaint(); } } diff --git a/osciwidget.h b/osciwidget.h index 63e044e..cd9fe9f 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -40,20 +40,23 @@ protected: void timerEvent(QTimerEvent *event) override; private: - void updateFrameBuffer(); + void updateDrawBuffer(); private: float m_factor{1.f}; int m_fps{30}; - float m_afterglow{0.2}; + float m_afterglow{0.01}; float m_lightspeed{35.f}; std::vector m_buffer; int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0}; QElapsedTimer m_statsTimer; + QElapsedTimer m_bufferTimer; int m_redrawTimerId; QPointF m_lastPoint; + size_t m_lastFrame; QPixmap m_pixmap; + void darkenFrame(); }; From 7db83d5eba7722c4b77ce536e2a41781fab363d4 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 09:54:18 +0200 Subject: [PATCH 13/23] Experiment with afterglow, and partial buffer painting --- mainwindow.cpp | 6 ++--- osciwidget.cpp | 61 ++++++++++++++++++++++++++++++++++---------------- osciwidget.h | 9 ++++---- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 400eb7b..d8df364 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -18,7 +18,7 @@ namespace { 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 }; @@ -125,8 +125,8 @@ MainWindow::MainWindow(QWidget *parent) : auto layout = new QFormLayout(widget); { auto input = new QDoubleSpinBox; - input->setRange(0, 1.0); - input->setSingleStep(0.1); + input->setRange(0, 10000.0); + input->setSingleStep(1.0); input->setValue(m_ui->widget->afterglow()); connect(input, qOverload(&QDoubleSpinBox::valueChanged), m_ui->widget, &OsciWidget::setAfterglow); layout->addRow(tr("Afterglow:"), input); diff --git a/osciwidget.cpp b/osciwidget.cpp index 6891231..4c81d10 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -16,11 +16,12 @@ qint32 framesForDuration(qint64 duration){ OsciWidget::OsciWidget(QWidget *parent) : QOpenGLWidget{parent} + , m_bufferOffset{m_buffer.begin()} + , m_lastTime{0} , m_redrawTimerId(startTimer(1000/m_fps, Qt::PreciseTimer)) - , m_lastFrame{0} { - m_bufferTimer.start(); m_statsTimer.start(); + m_bufferTimer.start(); } int OsciWidget::lightspeed() const @@ -39,9 +40,11 @@ void OsciWidget::setFps(int fps) void OsciWidget::setAfterglow(float afterglow) { - m_afterglow = 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) @@ -57,7 +60,20 @@ void OsciWidget::renderSamples(const SamplePair *begin, const SamplePair *end) m_samplesCounter += std::distance(begin, end); + auto offset = std::distance(m_buffer.begin(), m_bufferOffset); + + if(m_bufferTimer.elapsed()-m_lastTime > 5000) + { + qDebug() << "deleting: " << m_bufferOffset - m_buffer.begin(); + //m_buffer.erase(m_buffer.begin(), m_bufferOffset); + m_buffer.clear(); + offset = 0; + + m_lastTime = m_bufferTimer.elapsed(); + } + //qDebug () << " inserting " << std::distance(begin, end); m_buffer.insert(m_buffer.end(), begin, end); + m_bufferOffset = m_buffer.begin() + offset; //m_bufferTimer.restart(); //qDebug() << m_statsTimer.elapsed(); } @@ -69,7 +85,7 @@ void OsciWidget::paintEvent(QPaintEvent *event) m_frameCounter++; 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_bufferTimer.elapsed())); m_frameCounter = 0; m_callbacksCounter = 0; m_samplesCounter = 0; @@ -86,15 +102,18 @@ void OsciWidget::darkenFrame() painter.setCompositionMode(QPainter::CompositionMode_Multiply); painter.setPen({}); - auto afterglowColor = 255 * pow(m_afterglow, 1.0/m_fps); + //auto afterglowColor = 255 * pow(m_decayTime, 1.0/m_fps); + auto afterglowColor = static_cast(255 * pow(exp(-1), 1000.0/m_decayTime/m_fps)); + qDebug() << afterglowColor; painter.setBrush(QColor(afterglowColor, afterglowColor, afterglowColor)); painter.drawRect(m_pixmap.rect()); + //m_pixmap.fill(Qt::black); } void OsciWidget::updateDrawBuffer() { - // Workaround for flickering (do not update, when there is no new data) - //if(m_buffer.empty()) return; + // If there is no new data do not update + if(m_buffer.empty()) return; if (m_pixmap.size() != size()) { @@ -114,17 +133,18 @@ void OsciWidget::updateDrawBuffer() pen.setColor(QColor(0, 255, 0)); painter.setPen(pen); - qint64 samplesUsed = 0; - double timeConstant = log(m_afterglow); - auto duration = m_bufferTimer.elapsed()*1000; - qint32 framesCnt = framesForDuration(duration); - //qDebug() << framesCnt << duration; + // persistance time is the time it needs to decay to 1/e ~ 36,7% - for (size_t idx = 0; idx < framesCnt && idx < m_buffer.size(); ++idx) + auto duration = 1000*(m_bufferTimer.elapsed()-m_lastTime); + auto framesOffset = framesForDuration(duration); + //qDebug() << framesOffset << m_buffer.size()-framesOffset << m_bufferOffset - m_buffer.begin(); + + //m_bufferBegin = m_buffer.begin(); + auto bufferEnd = m_buffer.begin() + framesOffset; + for (;m_bufferOffset < bufferEnd && m_bufferOffset != m_buffer.end(); ++m_bufferOffset) { - const auto &frame = m_buffer[idx]; - double time = (m_buffer.size() - samplesUsed) / 44100.0; + const auto &frame = *m_bufferOffset; const QPointF p{ float(frame.first) / std::numeric_limits::max(), @@ -132,8 +152,14 @@ void OsciWidget::updateDrawBuffer() }; const QLineF line(m_lastPoint, p); + + // the time of one sample is 1/samplerate + // the brightness auto beamOpacity = std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1)); - auto beamDecay = exp(time*timeConstant); + + + double time = 1000.0 * std::distance(m_bufferOffset, bufferEnd) / 44100.0; + auto beamDecay = exp(-time/m_decayTime); //qDebug() << time << beamDecay; painter.setOpacity(beamDecay*beamOpacity); @@ -141,10 +167,7 @@ void OsciWidget::updateDrawBuffer() painter.drawLine(m_lastPoint, p); m_lastPoint = p; - ++samplesUsed; } - - //m_buffer.clear(); } void OsciWidget::timerEvent(QTimerEvent *event) diff --git a/osciwidget.h b/osciwidget.h index cd9fe9f..297ed1a 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -21,7 +21,7 @@ public: float factor() const { return m_factor; } int fps() const { return m_fps; } - float afterglow() const { return m_afterglow; } + float afterglow() const { return m_decayTime; } int lightspeed() const; signals: @@ -44,19 +44,20 @@ private: private: float m_factor{1.f}; - int m_fps{30}; - float m_afterglow{0.01}; + int m_fps{60}; + float m_decayTime{25.0}; float m_lightspeed{35.f}; std::vector m_buffer; + std::vector::iterator m_bufferOffset; int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0}; QElapsedTimer m_statsTimer; QElapsedTimer m_bufferTimer; + qint64 m_lastTime; int m_redrawTimerId; QPointF m_lastPoint; - size_t m_lastFrame; QPixmap m_pixmap; void darkenFrame(); }; From 5df7b6fce5a54e9edcbd8ecadc92bba8d83e9eec Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 11:58:48 +0200 Subject: [PATCH 14/23] Adds TODO on how to clear the buffer --- osciwidget.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index 4c81d10..77546df 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -64,8 +64,11 @@ void OsciWidget::renderSamples(const SamplePair *begin, const SamplePair *end) if(m_bufferTimer.elapsed()-m_lastTime > 5000) { - qDebug() << "deleting: " << m_bufferOffset - m_buffer.begin(); + //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 m_buffer.clear(); offset = 0; From 2b9b1cf9a47f5d206078d2fd9ad1fc4080f9cf0c Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 12:42:09 +0200 Subject: [PATCH 15/23] Factor out drawBuffer from updateDrawBuffer --- osciwidget.cpp | 59 ++++++++++++++++++++++++++------------------------ osciwidget.h | 7 ++++-- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index 77546df..0e5188e 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -113,19 +113,9 @@ void OsciWidget::darkenFrame() //m_pixmap.fill(Qt::black); } -void OsciWidget::updateDrawBuffer() + +void OsciWidget::drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffer::iterator &end) { - // If there is no new data do not update - if(m_buffer.empty()) return; - - if (m_pixmap.size() != size()) - { - m_pixmap = QPixmap(size()); - m_pixmap.fill(Qt::black); - } - - darkenFrame(); - QPainter painter(&m_pixmap); 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); @@ -136,18 +126,9 @@ void OsciWidget::updateDrawBuffer() pen.setColor(QColor(0, 255, 0)); painter.setPen(pen); - - // persistance time is the time it needs to decay to 1/e ~ 36,7% - - auto duration = 1000*(m_bufferTimer.elapsed()-m_lastTime); - auto framesOffset = framesForDuration(duration); - //qDebug() << framesOffset << m_buffer.size()-framesOffset << m_bufferOffset - m_buffer.begin(); - - //m_bufferBegin = m_buffer.begin(); - auto bufferEnd = m_buffer.begin() + framesOffset; - for (;m_bufferOffset < bufferEnd && m_bufferOffset != m_buffer.end(); ++m_bufferOffset) + for (;bufferPos < end; ++bufferPos) { - const auto &frame = *m_bufferOffset; + const auto &frame = *bufferPos; const QPointF p{ float(frame.first) / std::numeric_limits::max(), @@ -156,23 +137,45 @@ void OsciWidget::updateDrawBuffer() const QLineF line(m_lastPoint, p); - // the time of one sample is 1/samplerate - // the brightness auto beamOpacity = std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1)); - double time = 1000.0 * std::distance(m_bufferOffset, bufferEnd) / 44100.0; + double time = 1000.0 * std::distance(bufferPos, end) / 44100.0; auto beamDecay = exp(-time/m_decayTime); - //qDebug() << time << beamDecay; painter.setOpacity(beamDecay*beamOpacity); - painter.drawLine(m_lastPoint, p); m_lastPoint = p; } } +void OsciWidget::resizeDrawBuffer() +{ + if (m_pixmap.size() != size()) + { + m_pixmap = QPixmap(size()); + m_pixmap.fill(Qt::black); + } +} + +void OsciWidget::updateDrawBuffer() +{ + // If there is no new data do not update + if(m_buffer.empty()) return; + + resizeDrawBuffer(); + darkenFrame(); + // persistance time is the time it needs to decay to 1/e ~ 36,7% + + auto duration = 1000*(m_bufferTimer.elapsed()-m_lastTime); + size_t framesOffset = framesForDuration(duration); + //qDebug() << framesOffset << m_buffer.size()-framesOffset << m_bufferOffset - m_buffer.begin(); + + auto bufferEnd = m_buffer.begin() + std::min(framesOffset, m_buffer.size()); + drawBuffer(m_bufferOffset, bufferEnd); +} + void OsciWidget::timerEvent(QTimerEvent *event) { QWidget::timerEvent(event); diff --git a/osciwidget.h b/osciwidget.h index 297ed1a..b12428b 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -48,8 +48,9 @@ private: float m_decayTime{25.0}; float m_lightspeed{35.f}; - std::vector m_buffer; - std::vector::iterator m_bufferOffset; + typedef std::vector SampleBuffer; + SampleBuffer m_buffer; + SampleBuffer::iterator m_bufferOffset; int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0}; QElapsedTimer m_statsTimer; @@ -60,4 +61,6 @@ private: QPointF m_lastPoint; QPixmap m_pixmap; void darkenFrame(); + void drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffer::iterator &end); + void resizeDrawBuffer(); }; From 86dccd467ec641b598e5bf73e19ddba338c2bb47 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 18:58:45 +0200 Subject: [PATCH 16/23] Uses alpha channel to draw lines, uses Qt::FlatCap style, uses QPainter::Antialiasing --- osciwidget.cpp | 55 +++++++++++++++++++++++++++++++++----------------- osciwidget.h | 6 +++--- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/osciwidget.cpp b/osciwidget.cpp index 0e5188e..e6f3f21 100644 --- a/osciwidget.cpp +++ b/osciwidget.cpp @@ -17,11 +17,11 @@ qint32 framesForDuration(qint64 duration){ OsciWidget::OsciWidget(QWidget *parent) : QOpenGLWidget{parent} , m_bufferOffset{m_buffer.begin()} - , m_lastTime{0} + , m_lastBufferUpdate{0} , m_redrawTimerId(startTimer(1000/m_fps, Qt::PreciseTimer)) { m_statsTimer.start(); - m_bufferTimer.start(); + m_globalTimer.start(); } int OsciWidget::lightspeed() const @@ -62,17 +62,18 @@ void OsciWidget::renderSamples(const SamplePair *begin, const SamplePair *end) auto offset = std::distance(m_buffer.begin(), m_bufferOffset); - if(m_bufferTimer.elapsed()-m_lastTime > 5000) + 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_lastTime = m_bufferTimer.elapsed(); + m_lastBufferUpdate = m_globalTimer.elapsed(); } //qDebug () << " inserting " << std::distance(begin, end); m_buffer.insert(m_buffer.end(), begin, end); @@ -88,7 +89,7 @@ void OsciWidget::paintEvent(QPaintEvent *event) m_frameCounter++; if (m_statsTimer.hasExpired(1000)) { - 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_bufferTimer.elapsed())); + 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_callbacksCounter = 0; m_samplesCounter = 0; @@ -103,28 +104,32 @@ void OsciWidget::darkenFrame() { QPainter painter(&m_pixmap); - painter.setCompositionMode(QPainter::CompositionMode_Multiply); - painter.setPen({}); + //auto afterglowColor = 255 * pow(m_decayTime, 1.0/m_fps); - auto afterglowColor = static_cast(255 * pow(exp(-1), 1000.0/m_decayTime/m_fps)); - qDebug() << afterglowColor; + auto afterglowFactor = pow(exp(-1), 1000.0/m_decayTime/m_fps); + auto afterglowColor = static_cast(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) +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); - pen.setColor(QColor(0, 255, 0)); - painter.setPen(pen); + // This prevents most of the overlapping when drawing lines from and to the same points + pen.setCapStyle(Qt::FlatCap); for (;bufferPos < end; ++bufferPos) { @@ -137,14 +142,26 @@ void OsciWidget::drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffe const QLineF line(m_lastPoint, p); - auto beamOpacity = std::min(1.0, 1. / ((line.length() * m_lightspeed) + 1)); - + 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); - painter.setOpacity(beamDecay*beamOpacity); + 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; } @@ -166,14 +183,14 @@ void OsciWidget::updateDrawBuffer() resizeDrawBuffer(); darkenFrame(); - // persistance time is the time it needs to decay to 1/e ~ 36,7% + // decay time is the time it needs to decay to 1/e ~ 36,7% - auto duration = 1000*(m_bufferTimer.elapsed()-m_lastTime); + auto duration = 1000*(m_globalTimer.elapsed()-m_lastBufferUpdate); size_t framesOffset = framesForDuration(duration); //qDebug() << framesOffset << m_buffer.size()-framesOffset << m_bufferOffset - m_buffer.begin(); auto bufferEnd = m_buffer.begin() + std::min(framesOffset, m_buffer.size()); - drawBuffer(m_bufferOffset, bufferEnd); + drawBuffer(m_bufferOffset, bufferEnd, QColor(0, 255, 0)); } void OsciWidget::timerEvent(QTimerEvent *event) diff --git a/osciwidget.h b/osciwidget.h index b12428b..9a498c7 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -54,13 +54,13 @@ private: int m_frameCounter{0}, m_callbacksCounter{0}, m_samplesCounter{0}; QElapsedTimer m_statsTimer; - QElapsedTimer m_bufferTimer; - qint64 m_lastTime; + QElapsedTimer m_globalTimer; + qint64 m_lastBufferUpdate; int m_redrawTimerId; QPointF m_lastPoint; QPixmap m_pixmap; void darkenFrame(); - void drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffer::iterator &end); + void drawBuffer(SampleBuffer::iterator &bufferPos, const SampleBuffer::iterator &end, QColor color); void resizeDrawBuffer(); }; From 5619ef7b14d7ef795c37de8707e87b9936e3b441 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 18:59:09 +0200 Subject: [PATCH 17/23] Tweak defaults for decay and lightspeed --- osciwidget.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osciwidget.h b/osciwidget.h index 9a498c7..778e498 100644 --- a/osciwidget.h +++ b/osciwidget.h @@ -45,8 +45,8 @@ private: private: float m_factor{1.f}; int m_fps{60}; - float m_decayTime{25.0}; - float m_lightspeed{35.f}; + float m_decayTime{29.0}; + float m_lightspeed{18.f}; typedef std::vector SampleBuffer; SampleBuffer m_buffer; From 14353ae5ce2a2d31e364d4d19e021e891d0c6a50 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 23:31:15 +0200 Subject: [PATCH 18/23] Make travis happy (i.e. c++11 compliant code) --- audiodevice.cpp | 2 +- basetonegenerator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/audiodevice.cpp b/audiodevice.cpp index d71b850..a1e25f8 100644 --- a/audiodevice.cpp +++ b/audiodevice.cpp @@ -44,7 +44,7 @@ void AudioDevice::start() format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); - m_private = std::make_unique(*this, m_device, format); + m_private = std::unique_ptr(new AudioDevicePrivate(*this, m_device, format)); m_private->input.start(&m_private->helper); //m_private->input.setBufferSize(m_samplerate/m_framerate*sizeof(qint16)*2); } diff --git a/basetonegenerator.cpp b/basetonegenerator.cpp index 163f488..0075745 100644 --- a/basetonegenerator.cpp +++ b/basetonegenerator.cpp @@ -42,7 +42,7 @@ void BaseToneGenerator::start() format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); - m_private = std::make_unique(*this, m_device, format); + m_private = std::unique_ptr(new BaseToneGeneratorPrivate(*this, m_device, format)); m_private->output.start(&m_private->helper); } From 7e17181bea0fa5466484e87983b65130dbc1f6d0 Mon Sep 17 00:00:00 2001 From: Gitea Date: Sun, 22 Sep 2019 23:52:00 +0200 Subject: [PATCH 19/23] Try bionic for more recent compilers --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e7a3db6..f9d7f25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: cpp os: linux sudo: false -dist: trusty +dist: bionic compiler: - gcc - clang From 3dc0610c0999a678d111621e7611493e7ede7dc1 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 23 Sep 2019 00:04:27 +0200 Subject: [PATCH 20/23] Adds OpenGl deps to travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index f9d7f25..845007a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,9 @@ cache: - ~/.ccache - qt5 +before_install: + - sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev + install: - mkdir -p qt5 - if [ ! -d qt5/.git ] ; then rm qt5 -Rf ; git clone --branch=5.10 git://code.qt.io/qt/qt5.git ; fi From ff700dd75a669ab39cc5c05ef528492a64d03795 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 23 Sep 2019 00:06:59 +0200 Subject: [PATCH 21/23] Revert "qt 5.10" This reverts commit 9c573faba15001488b8c8a32ea2844f2a6216f63. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 845007a..fb278c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ before_install: install: - mkdir -p qt5 - - if [ ! -d qt5/.git ] ; then rm qt5 -Rf ; git clone --branch=5.10 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 - pushd qt5 - if [ ! -d qtbase/.git ] ; then perl init-repository --module-subset=qtbase,qtimageformats,qtmultimedia,qttools ; fi - if [ ! -f config.summary ] ; then ./configure -prefix `pwd`/build -opensource -confirm-license -nomake examples -nomake tests ; fi From 339fedea9afcb5394dd0c7f9656fdfbe4b5cdc70 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 23 Sep 2019 00:07:54 +0200 Subject: [PATCH 22/23] Revert "Make travis happy (i.e. c++11 compliant code)" This reverts commit 14353ae5ce2a2d31e364d4d19e021e891d0c6a50. --- audiodevice.cpp | 2 +- basetonegenerator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/audiodevice.cpp b/audiodevice.cpp index a1e25f8..d71b850 100644 --- a/audiodevice.cpp +++ b/audiodevice.cpp @@ -44,7 +44,7 @@ void AudioDevice::start() format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); - m_private = std::unique_ptr(new AudioDevicePrivate(*this, m_device, format)); + m_private = std::make_unique(*this, m_device, format); m_private->input.start(&m_private->helper); //m_private->input.setBufferSize(m_samplerate/m_framerate*sizeof(qint16)*2); } diff --git a/basetonegenerator.cpp b/basetonegenerator.cpp index 0075745..163f488 100644 --- a/basetonegenerator.cpp +++ b/basetonegenerator.cpp @@ -42,7 +42,7 @@ void BaseToneGenerator::start() format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); - m_private = std::unique_ptr(new BaseToneGeneratorPrivate(*this, m_device, format)); + m_private = std::make_unique(*this, m_device, format); m_private->output.start(&m_private->helper); } From 682927bb1384490346c432460e222301bb88d961 Mon Sep 17 00:00:00 2001 From: Gitea Date: Mon, 23 Sep 2019 00:23:50 +0200 Subject: [PATCH 23/23] Adds audio deps to travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index fb278c3..ff4bd1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,8 @@ cache: 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: - mkdir -p qt5