diff --git a/app/widget/timelinewidget/timelinescaledobject.h b/app/widget/timelinewidget/timelinescaledobject.h index 26a151a6f..b8afc1bd1 100644 --- a/app/widget/timelinewidget/timelinescaledobject.h +++ b/app/widget/timelinewidget/timelinescaledobject.h @@ -45,6 +45,7 @@ private: class TimelineScaledWidget : public QWidget, public TimelineScaledObject { + Q_OBJECT public: TimelineScaledWidget(QWidget* parent = nullptr); }; diff --git a/app/widget/timelinewidget/view/timelineviewblockitem.cpp b/app/widget/timelinewidget/view/timelineviewblockitem.cpp index 7b012a583..a0792c6a9 100644 --- a/app/widget/timelinewidget/view/timelineviewblockitem.cpp +++ b/app/widget/timelinewidget/view/timelineviewblockitem.cpp @@ -29,11 +29,10 @@ #include #include -#include "audio/sumsamples.h" -#include "common/clamp.h" #include "common/qtutils.h" #include "config/config.h" #include "node/block/transition/transition.h" +#include "widget/viewer/waveformview.h" TimelineViewBlockItem::TimelineViewBlockItem(Block *block, QGraphicsItem* parent) : TimelineViewRect(parent), @@ -94,47 +93,12 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI QByteArray w = wave_file.readAll(); // FIXME: Hardcoded channel count - int channels = 2; - - const SampleSummer::Sum* samples = reinterpret_cast(w.constData()); - int nb_samples = w.size() / sizeof(SampleSummer::Sum); - - int sample_index, next_sample_index = 0; - - QVector summary; - int summary_index = -1; - - int channel_height = rect().height() / channels; - int channel_half_height = channel_height / 2; - - for (int i=0;i(SampleSummer::kSumSampleRate) * static_cast(i+1) / this->GetScale()) * channels); - - if (summary_index != sample_index) { - summary = SampleSummer::ReSumSamples(&samples[sample_index], - qMax(channels, next_sample_index - sample_index), - channels); - summary_index = sample_index; - } - - int line_x = i + rect().x(); - - for (int j=0;jdrawLine(line_x, - channel_mid + clamp(qRound(summary.at(j).min * channel_half_height), -channel_half_height, channel_half_height), - line_x, - channel_mid + clamp(qRound(summary.at(j).max * channel_half_height), -channel_half_height, channel_half_height)); - } - } + WaveformView::DrawWaveform(painter, + rect().toRect(), + this->GetScale(), + reinterpret_cast(w.constData()), + w.size() / sizeof(SampleSummer::Sum), + 2); wave_file.close(); } diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index a2a8230fd..747296c0b 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -70,6 +70,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : // Create scrollbar layout->addWidget(scrollbar()); connect(scrollbar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); + connect(scrollbar(), &QScrollBar::valueChanged, waveform_view_, &WaveformView::SetScroll); // Create lower controls controls_ = new PlaybackControls(); @@ -94,6 +95,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler(), &TimeRuler::CacheInvalidatedRange); audio_renderer_ = new AudioBackend(this); + waveform_view_->SetBackend(audio_renderer_); + connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererParameters); SetAutoMaxScrollBar(true); @@ -180,6 +183,13 @@ void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n) audio_renderer_->SetViewerNode(n); } +void ViewerWidget::ScaleChangedEvent(const double &s) +{ + TimeBasedWidget::ScaleChangedEvent(s); + + waveform_view_->SetScale(s); +} + void ViewerWidget::resizeEvent(QResizeEvent *event) { TimeBasedWidget::resizeEvent(event); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index a45a34691..5a702b9bc 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -114,6 +114,8 @@ protected: virtual void DisconnectNodeInternal(ViewerOutput *) override; virtual void ConnectedNodeChanged(ViewerOutput*n) override; + virtual void ScaleChangedEvent(const double& s) override; + virtual void resizeEvent(QResizeEvent *event) override; OpenGLBackend* video_renderer_; diff --git a/app/widget/viewer/waveformview.cpp b/app/widget/viewer/waveformview.cpp index 130993efb..20508eb87 100644 --- a/app/widget/viewer/waveformview.cpp +++ b/app/widget/viewer/waveformview.cpp @@ -1,24 +1,148 @@ #include "waveformview.h" +#include #include #include +#include "common/clamp.h" + WaveformView::WaveformView(QWidget *parent) : - TimeBasedWidget(parent) + TimelineScaledWidget(parent), + backend_(nullptr) { setAutoFillBackground(true); - setStyleSheet("background: black;"); + setBackgroundRole(QPalette::Base); +} + +void WaveformView::SetBackend(AudioRenderBackend *backend) +{ + if (backend_) { + disconnect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast(&WaveformView::update)); + } + + backend_ = backend; + + if (backend_) { + connect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast(&WaveformView::update)); + } + + update(); +} + +void WaveformView::DrawWaveform(QPainter *painter, const QRect& rect, const double& scale, const SampleSummer::Sum* samples, int nb_samples, int channels) +{ + int sample_index, next_sample_index = 0; + + QVector summary; + int summary_index = -1; + + int channel_height = rect.height() / channels; + int channel_half_height = channel_height / 2; + + for (int i=0;i(SampleSummer::kSumSampleRate) * static_cast(i+1) / scale) * channels); + + if (summary_index != sample_index) { + summary = SampleSummer::ReSumSamples(&samples[sample_index], + qMax(channels, next_sample_index - sample_index), + channels); + summary_index = sample_index; + } + + int line_x = i + rect.x(); + + for (int j=0;jdrawLine(line_x, + channel_mid + clamp(qRound(summary.at(j).min * channel_half_height), -channel_half_height, channel_half_height), + line_x, + channel_mid + clamp(qRound(summary.at(j).max * channel_half_height), -channel_half_height, channel_half_height)); + } + } +} + +void WaveformView::SetScroll(int scroll) +{ + scroll_ = scroll; + + qDebug() << "Got scroll" << scroll_; + + update(); } void WaveformView::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); - QPainter p(this); + if (!backend_ || backend_->CachePathName().isEmpty() || !backend_->params().is_valid()) { + return; + } - p.setPen(Qt::green); + const AudioRenderingParams& params = backend_->params(); + + QFile fs(backend_->CachePathName()); + + if (fs.open(QFile::ReadOnly)) { + + QPainter p(this); + + p.setPen(Qt::green); + + int channel_height = height() / params.channel_count(); + int channel_half_height = channel_height / 2; + + int drew = 0; + + fs.seek(params.samples_to_bytes(GetSampleIndexFromPixel(0))); + + for (int x=0; x samples = SampleSummer::SumSamples(reinterpret_cast(read_buffer.constData()), + samples_len, + params.channel_count()); + + for (int i=0;i(channel_half_height), + x, + channel_mid + samples.at(i).max * static_cast(channel_half_height)); + + drew++; + } + } + + fs.close(); - for (int i=0;i(i) * 0.025) * (height() / 2)); } } + +void WaveformView::ScaleChangedEvent(const double &) +{ + update(); +} + +int WaveformView::GetSampleIndexFromPixel(int x) const +{ + qDebug() << "X was" << x << "scroll was" << scroll_ << "=" << (x + scroll_); + return qRound(static_cast(x + scroll_) * static_cast(backend_->params().sample_rate()) / GetScale()); +} diff --git a/app/widget/viewer/waveformview.h b/app/widget/viewer/waveformview.h index cc1a1c17a..1bc3b542c 100644 --- a/app/widget/viewer/waveformview.h +++ b/app/widget/viewer/waveformview.h @@ -1,16 +1,40 @@ #ifndef WAVEFORMVIEW_H #define WAVEFORMVIEW_H -#include "widget/timebased/timebased.h" +#include -class WaveformView : public TimeBasedWidget +#include "audio/sumsamples.h" +#include "render/audioparams.h" +#include "render/backend/audiorenderbackend.h" +#include "widget/timelinewidget/timelinescaledobject.h" + +class WaveformView : public TimelineScaledWidget { + Q_OBJECT public: WaveformView(QWidget* parent = nullptr); + //void SetData(const QString& file, const AudioRenderingParams& params); + + void SetBackend(AudioRenderBackend* backend); + + static void DrawWaveform(QPainter* painter, const QRect &rect, const double &scale, const SampleSummer::Sum *samples, int nb_samples, int channels); + +public slots: + void SetScroll(int scroll); + protected: virtual void paintEvent(QPaintEvent* event) override; + virtual void ScaleChangedEvent(const double& s) override; + +private: + int GetSampleIndexFromPixel(int x) const; + + AudioRenderBackend* backend_; + + int scroll_; + }; #endif // WAVEFORMVIEW_H