Merge branch 'master' of https://github.com/olive-editor/olive
This commit is contained in:
@@ -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<Timecode::Display>(Config::Current()["TimecodeDisplay"].toInt());
|
||||
}
|
||||
|
||||
void Timecode::SetCurrentDisplay(Timecode::Display d)
|
||||
{
|
||||
Config::Current()["TimecodeDisplay"] = d;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -482,6 +482,18 @@ Folder *Core::GetSelectedFolderInActiveProject()
|
||||
}
|
||||
}
|
||||
|
||||
Timecode::Display Core::GetTimecodeDisplay() const
|
||||
{
|
||||
return static_cast<Timecode::Display>(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);
|
||||
|
||||
+16
@@ -26,6 +26,7 @@
|
||||
#include <QTimer>
|
||||
|
||||
#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
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
|
||||
#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()));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef PREFERENCESGENERALTAB_H
|
||||
#define PREFERENCESGENERALTAB_H
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
|
||||
@@ -27,6 +28,8 @@ private:
|
||||
|
||||
QComboBox* autoscroll_method_;
|
||||
|
||||
QCheckBox* rectified_waveforms_;
|
||||
|
||||
FloatSlider* default_still_length_;
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#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<quintptr, StreamPtr>& footage_ptrs, QList<NodeParam::FootageConnection>&, 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<AudioStream>(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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <QEvent>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#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_);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<const SampleSummer::Sum*>(w.constData()),
|
||||
|
||||
@@ -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<void (TimeRuler::*)()>(&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;
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "audiowaveformview.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
|
||||
#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<void (AudioWaveformView::*)()>(&AudioWaveformView::update));
|
||||
disconnect(backend_, &AudioRenderBackend::ParamsChanged, this, &AudioWaveformView::BackendParamsChanged);
|
||||
|
||||
SetTimebase(0);
|
||||
}
|
||||
|
||||
backend_ = backend;
|
||||
|
||||
if (backend_) {
|
||||
connect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast<void (AudioWaveformView::*)()>(&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<SampleSummer::Sum> summary;
|
||||
int summary_index = -1;
|
||||
|
||||
int channel_height = rect.height() / channels;
|
||||
int channel_half_height = channel_height / 2;
|
||||
|
||||
for (int i=0;i<rect.width();i++) {
|
||||
sample_index = next_sample_index;
|
||||
|
||||
if (sample_index == nb_samples) {
|
||||
break;
|
||||
}
|
||||
|
||||
next_sample_index = qMin(nb_samples,
|
||||
qFloor(static_cast<double>(SampleSummer::kSumSampleRate) * static_cast<double>(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;j<summary.size();j++) {
|
||||
if (Config::Current()[QStringLiteral("RectifiedWaveforms")].toBool()) {
|
||||
int channel_bottom = rect.y() + channel_height * (j + 1);
|
||||
|
||||
int diff = qRound((summary.at(j).max - summary.at(j).min) * channel_half_height);
|
||||
|
||||
painter->drawLine(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<width() && !fs.atEnd(); x++) {
|
||||
|
||||
int samples_len = ScreenToUnitRounded(x+1) - ScreenToUnitRounded(x);
|
||||
int max_read_size = params.samples_to_bytes(samples_len);
|
||||
|
||||
QByteArray read_buffer = fs.read(max_read_size);
|
||||
|
||||
// Detect whether we've reached EOF and recalculate sample count if so
|
||||
if (read_buffer.size() < max_read_size) {
|
||||
samples_len = params.bytes_to_samples(read_buffer.size());
|
||||
}
|
||||
|
||||
QVector<SampleSummer::Sum> samples = SampleSummer::SumSamples(reinterpret_cast<const float*>(read_buffer.constData()),
|
||||
samples_len,
|
||||
params.channel_count());
|
||||
|
||||
for (int i=0;i<params.channel_count();i++) {
|
||||
if (Config::Current()[QStringLiteral("RectifiedWaveforms")].toBool()) {
|
||||
int channel_bottom = channel_height * (i + 1);
|
||||
|
||||
int diff = qRound((samples.at(i).max - samples.at(i).min) * channel_half_height);
|
||||
|
||||
wave_painter.drawLine(x,
|
||||
channel_bottom - diff,
|
||||
x,
|
||||
channel_bottom);
|
||||
} else {
|
||||
int channel_mid = channel_height * i + channel_half_height;
|
||||
|
||||
wave_painter.drawLine(x,
|
||||
channel_mid + samples.at(i).min * static_cast<float>(channel_half_height),
|
||||
x,
|
||||
channel_mid + samples.at(i).max * static_cast<float>(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());
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#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();
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "waveformview.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
|
||||
#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<void (WaveformView::*)()>(&WaveformView::update));
|
||||
disconnect(backend_, &AudioRenderBackend::ParamsChanged, this, &WaveformView::BackendParamsChanged);
|
||||
|
||||
SetTimebase(0);
|
||||
}
|
||||
|
||||
backend_ = backend;
|
||||
|
||||
if (backend_) {
|
||||
connect(backend_, &AudioRenderBackend::QueueComplete, this, static_cast<void (WaveformView::*)()>(&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<SampleSummer::Sum> summary;
|
||||
int summary_index = -1;
|
||||
|
||||
int channel_height = rect.height() / channels;
|
||||
int channel_half_height = channel_height / 2;
|
||||
|
||||
for (int i=0;i<rect.width();i++) {
|
||||
sample_index = next_sample_index;
|
||||
|
||||
if (sample_index == nb_samples) {
|
||||
break;
|
||||
}
|
||||
|
||||
next_sample_index = qMin(nb_samples,
|
||||
qFloor(static_cast<double>(SampleSummer::kSumSampleRate) * static_cast<double>(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;j<summary.size();j++) {
|
||||
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 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<width() && !fs.atEnd(); x++) {
|
||||
|
||||
int samples_len = ScreenToUnitRounded(x+1) - ScreenToUnitRounded(x);
|
||||
int max_read_size = params.samples_to_bytes(samples_len);
|
||||
|
||||
QByteArray read_buffer = fs.read(max_read_size);
|
||||
|
||||
// Detect whether we've reached EOF and recalculate sample count if so
|
||||
if (read_buffer.size() < max_read_size) {
|
||||
samples_len = params.bytes_to_samples(read_buffer.size());
|
||||
}
|
||||
|
||||
QVector<SampleSummer::Sum> samples = SampleSummer::SumSamples(reinterpret_cast<const float*>(read_buffer.constData()),
|
||||
samples_len,
|
||||
params.channel_count());
|
||||
|
||||
for (int i=0;i<params.channel_count();i++) {
|
||||
int channel_mid = channel_height * i + channel_half_height;
|
||||
|
||||
p.drawLine(x,
|
||||
channel_mid + samples.at(i).min * static_cast<float>(channel_half_height),
|
||||
x,
|
||||
channel_mid + samples.at(i).max * static_cast<float>(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()));
|
||||
}
|
||||
@@ -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<Timecode::Display>(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<QAction*> 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"));
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user