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:
@@ -981,40 +981,33 @@ void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event)
|
||||
|
||||
void TimelineWidget::AddBlock(Block *block, TrackReference track)
|
||||
{
|
||||
switch (block->type()) {
|
||||
case Block::kClip:
|
||||
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);
|
||||
// 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->SetScale(GetScale());
|
||||
item->SetTrack(track);
|
||||
item->SetTimebase(timebase());
|
||||
item->SetYCoords(GetTrackY(track), GetTrackHeight(track));
|
||||
item->SetScale(GetScale());
|
||||
item->SetTrack(track);
|
||||
item->SetTimebase(timebase());
|
||||
|
||||
// Add to list of clip items that can be iterated through
|
||||
block_items_.insert(block, item);
|
||||
// Add to list of clip items that can be iterated through
|
||||
block_items_.insert(block, item);
|
||||
|
||||
// Add item to graphics scene
|
||||
views_.at(track.type())->view()->scene()->addItem(item);
|
||||
// Add item to graphics scene
|
||||
views_.at(track.type())->view()->scene()->addItem(item);
|
||||
|
||||
connect(block, &Block::Refreshed, this, &TimelineWidget::BlockChanged);
|
||||
connect(block, &Block::LinksChanged, this, &TimelineWidget::PreviewUpdated);
|
||||
connect(block, &Block::NameChanged, this, &TimelineWidget::PreviewUpdated);
|
||||
connect(block, &Block::EnabledChanged, this, &TimelineWidget::PreviewUpdated);
|
||||
|
||||
if (block->type() == Block::kClip) {
|
||||
connect(static_cast<ClipBlock*>(block), &ClipBlock::PreviewUpdated, this, &TimelineWidget::PreviewUpdated);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
connect(block, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed);
|
||||
connect(block, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated);
|
||||
connect(block, &Block::NameChanged, this, &TimelineWidget::BlockUpdated);
|
||||
connect(block, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1025,11 +1018,13 @@ void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type)
|
||||
}
|
||||
|
||||
connect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
|
||||
connect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated);
|
||||
}
|
||||
|
||||
void TimelineWidget::RemoveTrack(TrackOutput *track)
|
||||
{
|
||||
disconnect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged);
|
||||
disconnect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated);
|
||||
|
||||
foreach (Block* b, track->Blocks()) {
|
||||
RemoveBlock(b);
|
||||
@@ -1065,7 +1060,7 @@ void TimelineWidget::ViewSelectionChanged()
|
||||
emit SelectionChanged(selected_blocks);
|
||||
}
|
||||
|
||||
void TimelineWidget::BlockChanged()
|
||||
void TimelineWidget::BlockRefreshed()
|
||||
{
|
||||
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()));
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
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
|
||||
* derivatives.
|
||||
*/
|
||||
void BlockChanged();
|
||||
void BlockRefreshed();
|
||||
|
||||
void PreviewUpdated();
|
||||
void BlockUpdated();
|
||||
|
||||
void TrackPreviewUpdated();
|
||||
|
||||
void UpdateHorizontalSplitters();
|
||||
|
||||
|
||||
@@ -210,10 +210,6 @@ 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_);
|
||||
|
||||
@@ -299,11 +295,6 @@ void TrackRippleRemoveAreaCommand::undo_internal()
|
||||
track_->RippleRemoveBlock(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 {
|
||||
@@ -448,20 +439,10 @@ 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_) {
|
||||
@@ -486,11 +467,6 @@ void BlockSplitCommand::undo_internal()
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -623,102 +599,6 @@ Project *BlockSplitPreservingLinksCommand::GetRelevantProject() const
|
||||
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) :
|
||||
UndoCommand(parent),
|
||||
block_(block),
|
||||
@@ -1203,7 +1083,7 @@ void TrackReplaceBlockWithGapCommand::undo_internal()
|
||||
} else {
|
||||
|
||||
// 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_) {
|
||||
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 {
|
||||
public:
|
||||
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
|
||||
painter->setPen(QColor(64, 64, 64));
|
||||
AudioVisualWaveform::DrawWaveform(painter,
|
||||
rect().toRect(),
|
||||
this->GetScale(),
|
||||
static_cast<ClipBlock*>(block_)->waveform());
|
||||
TrackOutput* track = TrackOutput::TrackFromBlock(block_);
|
||||
if (track) {
|
||||
AudioVisualWaveform::DrawWaveform(painter,
|
||||
rect().toRect(),
|
||||
this->GetScale(),
|
||||
track->waveform(),
|
||||
block_->in());
|
||||
}
|
||||
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawLine(rect().topLeft(), QPointF(rect().right(), rect().top()));
|
||||
|
||||
Reference in New Issue
Block a user