diff --git a/OpenUtau.Core/Util/Preferences.cs b/OpenUtau.Core/Util/Preferences.cs index 1baedf258..52e0a2262 100644 --- a/OpenUtau.Core/Util/Preferences.cs +++ b/OpenUtau.Core/Util/Preferences.cs @@ -133,6 +133,7 @@ public class SerializablePreferences { public bool ShowTips = true; public int Theme; public bool PenPlusDefault = false; + public bool OverwritePitchDrawTool = false; public int DegreeStyle; public bool UseTrackColor = false; public bool ClearCacheOnQuit = false; diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml index cccdafb0b..90a6778aa 100644 --- a/OpenUtau/Strings/Strings.axaml +++ b/OpenUtau/Strings/Strings.axaml @@ -123,9 +123,11 @@ Pitch Points Vibrato Expressions + Draw Pitch Tool to overwrite vibrato or MOD+ Paste Redo Select All + Tool Options Undo File Exit diff --git a/OpenUtau/Strings/Strings.ja-JP.axaml b/OpenUtau/Strings/Strings.ja-JP.axaml index 8e66086f4..505f1c05f 100644 --- a/OpenUtau/Strings/Strings.ja-JP.axaml +++ b/OpenUtau/Strings/Strings.ja-JP.axaml @@ -123,9 +123,11 @@ ピッチ点 ビブラート 表情 + ピッチ描画ツールでビブラートやMOD+を上書きする 貼り付け やり直す 全て選択 + ツールオプション 元に戻す ファイル OpenUTAUを終了 diff --git a/OpenUtau/ViewModels/NotesViewModelHitTest.cs b/OpenUtau/ViewModels/NotesViewModelHitTest.cs index 65cda3465..9cf8a9e9e 100644 --- a/OpenUtau/ViewModels/NotesViewModelHitTest.cs +++ b/OpenUtau/ViewModels/NotesViewModelHitTest.cs @@ -5,6 +5,7 @@ using OpenUtau.App.Controls; using OpenUtau.Core; using OpenUtau.Core.Ustx; +using OpenUtau.Core.Util; namespace OpenUtau.App.ViewModels { public struct NoteHitInfo { @@ -200,22 +201,40 @@ public PitchPointHitInfo HitTestPitchPoint(Point point) { return null; } double tick = viewModel.PointToTick(point); - var note = viewModel.Part.notes.FirstOrDefault(n => n.End >= tick); - if (note == null && viewModel.Part.notes.Count > 0) { - note = viewModel.Part.notes.Last(); - } - if (note == null) { - return null; - } - double pitch = note.tone * 100; - pitch += note.pitch.Sample(viewModel.Project, viewModel.Part, note, tick) ?? 0; - if (note.Next != null && note.Next.position == note.End) { - double? delta = note.Next.pitch.Sample(viewModel.Project, viewModel.Part, note.Next, tick); - if (delta != null) { - pitch += delta.Value + note.Next.tone * 100 - note.tone * 100; + + if (Preferences.Default.OverwritePitchDrawTool) { + if (viewModel.Part.renderPhrases.Count == 0) { + return null; + } + var phrase = viewModel.Part.renderPhrases.FirstOrDefault(p => p.position - p.leading >= tick); + if (phrase == null) { + phrase = viewModel.Part.renderPhrases.Last(); + } + if (phrase == null || phrase.pitchesBeforeDeviation.Length == 0) { + return null; + } + var curve = phrase.pitchesBeforeDeviation; + var pitchIndex = (int)Math.Round((tick - phrase.position + phrase.leading) / 5); + pitchIndex = Math.Clamp(pitchIndex, 0, curve.Length - 1); + return curve[pitchIndex]; + } else { + var note = viewModel.Part.notes.FirstOrDefault(n => n.End >= tick); + if (note == null && viewModel.Part.notes.Count > 0) { + note = viewModel.Part.notes.Last(); + } + if (note == null) { + return null; + } + double pitch = note.tone * 100; + pitch += note.pitch.Sample(viewModel.Project, viewModel.Part, note, tick) ?? 0; + if (note.Next != null && note.Next.position == note.End) { + double? delta = note.Next.pitch.Sample(viewModel.Project, viewModel.Part, note.Next, tick); + if (delta != null) { + pitch += delta.Value + note.Next.tone * 100 - note.tone * 100; + } } + return pitch; } - return pitch; } public VibratoHitInfo HitTestVibrato(Point mousePos) { diff --git a/OpenUtau/ViewModels/PianoRollViewModel.cs b/OpenUtau/ViewModels/PianoRollViewModel.cs index 3d43c524c..01e0462bd 100644 --- a/OpenUtau/ViewModels/PianoRollViewModel.cs +++ b/OpenUtau/ViewModels/PianoRollViewModel.cs @@ -51,6 +51,7 @@ public class PianoRollViewModel : ViewModelBase, ICmdSubscriber { public bool LockPitchPoints { get => Preferences.Default.LockUnselectedNotesPitch; } public bool LockVibrato { get => Preferences.Default.LockUnselectedNotesVibrato; } public bool LockExpressions { get => Preferences.Default.LockUnselectedNotesExpressions; } + public bool OverwritePitchDrawTool { get => Preferences.Default.OverwritePitchDrawTool; } public bool ShowPortrait { get => Preferences.Default.ShowPortrait; } public bool ShowIcon { get => Preferences.Default.ShowIcon; } public bool ShowGhostNotes { get => Preferences.Default.ShowGhostNotes; } diff --git a/OpenUtau/Views/PianoRollWindow.axaml b/OpenUtau/Views/PianoRollWindow.axaml index 11a4246a5..3ae57629d 100644 --- a/OpenUtau/Views/PianoRollWindow.axaml +++ b/OpenUtau/Views/PianoRollWindow.axaml @@ -225,6 +225,13 @@ + + + + + + + diff --git a/OpenUtau/Views/PianoRollWindow.axaml.cs b/OpenUtau/Views/PianoRollWindow.axaml.cs index f240c4468..b38c1e708 100644 --- a/OpenUtau/Views/PianoRollWindow.axaml.cs +++ b/OpenUtau/Views/PianoRollWindow.axaml.cs @@ -102,6 +102,11 @@ void OnMenuLockExpressions(object sender, RoutedEventArgs args) { Preferences.Save(); ViewModel.RaisePropertyChanged(nameof(ViewModel.LockExpressions)); } + void OnMenuOverwritePitchDrawTool(object sender, RoutedEventArgs args) { + Preferences.Default.OverwritePitchDrawTool = !Preferences.Default.OverwritePitchDrawTool; + Preferences.Save(); + ViewModel.RaisePropertyChanged(nameof(ViewModel.OverwritePitchDrawTool)); + } // View menu void OnMenuShowPortrait(object sender, RoutedEventArgs args) {