diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index c9ed53f97..8ba87384e 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -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(samples->sample_count()) / static_cast(sample_rate))); + int start_index = time_to_samples(start); + int samples_length = time_to_samples(static_cast(samples->sample_count()) / static_cast(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 diff --git a/app/audio/audiovisualwaveform.h b/app/audio/audiovisualwaveform.h index 35df5a054..c13ada097 100644 --- a/app/audio/audiovisualwaveform.h +++ b/app/audio/audiovisualwaveform.h @@ -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; diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index 1597d737d..bfa72f403 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -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 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()); diff --git a/app/node/block/block.h b/app/node/block/block.h index f69b568b8..1d881fa17 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -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 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_; diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 288cb53c6..04205c192 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -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 diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 3ce6a7b39..8cecf96f2 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -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_; diff --git a/app/widget/timelinewidget/undo/undo.cpp b/app/widget/timelinewidget/undo/undo.cpp index 45ba69b20..a9d624c6b 100644 --- a/app/widget/timelinewidget/undo/undo.cpp +++ b/app/widget/timelinewidget/undo/undo.cpp @@ -210,6 +210,10 @@ void TrackRippleRemoveAreaCommand::redo_internal() // Split the block here trim_in_ = static_cast(trim_out_->copy()); + if (trim_out_->type() == Block::kClip) { + static_cast(trim_in_)->set_waveform(static_cast(trim_out_)->waveform()); + } + static_cast(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(trim_out_)->waveform().OverwriteSums(static_cast(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(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(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(new_block_)->set_waveform(static_cast(block_)->waveform().Cut(new_length_)); - } - track_->UnblockInvalidateCache(); } @@ -471,7 +487,8 @@ void BlockSplitCommand::undo_internal() } if (block_->type() == Block::kClip) { - static_cast(block_)->waveform().Append(static_cast(new_block_)->waveform()); + static_cast(block_)->waveform().OverwriteSums(static_cast(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(block_)->waveform().TrimIn(trim_diff); - } else { - static_cast(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(block_)->waveform().PrependSilence(-trim_diff); - } else { - static_cast(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(block_)->waveform().PrependSilence(trim_diff); - } else { - static_cast(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(block_)->waveform().TrimIn(-trim_diff); - } else { - static_cast(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(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(); }