From 234176f278ea6dfd141966b8ff9edf48e43fee91 Mon Sep 17 00:00:00 2001 From: cadlaxa Date: Fri, 14 Mar 2025 20:50:53 +0800 Subject: [PATCH 1/3] Removed 0.9f limit of Preutter delta --- OpenUtau.Core/Ustx/UPhoneme.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenUtau.Core/Ustx/UPhoneme.cs b/OpenUtau.Core/Ustx/UPhoneme.cs index 6c46e5016..dbbd53795 100644 --- a/OpenUtau.Core/Ustx/UPhoneme.cs +++ b/OpenUtau.Core/Ustx/UPhoneme.cs @@ -118,9 +118,9 @@ void ValidateOverlap(UProject project, UTrack track, UPart part, UNote note) { autoPreutter = maxPreutter; autoOverlap *= ratio; } - if (autoPreutter > prevDur * 0.9f && overlapped) { - double delta = autoPreutter - prevDur * 0.9f; - autoPreutter -= delta; + if (autoPreutter > prevDur) { + double delta = autoPreutter - prevDur; + autoPreutter = prevDur; // Ensure autoPreutter doesn't exceed 100% of prevDur autoOverlap -= delta; } } From 916132fa2897b8d17c35e582acdbeb41bff57fd0 Mon Sep 17 00:00:00 2001 From: Anjo <87346264+AnAndroNerd@users.noreply.github.com> Date: Fri, 20 Jun 2025 00:26:07 -0700 Subject: [PATCH 2/3] Update UPhoneme.cs --- OpenUtau.Core/Ustx/UPhoneme.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenUtau.Core/Ustx/UPhoneme.cs b/OpenUtau.Core/Ustx/UPhoneme.cs index 577a6d4ca..f1e186572 100644 --- a/OpenUtau.Core/Ustx/UPhoneme.cs +++ b/OpenUtau.Core/Ustx/UPhoneme.cs @@ -118,7 +118,7 @@ void ValidateOverlap(UProject project, UTrack track, UPart part, UNote note) { autoPreutter = maxPreutter; autoOverlap *= ratio; } - if (autoPreutter > prevDur) { + if (autoPreutter > prevDur && overlapped) { double delta = autoPreutter - prevDur; autoPreutter = prevDur; // Ensure autoPreutter doesn't exceed 100% of prevDur autoOverlap -= delta; From 937cabee7bdc638955621a12f178697c919f3a59 Mon Sep 17 00:00:00 2001 From: cadlaxa Date: Thu, 21 May 2026 10:52:09 +0800 Subject: [PATCH 3/3] Envelope inversion and overlap crushing for negative preutterances --- OpenUtau.Core/Ustx/UPhoneme.cs | 45 +++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/OpenUtau.Core/Ustx/UPhoneme.cs b/OpenUtau.Core/Ustx/UPhoneme.cs index 4c6dcbe46..64ec6cc96 100644 --- a/OpenUtau.Core/Ustx/UPhoneme.cs +++ b/OpenUtau.Core/Ustx/UPhoneme.cs @@ -109,35 +109,58 @@ void ValidateOverlap(UProject project, UTrack track, UPart part, UNote note) { overlapped = false; tailIntrude = 0; tailOverlap = 0; - if (Prev != null) { double gapMs = PositionMs - Prev.EndMs; - double prevDur = Prev.DurationMs; + double prevAttackEnd = Math.Max(0d, -Prev.preutter + Math.Max(Prev.overlap, 5d)); + double prevUsableDur = Math.Max(0d, Prev.DurationMs - prevAttackEnd); double maxPreutter = autoPreutter; if (gapMs <= 0) { overlapped = true; - if (autoPreutter - autoOverlap > prevDur * 0.5f) { - maxPreutter = prevDur * 0.5f / (autoPreutter - autoOverlap) * autoPreutter; + // Scale down if the current note intrudes into more than 50% of the USABLE space + if (autoPreutter > 0 && autoPreutter - autoOverlap > prevUsableDur * 0.5f) { + maxPreutter = prevUsableDur * 0.5f / (autoPreutter - autoOverlap) * autoPreutter; } } else if (gapMs < autoPreutter) { maxPreutter = gapMs; } - if (autoPreutter > maxPreutter) { + if (autoPreutter > maxPreutter && autoPreutter > 0) { double ratio = maxPreutter / autoPreutter; autoPreutter = maxPreutter; autoOverlap *= ratio; } - if (autoPreutter > prevDur && overlapped) { - double delta = autoPreutter - prevDur; - autoPreutter = prevDur; // Ensure autoPreutter doesn't exceed 100% of prevDur + // HARD WALL: Prevent the next note from EVER crossing Prev's top-left point + if (autoPreutter > prevUsableDur && overlapped && autoPreutter > 0) { + double delta = autoPreutter - prevUsableDur; + autoPreutter = prevUsableDur; autoOverlap -= delta; } } - preutter = Math.Max(0, autoPreutter + (preutterDelta ?? 0)); + preutter = autoPreutter + (preutterDelta ?? 0); overlap = autoOverlap + (overlapDelta ?? 0); + // Prevent self-destruction of this note if it has a negative preutter + if (preutter < 0) { + double maxDelay = DurationMs * 0.5; // Reserve at least 50% for its own tail + if (-preutter > maxDelay) { + double ratio = maxDelay / -preutter; + preutter = -maxDelay; + overlap *= ratio; + } + } if (Prev != null) { - Prev.tailIntrude = overlapped ? Math.Max(preutter, preutter - overlap) : 0; - Prev.tailOverlap = overlapped ? Math.Max(overlap, 0) : 0; + if (overlapped) { + if (preutter < 0) { + // Dynamic pushback: pass negative preutter natively to push the tail forward + Prev.tailIntrude = preutter; + Prev.tailOverlap = Math.Max(overlap, 5d); + } else { + // Standard positive preutter logic + Prev.tailIntrude = Math.Max(0d, Math.Max(preutter, preutter - overlap)); + Prev.tailOverlap = Math.Max(overlap, 0d); + } + } else { + Prev.tailIntrude = 0d; + Prev.tailOverlap = 0d; + } Prev.ValidateEnvelope(project, track, Prev.Parent); } }