From 42d79a1a3b7941c98125ac6c1f79bba9fcaaa16a Mon Sep 17 00:00:00 2001 From: Maiko Date: Thu, 25 Jun 2026 02:32:20 +0900 Subject: [PATCH 1/2] Apply track settings (vel, clr, tone shift, alt) to all phonemizers --- OpenUtau.Core/Api/Phonemizer.cs | 50 +++++++++++++++++-- OpenUtau.Core/BaseChinesePhonemizer.cs | 1 + OpenUtau.Core/DefaultPhonemizer.cs | 6 ++- .../Phonemizers/DiffSingerKoreanPhonemizer.cs | 3 +- OpenUtau.Core/Enunu/EnunuKoreanPhonemizer.cs | 1 + OpenUtau.Core/Enunu/EnunuPhonemizer.cs | 3 +- OpenUtau.Core/MachineLearningPhonemizer.cs | 1 + OpenUtau.Core/Ustx/UNote.cs | 2 +- OpenUtau.Core/Vogen/VogenBasePhonemizer.cs | 1 + .../Phonemizers/VoicevoxPhonemizer.cs | 2 +- .../BaseKoreanPhonemizer.cs | 8 +-- .../CantoneseSyoPhonemizer.cs | 28 ++++------- .../ChineseCVVCPhonemizer.cs | 37 +++++++------- .../ChineseCVVPhonemizer.cs | 1 + .../ChineseCVVPlusPhonemizer.cs | 30 +++++------ .../EnunuOnnx/EnunuOnnxPhonemizer.cs | 1 + .../ItalianCVVCPhonemizer.cs | 10 ++-- .../JapaneseCVVCPhonemizer.cs | 20 +++++--- .../JapanesePresampPhonemizer.cs | 38 ++++++-------- .../JapaneseVCVPhonemizer.cs | 8 +-- OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs | 21 ++++---- .../KoreanCBNNPhonemizer.cs | 4 +- .../KoreanCVCCVPhonemizer.cs | 1 + .../KoreanCVCPhonemizer.cs | 19 +++---- OpenUtau.Plugin.Builtin/KoreanCVPhonemizer.cs | 4 +- ...reanCVVCStandardPronunciationPhonemizer.cs | 4 +- .../KoreanVCVPhonemizer.cs | 19 +++---- .../PhonemeBasedPhonemizer.cs | 12 ++--- .../PresampSamplePhonemizer.cs | 12 ++--- .../SyllableBasedPhonemizer.cs | 12 ++--- OpenUtau.Plugin.Builtin/ThaiVCCVPhonemizer.cs | 4 +- .../TurkishCVVCPhonemizer.cs | 18 ++++--- .../VietnameseCVVCPhonemizer.cs | 6 +-- .../VietnameseVCVPhonemizer.cs | 6 +-- .../VietnameseVINAPhonemizer.cs | 6 +-- 35 files changed, 227 insertions(+), 172 deletions(-) diff --git a/OpenUtau.Core/Api/Phonemizer.cs b/OpenUtau.Core/Api/Phonemizer.cs index 6f283c360..d54e6f270 100644 --- a/OpenUtau.Core/Api/Phonemizer.cs +++ b/OpenUtau.Core/Api/Phonemizer.cs @@ -86,7 +86,7 @@ public struct PhonemeAttributes { /// /// Tone shift. Shifts the note tone used for oto lookup. /// - public int toneShift; + public int? toneShift; /// /// Alternate index. The number suffix of duplicate aliases. /// @@ -94,7 +94,7 @@ public struct PhonemeAttributes { /// /// Voice color. /// - public string voiceColor; + public string? voiceColor; } public struct PhonemeExpression { @@ -176,7 +176,13 @@ public struct Result { /// public virtual bool LegacyMapping => false; - public virtual void SetUp(Note[][] notes, UProject project, UTrack track) { } + public UProject? project; + public UTrack? track; + + public virtual void SetUp(Note[][] notes, UProject project, UTrack track) { + this.project = project; + this.track = track; + } /// /// Phonemize a consecutive sequence of notes. This is the main logic of a phonemizer. @@ -259,6 +265,44 @@ protected Result MakeSimpleResult(string phoneme) { }; } + public double GetParentConsonantStretchRatio() { + if (project != null && track != null) { + if (track.TryGetExpDescriptor(project, Core.Format.Ustx.VEL, out var trackVEL)) { + return Math.Pow(2, 1.0 - trackVEL.CustomDefaultValue / 100.0); + } + } + return 1; + } + + public int GetParentToneShift() { + if (project != null && track != null) { + if (track.TryGetExpDescriptor(project, Core.Format.Ustx.SHFT, out var trackTS)) { + return (int)trackTS.CustomDefaultValue; + } + } + return 0; + } + + public int? GetParentAlternate() { + if (project != null && track != null) { + if (track.TryGetExpDescriptor(project, Core.Format.Ustx.ALT, out var trackAlt)) { + if (trackAlt.CustomDefaultValue != 0) { + return (int)trackAlt.CustomDefaultValue; + } + } + } + return null; + } + + public string GetParentVoiceColor() { + if (project != null && track != null) { + if (track.TryGetExpDescriptor(project, Core.Format.Ustx.CLR, out var trackCLR)) { + return track.VoiceColorExp.options[(int)trackCLR.CustomDefaultValue]; + } + } + return string.Empty; + } + /// /// Utility method to map a phoneme alias to proper pitch using prefixmap. /// For example, MapPhoneme("あ", 72, singer) may return "あC5". diff --git a/OpenUtau.Core/BaseChinesePhonemizer.cs b/OpenUtau.Core/BaseChinesePhonemizer.cs index d81c8038e..447e4ca27 100644 --- a/OpenUtau.Core/BaseChinesePhonemizer.cs +++ b/OpenUtau.Core/BaseChinesePhonemizer.cs @@ -44,6 +44,7 @@ public static void RomanizeNotes(Note[][] groups) { } public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); RomanizeNotes(groups); } } diff --git a/OpenUtau.Core/DefaultPhonemizer.cs b/OpenUtau.Core/DefaultPhonemizer.cs index 0eeba399e..2019356be 100644 --- a/OpenUtau.Core/DefaultPhonemizer.cs +++ b/OpenUtau.Core/DefaultPhonemizer.cs @@ -16,7 +16,11 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN // For this simple phonemizer, all these notes maps to a single phoneme. string alias = notes[0].lyric; var attr0 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - if (singer.TryGetMappedOto(notes[0].lyric, notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto)) { + string color = attr0.voiceColor ?? GetParentVoiceColor(); + int shift = attr0.toneShift ?? GetParentToneShift(); + int? alt = attr0.alternate ?? GetParentAlternate(); + + if (singer.TryGetMappedOto(notes[0].lyric + alt, notes[0].tone + shift, color, out var oto)) { alias = oto.Alias; } return new Result { diff --git a/OpenUtau.Core/DiffSinger/Phonemizers/DiffSingerKoreanPhonemizer.cs b/OpenUtau.Core/DiffSinger/Phonemizers/DiffSingerKoreanPhonemizer.cs index e28cd1d46..98bdb0df7 100644 --- a/OpenUtau.Core/DiffSinger/Phonemizers/DiffSingerKoreanPhonemizer.cs +++ b/OpenUtau.Core/DiffSinger/Phonemizers/DiffSingerKoreanPhonemizer.cs @@ -1,4 +1,4 @@ -using OpenUtau.Api; +using OpenUtau.Api; using OpenUtau.Core.Ustx; using System.Collections.Generic; using System.Linq; @@ -12,6 +12,7 @@ public class DiffSingerKoreanPhonemizer : DiffSingerBasePhonemizer public override string GetLangCode()=>"ko"; public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); if (groups.Length == 0) { return; } diff --git a/OpenUtau.Core/Enunu/EnunuKoreanPhonemizer.cs b/OpenUtau.Core/Enunu/EnunuKoreanPhonemizer.cs index 3103fea0e..4ae84b95c 100644 --- a/OpenUtau.Core/Enunu/EnunuKoreanPhonemizer.cs +++ b/OpenUtau.Core/Enunu/EnunuKoreanPhonemizer.cs @@ -395,6 +395,7 @@ public enum BatchimType{ Dictionary partResult = new Dictionary(); public override void SetUp(Note[][] notes, UProject project, UTrack track) { + base.SetUp(notes, project, track); partResult.Clear(); if (notes.Length == 0 || singer == null || !singer.Found) { return; diff --git a/OpenUtau.Core/Enunu/EnunuPhonemizer.cs b/OpenUtau.Core/Enunu/EnunuPhonemizer.cs index ac818c5fe..ca875afad 100644 --- a/OpenUtau.Core/Enunu/EnunuPhonemizer.cs +++ b/OpenUtau.Core/Enunu/EnunuPhonemizer.cs @@ -35,6 +35,7 @@ public override void SetSinger(USinger singer) { } public override void SetUp(Note[][] notes, UProject project, UTrack track) { + base.SetUp(notes, project, track); partResult.Clear(); if (notes.Length == 0 || singer == null || !singer.Found) { return; @@ -174,4 +175,4 @@ public override void CleanUp() { partResult.Clear(); } } -} \ No newline at end of file +} diff --git a/OpenUtau.Core/MachineLearningPhonemizer.cs b/OpenUtau.Core/MachineLearningPhonemizer.cs index 2ad4c2d75..519e001be 100644 --- a/OpenUtau.Core/MachineLearningPhonemizer.cs +++ b/OpenUtau.Core/MachineLearningPhonemizer.cs @@ -18,6 +18,7 @@ public abstract class MachineLearningPhonemizer : Phonemizer //groups is a two-dimensional array of Note, each Note[] represents a lyrical note and its following slur notes //Run phoneme timing model in sections to prevent butterfly effect public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); SetUpException = null; lastProcessPartException = null; partResult.Clear(); diff --git a/OpenUtau.Core/Ustx/UNote.cs b/OpenUtau.Core/Ustx/UNote.cs index b873e1850..45af0432c 100644 --- a/OpenUtau.Core/Ustx/UNote.cs +++ b/OpenUtau.Core/Ustx/UNote.cs @@ -139,7 +139,7 @@ internal Phonemizer.Note ToPhonemizerNote(UTrack track, UPart part) { attr.index = exp.index.Value; if (exp.abbr == Format.Ustx.VEL) { attr.consonantStretchRatio = Math.Pow(2, 1.0 - exp.value / 100.0); - } else if (exp.abbr == Format.Ustx.ALT) { + } else if (exp.abbr == Format.Ustx.ALT && exp.value != 0) { // 0 means no alt (nothing added) attr.alternate = (int)exp.value; } else if (exp.abbr == Format.Ustx.CLR && track.VoiceColorExp != null) { int optionIdx = (int)exp.value; diff --git a/OpenUtau.Core/Vogen/VogenBasePhonemizer.cs b/OpenUtau.Core/Vogen/VogenBasePhonemizer.cs index 747530f9a..9105d93b3 100644 --- a/OpenUtau.Core/Vogen/VogenBasePhonemizer.cs +++ b/OpenUtau.Core/Vogen/VogenBasePhonemizer.cs @@ -38,6 +38,7 @@ private void AddGroup(List phrase, Note[] group){ }); } public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); if (groups.Length == 0) { return; } diff --git a/OpenUtau.Core/Voicevox/Phonemizers/VoicevoxPhonemizer.cs b/OpenUtau.Core/Voicevox/Phonemizers/VoicevoxPhonemizer.cs index 2360fd669..3e93f7ab3 100644 --- a/OpenUtau.Core/Voicevox/Phonemizers/VoicevoxPhonemizer.cs +++ b/OpenUtau.Core/Voicevox/Phonemizers/VoicevoxPhonemizer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using OpenUtau.Api; using OpenUtau.Core.Ustx; @@ -17,6 +16,7 @@ public override void SetSinger(USinger singer) { } public override void SetUp(Note[][] notes, UProject project, UTrack track) { + base.SetUp(notes, project, track); partResult.Clear(); VoicevoxNote[] vNotes = new VoicevoxNote[notes.Length]; for (int i = 0; i < notes.Length; i++) { diff --git a/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs b/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs index 029394c33..6a8604293 100644 --- a/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs @@ -29,15 +29,15 @@ protected virtual bool additionalTest(string lyric) { return false; } public override void SetSinger(USinger singer) => this.singer = singer; - public static string? FindInOto(USinger singer, string phoneme, Note note, bool nullIfNotFound = false) { + public string? FindInOto(USinger singer, string phoneme, Note note, bool nullIfNotFound = false) { // 음소와 노트를 입력받고, 다음계 및 보이스컬러 에일리어스를 적용한다. // nullIfNotFound가 true이면 음소가 찾아지지 않을 때 음소가 아닌 null을 리턴한다. // nullIfNotFound가 false면 음소가 찾아지지 않을 때 그대로 음소를 반환 string phonemeToReturn; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - string color = attr.voiceColor ?? string.Empty; - int toneShift = 0; - int? alt = null; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); if (phoneme.Equals("")) {return phoneme;} if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var otoAlt)) { diff --git a/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs b/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs index dbbbc4d9f..4b90801b0 100644 --- a/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs @@ -71,6 +71,7 @@ static CantoneseSyoPhonemizer() { /// /// public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); JyutpingConversion.RomanizeNotes(groups); } public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevNeighbour, Note? nextNeighbour, Note[] prevNeighbours) { @@ -98,17 +99,6 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN string phoneme0 = lyric; - // Get color - string color = string.Empty; - int toneShift = 0; - int? alt = 0; - if (note.phonemeAttributes != null) { - var attr = note.phonemeAttributes.FirstOrDefault(attr0 => attr0.index == 0); - color = attr.voiceColor; - toneShift = attr.toneShift; - alt = attr.alternate; - } - string fin = $"{vowel} -"; // We will need to split the total duration for phonemes, so we compute it here. int totalDuration = notes.Sum(n => n.duration); @@ -316,17 +306,19 @@ public void SetUp(Note[][] groups) { private bool checkOtoUntilHit(List input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attrCheck => attrCheck.index == 0) ?? default; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, attr.voiceColor, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, attr.voiceColor, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } - string color = attr.voiceColor ?? ""; if (otos.Count > 0) { oto = otos.FirstOrDefault(oto => oto.IsColorMatch(color)); if (oto == null) { @@ -341,17 +333,19 @@ private bool checkOtoUntilHit(List input, Note note, out UOto oto) { private bool checkOtoUntilHitFinal(List input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attrCheck => attrCheck.index == 1) ?? default; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, attr.voiceColor, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, attr.voiceColor, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } - string color = attr.voiceColor ?? ""; if (otos.Count > 0) { oto = otos.FirstOrDefault(oto => oto.IsColorMatch(color)); if (oto != null) { diff --git a/OpenUtau.Plugin.Builtin/ChineseCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/ChineseCVVCPhonemizer.cs index 431f4b435..f27394a71 100644 --- a/OpenUtau.Plugin.Builtin/ChineseCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/ChineseCVVCPhonemizer.cs @@ -34,7 +34,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN var attr1 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 1) ?? default; var attr2 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 2) ?? default; if (lyric == "-" || lyric.ToLowerInvariant() == "r") { - if (singer.TryGetMappedOto($"{prevVowel} R", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto1)) { + if (singer.TryGetMappedOto($"{prevVowel} R", notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto1)) { return MakeSimpleResult(oto1.Alias); } return MakeSimpleResult($"{prevVowel} R"); @@ -42,8 +42,8 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN string currVowel = vowels.TryGetValue(lyric, out currVowel) ? currVowel : lyric; int totalDuration = notes.Sum(n => n.duration); // totalDuration of current note - if (singer.TryGetMappedOto($"{prevVowel} {lyric}", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto)) { - if (nextNeighbour == null && singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr1.toneShift, attr1.voiceColor, out var oto1)) { + if (singer.TryGetMappedOto($"{prevVowel} {lyric}", notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)) { + if (nextNeighbour == null && singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + (attr1.toneShift ?? GetParentToneShift()), attr1.voiceColor ?? GetParentVoiceColor(), out var oto1)) { // automatically add ending if present return new Result { phonemes = new Phoneme[] { @@ -61,7 +61,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } int vcLen = 120; int endTick = notes[^1].position + notes[^1].duration; - if (singer.TryGetMappedOto(lyric, notes[0].tone + attr1.toneShift, attr1.voiceColor, out var cvOto)) { + if (singer.TryGetMappedOto(lyric, notes[0].tone + (attr1.toneShift ?? GetParentToneShift()), attr1.voiceColor ?? GetParentVoiceColor(), out var cvOto)) { vcLen = -timeAxis.MsToTickAt(-cvOto.Preutter, endTick); if (cvOto.Overlap == 0 && vcLen < 120) { vcLen = Math.Min(120, vcLen * 2); // explosive consonant with short preutter. @@ -71,30 +71,30 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } - if (singer.TryGetMappedOto(lyric, notes[0].tone + attr0.toneShift, attr0.voiceColor, out var cvOtoSimple)) { + if (singer.TryGetMappedOto(lyric, notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var cvOtoSimple)) { lyric = cvOtoSimple.Alias; } var vcPhoneme = $"{prevVowel} {consonant}"; if (prevNeighbour != null) { - if (singer.TryGetMappedOto(vcPhoneme, prevNeighbour.Value.tone + attr0.toneShift, attr0.voiceColor, out oto)) { + if (singer.TryGetMappedOto(vcPhoneme, prevNeighbour.Value.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out oto)) { vcPhoneme = oto.Alias; } // prevDuration calculated on basis of previous note length int prevDuration = notes[0].position - prevNeighbour.Value.position; // vcLength depends on the Vel of the current base note - vcLen = Convert.ToInt32(Math.Min(prevDuration / 1.5, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? 1)))); + vcLen = Convert.ToInt32(Math.Min(prevDuration / 1.5, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? GetParentConsonantStretchRatio())))); } else { - if (singer.TryGetMappedOto(vcPhoneme, notes[0].tone + attr0.toneShift, attr0.voiceColor, out oto)) { + if (singer.TryGetMappedOto(vcPhoneme, notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out oto)) { vcPhoneme = oto.Alias; } // no previous note, so length can be minimum velocity regardless of oto - vcLen = Convert.ToInt32(Math.Min(vcLen * 2, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? 1)))); + vcLen = Convert.ToInt32(Math.Min(vcLen * 2, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? GetParentConsonantStretchRatio())))); } if (nextNeighbour == null) { // automatically add ending if present - if (singer.TryGetMappedOto($"{prevVowel} {lyric}", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto0)) { - if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr1.toneShift, attr1.voiceColor, out var otoEnd)) { + if (singer.TryGetMappedOto($"{prevVowel} {lyric}", notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto0)) { + if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + (attr1.toneShift ?? GetParentToneShift()), attr1.voiceColor ?? GetParentVoiceColor(), out var otoEnd)) { // automatically add ending if present return new Result { phonemes = new Phoneme[] { @@ -110,10 +110,10 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } else { // use vc if present - if (prevNeighbour == null && singer.TryGetMappedOto(vcPhoneme, notes[0].tone + attr0.toneShift, attr0.voiceColor, out var vcOto1)) { + if (prevNeighbour == null && singer.TryGetMappedOto(vcPhoneme, notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var vcOto1)) { vcPhoneme = vcOto1.Alias; // automatically add ending if present - if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr2.toneShift, attr2.voiceColor, out var otoEnd)) { + if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + (attr2.toneShift ?? GetParentToneShift()), attr2.voiceColor ?? GetParentVoiceColor(), out var otoEnd)) { return new Result { phonemes = new Phoneme[] { new Phoneme() { @@ -130,10 +130,10 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN }, }; } - } else if (prevNeighbour != null && singer.TryGetMappedOto(vcPhoneme, prevNeighbour.Value.tone + attr0.toneShift, attr0.voiceColor, out var vcOto2)) { + } else if (prevNeighbour != null && singer.TryGetMappedOto(vcPhoneme, prevNeighbour.Value.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var vcOto2)) { vcPhoneme = vcOto2.Alias; // automatically add ending if present - if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr2.toneShift, attr2.voiceColor, out var otoEnd)) { + if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + (attr2.toneShift ?? GetParentToneShift()), attr2.voiceColor ?? GetParentVoiceColor(), out var otoEnd)) { return new Result { phonemes = new Phoneme[] { new Phoneme() { @@ -151,7 +151,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN }; } } // just base note and ending - if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr1.toneShift, attr1.voiceColor, out var otoEnd1)) { + if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + (attr1.toneShift ?? GetParentToneShift()), attr1.voiceColor ?? GetParentVoiceColor(), out var otoEnd1)) { return new Result { phonemes = new Phoneme[] { new Phoneme() { @@ -167,7 +167,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } - if (singer.TryGetMappedOto(vcPhoneme, notes[0].tone + attr0.toneShift, attr0.voiceColor, out oto)) { + if (singer.TryGetMappedOto(vcPhoneme, notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out oto)) { return new Result { phonemes = new Phoneme[] { new Phoneme() { @@ -257,7 +257,8 @@ protected void RomanizeNotes(Note[][] groups) { } public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); RomanizeNotes(groups); } } -} \ No newline at end of file +} diff --git a/OpenUtau.Plugin.Builtin/ChineseCVVPhonemizer.cs b/OpenUtau.Plugin.Builtin/ChineseCVVPhonemizer.cs index 625398e75..9baab4836 100644 --- a/OpenUtau.Plugin.Builtin/ChineseCVVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/ChineseCVVPhonemizer.cs @@ -56,6 +56,7 @@ protected override Dictionary LoadVowelFallbacks() { } public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); BaseChinesePhonemizer.RomanizeNotes(groups); } } diff --git a/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs b/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs index 03581a9e9..0ff97bb3e 100644 --- a/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs @@ -225,13 +225,13 @@ private string GetLyricVowel(string lyric) { } // Method to check if the alias exists in oto.ini. - public static bool isExistPhonemeInOto(USinger singer, string phoneme, Note note) { + public bool isExistPhonemeInOto(string phoneme, Note note) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - string color = attr.voiceColor ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); - var toneShift = 0; - int? alt = null; if (phoneme.Equals(string.Empty)) { return false; } @@ -247,11 +247,11 @@ public static bool isExistPhonemeInOto(USinger singer, string phoneme, Note note return false; } - static string GetOtoAlias(USinger singer, string phoneme, Note note) { + string GetOtoAlias(string phoneme, Note note) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - string color = attr.voiceColor ?? string.Empty; - int? alt = attr.alternate; - var toneShift = attr.toneShift; + string color = attr.voiceColor ?? GetParentVoiceColor(); + var toneShift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var otoAlt)) { @@ -287,7 +287,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN foreach (var phoneticHint in phoneticHints.Select((hint, index) => (hint, index))) { phonemes[phoneticHint.index] = new Phoneme { - phoneme = GetOtoAlias(singer, phoneticHint.hint.Trim(), notes[0]) , + phoneme = GetOtoAlias(phoneticHint.hint.Trim(), notes[0]) , // The position is evenly divided into n parts. position = totalDuration - ((totalDuration / phoneticHints.Length) * (phoneticHints.Length - phoneticHint.index)), }; @@ -300,7 +300,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN // If the note is an End Breath note if (Config.SupportedTailBreath.Contains(phoneme) && prevNeighbour != null) { - phoneme = GetOtoAlias(singer, $"{GetLyricVowel(prevNeighbour?.lyric)} {phoneme}", notes[0]); + phoneme = GetOtoAlias($"{GetLyricVowel(prevNeighbour?.lyric)} {phoneme}", notes[0]); return new Result { // Output in the form "Basic vowel shape + End Breath written with lyrics" @@ -309,10 +309,10 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } // If retan is set to True in zhcvvplus.yaml, there is no previous note, and the "- lyrics" alias exists in oto.ini - if (Config.UseRetan && prevNeighbour == null && isExistPhonemeInOto(singer, $"- {phoneme}", notes[0])) { + if (Config.UseRetan && prevNeighbour == null && isExistPhonemeInOto($"- {phoneme}", notes[0])) { // 가사를 "- 가사"로 변경 phoneme = $"- {phoneme}"; - phoneme = GetOtoAlias(singer, phoneme, notes[0]); + phoneme = GetOtoAlias(phoneme, notes[0]); } // If the lyrics require a tail vowel @@ -339,8 +339,8 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN // Change to the position specified in zhcvvplus.yaml. tailVowelPosition = Config.FastTailVowelTimingTick; } - phoneme = GetOtoAlias(singer, phoneme, notes[0]); - tailPhoneme = GetOtoAlias(singer, tailPhoneme, notes[0]); + phoneme = GetOtoAlias(phoneme, notes[0]); + tailPhoneme = GetOtoAlias(tailPhoneme, notes[0]); return new Result() { phonemes = new Phoneme[] { new Phoneme { phoneme = phoneme }, // Original note lyrics @@ -354,7 +354,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN return new Result { phonemes = new Phoneme[] { new Phoneme() { - phoneme = GetOtoAlias(singer, phoneme, notes[0]), // 防止无尾音歌词在多音阶情况下丢失prefix map suffix + phoneme = GetOtoAlias(phoneme, notes[0]), // 防止无尾音歌词在多音阶情况下丢失prefix map suffix } } }; diff --git a/OpenUtau.Plugin.Builtin/EnunuOnnx/EnunuOnnxPhonemizer.cs b/OpenUtau.Plugin.Builtin/EnunuOnnx/EnunuOnnxPhonemizer.cs index 8c3b74a07..6826d7ab6 100644 --- a/OpenUtau.Plugin.Builtin/EnunuOnnx/EnunuOnnxPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/EnunuOnnx/EnunuOnnxPhonemizer.cs @@ -210,6 +210,7 @@ public void LoadQuestionSet(string path, Encoding encoding) { } public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); if (groups.Length == 0) { return; } diff --git a/OpenUtau.Plugin.Builtin/ItalianCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/ItalianCVVCPhonemizer.cs index 42bf1cc90..ca9b22c1c 100644 --- a/OpenUtau.Plugin.Builtin/ItalianCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/ItalianCVVCPhonemizer.cs @@ -88,7 +88,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN if (prevNeighbour == null) { // Use "- V" or "- CV" if present in voicebank var initial = $"-{currentLyric}"; - if (singer.TryGetMappedOto(initial, note.tone + attr0.toneShift, attr0.voiceColor, out var oto)) { + if (singer.TryGetMappedOto(initial, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)) { currentLyric = oto.Alias; } } else if (plainVowels.Contains(currentLyric)) { @@ -96,11 +96,11 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN // Current note is VV if (vowelLookup.TryGetValue(prevUnicode.LastOrDefault() ?? string.Empty, out var vow)) { currentLyric = $"{vow} {currentLyric}"; - if (singer.TryGetMappedOto(currentLyric, note.tone + attr0.toneShift, attr0.voiceColor, out var oto)) { + if (singer.TryGetMappedOto(currentLyric, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)) { currentLyric = oto.Alias; } } - } else if (singer.TryGetMappedOto(currentLyric, note.tone + attr0.toneShift, attr0.voiceColor, out var oto)) { + } else if (singer.TryGetMappedOto(currentLyric, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)) { currentLyric = oto.Alias; } @@ -147,7 +147,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } var vcPhoneme = $"{vowel} {consonant}"; - if (singer.TryGetMappedOto(vcPhoneme, note.tone + attr1.toneShift, attr1.voiceColor, out var oto1)) { + if (singer.TryGetMappedOto(vcPhoneme, note.tone + (attr1.toneShift ?? GetParentToneShift()), attr1.voiceColor ?? GetParentVoiceColor(), out var oto1)) { vcPhoneme = oto1.Alias; } else { return new Result { @@ -162,7 +162,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int totalDuration = notes.Sum(n => n.duration); int vcLength = 120; var nextAttr = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + nextAttr.toneShift, nextAttr.voiceColor, out var oto)) { + if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + (nextAttr.toneShift ?? GetParentToneShift()), nextAttr.voiceColor ?? GetParentVoiceColor(), out var oto)) { vcLength = MsToTick(oto.Preutter); } vcLength = Math.Min(totalDuration / 2, vcLength); diff --git a/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs index 3bdfd82d9..820e17f12 100644 --- a/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs @@ -103,17 +103,19 @@ static JapaneseCVVCPhonemizer() { private bool checkOtoUntilHit(string[] input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, attr.voiceColor, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, attr.voiceColor, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } - string color = attr.voiceColor ?? ""; if (otos.Count > 0) { oto = otos.FirstOrDefault(oto => oto.IsColorMatch(color)); if (oto == null) { @@ -129,17 +131,19 @@ private bool checkOtoUntilHit(string[] input, Note note, out UOto oto) { private bool checkOtoUntilHitVc(string[] input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 1) ?? default; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, attr.voiceColor, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, attr.voiceColor, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } - string color = attr.voiceColor ?? ""; if (otos.Count > 0) { oto = otos.FirstOrDefault(oto => oto.IsColorMatch(color)); if (oto != null) { @@ -257,7 +261,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int totalDuration = notes.Sum(n => n.duration); int vcLength = 120; var nextAttr = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + nextAttr.toneShift, nextAttr.voiceColor, out var oto)) { + if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + (nextAttr.toneShift ?? GetParentToneShift()), nextAttr.voiceColor ?? GetParentVoiceColor(), out var oto)) { // If overlap is a negative value, vcLength is longer than Preutter if (oto.Overlap < 0) { vcLength = MsToTick(oto.Preutter - oto.Overlap); @@ -266,7 +270,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } // vcLength depends on the Vel of the next note - vcLength = Convert.ToInt32(Math.Min(totalDuration / 2, vcLength * (nextAttr.consonantStretchRatio ?? 1))); + vcLength = Convert.ToInt32(Math.Min(totalDuration / 2, vcLength * (nextAttr.consonantStretchRatio ?? GetParentConsonantStretchRatio()))); return new Result { phonemes = new Phoneme[] { diff --git a/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs index fceed12e9..424fb0720 100644 --- a/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs @@ -20,8 +20,6 @@ public class JapanesePresampPhonemizer : Phonemizer { private USinger singer; private Presamp presamp; - private UProject project; - private UTrack track; // in case voicebank is missing certain symbols static readonly string[] substitution = new string[] { @@ -39,11 +37,6 @@ static JapanesePresampPhonemizer() { .ToDictionary(t => t.Item1, t => t.Item2); } - public override void SetUp(Note[][] groups, UProject project, UTrack track) { - this.project = project; - this.track = track; - } - public override void SetSinger(USinger singer) { if (this.singer == singer) { return; @@ -199,7 +192,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN && checkOtoUntilHit(new List { currentLyric }, note, out var oto)) { int endTick = notes[^1].position + notes[^1].duration; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - var cLength = Math.Max(30, -timeAxis.MsToTickAt(-oto.Preutter, endTick) * (attr.consonantStretchRatio ?? 1)); + var cLength = Math.Max(30, -timeAxis.MsToTickAt(-oto.Preutter, endTick) * (attr.consonantStretchRatio ?? GetParentConsonantStretchRatio())); if (prevNeighbour != null) { cLength = Math.Min(prevNeighbour.Value.duration / 2, cLength); @@ -225,7 +218,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN // Insert 2nd phoneme (when next doesn't have hint) if (nextNeighbour != null && string.IsNullOrEmpty(nextNeighbour.Value.phoneticHint)) { int totalDuration = notes.Sum(n => n.duration); - if (TickToMs(totalDuration) < 100 && presamp.MustVC == false) { + if (timeAxis.TickPosToMsPos(totalDuration) < 100 && presamp.MustVC == false) { return new Result { phonemes = result.ToArray() }; } @@ -312,7 +305,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int vcLength = 120; int endTick = notes[^1].position + notes[^1].duration; var nextAttr = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + nextAttr.toneShift, nextAttr.voiceColor, out var nextOto)) { + if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + (nextAttr.toneShift ?? GetParentToneShift()), nextAttr.voiceColor ?? GetParentVoiceColor(), out var nextOto)) { // If overlap is a negative value, vcLength is longer than Preutter if (nextOto.Overlap < 0) { vcLength = -timeAxis.MsToTickAt(-(nextOto.Preutter - nextOto.Overlap), endTick); @@ -321,7 +314,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } // Minimam is 30 tick, maximum is half of note - vcLength = Convert.ToInt32(Math.Min(totalDuration / 2, Math.Max(30, vcLength * (nextAttr.consonantStretchRatio ?? 1)))); + vcLength = Convert.ToInt32(Math.Min(totalDuration / 2, Math.Max(30, vcLength * (nextAttr.consonantStretchRatio ?? GetParentConsonantStretchRatio())))); result.Add(new Phoneme() { phoneme = vcPhoneme, @@ -338,19 +331,18 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN return new Result { phonemes = result.ToArray() }; } - // make it quicker to check multiple oto occurrences at once rather than spamming if else if private bool checkOtoUntilHit(List input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - // track.TryGetExpression(project, Core.Format.Ustx.CLR, out var trackExp); - // string color = attr.voiceColor ?? trackExp.descriptor.options[(int)trackExp.value]; - string color = attr.voiceColor ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, color, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, color, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } @@ -369,13 +361,15 @@ private bool checkOtoUntilHit(List input, Note note, int index, out UOto colorIndex = null; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == index) ?? default; var attr0 = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - string color = attr.voiceColor ?? attr0.voiceColor ?? string.Empty; + string color = attr.voiceColor ?? attr0.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? attr0.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, color, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, color, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } @@ -383,11 +377,11 @@ private bool checkOtoUntilHit(List input, Note note, int index, out UOto if (otos.Count > 0) { oto = otos.FirstOrDefault(oto => oto.IsColorMatch(color)); if (oto != null) { - if (track.VoiceColorExp.options.Contains(color)) { + if (track != null && track.VoiceColorExp.options.Contains(color)) { colorIndex = Array.IndexOf(track.VoiceColorExp.options, color); } return true; - } else if (index != 1 && index != 2) { + } else if (index != 1 && index != 2) { // Main phoneme is required, preC and VC are not required oto = otos.First(); return true; } diff --git a/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs index 40df4d382..08c06dc60 100644 --- a/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs @@ -90,13 +90,15 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN private bool CheckOtoUntilHit(string[] input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - string color = attr.voiceColor ?? ""; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, color, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, color, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } diff --git a/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs b/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs index f05e18a7d..2defa7e38 100644 --- a/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs @@ -313,6 +313,7 @@ static KOtoJAPhonemizer() { /// Apply Korean sandhi rules to Hangeul lyrics. /// public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); // variate lyrics RomanizeNotes(groups, false); } @@ -393,19 +394,19 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int? alt2; PhonemeAttributes attr = note.phonemeAttributes.FirstOrDefault(a => a.index == 0); - color = attr.voiceColor; - shift = attr.toneShift; - alt = attr.alternate; + color = attr.voiceColor ?? GetParentVoiceColor(); + shift = attr.toneShift ?? GetParentToneShift(); + alt = attr.alternate ?? GetParentAlternate(); PhonemeAttributes attr1 = note.phonemeAttributes.FirstOrDefault(a => a.index == 1); - color1 = attr1.voiceColor; - shift1 = attr1.toneShift; - alt1 = attr1.alternate; + color1 = attr1.voiceColor ?? GetParentVoiceColor(); + shift1 = attr1.toneShift ?? GetParentToneShift(); + alt1 = attr1.alternate ?? GetParentAlternate(); PhonemeAttributes attr2 = note.phonemeAttributes.FirstOrDefault(a => a.index == 2); - color2 = attr2.voiceColor; - shift2 = attr2.toneShift; - alt2 = attr2.alternate; + color2 = attr2.voiceColor ?? GetParentVoiceColor(); + shift2 = attr2.toneShift ?? GetParentToneShift(); + alt2 = attr2.alternate ?? GetParentAlternate(); string[] currIMF; string currPhoneme; @@ -648,7 +649,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } // vcLength depends on the Vel of the current base note - vcLength = Convert.ToInt32(Math.Min(totalDuration / 2, vcLength * (attr1.consonantStretchRatio ?? 1))); + vcLength = Convert.ToInt32(Math.Min(totalDuration / 2, vcLength * (attr1.consonantStretchRatio ?? GetParentConsonantStretchRatio()))); if (string.IsNullOrEmpty(prevIMF[2])) { if (prevIMF[1][0] == 'w' || prevIMF[1][0] == 'y') { diff --git a/OpenUtau.Plugin.Builtin/KoreanCBNNPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanCBNNPhonemizer.cs index 008f86847..01763b3f5 100644 --- a/OpenUtau.Plugin.Builtin/KoreanCBNNPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanCBNNPhonemizer.cs @@ -219,7 +219,7 @@ private Result ConvertForCBNN(Note[] notes, string[] prevLyric, string[] thisLyr } private string? FindInOto(String phoneme, Note note, bool nullIfNotFound=false){ - return BaseKoreanPhonemizer.FindInOto(singer, phoneme, note, nullIfNotFound); + return FindInOto(singer, phoneme, note, nullIfNotFound); } @@ -282,4 +282,4 @@ public override Result GenerateEndSound(Note[] notes, Note? prev, Note? next, No return GenerateResult(FindInOto($"{prevMidVowel} {endSound}", note)); } } -} \ No newline at end of file +} diff --git a/OpenUtau.Plugin.Builtin/KoreanCVCCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanCVCCVPhonemizer.cs index d42470b77..705a23e5d 100644 --- a/OpenUtau.Plugin.Builtin/KoreanCVCCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanCVCCVPhonemizer.cs @@ -213,6 +213,7 @@ private char[] SeparateHangul(char letter) { /// Apply Korean sandhi rules to Hangeul lyrics. /// public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); // variate lyrics KoreanPhonemizerUtil.RomanizeNotes(groups, false); } diff --git a/OpenUtau.Plugin.Builtin/KoreanCVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanCVCPhonemizer.cs index 6c1fa2afd..ecef09b30 100644 --- a/OpenUtau.Plugin.Builtin/KoreanCVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanCVCPhonemizer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using OpenUtau.Api; @@ -96,6 +96,7 @@ string getConsonant(string str) { /// Apply Korean sandhi rules to Hangeul lyrics. /// public override void SetUp(Note[][] groups, UProject project, UTrack track) { + base.SetUp(groups, project, track); // variate lyrics KoreanPhonemizerUtil.RomanizeNotes(groups, false); } @@ -155,7 +156,7 @@ private bool checkOtoUntilHit(string[] input, Note note, out UOto oto){ var attr1 = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 1) ?? default; foreach (string test in input){ - if (singer.TryGetMappedOto(test, note.tone + attr0.toneShift, attr0.voiceColor, out oto)){ + if (singer.TryGetMappedOto(test, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out oto)){ return true; } } @@ -592,7 +593,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int fcLength = totalDuration / 3; if ((TCLfinal == "k") || (TCLfinal == "p") || (TCLfinal == "t")) { fcLength = totalDuration / 2; } - if (singer.TryGetMappedOto(CV, note.tone + attr0.toneShift, attr0.voiceColor, out var oto1) && singer.TryGetMappedOto(FC, note.tone + attr0.toneShift, attr0.voiceColor, out var oto2)) { + if (singer.TryGetMappedOto(CV, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto1) && singer.TryGetMappedOto(FC, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto2)) { CV = oto1.Alias; FC = oto2.Alias; return new Result { @@ -622,7 +623,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN else if ((TNLconsonant == "gg") || (TNLconsonant == "dd") || (TNLconsonant == "bb") || (TNLconsonant == "ss") || (TNLconsonant == "jj")) { vcLength = totalDuration / 2; } vcLength = Math.Min(totalDuration / 2, vcLength); - if (singer.TryGetMappedOto(CV, note.tone + attr0.toneShift, attr0.voiceColor, out var oto1) && singer.TryGetMappedOto(VC, note.tone + attr0.toneShift, attr0.voiceColor, out var oto2)) { + if (singer.TryGetMappedOto(CV, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto1) && singer.TryGetMappedOto(VC, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto2)) { CV = oto1.Alias; VC = oto2.Alias; return new Result { @@ -642,13 +643,13 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN var nextAttr = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; var nextUnicode = ToUnicodeElements(nextNeighbour?.lyric); var nextLyric = string.Join("", nextUnicode); - if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + nextAttr.toneShift, nextAttr.voiceColor, out var oto0)) { + if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + (nextAttr.toneShift ?? GetParentToneShift()), nextAttr.voiceColor ?? GetParentVoiceColor(), out var oto0)) { vcLength = MsToTick(oto0.Preutter); } vcLength = Math.Min(totalDuration / 2, vcLength); - if (singer.TryGetMappedOto(CV, note.tone + attr0.toneShift, attr0.voiceColor, out var oto1) && singer.TryGetMappedOto(VC, note.tone + attr0.toneShift, attr0.voiceColor, out var oto2)) { + if (singer.TryGetMappedOto(CV, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto1) && singer.TryGetMappedOto(VC, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto2)) { CV = oto1.Alias; VC = oto2.Alias; return new Result { @@ -665,7 +666,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } // 그 외(받침 없는 마지막 노트) - if (singer.TryGetMappedOto(CV, note.tone + attr0.toneShift, attr0.voiceColor, out var oto)) { + if (singer.TryGetMappedOto(CV, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)) { CV = oto.Alias; return new Result { phonemes = new Phoneme[] { @@ -687,7 +688,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN endBreath = $"{TPLplainfinal} R"; } - if (singer.TryGetMappedOto(endBreath, note.tone + attr0.toneShift, attr0.voiceColor, out var oto)){ + if (singer.TryGetMappedOto(endBreath, note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)){ endBreath = oto.Alias; return new Result { phonemes = new Phoneme[] { @@ -892,7 +893,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int vcLength = 60; var nextAttr = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + nextAttr.toneShift, nextAttr.voiceColor, out var oto)) { + if (singer.TryGetMappedOto(nextLyric, nextNeighbour.Value.tone + (nextAttr.toneShift ?? GetParentToneShift()), nextAttr.voiceColor ?? GetParentVoiceColor(), out var oto)) { vcLength = MsToTick(oto.Preutter); } else if ((TNLconsonant == "r") || (TNLconsonant == "h")) { vcLength = 30; } else if (TNLconsonant == "s") { vcLength = totalDuration / 3; } diff --git a/OpenUtau.Plugin.Builtin/KoreanCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanCVPhonemizer.cs index 3a9447701..3b7cc65cb 100644 --- a/OpenUtau.Plugin.Builtin/KoreanCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanCVPhonemizer.cs @@ -339,7 +339,7 @@ private Result ConvertForCV(Note[] notes, string[] prevLyric, string[] thisLyric } private string? FindInOto(String phoneme, Note note, bool nullIfNotFound=false){ - return BaseKoreanPhonemizer.FindInOto(singer, phoneme, note, nullIfNotFound); + return FindInOto(singer, phoneme, note, nullIfNotFound); } @@ -415,4 +415,4 @@ public override Result GenerateEndSound(Note[] notes, Note? prev, Note? next, No return GenerateResult(FindInOto($"{prevMidVowel} {endSound}", note)); } } -} \ No newline at end of file +} diff --git a/OpenUtau.Plugin.Builtin/KoreanCVVCStandardPronunciationPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanCVVCStandardPronunciationPhonemizer.cs index c1f5e560a..4931ffdd5 100644 --- a/OpenUtau.Plugin.Builtin/KoreanCVVCStandardPronunciationPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanCVVCStandardPronunciationPhonemizer.cs @@ -277,7 +277,7 @@ private Result ConvertForCVVC(Note[] notes, string[] prevLyric, string[] thisLyr } private string? FindInOto(String phoneme, Note note, bool nullIfNotFound=false){ - return BaseKoreanPhonemizer.FindInOto(singer, phoneme, note, nullIfNotFound); + return FindInOto(singer, phoneme, note, nullIfNotFound); } private bool IsENPhoneme(String phoneme) { @@ -468,4 +468,4 @@ public override Result GenerateEndSound(Note[] notes, Note? prev, Note? next, No return GenerateResult(FindInOto($"{prevMidVowel} {endSound}", note)); } } -} \ No newline at end of file +} diff --git a/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs index 541d5e2a1..0fdbcf71c 100644 --- a/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -44,8 +44,9 @@ public class KoreanVCVPhonemizer : BaseKoreanPhonemizer /// Apply Korean sandhi rules to Hangeul lyrics. /// public override void SetUp(Note[][] groups, UProject project, UTrack track) { - // variate lyrics - RomanizeNotes(groups, false); + base.SetUp(groups, project, track); + // variate lyrics + RomanizeNotes(groups, false); } /// @@ -138,14 +139,14 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int? alt1; PhonemeAttributes attr = note.phonemeAttributes.FirstOrDefault(a => a.index == 0); - color = attr.voiceColor; - shift = attr.toneShift; - alt = attr.alternate; + color = attr.voiceColor ?? GetParentVoiceColor(); + shift = attr.toneShift ?? GetParentToneShift(); + alt = attr.alternate ?? GetParentAlternate(); PhonemeAttributes attr1 = note.phonemeAttributes.FirstOrDefault(a => a.index == 1); - color1 = attr1.voiceColor; - shift1 = attr1.toneShift; - alt1 = attr1.alternate; + color1 = attr1.voiceColor ?? GetParentVoiceColor(); + shift1 = attr1.toneShift ?? GetParentToneShift(); + alt1 = attr1.alternate ?? GetParentAlternate(); string[] currIMF; string currPhoneme; diff --git a/OpenUtau.Plugin.Builtin/PhonemeBasedPhonemizer.cs b/OpenUtau.Plugin.Builtin/PhonemeBasedPhonemizer.cs index 2c33d0a99..7f6447631 100644 --- a/OpenUtau.Plugin.Builtin/PhonemeBasedPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/PhonemeBasedPhonemizer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using OpenUtau.Api; @@ -62,7 +62,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN // The user is using a tail "-" note to produce a " -" sound. if (note.lyric == "-" && prevSymbols != null) { var attr = note.phonemeAttributes?.FirstOrDefault() ?? default; - string color = attr.voiceColor; + string color = attr.voiceColor ?? GetParentVoiceColor(); string alias = $"{prevSymbols.Last()} -"; if (singer.TryGetMappedOto(alias, note.tone, color, out var oto)) { return MakeSimpleResult(oto.Alias); @@ -143,9 +143,9 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN string prevSymbol = prevSymbols == null ? "-" : prevSymbols.Last(); for (int i = 0; i < symbols.Length; i++) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == i) ?? default; - string alt = attr.alternate?.ToString() ?? string.Empty; - string color = attr.voiceColor; - int toneShift = attr.toneShift; + string alt = (attr.alternate ?? GetParentAlternate())?.ToString() ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); var phoneme = phonemes[i]; while (noteIndex < notes.Length - 1 && notes[noteIndex].position - note.position < phoneme.position) { noteIndex++; @@ -219,4 +219,4 @@ void DistributeDuration(bool[] isVowel, Phoneme[] phonemes, int startIndex, int } } } -} \ No newline at end of file +} diff --git a/OpenUtau.Plugin.Builtin/PresampSamplePhonemizer.cs b/OpenUtau.Plugin.Builtin/PresampSamplePhonemizer.cs index d330d681b..63e53ee58 100644 --- a/OpenUtau.Plugin.Builtin/PresampSamplePhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/PresampSamplePhonemizer.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; using Classic; using OpenUtau.Api; -using OpenUtau.Classic; using OpenUtau.Core.Ustx; #if DEBUG @@ -60,25 +58,25 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN var attr0 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; var attr1 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 1) ?? default; if (lyric == "-" || lyric.ToLowerInvariant() == "r") { - if (singer.TryGetMappedOto($"{prevVowel}{vcpad}R", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto1)) { + if (singer.TryGetMappedOto($"{prevVowel}{vcpad}R", notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto1)) { return MakeSimpleResult(oto1.Alias); } return MakeSimpleResult($"{prevVowel}{vcpad}R"); } int totalDuration = notes.Sum(n => n.duration); - if (singer.TryGetMappedOto($"{prevVowel}{vcpad}{lyric}", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto)) { + if (singer.TryGetMappedOto($"{prevVowel}{vcpad}{lyric}", notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto)) { return MakeSimpleResult(oto.Alias); } int vcLen = 120; - if (singer.TryGetMappedOto(lyric, notes[0].tone + attr0.toneShift, attr0.voiceColor, out var cvOto)) { + if (singer.TryGetMappedOto(lyric, notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var cvOto)) { if (cvOto.Overlap < 0) { vcLen = MsToTick(cvOto.Preutter - cvOto.Overlap); } else { vcLen = MsToTick(cvOto.Preutter); } - vcLen = Convert.ToInt32(Math.Min(totalDuration / 2, vcLen * (attr0.consonantStretchRatio ?? 1))); + vcLen = Convert.ToInt32(Math.Min(totalDuration / 2, vcLen * (attr0.consonantStretchRatio ?? GetParentConsonantStretchRatio()))); } - if (singer.TryGetMappedOto($"{prevVowel}{vcpad}{consonant}", notes[0].tone + attr0.toneShift, attr0.voiceColor, out oto)) { + if (singer.TryGetMappedOto($"{prevVowel}{vcpad}{consonant}", notes[0].tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out oto)) { return new Result { phonemes = new Phoneme[] { new Phoneme() { diff --git a/OpenUtau.Plugin.Builtin/SyllableBasedPhonemizer.cs b/OpenUtau.Plugin.Builtin/SyllableBasedPhonemizer.cs index c576430f0..95ca6df74 100644 --- a/OpenUtau.Plugin.Builtin/SyllableBasedPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/SyllableBasedPhonemizer.cs @@ -217,9 +217,9 @@ protected virtual Phoneme[] AssignAllAffixes(List phonemes, Note[] note int noteIndex = 0; for (int i = 0; i < phonemes.Count; i++) { var attr = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == i) ?? default; - string alt = attr.alternate?.ToString() ?? string.Empty; - string color = attr.voiceColor; - int toneShift = attr.toneShift; + string alt = (attr.alternate ?? GetParentAlternate())?.ToString() ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); var phoneme = phonemes[i]; while (noteIndex < notes.Length - 1 && notes[noteIndex].position - notes[0].position < phoneme.position) { noteIndex++; @@ -692,9 +692,9 @@ protected virtual Note[] HandleNotEnoughNotes(Note[] notes, List vowelIds) /// protected virtual string[] HandleWordNotFound(Note note) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - string alt = attr.alternate?.ToString() ?? string.Empty; - string color = attr.voiceColor; - int toneShift = attr.toneShift; + string alt = (attr.alternate ?? GetParentAlternate())?.ToString() ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); var mpdlyric = MapPhoneme(note.lyric, note.tone + toneShift, color, alt, singer); if(HasOto(mpdlyric, note.tone)){ error = mpdlyric; diff --git a/OpenUtau.Plugin.Builtin/ThaiVCCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/ThaiVCCVPhonemizer.cs index 6fd646a49..9dc3e2db5 100644 --- a/OpenUtau.Plugin.Builtin/ThaiVCCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/ThaiVCCVPhonemizer.cs @@ -68,7 +68,7 @@ private bool checkOtoUntilHit(string[] input, Note note, out UOto oto) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; foreach (string test in input) { - if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, attr.voiceColor, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test, note.tone + (attr.toneShift ?? GetParentToneShift()), attr.voiceColor ?? GetParentVoiceColor(), out var otoCandidacy)) { oto = otoCandidacy; return true; } @@ -180,7 +180,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN nextCheck = nextTh.Consonant + nextTh.Dipthong + nextTh.Vowel; } var nextAttr = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; - if (singer.TryGetMappedOto(nextCheck, nextNeighbour.Value.tone + nextAttr.toneShift, nextAttr.voiceColor, out var nextOto)) { + if (singer.TryGetMappedOto(nextCheck, nextNeighbour.Value.tone + (nextAttr.toneShift ?? GetParentToneShift()), nextAttr.voiceColor ?? GetParentVoiceColor(), out var nextOto)) { if (oto.Overlap > 0) { vcPosition = noteDuration - MsToTick(nextOto.Overlap) - MsToTick(nextOto.Preutter); } diff --git a/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs index 5d25be093..4be80f1ca 100644 --- a/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs @@ -21,17 +21,19 @@ public class TurkishCVVCPhonemizer : Phonemizer { private bool checkOtoUntilHit(string[] input, Note note, out UOto oto) { oto = default; var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int shift = attr.toneShift ?? GetParentToneShift(); + int? alt = attr.alternate ?? GetParentAlternate(); var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + attr.alternate, note.tone + attr.toneShift, attr.voiceColor, out var otoAlt)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + attr.toneShift, attr.voiceColor, out var otoCandidacy)) { + } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } - string color = attr.voiceColor ?? ""; if (otos.Count > 0) { if (otos.Any(oto => (oto.Color ?? string.Empty) == color)) { oto = otos.Find(oto => (oto.Color ?? string.Empty) == color); @@ -279,7 +281,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN if (nextNeighbour != null) { isEndCoeff = 1; var attr0 = nextNeighbour.Value.phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default; //next first - if (singer.TryGetMappedOto(getNoteStart(phonemesNext, phonemesCurrent)[0], note.tone + attr0.toneShift, attr0.voiceColor, out var oto0)) { + if (singer.TryGetMappedOto(getNoteStart(phonemesNext, phonemesCurrent)[0], note.tone + (attr0.toneShift ?? GetParentToneShift()), attr0.voiceColor ?? GetParentVoiceColor(), out var oto0)) { // If overlap is a negative value, vcLength is longer than Preutter if (oto0.Overlap < 0) lastLengthFromOto = timeAxis.MsPosToTickPos(oto0.Preutter - oto0.Overlap); @@ -289,7 +291,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } // vcLength depends on the Vel of the note var attr1 = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 1) ?? default; // current last (noteEnd) - var vcLength = Convert.ToInt32(Math.Min(totalDuration / (2 * isEndCoeff), lastLengthFromOto * isCVCoeff * (attr1.consonantStretchRatio ?? 1))); + var vcLength = Convert.ToInt32(Math.Min(totalDuration / (2 * isEndCoeff), lastLengthFromOto * isCVCoeff * (attr1.consonantStretchRatio ?? GetParentConsonantStretchRatio()))); if (noteEndCC == "") { return new Result { @@ -307,7 +309,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int ccLengthFromOto = 60; var attr2 = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == 2) ?? default; if (nextNeighbour != null) { - if (singer.TryGetMappedOto(noteEndCC, note.tone + attr2.toneShift, attr2.voiceColor, out var oto1)) { + if (singer.TryGetMappedOto(noteEndCC, note.tone + (attr2.toneShift ?? GetParentToneShift()), attr2.voiceColor ?? GetParentVoiceColor(), out var oto1)) { // If overlap is a negative value, vcLength is longer than Preutter if (oto1.Overlap < 0) { ccLengthFromOto = timeAxis.MsPosToTickPos(oto1.Preutter - oto1.Overlap); @@ -316,8 +318,8 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } } - vcLength = Convert.ToInt32(Math.Min(totalDuration / 3, ccLengthFromOto * (attr1.consonantStretchRatio ?? 1))); - var ccLength = Convert.ToInt32(Math.Min(totalDuration / 3, lastLengthFromOto * (attr2.consonantStretchRatio ?? 1))); + vcLength = Convert.ToInt32(Math.Min(totalDuration / 3, ccLengthFromOto * (attr1.consonantStretchRatio ?? GetParentConsonantStretchRatio()))); + var ccLength = Convert.ToInt32(Math.Min(totalDuration / 3, lastLengthFromOto * (attr2.consonantStretchRatio ?? GetParentConsonantStretchRatio()))); List exp = new List(); PhonemeExpression e = new PhonemeExpression() { abbr = Core.Format.Ustx.VOL, value = 70 }; diff --git a/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs index 66881e045..6cd89635c 100644 --- a/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs @@ -1323,9 +1323,9 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int noteIndex = 0; for (int i = 0; i < phonemes.Count; i++) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == i) ?? default; - string alt = attr.alternate?.ToString() ?? string.Empty; - string color = attr.voiceColor; - int toneShift = attr.toneShift; + string alt = (attr.alternate ?? GetParentAlternate())?.ToString() ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); var phoneme1 = phonemes[i]; while (noteIndex < notes.Length - 1 && notes[noteIndex].position - note.position < phoneme1.position) { noteIndex++; diff --git a/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs index 41f6826fb..df41697d8 100644 --- a/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs @@ -1146,9 +1146,9 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int noteIndex = 0; for (int i = 0; i < phonemes.Count; i++) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == i) ?? default; - string alt = attr.alternate?.ToString() ?? string.Empty; - string color = attr.voiceColor; - int toneShift = attr.toneShift; + string alt = (attr.alternate ?? GetParentAlternate())?.ToString() ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); var phoneme1 = phonemes[i]; while (noteIndex < notes.Length - 1 && notes[noteIndex].position - note.position < phoneme1.position) { noteIndex++; diff --git a/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs b/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs index 395181f9a..cccee2e89 100644 --- a/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs @@ -2417,9 +2417,9 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int noteIndex = 0; for (int i = 0; i < phonemes.Count; i++) { var attr = note.phonemeAttributes?.FirstOrDefault(attr => attr.index == i) ?? default; - string alt = attr.alternate?.ToString() ?? string.Empty; - string color = attr.voiceColor; - int toneShift = attr.toneShift; + string alt = (attr.alternate ?? GetParentAlternate())?.ToString() ?? string.Empty; + string color = attr.voiceColor ?? GetParentVoiceColor(); + int toneShift = attr.toneShift ?? GetParentToneShift(); var phoneme1 = phonemes[i]; while (noteIndex < notes.Length - 1 && notes[noteIndex].position - note.position < phoneme1.position) { noteIndex++; From 45d0187ee0c31317244640606ccc9174e2093829 Mon Sep 17 00:00:00 2001 From: Maiko Date: Thu, 25 Jun 2026 23:55:43 +0900 Subject: [PATCH 2/2] update ALT logic --- .../BaseKoreanPhonemizer.cs | 5 +-- .../CantoneseSyoPhonemizer.cs | 8 ++--- .../ChineseCVVPlusPhonemizer.cs | 9 ++---- .../JapaneseCVVCPhonemizer.cs | 8 ++--- .../JapanesePresampPhonemizer.cs | 8 ++--- .../JapaneseVCVPhonemizer.cs | 4 +-- OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs | 32 +++++-------------- .../KoreanVCVPhonemizer.cs | 16 +++------- .../TurkishCVVCPhonemizer.cs | 4 +-- OpenUtau.Test/Plugins/PhonemizerTestBase.cs | 2 +- 10 files changed, 24 insertions(+), 72 deletions(-) diff --git a/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs b/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs index 6a8604293..3eed0c1ea 100644 --- a/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/BaseKoreanPhonemizer.cs @@ -40,10 +40,7 @@ protected virtual bool additionalTest(string lyric) { int? alt = attr.alternate ?? GetParentAlternate(); if (phoneme.Equals("")) {return phoneme;} - if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var otoAlt)) { - phonemeToReturn = otoAlt.Alias; - } - else if (singer.TryGetMappedOto(phoneme, note.tone + toneShift, color, out var oto)) { + if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var oto)) { phonemeToReturn = oto.Alias; } else if (singer.TryGetMappedOto(phoneme, note.tone, color, out oto)) { diff --git a/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs b/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs index 4b90801b0..410ac8aee 100644 --- a/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/CantoneseSyoPhonemizer.cs @@ -312,9 +312,7 @@ private bool checkOtoUntilHit(List input, Note note, out UOto oto) { var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } @@ -339,9 +337,7 @@ private bool checkOtoUntilHitFinal(List input, Note note, out UOto oto) var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } diff --git a/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs b/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs index 0ff97bb3e..8071effd9 100644 --- a/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/ChineseCVVPlusPhonemizer.cs @@ -236,9 +236,7 @@ public bool isExistPhonemeInOto(string phoneme, Note note) { return false; } - if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var otoAlt)) { - return true; - } else if (singer.TryGetMappedOto(phoneme, note.tone + toneShift, color, out var oto)) { + if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var oto)) { return true; } else if (singer.TryGetMappedOto(phoneme, note.tone, color, out oto)) { return true; @@ -253,10 +251,7 @@ string GetOtoAlias(string phoneme, Note note) { var toneShift = attr.toneShift ?? GetParentToneShift(); int? alt = attr.alternate ?? GetParentAlternate(); - - if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var otoAlt)) { - return otoAlt.Alias; - } else if (singer.TryGetMappedOto(phoneme, note.tone + toneShift, color, out var oto)) { + if (singer.TryGetMappedOto(phoneme + alt, note.tone + toneShift, color, out var oto)) { return oto.Alias; } else if (singer.TryGetMappedOto(phoneme, note.tone, color, out oto)) { return oto.Alias; diff --git a/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs index 820e17f12..11acdceea 100644 --- a/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs @@ -109,9 +109,7 @@ private bool checkOtoUntilHit(string[] input, Note note, out UOto oto) { var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } @@ -137,9 +135,7 @@ private bool checkOtoUntilHitVc(string[] input, Note note, out UOto oto) { var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } diff --git a/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs index 424fb0720..648fcd414 100644 --- a/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs @@ -340,9 +340,7 @@ private bool checkOtoUntilHit(List input, Note note, out UOto oto) { var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } @@ -367,9 +365,7 @@ private bool checkOtoUntilHit(List input, Note note, int index, out UOto var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } diff --git a/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs index 08c06dc60..281075fd1 100644 --- a/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapaneseVCVPhonemizer.cs @@ -96,9 +96,7 @@ private bool CheckOtoUntilHit(string[] input, Note note, out UOto oto) { var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } diff --git a/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs b/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs index 2defa7e38..a85e5f680 100644 --- a/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KOtoJAPhonemizer.cs @@ -477,9 +477,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } } // Map alias (apply shift + color) - if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift, color, out var oto)) { + if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var oto)) { currPhoneme = oto.Alias; } @@ -679,9 +677,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN if (substituteLookup.TryGetValue(consonant ?? string.Empty, out con)) { vcPhonemes[1] = $"{prevConnect} {con}"; } - if (singer.TryGetMappedOto(currPhoneme + alt1, note.tone + shift1, color1, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift1, color1, out var oto0)) { + if (singer.TryGetMappedOto(currPhoneme + alt1, note.tone + shift1, color1, out var oto0)) { currPhoneme = oto0.Alias; } string secondPhoneme = (currIMF[1][0] == 'w' || currIMF[1][0] == 'y') ? currIMF[1].Remove(0, 1) : currIMF[1]; @@ -743,19 +739,13 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int noteLength = 0; for (int i = 0; i < notes.Length; i++) noteLength += notes[i].duration; int secondPosition = Math.Max(noteLength - (nextNeighbour == null ? 120 : 180), noteLength / 2); - if (singer.TryGetMappedOto(currPhoneme + alt1, note.tone + shift1, color1, out var otoAlt0)) { - currPhoneme = otoAlt0.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift1, color1, out var oto0)) { + if (singer.TryGetMappedOto(currPhoneme + alt1, note.tone + shift1, color1, out oto0)) { currPhoneme = oto0.Alias; } - if (singer.TryGetMappedOto(vcPhoneme ?? vcPhonemes[1] ?? string.Empty + alt, prevNeighbour.Value.tone + shift, color, out var otoVcAlt)) { - vcPhoneme = otoVcAlt.Alias; - } else if (singer.TryGetMappedOto(vcPhoneme ?? vcPhonemes[1] ?? string.Empty, prevNeighbour.Value.tone + shift, color, out var otoVc)) { + if (singer.TryGetMappedOto(vcPhoneme ?? vcPhonemes[1] ?? string.Empty + alt, prevNeighbour.Value.tone + shift, color, out var otoVc)) { vcPhoneme = otoVc.Alias; } - if (singer.TryGetMappedOto(secondPhoneme + alt2, note.tone + shift2, color2, out var otoAlt3)) { - secondPhoneme = otoAlt3.Alias; - } else if (singer.TryGetMappedOto(secondPhoneme, note.tone + shift2, color2, out var oto3)) { + if (singer.TryGetMappedOto(secondPhoneme + alt2, note.tone + shift2, color2, out var oto3)) { secondPhoneme = oto3.Alias; } if (singer.TryGetMappedOto(vcPhoneme, note.tone + shift, color, out _) @@ -804,9 +794,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN if (string.IsNullOrEmpty(currIMF[2])) { // Map alias (apply shift + color) - if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift, color, out var oto)) { + if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var oto)) { currPhoneme = oto.Alias; } return new Result { @@ -875,14 +863,10 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN for (int i = 0; i < notes.Length; i++) noteLength += notes[i].duration; int secondPosition = Math.Max(noteLength - (nextNeighbour == null ? 120 : 180), noteLength / 2); // Map alias (apply shift + color) - if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift, color, out var oto)) { + if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var oto)) { currPhoneme = oto.Alias; } - if (singer.TryGetMappedOto(secondPhoneme + alt1, note.tone + shift1, color1, out var otoalt)) { - secondPhoneme = otoalt.Alias; - } else if (singer.TryGetMappedOto(secondPhoneme, note.tone + shift1, color1, out var oto)) { + if (singer.TryGetMappedOto(secondPhoneme + alt1, note.tone + shift1, color1, out oto)) { secondPhoneme = oto.Alias; } // Return Result diff --git a/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs index 0fdbcf71c..2bbcfbff3 100644 --- a/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/KoreanVCVPhonemizer.cs @@ -208,9 +208,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN } // Map alias (apply shift + color) - if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift, color, out var oto)) { + if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var oto)) { currPhoneme = oto.Alias; } @@ -297,9 +295,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN if (string.IsNullOrEmpty(currIMF[2])) { // Map alias (apply shift + color) - if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift, color, out var oto)) { + if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var oto)) { currPhoneme = oto.Alias; } @@ -341,15 +337,11 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN int secondPosition = Math.Max(noteLength - (nextNeighbour == null ? 120 : 180), noteLength / 2); // Map alias (apply shift + color) - if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var otoAlt)) { - currPhoneme = otoAlt.Alias; - } else if (singer.TryGetMappedOto(currPhoneme, note.tone + shift, color, out var oto)) { + if (singer.TryGetMappedOto(currPhoneme + alt, note.tone + shift, color, out var oto)) { currPhoneme = oto.Alias; } - if (singer.TryGetMappedOto(secondPhoneme + alt1, note.tone + shift1, color1, out var otoAlt1)) { - secondPhoneme = otoAlt1.Alias; - } else if (singer.TryGetMappedOto(secondPhoneme, note.tone + shift1, color1, out var oto)) { + if (singer.TryGetMappedOto(secondPhoneme + alt1, note.tone + shift1, color1, out oto)) { secondPhoneme = oto.Alias; } diff --git a/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs index 4be80f1ca..d4a4f555c 100644 --- a/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/TurkishCVVCPhonemizer.cs @@ -27,9 +27,7 @@ private bool checkOtoUntilHit(string[] input, Note note, out UOto oto) { var otos = new List(); foreach (string test in input) { - if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoAlt)) { - otos.Add(otoAlt); - } else if (singer.TryGetMappedOto(test, note.tone + shift, color, out var otoCandidacy)) { + if (singer.TryGetMappedOto(test + alt, note.tone + shift, color, out var otoCandidacy)) { otos.Add(otoCandidacy); } } diff --git a/OpenUtau.Test/Plugins/PhonemizerTestBase.cs b/OpenUtau.Test/Plugins/PhonemizerTestBase.cs index 41dedc2be..0b533ca17 100644 --- a/OpenUtau.Test/Plugins/PhonemizerTestBase.cs +++ b/OpenUtau.Test/Plugins/PhonemizerTestBase.cs @@ -148,7 +148,7 @@ void RunPhonemizeTest(string singerName, List groups, string[ index = j, consonantStretchRatio = 1, toneShift = phonemeParams.shift, - alternate = phonemeParams.alt, + alternate = phonemeParams.alt == 0 ? null : phonemeParams.alt, // 0 means no alt (nothing added) voiceColor = phonemeParams.color }; }