waveforms: moved waveform to track rather than block
This is a much more robust and thread-safe system of storing the waveforms.
This commit is contained in:
@@ -28,69 +28,27 @@ OLIVE_NAMESPACE_ENTER
|
|||||||
|
|
||||||
const int AudioVisualWaveform::kSumSampleRate = 200;
|
const int AudioVisualWaveform::kSumSampleRate = 200;
|
||||||
|
|
||||||
|
void AudioVisualWaveform::AddSamples(SampleBufferPtr samples, int sample_rate)
|
||||||
|
{
|
||||||
|
if (!channels_) {
|
||||||
|
qWarning() << "Failed to write samples - channel count is zero";
|
||||||
|
}
|
||||||
|
|
||||||
|
overwrite_samples_internal(samples, sample_rate, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void AudioVisualWaveform::AddSum(const float *samples, int nb_samples, int nb_channels)
|
void AudioVisualWaveform::AddSum(const float *samples, int nb_samples, int nb_channels)
|
||||||
{
|
{
|
||||||
data_.append(SumSamples(samples, nb_samples, nb_channels));
|
data_.append(SumSamples(samples, nb_samples, nb_channels));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void AudioVisualWaveform::AddSamples(SampleBufferPtr samples)
|
|
||||||
{
|
|
||||||
if (!params_.is_valid()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int chunk_size = (audio_params_.sample_rate() / waveform_params.sample_rate());
|
|
||||||
|
|
||||||
qint64 start_offset = sizeof(SampleSummer::Info) + waveform_params.time_to_bytes(range_for_block.in() - b->in());
|
|
||||||
qint64 length_offset = waveform_params.time_to_bytes(range_for_block.length());
|
|
||||||
qint64 end_offset = start_offset + length_offset;
|
|
||||||
|
|
||||||
if (wave_file.size() < end_offset) {
|
|
||||||
wave_file.resize(end_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
wave_file.seek(start_offset);
|
|
||||||
|
|
||||||
for (int i=0;i<samples->sample_count();i+=chunk_size) {
|
|
||||||
QVector<Sample> summary = SumSamples(samples,
|
|
||||||
i,
|
|
||||||
qMin(chunk_size, samples->sample_count_per_channel() - i));
|
|
||||||
|
|
||||||
wave_file.write(reinterpret_cast<const char*>(summary.constData()),
|
|
||||||
summary.size() * sizeof(SampleSummer::Sum));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start)
|
void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start)
|
||||||
{
|
{
|
||||||
if (!channels_) {
|
if (!channels_) {
|
||||||
qWarning() << "Failed to write samples - channel count is zero";
|
qWarning() << "Failed to write samples - channel count is zero";
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_index = time_to_samples(start);
|
overwrite_samples_internal(samples, sample_rate, time_to_samples(start));
|
||||||
int samples_length = time_to_samples(static_cast<double>(samples->sample_count()) / static_cast<double>(sample_rate));
|
|
||||||
|
|
||||||
int end_index = start_index + samples_length;
|
|
||||||
if (data_.size() < end_index) {
|
|
||||||
data_.resize(end_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
int chunk_size = sample_rate / kSumSampleRate;
|
|
||||||
|
|
||||||
for (int i=0; i<samples_length; i++) {
|
|
||||||
|
|
||||||
int src_index = (i * chunk_size) / channels_;
|
|
||||||
|
|
||||||
QVector<SamplePerChannel> summary = SumSamples(samples,
|
|
||||||
src_index,
|
|
||||||
qMin(chunk_size, samples->sample_count() - src_index));
|
|
||||||
|
|
||||||
memcpy(&data_.data()[i + start_index],
|
|
||||||
summary.constData(),
|
|
||||||
summary.size() * sizeof(SamplePerChannel));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &start)
|
void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &start)
|
||||||
@@ -150,10 +108,7 @@ void AudioVisualWaveform::PrependSilence(const rational &time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill remainder with silence
|
// Fill remainder with silence
|
||||||
for (int i=0;i<added_samples;i++) {
|
memset(data_.data(), 0, added_samples * sizeof(SamplePerChannel));
|
||||||
data_[i].max = 0;
|
|
||||||
data_[i].min = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioVisualWaveform::AppendSilence(const rational &time)
|
void AudioVisualWaveform::AppendSilence(const rational &time)
|
||||||
@@ -165,10 +120,7 @@ void AudioVisualWaveform::AppendSilence(const rational &time)
|
|||||||
data_.resize(old_size + added_samples);
|
data_.resize(old_size + added_samples);
|
||||||
|
|
||||||
// Fill remainder with silence
|
// Fill remainder with silence
|
||||||
for (int i=old_size;i<data_.size();i++) {
|
memset(&data_[old_size], 0, (data_.size() - old_size) * sizeof(SamplePerChannel));
|
||||||
data_[i].max = 0;
|
|
||||||
data_[i].min = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<AudioVisualWaveform::SamplePerChannel> AudioVisualWaveform::SumSamples(const float *samples, int nb_samples, int nb_channels)
|
QVector<AudioVisualWaveform::SamplePerChannel> AudioVisualWaveform::SumSamples(const float *samples, int nb_samples, int nb_channels)
|
||||||
@@ -245,9 +197,11 @@ void AudioVisualWaveform::DrawSample(QPainter *painter, const QVector<SamplePerC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, const double& scale, const AudioVisualWaveform &samples)
|
void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, const double& scale, const AudioVisualWaveform &samples, const rational& start_time)
|
||||||
{
|
{
|
||||||
int sample_index, next_sample_index = 0;
|
int start_sample_index = samples.time_to_samples(start_time);
|
||||||
|
int next_sample_index = start_sample_index;
|
||||||
|
int sample_index;
|
||||||
|
|
||||||
QVector<SamplePerChannel> summary;
|
QVector<SamplePerChannel> summary;
|
||||||
int summary_index = -1;
|
int summary_index = -1;
|
||||||
@@ -258,8 +212,6 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
|
|||||||
int start = qMax(rect.x(), -top_left.x());
|
int start = qMax(rect.x(), -top_left.x());
|
||||||
int end = qMin(rect.right(), -top_left.x() + viewport.width());
|
int end = qMin(rect.right(), -top_left.x() + viewport.width());
|
||||||
|
|
||||||
QVector<QLine> lines;
|
|
||||||
|
|
||||||
for (int i=start;i<end;i++) {
|
for (int i=start;i<end;i++) {
|
||||||
sample_index = next_sample_index;
|
sample_index = next_sample_index;
|
||||||
|
|
||||||
@@ -268,7 +220,7 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
next_sample_index = qMin(samples.nb_samples(),
|
next_sample_index = qMin(samples.nb_samples(),
|
||||||
qFloor(static_cast<double>(kSumSampleRate) * static_cast<double>(i - rect.x() + 1) / scale) * samples.channel_count());
|
start_sample_index + qFloor(static_cast<double>(kSumSampleRate) * static_cast<double>(i - rect.x() + 1) / scale) * samples.channel_count());
|
||||||
|
|
||||||
if (summary_index != sample_index) {
|
if (summary_index != sample_index) {
|
||||||
summary = AudioVisualWaveform::ReSumSamples(&samples.data_.at(sample_index),
|
summary = AudioVisualWaveform::ReSumSamples(&samples.data_.at(sample_index),
|
||||||
@@ -279,8 +231,31 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
|
|||||||
|
|
||||||
DrawSample(painter, summary, i, rect.y(), rect.height());
|
DrawSample(painter, summary, i, rect.y(), rect.height());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
painter->drawLines(lines);
|
void AudioVisualWaveform::overwrite_samples_internal(SampleBufferPtr samples, int sample_rate, int start_index)
|
||||||
|
{
|
||||||
|
int samples_length = time_to_samples(static_cast<double>(samples->sample_count()) / static_cast<double>(sample_rate));
|
||||||
|
|
||||||
|
int end_index = start_index + samples_length;
|
||||||
|
if (data_.size() < end_index) {
|
||||||
|
data_.resize(end_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int chunk_size = sample_rate / kSumSampleRate;
|
||||||
|
|
||||||
|
for (int i=0; i<samples_length; i++) {
|
||||||
|
|
||||||
|
int src_index = (i * chunk_size) / channels_;
|
||||||
|
|
||||||
|
QVector<SamplePerChannel> summary = SumSamples(samples,
|
||||||
|
src_index,
|
||||||
|
qMin(chunk_size, samples->sample_count() - src_index));
|
||||||
|
|
||||||
|
memcpy(&data_.data()[i + start_index],
|
||||||
|
summary.constData(),
|
||||||
|
summary.size() * sizeof(SamplePerChannel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioVisualWaveform::time_to_samples(const rational &time) const
|
int AudioVisualWaveform::time_to_samples(const rational &time) const
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public:
|
|||||||
return data_.constData();
|
return data_.constData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddSamples(SampleBufferPtr samples, int sample_rate);
|
||||||
void AddSum(const float* samples, int nb_samples, int nb_channels);
|
void AddSum(const float* samples, int nb_samples, int nb_channels);
|
||||||
|
|
||||||
void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start);
|
void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start);
|
||||||
@@ -89,7 +90,7 @@ public:
|
|||||||
|
|
||||||
static void DrawSample(QPainter* painter, const QVector<SamplePerChannel> &sample, int x, int y, int height);
|
static void DrawSample(QPainter* painter, const QVector<SamplePerChannel> &sample, int x, int y, int height);
|
||||||
|
|
||||||
static void DrawWaveform(QPainter* painter, const QRect &rect, const double &scale, const AudioVisualWaveform& samples);
|
static void DrawWaveform(QPainter* painter, const QRect &rect, const double &scale, const AudioVisualWaveform& samples, const rational &start_time);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -98,6 +99,8 @@ private:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
static void ClampMinMax(SamplePerChannel &sum, T value);
|
static void ClampMinMax(SamplePerChannel &sum, T value);
|
||||||
|
|
||||||
|
void overwrite_samples_internal(SampleBufferPtr samples, int sample_rate, int start_index);
|
||||||
|
|
||||||
int time_to_samples(const rational& time) const;
|
int time_to_samples(const rational& time) const;
|
||||||
int time_to_samples(const double& time) const;
|
int time_to_samples(const double& time) const;
|
||||||
|
|
||||||
@@ -109,4 +112,6 @@ private:
|
|||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::AudioVisualWaveform)
|
||||||
|
|
||||||
#endif // SUMSAMPLES_H
|
#endif // SUMSAMPLES_H
|
||||||
|
|||||||
@@ -552,6 +552,7 @@ void Core::DeclareTypesForQt()
|
|||||||
qRegisterMetaType<OLIVE_NAMESPACE::TimeRange>();
|
qRegisterMetaType<OLIVE_NAMESPACE::TimeRange>();
|
||||||
qRegisterMetaType<Color>();
|
qRegisterMetaType<Color>();
|
||||||
qRegisterMetaType<OLIVE_NAMESPACE::ProjectPtr>();
|
qRegisterMetaType<OLIVE_NAMESPACE::ProjectPtr>();
|
||||||
|
qRegisterMetaType<OLIVE_NAMESPACE::AudioVisualWaveform>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::StartGUI(bool full_screen)
|
void Core::StartGUI(bool full_screen)
|
||||||
|
|||||||
@@ -28,13 +28,6 @@ OLIVE_NAMESPACE_ENTER
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A Node that represents a block of time, also displayable on a Timeline
|
* @brief A Node that represents a block of time, also displayable on a Timeline
|
||||||
*
|
|
||||||
* This is an abstract function. Since different types of Block will provide their lengths in different ways, it's
|
|
||||||
* necessary to subclass and override the length() function for a Block to be usable.
|
|
||||||
*
|
|
||||||
* When overriding Node::copy(), the derivative class should also call Block::CopyParameters() on the new Block instance
|
|
||||||
* which will copy the block's name, length, and media in point. It does not copy any node-specific parameters like any
|
|
||||||
* input values or connections as per standard with Node::copy().
|
|
||||||
*/
|
*/
|
||||||
class Block : public Node
|
class Block : public Node
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,26 +59,6 @@ NodeInput *ClipBlock::texture_input() const
|
|||||||
return texture_input_;
|
return texture_input_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClipBlock::LengthChangedEvent(const rational &old_length, const rational &new_length, const Timeline::MovementMode &mode)
|
|
||||||
{
|
|
||||||
// Positive if made longer, negative if made shorter
|
|
||||||
rational diff = new_length - old_length;
|
|
||||||
|
|
||||||
if (diff < rational()) {
|
|
||||||
if (mode == Timeline::kTrimIn) {
|
|
||||||
waveform().TrimIn(-diff);
|
|
||||||
} else {
|
|
||||||
waveform().TrimOut(-diff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mode == Timeline::kTrimIn) {
|
|
||||||
waveform().PrependSilence(diff);
|
|
||||||
} else {
|
|
||||||
waveform().AppendSilence(diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipBlock::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
|
void ClipBlock::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source)
|
||||||
{
|
{
|
||||||
// If signal is from texture input, transform all times from media time to sequence time
|
// If signal is from texture input, transform all times from media time to sequence time
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#ifndef CLIPBLOCK_H
|
#ifndef CLIPBLOCK_H
|
||||||
#define CLIPBLOCK_H
|
#define CLIPBLOCK_H
|
||||||
|
|
||||||
#include "audio/audiovisualwaveform.h"
|
|
||||||
#include "node/block/block.h"
|
#include "node/block/block.h"
|
||||||
|
|
||||||
OLIVE_NAMESPACE_ENTER
|
OLIVE_NAMESPACE_ENTER
|
||||||
@@ -57,31 +56,9 @@ public:
|
|||||||
|
|
||||||
virtual void Hash(QCryptographicHash &hash, const rational &time) const override;
|
virtual void Hash(QCryptographicHash &hash, const rational &time) const override;
|
||||||
|
|
||||||
AudioVisualWaveform& waveform()
|
|
||||||
{
|
|
||||||
return waveform_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_waveform(const AudioVisualWaveform& wave)
|
|
||||||
{
|
|
||||||
waveform_ = wave;
|
|
||||||
|
|
||||||
emit PreviewUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void PreviewUpdated();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void LengthChangedEvent(const rational& old_length,
|
|
||||||
const rational& new_length,
|
|
||||||
const Timeline::MovementMode& mode) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeInput* texture_input_;
|
NodeInput* texture_input_;
|
||||||
|
|
||||||
AudioVisualWaveform waveform_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -63,12 +63,7 @@ const Timeline::TrackType& TrackOutput::track_type() const
|
|||||||
return track_type_;
|
return track_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::Type TrackOutput::type() const
|
Node *TrackOutput::copy() const
|
||||||
{
|
|
||||||
return kClip;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block *TrackOutput::copy() const
|
|
||||||
{
|
{
|
||||||
return new TrackOutput();
|
return new TrackOutput();
|
||||||
}
|
}
|
||||||
@@ -116,7 +111,7 @@ void TrackOutput::SetTrackHeight(const int &height)
|
|||||||
|
|
||||||
void TrackOutput::Retranslate()
|
void TrackOutput::Retranslate()
|
||||||
{
|
{
|
||||||
Block::Retranslate();
|
Node::Retranslate();
|
||||||
|
|
||||||
block_input_->set_name(tr("Blocks"));
|
block_input_->set_name(tr("Blocks"));
|
||||||
muted_input_->set_name(tr("Muted"));
|
muted_input_->set_name(tr("Muted"));
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#ifndef TRACKOUTPUT_H
|
#ifndef TRACKOUTPUT_H
|
||||||
#define TRACKOUTPUT_H
|
#define TRACKOUTPUT_H
|
||||||
|
|
||||||
|
#include "audio/audiovisualwaveform.h"
|
||||||
#include "node/block/block.h"
|
#include "node/block/block.h"
|
||||||
#include "timeline/timelinecommon.h"
|
#include "timeline/timelinecommon.h"
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ OLIVE_NAMESPACE_ENTER
|
|||||||
/**
|
/**
|
||||||
* @brief A time traversal Node for sorting through one channel/track of Blocks
|
* @brief A time traversal Node for sorting through one channel/track of Blocks
|
||||||
*/
|
*/
|
||||||
class TrackOutput : public Block
|
class TrackOutput : public Node
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -38,9 +39,7 @@ public:
|
|||||||
const Timeline::TrackType& track_type() const;
|
const Timeline::TrackType& track_type() const;
|
||||||
void set_track_type(const Timeline::TrackType& track_type);
|
void set_track_type(const Timeline::TrackType& track_type);
|
||||||
|
|
||||||
virtual Type type() const override;
|
virtual Node* copy() const override;
|
||||||
|
|
||||||
virtual Block* copy() const override;
|
|
||||||
|
|
||||||
virtual QString Name() const override;
|
virtual QString Name() const override;
|
||||||
virtual QString id() const override;
|
virtual QString id() const override;
|
||||||
@@ -195,6 +194,11 @@ public:
|
|||||||
|
|
||||||
void PushLengthChangeSignal();
|
void PushLengthChangeSignal();
|
||||||
|
|
||||||
|
AudioVisualWaveform& waveform()
|
||||||
|
{
|
||||||
|
return waveform_;
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SetTrackName(const QString& name);
|
void SetTrackName(const QString& name);
|
||||||
|
|
||||||
@@ -233,6 +237,11 @@ signals:
|
|||||||
*/
|
*/
|
||||||
void IndexChanged(int i);
|
void IndexChanged(int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signal emitted when preview (waveform) has changed and UI should be updated
|
||||||
|
*/
|
||||||
|
void PreviewChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -266,6 +275,8 @@ private:
|
|||||||
bool queued_length_change_;
|
bool queued_length_change_;
|
||||||
rational queued_length_;
|
rational queued_length_;
|
||||||
|
|
||||||
|
AudioVisualWaveform waveform_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void BlockConnected(NodeEdgePtr edge);
|
void BlockConnected(NodeEdgePtr edge);
|
||||||
|
|
||||||
|
|||||||
@@ -94,11 +94,6 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderBackend::SetUpdateWithGraph(bool e)
|
|
||||||
{
|
|
||||||
update_with_graph_ = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderBackend::ClearVideoQueue()
|
void RenderBackend::ClearVideoQueue()
|
||||||
{
|
{
|
||||||
foreach (RenderTicketPtr t, render_queue_) {
|
foreach (RenderTicketPtr t, render_queue_) {
|
||||||
@@ -275,6 +270,7 @@ void RenderBackend::RunNextJob()
|
|||||||
RenderWorker* worker = CreateNewWorker();
|
RenderWorker* worker = CreateNewWorker();
|
||||||
|
|
||||||
connect(worker, &RenderWorker::FinishedJob, this, &RenderBackend::WorkerFinished);
|
connect(worker, &RenderWorker::FinishedJob, this, &RenderBackend::WorkerFinished);
|
||||||
|
connect(worker, &RenderWorker::WaveformGenerated, this, &RenderBackend::WorkerGeneratedWaveform);
|
||||||
|
|
||||||
workers_.replace(i, {worker, false});
|
workers_.replace(i, {worker, false});
|
||||||
}
|
}
|
||||||
@@ -292,6 +288,7 @@ void RenderBackend::RunNextJob()
|
|||||||
worker->SetVideoParams(video_params_);
|
worker->SetVideoParams(video_params_);
|
||||||
worker->SetAudioParams(audio_params_);
|
worker->SetAudioParams(audio_params_);
|
||||||
worker->SetVideoDownloadMatrix(video_download_matrix_);
|
worker->SetVideoDownloadMatrix(video_download_matrix_);
|
||||||
|
worker->SetGeneratePreviews(generate_previews_);
|
||||||
worker->SetCopyMap(©_map_);
|
worker->SetCopyMap(©_map_);
|
||||||
|
|
||||||
RenderTicketPtr ticket = render_queue_.front();
|
RenderTicketPtr ticket = render_queue_.front();
|
||||||
@@ -354,6 +351,34 @@ void RenderBackend::WorkerFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderBackend::WorkerGeneratedWaveform(const TrackOutput *copied_track, const AudioVisualWaveform& samples, const rational &r)
|
||||||
|
{
|
||||||
|
TrackOutput* track = nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!viewer_node_->audio_playback_cache()->JobIsCurrent(r)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
QHash<Node*, Node*>::const_iterator i;
|
||||||
|
for (i=copy_map_.constBegin(); i!=copy_map_.constEnd(); i++) {
|
||||||
|
if (i.value() == copied_track) {
|
||||||
|
track = static_cast<TrackOutput*>(i.key());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track) {
|
||||||
|
track->waveform().set_channel_count(audio_params_.channel_count());
|
||||||
|
track->waveform().OverwriteSums(samples, r);
|
||||||
|
qDebug() << "Preview changed";
|
||||||
|
emit track->PreviewChanged();
|
||||||
|
} else {
|
||||||
|
qDebug() << "Failed to find track";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RenderBackend::CopyNodeInputValue(NodeInput *input)
|
void RenderBackend::CopyNodeInputValue(NodeInput *input)
|
||||||
{
|
{
|
||||||
// Find our copy of this parameter
|
// Find our copy of this parameter
|
||||||
|
|||||||
@@ -45,7 +45,15 @@ public:
|
|||||||
|
|
||||||
void SetViewerNode(ViewerOutput* viewer_node);
|
void SetViewerNode(ViewerOutput* viewer_node);
|
||||||
|
|
||||||
void SetUpdateWithGraph(bool e);
|
void SetUpdateWithGraph(bool e)
|
||||||
|
{
|
||||||
|
update_with_graph_ = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGeneratePreviews(bool e)
|
||||||
|
{
|
||||||
|
generate_previews_ = e;
|
||||||
|
}
|
||||||
|
|
||||||
void ClearVideoQueue();
|
void ClearVideoQueue();
|
||||||
|
|
||||||
@@ -113,9 +121,13 @@ private:
|
|||||||
|
|
||||||
bool update_with_graph_;
|
bool update_with_graph_;
|
||||||
|
|
||||||
|
bool generate_previews_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void WorkerFinished();
|
void WorkerFinished();
|
||||||
|
|
||||||
|
void WorkerGeneratedWaveform(const OLIVE_NAMESPACE::TrackOutput* copied_track, const OLIVE_NAMESPACE::AudioVisualWaveform& samples, const OLIVE_NAMESPACE::rational& start);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OLIVE_NAMESPACE_EXIT
|
OLIVE_NAMESPACE_EXIT
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ OLIVE_NAMESPACE_ENTER
|
|||||||
RenderWorker::RenderWorker(RenderBackend* parent) :
|
RenderWorker::RenderWorker(RenderBackend* parent) :
|
||||||
parent_(parent),
|
parent_(parent),
|
||||||
available_(true),
|
available_(true),
|
||||||
audio_mode_is_preview_(false)
|
audio_mode_is_preview_(false),
|
||||||
|
generate_previews_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,24 +124,17 @@ NodeValueTable RenderWorker::GenerateBlockTable(const TrackOutput *track, const
|
|||||||
// Copy samples into destination buffer
|
// Copy samples into destination buffer
|
||||||
block_range_buffer->set(samples_from_this_block->const_data(), destination_offset, copy_length);
|
block_range_buffer->set(samples_from_this_block->const_data(), destination_offset, copy_length);
|
||||||
|
|
||||||
if (b->type() == Block::kClip) {
|
|
||||||
// Save waveform to file
|
|
||||||
ClipBlock* src_block = static_cast<ClipBlock*>(copy_map_->key(b));
|
|
||||||
|
|
||||||
AudioVisualWaveform& clip_waveform = src_block->waveform();
|
|
||||||
|
|
||||||
clip_waveform.set_channel_count(audio_params_.channel_count());
|
|
||||||
|
|
||||||
clip_waveform.OverwriteSamples(samples_from_this_block,
|
|
||||||
audio_params_.sample_rate(),
|
|
||||||
range_for_block.in() - b->in());
|
|
||||||
|
|
||||||
emit static_cast<ClipBlock*>(src_block)->PreviewUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeValueTable::Merge({merged_table, table});
|
NodeValueTable::Merge({merged_table, table});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (generate_previews_) {
|
||||||
|
// Generate visual waveform in this background thread
|
||||||
|
AudioVisualWaveform visual_waveform;
|
||||||
|
visual_waveform.set_channel_count(audio_params_.channel_count());
|
||||||
|
visual_waveform.AddSamples(block_range_buffer, audio_params_.sample_rate());
|
||||||
|
emit WaveformGenerated(track, visual_waveform, range.in());
|
||||||
|
}
|
||||||
|
|
||||||
merged_table.Push(NodeParam::kSamples, QVariant::fromValue(block_range_buffer));
|
merged_table.Push(NodeParam::kSamples, QVariant::fromValue(block_range_buffer));
|
||||||
|
|
||||||
return merged_table;
|
return merged_table;
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ public:
|
|||||||
copy_map_ = copy_map;
|
copy_map_ = copy_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetGeneratePreviews(bool e)
|
||||||
|
{
|
||||||
|
generate_previews_ = e;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a unique ID for the image generated at this time
|
* @brief Return a unique ID for the image generated at this time
|
||||||
*
|
*
|
||||||
@@ -127,6 +132,8 @@ signals:
|
|||||||
|
|
||||||
void FinishedJob();
|
void FinishedJob();
|
||||||
|
|
||||||
|
void WaveformGenerated(const OLIVE_NAMESPACE::TrackOutput* track, const OLIVE_NAMESPACE::AudioVisualWaveform& samples, const OLIVE_NAMESPACE::rational& start);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeValue GetDataFromStream(StreamPtr stream, const TimeRange& input_time);
|
NodeValue GetDataFromStream(StreamPtr stream, const TimeRange& input_time);
|
||||||
|
|
||||||
@@ -157,6 +164,8 @@ private:
|
|||||||
|
|
||||||
bool audio_mode_is_preview_;
|
bool audio_mode_is_preview_;
|
||||||
|
|
||||||
|
bool generate_previews_;
|
||||||
|
|
||||||
QHash<Node*, Node*>* copy_map_;
|
QHash<Node*, Node*>* copy_map_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Vendored
+2
@@ -32,6 +32,8 @@ CacheTask::CacheTask(ViewerOutput* viewer, const VideoRenderingParams& vparams,
|
|||||||
in_out_only_(in_out_only)
|
in_out_only_(in_out_only)
|
||||||
{
|
{
|
||||||
SetTitle(tr("Caching \"%1\"").arg(viewer->media_name()));
|
SetTitle(tr("Caching \"%1\"").arg(viewer->media_name()));
|
||||||
|
|
||||||
|
backend()->SetGeneratePreviews(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CacheTask::Run()
|
bool CacheTask::Run()
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ protected:
|
|||||||
return job_time_;
|
return job_time_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLBackend* backend()
|
||||||
|
{
|
||||||
|
return &backend_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ViewerOutput* viewer_;
|
ViewerOutput* viewer_;
|
||||||
|
|
||||||
|
|||||||
@@ -981,40 +981,33 @@ void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event)
|
|||||||
|
|
||||||
void TimelineWidget::AddBlock(Block *block, TrackReference track)
|
void TimelineWidget::AddBlock(Block *block, TrackReference track)
|
||||||
{
|
{
|
||||||
switch (block->type()) {
|
// Set up clip with view parameters (clip item will automatically size its rect accordingly)
|
||||||
case Block::kClip:
|
TimelineViewBlockItem* item = new TimelineViewBlockItem(block);
|
||||||
case Block::kTransition:
|
|
||||||
case Block::kGap:
|
|
||||||
{
|
|
||||||
// Set up clip with view parameters (clip item will automatically size its rect accordingly)
|
|
||||||
TimelineViewBlockItem* item = new TimelineViewBlockItem(block);
|
|
||||||
|
|
||||||
item->SetYCoords(GetTrackY(track), GetTrackHeight(track));
|
item->SetYCoords(GetTrackY(track), GetTrackHeight(track));
|
||||||
item->SetScale(GetScale());
|
item->SetScale(GetScale());
|
||||||
item->SetTrack(track);
|
item->SetTrack(track);
|
||||||
item->SetTimebase(timebase());
|
item->SetTimebase(timebase());
|
||||||
|
|
||||||
// Add to list of clip items that can be iterated through
|
// Add to list of clip items that can be iterated through
|
||||||
block_items_.insert(block, item);
|
block_items_.insert(block, item);
|
||||||
|
|
||||||
// Add item to graphics scene
|
// Add item to graphics scene
|
||||||
views_.at(track.type())->view()->scene()->addItem(item);
|
views_.at(track.type())->view()->scene()->addItem(item);
|
||||||
|
|
||||||
connect(block, &Block::Refreshed, this, &TimelineWidget::BlockChanged);
|
connect(block, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed);
|
||||||
connect(block, &Block::LinksChanged, this, &TimelineWidget::PreviewUpdated);
|
connect(block, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated);
|
||||||
connect(block, &Block::NameChanged, this, &TimelineWidget::PreviewUpdated);
|
connect(block, &Block::NameChanged, this, &TimelineWidget::BlockUpdated);
|
||||||
connect(block, &Block::EnabledChanged, this, &TimelineWidget::PreviewUpdated);
|
connect(block, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated);
|
||||||
|
|
||||||
if (block->type() == Block::kClip) {
|
|
||||||
connect(static_cast<ClipBlock*>(block), &ClipBlock::PreviewUpdated, this, &TimelineWidget::PreviewUpdated);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineWidget::RemoveBlock(Block *block)
|
void TimelineWidget::RemoveBlock(Block *block)
|
||||||
{
|
{
|
||||||
|
disconnect(block, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed);
|
||||||
|
disconnect(block, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated);
|
||||||
|
disconnect(block, &Block::NameChanged, this, &TimelineWidget::BlockUpdated);
|
||||||
|
disconnect(block, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated);
|
||||||
|
|
||||||
delete block_items_.take(block);
|
delete block_items_.take(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,11 +1018,13 @@ void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
|
connect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
|
||||||
|
connect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineWidget::RemoveTrack(TrackOutput *track)
|
void TimelineWidget::RemoveTrack(TrackOutput *track)
|
||||||
{
|
{
|
||||||
disconnect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
|
disconnect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
|
||||||
|
disconnect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated);
|
||||||
|
|
||||||
foreach (Block* b, track->Blocks()) {
|
foreach (Block* b, track->Blocks()) {
|
||||||
RemoveBlock(b);
|
RemoveBlock(b);
|
||||||
@@ -1065,7 +1060,7 @@ void TimelineWidget::ViewSelectionChanged()
|
|||||||
emit SelectionChanged(selected_blocks);
|
emit SelectionChanged(selected_blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineWidget::BlockChanged()
|
void TimelineWidget::BlockRefreshed()
|
||||||
{
|
{
|
||||||
TimelineViewRect* rect = block_items_.value(static_cast<Block*>(sender()));
|
TimelineViewRect* rect = block_items_.value(static_cast<Block*>(sender()));
|
||||||
|
|
||||||
@@ -1074,7 +1069,7 @@ void TimelineWidget::BlockChanged()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineWidget::PreviewUpdated()
|
void TimelineWidget::BlockUpdated()
|
||||||
{
|
{
|
||||||
TimelineViewRect* rect = block_items_.value(static_cast<Block*>(sender()));
|
TimelineViewRect* rect = block_items_.value(static_cast<Block*>(sender()));
|
||||||
|
|
||||||
@@ -1083,6 +1078,20 @@ void TimelineWidget::PreviewUpdated()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelineWidget::TrackPreviewUpdated()
|
||||||
|
{
|
||||||
|
QMap<Block*, TimelineViewBlockItem*>::const_iterator i;
|
||||||
|
|
||||||
|
TrackOutput* track = static_cast<TrackOutput*>(sender());
|
||||||
|
TrackReference track_ref(track->track_type(), track->Index());
|
||||||
|
|
||||||
|
for (i=block_items_.constBegin(); i!=block_items_.constEnd(); i++) {
|
||||||
|
if (i.value()->Track() == track_ref) {
|
||||||
|
i.value()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TimelineWidget::UpdateHorizontalSplitters()
|
void TimelineWidget::UpdateHorizontalSplitters()
|
||||||
{
|
{
|
||||||
QSplitter* sender_splitter = static_cast<QSplitter*>(sender());
|
QSplitter* sender_splitter = static_cast<QSplitter*>(sender());
|
||||||
|
|||||||
@@ -528,9 +528,11 @@ private slots:
|
|||||||
* This slot does a static_cast on sender() to Block*, meaning all objects triggering this slot must be Blocks or
|
* This slot does a static_cast on sender() to Block*, meaning all objects triggering this slot must be Blocks or
|
||||||
* derivatives.
|
* derivatives.
|
||||||
*/
|
*/
|
||||||
void BlockChanged();
|
void BlockRefreshed();
|
||||||
|
|
||||||
void PreviewUpdated();
|
void BlockUpdated();
|
||||||
|
|
||||||
|
void TrackPreviewUpdated();
|
||||||
|
|
||||||
void UpdateHorizontalSplitters();
|
void UpdateHorizontalSplitters();
|
||||||
|
|
||||||
|
|||||||
@@ -210,10 +210,6 @@ void TrackRippleRemoveAreaCommand::redo_internal()
|
|||||||
// Split the block here
|
// Split the block here
|
||||||
trim_in_ = static_cast<Block*>(trim_out_->copy());
|
trim_in_ = static_cast<Block*>(trim_out_->copy());
|
||||||
|
|
||||||
if (trim_out_->type() == Block::kClip) {
|
|
||||||
static_cast<ClipBlock*>(trim_in_)->set_waveform(static_cast<ClipBlock*>(trim_out_)->waveform());
|
|
||||||
}
|
|
||||||
|
|
||||||
static_cast<NodeGraph*>(track_->parent())->AddNode(trim_in_);
|
static_cast<NodeGraph*>(track_->parent())->AddNode(trim_in_);
|
||||||
Node::CopyInputs(trim_out_, trim_in_);
|
Node::CopyInputs(trim_out_, trim_in_);
|
||||||
|
|
||||||
@@ -299,11 +295,6 @@ void TrackRippleRemoveAreaCommand::undo_internal()
|
|||||||
track_->RippleRemoveBlock(trim_in_);
|
track_->RippleRemoveBlock(trim_in_);
|
||||||
trim_out_->set_length_and_media_out(trim_out_old_length_);
|
trim_out_->set_length_and_media_out(trim_out_old_length_);
|
||||||
|
|
||||||
if (trim_out_->type() == Block::kClip) {
|
|
||||||
static_cast<ClipBlock*>(trim_out_)->waveform().OverwriteSums(static_cast<ClipBlock*>(trim_in_)->waveform(),
|
|
||||||
out_ - trim_out_->in());
|
|
||||||
}
|
|
||||||
|
|
||||||
delete TakeNodeFromParentGraph(trim_in_);
|
delete TakeNodeFromParentGraph(trim_in_);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -448,20 +439,10 @@ void BlockSplitCommand::redo_internal()
|
|||||||
|
|
||||||
rational new_part_length = block_->length() - (point_ - block_->in());
|
rational new_part_length = block_->length() - (point_ - block_->in());
|
||||||
|
|
||||||
AudioVisualWaveform split_waveform;
|
|
||||||
|
|
||||||
if (block_->type() == Block::kClip) {
|
|
||||||
split_waveform = static_cast<ClipBlock*>(block_)->waveform().Mid(new_length_);
|
|
||||||
}
|
|
||||||
|
|
||||||
block_->set_length_and_media_out(new_length_);
|
block_->set_length_and_media_out(new_length_);
|
||||||
|
|
||||||
new_block_->set_length_and_media_in(new_part_length);
|
new_block_->set_length_and_media_in(new_part_length);
|
||||||
|
|
||||||
if (block_->type() == Block::kClip) {
|
|
||||||
static_cast<ClipBlock*>(new_block_)->set_waveform(split_waveform);
|
|
||||||
}
|
|
||||||
|
|
||||||
track_->InsertBlockAfter(new_block_, block_);
|
track_->InsertBlockAfter(new_block_, block_);
|
||||||
|
|
||||||
foreach (NodeInput* transition, transitions_to_move_) {
|
foreach (NodeInput* transition, transitions_to_move_) {
|
||||||
@@ -486,11 +467,6 @@ void BlockSplitCommand::undo_internal()
|
|||||||
NodeParam::ConnectEdge(block_->output(), transition);
|
NodeParam::ConnectEdge(block_->output(), transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_->type() == Block::kClip) {
|
|
||||||
static_cast<ClipBlock*>(block_)->waveform().OverwriteSums(static_cast<ClipBlock*>(new_block_)->waveform(),
|
|
||||||
new_length_);
|
|
||||||
}
|
|
||||||
|
|
||||||
track_->UnblockInvalidateCache();
|
track_->UnblockInvalidateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,102 +599,6 @@ Project *BlockSplitPreservingLinksCommand::GetRelevantProject() const
|
|||||||
return static_cast<Sequence*>(blocks_.first()->parent())->project();
|
return static_cast<Sequence*>(blocks_.first()->parent())->project();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
TrackCleanGapsCommand::TrackCleanGapsCommand(TrackList *track_list, int index, QUndoCommand *parent) :
|
|
||||||
UndoCommand(parent),
|
|
||||||
track_list_(track_list),
|
|
||||||
track_index_(index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Project *TrackCleanGapsCommand::GetRelevantProject() const
|
|
||||||
{
|
|
||||||
return static_cast<Sequence*>(track_list_->GetParentGraph())->project();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackCleanGapsCommand::redo_internal()
|
|
||||||
{
|
|
||||||
GapBlock* on_gap = nullptr;
|
|
||||||
QList<GapBlock*> consecutive_gaps;
|
|
||||||
|
|
||||||
TrackOutput* track = track_list_->GetTrackAt(track_index_);
|
|
||||||
|
|
||||||
// We can block the IC signal because merging gaps won't actually change anything
|
|
||||||
track->BlockInvalidateCache();
|
|
||||||
|
|
||||||
foreach (Block* b, track->Blocks()) {
|
|
||||||
if (b->type() == Block::kGap) {
|
|
||||||
if (on_gap) {
|
|
||||||
consecutive_gaps.append(static_cast<GapBlock*>(b));
|
|
||||||
} else {
|
|
||||||
on_gap = static_cast<GapBlock*>(b);
|
|
||||||
}
|
|
||||||
} else if (on_gap) {
|
|
||||||
merged_gaps_.append({on_gap, on_gap->length(), consecutive_gaps});
|
|
||||||
|
|
||||||
// Remove each gap and add to the length of the merged
|
|
||||||
rational new_gap_length = on_gap->length();
|
|
||||||
foreach (GapBlock* gap, consecutive_gaps) {
|
|
||||||
track->RippleRemoveBlock(gap);
|
|
||||||
static_cast<NodeGraph*>(track->parent())->TakeNode(gap, &memory_manager_);
|
|
||||||
|
|
||||||
new_gap_length += gap->length();
|
|
||||||
}
|
|
||||||
on_gap->set_length_and_media_out(new_gap_length);
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
on_gap = nullptr;
|
|
||||||
consecutive_gaps.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (on_gap) {
|
|
||||||
// If we're here, we found at least one or several
|
|
||||||
removed_end_gaps_.append(on_gap);
|
|
||||||
removed_end_gaps_.append(consecutive_gaps);
|
|
||||||
|
|
||||||
foreach (GapBlock* gap, removed_end_gaps_) {
|
|
||||||
track->RippleRemoveBlock(gap);
|
|
||||||
static_cast<NodeGraph*>(track->parent())->TakeNode(gap, &memory_manager_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
track->UnblockInvalidateCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackCleanGapsCommand::undo_internal()
|
|
||||||
{
|
|
||||||
TrackOutput* track = track_list_->GetTrackAt(track_index_);
|
|
||||||
|
|
||||||
track->BlockInvalidateCache();
|
|
||||||
|
|
||||||
// Restored removed end gaps
|
|
||||||
foreach (GapBlock* gap, removed_end_gaps_) {
|
|
||||||
static_cast<NodeGraph*>(track->parent())->AddNode(gap);
|
|
||||||
track->AppendBlock(gap);
|
|
||||||
}
|
|
||||||
removed_end_gaps_.clear();
|
|
||||||
|
|
||||||
for (int i=merged_gaps_.size()-1;i>=0;i--) {
|
|
||||||
const MergedGap& merge_info = merged_gaps_.at(i);
|
|
||||||
|
|
||||||
merge_info.merged->set_length_and_media_out(merge_info.original_length);
|
|
||||||
|
|
||||||
GapBlock* last_gap_added = merge_info.merged;
|
|
||||||
|
|
||||||
foreach (GapBlock* gap, merge_info.removed) {
|
|
||||||
static_cast<NodeGraph*>(track->parent())->AddNode(gap);
|
|
||||||
track->InsertBlockAfter(gap, last_gap_added);
|
|
||||||
last_gap_added = gap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
track->UnblockInvalidateCache();
|
|
||||||
|
|
||||||
merged_gaps_.clear();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
BlockSetSpeedCommand::BlockSetSpeedCommand(Block *block, const rational &new_speed, QUndoCommand *parent) :
|
BlockSetSpeedCommand::BlockSetSpeedCommand(Block *block, const rational &new_speed, QUndoCommand *parent) :
|
||||||
UndoCommand(parent),
|
UndoCommand(parent),
|
||||||
block_(block),
|
block_(block),
|
||||||
@@ -1203,7 +1083,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
// If there's no `gap_`, we must have removed the block at the end
|
// If there's no `gap_`, we must have removed the block at the end
|
||||||
invalidate_range = TimeRange(track_->length(), RATIONAL_MAX);
|
invalidate_range = TimeRange(track_->track_length(), RATIONAL_MAX);
|
||||||
|
|
||||||
if (merged_gap_) {
|
if (merged_gap_) {
|
||||||
static_cast<NodeGraph*>(track_->parent())->AddNode(merged_gap_);
|
static_cast<NodeGraph*>(track_->parent())->AddNode(merged_gap_);
|
||||||
|
|||||||
@@ -420,37 +420,6 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
class TrackCleanGapsCommand : public UndoCommand {
|
|
||||||
public:
|
|
||||||
TrackCleanGapsCommand(TrackList* track_list, int index, QUndoCommand* parent = nullptr);
|
|
||||||
|
|
||||||
virtual Project* GetRelevantProject() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void redo_internal() override;
|
|
||||||
virtual void undo_internal() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct MergedGap {
|
|
||||||
GapBlock* merged;
|
|
||||||
rational original_length;
|
|
||||||
QList<GapBlock*> removed;
|
|
||||||
};
|
|
||||||
|
|
||||||
TrackList* track_list_;
|
|
||||||
|
|
||||||
int track_index_;
|
|
||||||
|
|
||||||
QObject memory_manager_;
|
|
||||||
|
|
||||||
QList<MergedGap> merged_gaps_;
|
|
||||||
|
|
||||||
QList<GapBlock*> removed_end_gaps_;
|
|
||||||
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand {
|
class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand {
|
||||||
public:
|
public:
|
||||||
TimelineRippleDeleteGapsAtRegionsCommand(ViewerOutput* vo, const TimeRangeList& regions, QUndoCommand* parent = nullptr);
|
TimelineRippleDeleteGapsAtRegionsCommand(ViewerOutput* vo, const TimeRangeList& regions, QUndoCommand* parent = nullptr);
|
||||||
|
|||||||
@@ -97,10 +97,14 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
|
|||||||
|
|
||||||
// Draw waveform if one is available
|
// Draw waveform if one is available
|
||||||
painter->setPen(QColor(64, 64, 64));
|
painter->setPen(QColor(64, 64, 64));
|
||||||
AudioVisualWaveform::DrawWaveform(painter,
|
TrackOutput* track = TrackOutput::TrackFromBlock(block_);
|
||||||
rect().toRect(),
|
if (track) {
|
||||||
this->GetScale(),
|
AudioVisualWaveform::DrawWaveform(painter,
|
||||||
static_cast<ClipBlock*>(block_)->waveform());
|
rect().toRect(),
|
||||||
|
this->GetScale(),
|
||||||
|
track->waveform(),
|
||||||
|
block_->in());
|
||||||
|
}
|
||||||
|
|
||||||
painter->setPen(Qt::white);
|
painter->setPen(Qt::white);
|
||||||
painter->drawLine(rect().topLeft(), QPointF(rect().right(), rect().top()));
|
painter->drawLine(rect().topLeft(), QPointF(rect().right(), rect().top()));
|
||||||
|
|||||||
Reference in New Issue
Block a user