diff --git a/OpenUtau/ViewModels/NotesViewModel.cs b/OpenUtau/ViewModels/NotesViewModel.cs index c291fdd20..bb1775fa9 100644 --- a/OpenUtau/ViewModels/NotesViewModel.cs +++ b/OpenUtau/ViewModels/NotesViewModel.cs @@ -53,6 +53,7 @@ public class NotesViewModel : ViewModelBase, ICmdSubscriber { [Reactive] public bool PenPlusTool { get; set; } [Reactive] public bool EraserTool { get; set; } [Reactive] public bool DrawPitchTool { get; set; } + [Reactive] public bool DrawLinePitchTool { get; set; } [Reactive] public bool OverwritePitchTool { get; set; } [Reactive] public bool KnifeTool { get; set; } public ReactiveCommand SelectToolCommand { get; } @@ -204,6 +205,7 @@ public NotesViewModel() { } EraserTool = false; DrawPitchTool = false; + DrawLinePitchTool = false; OverwritePitchTool = false; KnifeTool = false; SelectToolCommand = ReactiveCommand.Create(index => { @@ -212,6 +214,7 @@ public NotesViewModel() { PenPlusTool = index == "2+"; EraserTool = index == "3"; DrawPitchTool = index == "4"; + DrawLinePitchTool = index == "4++"; OverwritePitchTool = index == "4+"; KnifeTool = index == "5"; }); diff --git a/OpenUtau/Views/NoteEditStates.cs b/OpenUtau/Views/NoteEditStates.cs index 34029e27b..c906a1ab6 100644 --- a/OpenUtau/Views/NoteEditStates.cs +++ b/OpenUtau/Views/NoteEditStates.cs @@ -413,7 +413,7 @@ public override void Begin(IPointer pointer, Point point) { if (newNote == null) { return; } - + DocManager.Inst.ExecuteCmd(new ChangeNoteLyricCommand(part, newNote, "+")); } @@ -436,8 +436,8 @@ public override void Update(IPointer pointer, Point point) { maxNegDelta = (int)Math.Floor((double)maxNegDelta / snapUnit) * snapUnit; } - int maxNoteTicks = (notesVm.IsSnapOn && snapUnit > 0) - ? (oldDur-1) / snapUnit * snapUnit + int maxNoteTicks = (notesVm.IsSnapOn && snapUnit > 0) + ? (oldDur-1) / snapUnit * snapUnit : oldDur - 15; int maxDelta = maxNoteTicks - note.duration; @@ -1107,6 +1107,50 @@ public override void Update(IPointer pointer, Point point) { } } + class DrawLinePitchState : NoteEditState { + protected override bool ShowValueTip => false; + double? firstPitch; + Point firstPoint; + double? lastPitch; + Point lastPoint; + public DrawLinePitchState( + Control control, + PianoRollViewModel vm, + IValueTip valueTip) : base(control, vm, valueTip) { } + public override void Begin(IPointer pointer, Point point) { + base.Begin(pointer, point); + int tick = vm.NotesViewModel.PointToTick(point); + var samplePoint = vm.NotesViewModel.TickToneToPoint( + (int)Math.Round(tick / 5.0) * 5, + vm.NotesViewModel.PointToToneDouble(point)); + firstPitch = vm.NotesViewModel.HitTest.SamplePitch(samplePoint); + firstPoint = point; + lastPoint = point; + } + public override void Update(IPointer pointer, Point point) { + int tick = vm.NotesViewModel.PointToTick(point); + var samplePoint = vm.NotesViewModel.TickToneToPoint( + (int)Math.Round(tick / 5.0) * 5, + vm.NotesViewModel.PointToToneDouble(point)); + double? pitch = vm.NotesViewModel.HitTest.SamplePitch(samplePoint); + if (pitch == null || vm.NotesViewModel.Part == null) { + return; + } + double tone = vm.NotesViewModel.PointToToneDouble(point); + DocManager.Inst.ExecuteCmd(new SetCurveCommand( + vm.NotesViewModel.Project, + vm.NotesViewModel.Part, + Core.Format.Ustx.PITD, + vm.NotesViewModel.PointToTick(lastPitch == null ? point : lastPoint), + (int)Math.Round(tone * 100 - (lastPitch ?? pitch.Value)), + vm.NotesViewModel.PointToTick(firstPoint), + (int)Math.Round(tone * 100 - (firstPitch == null ? pitch.Value : firstPitch.Value)) + )); + lastPitch = pitch; + lastPoint = point; + } + } + class OverwritePitchState : NoteEditState { protected override bool ShowValueTip => false; double? lastPitch; diff --git a/OpenUtau/Views/PianoRollWindow.axaml b/OpenUtau/Views/PianoRollWindow.axaml index 0959512da..d7c2a7854 100644 --- a/OpenUtau/Views/PianoRollWindow.axaml +++ b/OpenUtau/Views/PianoRollWindow.axaml @@ -195,7 +195,7 @@ - + @@ -227,7 +227,7 @@ - + @@ -421,6 +421,21 @@ + + + + + + + + + + + + ", e); DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx)); } - + }); ViewModel.NoteBatchEdits.AddRange(new List() { new LoadRenderedPitch(), @@ -218,7 +218,7 @@ void OnMenuShowGhostNotes(object sender, RoutedEventArgs args) { Preferences.Save(); ViewModel.RaisePropertyChanged(nameof(ViewModel.ShowGhostNotes)); MessageBus.Current.SendMessage(new PianorollRefreshEvent("Part")); - + } void OnMenuUseTrackColor(object sender, RoutedEventArgs args) { Preferences.Default.UseTrackColor = !Preferences.Default.UseTrackColor; @@ -497,7 +497,7 @@ public void NotesCanvasPointerPressed(object sender, PointerPressedEventArgs arg } private void NotesCanvasLeftPointerPressed(Control control, PointerPoint point, PointerPressedEventArgs args) { - if (ViewModel.NotesViewModel.DrawPitchTool || ViewModel.NotesViewModel.OverwritePitchTool) { + if (ViewModel.NotesViewModel.DrawPitchTool || ViewModel.NotesViewModel.DrawLinePitchTool || ViewModel.NotesViewModel.OverwritePitchTool) { ViewModel.NotesViewModel.DeselectNotes(); if (args.KeyModifiers == KeyModifiers.Alt) { editState = new SmoothenPitchState(control, ViewModel, this); @@ -505,6 +505,8 @@ private void NotesCanvasLeftPointerPressed(Control control, PointerPoint point, } else if (args.KeyModifiers != cmdKey) { if (ViewModel.NotesViewModel.DrawPitchTool) { editState = new DrawPitchState(control, ViewModel, this); + } else if (ViewModel.NotesViewModel.DrawLinePitchTool) { + editState = new DrawLinePitchState(control, ViewModel, this); } else { editState = new OverwritePitchState(control, ViewModel, this); } @@ -584,6 +586,7 @@ private void NotesCanvasLeftPointerPressed(Control control, PointerPoint point, ViewModel.NotesViewModel.PenTool && args.KeyModifiers == cmdKey || ViewModel.NotesViewModel.PenPlusTool && args.KeyModifiers == cmdKey || ViewModel.NotesViewModel.DrawPitchTool && args.KeyModifiers == cmdKey || + ViewModel.NotesViewModel.DrawLinePitchTool && args.KeyModifiers == cmdKey || ViewModel.NotesViewModel.OverwritePitchTool && args.KeyModifiers == cmdKey) { if (args.KeyModifiers == KeyModifiers.None) { // New selection. @@ -608,7 +611,7 @@ private void NotesCanvasLeftPointerPressed(Control control, PointerPoint point, private void NotesCanvasRightPointerPressed(Control control, PointerPoint point, PointerPressedEventArgs args) { var selectedNotes = ViewModel.NotesViewModel.Selection.ToList(); - if (ViewModel.NotesViewModel.DrawPitchTool || ViewModel.NotesViewModel.OverwritePitchTool) { + if (ViewModel.NotesViewModel.DrawPitchTool || ViewModel.NotesViewModel.DrawLinePitchTool || ViewModel.NotesViewModel.OverwritePitchTool) { editState = new ResetPitchState(control, ViewModel, this); return; } @@ -729,7 +732,7 @@ public void NotesCanvasPointerMoved(object sender, PointerEventArgs args) { if (ViewModel?.NotesViewModel?.HitTest == null) { return; } - if(((ViewModel.NotesViewModel.DrawPitchTool || ViewModel.NotesViewModel.OverwritePitchTool) && args.KeyModifiers != cmdKey) || ViewModel.NotesViewModel.EraserTool) { + if(((ViewModel.NotesViewModel.DrawPitchTool || ViewModel.NotesViewModel.DrawLinePitchTool || ViewModel.NotesViewModel.OverwritePitchTool) && args.KeyModifiers != cmdKey) || ViewModel.NotesViewModel.EraserTool) { Cursor = null; return; }