diff --git a/OpenUtau.Core/Api/PhonemizerRunner.cs b/OpenUtau.Core/Api/PhonemizerRunner.cs index 50b465a5c..636af3b5d 100644 --- a/OpenUtau.Core/Api/PhonemizerRunner.cs +++ b/OpenUtau.Core/Api/PhonemizerRunner.cs @@ -30,6 +30,7 @@ internal class PhonemizerRunner : IDisposable { private readonly TaskScheduler mainScheduler; private readonly CancellationTokenSource shutdown = new CancellationTokenSource(); private readonly BlockingCollection requests = new BlockingCollection(); + private readonly object busyLock = new object(); private Thread thread; public PhonemizerRunner(TaskScheduler mainScheduler) { @@ -49,22 +50,24 @@ void PhonemizerLoop() { var parts = new HashSet(); var toRun = new List(); while (!shutdown.IsCancellationRequested) { - while (requests.TryTake(out var request)) { - toRun.Add(request); - } - foreach (var request in toRun) { - parts.Add(request.part); - } - for (int i = toRun.Count - 1; i >= 0; i--) { - if (parts.Remove(toRun[i].part)) { - SendResponse(Phonemize(toRun[i])); + lock (busyLock) { + while (requests.TryTake(out var request)) { + toRun.Add(request); + } + foreach (var request in toRun) { + parts.Add(request.part); } + for (int i = toRun.Count - 1; i >= 0; i--) { + if (parts.Remove(toRun[i].part)) { + SendResponse(Phonemize(toRun[i])); + } + } + parts.Clear(); + toRun.Clear(); + try { + toRun.Add(requests.Take(shutdown.Token)); + } catch (OperationCanceledException) { } } - parts.Clear(); - toRun.Clear(); - try { - toRun.Add(requests.Take(shutdown.Token)); - } catch (OperationCanceledException) { } } } @@ -170,6 +173,20 @@ static PhonemizerResponse Phonemize(PhonemizerRequest request) { }; } + /// + /// Wait already queued phonemizer requests to finish. + /// Should only be used in command line mode. + /// + public void WaitFinish() { + while (true) { + lock (busyLock) { + if (requests.Count == 0) { + return; + } + } + } + } + public void Dispose() { if (shutdown.IsCancellationRequested) { return; diff --git a/OpenUtau.Core/Classic/ExeWavtool.cs b/OpenUtau.Core/Classic/ExeWavtool.cs index fd7469a86..f852e3138 100644 --- a/OpenUtau.Core/Classic/ExeWavtool.cs +++ b/OpenUtau.Core/Classic/ExeWavtool.cs @@ -93,7 +93,7 @@ void WriteSetUp(StreamWriter writer, List resamplerItems, string void WriteItem(StreamWriter writer, ResamplerItem item, int index, int total) { writer.WriteLine($"@set resamp={item.resampler.FilePath}"); - writer.WriteLine($"@set params={item.volume} {item.modulation} !{item.tempo} {Base64.Base64EncodeInt12(item.pitches)}"); + writer.WriteLine($"@set params={item.volume} {item.modulation} !{item.tempo.ToString("G999")} {Base64.Base64EncodeInt12(item.pitches)}"); writer.WriteLine($"@set flag=\"{item.GetFlagsString()}\""); writer.WriteLine($"@set env={GetEnvelope(item)}"); writer.WriteLine($"@set stp={item.skipOver}"); @@ -101,7 +101,7 @@ void WriteItem(StreamWriter writer, ResamplerItem item, int index, int total) { string relOutputFile = Path.GetRelativePath(PathManager.Inst.CachePath, item.outputFile); writer.WriteLine($"@set temp=\"%cachedir%\\{relOutputFile}\""); string toneName = MusicMath.GetToneName(item.tone); - string dur = $"{item.phone.duration}@{item.phone.tempo}{(item.durCorrection >= 0 ? "+" : "")}{item.durCorrection}"; + string dur = $"{item.phone.duration.ToString("G999")}@{item.phone.adjustedTempo.ToString("G999")}{(item.durCorrection >= 0 ? "+" : "")}{item.durCorrection}"; string relInputTemp = Path.GetRelativePath(PathManager.Inst.CachePath, item.inputTemp); writer.WriteLine($"@echo {MakeProgressBar(index + 1, total)}"); writer.WriteLine($"@call %helper% \"%oto%\\{relInputTemp}\" {toneName} {dur} {item.preutter} {item.offset} {item.durRequired} {item.consonant} {item.cutoff} {index}"); diff --git a/OpenUtau.Core/Classic/ResamplerItem.cs b/OpenUtau.Core/Classic/ResamplerItem.cs index c3a2f8c84..f91552343 100644 --- a/OpenUtau.Core/Classic/ResamplerItem.cs +++ b/OpenUtau.Core/Classic/ResamplerItem.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -6,6 +7,8 @@ using NAudio.Wave; using OpenUtau.Core; using OpenUtau.Core.Render; +using OpenUtau.Core.Ustx; +using static OpenUtau.Api.Phonemizer; namespace OpenUtau.Classic { public class ResamplerItem { @@ -64,29 +67,37 @@ public ResamplerItem(RenderPhrase phrase, RenderPhone phone) { consonant = phone.oto.Consonant; cutoff = phone.oto.Cutoff; - int pitchLeading = phrase.timeAxis.TicksBetweenMsPos(phone.positionMs - pitchLeadingMs, phone.positionMs); - int pitchSkip = (phrase.leading + phone.position - pitchLeading) / 5; - int pitchCount = (int)Math.Ceiling( - (double)phrase.timeAxis.TicksBetweenMsPos( - phone.positionMs - pitchLeadingMs, - phone.positionMs + phone.envelope[4].X) / 5); - tempo = phone.tempo; - pitches = phrase.pitches - .Skip(pitchSkip) - .Take(pitchCount) - .Select(pitch => (int)Math.Round(pitch - phone.tone * 100)) - .ToArray(); - if (pitchSkip < 0) { - pitches = Enumerable.Repeat(pitches[0], -pitchSkip) - .Concat(pitches) - .ToArray(); + tempo = phone.adjustedTempo; + + double pitchCountMs = (phone.positionMs + phone.envelope[4].X) - (phone.positionMs - pitchLeadingMs); + int pitchCount = (int)Math.Ceiling(MusicMath.TempoMsToTick(tempo, pitchCountMs) / 5.0); + pitchCount = Math.Max(pitchCount, 0); + pitches = new int[pitchCount]; + + double phoneStartMs = phone.positionMs - pitchLeadingMs; + double phraseStartMs = phrase.positionMs - phrase.leadingMs; + for (int i = 0; i < phone.tempos.Length; i++) { + double startMs = Math.Max(phrase.timeAxis.TickPosToMsPos(phone.tempos[i].position), phoneStartMs); + double endMs = i + 1 < phone.tempos.Length ? phrase.timeAxis.TickPosToMsPos(phone.tempos[i + 1].position) : phone.positionMs + phone.envelope[4].X; + double durationMs = endMs - startMs; + int tempoPitchCount = (int)Math.Floor(MusicMath.TempoMsToTick(tempo, durationMs) / 5.0); + int tempoPitchSkip = (int)Math.Floor(MusicMath.TempoMsToTick(tempo, startMs - phoneStartMs) / 5.0); + tempoPitchCount = Math.Min(tempoPitchCount, pitches.Length - tempoPitchSkip); + int phrasePitchSkip = (int)Math.Floor(phrase.timeAxis.TicksBetweenMsPos(phraseStartMs, startMs) / 5.0); + double tempoRatio = phone.tempos[i].bpm / tempo; + for (int j = 0; j < tempoPitchCount; j++) { + int index = tempoPitchSkip + j; + int scaled = phrasePitchSkip + (int)Math.Ceiling(j * tempoRatio); + scaled = Math.Clamp(scaled, 0, phrase.pitches.Length - 1); + index = Math.Clamp(index, 0, pitchCount - 1); + pitches[index] = (int)Math.Round(phrase.pitches[scaled] - phone.tone * 100); + } } hash = Hash(); outputFile = Path.Join(PathManager.Inst.CachePath, $"res-{XXH32.DigestOf(Encoding.UTF8.GetBytes(phrase.singer.Id)):x8}-{hash:x16}.wav"); } - public string GetFlagsString() { var builder = new StringBuilder(); foreach (var flag in flags) { diff --git a/OpenUtau.Core/Classic/VoicebankInstaller.cs b/OpenUtau.Core/Classic/VoicebankInstaller.cs index a34fffee0..a9f0e04c6 100644 --- a/OpenUtau.Core/Classic/VoicebankInstaller.cs +++ b/OpenUtau.Core/Classic/VoicebankInstaller.cs @@ -31,7 +31,9 @@ public VoicebankInstaller(string basePath, Action progress, Enco public void LoadArchive(string path) { progress.Invoke(0, "Analyzing archive..."); var readerOptions = new ReaderOptions { - ArchiveEncoding = new ArchiveEncoding(archiveEncoding, archiveEncoding) + ArchiveEncoding = new ArchiveEncoding { + Forced = archiveEncoding, + } }; var extractionOptions = new ExtractionOptions { Overwrite = true, diff --git a/OpenUtau.Core/Editing/LyricBatchEdits.cs b/OpenUtau.Core/Editing/LyricBatchEdits.cs index 9dc3c4e24..c658464d4 100644 --- a/OpenUtau.Core/Editing/LyricBatchEdits.cs +++ b/OpenUtau.Core/Editing/LyricBatchEdits.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using OpenUtau.Core.Ustx; using TinyPinyin; using WanaKanaNet; @@ -87,6 +88,19 @@ private bool ShouldRemove(char c) { } } + public class RemovePhoneticHint : SingleNoteLyricEdit { + static readonly Regex phoneticHintPattern = new Regex(@"\[(.*)\]"); + public override string Name => "pianoroll.menu.lyrics.removephonetichint"; + protected override string Transform(string lyric) { + var lrc = lyric; + lrc = phoneticHintPattern.Replace(lrc, match => ""); + if (string.IsNullOrEmpty(lrc)) { + return lyric; + } + return lrc; + } + } + public class DashToPlus : SingleNoteLyricEdit { public override string Name => "pianoroll.menu.lyrics.dashtoplus"; protected override string Transform(string lyric) { diff --git a/OpenUtau.Core/OpenUtau.Core.csproj b/OpenUtau.Core/OpenUtau.Core.csproj index c7395a4a4..c42f5c522 100644 --- a/OpenUtau.Core/OpenUtau.Core.csproj +++ b/OpenUtau.Core/OpenUtau.Core.csproj @@ -10,32 +10,34 @@ - - - - + + - + - - + + - + - - + + + + + + diff --git a/OpenUtau.Core/Render/RenderPhrase.cs b/OpenUtau.Core/Render/RenderPhrase.cs index c7f33e3b6..514623d6b 100644 --- a/OpenUtau.Core/Render/RenderPhrase.cs +++ b/OpenUtau.Core/Render/RenderPhrase.cs @@ -50,12 +50,14 @@ public class RenderPhone { public readonly int tone; public readonly int noteIndex; public readonly double tempo; + public readonly UTempo[] tempos; // classic args public readonly double preutterMs; public readonly double overlapMs; public readonly double durCorrectionMs; public readonly string resampler; + public readonly double adjustedTempo; public readonly Tuple[] flags; public readonly string suffix; public readonly float volume; @@ -78,11 +80,25 @@ internal RenderPhone(UProject project, UTrack track, UVoicePart part, UNote note this.phoneme = phoneme.phoneme; tone = note.tone; - tempo = project.timeAxis.GetBpmAtTick(part.position + phoneme.position); + tempos = project.timeAxis.TemposBetweenTicks(part.position + phoneme.position - leading, part.position + phoneme.End); + UTempo[] noteTempos = project.timeAxis.TemposBetweenTicks(part.position + phoneme.position, part.position + phoneme.End); + tempo = noteTempos[0].bpm; + + double actualTickDuration = 0; + for (int i = 0; i < noteTempos.Length; i++) { + int tempoStart = Math.Max(part.position + phoneme.position, noteTempos[i].position); + int tempoEnd = i + 1 < noteTempos.Length ? noteTempos[i + 1].position : part.position + phoneme.End; + int tempoLength = tempoEnd - tempoStart; + actualTickDuration += (double)(tempoLength * (tempo / noteTempos[i].bpm)); + } + + adjustedTempo = duration / actualTickDuration * tempo; + preutterMs = phoneme.preutter; overlapMs = phoneme.overlap; durCorrectionMs = phoneme.preutter - phoneme.tailIntrude + phoneme.tailOverlap; + resampler = track.RendererSettings.resampler; int eng = (int)phoneme.GetExpression(project, track, Format.Ustx.ENG).Item1; if (project.expressions.TryGetValue(Format.Ustx.ENG, out var descriptor) @@ -103,10 +119,10 @@ internal RenderPhone(UProject project, UTrack track, UVoicePart part, UNote note oto = phoneme.oto; hash = Hash(); } - private ulong Hash() { using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { + writer.Write(adjustedTempo); writer.Write(duration); writer.Write(phoneme ?? string.Empty); writer.Write(tone); diff --git a/OpenUtau.Core/SingerManager.cs b/OpenUtau.Core/SingerManager.cs index 95042cbb4..4e8eb90f0 100644 --- a/OpenUtau.Core/SingerManager.cs +++ b/OpenUtau.Core/SingerManager.cs @@ -15,16 +15,20 @@ namespace OpenUtau.Core { public class SingerManager : SingletonBase { public Dictionary Singers { get; private set; } = new Dictionary(); public Dictionary> SingerGroups { get; private set; } = new Dictionary>(); + public Task? InitializationTask = null; private readonly ConcurrentQueue reloadQueue = new ConcurrentQueue(); private CancellationTokenSource reloadCancellation; public void Initialize() { - SearchAllSingers(); + InitializationTask = Task.Run(() => { + SearchAllSingers(); + }); } public void SearchAllSingers() { try { + Log.Information("Searching singers."); Directory.CreateDirectory(PathManager.Inst.SingersPath); var stopWatch = Stopwatch.StartNew(); var singers = ClassicSingerLoader.FindAllSingers() diff --git a/OpenUtau.Core/Util/MusicMath.cs b/OpenUtau.Core/Util/MusicMath.cs index 6e066523f..93bdee862 100644 --- a/OpenUtau.Core/Util/MusicMath.cs +++ b/OpenUtau.Core/Util/MusicMath.cs @@ -189,5 +189,13 @@ public static void GetSnapUnit( div *= 2; } } + + public static double TempoMsToTick(double tempo, double ms) { + return (tempo * 480 * ms) / (60.0 * 1000.0); + } + + public static double TempoTickToMs(double tempo, int tick) { + return (60.0 * 1000.0 * tick) / (tempo * 480); + } } } diff --git a/OpenUtau.Core/Util/TimeAxis.cs b/OpenUtau.Core/Util/TimeAxis.cs index 31ea1640c..3296d9604 100644 --- a/OpenUtau.Core/Util/TimeAxis.cs +++ b/OpenUtau.Core/Util/TimeAxis.cs @@ -160,6 +160,14 @@ public void NextBarBeat(int bar, int beat, out int nextBar, out int nextBeat) { } } + public UTempo[] TemposBetweenTicks(int start, int end) { + var list = tempoSegments + .Where(tempo => start < tempo.tickEnd && tempo.tickPos < end) + .Select(tempo => new UTempo { position = tempo.tickPos, bpm = tempo.bpm }) + .ToArray(); + return list; + } + public UTimeSignature TimeSignatureAtTick(int tick) { var segment = timeSigSegments.First(seg => seg.tickPos == tick || seg.tickEnd > tick); // TODO: optimize return new UTimeSignature { diff --git a/OpenUtau.Core/Vogen/VogenRenderer.cs b/OpenUtau.Core/Vogen/VogenRenderer.cs index 8fdb6c2cd..6b9d8a938 100644 --- a/OpenUtau.Core/Vogen/VogenRenderer.cs +++ b/OpenUtau.Core/Vogen/VogenRenderer.cs @@ -145,7 +145,7 @@ float[] InvokeVogen(RenderPhrase phrase) { new DenseTensor(phonemes.ToArray(), new int[] { phonemes.Count }))); inputs.Add(NamedOnnxValue.CreateFromTensor("phDurs", new DenseTensor(phDurs.ToArray(), new int[] { phonemes.Count }))); - using (var session = new InferenceSession(Data.VogenRes.f0_man)) { + using (var session = Onnx.getInferenceSession(Data.VogenRes.f0_man)) { using var outputs = session.Run(inputs); var f0Out = outputs.First().AsTensor(); var f0Path = Path.Join(PathManager.Inst.CachePath, $"vog-{phrase.hash:x16}-f0.npy"); @@ -169,7 +169,7 @@ float[] InvokeVogen(RenderPhrase phrase) { new DenseTensor(breAmp, new int[] { 1, f0.Length }))); double[,] sp; double[,] ap; - using (var session = new InferenceSession(singer.model)) { + using (var session = Onnx.getInferenceSession(singer.model)) { using var outputs = session.Run(inputs); var mgc = outputs.First().AsTensor().Select(f => (double)f).ToArray(); var bap = outputs.Last().AsTensor().Select(f => (double)f).ToArray(); diff --git a/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs index 2d924ea0e..ede73fae6 100644 --- a/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/JapaneseCVVCPhonemizer.cs @@ -13,7 +13,7 @@ public class JapaneseCVVCPhonemizer : Phonemizer { "s","sh","z","j","t","ch","ty","ts", "d","dy","n","ny","h","hy","f","b", "by","p","py","m","my","y","r","4", - "ry","w","v","ng","l","・", + "ry","w","v","ng","l","・","B", "H", }; static readonly string[] vowels = new string[] { diff --git a/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs b/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs index 5f3bfbaef..ab6a2d547 100644 --- a/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/VietnameseCVVCPhonemizer.cs @@ -57,12 +57,27 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN }; } int totalDuration = notes.Sum(n => n.duration); - int Short = totalDuration * 4 / 6; - int Long = totalDuration / 6; - int Medium = totalDuration / 3; - int VCP = -80; - int End = totalDuration - 30; - int ViTri = Short; + int Short = 0; + int Long = 0; + int Medium = 0; + int VCP = 0; + int End = 0; + int ViTri = 0; + if (totalDuration < 350) { + Short = totalDuration * 4 / 7; + Long = totalDuration / 6; + Medium = totalDuration / 3; + VCP = -90; + End = totalDuration * 4 / 5; + ViTri = Short; + } else { + Short = totalDuration - 170; + Long = 90; + Medium = 180; + VCP = -90; + End = totalDuration - 50; + ViTri = Short; + } bool a; bool NoNext = nextNeighbour == null && note.lyric != "R"; var loi = note.lyric; @@ -125,6 +140,12 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN || loi.StartsWith("J") || loi.StartsWith("r") || loi.StartsWith("s") || loi.StartsWith("t") || loi.StartsWith("T") || loi.StartsWith("Z") || loi.StartsWith("v") || loi.StartsWith("w") || loi.StartsWith("z") || loi.StartsWith("p")); + int x = prevNeighbour?.duration ?? default(int); + if (x < 160 && prevNeighbour != null) { VCP = -(x * 4 / 7); } + else if (loi.StartsWith("b") || loi.StartsWith("d") || loi.StartsWith("g") || loi.StartsWith("d") || loi.StartsWith("k") || loi.StartsWith("l") + || loi.StartsWith("m") || loi.StartsWith("n") || loi.StartsWith("nh") || loi.StartsWith("ng") || loi.StartsWith("t") || loi.StartsWith("th") + || loi.StartsWith("v") || loi.StartsWith("w") || loi.StartsWith("y")) VCP = -50; + else VCP = -110; bool kocoC; if (tontaiC == true) { kocoC = false; diff --git a/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs b/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs index 744db85cd..9406ebe19 100644 --- a/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs +++ b/OpenUtau.Plugin.Builtin/VietnameseVCVPhonemizer.cs @@ -57,11 +57,24 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN }; } int totalDuration = notes.Sum(n => n.duration); - int Short = totalDuration * 4 / 7; - int Long = totalDuration / 6; - int Medium = totalDuration / 3; - int End = totalDuration - 30; - int ViTri = Short; + int Short = 0; + int Long = 0; + int Medium = 0; + int End = 0; + int ViTri = 0; + if (totalDuration < 350) { + Short = totalDuration * 4 / 8; + Long = totalDuration / 6; + Medium = totalDuration / 3; + End = totalDuration * 4 / 5; + ViTri = Short; + } else { + Short = totalDuration - 170; + Long = 90; + Medium = 180; + End = totalDuration - 50; + ViTri = Short; + } bool a; bool NoNext = nextNeighbour == null && note.lyric != "R"; var loi = note.lyric; diff --git a/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs b/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs new file mode 100644 index 000000000..899ac10c2 --- /dev/null +++ b/OpenUtau.Plugin.Builtin/VietnameseVINAPhonemizer.cs @@ -0,0 +1,2625 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenUtau.Api; +using OpenUtau.Core.Ustx; + +namespace OpenUtau.Plugin.Builtin { + [Phonemizer("Vietnamese VINA Phonemizer", "VIE VINA", "Jani Tran - Hoang Phuc", language:"VI")] + public class VietnameseVINAPhonemizer : Phonemizer { + /// + /// The lookup table to convert a hiragana to its tail vowel. + /// + static readonly string[] vowels = new string[] { + "a=a,à,á,ả,ã,ạ,ă,ằ,ắ,ẳ,ẵ,ặ,A,À,Á,Ả,Ã,Ạ,Ă,Ằ,Ắ,Ẳ,Ẵ,Ặ", + "A=â,ầ,ấ,ẩ,ẫ,ậ,Â,Ầ,Ấ,Ẩ,Ẫ,Ậ", + "@=ơ,ờ,ớ,ở,ỡ,ợ,Ơ,Ờ,Ớ,Ở,Ỡ,Ợ,@", + "i=i,y,ì,í,ỉ,ĩ,ị,ỳ,ý,ỷ,ỹ,ỵ,I,Y,Ì,Í,Ỉ,Ĩ,Ị,Ỳ,Ý,Ỷ,Ỹ,Ỵ", + "e=e,è,é,ẻ,ẽ,ẹ,E,È,É,Ẻ,Ẽ,Ẹ", + "E=ê,ề,ế,ể,ễ,ệ,Ê,Ề,Ế,Ể,Ễ,Ệ", + "o=o,ò,ó,ỏ,õ,ọ,O,Ò,Ó,Ỏ,Õ,Ọ", + "O=ô,ồ,ố,ổ,ỗ,ộ,Ô,Ồ,Ố,Ổ,Ỗ,Ộ", + "u=u,ù,ú,ủ,ũ,ụ,U,Ù,Ú,Ủ,Ũ,Ụ", + "U=ư,ừ,ứ,ử,ữ,ự,Ư,Ừ,Ứ,Ử,Ữ,Ự", + "m=m,M", + "n=n,N", + "ng=g,G", + "nh=h,H", + "-=c,C,t,T,-,p,P,R,'", + ".=.", + }; + + static readonly Dictionary vowelLookup; + + static VietnameseVINAPhonemizer() { + vowelLookup = vowels.ToList() + .SelectMany(line => { + var parts = line.Split('='); + return parts[1].Split(',').Select(cv => (cv, parts[0])); + }) + .ToDictionary(t => t.Item1, t => t.Item2); + } + + private USinger singer; + + public override void SetSinger(USinger singer) => this.singer = singer; + + // Legacy mapping. Might adjust later to new mapping style. + public override bool LegacyMapping => true; + + public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevNeighbour, Note? nextNeighbour, Note[] prevNeighbours) { + var note = notes[0]; + if (!string.IsNullOrEmpty(note.phoneticHint)) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { + phoneme = note.phoneticHint, + } + }, + }; + } + int totalDuration = notes.Sum(n => n.duration); + int Short = 0; + int Long = 0; + int Medium = 0; + int VCP = 0; + int End = 0; + int ViTri = 0; + if (totalDuration < 350) { + Short = totalDuration * 4 / 7; + Long = totalDuration / 6; + Medium = totalDuration / 3; + VCP = -90; + End = totalDuration * 4 / 5; + ViTri = Short; + } else { + Short = totalDuration - 170; + Long = 90; + Medium = 180; + VCP = -90; + End = totalDuration - 50; + ViTri = Short; + } + bool a; + bool NoNext = nextNeighbour == null && note.lyric != "R"; + var loi = note.lyric; + bool fry = note.lyric.EndsWith("'"); + if (note.lyric.StartsWith("?")) { + } else { + if (note.lyric != "R") { + loi = note.lyric.ToLower(); + note.lyric = note.lyric.ToLower(); + } + } + note.lyric = note.lyric.Replace('à', 'a').Replace('á', 'a').Replace('ả', 'a').Replace('ã', 'a').Replace('ạ', 'a'); + note.lyric = note.lyric.Replace('ằ', 'ă').Replace('ắ', 'ă').Replace('ẳ', 'ă').Replace('ẵ', 'ă').Replace('ặ', 'ă'); + note.lyric = note.lyric.Replace('ầ', 'â').Replace('ấ', 'â').Replace('ẩ', 'â').Replace('ẫ', 'â').Replace('ậ', 'â'); + note.lyric = note.lyric.Replace('ờ', 'ơ').Replace('ớ', 'ơ').Replace('ở', 'ơ').Replace('ỡ', 'ơ').Replace('ợ', 'ơ'); + note.lyric = note.lyric.Replace('ì', 'i').Replace('í', 'i').Replace('ỉ', 'i').Replace('ĩ', 'i').Replace('ị', 'i'); + note.lyric = note.lyric.Replace('ỳ', 'y').Replace('ý', 'y').Replace('ỷ', 'y').Replace('ỹ', 'y').Replace('ỵ', 'y'); + note.lyric = note.lyric.Replace('è', 'e').Replace('é', 'e').Replace('ẻ', 'e').Replace('ẽ', 'e').Replace('ẹ', 'e'); + note.lyric = note.lyric.Replace('ề', 'ê').Replace('ế', 'ê').Replace('ể', 'ê').Replace('ễ', 'ê').Replace('ệ', 'ê'); + note.lyric = note.lyric.Replace('ò', 'o').Replace('ó', 'o').Replace('ỏ', 'o').Replace('õ', 'o').Replace('ọ', 'o'); + note.lyric = note.lyric.Replace('ồ', 'ô').Replace('ố', 'ô').Replace('ổ', 'ô').Replace('ỗ', 'ô').Replace('ộ', 'ô'); + note.lyric = note.lyric.Replace('ù', 'u').Replace('ú', 'u').Replace('ủ', 'u').Replace('ũ', 'u').Replace('ụ', 'u'); + note.lyric = note.lyric.Replace('ừ', 'ư').Replace('ứ', 'ư').Replace('ử', 'ư').Replace('ữ', 'ư').Replace('ự', 'ư'); + if (note.lyric == "quôc") { + note.lyric = "quâc"; + } + if (note.lyric != "gi" && note.lyric != "gin" && note.lyric != "gim" && note.lyric != "ginh" && note.lyric != "ging" && note.lyric != "git" && note.lyric != "gip" && note.lyric != "gic" && note.lyric != "gich") { + loi = note.lyric.Replace('à', 'a').Replace('á', 'a').Replace('ả', 'a').Replace('ã', 'a').Replace('ạ', 'a'); + loi = note.lyric.Replace('ằ', 'ă').Replace('ắ', 'ă').Replace('ẳ', 'ă').Replace('ẵ', 'ă').Replace('ặ', 'ă'); + loi = note.lyric.Replace('ầ', 'â').Replace('ấ', 'â').Replace('ẩ', 'â').Replace('ẫ', 'â').Replace('ậ', 'â'); + loi = note.lyric.Replace('ờ', 'ơ').Replace('ớ', 'ơ').Replace('ở', 'ơ').Replace('ỡ', 'ơ').Replace('ợ', 'ơ'); + loi = note.lyric.Replace('ì', 'i').Replace('í', 'i').Replace('ỉ', 'i').Replace('ĩ', 'i').Replace('ị', 'i'); + loi = note.lyric.Replace('ỳ', 'y').Replace('ý', 'y').Replace('ỷ', 'y').Replace('ỹ', 'y').Replace('ỵ', 'y'); + loi = note.lyric.Replace('è', 'e').Replace('é', 'e').Replace('ẻ', 'e').Replace('ẽ', 'e').Replace('ẹ', 'e'); + loi = note.lyric.Replace('ề', 'ê').Replace('ế', 'ê').Replace('ể', 'ê').Replace('ễ', 'ê').Replace('ệ', 'ê'); + loi = note.lyric.Replace('ò', 'o').Replace('ó', 'o').Replace('ỏ', 'o').Replace('õ', 'o').Replace('ọ', 'o'); + loi = note.lyric.Replace('ồ', 'ô').Replace('ố', 'ô').Replace('ổ', 'ô').Replace('ỗ', 'ô').Replace('ộ', 'ô'); + loi = note.lyric.Replace('ù', 'u').Replace('ú', 'u').Replace('ủ', 'u').Replace('ũ', 'u').Replace('ụ', 'u'); + loi = note.lyric.Replace('ừ', 'ư').Replace('ứ', 'ư').Replace('ử', 'ư').Replace('ữ', 'ư').Replace('ự', 'ư'); + loi = note.lyric.Replace("ch", "C").Replace("d", "z").Replace("đ", "d").Replace("ph", "f").Replace("ch", "C") + .Replace("gi", "z").Replace("gh", "g").Replace("c", "k").Replace("kh", "K").Replace("ng", "N") + .Replace("ngh", "N").Replace("nh", "J").Replace("x", "s").Replace("tr", "C").Replace("th", "T") + .Replace("q", "k").Replace("r", "z"); + } else { + loi = note.lyric.Replace('ì', 'i').Replace('í', 'i').Replace('ỉ', 'i').Replace('ĩ', 'i').Replace('ị', 'i'); + loi = loi.Replace("gi", "zi").Replace("ng", "N").Replace("nh", "J").Replace("ch", "C").Replace("c", "k"); + } + bool tontaiVVC = loi.Contains("iên") || loi.Contains("iêN") || loi.Contains("iêm") || loi.Contains("iêt") || loi.Contains("iêk") || loi.Contains("iêp") || loi.Contains("iêu") + || loi.Contains("yên") || loi.Contains("yêN") || loi.Contains("yêm") || loi.Contains("yêt") || loi.Contains("yêk") || loi.Contains("yêp") || loi.Contains("yêu") + || loi.Contains("uôn") || loi.Contains("uôN") || loi.Contains("uôm") || loi.Contains("uôt") || loi.Contains("uôk") || loi.Contains("uôi") + || loi.Contains("ươn") || loi.Contains("ươN") || loi.Contains("ươm") || loi.Contains("ươt") || loi.Contains("ươk") || loi.Contains("ươp") || loi.Contains("ươi") || loi.Contains("ươu"); + int x = prevNeighbour?.duration ?? default(int); + if (x < 160 && prevNeighbour != null) { VCP = - (x * 4 / 7); } + else if (loi.StartsWith("b") || loi.StartsWith("d") || loi.StartsWith("g") || loi.StartsWith("d") || loi.StartsWith("k") || loi.StartsWith("l") + || loi.StartsWith("m") || loi.StartsWith("n") || loi.StartsWith("nh") || loi.StartsWith("ng") || loi.StartsWith("t") || loi.StartsWith("th") + || loi.StartsWith("v") || loi.StartsWith("w") || loi.StartsWith("y")) VCP = -50; + else VCP = -110; + bool koVVCchia; + if (tontaiVVC == true) { + koVVCchia = false; + } else + koVVCchia = true; + bool tontaiCcuoi = (loi.EndsWith("k") || loi.EndsWith("t") || loi.EndsWith("C") || loi.EndsWith("p") || loi.EndsWith(".")); + bool tontaiC = loi.StartsWith("b") || loi.StartsWith("C") || loi.StartsWith("d") || loi.StartsWith("f") + || loi.StartsWith("g") || loi.StartsWith("h") || loi.StartsWith("k") || loi.StartsWith("K") + || loi.StartsWith("l") || loi.StartsWith("m") || loi.StartsWith("n") || loi.StartsWith("N") + || loi.StartsWith("J") || loi.StartsWith("r") || loi.StartsWith("s") || loi.StartsWith("t") + || loi.StartsWith("T") || loi.StartsWith("Z") || loi.StartsWith("v") || loi.StartsWith("w") + || loi.StartsWith("z") || loi.StartsWith("p") || loi.StartsWith("'") || loi.StartsWith("."); + bool kocoC; + if (tontaiC == true) { + kocoC = false; + } else + kocoC = true; + bool BR = note.lyric.StartsWith("breath"); + bool tontaiVV = (loi.EndsWith("ai") || loi.EndsWith("ơi") || loi.EndsWith("oi") || loi.EndsWith("ôi") || loi.EndsWith("ui") || loi.EndsWith("ưi") + || loi.EndsWith("ao") || loi.EndsWith("eo") || loi.EndsWith("êu") || loi.EndsWith("iu") + || loi.EndsWith("an") || loi.EndsWith("ơn") || loi.EndsWith("in") || loi.EndsWith("en") || loi.EndsWith("ên") || loi.EndsWith("on") || loi.EndsWith("ôn") || loi.EndsWith("un") || loi.EndsWith("ưn") + || loi.EndsWith("am") || loi.EndsWith("ơm") || loi.EndsWith("im") || loi.EndsWith("em") || loi.EndsWith("êm") || loi.EndsWith("om") || loi.EndsWith("ôm") || loi.EndsWith("um") || loi.EndsWith("ưm") + || loi.EndsWith("aN") || loi.EndsWith("ơN") || loi.EndsWith("iN") || loi.EndsWith("eN") || loi.EndsWith("êN") || loi.EndsWith("ưN") + || loi.EndsWith("aJ") || loi.EndsWith("iJ") || loi.EndsWith("êJ") + || loi.EndsWith("at") || loi.EndsWith("ơt") || loi.EndsWith("it") || loi.EndsWith("et") || loi.EndsWith("êt") || loi.EndsWith("ot") || loi.EndsWith("ôt") || loi.EndsWith("ut") || loi.EndsWith("ưt") + || loi.EndsWith("aC") || loi.EndsWith("iC") || loi.EndsWith("êC") + || loi.EndsWith("ak") || loi.EndsWith("ơk") || loi.EndsWith("ik") || loi.EndsWith("ek") || loi.EndsWith("êk") || loi.EndsWith("ok") || loi.EndsWith("ôk") || loi.EndsWith("uk") || loi.EndsWith("ưk") + || loi.EndsWith("ap") || loi.EndsWith("ơp") || loi.EndsWith("ip") || loi.EndsWith("ep") || loi.EndsWith("êp") || loi.EndsWith("op") || loi.EndsWith("ôp") || loi.EndsWith("up") || loi.EndsWith("ưp") + || loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") + || loi.EndsWith("ay") || loi.EndsWith("ây") || loi.EndsWith("uy") + || loi.EndsWith("au") || loi.EndsWith("âu") + || loi.EndsWith("oa") || loi.EndsWith("oe") || loi.EndsWith("uê")); + bool ViTriNgan = (loi.EndsWith("ai") || loi.EndsWith("ơi") || loi.EndsWith("oi") || loi.EndsWith("ôi") || loi.EndsWith("ui") || loi.EndsWith("ưi") + || loi.EndsWith("ao") || loi.EndsWith("eo") || loi.EndsWith("êu") || loi.EndsWith("iu") + || loi.EndsWith("an") || loi.EndsWith("ơn") || loi.EndsWith("in") || loi.EndsWith("en") || loi.EndsWith("ên") || loi.EndsWith("on") || loi.EndsWith("ôn") || loi.EndsWith("un") || loi.EndsWith("ưn") + || loi.EndsWith("am") || loi.EndsWith("ơm") || loi.EndsWith("im") || loi.EndsWith("em") || loi.EndsWith("êm") || loi.EndsWith("om") || loi.EndsWith("ôm") || loi.EndsWith("um") || loi.EndsWith("ưm") + || loi.EndsWith("aN") || loi.EndsWith("ơN") || loi.EndsWith("iN") || loi.EndsWith("eN") || loi.EndsWith("êN") || loi.EndsWith("ưN") + || loi.EndsWith("at") || loi.EndsWith("ơt") || loi.EndsWith("it") || loi.EndsWith("et") || loi.EndsWith("êt") || loi.EndsWith("ot") || loi.EndsWith("ôt") || loi.EndsWith("ut") || loi.EndsWith("ưt") + || loi.EndsWith("ak") || loi.EndsWith("ơk") || loi.EndsWith("ik") || loi.EndsWith("ek") || loi.EndsWith("êk") || loi.EndsWith("ok") || loi.EndsWith("ôk") || loi.EndsWith("uk") || loi.EndsWith("ưk") + || loi.EndsWith("ap") || loi.EndsWith("ơp") || loi.EndsWith("ip") || loi.EndsWith("ep") || loi.EndsWith("êp") || loi.EndsWith("op") || loi.EndsWith("ôp") || loi.EndsWith("up") || loi.EndsWith("ưp") + || loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("uôN") + || loi.EndsWith("yt") || loi.EndsWith("yn") || loi.EndsWith("ym") || loi.EndsWith("yC") || loi.EndsWith("yp") || loi.EndsWith("yk") || loi.EndsWith("yN") + || loi.EndsWith("uya") && (note.lyric != "qua")); + bool ViTriDai = loi.EndsWith("uy") + || loi.EndsWith("au") || loi.EndsWith("âu") + || loi.EndsWith("oa") || loi.EndsWith("oe") || loi.EndsWith("uê") || note.lyric.EndsWith("qua"); + bool ViTriTB = loi.Contains("ăt") || loi.Contains("ât") || loi.EndsWith("oay") || loi.EndsWith("uây") || loi.EndsWith("ay") || loi.EndsWith("ây") + || loi.Contains("ăk") || loi.Contains("âk") || loi.EndsWith("oay'") || loi.EndsWith("uây'") || loi.EndsWith("ay'") || loi.EndsWith("ây'") + || loi.Contains("ăp") || loi.Contains("âp") + || loi.Contains("ăn") || loi.Contains("ân") + || loi.Contains("ăN") || loi.Contains("âN") + || loi.Contains("ăm") || loi.Contains("âm") + || loi.Contains("aJ") || loi.Contains("iJ") || loi.Contains("êJ") || loi.Contains("yJ") + || loi.Contains("ôN") || loi.Contains("uN") || loi.Contains("oN") + || loi.Contains("aC") || loi.Contains("iC") || loi.Contains("êC") || loi.Contains("yC"); + bool _C = loi.StartsWith("f") || loi.StartsWith("K") || loi.StartsWith("l") || loi.StartsWith("m") || loi.StartsWith("n") || loi.StartsWith("J") || loi.StartsWith("N") || loi.StartsWith("s") || loi.StartsWith("v") || loi.StartsWith("z"); + bool _Cw = loi.StartsWith("Ku") || loi.StartsWith("Koa") || loi.StartsWith("Koe") || loi.StartsWith("Koă") || loi.StartsWith("su") || loi.StartsWith("soa") || loi.StartsWith("soe") || loi.StartsWith("soă") || loi.StartsWith("zu") || loi.StartsWith("zoa") || loi.StartsWith("zoe") || loi.StartsWith("zoă") || loi.StartsWith("Ky") || loi.StartsWith("Ki"); + bool _CV = loi.StartsWith("g") || loi.StartsWith("h") || loi.StartsWith("'") || loi.StartsWith("w") || loi.StartsWith("y") || loi.StartsWith("'"); + bool wV = loi.Contains("oa") || loi.Contains("oe") || loi.Contains("uâ") || loi.Contains("uê") || loi.Contains("uy") || loi.Contains("uơ") || loi.Contains("oă"); + bool VV_ = (loi.EndsWith("ai") || loi.EndsWith("eo") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ơi") || loi.EndsWith("oi") || loi.EndsWith("ôi") || loi.EndsWith("ui") || loi.EndsWith("ưi") || loi.EndsWith("ya") + || loi.EndsWith("êu") || loi.EndsWith("ưu") || loi.EndsWith("ao") || loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("iu") + || loi.EndsWith("ai'") || loi.EndsWith("eo'") || loi.EndsWith("ua'") || loi.EndsWith("ưa'") || loi.EndsWith("ơi'") || loi.EndsWith("oi'") || loi.EndsWith("ôi'") || loi.EndsWith("ui'") || loi.EndsWith("ưi'") || loi.EndsWith("ya'") + || loi.EndsWith("êu'") || loi.EndsWith("ưu'") || loi.EndsWith("ao'") || loi.EndsWith("ia'") || loi.EndsWith("ua'") || loi.EndsWith("ưa'") || loi.EndsWith("iu'")) + && (note.lyric != "qua"); + bool wAn = loi.StartsWith("K") || loi.StartsWith("z"); + bool H = loi.StartsWith("b") || loi.StartsWith("d") || loi.StartsWith("k") || loi.StartsWith("l") + || loi.StartsWith("t") || loi.StartsWith("T") || loi.StartsWith("C") + || loi.StartsWith("m") || loi.StartsWith("n") || loi.StartsWith("J") + || loi.StartsWith("N") || loi.StartsWith("h") || loi.StartsWith("g") || loi.StartsWith("."); + if (ViTriTB) { + ViTri = Medium; + } + if (ViTriNgan) { + ViTri = Short; + } + if (ViTriDai) { + ViTri = Long; + } + if (loi.EndsWith("uôN")) { + ViTri = Short; + } + var phoneme = ""; + var dem = loi.Length; + + if (note.lyric.StartsWith("?")) { + phoneme = note.lyric.Substring(1); + } else if (prevNeighbour == null) { + if (note.lyric == "qua") { + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"kwa" }, + new Phoneme { phoneme = $"a -", position = End }, + } + }; + } else + phoneme = $"kwa"; + } else { + // 1 âm + if (dem == 1) { + string N = loi.Substring(0, 1); + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh") + .Replace("Z", "tr").Replace("T", "th"); + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {N}" }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else + phoneme = $"- {N}"; + } + // 2 âm CV, ví dụ: "ba" + if ((dem == 2) && tontaiC) { + string N = loi; + string N1 = loi.Substring(0, 1); + string N2 = loi.Substring(1, 1); + N1 = N1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh") + .Replace("Z", "tr").Replace("T", "th"); + if (_Cw) { + if (N2 == "u") + N1 = N1 + "w"; + if ((N2 == "i") || (N2 == "y")) + N1 = N1 + "y"; + } + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh") + .Replace("Z", "tr").Replace("T", "th"); + N2 = N2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + if (_CV) { N = "- " + N; } + if (NoNext) { // ko co note ke tiep + if (_C) { // co - C + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {N1}", position = VCP }, + new Phoneme { phoneme = $"{N}" }, + new Phoneme { phoneme = $"{N2} -", position = End }, + } + }; + } else // ko co gi + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{N}" }, + new Phoneme { phoneme = $"{N2} -", position = End }, + } + }; + } else // co note ke tiep + if (_C) { // co - C + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {N1}", position = VCP }, + new Phoneme { phoneme = $"{N}" }, + } + }; + } else // ko co gi + if (prevNeighbour == null) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{N}" }, + } + }; + } + } + // 3 âm CVV/CVC, ví dụ: "hoa" "hang" "hát" + if (fry) { } else + if (dem == 3 && tontaiC) { + string C = loi.Substring(0, 1); + string V1 = loi.Substring(1, 1); + string V2 = loi.Substring(2); + string V2_2 = V2; + string Cw = C; + string V1_1 = V1; + if (loi.EndsWith("uy")) { V2 = "i"; V2_2 = V2; } + bool kAn = loi.EndsWith("cân") || loi.EndsWith("kân"); + if (V1 == "â") V1 = "@"; + if (V1 == "ă") V1_1 = "ae"; + if (wV && _Cw) { + Cw = C + "w"; + V1 = "w"; + } else + if (wV) { + V1 = "w"; + } else if (_Cw) Cw = C + "w"; + if (V1 == "i" && _Cw) Cw = C + "y"; + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + V2_2 = V2_2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + V1_1 = V1_1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + V2 = "@"; + V2_2 = "@"; + } + string N = V2; + if (V1 + V2 == "Ong" || V1 + V2 == "ung" || V1 + V2 == "ong") { + N = "ng0"; + } + if (V1 + V2 == "Ai") { + V2 = "y"; + N = "i"; + } + if (loi.EndsWith("ay")) { + V2 = "y"; + N = "i"; + } + if (_CV) { C = "- " + C; } + if (tontaiCcuoi) { // co C cuoi (at, ac,...) + if (_C) { // co - C + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else + if (kAn) { + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"kAn" }, + new Phoneme { phoneme = $"n -", position = End }, + } + }; + } else { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"kAn" }, + } + }; + } + } else + if (NoNext) { // ko co note ke tiep + if (_C) { // co - C + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else { // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else // ko - C, - CV + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // co note ke tiep + if (_C) { // co - C + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + } + }; + } else { // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } + } else { //bth ko - C, ko - CV + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } + } + } + // 4 âm VVVC có VVC liền, chia 3 nốt, ví dụ "uyết" "uyên" + if (fry) { } else + if (dem == 4 && kocoC && tontaiVVC) { + string V1 = loi.Substring(0, 1); + string V2 = loi.Substring(1, 1); + string VVC = loi.Substring(1); + string C = loi.Substring(3); + if (V1 == "u") V1 = "w"; + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + C = C.Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (NoNext && tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{C} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + // 4 âm CVVC/CVVV, chia 3 nốt, ví dụ "thoát" "toan" "toại" + if (tontaiVVC) { } else + if (fry) { } else + if (dem == 4 && tontaiC) { + string C = loi.Substring(0, 1); + string Cw = C; + string V1 = loi.Substring(1, 1); + string V2 = loi.Substring(2, 1); + string V2_2 = V2; + string VC = loi.Substring(2); + string N = loi.Substring(3); + string N_ = N; + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + N = "@"; + N_ = "@"; + } + if (V1 == "u") V1 = "w"; + if (wV && _Cw) { + Cw = C + "w"; + V1 = "w"; + } else if (wV) + V1 = "w"; + if (V1 == "i") + Cw = C + "y"; + if (V2 == "ă") V2_2 = "ae"; + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "@").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VC = VC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N_ = N_.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (_CV) { C = "- " + C; } + if (tontaiCcuoi) { // có C ngắt + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VC}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VC}", position = ViTri }, + } + }; + } else + if (note.lyric.EndsWith("uân") || note.lyric.EndsWith("uâng")) { + if (wAn == false) { + if (NoNext) { + if (loi.StartsWith(".")) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w@" }, + new Phoneme { phoneme = $"A{N}", position = ViTri }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}wA{N}" }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}wA{N}" }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else { // + if (loi.StartsWith(".")) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w@" }, + new Phoneme { phoneme = $"A{N}", position = ViTri }, + } + }; + } else if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}wA{N}" }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}wA{N}" }, + } + }; + } + } else { // khuân luân + if (NoNext) { + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"_w@", position = Long }, + new Phoneme { phoneme = $"A{N}", position = Medium }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"_w@", position = Long }, + new Phoneme { phoneme = $"A{N}", position = Medium }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else { // + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"_w@", position = Long }, + new Phoneme { phoneme = $"A{N}", position = Medium }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"_w@", position = Long }, + new Phoneme { phoneme = $"A{N}", position = Medium }, + } + }; + } + } + } else + if (NoNext) { + if (VV_) { + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N_} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N_} -", position = End }, + } + }; + } else { // ko có VV - + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } + } else { + if (VV_) { + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N}", position = ViTri }, + } + }; + } else { // ko có VV - + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + } + }; + } + } + } + // 4 âm CVVC/CVVV, (tiên, tiết) + if (fry) { } else + if (dem == 4 && tontaiVVC && tontaiC) { + string C = loi.Substring(0, 1); + string Cw = C; + string V1 = loi.Substring(1, 1); + string VVC = loi.Substring(1); + string N = loi.Substring(3); + if (V1 == "i" && _Cw) { + Cw = C + "y"; + } + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("N", "ng").Replace("J", "nh"); + if (_CV) { C = "- " + C; } + if (tontaiCcuoi) { // có C ngắt + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko có note kế tiếp + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // có note kế tiếp + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } + // 5 âm CVVVC, có VVC liền, chia 3 nốt, ví dụ "thuyết" + if (fry) { } else + if (dem == 5 && tontaiVVC && tontaiC) { + string C = loi.Substring(0, 1); + string Cw = C; + string V1 = loi.Substring(1, 1); + string V2 = loi.Substring(2, 1); + string VVC = loi.Substring(2); + string N = loi.Substring(4); + if (wV && _Cw) { + Cw = C + "w"; + V1 = "w"; + } else if (wV) + V1 = "w"; + if (V1 == "i") + Cw = C + "y"; + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("N", "ng").Replace("J", "nh"); + if (_CV) { C = "- " + C; } + if (tontaiCcuoi) { // có C ngắt + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko có note kế tiếp + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // có note kế tiếp + if (_C) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } + if (BR) { + string num = loi.Substring(5); + if (num == "") { + num = "1"; + } + if (prevNeighbour == null) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"breath{num}" }, + } + }; + } + } + if (note.lyric.StartsWith("y") && koVVCchia) { + if (dem == 2) { // ya + string C = note.lyric.Substring(0, 1); + string V = note.lyric.Substring(1, 1); + V = V.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V}" }, + new Phoneme { phoneme = $"{V} -", position = ViTri }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V}" }, + } + }; + } + else if (dem == 3) { + string C = note.lyric.Substring(0, 1); + string V1 = note.lyric.Substring(1, 1); + string V2 = note.lyric.Substring(2, 1); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (wV) { + V1 = "w"; + } + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + V2 = "@"; + } + string N = V2; + if (V1 + V2 == "Ong" || V1 + V2 == "ung" || V1 + V2 == "ong") { + N = "ng0"; + } + if (V1 + V2 == "Ai") { + V2 = "y"; + N = "i"; + } + if (loi.EndsWith("ay")) { + V2 = "y"; + N = "i"; + } + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } else + if (NoNext) { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}{V2}" }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } + } // phụ âm y + else { // nếu ko phải phụ âm y + // 2 âm VV, ví dụ: "oa" + if (fry) { } else + if ((dem == 2) && kocoC) { + string V1 = loi.Substring(0, 1); + string V1_ = V1; + string V2 = loi.Substring(1, 1); + string N = V2; + if (loi.StartsWith("uy")) V2 = "i"; + if (V1 + V2 == "ôN" || V1 + V2 == "uN" || V1 + V2 == "oN") { + N = "ng0"; + } + if (V2 == "y") + N = "i"; + if (wV) { + V1 = "w"; + } + if (V1 == "â") { + V1 = "@"; + } + if (V1 + V2 == "ia" || V1 + V2 == "ua" || V1 + V2 == "ưa") + N = "@"; + if (V1 == "ă") { + V1_ = "ae"; + } + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V1_ = V1_.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa")); + if (a) { + V2 = "@"; + } + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko co note ke tiep + if (wV) { // oa oe uê ,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else + if (VV_) { // ai eo êu ao,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{V1}{N} -", position = End }, + } + }; + } else { // an anh + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{V1_}{V2}",position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else { // co note ke tiep + if (wV) { // oa oe uê ,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + } + }; + } else + if (VV_) { // ai eo êu ao,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{V1}{N}", position = ViTri }, + } + }; + } else { // an anh + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{V1_}{V2}",position = ViTri }, + } + }; + } + } + } + // 3 âm VVC/VVV, ví dụ: "oát" "oan" "oai" + if (fry) { } else + if ((dem == 3) && koVVCchia && kocoC) { + string V1 = loi.Substring(0, 1); + string V2 = loi.Substring(1, 1); + string V2_2 = V2; + string V3 = loi.Substring(2, 1); + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + V3 = "@"; + } + if (wV) { + V1 = "w"; + } + if (V2 == "ă") { + V2_2 = "ae"; + } + if (V2 == "â") { + V2 = "@"; + } + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V2_2 = V2_2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V3 = V3.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + string N = V3; + if (V2 + V3 == "Ong" || V2 + V3 == "ung" || V2 + V3 == "ong") { + N = "ng0"; + } + if (V3 == "y") N = "i"; + if (tontaiCcuoi && wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{V3}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko co note ke tiep + if (wV && VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N} -", position = End }, + } + }; + } else + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else { // co note ke tiep + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + } + }; + } + } + } + // 3 âm VVV/VVC chia 2 nốt, ví dụ: "yên" "ướt" + if ((dem == 3) && tontaiVVC && kocoC) { + string V1 = loi.Substring(0, 1); + string VVC = loi.Substring(0); + string C = loi.Substring(2); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + C = C.Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (NoNext && tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{C} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } + } + } else + if (prevNeighbour != null) { + var lyric = prevNeighbour?.phoneticHint ?? prevNeighbour?.lyric; + var unicode = ToUnicodeElements(lyric); + if (vowelLookup.TryGetValue(unicode.LastOrDefault() ?? string.Empty, out var vow)) { + string PR = prevNeighbour?.lyric; + if (PR.EndsWith("nh")) { + vow = "nh"; + } + if (PR.EndsWith("ng")) { + vow = "ng"; + } + if (PR.EndsWith("ch") || PR.EndsWith("t") || PR.EndsWith("k") || PR.EndsWith("p")) { + vow = "-"; + } + if (PR != "R") { + PR = PR.ToLower(); + } + if (PR == "gi") { + PR = "zi"; + } + PR = PR.Replace('à', 'a').Replace('á', 'a').Replace('ả', 'a').Replace('ã', 'a').Replace('ạ', 'a'); + PR = PR.Replace('ằ', 'ă').Replace('ắ', 'ă').Replace('ẳ', 'ă').Replace('ẵ', 'ă').Replace('ặ', 'ă'); + PR = PR.Replace('ầ', 'â').Replace('ấ', 'â').Replace('ẩ', 'â').Replace('ẫ', 'â').Replace('ậ', 'â'); + PR = PR.Replace('ờ', 'ơ').Replace('ớ', 'ơ').Replace('ở', 'ơ').Replace('ỡ', 'ơ').Replace('ợ', 'ơ'); + PR = PR.Replace('ì', 'i').Replace('í', 'i').Replace('ỉ', 'i').Replace('ĩ', 'i').Replace('ị', 'i'); + PR = PR.Replace('ỳ', 'y').Replace('ý', 'y').Replace('ỷ', 'y').Replace('ỹ', 'y').Replace('ỵ', 'y'); + PR = PR.Replace('è', 'e').Replace('é', 'e').Replace('ẻ', 'e').Replace('ẽ', 'e').Replace('ẹ', 'e'); + PR = PR.Replace('ề', 'ê').Replace('ế', 'ê').Replace('ể', 'ê').Replace('ễ', 'ê').Replace('ệ', 'ê'); + PR = PR.Replace('ò', 'o').Replace('ó', 'o').Replace('ỏ', 'o').Replace('õ', 'o').Replace('ọ', 'o'); + PR = PR.Replace('ồ', 'ô').Replace('ố', 'ô').Replace('ổ', 'ô').Replace('ỗ', 'ô').Replace('ộ', 'ô'); + PR = PR.Replace('ù', 'u').Replace('ú', 'u').Replace('ủ', 'u').Replace('ũ', 'u').Replace('ụ', 'u'); + PR = PR.Replace('ừ', 'ư').Replace('ứ', 'ư').Replace('ử', 'ư').Replace('ữ', 'ư').Replace('ự', 'ư'); + PR = PR.Replace("ch", "C").Replace("d", "z").Replace("đ", "d").Replace("ph", "f").Replace("ch", "C") + .Replace("gi", "z").Replace("gh", "g").Replace("c", "k").Replace("kh", "K").Replace("ng", "N") + .Replace("ngh", "N").Replace("nh", "J").Replace("x", "s").Replace("tr", "Z").Replace("th", "T") + .Replace("qu", "w"); + if (loi == "R") { + a = (PR.EndsWith("ua") || PR.EndsWith("ưa") || PR.EndsWith("ia") || PR.EndsWith("uya")); + if (a) { + vow = "@"; + } + } else { + a = (PR.EndsWith("ua") || PR.EndsWith("ưa") || PR.EndsWith("ia") || PR.EndsWith("uya")); + if (a) { + vow = "@0"; + } + a = (PR.EndsWith("breaT")); + if (a) { + vow = "-"; + } + if (PR.EndsWith("ao") || PR.EndsWith("eo") || PR.EndsWith("êu") || PR.EndsWith("iu") || PR.EndsWith("ưu")) { + vow = "u0"; + } + if (PR.EndsWith("ai") || PR.EndsWith("ơi") || PR.EndsWith("oi") || PR.EndsWith("ôi") || PR.EndsWith("ui") || PR.EndsWith("ưi")) { + vow = "i0"; + } + } + bool ng0 = (PR.EndsWith("uN") || PR.EndsWith("ôN") || PR.EndsWith("oN")); + if (PR.EndsWith("uôN")) { + vow = "ng"; + } else if (ng0) { + vow = "ng0"; + } + bool prevtontaiCcuoi = PR.EndsWith("t") || PR.EndsWith("C") || PR.EndsWith("p") || PR.EndsWith("k") || PR.EndsWith("'"); + if (prevtontaiCcuoi && _C) { + if (PR.EndsWith("t")) vow = "t"; + if (PR.EndsWith("C")) vow = "ch"; + if (PR.EndsWith("p")) vow = "p"; + if (PR.EndsWith("k")) vow = "k"; + if (PR.EndsWith("'")) vow = "-"; + } + string B1 = PR.Substring(PR.Length - 1); + string B2 = loi.Substring(0, 1); + bool M = (B1 == B2) && vow != "ng0"; + bool NoVCP = (H && prevtontaiCcuoi) || M; + bool prevkocoCcuoi; + bool Cvoiced = PR.EndsWith("J") || PR.EndsWith("n") || PR.EndsWith("m") || PR.EndsWith("N"); + if (prevtontaiCcuoi == true) { + prevkocoCcuoi = false; + } else prevkocoCcuoi = true; + if (note.lyric.StartsWith("?")) { + phoneme = note.lyric.Substring(1); + } else { + if (note.lyric == "qua") { + if (NoVCP) { + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"kwa" }, + new Phoneme { phoneme = $"a -", position = End }, + } + }; + } else + phoneme = $"kwa"; + } else + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow} k", position = VCP }, + new Phoneme { phoneme = $"kwa" }, + new Phoneme { phoneme = $"a -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow} k", position = VCP }, + new Phoneme { phoneme = $"kwa" }, + } + }; + } else { + // 1 âm + if (dem == 1 && loi != "R") { + string N = loi; + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh") + .Replace("Z", "tr").Replace("T", "th"); + string N2 = N; + bool A = (vow == "o" || vow == "O" || vow == "u"); + if (A && loi == "ng") N2 = "ng0"; + if (loi == "N" || loi == "n" || loi == "J" || loi == "m") { } else + vow = vow + " "; + if ((loi == "N" || loi == "n" || loi == "J" || loi == "m") && prevtontaiCcuoi) { vow = "- "; } else if (prevtontaiCcuoi) + vow = "."; + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{N}" }, + new Phoneme { phoneme = $"{N2} -", position = End }, + } + }; + } else { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{N}" }, + } + }; + } + } + if (note.lyric == "R") { // R + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow} --" }, + } + }; + } + // 2 âm CV, ví dụ: "ba" + if ((dem == 2) && tontaiC) { + string N = loi; + string N1 = loi.Substring(0, 1); + string N2 = loi.Substring(1, 1); + N1 = N1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh") + .Replace("Z", "tr").Replace("T", "th"); + if (_Cw) { + if (N2 == "u") + N1 = N1 + "w"; + if ((N2 == "i") || (N2 == "y")) + N1 = N1 + "y"; + } + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh") + .Replace("Z", "tr").Replace("T", "th"); + N2 = N2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + if (_CV && prevtontaiCcuoi) { N = "- " + N; } + vow = vow + " "; + if (NoNext) { // ko co note ke tiep + if (NoVCP) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{N}" }, + new Phoneme { phoneme = $"{N2} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{N1}", position = VCP }, + new Phoneme { phoneme = $"{N}" }, + new Phoneme { phoneme = $"{N2} -", position = End }, + } + }; + } else // co note ke tiep + if (NoVCP) { // co - C + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{N}" }, + } + }; + } else // ko co gi + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{N1}", position = VCP }, + new Phoneme { phoneme = $"{N}" }, + } + }; + } + // 3 âm CVV/CVC, ví dụ: "hoa" "hang" "hát" + if (fry) { } else + if (dem == 3 && tontaiC) { + string C = loi.Substring(0, 1); + string V1 = loi.Substring(1, 1); + string V2 = loi.Substring(2); + string V2_2 = V2; + string Cw = C; + string V1_1 = V1; + if (loi.EndsWith("uy")) { V2 = "i"; V2_2 = V2; } + bool kAn = loi.EndsWith("cân") || loi.EndsWith("kân"); + if (V1 == "â") V1 = "@"; + if (V1 == "ă") V1_1 = "ae"; + if (wV && _Cw) { + Cw = C + "w"; + V1 = "w"; + } else + if (wV) { + V1 = "w"; + } else if (_Cw) Cw = C + "w"; + if (V1 == "i" && _Cw) Cw = C + "y"; + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + V2_2 = V2_2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + V1_1 = V1_1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + V2 = "@"; + V2_2 = "@"; + } + string N = V2; + if (V1 + V2 == "Ong" || V1 + V2 == "ung" || V1 + V2 == "ong") { + N = "ng0"; + } + if (V1 + V2 == "Ai") { + V2 = "y"; + N = "i"; + } + if (loi.EndsWith("ay")) { + V2 = "y"; + N = "i"; + } + if (_CV && prevtontaiCcuoi) { C = "- " + C; } + vow = vow + " "; + if (NoVCP) { + if (tontaiCcuoi) { // co C cuoi (at, ac,...) + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else + if (kAn) { + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"kAn" }, + new Phoneme { phoneme = $"n -", position = End }, + } + }; + } else { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"kAn" }, + } + }; + } + } else + if (NoNext) { // ko co note ke tiep + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // co note ke tiep + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } + } else + if (tontaiCcuoi) { // co C cuoi (at, ac,...) + if (_C) { // co - C + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else + if (kAn) { + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}k", position = VCP }, + new Phoneme { phoneme = $"kAn" }, + new Phoneme { phoneme = $"n -", position = End }, + } + }; + } else { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}k", position = VCP }, + new Phoneme { phoneme = $"kAn" }, + } + }; + } + } else + if (NoNext) { // ko co note ke tiep + if (_C) { // co - C + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else { // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else // ko - C, - CV + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // co note ke tiep + if (_C) { // co - C + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + } + }; + } else { // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } + } else { //bth ko - C, ko - CV + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2_2}" }, + } + }; + } else // bths + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1_1}{V2_2}", position = ViTri }, + } + }; + } + } + } + // 4 âm VVVC có VVC liền, chia 3 nốt, ví dụ "uyết" "uyên" + if (fry) { } else + if (dem == 4 && kocoC && tontaiVVC) { + string V1 = loi.Substring(0, 1); + string V2 = loi.Substring(1, 1); + string VVC = loi.Substring(1); + string C = loi.Substring(3); + if (V1 == "u") V1 = "w"; + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + C = C.Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (prevtontaiCcuoi) vow = "."; else vow = vow + " "; + if (prevtontaiCcuoi) { + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{C} -", position = End }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext && tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{C} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + // 4 âm CVVC/CVVV, chia 3 nốt, ví dụ "thoát" "toan" "toại" + if (tontaiVVC) { } else + if (fry) { } else + if (dem == 4 && tontaiC) { + string C = loi.Substring(0, 1); + string Cw = C; + string V1 = loi.Substring(1, 1); + string V2 = loi.Substring(2, 1); + string V2_2 = V2; + string VC = loi.Substring(2); + string N = loi.Substring(3); + string N_ = N; + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + N = "@"; + N_ = "@"; + } + if (V1 == "u") V1 = "w"; + if (wV && _Cw) { + Cw = C + "w"; + V1 = "w"; + } else if (wV) + V1 = "w"; + if (V1 == "i") + Cw = C + "y"; + if (V2 == "ă") V2_2 = "ae"; + if (V2 == "â") V2 = "@"; + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2_2 = V2_2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VC = VC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N_ = N_.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (_CV && prevtontaiCcuoi) { N = "- " + N; } + vow = vow + " "; + if (NoVCP) { + if (tontaiCcuoi) { // có C ngắt + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VC}", position = ViTri }, + } + }; + } else + if (note.lyric.EndsWith("uân")) { + if (wAn == false) { + if (NoNext) { + if (loi.StartsWith(".")) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w@" }, + new Phoneme { phoneme = $"An", position = ViTri }, + new Phoneme { phoneme = $"n -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}wAn" }, + new Phoneme { phoneme = $"n -", position = End }, + } + }; + } else { // + if (loi.StartsWith(".")) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w@" }, + new Phoneme { phoneme = $"An", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}wAn" }, + } + }; + } + } else { // khuân luân + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"w@", position = Long }, + new Phoneme { phoneme = $"An", position = Medium }, + new Phoneme { phoneme = $"n -", position = End }, + } + }; + } else { // + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"w@", position = Long }, + new Phoneme { phoneme = $"An", position = Medium }, + } + }; + } + } + } else + if (NoNext) { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N} -", position = End }, + } + }; + } else { // ko có VV - + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N}", position = ViTri }, + } + }; + } else { // ko có VV - + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + } + }; + } + } + } else + if (tontaiCcuoi) { // có C ngắt + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VC}", position = ViTri }, + } + }; + } else + if (note.lyric.EndsWith("uân") || note.lyric.EndsWith("uâng")) { + if (wAn == false) { + if (NoNext) { + if (loi.StartsWith(".")) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}w@" }, + new Phoneme { phoneme = $"A{N}", position = ViTri }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}wA{N}" }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else { // + if (loi.StartsWith(".")) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}w@" }, + new Phoneme { phoneme = $"A{N}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}wA{N}" }, + } + }; + } + } else { // khuân luân + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"_w@", position = Long }, + new Phoneme { phoneme = $"A{N}", position = Medium }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } else { // + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}w" }, + new Phoneme { phoneme = $"_w@", position = Long }, + new Phoneme { phoneme = $"A{N}", position = Medium }, + } + }; + } + } + } else + if (NoNext) { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N_} -", position = End }, + } + }; + } else { // ko có VV - + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + new Phoneme { phoneme = $"{N_} -", position = End }, + } + }; + } + } else { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2}{N}", position = ViTri }, + } + }; + } else { // ko có VV - + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N}", position = ViTri }, + } + }; + } + } + } + // 4 âm CVVC/CVVV, (tiên, tiết) + if (fry) { } else + if (dem == 4 && tontaiVVC && tontaiC) { + string C = loi.Substring(0, 1); + string Cw = C; + string V1 = loi.Substring(1, 1); + string VVC = loi.Substring(1); + string N = loi.Substring(3); + if (V1 == "i" && _Cw) { + Cw = C + "y"; + } + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("N", "ng").Replace("J", "nh"); + if (_CV && prevtontaiCcuoi) { C = "- " + C; } + vow = vow + " "; + if (NoVCP) { + if (tontaiCcuoi) { // có C ngắt + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } else + if (tontaiCcuoi) { // có C ngắt + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } + // 5 âm CVVVC, có VVC liền, chia 3 nốt, ví dụ "thuyết" + if (fry) { } else + if (dem == 5 && tontaiVVC && tontaiC) { + string C = loi.Substring(0, 1); + string Cw = C; + string V1 = loi.Substring(1, 1); + string V2 = loi.Substring(2, 1); + string VVC = loi.Substring(2); + string N = loi.Substring(4); + if (wV && _Cw) { + Cw = C + "w"; + V1 = "w"; + } else if (wV) + V1 = "w"; + if (V1 == "i") + Cw = C + "y"; + C = C.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + Cw = Cw.Replace("C", "ch").Replace("K", "kh").Replace("N", "ng").Replace("J", "nh").Replace("Z", "tr").Replace("T", "th"); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("N", "ng").Replace("J", "nh"); + if (_CV && prevtontaiCcuoi) { N = "- " + N; } + vow = vow + " "; + if (NoVCP) { + if (tontaiCcuoi) { // có C ngắt + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } else + if (tontaiCcuoi) { // có C ngắt + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // có note kế tiếp + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{Cw}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } + // y + if (note.lyric.StartsWith("y") && koVVCchia) { + if (dem == 2) { // ya + string C = note.lyric.Substring(0, 1); + string V = note.lyric.Substring(1, 1); + V = V.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + vow = vow + " "; + if (prevtontaiCcuoi) { + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V}" }, + new Phoneme { phoneme = $"{V} -", position = End }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V}" }, + } + }; + } else + if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V}" }, + new Phoneme { phoneme = $"{V} -", position = End }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V}" }, + } + }; + } else if (dem == 3) { + string C = note.lyric.Substring(0, 1); + string V1 = note.lyric.Substring(1, 1); + string V2 = note.lyric.Substring(2, 1); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (wV) { + V1 = "w"; + } + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a && note.lyric != "qua") { + V2 = "@"; + } + string N = V2; + if (V1 + V2 == "Ong" || V1 + V2 == "ung" || V1 + V2 == "ong") { + N = "ng0"; + } + if (V1 + V2 == "Ai") { + V2 = "y"; + N = "i"; + } + if (loi.EndsWith("ay")) { + V2 = "y"; + N = "i"; + } + vow = vow + " "; + if (prevtontaiCcuoi) { + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } + else + if (NoNext) { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}{V2}" }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"- {C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } else + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } else + if (NoNext) { + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2} -", position = End }, + } + }; + } else if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + new Phoneme { phoneme = $"{V2} -", position = End }, + } + }; + } else + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}{V2}" }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{C}", position = VCP }, + new Phoneme { phoneme = $"{C}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } + } + else { // nếu ko phải phụ âm y + // 2 âm VV, ví dụ: "oa" + if (fry) { } else + if ((dem == 2) && kocoC) { + string V1 = loi.Substring(0, 1); + string V1_ = V1; + string V2 = loi.Substring(1, 1); + string N = V2; + if (loi.StartsWith("uy")) V2 = "i"; + if (V1 + V2 == "ôN" || V1 + V2 == "uN" || V1 + V2 == "oN") { + N = "ng0"; + } + if (V2 == "y") + N = "i"; + if (wV) { + V1 = "w"; + } + if (V1 == "â") { + V1 = "@"; + } + if (V1 + V2 == "ia" || V1 + V2 == "ua" || V1 + V2 == "ưa") + N = "@"; + if (V1 == "ă") { + V1_ = "ae"; + } + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V1_ = V1_.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + N = N.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O").Replace("ư", "U") + .Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa")); + if (a) { + V2 = "@"; + } + if (prevtontaiCcuoi) vow = "."; else vow = vow + " "; + if (prevtontaiCcuoi) { + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko co note ke tiep + if (wV) { // oa oe uê ,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else + if (VV_) { // ai eo êu ao,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1}{N} -", position = End }, + } + }; + } else { // an anh + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1_}{V2}",position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else { // co note ke tiep + if (wV) { // oa oe uê ,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + } + }; + } else + if (VV_) { // ai eo êu ao,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1}{N}", position = ViTri }, + } + }; + } else { // an anh + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1_}{V2}",position = ViTri }, + } + }; + } + } + } else + if (tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1}{V2}", position = ViTri }, + } + }; + } else + if (NoNext) { // ko co note ke tiep + if (wV) { // oa oe uê ,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else + if (VV_) { // ai eo êu ao,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1}{N} -", position = End }, + } + }; + } else { // an anh + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1_}{V2}",position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else { // co note ke tiep + if (wV) { // oa oe uê ,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + } + }; + } else + if (VV_) { // ai eo êu ao,... + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1}{N}", position = ViTri }, + } + }; + } else { // an anh + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{V1_}{V2}",position = ViTri }, + } + }; + } + } + } + // 3 âm VVC/VVV, ví dụ: "oát" "oan" "oai" "uân" + if (fry) { } else + if ((dem == 3) && koVVCchia && kocoC) { + string V1 = loi.Substring(0, 1); + string V2 = loi.Substring(1, 1); + string V2_2 = V2; + string V3 = loi.Substring(2, 1); + a = (loi.EndsWith("ia") || loi.EndsWith("ua") || loi.EndsWith("ưa") || loi.EndsWith("ya")); + if (a) { + V3 = "@"; + } + if (wV) { + V1 = "w"; + } + if (V2 == "ă") { + V2_2 = "ae"; + } + if (V2 == "â") { + V2 = "@"; + } + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V2 = V2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + V2_2 = V2_2.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + + V3 = V3.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + string N = V3; + if (V3 == "y") N = "i"; + if (V2 + V3 == "Ong" || V2 + V3 == "ung" || V2 + V3 == "ong") { + N = "ng0"; + } + if (prevtontaiCcuoi) vow = "."; else vow = vow + " "; + if (prevtontaiCcuoi) { + if (NoNext) { // ko co note ke tiep + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } else { // co note ke tiep + if (VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + } + }; + } + } else { + if (NoNext) { // ko co note ke tiep + if (wV && VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{N} -", position = End }, + } + }; + } else + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + new Phoneme { phoneme = $"{N} -", position = End }, + } + }; + } + } else { // co note ke tiep + if (wV && VV_) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + } + }; + } else + if (wV) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}", position = VCP }, + new Phoneme { phoneme = $"{V1}{V2}" }, + new Phoneme { phoneme = $"{V2_2}{V3}", position = ViTri }, + } + }; + } + } + } + } + // 3 âm VVV/VVC chia 2 nốt, ví dụ: "yên" "ướt" + if ((dem == 3) && tontaiVVC && kocoC) { + string V1 = loi.Substring(0, 1); + string VVC = loi.Substring(0); + string C = loi.Substring(2); + V1 = V1.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U"); + VVC = VVC.Replace("ă", "a").Replace("â", "A").Replace("ơ", "@").Replace("y", "i").Replace("ê", "E").Replace("ô", "O") + .Replace("ư", "U").Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + C = C.Replace("C", "ch").Replace("N", "ng").Replace("J", "nh"); + if (prevtontaiCcuoi) vow = "."; else vow = vow + " "; + if (NoNext && tontaiCcuoi) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } else if (NoNext) { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + new Phoneme { phoneme = $"{C} -", position = End }, + } + }; + } else + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow}{V1}" }, + new Phoneme { phoneme = $"{VVC}", position = ViTri }, + } + }; + } + } + // BR + if (BR) { + string num = loi.Substring(5); + if (num == "") { + num = "1"; + } + if (vow == "-") { + return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"breath{num}" }, + } + }; + } else return new Result { + phonemes = new Phoneme[] { + new Phoneme { phoneme = $"{vow} -", position = -60 }, + new Phoneme { phoneme = $"breath{num}" }, + } + }; + } + } + } + } + } + // Get color + string color = string.Empty; + int toneShift = 0; + if (note.phonemeAttributes != null) { + var attr = note.phonemeAttributes.FirstOrDefault(attr => attr.index == 0); + color = attr.voiceColor; + toneShift = attr.toneShift; + } + if (singer.TryGetMappedOto(phoneme, note.tone + toneShift, color, out var oto)) { + phoneme = oto.Alias; + } else { + phoneme = note.lyric; + } + return new Result { + phonemes = new Phoneme[] { + new Phoneme { + phoneme = phoneme, + } + }, + }; + } + } +} diff --git a/OpenUtau.Test/OpenUtau.Test.csproj b/OpenUtau.Test/OpenUtau.Test.csproj index 78f0bcce1..b147e02a0 100644 --- a/OpenUtau.Test/OpenUtau.Test.csproj +++ b/OpenUtau.Test/OpenUtau.Test.csproj @@ -11,16 +11,16 @@ - - + + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/OpenUtau/OpenUtau.csproj b/OpenUtau/OpenUtau.csproj index ceac1777b..58354188a 100644 --- a/OpenUtau/OpenUtau.csproj +++ b/OpenUtau/OpenUtau.csproj @@ -43,8 +43,8 @@ - - + + diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml index 34204b065..39a42f838 100644 --- a/OpenUtau/Strings/Strings.axaml +++ b/OpenUtau/Strings/Strings.axaml @@ -180,6 +180,7 @@ Warning: this option removes custom presets. Hiragana to Romaji Japanese VCV to CV Remove Letter Suffix + Remove Phonetic Hint Remove Tone Suffix Romaji to Hiragana Note Defaults @@ -289,6 +290,7 @@ Hold Ctrl to select Project saved. {0} Waiting Rendering + Loading Singers... Singers Edit In vLabeler diff --git a/OpenUtau/Strings/Strings.zh-CN.axaml b/OpenUtau/Strings/Strings.zh-CN.axaml index 362e397b1..3783f870c 100644 --- a/OpenUtau/Strings/Strings.zh-CN.axaml +++ b/OpenUtau/Strings/Strings.zh-CN.axaml @@ -286,6 +286,7 @@ 工程已保存 {0} 等待渲染 + 正在加载歌手... 歌手 diff --git a/OpenUtau/ViewModels/MainWindowViewModel.cs b/OpenUtau/ViewModels/MainWindowViewModel.cs index 082ad0b18..412af5fb2 100644 --- a/OpenUtau/ViewModels/MainWindowViewModel.cs +++ b/OpenUtau/ViewModels/MainWindowViewModel.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Avalonia.Threading; using DynamicData.Binding; +using OpenUtau.Classic; using OpenUtau.Core; using OpenUtau.Core.Ustx; using ReactiveUI; @@ -87,6 +88,10 @@ public void Redo() { DocManager.Inst.Redo(); } + public Task? GetInitSingerTask() { + return SingerManager.Inst.InitializationTask; + } + public void InitProject() { var args = Environment.GetCommandLineArgs(); if (args.Length == 2 && File.Exists(args[1])) { @@ -155,12 +160,12 @@ public void ImportAudio(string file) { DocManager.Inst.EndUndoGroup(); } - public void ImportMidi(string file, bool UseDrywetmidi=false) { + public void ImportMidi(string file, bool UseDrywetmidi = false) { if (file == null) { return; } var project = DocManager.Inst.Project; - var parts = UseDrywetmidi? Core.Format.MidiWriter.Load(file, project): Core.Format.Midi.Load(file, project); + var parts = UseDrywetmidi ? Core.Format.MidiWriter.Load(file, project) : Core.Format.Midi.Load(file, project); DocManager.Inst.StartUndoGroup(); foreach (var part in parts) { var track = new UTrack(); diff --git a/OpenUtau/ViewModels/PianoRollViewModel.cs b/OpenUtau/ViewModels/PianoRollViewModel.cs index f349b7c90..49c70fdc6 100644 --- a/OpenUtau/ViewModels/PianoRollViewModel.cs +++ b/OpenUtau/ViewModels/PianoRollViewModel.cs @@ -179,6 +179,7 @@ public PianoRollViewModel() { new JapaneseVCVtoCV(), new RemoveToneSuffix(), new RemoveLetterSuffix(), + new RemovePhoneticHint(), new DashToPlus(), }.Select(edit => new MenuItemViewModel() { Header = ThemeManager.GetString(edit.Name), diff --git a/OpenUtau/Views/MainWindow.axaml b/OpenUtau/Views/MainWindow.axaml index b1bbcd20a..6b055a4dd 100644 --- a/OpenUtau/Views/MainWindow.axaml +++ b/OpenUtau/Views/MainWindow.axaml @@ -15,236 +15,241 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + TrackOffset="{Binding TrackOffset}"/> + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + diff --git a/OpenUtau/Views/MainWindow.axaml.cs b/OpenUtau/Views/MainWindow.axaml.cs index d57493661..dfa84870a 100644 --- a/OpenUtau/Views/MainWindow.axaml.cs +++ b/OpenUtau/Views/MainWindow.axaml.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Linq; using System.Reactive; +using System.Threading; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; @@ -31,6 +32,8 @@ public partial class MainWindow : Window, ICmdSubscriber { OS.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control; private readonly MainWindowViewModel viewModel; + private bool splashDone = false; + private PianoRollWindow? pianoRollWindow; private bool openPianoRollWindow; @@ -55,11 +58,22 @@ public MainWindow() { #if DEBUG this.AttachDevTools(); #endif - viewModel.InitProject(); - viewModel.AddTempoChangeCmd = ReactiveCommand.Create(tick => AddTempoChange(tick)); - viewModel.DelTempoChangeCmd = ReactiveCommand.Create(tick => DelTempoChange(tick)); - viewModel.AddTimeSigChangeCmd = ReactiveCommand.Create(bar => AddTimeSigChange(bar)); - viewModel.DelTimeSigChangeCmd = ReactiveCommand.Create(bar => DelTimeSigChange(bar)); + var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); + viewModel.GetInitSingerTask()!.ContinueWith(_ => { + viewModel.InitProject(); + viewModel.AddTempoChangeCmd = ReactiveCommand.Create(tick => AddTempoChange(tick)); + viewModel.DelTempoChangeCmd = ReactiveCommand.Create(tick => DelTempoChange(tick)); + viewModel.AddTimeSigChangeCmd = ReactiveCommand.Create(bar => AddTimeSigChange(bar)); + viewModel.DelTimeSigChangeCmd = ReactiveCommand.Create(bar => DelTimeSigChange(bar)); + + var splash = this.Find("Splash"); + splash.IsEnabled = false; + splash.IsVisible = false; + var mainGrid = this.Find("MainGrid"); + mainGrid.IsEnabled = true; + mainGrid.IsVisible = true; + splashDone = true; + }, CancellationToken.None, TaskContinuationOptions.None, scheduler); timer = new DispatcherTimer( TimeSpan.FromMilliseconds(15), @@ -311,7 +325,7 @@ async void OnMenuImportAudio(object sender, RoutedEventArgs args) { } } - async void OnMenuImportMidi(bool UseDrywetmidi=false) { + async void OnMenuImportMidi(bool UseDrywetmidi = false) { var dialog = new OpenFileDialog() { Filters = new List() { new FileDialogFilter() { @@ -662,6 +676,9 @@ private void LayoutSplit(double? x, double? y) { } void OnKeyDown(object sender, KeyEventArgs args) { + if (!splashDone) { + return; + } var tracksVm = viewModel.TracksViewModel; if (args.KeyModifiers == KeyModifiers.None) { args.Handled = true; diff --git a/runtimes/osx/native/libonnxruntime.dylib b/runtimes/osx/native/libonnxruntime.dylib old mode 100755 new mode 100644