diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index c02588cc6..a58a1cd11 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -28,69 +28,27 @@ OLIVE_NAMESPACE_ENTER 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) { 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;isample_count();i+=chunk_size) { - QVector summary = SumSamples(samples, - i, - qMin(chunk_size, samples->sample_count_per_channel() - i)); - - wave_file.write(reinterpret_cast(summary.constData()), - summary.size() * sizeof(SampleSummer::Sum)); - } -} -*/ - void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start) { if (!channels_) { qWarning() << "Failed to write samples - channel count is zero"; } - 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) { - data_.resize(end_index); - } - - int chunk_size = sample_rate / kSumSampleRate; - - for (int i=0; i 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)); - } + overwrite_samples_internal(samples, sample_rate, time_to_samples(start)); } void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &start) @@ -150,10 +108,7 @@ void AudioVisualWaveform::PrependSilence(const rational &time) } // Fill remainder with silence - for (int i=0;i AudioVisualWaveform::SumSamples(const float *samples, int nb_samples, int nb_channels) @@ -245,9 +197,11 @@ void AudioVisualWaveform::DrawSample(QPainter *painter, const QVector summary; 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 end = qMin(rect.right(), -top_left.x() + viewport.width()); - QVector lines; - for (int i=start;i(kSumSampleRate) * static_cast(i - rect.x() + 1) / scale) * samples.channel_count()); + start_sample_index + qFloor(static_cast(kSumSampleRate) * static_cast(i - rect.x() + 1) / scale) * samples.channel_count()); if (summary_index != 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()); } +} - painter->drawLines(lines); +void AudioVisualWaveform::overwrite_samples_internal(SampleBufferPtr samples, int sample_rate, int start_index) +{ + 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) { + data_.resize(end_index); + } + + int chunk_size = sample_rate / kSumSampleRate; + + for (int i=0; i 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 diff --git a/app/audio/audiovisualwaveform.h b/app/audio/audiovisualwaveform.h index c13ada097..434461860 100644 --- a/app/audio/audiovisualwaveform.h +++ b/app/audio/audiovisualwaveform.h @@ -66,6 +66,7 @@ public: return data_.constData(); } + void AddSamples(SampleBufferPtr samples, int sample_rate); void AddSum(const float* samples, int nb_samples, int nb_channels); void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start); @@ -89,7 +90,7 @@ public: static void DrawSample(QPainter* painter, const QVector &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: template @@ -98,6 +99,8 @@ private: template 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 double& time) const; @@ -109,4 +112,6 @@ private: OLIVE_NAMESPACE_EXIT +Q_DECLARE_METATYPE(OLIVE_NAMESPACE::AudioVisualWaveform) + #endif // SUMSAMPLES_H diff --git a/app/core.cpp b/app/core.cpp index ba838dbdc..58295d300 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -552,6 +552,7 @@ void Core::DeclareTypesForQt() qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); + qRegisterMetaType(); } void Core::StartGUI(bool full_screen) diff --git a/app/node/block/block.h b/app/node/block/block.h index 1d881fa17..6568ca543 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -28,13 +28,6 @@ OLIVE_NAMESPACE_ENTER /** * @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 { diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 604ce0204..851f8b9f8 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -59,26 +59,6 @@ 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 8cecf96f2..00f6e0ba0 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -21,7 +21,6 @@ #ifndef CLIPBLOCK_H #define CLIPBLOCK_H -#include "audio/audiovisualwaveform.h" #include "node/block/block.h" OLIVE_NAMESPACE_ENTER @@ -57,31 +56,9 @@ public: 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: NodeInput* texture_input_; - AudioVisualWaveform waveform_; - }; OLIVE_NAMESPACE_EXIT diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 28b6ab73d..8d60a5534 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -63,12 +63,7 @@ const Timeline::TrackType& TrackOutput::track_type() const return track_type_; } -Block::Type TrackOutput::type() const -{ - return kClip; -} - -Block *TrackOutput::copy() const +Node *TrackOutput::copy() const { return new TrackOutput(); } @@ -116,7 +111,7 @@ void TrackOutput::SetTrackHeight(const int &height) void TrackOutput::Retranslate() { - Block::Retranslate(); + Node::Retranslate(); block_input_->set_name(tr("Blocks")); muted_input_->set_name(tr("Muted")); diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index a17f82ea9..85c995870 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -21,6 +21,7 @@ #ifndef TRACKOUTPUT_H #define TRACKOUTPUT_H +#include "audio/audiovisualwaveform.h" #include "node/block/block.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 */ -class TrackOutput : public Block +class TrackOutput : public Node { Q_OBJECT public: @@ -38,9 +39,7 @@ public: const Timeline::TrackType& track_type() const; void set_track_type(const Timeline::TrackType& track_type); - virtual Type type() const override; - - virtual Block* copy() const override; + virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; @@ -195,6 +194,11 @@ public: void PushLengthChangeSignal(); + AudioVisualWaveform& waveform() + { + return waveform_; + } + public slots: void SetTrackName(const QString& name); @@ -233,6 +237,11 @@ signals: */ void IndexChanged(int i); + /** + * @brief Signal emitted when preview (waveform) has changed and UI should be updated + */ + void PreviewChanged(); + protected: private: @@ -266,6 +275,8 @@ private: bool queued_length_change_; rational queued_length_; + AudioVisualWaveform waveform_; + private slots: void BlockConnected(NodeEdgePtr edge); diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index bf5153d67..6a214fc5b 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -94,11 +94,6 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node) } } -void RenderBackend::SetUpdateWithGraph(bool e) -{ - update_with_graph_ = e; -} - void RenderBackend::ClearVideoQueue() { foreach (RenderTicketPtr t, render_queue_) { @@ -275,6 +270,7 @@ void RenderBackend::RunNextJob() RenderWorker* worker = CreateNewWorker(); connect(worker, &RenderWorker::FinishedJob, this, &RenderBackend::WorkerFinished); + connect(worker, &RenderWorker::WaveformGenerated, this, &RenderBackend::WorkerGeneratedWaveform); workers_.replace(i, {worker, false}); } @@ -292,6 +288,7 @@ void RenderBackend::RunNextJob() worker->SetVideoParams(video_params_); worker->SetAudioParams(audio_params_); worker->SetVideoDownloadMatrix(video_download_matrix_); + worker->SetGeneratePreviews(generate_previews_); worker->SetCopyMap(©_map_); 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::const_iterator i; + for (i=copy_map_.constBegin(); i!=copy_map_.constEnd(); i++) { + if (i.value() == copied_track) { + track = static_cast(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) { // Find our copy of this parameter diff --git a/app/render/backend/renderbackend.h b/app/render/backend/renderbackend.h index e8b1d043d..6812b6db2 100644 --- a/app/render/backend/renderbackend.h +++ b/app/render/backend/renderbackend.h @@ -45,7 +45,15 @@ public: 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(); @@ -113,9 +121,13 @@ private: bool update_with_graph_; + bool generate_previews_; + private slots: void WorkerFinished(); + void WorkerGeneratedWaveform(const OLIVE_NAMESPACE::TrackOutput* copied_track, const OLIVE_NAMESPACE::AudioVisualWaveform& samples, const OLIVE_NAMESPACE::rational& start); + }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/renderworker.cpp b/app/render/backend/renderworker.cpp index 5e465af50..a0c3aa762 100644 --- a/app/render/backend/renderworker.cpp +++ b/app/render/backend/renderworker.cpp @@ -34,7 +34,8 @@ OLIVE_NAMESPACE_ENTER RenderWorker::RenderWorker(RenderBackend* parent) : parent_(parent), 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 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(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(src_block)->PreviewUpdated(); - } - 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)); return merged_table; diff --git a/app/render/backend/renderworker.h b/app/render/backend/renderworker.h index fc8cf5fc2..8ebc3d8f3 100644 --- a/app/render/backend/renderworker.h +++ b/app/render/backend/renderworker.h @@ -73,6 +73,11 @@ public: copy_map_ = copy_map; } + void SetGeneratePreviews(bool e) + { + generate_previews_ = e; + } + /** * @brief Return a unique ID for the image generated at this time * @@ -127,6 +132,8 @@ signals: void FinishedJob(); + void WaveformGenerated(const OLIVE_NAMESPACE::TrackOutput* track, const OLIVE_NAMESPACE::AudioVisualWaveform& samples, const OLIVE_NAMESPACE::rational& start); + private: NodeValue GetDataFromStream(StreamPtr stream, const TimeRange& input_time); @@ -157,6 +164,8 @@ private: bool audio_mode_is_preview_; + bool generate_previews_; + QHash* copy_map_; }; diff --git a/app/task/cache/cache.cpp b/app/task/cache/cache.cpp index 4c10bf1cf..ed9df21c6 100644 --- a/app/task/cache/cache.cpp +++ b/app/task/cache/cache.cpp @@ -32,6 +32,8 @@ CacheTask::CacheTask(ViewerOutput* viewer, const VideoRenderingParams& vparams, in_out_only_(in_out_only) { SetTitle(tr("Caching \"%1\"").arg(viewer->media_name())); + + backend()->SetGeneratePreviews(true); } bool CacheTask::Run() diff --git a/app/task/render/render.h b/app/task/render/render.h index e51b9681a..14f56e138 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -68,6 +68,11 @@ protected: return job_time_; } + OpenGLBackend* backend() + { + return &backend_; + } + private: ViewerOutput* viewer_; diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 95c982e4a..9c0b0e35d 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -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(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(sender())); @@ -1074,7 +1069,7 @@ void TimelineWidget::BlockChanged() } } -void TimelineWidget::PreviewUpdated() +void TimelineWidget::BlockUpdated() { TimelineViewRect* rect = block_items_.value(static_cast(sender())); @@ -1083,6 +1078,20 @@ void TimelineWidget::PreviewUpdated() } } +void TimelineWidget::TrackPreviewUpdated() +{ + QMap::const_iterator i; + + TrackOutput* track = static_cast(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(sender()); diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 94251d0bc..d0eed8496 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -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(); diff --git a/app/widget/timelinewidget/undo/undo.cpp b/app/widget/timelinewidget/undo/undo.cpp index 282b4d587..d447bca77 100644 --- a/app/widget/timelinewidget/undo/undo.cpp +++ b/app/widget/timelinewidget/undo/undo.cpp @@ -210,10 +210,6 @@ 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_); @@ -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(trim_out_)->waveform().OverwriteSums(static_cast(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(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_) { @@ -486,11 +467,6 @@ void BlockSplitCommand::undo_internal() NodeParam::ConnectEdge(block_->output(), transition); } - if (block_->type() == Block::kClip) { - static_cast(block_)->waveform().OverwriteSums(static_cast(new_block_)->waveform(), - new_length_); - } - track_->UnblockInvalidateCache(); } @@ -623,102 +599,6 @@ Project *BlockSplitPreservingLinksCommand::GetRelevantProject() const return static_cast(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(track_list_->GetParentGraph())->project(); -} - -void TrackCleanGapsCommand::redo_internal() -{ - GapBlock* on_gap = nullptr; - QList 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(b)); - } else { - on_gap = static_cast(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(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(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(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(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(track_->parent())->AddNode(merged_gap_); diff --git a/app/widget/timelinewidget/undo/undo.h b/app/widget/timelinewidget/undo/undo.h index 892c21daa..511fffdb2 100644 --- a/app/widget/timelinewidget/undo/undo.h +++ b/app/widget/timelinewidget/undo/undo.h @@ -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 removed; - }; - - TrackList* track_list_; - - int track_index_; - - QObject memory_manager_; - - QList merged_gaps_; - - QList removed_end_gaps_; - -}; -*/ - class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand { public: TimelineRippleDeleteGapsAtRegionsCommand(ViewerOutput* vo, const TimeRangeList& regions, QUndoCommand* parent = nullptr); diff --git a/app/widget/timelinewidget/view/timelineviewblockitem.cpp b/app/widget/timelinewidget/view/timelineviewblockitem.cpp index 48df43b20..8195fa4b7 100644 --- a/app/widget/timelinewidget/view/timelineviewblockitem.cpp +++ b/app/widget/timelinewidget/view/timelineviewblockitem.cpp @@ -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(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()));