From 2d44dc3c8ce02cba2323f4270ad7961c62a82802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E5=88=9A?= <1219318552@qq.com> Date: Sat, 7 Dec 2024 00:53:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=92=AD=E6=94=BE=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=9E=E5=88=B0=E5=BC=80=E5=A4=B4=E4=B8=8E?= =?UTF-8?q?=E8=B7=B3=E5=88=B0=E7=BB=93=E5=B0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TuneLab/Audio/AudioEngine.cs | 1 + TuneLab/Data/ITempoManager.cs | 2 +- TuneLab/GUI/Assets.cs | 2 ++ TuneLab/UI/MainWindow/Editor/Editor.cs | 22 +++++++++++++++++++ .../Editor/FunctionBar/FunctionBar.cs | 20 +++++++++++++++-- .../Editor/TimelineView/TimelineView.cs | 5 +++++ .../TimelineView/TimelineViewOperation.cs | 3 +++ 7 files changed, 52 insertions(+), 3 deletions(-) diff --git a/TuneLab/Audio/AudioEngine.cs b/TuneLab/Audio/AudioEngine.cs index f639de5..75221cb 100644 --- a/TuneLab/Audio/AudioEngine.cs +++ b/TuneLab/Audio/AudioEngine.cs @@ -21,6 +21,7 @@ internal static class AudioEngine public static int SamplingRate => mAudioProvider!.SamplingRate; public static double CurrentTime => mAudioProvider!.CurrentTime; public static double MasterGain { get; set; } = 0; + public static double EndTime => AudioGraph.EndTime; public static void Init(IAudioPlaybackHandler playbackHandler) { diff --git a/TuneLab/Data/ITempoManager.cs b/TuneLab/Data/ITempoManager.cs index 6221616..4dcbb29 100644 --- a/TuneLab/Data/ITempoManager.cs +++ b/TuneLab/Data/ITempoManager.cs @@ -14,7 +14,7 @@ namespace TuneLab.Data; internal interface ITempoManager : IDataObject> { - IProject Project { get; } + IProject Project { get; } // TODO: Remove this IReadOnlyList Tempos { get; } int AddTempo(double pos, double bpm); void RemoveTempoAt(int index); diff --git a/TuneLab/GUI/Assets.cs b/TuneLab/GUI/Assets.cs index 425cdf3..9ab5a80 100644 --- a/TuneLab/GUI/Assets.cs +++ b/TuneLab/GUI/Assets.cs @@ -34,6 +34,8 @@ internal static class Assets public static SvgIcon Hyphen = new("\r\n\r\n"); public static SvgIcon Anchor = new("\r\n\r\n\r\n\r\n\r\n\r\n"); public static SvgIcon Pause = new("\r\n\r\n\r\n"); + public static SvgIcon GotoStart = new("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"); + public static SvgIcon GotoEnd = new("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"); public static SvgIcon None = new(""); public static FontFamily NotoMono = new FontFamily("NotoMono"); diff --git a/TuneLab/UI/MainWindow/Editor/Editor.cs b/TuneLab/UI/MainWindow/Editor/Editor.cs index a3aeff2..276f802 100644 --- a/TuneLab/UI/MainWindow/Editor/Editor.cs +++ b/TuneLab/UI/MainWindow/Editor/Editor.cs @@ -75,6 +75,28 @@ public Editor() mFunctionBar.Moved += y => TrackWindowHeight = y; mFunctionBar.CollapsePropertiesAsked += show => mRightSideBar.IsVisible = show; + mFunctionBar.GotoStartAsked += () => + { + var startTime = 0; + AudioEngine.Seek(startTime); + if (Project == null) + return; + + var startTick = Project.TempoManager.GetTick(startTime); + mTrackWindow.TickAxis.AnimateMoveTickToX(startTick, 0); + mPianoWindow.TickAxis.AnimateMoveTickToX(startTick, 0); + }; + mFunctionBar.GotoEndAsked += () => + { + var endTime = AudioEngine.EndTime; + AudioEngine.Seek(endTime); + if (Project == null) + return; + + var endTick = Project.TempoManager.GetTick(endTime); + mTrackWindow.TickAxis.AnimateMoveTickToX(endTick, mTrackWindow.TickAxis.ViewLength); + mPianoWindow.TickAxis.AnimateMoveTickToX(endTick, mPianoWindow.TickAxis.ViewLength); + }; ProjectProvider.ObjectWillChange.Subscribe(OnProjectWillChange, s); ProjectProvider.ObjectChanged.Subscribe(OnProjectChanged, s); ProjectProvider.When(project => project.Tracks.Any(track => track.Parts.ItemRemoved)).Subscribe(part => { if (part == mEditingPart) SwitchEditingPart(null); }); diff --git a/TuneLab/UI/MainWindow/Editor/FunctionBar/FunctionBar.cs b/TuneLab/UI/MainWindow/Editor/FunctionBar/FunctionBar.cs index d2fbd10..b2e672c 100644 --- a/TuneLab/UI/MainWindow/Editor/FunctionBar/FunctionBar.cs +++ b/TuneLab/UI/MainWindow/Editor/FunctionBar/FunctionBar.cs @@ -22,14 +22,16 @@ internal class FunctionBar : LayerPanel { public event Action? Moved; public event Action? CollapsePropertiesAsked; + public event Action? GotoStartAsked; + public event Action? GotoEndAsked; public INotifiableProperty PlayScrollTarget => mDependency.PlayScrollTarget; public IActionEvent QuantizationChanged => mQuantizationChanged; public interface IDependency { - public INotifiableProperty PianoTool { get; } - public INotifiableProperty PlayScrollTarget { get; } + INotifiableProperty PianoTool { get; } + INotifiableProperty PlayScrollTarget { get; } } public FunctionBar(IDependency dependency) @@ -79,6 +81,20 @@ void SetupToolTip(Control toggleButton,string ToolTipText) SetupToolTip(autoPageButton, "Auto Scroll".Tr(this)); audioControlPanel.Children.Add(autoPageButton); + + var gotoStartButton = new GUI.Components.Button() { Width = 36, Height = 36 } + .AddContent(new() { Item = new BorderItem() { CornerRadius = 4 }, ColorSet = new() { HoveredColor = hoverBack, PressedColor = hoverBack } }) + .AddContent(new() { Item = new IconItem() { Icon = Assets.GotoStart }, ColorSet = new() { Color = Style.LIGHT_WHITE.Opacity(0.5) } }); + SetupToolTip(gotoStartButton, "Go to Start".Tr(this)); + gotoStartButton.Clicked += () => { GotoStartAsked?.Invoke(); }; + audioControlPanel.Children.Add(gotoStartButton); + + var gotoEndButton = new GUI.Components.Button() { Width = 36, Height = 36 } + .AddContent(new() { Item = new BorderItem() { CornerRadius = 4 }, ColorSet = new() { HoveredColor = hoverBack, PressedColor = hoverBack } }) + .AddContent(new() { Item = new IconItem() { Icon = Assets.GotoEnd }, ColorSet = new() { Color = Style.LIGHT_WHITE.Opacity(0.5) } }); + SetupToolTip(gotoEndButton, "Go to End".Tr(this)); + gotoEndButton.Clicked += () => { GotoEndAsked?.Invoke(); }; + audioControlPanel.Children.Add(gotoEndButton); } dockPanel.AddDock(audioControlPanel, Dock.Left); diff --git a/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineView.cs b/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineView.cs index 8499690..029e700 100644 --- a/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineView.cs +++ b/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineView.cs @@ -58,6 +58,7 @@ public TimelineView(IDependency dependency) { if (AudioEngine.IsPlaying) { + // Auto Page if (mDependency.PlayScrollTarget.Value == PlayScrollTarget.None) return; @@ -87,9 +88,13 @@ public TimelineView(IDependency dependency) else { mFixedPlayheadX = TickAxis.Tick2X(Playhead.Pos); + if (!mIsSeeking) + return; + if (mState == State.Seeking) return; + // Move view if (Playhead.Pos < TickAxis.MinVisibleTick) { TickAxis.MoveTickToX(Playhead.Pos, 0); diff --git a/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineViewOperation.cs b/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineViewOperation.cs index 833fb74..c012b8d 100644 --- a/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineViewOperation.cs +++ b/TuneLab/UI/MainWindow/Editor/TimelineView/TimelineViewOperation.cs @@ -230,6 +230,7 @@ public void Down(double x) if (State != State.None) return; + mIsSeeking = true; State = State.Seeking; mIsPlaying = AudioEngine.IsPlaying; if (mIsPlaying) AudioEngine.Pause(); @@ -263,6 +264,7 @@ public void Up() if (!IsOperating) return; + mIsSeeking = false; State = State.None; TimelineView.TickAxis.StopMoveAnimation(); if (mIsPlaying) AudioEngine.Play(); @@ -272,6 +274,7 @@ public void Up() } readonly SeekOperation mSeekOperation; + static bool mIsSeeking = false; class TempoMovingOperation(TimelineView timelineView) : Operation(timelineView) {