timeline: automate waveform resizing
Now each UndoCommand won't have to handle it (unless it can introduce specific optimizations).
This commit is contained in:
@@ -69,8 +69,8 @@ void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_r
|
||||
qWarning() << "Failed to write samples - channel count is zero";
|
||||
}
|
||||
|
||||
int start_index = channels_ * qFloor(kSumSampleRate * start.toDouble());
|
||||
int samples_length = channels_ * qFloor(kSumSampleRate * (static_cast<double>(samples->sample_count()) / static_cast<double>(sample_rate)));
|
||||
int start_index = 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) {
|
||||
@@ -93,7 +93,21 @@ void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_r
|
||||
}
|
||||
}
|
||||
|
||||
AudioVisualWaveform AudioVisualWaveform::Cut(const rational &time)
|
||||
void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &start)
|
||||
{
|
||||
int start_index = time_to_samples(start);
|
||||
int end_index = start_index + sums.data_.size();
|
||||
|
||||
if (data_.size() < end_index) {
|
||||
data_.resize(end_index);
|
||||
}
|
||||
|
||||
memcpy(&data_[start_index],
|
||||
sums.data_.constData(),
|
||||
sums.data_.size() * sizeof(SamplePerChannel));
|
||||
}
|
||||
|
||||
AudioVisualWaveform AudioVisualWaveform::Mid(const rational &time) const
|
||||
{
|
||||
int sample_index = time_to_samples(time);
|
||||
|
||||
@@ -101,9 +115,6 @@ AudioVisualWaveform AudioVisualWaveform::Cut(const rational &time)
|
||||
AudioVisualWaveform copy = *this;
|
||||
copy.data_ = data_.mid(sample_index);
|
||||
|
||||
// Chop the latter section off too
|
||||
data_.resize(sample_index);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -270,7 +281,12 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con
|
||||
|
||||
int AudioVisualWaveform::time_to_samples(const rational &time) const
|
||||
{
|
||||
return qFloor(time.toDouble() * kSumSampleRate) * channels_;
|
||||
return time_to_samples(time.toDouble());
|
||||
}
|
||||
|
||||
int AudioVisualWaveform::time_to_samples(const double &time) const
|
||||
{
|
||||
return qFloor(time * kSumSampleRate) * channels_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -69,8 +69,9 @@ public:
|
||||
void AddSum(const float* samples, int nb_samples, int nb_channels);
|
||||
|
||||
void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start);
|
||||
void OverwriteSums(const AudioVisualWaveform& sums, const rational& start);
|
||||
|
||||
AudioVisualWaveform Cut(const rational& time);
|
||||
AudioVisualWaveform Mid(const rational& time) const;
|
||||
void Append(const AudioVisualWaveform& waveform);
|
||||
void TrimIn(const rational& time);
|
||||
void TrimOut(const rational& time);
|
||||
@@ -98,6 +99,7 @@ private:
|
||||
static void ClampMinMax(SamplePerChannel &sum, T value);
|
||||
|
||||
int time_to_samples(const rational& time) const;
|
||||
int time_to_samples(const double& time) const;
|
||||
|
||||
int channels_ = 0;
|
||||
|
||||
|
||||
@@ -101,7 +101,11 @@ void Block::set_length_and_media_out(const rational &length)
|
||||
return;
|
||||
}
|
||||
|
||||
length_input_->set_standard_value(QVariant::fromValue(length));
|
||||
rational old_length = this->length();
|
||||
|
||||
set_length_internal(length);
|
||||
|
||||
LengthChangedEvent(old_length, length, Timeline::kTrimOut);
|
||||
}
|
||||
|
||||
void Block::set_length_and_media_in(const rational &length)
|
||||
@@ -115,8 +119,12 @@ void Block::set_length_and_media_in(const rational &length)
|
||||
// Calculate media_in adjustment
|
||||
set_media_in(media_in() + (this->length() - length) * speed());
|
||||
|
||||
rational old_length = this->length();
|
||||
|
||||
// Set the length without setting media out
|
||||
set_length_and_media_out(length);
|
||||
set_length_internal(length);
|
||||
|
||||
LengthChangedEvent(old_length, length, Timeline::kTrimIn);
|
||||
}
|
||||
|
||||
Block *Block::previous()
|
||||
@@ -246,6 +254,15 @@ QList<NodeInput *> Block::GetInputsToHash() const
|
||||
return inputs;
|
||||
}
|
||||
|
||||
void Block::LengthChangedEvent(const rational &, const rational &, const Timeline::MovementMode &)
|
||||
{
|
||||
}
|
||||
|
||||
void Block::set_length_internal(const rational &length)
|
||||
{
|
||||
length_input_->set_standard_value(QVariant::fromValue(length));
|
||||
}
|
||||
|
||||
void Block::LengthInputChanged()
|
||||
{
|
||||
emit LengthChanged(length());
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define BLOCK_H
|
||||
|
||||
#include "node/node.h"
|
||||
#include "timeline/timelinecommon.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -130,10 +131,16 @@ protected:
|
||||
|
||||
virtual QList<NodeInput*> GetInputsToHash() const override;
|
||||
|
||||
virtual void LengthChangedEvent(const rational& old_length,
|
||||
const rational& new_length,
|
||||
const Timeline::MovementMode& mode);
|
||||
|
||||
Block* previous_;
|
||||
Block* next_;
|
||||
|
||||
private:
|
||||
void set_length_internal(const rational &length);
|
||||
|
||||
NodeInput* name_input_;
|
||||
NodeInput* length_input_;
|
||||
NodeInput* media_in_input_;
|
||||
|
||||
@@ -59,6 +59,26 @@ NodeInput *ClipBlock::texture_input() const
|
||||
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)
|
||||
{
|
||||
// If signal is from texture input, transform all times from media time to sequence time
|
||||
|
||||
@@ -72,6 +72,11 @@ public:
|
||||
signals:
|
||||
void PreviewUpdated();
|
||||
|
||||
protected:
|
||||
virtual void LengthChangedEvent(const rational& old_length,
|
||||
const rational& new_length,
|
||||
const Timeline::MovementMode& mode) override;
|
||||
|
||||
private:
|
||||
NodeInput* texture_input_;
|
||||
|
||||
|
||||
@@ -210,6 +210,10 @@ void TrackRippleRemoveAreaCommand::redo_internal()
|
||||
// Split the block here
|
||||
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_);
|
||||
Node::CopyInputs(trim_out_, trim_in_);
|
||||
|
||||
@@ -293,9 +297,15 @@ void TrackRippleRemoveAreaCommand::undo_internal()
|
||||
|
||||
// trim_in_ is our copy and trim_out_ is our original
|
||||
track_->RippleRemoveBlock(trim_in_);
|
||||
delete TakeNodeFromParentGraph(trim_in_);
|
||||
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_);
|
||||
|
||||
} else {
|
||||
|
||||
// If we picked up a block to trim the out point of
|
||||
@@ -438,10 +448,20 @@ void BlockSplitCommand::redo_internal()
|
||||
|
||||
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_);
|
||||
|
||||
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_);
|
||||
|
||||
foreach (NodeInput* transition, transitions_to_move_) {
|
||||
@@ -449,10 +469,6 @@ void BlockSplitCommand::redo_internal()
|
||||
NodeParam::ConnectEdge(new_block_->output(), transition);
|
||||
}
|
||||
|
||||
if (block_->type() == Block::kClip) {
|
||||
static_cast<ClipBlock*>(new_block_)->set_waveform(static_cast<ClipBlock*>(block_)->waveform().Cut(new_length_));
|
||||
}
|
||||
|
||||
track_->UnblockInvalidateCache();
|
||||
}
|
||||
|
||||
@@ -471,7 +487,8 @@ void BlockSplitCommand::undo_internal()
|
||||
}
|
||||
|
||||
if (block_->type() == Block::kClip) {
|
||||
static_cast<ClipBlock*>(block_)->waveform().Append(static_cast<ClipBlock*>(new_block_)->waveform());
|
||||
static_cast<ClipBlock*>(block_)->waveform().OverwriteSums(static_cast<ClipBlock*>(new_block_)->waveform(),
|
||||
new_length_);
|
||||
}
|
||||
|
||||
track_->UnblockInvalidateCache();
|
||||
@@ -1006,14 +1023,6 @@ void BlockTrimCommand::redo_internal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (block_->type() == Block::kClip) {
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
static_cast<ClipBlock*>(block_)->waveform().TrimIn(trim_diff);
|
||||
} else {
|
||||
static_cast<ClipBlock*>(block_)->waveform().TrimOut(trim_diff);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (adjacent_) {
|
||||
// If trimming LONGER, we'll need to trim the adjacent
|
||||
@@ -1024,14 +1033,6 @@ void BlockTrimCommand::redo_internal()
|
||||
adjacent_->set_length_and_media_in(adjacent_->length() + trim_diff);
|
||||
}
|
||||
}
|
||||
|
||||
if (block_->type() == Block::kClip) {
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
static_cast<ClipBlock*>(block_)->waveform().PrependSilence(-trim_diff);
|
||||
} else {
|
||||
static_cast<ClipBlock*>(block_)->waveform().AppendSilence(-trim_diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
track_->UnblockInvalidateCache();
|
||||
@@ -1051,22 +1052,13 @@ void BlockTrimCommand::undo_internal()
|
||||
if (we_created_adjacent_) {
|
||||
// If we created a gap, just remove it straight up
|
||||
track_->RippleRemoveBlock(adjacent_);
|
||||
TakeNodeFromParentGraph(adjacent_);
|
||||
delete adjacent_;
|
||||
delete TakeNodeFromParentGraph(adjacent_);
|
||||
adjacent_ = nullptr;
|
||||
we_created_adjacent_ = false;
|
||||
} else if (adjacent_) {
|
||||
// If we adjusted an existing gap, unadjust here
|
||||
adjacent_->set_length_and_media_out(adjacent_->length() - trim_diff);
|
||||
}
|
||||
|
||||
if (block_->type() == Block::kClip) {
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
static_cast<ClipBlock*>(block_)->waveform().PrependSilence(trim_diff);
|
||||
} else {
|
||||
static_cast<ClipBlock*>(block_)->waveform().AppendSilence(trim_diff);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (adjacent_) {
|
||||
// If trimmed LONGER, we adjusted an existing block
|
||||
@@ -1075,14 +1067,6 @@ void BlockTrimCommand::undo_internal()
|
||||
adjacent_->set_length_and_media_out(adjacent_->length() - trim_diff);
|
||||
}
|
||||
}
|
||||
|
||||
if (block_->type() == Block::kClip) {
|
||||
if (mode_ == Timeline::kTrimIn) {
|
||||
static_cast<ClipBlock*>(block_)->waveform().TrimIn(-trim_diff);
|
||||
} else {
|
||||
static_cast<ClipBlock*>(block_)->waveform().TrimOut(-trim_diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimeRange invalidate_range;
|
||||
@@ -1194,8 +1178,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
|
||||
if (we_created_gap_) {
|
||||
// We made this gap, simply swap our gap back
|
||||
track_->ReplaceBlock(gap_, block_);
|
||||
TakeNodeFromParentGraph(gap_);
|
||||
delete gap_;
|
||||
delete TakeNodeFromParentGraph(gap_);
|
||||
gap_ = nullptr;
|
||||
} else {
|
||||
// We must have extended an existing gap
|
||||
@@ -1278,24 +1261,6 @@ void TrackSlideCommand::slide_internal(bool undo)
|
||||
if (info.mode == Timeline::kTrimIn || info.mode == Timeline::kTrimOut) {
|
||||
rational new_len = undo ? info.old_time : info.new_time;
|
||||
|
||||
if (info.block->type() == Block::kClip) {
|
||||
AudioVisualWaveform& waveform = static_cast<ClipBlock*>(info.block)->waveform();
|
||||
|
||||
if (new_len < info.block->length()) {
|
||||
if (info.mode == Timeline::kTrimIn) {
|
||||
waveform.TrimIn(info.block->length() - new_len);
|
||||
} else {
|
||||
waveform.TrimOut(info.block->length() - new_len);
|
||||
}
|
||||
} else {
|
||||
if (info.mode == Timeline::kTrimIn) {
|
||||
waveform.PrependSilence(new_len - info.block->length());
|
||||
} else {
|
||||
waveform.AppendSilence(new_len - info.block->length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info.mode == Timeline::kTrimIn) {
|
||||
info.block->set_length_and_media_in(new_len);
|
||||
} else {
|
||||
@@ -1322,8 +1287,7 @@ void TrackSlideCommand::slide_internal(bool undo)
|
||||
track->BlockInvalidateCache();
|
||||
|
||||
track->RippleRemoveBlock(gap);
|
||||
TakeNodeFromParentGraph(gap);
|
||||
delete gap;
|
||||
delete TakeNodeFromParentGraph(gap);
|
||||
|
||||
track->UnblockInvalidateCache();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user