implemented separate waveform cache

This commit is contained in:
itsmattkc
2022-05-29 17:52:35 -07:00
parent 826090b621
commit 2f7dc3c98b
28 changed files with 381 additions and 178 deletions
+38 -30
View File
@@ -193,38 +193,12 @@ void AudioVisualWaveform::OverwriteSilence(const rational &start, const rational
}
}
void AudioVisualWaveform::Shift(const rational &from, const rational &to)
{
for (auto it=mipmapped_data_.begin(); it!=mipmapped_data_.end(); it++) {
rational rate = it->first;
double rate_dbl = rate.toDouble();
Sample& data = it->second;
int from_index = time_to_samples(from, rate_dbl);
int to_index = time_to_samples(to, rate_dbl);
if (from_index == to_index) {
continue;
}
if (from_index >= data.size()) {
continue;
}
if (from_index > to_index) {
// Shifting backwards <-
data.remove(to_index, from_index - to_index);
} else {
// Shifting forwards ->
data.insert(from_index, to_index - from_index, {0, 0});
}
}
length_ = qMax(rational(0), length_ + (to-from));
}
void AudioVisualWaveform::TrimIn(const rational &length)
{
if (length == 0) {
return;
}
for (auto it=mipmapped_data_.begin(); it!=mipmapped_data_.end(); it++) {
rational rate = it->first;
double rate_dbl = rate.toDouble();
@@ -255,6 +229,40 @@ AudioVisualWaveform AudioVisualWaveform::Mid(const rational &offset) const
return mid;
}
AudioVisualWaveform AudioVisualWaveform::Mid(const rational &offset, const rational &length) const
{
AudioVisualWaveform mid = *this;
mid.TrimRange(offset, length);
return mid;
}
void AudioVisualWaveform::Resize(const rational &length)
{
if (length_ == length) {
return;
}
for (auto it=mipmapped_data_.begin(); it!=mipmapped_data_.end(); it++) {
rational rate = it->first;
double rate_dbl = rate.toDouble();
Sample& data = it->second;
int chop_length = time_to_samples(length, rate_dbl);
data.resize(chop_length);
}
length_ = length;
}
void AudioVisualWaveform::TrimRange(const rational &in, const rational &length)
{
TrimIn(in);
Resize(length);
}
AudioVisualWaveform::Sample AudioVisualWaveform::GetSummaryFromTime(const rational &start, const rational &length) const
{
// Find mipmap that requires
+5 -2
View File
@@ -90,11 +90,14 @@ public:
void OverwriteSilence(const rational &start, const rational &length);
void Shift(const rational& from, const rational& to);
void TrimIn(const rational &length);
AudioVisualWaveform Mid(const rational &offset) const;
AudioVisualWaveform Mid(const rational &offset, const rational &length) const;
void Resize(const rational &length);
void TrimRange(const rational &in, const rational &length);
Sample GetSummaryFromTime(const rational& start, const rational& length) const;
+15 -5
View File
@@ -38,7 +38,8 @@ const QString ClipBlock::kMaintainAudioPitchInput = QStringLiteral("maintain_aud
ClipBlock::ClipBlock() :
in_transition_(nullptr),
out_transition_(nullptr),
connected_viewer_(nullptr)
connected_viewer_(nullptr),
autocache_(false)
{
AddInput(kMediaInInput, NodeValue::kRational, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
SetInputProperty(kMediaInInput, QStringLiteral("view"), RationalSlider::kTime);
@@ -188,8 +189,14 @@ void ClipBlock::InvalidateCache(const TimeRange& range, const QString& from, int
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, length()));
if (type == Track::kVideo) {
emit connected->thumbnail_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
if (autocache_) {
emit connected->video_frame_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
}
} else if (type == Track::kAudio) {
emit connected->audio_playback_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
emit connected->waveform_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
if (autocache_) {
emit connected->audio_playback_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
}
}
}
}
@@ -251,7 +258,7 @@ void ClipBlock::InputConnectedEvent(const QString &input, int element, Node *out
if (input == kBufferIn) {
connect(output->thumbnail_cache(), &FrameHashCache::Validated, this, &Block::PreviewChanged);
connect(output->audio_playback_cache(), &AudioPlaybackCache::WaveformUpdated, this, &Block::PreviewChanged);
connect(output->waveform_cache(), &AudioPlaybackCache::Validated, this, &Block::PreviewChanged);
}
}
@@ -261,7 +268,7 @@ void ClipBlock::InputDisconnectedEvent(const QString &input, int element, Node *
if (input == kBufferIn) {
disconnect(output->thumbnail_cache(), &FrameHashCache::Validated, this, &Block::PreviewChanged);
disconnect(output->audio_playback_cache(), &AudioPlaybackCache::WaveformUpdated, this, &Block::PreviewChanged);
disconnect(output->waveform_cache(), &AudioPlaybackCache::Validated, this, &Block::PreviewChanged);
}
}
@@ -324,7 +331,10 @@ void ClipBlock::ConnectedToPreviewEvent()
emit connected->thumbnail_cache()->Request(r, PlaybackCache::kPreviewsOnly);
}
} else if (type == Track::kAudio) {
//emit connected->audio_playback_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
TimeRangeList invalid = connected->waveform_cache()->GetInvalidatedRanges(max_range);
for (const TimeRange &r : invalid) {
emit connected->waveform_cache()->Request(r, PlaybackCache::kPreviewsOnly);
}
}
}
}
+4 -2
View File
@@ -128,10 +128,10 @@ public:
}
}
const AudioVisualWaveform *waveform()
const AudioWaveformCache *waveform()
{
if (Node *n = GetConnectedOutput(kBufferIn)) {
return &n->audio_playback_cache()->visual();
return n->waveform_cache();
} else {
return nullptr;
}
@@ -185,6 +185,8 @@ private:
ViewerOutput *connected_viewer_;
bool autocache_;
private:
rational last_media_in_;
+1
View File
@@ -56,6 +56,7 @@ Node::Node() :
video_cache_ = new FrameHashCache(this);
thumbnail_cache_ = new FrameHashCache(this);
audio_cache_ = new AudioPlaybackCache(this);
waveform_cache_ = new AudioWaveformCache(this);
}
Node::~Node()
+7
View File
@@ -40,6 +40,7 @@
#include "node/param.h"
#include "render/audioparams.h"
#include "render/audioplaybackcache.h"
#include "render/audiowaveformcache.h"
#include "render/framehashcache.h"
#include "render/job/generatejob.h"
#include "render/job/samplejob.h"
@@ -236,6 +237,11 @@ public:
return audio_cache_;
}
AudioWaveformCache* waveform_cache() const
{
return waveform_cache_;
}
virtual TimeRange GetVideoCacheRange() const { return TimeRange(); }
virtual TimeRange GetAudioCacheRange() const { return TimeRange(); }
@@ -1413,6 +1419,7 @@ private:
FrameHashCache *thumbnail_cache_;
AudioPlaybackCache *audio_cache_;
AudioWaveformCache *waveform_cache_;
private slots:
/**
+34 -1
View File
@@ -37,7 +37,9 @@ const QString ViewerOutput::kSamplesInput = QStringLiteral("samples_in");
ViewerOutput::ViewerOutput(bool create_buffer_inputs, bool create_default_streams) :
last_length_(0),
video_length_(0),
audio_length_(0)
audio_length_(0),
autocache_input_video_(false),
autocache_input_audio_(false)
{
AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable | kInputFlagArray | kInputFlagHidden));
@@ -219,6 +221,22 @@ void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from,
{
Q_UNUSED(element)
if (Node *connected = GetConnectedOutput(from, element)) {
if (from == kTextureInput) {
//emit connected->thumbnail_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
if (autocache_input_video_) {
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, GetVideoLength()));
emit connected->video_frame_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
}
} else if (from == kSamplesInput) {
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, GetAudioLength()));
emit connected->waveform_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
if (autocache_input_audio_) {
emit connected->audio_playback_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
}
}
}
VerifyLength();
super::InvalidateCache(range, from, element, options);
@@ -298,6 +316,8 @@ void ViewerOutput::InputConnectedEvent(const QString &input, int element, Node *
{
if (input == kTextureInput) {
emit TextureInputChanged();
} else if (input == kSamplesInput) {
connect(output->waveform_cache(), &AudioWaveformCache::Validated, this, &ViewerOutput::ConnectedWaveformChanged);
}
super::InputConnectedEvent(input, element, output);
@@ -307,6 +327,8 @@ void ViewerOutput::InputDisconnectedEvent(const QString &input, int element, Nod
{
if (input == kTextureInput) {
emit TextureInputChanged();
} else if (input == kSamplesInput) {
disconnect(output->waveform_cache(), &AudioWaveformCache::Validated, this, &ViewerOutput::ConnectedWaveformChanged);
}
super::InputDisconnectedEvent(input, element, output);
@@ -364,6 +386,17 @@ Node::ValueHint ViewerOutput::GetConnectedSampleValueHint()
return GetValueHintForInput(kSamplesInput);
}
void ViewerOutput::ConnectedToPreviewEvent()
{
if (Node *connected = GetConnectedOutput(kSamplesInput)) {
TimeRange max_range = InputTimeAdjustment(kSamplesInput, -1, TimeRange(0, GetAudioLength()));
TimeRangeList invalid = connected->waveform_cache()->GetInvalidatedRanges(max_range);
for (const TimeRange &r : invalid) {
emit connected->waveform_cache()->Request(r, PlaybackCache::kPreviewsOnly);
}
}
}
void ViewerOutput::InputValueChangedEvent(const QString &input, int element)
{
if (element == 0) {
+16
View File
@@ -130,6 +130,15 @@ public:
return GetVideoStreamCount() + GetAudioStreamCount() + GetSubtitleStreamCount();
}
const AudioWaveformCache *GetConnectedWaveform()
{
if (Node *n = GetConnectedSampleOutput()) {
return n->waveform_cache();
} else {
return nullptr;
}
}
bool HasEnabledVideoStreams() const;
bool HasEnabledAudioStreams() const;
bool HasEnabledSubtitleStreams() const;
@@ -173,6 +182,8 @@ public:
virtual ValueHint GetConnectedSampleValueHint();
virtual void ConnectedToPreviewEvent() override;
static const QString kVideoParamsInput;
static const QString kAudioParamsInput;
static const QString kSubtitleParamsInput;
@@ -198,6 +209,8 @@ signals:
void SampleRateChanged(int sr);
void ConnectedWaveformChanged();
public slots:
void VerifyLength();
@@ -224,6 +237,9 @@ private:
TimelinePoints *timeline_points_;
bool autocache_input_video_;
bool autocache_input_audio_;
};
}
+2
View File
@@ -63,6 +63,8 @@ Footage::Footage(const QString &filename) :
check_timer->setInterval(5000);
connect(check_timer, &QTimer::timeout, this, &Footage::CheckFootage);
check_timer->start();
connect(this->waveform_cache(), &AudioWaveformCache::Validated, this, &ViewerOutput::ConnectedWaveformChanged);
}
void Footage::Retranslate()
@@ -552,6 +552,8 @@ void ProjectSerializer220403::LoadNode(Node *node, XMLNodeData &xml_node_data, Q
node->video_frame_cache()->SetUuid(reader->readElementText());
} else if (reader->name() == QStringLiteral("thumb")) {
node->thumbnail_cache()->SetUuid(reader->readElementText());
} else if (reader->name() == QStringLiteral("waveform")) {
node->waveform_cache()->SetUuid(reader->readElementText());
} else {
reader->skipCurrentElement();
}
@@ -616,6 +618,7 @@ void ProjectSerializer220403::SaveNode(Node *node, QXmlStreamWriter *writer) con
writer->writeTextElement(QStringLiteral("audio"), node->audio_playback_cache()->GetUuid().toString());
writer->writeTextElement(QStringLiteral("video"), node->video_frame_cache()->GetUuid().toString());
writer->writeTextElement(QStringLiteral("thumb"), node->thumbnail_cache()->GetUuid().toString());
writer->writeTextElement(QStringLiteral("waveform"), node->waveform_cache()->GetUuid().toString());
writer->writeEndElement(); // caches
+2
View File
@@ -24,6 +24,8 @@ set(OLIVE_SOURCES
render/audioparams.h
render/audioplaybackcache.cpp
render/audioplaybackcache.h
render/audiowaveformcache.cpp
render/audiowaveformcache.h
render/color.cpp
render/color.h
render/colorprocessor.cpp
-20
View File
@@ -48,9 +48,6 @@ void AudioPlaybackCache::SetParameters(const AudioParams &params)
}
params_ = params;
visual_.set_channel_count(params_.channel_count());
emit ParametersChanged();
}
void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, const SampleBuffer &samples)
@@ -62,23 +59,6 @@ void AudioPlaybackCache::WritePCM(const TimeRange &range, const TimeRangeList &v
}
}
void AudioPlaybackCache::WriteWaveform(const TimeRange &range, const TimeRangeList &valid_ranges, const AudioVisualWaveform *waveform)
{
// Write each valid range to the segments
foreach (const TimeRange& r, valid_ranges) {
// Write visual
if (waveform) {
visual_.OverwriteSums(*waveform, r.in(), r.in() - range.in(), r.length());
} else {
visual_.OverwriteSilence(r.in(), r.length());
}
}
if (!valid_ranges.isEmpty()) {
emit WaveformUpdated();
}
}
void AudioPlaybackCache::WriteSilence(const TimeRange &range)
{
// WritePCM will automatically fill non-existent bytes with silence, so we just have to send
-12
View File
@@ -68,18 +68,8 @@ public:
void WritePCM(const TimeRange &range, const TimeRangeList &valid_ranges, const SampleBuffer &samples);
void WriteWaveform(const TimeRange &range, const TimeRangeList &valid_ranges, const AudioVisualWaveform *waveform);
void WriteSilence(const TimeRange &range);
const AudioVisualWaveform &visual() const { return visual_; }
void set_visual(const AudioVisualWaveform &v) { visual_ = v; }
signals:
void ParametersChanged();
void WaveformUpdated();
private:
bool WritePartOfSampleBuffer(const SampleBuffer &samples, const rational &write_start, const rational &buffer_start, const rational &length);
@@ -89,8 +79,6 @@ private:
AudioParams params_;
AudioVisualWaveform visual_;
};
}
+101
View File
@@ -0,0 +1,101 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "audiowaveformcache.h"
namespace olive {
AudioWaveformCache::AudioWaveformCache(QObject *parent) :
PlaybackCache{parent}
{
}
void AudioWaveformCache::WriteWaveform(const TimeRange &range, const TimeRangeList &valid_ranges, const AudioVisualWaveform *waveform)
{
// Write each valid range to the segments
foreach (const TimeRange& r, valid_ranges) {
// Write visual
TimeRangeList::util_remove(&waveforms_, r);
if (waveform) {
TimeRangeWithWaveform wv = r;
rational local_start = r.in() - range.in();
wv.waveform = waveform->Mid(local_start, r.length());
waveforms_.append(wv);
}
Validate(r);
}
}
void AudioWaveformCache::Draw(QPainter *painter, const QRect &rect, const double &scale, const rational &start_time) const
{
rational end = start_time + rational::fromDouble(rect.width() / scale);
TimeRange draw_range(start_time, end);
foreach (const TimeRangeWithWaveform &wv, waveforms_) {
if (wv.OverlapsWith(draw_range)) {
rational substart = std::max(wv.in(), draw_range.in());
rational subend = std::min(wv.out(), draw_range.out());
QRect subrect = rect;
subrect.setLeft(subrect.left() + (substart - draw_range.in()).toDouble()*scale);
subrect.setWidth((subend - substart).toDouble()*scale);
rational local_start = substart - wv.in();
AudioVisualWaveform::DrawWaveform(painter, subrect, scale, wv.waveform, local_start);
}
}
}
AudioVisualWaveform::Sample AudioWaveformCache::GetSummaryFromTime(const rational &start, const rational &length) const
{
QMap<rational, AudioVisualWaveform::Sample> sample;
TimeRange acquire(start, start+length);
foreach (const TimeRangeWithWaveform &wv, waveforms_) {
if (wv.OverlapsWith(acquire)) {
TimeRange this_range = wv.Intersected(acquire);
auto sum = wv.waveform.GetSummaryFromTime(this_range.in() - wv.in(), this_range.length());
sample.insert(this_range.in(), sum);
}
}
AudioVisualWaveform::Sample result;
for (auto it=sample.cbegin(); it!=sample.cend(); it++) {
result.append(it.value());
}
return result;
}
rational AudioWaveformCache::length() const
{
rational len = 0;
foreach (const TimeRangeWithWaveform &wv, waveforms_) {
len = std::max(len, wv.out());
}
return len;
}
}
+85
View File
@@ -0,0 +1,85 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2022 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef AUDIOWAVEFORMCACHE_H
#define AUDIOWAVEFORMCACHE_H
#include "audio/audiovisualwaveform.h"
#include "playbackcache.h"
namespace olive {
class AudioWaveformCache : public PlaybackCache
{
Q_OBJECT
public:
AudioWaveformCache(QObject *parent = nullptr);
void WriteWaveform(const TimeRange &range, const TimeRangeList &valid_ranges, const AudioVisualWaveform *waveform);
const AudioParams &GetParameters() const { return params_; }
void SetParameters(const AudioParams &p) { params_ = p; }
void Draw(QPainter* painter, const QRect &rect, const double &scale, const rational &start_time) const;
AudioVisualWaveform::Sample GetSummaryFromTime(const rational &start, const rational &length) const;
rational length() const;
private:
class TimeRangeWithWaveform : public TimeRange
{
public:
TimeRangeWithWaveform() = default;
TimeRangeWithWaveform(const TimeRange &r) :
TimeRange(r)
{
}
void set_in(const rational& in)
{
waveform.TrimIn(in - this->in());
TimeRange::set_in(in);
}
void set_out(const rational& out)
{
waveform.Resize(out - this->in());
TimeRange::set_out(out);
}
void set_range(const rational& in, const rational& out)
{
waveform.TrimRange(in, out-in);
TimeRange::set_range(in, out);
}
AudioVisualWaveform waveform;
};
QVector<TimeRangeWithWaveform> waveforms_;
AudioParams params_;
};
}
#endif // AUDIOWAVEFORMCACHE_H
+30 -76
View File
@@ -80,7 +80,7 @@ RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t, RenderTicke
RenderTicketPtr PreviewAutoCacher::GetRangeOfAudio(TimeRange range, RenderTicketPriority priority)
{
return RenderAudio(copied_viewer_node_->GetConnectedSampleOutput(), range, PlaybackCache::kCacheOnly, priority);
return RenderAudio(copied_viewer_node_->GetConnectedSampleOutput(), range, PlaybackCache::kCacheOnly, priority, nullptr);
}
void PreviewAutoCacher::VideoInvalidatedFromCache(const TimeRange &range)
@@ -127,14 +127,17 @@ void PreviewAutoCacher::AudioRendered()
SampleBuffer buf = watcher->Get().value<SampleBuffer>();
node->audio_playback_cache()->SetParameters(buf.audio_params());
node->waveform_cache()->SetParameters(buf.audio_params());
PlaybackCache::RequestType type = PlaybackCache::RequestType(watcher->property("type").toInt());
if (type == PlaybackCache::kCacheOnly) {
// WritePCM is tolerant to its buffer being null, it will just write silence instead
node->audio_playback_cache()->WritePCM(range,
valid_ranges,
watcher->Get().value<SampleBuffer>());
if (AudioPlaybackCache *cache = Node::ValueToPtr<AudioPlaybackCache>(watcher->property("cache"))) {
cache->WritePCM(range,
valid_ranges,
watcher->Get().value<SampleBuffer>());
}
} else {
// Detect if this audio was incomplete because it was waiting on a conform to finish
if (watcher->GetTicket()->property("incomplete").toBool()) {
@@ -146,7 +149,9 @@ void PreviewAutoCacher::AudioRendered()
d.needing_conform.insert(range);
}
} else {
node->audio_playback_cache()->WriteWaveform(range, valid_ranges, &waveform);
if (AudioWaveformCache *cache = Node::ValueToPtr<AudioWaveformCache>(watcher->property("cache"))) {
cache->WriteWaveform(range, valid_ranges, &waveform);
}
}
}
}
@@ -320,16 +325,6 @@ void PreviewAutoCacher::InsertIntoCopyMap(Node *node, Node *copy)
void PreviewAutoCacher::ConnectToNodeCache(Node *node)
{
connect(node->video_frame_cache(),
&PlaybackCache::AutomaticChanged,
this,
&PreviewAutoCacher::VideoAutoCacheEnableChanged);
connect(node->audio_playback_cache(),
&PlaybackCache::AutomaticChanged,
this,
&PreviewAutoCacher::AudioAutoCacheEnableChanged);
connect(node->video_frame_cache(),
&PlaybackCache::Request,
this,
@@ -345,32 +340,18 @@ void PreviewAutoCacher::ConnectToNodeCache(Node *node)
this,
&PreviewAutoCacher::AudioInvalidatedFromCache);
connect(node->waveform_cache(),
&PlaybackCache::Request,
this,
&PreviewAutoCacher::AudioInvalidatedFromCache);
node->video_frame_cache()->LoadState();
node->audio_playback_cache()->LoadState();
node->thumbnail_cache()->LoadState();
// Copy invalidated ranges and start rendering if necessary
if (node->video_frame_cache()->IsAutomatic()) {
VideoAutoCacheEnableChangedFromNode(node, true);
}
if (node->audio_playback_cache()->IsAutomatic()) {
AudioAutoCacheEnableChangedFromNode(node, true);
}
}
void PreviewAutoCacher::DisconnectFromNodeCache(Node *node)
{
disconnect(node->video_frame_cache(),
&PlaybackCache::AutomaticChanged,
this,
&PreviewAutoCacher::VideoAutoCacheEnableChanged);
disconnect(node->audio_playback_cache(),
&PlaybackCache::AutomaticChanged,
this,
&PreviewAutoCacher::AudioAutoCacheEnableChanged);
disconnect(node->video_frame_cache(),
&PlaybackCache::Request,
this,
@@ -386,17 +367,14 @@ void PreviewAutoCacher::DisconnectFromNodeCache(Node *node)
this,
&PreviewAutoCacher::AudioInvalidatedFromCache);
disconnect(node->waveform_cache(),
&PlaybackCache::Request,
this,
&PreviewAutoCacher::AudioInvalidatedFromCache);
node->video_frame_cache()->SaveState();
node->audio_playback_cache()->SaveState();
node->thumbnail_cache()->SaveState();
if (node->video_frame_cache()->IsAutomatic()) {
VideoAutoCacheEnableChangedFromNode(node, false);
}
if (node->audio_playback_cache()->IsAutomatic()) {
AudioAutoCacheEnableChangedFromNode(node, false);
}
}
void PreviewAutoCacher::UpdateGraphChangeValue()
@@ -474,24 +452,6 @@ void PreviewAutoCacher::AudioInvalidatedFromNode(Node *node, const TimeRange &ra
StartCachingAudioRange(node, range, type);
}
void PreviewAutoCacher::VideoAutoCacheEnableChangedFromNode(Node *node, bool e)
{
if (e) {
VideoInvalidatedList(node, node->video_frame_cache()->GetInvalidatedRanges(node->GetVideoCacheRange()));
} else {
CancelVideoTasks(node);
}
}
void PreviewAutoCacher::AudioAutoCacheEnableChangedFromNode(Node *node, bool e)
{
if (e) {
AudioInvalidatedList(node, node->audio_playback_cache()->GetInvalidatedRanges(node->GetAudioCacheRange()));
} else {
CancelAudioTasks(node);
}
}
void PreviewAutoCacher::SetPlayhead(const rational &playhead)
{
cache_range_ = TimeRange(playhead - OLIVE_CONFIG("DiskCacheBehind").value<rational>(),
@@ -657,7 +617,13 @@ void PreviewAutoCacher::TryRender()
// Start job
if (Node *copy = copy_map_.value(d.node)) {
RenderAudio(copy, d.range, d.type, RenderTicketPriority::kNormal);
PlaybackCache *cache;
if (d.type == PlaybackCache::kPreviewsOnly) {
cache = d.node->waveform_cache();
} else {
cache = d.node->audio_playback_cache();
}
RenderAudio(copy, d.range, d.type, RenderTicketPriority::kNormal, cache);
} else {
qCritical() << "Failed to find node copy for audio job";
}
@@ -705,12 +671,13 @@ RenderTicketWatcher* PreviewAutoCacher::RenderFrame(Node *node, const rational&
return watcher;
}
RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node, const TimeRange &r, PlaybackCache::RequestType type, RenderTicketPriority priority)
RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node, const TimeRange &r, PlaybackCache::RequestType type, RenderTicketPriority priority, PlaybackCache *cache)
{
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("job", QVariant::fromValue(last_update_time_));
watcher->setProperty("node", Node::PtrToValue(node));
watcher->setProperty("type", type);
watcher->setProperty("cache", Node::PtrToValue(cache));
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::AudioRendered);
audio_tasks_.insert(watcher, r);
@@ -720,6 +687,7 @@ RenderTicketPtr PreviewAutoCacher::RenderAudio(Node *node, const TimeRange &r, P
rap.generate_waveforms = (type == PlaybackCache::kPreviewsOnly);
rap.priority = priority;
rap.clamp = false;
RenderTicketPtr ticket = RenderManager::instance()->RenderAudio(rap);
watcher->SetTicket(ticket);
@@ -744,20 +712,6 @@ void PreviewAutoCacher::ConformFinished()
}
}
void PreviewAutoCacher::VideoAutoCacheEnableChanged(bool e)
{
FrameHashCache *cache = static_cast<FrameHashCache*>(sender());
VideoAutoCacheEnableChangedFromNode(cache->parent(), e);
}
void PreviewAutoCacher::AudioAutoCacheEnableChanged(bool e)
{
AudioPlaybackCache *cache = static_cast<AudioPlaybackCache*>(sender());
AudioAutoCacheEnableChangedFromNode(cache->parent(), e);
}
void PreviewAutoCacher::CacheProxyTaskCancelled()
{
pending_video_jobs_.clear();
+1 -8
View File
@@ -105,7 +105,7 @@ private:
RenderTicketWatcher *RenderFrame(Node *node, const rational &time, PlaybackCache::RequestType type, RenderTicketPriority priority, FrameHashCache *cache);
RenderTicketPtr RenderAudio(Node *node, const TimeRange &range, PlaybackCache::RequestType type, RenderTicketPriority priority);
RenderTicketPtr RenderAudio(Node *node, const TimeRange &range, PlaybackCache::RequestType type, RenderTicketPriority priority, PlaybackCache *cache);
/**
* @brief Process all changes to internal NodeGraph copy
@@ -142,9 +142,6 @@ private:
void VideoInvalidatedFromNode(Node *node, const olive::TimeRange &range, PlaybackCache::RequestType type);
void AudioInvalidatedFromNode(Node *node, const olive::TimeRange &range, PlaybackCache::RequestType type);
void VideoAutoCacheEnableChangedFromNode(Node *node, bool e);
void AudioAutoCacheEnableChangedFromNode(Node *node, bool e);
class QueuedJob {
public:
enum Type {
@@ -264,10 +261,6 @@ private slots:
void ConformFinished();
void VideoAutoCacheEnableChanged(bool e);
void AudioAutoCacheEnableChanged(bool e);
void CacheProxyTaskCancelled();
};
+1
View File
@@ -112,6 +112,7 @@ RenderTicketPtr RenderManager::RenderAudio(const RenderAudioParams &params)
ticket->setProperty("time", QVariant::fromValue(params.range));
ticket->setProperty("type", kTypeAudio);
ticket->setProperty("enablewaveforms", params.generate_waveforms);
ticket->setProperty("clamp", params.clamp);
ticket->setProperty("aparam", QVariant::fromValue(params.audio_params));
AddTicket(ticket, params.priority);
+2
View File
@@ -129,6 +129,7 @@ public:
audio_params = aparam;
generate_waveforms = false;
priority = RenderTicketPriority::kNormal;
clamp = true;
}
Node *node;
@@ -136,6 +137,7 @@ public:
AudioParams audio_params;
bool generate_waveforms;
RenderTicketPriority priority;
bool clamp;
};
/**
+3 -1
View File
@@ -216,7 +216,9 @@ void RenderProcessor::Run()
SampleBuffer samples = sample_val.toSamples();
if (samples.is_allocated()) {
samples.clamp();
if (ticket_->property("clamp").toBool()) {
samples.clamp();
}
if (ticket_->property("enablewaveforms").toBool()) {
AudioVisualWaveform vis;
+4 -3
View File
@@ -93,11 +93,12 @@ void AudioMonitor::PushSampleBuffer(const SampleBuffer &d)
SetUpdateLoop(true);
}
void AudioMonitor::StartWaveform(const AudioVisualWaveform *waveform, const rational &start, int playback_speed)
void AudioMonitor::StartWaveform(const AudioWaveformCache *waveform, const rational &start, int playback_speed)
{
Stop();
if (start >= waveform->length()) {
waveform_length_ = waveform->length();
if (start >= waveform_length_) {
return;
}
@@ -239,7 +240,7 @@ void AudioMonitor::paintGL()
if (waveform_) {
UpdateValuesFromWaveform(v, delta_time);
if (waveform_time_ >= waveform_->length()) {
if (waveform_time_ >= waveform_length_) {
Stop();
}
}
+5 -4
View File
@@ -28,7 +28,7 @@
#include "audio/audiovisualwaveform.h"
#include "common/define.h"
#include "render/audioparams.h"
#include "render/audioplaybackcache.h"
#include "render/audiowaveformcache.h"
namespace olive {
@@ -45,7 +45,7 @@ public:
return waveform_;
}
static void StartWaveformOnAll(const AudioVisualWaveform *waveform, const rational& start, int playback_speed)
static void StartWaveformOnAll(const AudioWaveformCache *waveform, const rational& start, int playback_speed)
{
foreach (AudioMonitor *m, instances_) {
m->StartWaveform(waveform, start, playback_speed);
@@ -73,7 +73,7 @@ public slots:
void PushSampleBuffer(const SampleBuffer &samples);
void StartWaveform(const AudioVisualWaveform *waveform, const rational& start, int playback_speed);
void StartWaveform(const AudioWaveformCache *waveform, const rational& start, int playback_speed);
protected:
virtual void paintGL() override;
@@ -97,8 +97,9 @@ private:
qint64 last_time_;
const AudioVisualWaveform* waveform_;
const AudioWaveformCache* waveform_;
rational waveform_time_;
rational waveform_length_;
int playback_speed_;
+2 -1
View File
@@ -699,7 +699,8 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
// Place the copy instead of the original block
block = static_cast<Block*>(Node::CopyNodeInGraph(block, command));
if (ClipBlock *new_clip = dynamic_cast<ClipBlock*>(block)) {
new_clip->set_waveform(static_cast<ClipBlock*>(p.block)->waveform());
qDebug() << "FIXME: Copy clip stub"; Q_UNUSED(new_clip)
//new_clip->set_waveform(static_cast<ClipBlock*>(p.block)->waveform());
}
}
@@ -44,7 +44,10 @@ void BlockSplitCommand::redo()
if (ClipBlock *new_clip = dynamic_cast<ClipBlock*>(new_block_)) {
ClipBlock *old_clip = static_cast<ClipBlock*>(block_);
new_clip->set_waveform(old_clip->waveform());
qDebug() << "FIXME: Copy waveform stub";
Q_UNUSED(old_clip)
Q_UNUSED(new_clip)
//new_clip->set_waveform(old_clip->waveform());
}
// Determine our new lengths
@@ -558,11 +558,11 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
// Draw waveform
if (clip->GetTrackType() == Track::kAudio && show_waveforms_) {
if (const AudioVisualWaveform *wave = clip->waveform()) {
if (const AudioWaveformCache *wave = clip->waveform()) {
rational waveform_start = SceneToTime(block_left - block_in, GetScale(), connected_track_list_->parent()->GetAudioParams().sample_rate_as_time_base()) + media_in;
painter->setPen(shadow_color);
AudioVisualWaveform::DrawWaveform(painter, preview_rect, this->GetScale(), *wave, waveform_start);
wave->Draw(painter, preview_rect, this->GetScale(), waveform_start);
}
}
+10 -6
View File
@@ -47,13 +47,13 @@ AudioWaveformView::AudioWaveformView(QWidget *parent) :
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
void AudioWaveformView::SetViewer(AudioPlaybackCache *playback)
void AudioWaveformView::SetViewer(ViewerOutput *playback)
{
if (playback_) {
pool_.clear();
pool_.waitForDone();
disconnect(playback_, &AudioPlaybackCache::Validated, this, static_cast<void(AudioWaveformView::*)()>(&AudioWaveformView::update));
disconnect(playback_, &ViewerOutput::ConnectedWaveformChanged, this, static_cast<void(AudioWaveformView::*)()>(&AudioWaveformView::update));
SetTimebase(0);
}
@@ -61,9 +61,9 @@ void AudioWaveformView::SetViewer(AudioPlaybackCache *playback)
playback_ = playback;
if (playback_) {
connect(playback_, &AudioPlaybackCache::Validated, this, static_cast<void(AudioWaveformView::*)()>(&AudioWaveformView::update));
connect(playback_, &ViewerOutput::ConnectedWaveformChanged, this, static_cast<void(AudioWaveformView::*)()>(&AudioWaveformView::update));
SetTimebase(playback_->GetParameters().sample_rate_as_time_base());
SetTimebase(playback_->GetAudioParams().sample_rate_as_time_base());
}
}
@@ -75,8 +75,12 @@ void AudioWaveformView::drawForeground(QPainter *p, const QRectF &rect)
return;
}
const AudioParams& params = playback_->GetParameters();
const AudioWaveformCache *wave = playback_->GetConnectedWaveform();
if (!wave) {
return;
}
const AudioParams& params = wave->GetParameters();
if (!params.is_valid()) {
return;
}
@@ -86,7 +90,7 @@ void AudioWaveformView::drawForeground(QPainter *p, const QRectF &rect)
// Draw waveform
p->setPen(QColor(64, 255, 160)); // FIXME: Hardcoded color
AudioVisualWaveform::DrawWaveform(p, rect.toRect(), GetScale(), playback_->visual(), SceneToTime(GetScroll()));
wave->Draw(p, rect.toRect(), GetScale(), SceneToTime(GetScroll()));
// Draw playhead
p->setPen(PLAYHEAD_COLOR);
+2 -2
View File
@@ -36,7 +36,7 @@ class AudioWaveformView : public SeekableWidget
public:
AudioWaveformView(QWidget* parent = nullptr);
void SetViewer(AudioPlaybackCache *playback);
void SetViewer(ViewerOutput *playback);
protected:
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
@@ -44,7 +44,7 @@ protected:
private:
QThreadPool pool_;
AudioPlaybackCache *playback_;
ViewerOutput *playback_;
};
+2 -2
View File
@@ -232,7 +232,7 @@ void ViewerWidget::ConnectNodeEvent(ViewerOutput *n)
UpdateStack();
waveform_view_->SetViewer(GetConnectedNode()->audio_playback_cache());
waveform_view_->SetViewer(GetConnectedNode());
waveform_view_->ConnectTimelinePoints(GetConnectedNode()->GetTimelinePoints());
UpdateRendererVideoParameters();
@@ -947,7 +947,7 @@ void ViewerWidget::FinishPlayPreprocess()
}
prequeued_audio_.clear();
AudioMonitor::StartWaveformOnAll(&GetConnectedNode()->audio_playback_cache()->visual(),
AudioMonitor::StartWaveformOnAll(GetConnectedNode()->GetConnectedWaveform(),
GetTime(), playback_speed_);
}