diff --git a/app/node/globals.h b/app/node/globals.h index 4db941be9..c7ec1ce59 100644 --- a/app/node/globals.h +++ b/app/node/globals.h @@ -24,6 +24,7 @@ #include #include "common/timerange.h" +#include "render/audioparams.h" #include "render/videoparams.h" namespace olive { @@ -33,19 +34,22 @@ class NodeGlobals public: NodeGlobals(){} - NodeGlobals(const VideoParams &vparam, const TimeRange &time) : + NodeGlobals(const VideoParams &vparam, const AudioParams &aparam, const TimeRange &time) : video_params_(vparam), + audio_params_(aparam), time_(time) { } QVector2D square_resolution() const { return video_params_.square_resolution(); } QVector2D nonsquare_resolution() const { return video_params_.resolution(); } + const AudioParams &aparams() const { return audio_params_; } const VideoParams &vparams() const { return video_params_; } const TimeRange &time() const { return time_; } private: VideoParams video_params_; + AudioParams audio_params_; TimeRange time_; }; diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 527b019bc..3d242077a 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -116,7 +116,7 @@ Node::ActiveElements Track::GetActiveElementsAtTime(const QString &input, const ActiveElements a; for (int i=start; i<=end; i++) { Block *b = blocks_.at(i); - if (b->is_enabled()) { + if (b->is_enabled() && (dynamic_cast(b) || dynamic_cast(b))) { a.add(GetArrayIndexFromCacheIndex(i)); } } @@ -142,7 +142,7 @@ void Track::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeVal } } else if (this->type() == Track::kAudio) { // Audio - ProcessAudioTrack(table, globals.time()); + ProcessAudioTrack(value, globals, table); } } @@ -603,100 +603,97 @@ int Track::GetBlockIndexAtTime(const rational &time) const return -1; } -void Track::ProcessAudioTrack(NodeValueTable *table, const TimeRange &range) const +void Track::ProcessAudioTrack(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const { - /* + const TimeRange &range = globals.time(); + // All these blocks will need to output to a buffer so we create one here - SampleBuffer block_range_buffer(audio_params, range.length()); + SampleBuffer block_range_buffer(globals.aparams(), range.length()); block_range_buffer.silence(); - NodeValueTable merged_table; - // Loop through active blocks retrieving their audio - foreach (Block* b, active_blocks) { - if (dynamic_cast(b) || dynamic_cast(b)) { - TimeRange range_for_block(qMax(b->in(), range.in()), - qMin(b->out(), range.out())); + NodeValueArray arr = value[kBlockInput].toArray(); - qint64 destination_offset = audio_params.time_to_samples(range_for_block.in() - range.in()); - qint64 max_dest_sz = audio_params.time_to_samples(range_for_block.length()); + for (auto it=arr.cbegin(); it!=arr.cend(); it++) { + Block *b = blocks_.at(GetCacheIndexFromArrayIndex(it->first)); - // Destination buffer - NodeValueTable table = GenerateTable(b, Track::TransformRangeForBlock(b, range_for_block)); - SampleBuffer samples_from_this_block = table.Take(NodeValue::kSamples).toSamples(); - ClipBlock *clip_cast = dynamic_cast(b); + TimeRange range_for_block(qMax(b->in(), range.in()), + qMin(b->out(), range.out())); - if (samples_from_this_block.is_allocated()) { - // If this is a clip, we might have extra speed/reverse information - if (clip_cast) { - double speed_value = clip_cast->speed(); - bool reversed = clip_cast->reverse(); + qint64 destination_offset = globals.aparams().time_to_samples(range_for_block.in() - range.in()); + qint64 max_dest_sz = globals.aparams().time_to_samples(range_for_block.length()); - if (qIsNull(speed_value)) { - // Just silence, don't think there's any other practical application of 0 speed audio - samples_from_this_block.silence(); - } else if (!qFuzzyCompare(speed_value, 1.0)) { - if (clip_cast->maintain_audio_pitch()) { - AudioProcessor processor; + // Destination buffer + SampleBuffer samples_from_this_block = it->second.toSamples(); + ClipBlock *clip_cast = dynamic_cast(b); - if (processor.Open(samples_from_this_block.audio_params(), samples_from_this_block.audio_params(), speed_value)) { - AudioProcessor::Buffer out; + if (samples_from_this_block.is_allocated()) { + // If this is a clip, we might have extra speed/reverse information + if (clip_cast) { + double speed_value = clip_cast->speed(); + bool reversed = clip_cast->reverse(); - // FIXME: This is not the best way to do this, the TempoProcessor works best - // when it's given a continuous stream of audio, which is challenging - // in our current "modular" audio system. This should still work reasonably - // well on export (assuming audio is all generated at once on export), but - // users may hear clicks and pops in the audio during preview due to this - // approach. - int r = processor.Convert(samples_from_this_block.to_raw_ptrs().data(), samples_from_this_block.sample_count(), nullptr); + if (qIsNull(speed_value)) { + // Just silence, don't think there's any other practical application of 0 speed audio + samples_from_this_block.silence(); + } else if (!qFuzzyCompare(speed_value, 1.0)) { + if (clip_cast->maintain_audio_pitch()) { + AudioProcessor processor; - if (r < 0) { - qCritical() << "Failed to change tempo of audio:" << r; - } else { - processor.Flush(); + if (processor.Open(samples_from_this_block.audio_params(), samples_from_this_block.audio_params(), speed_value)) { + AudioProcessor::Buffer out; - processor.Convert(nullptr, 0, &out); + // FIXME: This is not the best way to do this, the TempoProcessor works best + // when it's given a continuous stream of audio, which is challenging + // in our current "modular" audio system. This should still work reasonably + // well on export (assuming audio is all generated at once on export), but + // users may hear clicks and pops in the audio during preview due to this + // approach. + int r = processor.Convert(samples_from_this_block.to_raw_ptrs().data(), samples_from_this_block.sample_count(), nullptr); - if (!out.empty()) { - int nb_samples = out.front().size() * samples_from_this_block.audio_params().bytes_per_sample_per_channel(); + if (r < 0) { + qCritical() << "Failed to change tempo of audio:" << r; + } else { + processor.Flush(); - if (nb_samples) { - SampleBuffer new_samples(samples_from_this_block.audio_params(), nb_samples); + processor.Convert(nullptr, 0, &out); - for (int i=0; iPush(NodeValue::kSamples, QVariant::fromValue(block_range_buffer), this); - */ } void Track::BlockLengthChanged() diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index e2ac8d3bb..e6ae5584e 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -453,7 +453,7 @@ private: int GetBlockIndexAtTime(const rational &time) const; - void ProcessAudioTrack(NodeValueTable *table, const TimeRange &range) const; + void ProcessAudioTrack(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const; TimeRangeList block_length_pending_invalidations_; diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index d962dc798..bb95a6463 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -179,9 +179,9 @@ void NodeTraverser::Transform(QTransform *transform, const Node *start, const No transform_ = nullptr; } -NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams ¶ms, const TimeRange &time) +NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams &vparams, const AudioParams &aparams, const TimeRange &time) { - return NodeGlobals(params, time); + return NodeGlobals(vparams, aparams, time); } NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range) @@ -304,7 +304,7 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang table = database.Merge(); // By this point, the node should have all the inputs it needs to render correctly - NodeGlobals globals = GenerateGlobals(video_params_, range); + NodeGlobals globals = GenerateGlobals(video_params_, audio_params_, range); n->Value(row, globals, &table); // `transform_now_` is the next node in the path that needs to be traversed. It only ever goes diff --git a/app/node/traverser.h b/app/node/traverser.h index cb44bfc44..e34a708b5 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -54,10 +54,10 @@ public: void Transform(QTransform *transform, const Node *start, const Node *end, const TimeRange &range); - static NodeGlobals GenerateGlobals(const VideoParams ¶ms, const TimeRange &time); - static NodeGlobals GenerateGlobals(const VideoParams ¶ms, const rational &time) + static NodeGlobals GenerateGlobals(const VideoParams &vparams, const AudioParams &aparams, const TimeRange &time); + static NodeGlobals GenerateGlobals(const VideoParams &vparams, const AudioParams &aparams, const rational &time) { - return GenerateGlobals(params, TimeRange(time, time + params.frame_rate_as_time_base())); + return GenerateGlobals(vparams, aparams, TimeRange(time, time + vparams.frame_rate_as_time_base())); } const VideoParams& GetCacheVideoParams() const diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index e70fb7387..d45955f9f 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -1678,7 +1678,13 @@ void ViewerWidget::UpdateRendererVideoParameters() void ViewerWidget::UpdateRendererAudioParameters() { + AudioParams ap = GetConnectedNode()->GetAudioParams(); + UpdateAudioProcessor(); + + foreach (ViewerDisplayWidget *dw, playback_devices_) { + dw->SetAudioParams(ap); + } } void ViewerWidget::SetZoomFromMenu(QAction *action) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index c3a811fd3..bd1d8bc59 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -191,6 +191,15 @@ void ViewerDisplayWidget::SetVideoParams(const VideoParams ¶ms) } } +void ViewerDisplayWidget::SetAudioParams(const AudioParams ¶ms) +{ + gizmo_audio_params_ = params; + + if (gizmos_) { + update(); + } +} + void ViewerDisplayWidget::SetTime(const rational &time) { time_ = time; @@ -437,7 +446,7 @@ void ViewerDisplayWidget::OnPaint() p.setWorldTransform(gizmo_last_draw_transform_); - gizmos_->UpdateGizmoPositions(gizmo_db_, NodeTraverser::GenerateGlobals(gizmo_params_, gizmo_draw_time_)); + gizmos_->UpdateGizmoPositions(gizmo_db_, NodeTraverser::GenerateGlobals(gizmo_params_, gizmo_audio_params_, gizmo_draw_time_)); foreach (NodeGizmo *gizmo, gizmos_->GetGizmos()) { if (gizmo->IsVisible()) { gizmo->Draw(&p); @@ -813,7 +822,7 @@ bool ViewerDisplayWidget::OnMousePress(QMouseEvent *event) // Handle gizmo click gizmo_start_drag_ = event->pos(); gizmo_last_drag_ = gizmo_start_drag_; - current_gizmo_->SetGlobals(NodeTraverser::GenerateGlobals(gizmo_params_, GenerateGizmoTime())); + current_gizmo_->SetGlobals(NodeTraverser::GenerateGlobals(gizmo_params_, gizmo_audio_params_, GenerateGizmoTime())); } else { diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 04e9f6e15..d11ef585a 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -74,8 +74,13 @@ public: void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin); void SetGizmos(Node* node); + const VideoParams &GetVideoParams() const { return gizmo_params_; } void SetVideoParams(const VideoParams ¶ms); + + const AudioParams &GetAudioParams() const { return gizmo_audio_params_; } + void SetAudioParams(const AudioParams &p); + void SetTime(const rational& time); void SetSubtitleTracks(Sequence *list); @@ -343,6 +348,7 @@ private: Node* gizmos_; NodeValueRow gizmo_db_; VideoParams gizmo_params_; + AudioParams gizmo_audio_params_; QPoint gizmo_start_drag_; QPoint gizmo_last_drag_; TimeRange gizmo_draw_time_;