diff --git a/app/common/timecodefunctions.cpp b/app/common/timecodefunctions.cpp index c2725290b..86c9eaf36 100644 --- a/app/common/timecodefunctions.cpp +++ b/app/common/timecodefunctions.cpp @@ -258,13 +258,3 @@ int64_t Timecode::time_to_timestamp(const double &time, const rational &timebase { return qRound64(time * timebase.flipped().toDouble()); } - -Timecode::Display Timecode::CurrentDisplay() -{ - return static_cast(Config::Current()["TimecodeDisplay"].toInt()); -} - -void Timecode::SetCurrentDisplay(Timecode::Display d) -{ - Config::Current()["TimecodeDisplay"] = d; -} diff --git a/app/common/timecodefunctions.h b/app/common/timecodefunctions.h index e9bb4d35d..0d1748394 100644 --- a/app/common/timecodefunctions.h +++ b/app/common/timecodefunctions.h @@ -45,9 +45,6 @@ public: kMilliseconds }; - static Display CurrentDisplay(); - static void SetCurrentDisplay(Display d); - /** * @brief Convert a timestamp (according to a rational timebase) to a user-friendly string representation */ diff --git a/app/config/config.cpp b/app/config/config.cpp index f9c1bcb46..88d80d4c0 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -77,6 +77,7 @@ void Config::SetDefaults() config_map_["DefaultViewerDivider"] = 2; config_map_["AutoSelectDivider"] = false; config_map_["SetNameWithMarker"] = false; + config_map_["RectifiedWaveforms"] = false; config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk; config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); diff --git a/app/core.cpp b/app/core.cpp index e87e1d755..7854a5271 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -482,6 +482,18 @@ Folder *Core::GetSelectedFolderInActiveProject() } } +Timecode::Display Core::GetTimecodeDisplay() const +{ + return static_cast(Config::Current()["TimecodeDisplay"].toInt()); +} + +void Core::SetTimecodeDisplay(Timecode::Display d) +{ + Config::Current()["TimecodeDisplay"] = d; + + emit TimecodeDisplayChanged(d); +} + void Core::SetProjectModified(bool e) { main_window()->setWindowModified(e); diff --git a/app/core.h b/app/core.h index 9fdb85501..5cb9bc6cf 100644 --- a/app/core.h +++ b/app/core.h @@ -26,6 +26,7 @@ #include #include "common/rational.h" +#include "common/timecodefunctions.h" #include "project/item/footage/footage.h" #include "project/item/sequence/sequence.h" #include "project/project.h" @@ -125,6 +126,16 @@ public: ProjectViewModel* GetActiveProjectModel(); Folder* GetSelectedFolderInActiveProject(); + /** + * @brief Gets current timecode display mode + */ + Timecode::Display GetTimecodeDisplay() const; + + /** + * @brief Sets current timecode display mode + */ + void SetTimecodeDisplay(Timecode::Display d); + /** * @brief Sets state to "modified" so that the GUI will prompt the user to save before closing * @@ -269,6 +280,11 @@ signals: */ void SnappingChanged(const bool& b); + /** + * @brief Signal emitted when the default timecode display mode changed + */ + void TimecodeDisplayChanged(Timecode::Display d); + private: /** * @brief Get the file filter than can be used with QFileDialog to open and save compatible projects diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp index 2412619cd..cbb75d12e 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp @@ -2,8 +2,6 @@ #include #include -#include -#include #include #include "common/autoscroll.h" @@ -74,6 +72,14 @@ PreferencesGeneralTab::PreferencesGeneralTab() row++; + general_layout->addWidget(new QLabel(tr("Rectified Waveforms:")), row, 0); + + rectified_waveforms_ = new QCheckBox(); + rectified_waveforms_->setChecked(Config::Current()["RectifiedWaveforms"].toBool()); + general_layout->addWidget(rectified_waveforms_, row, 1); + + row++; + general_layout->addWidget(new QLabel(tr("Default Still Image Length:")), row, 0); default_still_length_ = new FloatSlider(); @@ -101,6 +107,8 @@ void PreferencesGeneralTab::Accept() Config::Current()["DefaultSequenceAudioFrequency"] = default_sequence_.audio_params().sample_rate(); Config::Current()["DefaultSequenceAudioLayout"] = QVariant::fromValue(default_sequence_.audio_params().channel_layout()); + Config::Current()["RectifiedWaveforms"] = rectified_waveforms_->isChecked(); + Config::Current()["Autoscroll"] = autoscroll_method_->currentData(); Config::Current()["DefaultStillLength"] = QVariant::fromValue(rational::fromDouble(default_still_length_->GetValue())); diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.h b/app/dialog/preferences/tabs/preferencesgeneraltab.h index b05633040..f6d6d8f2a 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.h +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.h @@ -1,6 +1,7 @@ #ifndef PREFERENCESGENERALTAB_H #define PREFERENCESGENERALTAB_H +#include #include #include @@ -27,6 +28,8 @@ private: QComboBox* autoscroll_method_; + QCheckBox* rectified_waveforms_; + FloatSlider* default_still_length_; /** diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index e0b98a9ac..4434eb531 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -23,9 +23,9 @@ #include #include "codec/decoder.h" -#include "common/timecodefunctions.h" #include "common/xmlutils.h" #include "config/config.h" +#include "core.h" #include "ui/icons/icons.h" Footage::Footage() @@ -40,8 +40,6 @@ Footage::~Footage() void Footage::Load(QXmlStreamReader *reader, QHash& footage_ptrs, QList&, const QAtomicInt* cancelled) { - qDebug() << "Hello?"; - QXmlStreamAttributes attributes = reader->attributes(); foreach (const QXmlStreamAttribute& attr, attributes) { @@ -234,12 +232,12 @@ QString Footage::duration() return Timecode::timestamp_to_timecode(duration, frame_rate_timebase, - Timecode::CurrentDisplay()); + Core::instance()->GetTimecodeDisplay()); } else if (streams_.first()->type() == Stream::kAudio) { AudioStreamPtr audio_stream = std::static_pointer_cast(streams_.first()); // If we're showing in a timecode, we prefer showing audio in seconds instead - Timecode::Display display = Timecode::CurrentDisplay(); + Timecode::Display display = Core::instance()->GetTimecodeDisplay(); if (display == Timecode::kTimecodeDropFrame || display == Timecode::kTimecodeNonDropFrame) { display = Timecode::kTimecodeSeconds; diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index f15344310..00101f126 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -199,7 +199,7 @@ QString Sequence::duration() int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params().time_base()); - return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Timecode::CurrentDisplay()); + return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Core::instance()->GetTimecodeDisplay()); } QString Sequence::rate() diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index 523a7a9e5..400fdedba 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -24,7 +24,7 @@ #include #include -#include "common/timecodefunctions.h" +#include "core.h" #include "config/config.h" #include "ui/icons/icons.h" @@ -120,6 +120,8 @@ PlaybackControls::PlaybackControls(QWidget *parent) : UpdateIcons(); SetTimebase(0); + + connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &PlaybackControls::TimecodeChanged); } void PlaybackControls::SetTimecodeEnabled(bool enabled) @@ -147,9 +149,11 @@ void PlaybackControls::SetEndTime(const int64_t &r) return; } - end_tc_lbl_->setText(Timecode::timestamp_to_timecode(r, + end_time_ = r; + + end_tc_lbl_->setText(Timecode::timestamp_to_timecode(end_time_, time_base_, - Timecode::CurrentDisplay())); + Core::instance()->GetTimecodeDisplay())); } void PlaybackControls::ShowPauseButton() @@ -181,3 +185,9 @@ void PlaybackControls::UpdateIcons() next_frame_btn_->setIcon(icon::NextFrame); go_to_end_btn_->setIcon(icon::GoToEnd); } + +void PlaybackControls::TimecodeChanged() +{ + // Update end time + SetEndTime(end_time_); +} diff --git a/app/widget/playbackcontrols/playbackcontrols.h b/app/widget/playbackcontrols/playbackcontrols.h index 2c9701d91..9ad983f0b 100644 --- a/app/widget/playbackcontrols/playbackcontrols.h +++ b/app/widget/playbackcontrols/playbackcontrols.h @@ -101,6 +101,8 @@ private: TimeSlider* cur_tc_lbl_; QLabel* end_tc_lbl_; + int64_t end_time_; + rational time_base_; QPushButton* go_to_start_btn_; @@ -113,7 +115,7 @@ private: QStackedWidget* playpause_stack_; private slots: - + void TimecodeChanged(); }; diff --git a/app/widget/slider/timeslider.cpp b/app/widget/slider/timeslider.cpp index 5899596db..4d59c007c 100644 --- a/app/widget/slider/timeslider.cpp +++ b/app/widget/slider/timeslider.cpp @@ -1,11 +1,14 @@ #include "timeslider.h" #include "common/timecodefunctions.h" +#include "core.h" TimeSlider::TimeSlider(QWidget *parent) : IntegerSlider(parent) { SetMinimum(0); + + connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &TimeSlider::TimecodeDisplayChanged); } void TimeSlider::SetTimebase(const rational &timebase) @@ -25,10 +28,15 @@ QString TimeSlider::ValueToString(const QVariant &v) return Timecode::timestamp_to_timecode(v.toLongLong(), timebase_, - Timecode::CurrentDisplay()); + Core::instance()->GetTimecodeDisplay()); } QVariant TimeSlider::StringToValue(const QString &s, bool *ok) { - return QVariant::fromValue(Timecode::timecode_to_timestamp(s, timebase_, Timecode::CurrentDisplay(), ok)); + return QVariant::fromValue(Timecode::timecode_to_timestamp(s, timebase_, Core::instance()->GetTimecodeDisplay(), ok)); +} + +void TimeSlider::TimecodeDisplayChanged() +{ + UpdateLabel(Value()); } diff --git a/app/widget/slider/timeslider.h b/app/widget/slider/timeslider.h index 331572d96..a69c0f31b 100644 --- a/app/widget/slider/timeslider.h +++ b/app/widget/slider/timeslider.h @@ -6,6 +6,7 @@ class TimeSlider : public IntegerSlider { + Q_OBJECT public: TimeSlider(QWidget* parent = nullptr); @@ -19,6 +20,9 @@ protected: private: rational timebase_; +private slots: + void TimecodeDisplayChanged(); + }; #endif // TIMESLIDER_H diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index 366f46277..92293cbd4 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -143,7 +143,7 @@ void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event) int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, parent()->timebase()); QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, parent()->timebase(), - Timecode::CurrentDisplay()); + Core::instance()->GetTimecodeDisplay()); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way // of the cursor) diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index e88cad283..80fd34194 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -404,7 +404,7 @@ void TimelineWidget::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_po int64_t earliest_timestamp = Timecode::time_to_timestamp(time_movement, parent()->timebase()); QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, parent()->timebase(), - Timecode::CurrentDisplay(), + Core::instance()->GetTimecodeDisplay(), true); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way diff --git a/app/widget/timelinewidget/tool/slip.cpp b/app/widget/timelinewidget/tool/slip.cpp index b13f5297e..299ed5f22 100644 --- a/app/widget/timelinewidget/tool/slip.cpp +++ b/app/widget/timelinewidget/tool/slip.cpp @@ -54,7 +54,7 @@ void TimelineWidget::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) int64_t earliest_timestamp = Timecode::time_to_timestamp(time_movement, parent()->timebase()); QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, parent()->timebase(), - Timecode::CurrentDisplay(), + Core::instance()->GetTimecodeDisplay(), true); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way // of the cursor) diff --git a/app/widget/timelinewidget/view/timelineviewblockitem.cpp b/app/widget/timelinewidget/view/timelineviewblockitem.cpp index a0792c6a9..c70c979da 100644 --- a/app/widget/timelinewidget/view/timelineviewblockitem.cpp +++ b/app/widget/timelinewidget/view/timelineviewblockitem.cpp @@ -32,7 +32,7 @@ #include "common/qtutils.h" #include "config/config.h" #include "node/block/transition/transition.h" -#include "widget/viewer/waveformview.h" +#include "widget/viewer/audiowaveformview.h" TimelineViewBlockItem::TimelineViewBlockItem(Block *block, QGraphicsItem* parent) : TimelineViewRect(parent), @@ -93,7 +93,7 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI QByteArray w = wave_file.readAll(); // FIXME: Hardcoded channel count - WaveformView::DrawWaveform(painter, + AudioWaveformView::DrawWaveform(painter, rect().toRect(), this->GetScale(), reinterpret_cast(w.constData()), diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index c9ff31939..25b504995 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -47,6 +47,9 @@ TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* pare // Text visibility affects height, so we set that here UpdateHeight(); + + // Force update if the default timecode display mode changes + connect(Core::instance(), &Core::TimecodeDisplayChanged, this, static_cast(&TimeRuler::update)); } void TimeRuler::SetCacheStatusLength(const rational &length) @@ -203,7 +206,7 @@ void TimeRuler::paintEvent(QPaintEvent *) if (text_visible_) { QRect text_rect; Qt::Alignment text_align; - QString timecode_str = Timecode::timestamp_to_timecode(ScreenToUnit(i), timebase(), Timecode::CurrentDisplay()); + QString timecode_str = Timecode::timestamp_to_timecode(ScreenToUnit(i), timebase(), Core::instance()->GetTimecodeDisplay()); int timecode_width = QFontMetricsWidth(fm, timecode_str); int timecode_left; diff --git a/app/widget/viewer/CMakeLists.txt b/app/widget/viewer/CMakeLists.txt index 6d99220dc..16693f4de 100644 --- a/app/widget/viewer/CMakeLists.txt +++ b/app/widget/viewer/CMakeLists.txt @@ -16,6 +16,8 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} + widget/viewer/audiowaveformview.h + widget/viewer/audiowaveformview.cpp widget/viewer/footageviewer.h widget/viewer/footageviewer.cpp widget/viewer/viewer.h @@ -24,7 +26,5 @@ set(OLIVE_SOURCES widget/viewer/viewerglwidget.cpp widget/viewer/viewersizer.h widget/viewer/viewersizer.cpp - widget/viewer/waveformview.h - widget/viewer/waveformview.cpp PARENT_SCOPE ) diff --git a/app/widget/viewer/audiowaveformview.cpp b/app/widget/viewer/audiowaveformview.cpp new file mode 100644 index 000000000..dd7ac643b --- /dev/null +++ b/app/widget/viewer/audiowaveformview.cpp @@ -0,0 +1,189 @@ +#include "audiowaveformview.h" + +#include +#include +#include + +#include "common/clamp.h" +#include "config/config.h" + +AudioWaveformView::AudioWaveformView(QWidget *parent) : + SeekableWidget(parent), + backend_(nullptr) +{ + setAutoFillBackground(true); + setBackgroundRole(QPalette::Base); +} + +void AudioWaveformView::SetBackend(AudioRenderBackend *backend) +{ + if (backend_) { + disconnect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast(&AudioWaveformView::update)); + disconnect(backend_, &AudioRenderBackend::ParamsChanged, this, &AudioWaveformView::BackendParamsChanged); + + SetTimebase(0); + } + + backend_ = backend; + + if (backend_) { + connect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast(&AudioWaveformView::update)); + connect(backend_, &AudioRenderBackend::ParamsChanged, this, &AudioWaveformView::BackendParamsChanged); + + SetTimebase(backend_->params().time_base()); + } + + update(); +} + +void AudioWaveformView::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_bottom - diff, + line_x, + channel_bottom); + } else{ + int channel_mid = rect.y() + channel_height * j + channel_half_height; + + painter->drawLine(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 AudioWaveformView::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + + if (!backend_ || backend_->CachePathName().isEmpty() || !backend_->params().is_valid()) { + return; + } + + const AudioRenderingParams& params = backend_->params(); + + if (cached_size_ != size() + || cached_scale_ != GetScale() + || cached_scroll_ != GetScroll()) { + + cached_waveform_ = QPixmap(size()); + cached_waveform_.fill(Qt::transparent); + + QFile fs(backend_->CachePathName()); + + if (fs.open(QFile::ReadOnly)) { + + QPainter wave_painter(&cached_waveform_); + + // FIXME: Hardcoded color + wave_painter.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(ScreenToUnitRounded(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++; + } + } + + cached_size_ = size(); + cached_scale_ = GetScale(); + cached_scroll_ = GetScroll(); + + fs.close(); + + } + } + + QPainter p(this); + + // Draw in/out points + DrawTimelinePoints(&p); + + // Draw cached waveform pixmap + p.drawPixmap(0, 0, cached_waveform_); + + // Draw playhead + p.setPen(GetPlayheadColor()); + + int playhead_x = UnitToScreen(GetTime()); + p.drawLine(playhead_x, 0, playhead_x, height()); +} + +void AudioWaveformView::BackendParamsChanged() +{ + SetTimebase(backend_->params().time_base()); +} diff --git a/app/widget/viewer/waveformview.h b/app/widget/viewer/audiowaveformview.h similarity index 78% rename from app/widget/viewer/waveformview.h rename to app/widget/viewer/audiowaveformview.h index 1e92e2d1d..283670c1d 100644 --- a/app/widget/viewer/waveformview.h +++ b/app/widget/viewer/audiowaveformview.h @@ -8,11 +8,11 @@ #include "render/backend/audiorenderbackend.h" #include "widget/timeruler/seekablewidget.h" -class WaveformView : public SeekableWidget +class AudioWaveformView : public SeekableWidget { Q_OBJECT public: - WaveformView(QWidget* parent = nullptr); + AudioWaveformView(QWidget* parent = nullptr); //void SetData(const QString& file, const AudioRenderingParams& params); @@ -26,6 +26,11 @@ protected: private: AudioRenderBackend* backend_; + QPixmap cached_waveform_; + QSize cached_size_; + double cached_scale_; + int cached_scroll_; + private slots: void BackendParamsChanged(); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 4ff69b2d2..d2408630b 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -61,7 +61,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : sizer_->SetWidget(gl_widget_); // Create waveform view when audio is connected and video isn't - waveform_view_ = new WaveformView(); + waveform_view_ = new AudioWaveformView(); stack_->addWidget(waveform_view_); // Create time ruler @@ -70,7 +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); + connect(scrollbar(), &QScrollBar::valueChanged, waveform_view_, &AudioWaveformView::SetScroll); // Create lower controls controls_ = new PlaybackControls(); @@ -96,7 +96,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : audio_renderer_ = new AudioBackend(this); waveform_view_->SetBackend(audio_renderer_); - connect(waveform_view_, &WaveformView::TimeChanged, this, &ViewerWidget::SetTimeAndSignal); + connect(waveform_view_, &AudioWaveformView::TimeChanged, this, &ViewerWidget::SetTimeAndSignal); connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererParameters); @@ -306,8 +306,8 @@ void ViewerWidget::PushScrubbedAudio() QIODevice* audio_src = audio_renderer_->GetAudioPullDevice(); if (audio_src && audio_src->open(QFile::ReadOnly)) { - // Try to get one "frame" of audio - int size_of_sample = audio_renderer_->params().time_to_bytes(timebase()); + // FIXME: Hardcoded scrubbing interval (20ms) + int size_of_sample = audio_renderer_->params().time_to_bytes(rational(20, 1000)); // Push audio audio_src->seek(audio_renderer_->params().time_to_bytes(GetTime())); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 88aab38b7..4c3c642dd 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -28,6 +28,7 @@ #include #include +#include "audiowaveformview.h" #include "common/rational.h" #include "node/output/viewer/viewer.h" #include "render/backend/opengl/openglbackend.h" @@ -35,7 +36,6 @@ #include "render/backend/audio/audiobackend.h" #include "viewerglwidget.h" #include "viewersizer.h" -#include "waveformview.h" #include "widget/playbackcontrols/playbackcontrols.h" #include "widget/timebased/timebased.h" @@ -159,7 +159,7 @@ private: bool time_changed_from_timer_; - WaveformView* waveform_view_; + AudioWaveformView* waveform_view_; private slots: void PlaybackTimerUpdate(); diff --git a/app/widget/viewer/waveformview.cpp b/app/widget/viewer/waveformview.cpp deleted file mode 100644 index e6305bc16..000000000 --- a/app/widget/viewer/waveformview.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "waveformview.h" - -#include -#include -#include - -#include "common/clamp.h" - -WaveformView::WaveformView(QWidget *parent) : - SeekableWidget(parent), - backend_(nullptr) -{ - setAutoFillBackground(true); - setBackgroundRole(QPalette::Base); -} - -void WaveformView::SetBackend(AudioRenderBackend *backend) -{ - if (backend_) { - disconnect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast(&WaveformView::update)); - disconnect(backend_, &AudioRenderBackend::ParamsChanged, this, &WaveformView::BackendParamsChanged); - - SetTimebase(0); - } - - backend_ = backend; - - if (backend_) { - connect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast(&WaveformView::update)); - connect(backend_, &AudioRenderBackend::ParamsChanged, this, &WaveformView::BackendParamsChanged); - - SetTimebase(backend_->params().time_base()); - } - - 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::paintEvent(QPaintEvent *event) -{ - QWidget::paintEvent(event); - - if (!backend_ || backend_->CachePathName().isEmpty() || !backend_->params().is_valid()) { - return; - } - - const AudioRenderingParams& params = backend_->params(); - - QFile fs(backend_->CachePathName()); - - if (fs.open(QFile::ReadOnly)) { - - QPainter p(this); - - DrawTimelinePoints(&p); - - // FIXME: Hardcoded color - 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(ScreenToUnitRounded(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(); - - // Draw playhead - p.setPen(GetPlayheadColor()); - - int playhead_x = UnitToScreen(GetTime()); - p.drawLine(playhead_x, 0, playhead_x, height()); - - } -} - -void WaveformView::BackendParamsChanged() -{ - SetTimebase(rational(1, backend_->params().sample_rate())); -} diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index 95c4eba68..1034fe378 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -100,9 +100,6 @@ MainMenu::MainMenu(QMainWindow *parent) : view_show_all_item_ = view_menu_->AddItem("showall", nullptr, nullptr, "\\"); view_show_all_item_->setCheckable(true); view_menu_->addSeparator(); - view_rectified_waveforms_item_ = view_menu_->AddItem("rectifiedwaveforms", nullptr, nullptr); - view_rectified_waveforms_item_->setCheckable(true); - view_menu_->addSeparator(); frame_view_mode_group_ = new QActionGroup(this); @@ -327,7 +324,7 @@ void MainMenu::TimecodeDisplayTriggered() Timecode::Display display = static_cast(action->data().toInt()); // Set the current display mode - Timecode::SetCurrentDisplay(display); + Core::instance()->SetTimecodeDisplay(display); } void MainMenu::FileMenuAboutToShow() @@ -343,7 +340,7 @@ void MainMenu::ViewMenuAboutToShow() // Ensure checked timecode display mode is correct QList timecode_display_actions = frame_view_mode_group_->actions(); foreach (QAction* a, timecode_display_actions) { - if (a->data() == Timecode::CurrentDisplay()) { + if (a->data() == Core::instance()->GetTimecodeDisplay()) { a->setChecked(true); break; } @@ -553,7 +550,6 @@ void MainMenu::Retranslate() view_increase_track_height_item_->setText(tr("Increase Track Height")); view_decrease_track_height_item_->setText(tr("Decrease Track Height")); view_show_all_item_->setText(tr("Toggle Show All")); - view_rectified_waveforms_item_->setText(tr("Rectified Waveforms")); view_timecode_view_frames_item_->setText(tr("Frames")); view_timecode_view_dropframe_item_->setText(tr("Drop Frame")); view_timecode_view_nondropframe_item_->setText(tr("Non-Drop Frame")); diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index 2f4eea741..d45b0818a 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -181,7 +181,6 @@ private: QAction* view_increase_track_height_item_; QAction* view_decrease_track_height_item_; QAction* view_show_all_item_; - QAction* view_rectified_waveforms_item_; QActionGroup* frame_view_mode_group_; QAction* view_timecode_view_dropframe_item_; QAction* view_timecode_view_nondropframe_item_;