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) {