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(); };