Skip to content

Commit

Permalink
Merge pull request #1242 from rokujyushi/AddPhonemizer
Browse files Browse the repository at this point in the history
Add SimpleVOICEVOX ENtoJA Phonemizer
  • Loading branch information
stakira committed Sep 1, 2024
2 parents a25ac24 + e102ca7 commit 631f4e2
Show file tree
Hide file tree
Showing 5 changed files with 481 additions and 92 deletions.
22 changes: 12 additions & 10 deletions OpenUtau.Core/Voicevox/Phonemizers/SimpleVoicevoxPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Voicevox {
[Phonemizer("Simple Voicevox Japanese Phonemizer", "S-VOICEVOX JA", language: "JA")]
public class SimpleVoicevoxPhonemizer : Phonemizer {

protected VoicevoxSinger singer;
protected VoicevoxSinger singer;

public override void SetSinger(USinger singer) {
this.singer = singer as VoicevoxSinger;
Expand All @@ -18,7 +18,7 @@ public override void SetSinger(USinger singer) {
}

protected bool IsSyllableVowelExtensionNote(Note note) {
return note.lyric.StartsWith("+~") || note.lyric.StartsWith("+*");
return note.lyric.StartsWith("+~") || note.lyric.StartsWith("+*") || note.lyric.StartsWith("+") || note.lyric.StartsWith("-");
}

public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevNeighbour, Note? nextNeighbour, Note[] prevNeighbours) {
Expand All @@ -32,15 +32,17 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
notes[i].lyric = lyricList[1];
}
if (!IsSyllableVowelExtensionNote(notes[i])) {
if (VoicevoxUtils.IsHiraKana(notes[i].lyric)) {
phonemes.Add(new Phoneme { phoneme = notes[i].lyric });
} else if (VoicevoxUtils.IsPau(notes[i].lyric)) {
phonemes.Add(new Phoneme { phoneme = "R" });
} else if (VoicevoxUtils.dic.IsDic(notes[i].lyric)) {
phonemes.Add(new Phoneme { phoneme = VoicevoxUtils.dic.Lyrictodic(notes[i].lyric) });
} else {
phonemes.Add(new Phoneme { phoneme = "error"});
string val = "error";
if (VoicevoxUtils.phoneme_List.kanas.ContainsKey(notes[i].lyric) || VoicevoxUtils.phoneme_List.paus.ContainsKey(notes[i].lyric)) {
if (VoicevoxUtils.phoneme_List.paus.TryGetValue(notes[i].lyric, out string str)) {
val = str;
} else if (VoicevoxUtils.dic.IsDic(notes[i].lyric)) {
val = VoicevoxUtils.dic.Lyrictodic(notes[i].lyric);
} else {
val = notes[i].lyric;
}
}
phonemes.Add(new Phoneme { phoneme = val });
}
}
return new Result { phonemes = phonemes.ToArray() };
Expand Down
55 changes: 0 additions & 55 deletions OpenUtau.Core/Voicevox/VoicevoxConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,61 +167,6 @@ public void SaveLicenses(string location) {
}
}

public class Phoneme_list {
public string[] vowels;
public string[] consonants;
public string[] kana;
}

public class Dictionary_list {
public Dictionary<string, string> dict = new Dictionary<string, string>();

public void Loaddic(string location) {
try {
var parentDirectory = Directory.GetParent(location).ToString();
var yamlPath = Path.Join(parentDirectory, "dictionary.yaml");
if (File.Exists(yamlPath)) {
var yamlTxt = File.ReadAllText(yamlPath);
var yamlObj = Yaml.DefaultDeserializer.Deserialize<Dictionary<string, List<Dictionary<string, string>>>>(yamlTxt);
var list = yamlObj["list"];
dict = new Dictionary<string, string>();

foreach (var item in list) {
foreach (var pair in item) {
dict[pair.Key] = pair.Value;
}
}

}
} catch (Exception e) {
Log.Error($"Failed to read dictionary file. : {e}");
}
}
public string Notetodic(Note[][] notes, int index) {
if (dict.TryGetValue(notes[index][0].lyric, out var lyric_)) {
if (string.IsNullOrEmpty(lyric_)) {
return "";
}
return lyric_;
}
return notes[index][0].lyric;
}

public string Lyrictodic(string lyric) {
if (dict.TryGetValue(lyric, out var lyric_)) {
if (string.IsNullOrEmpty(lyric_)) {
return "";
}
return lyric_;
}
return lyric;
}

public bool IsDic(string lyric) {
return dict.ContainsKey(lyric);
}
}

public class Style_infos {
public int id;
public string icon = string.Empty;
Expand Down
21 changes: 10 additions & 11 deletions OpenUtau.Core/Voicevox/VoicevoxSinger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,18 @@ void Load() {
table.Clear();
otos.Clear();
try {
var parentDirectory = Directory.GetParent(this.Location).ToString();
var yamlPath = Path.Join(parentDirectory, "phonemes.yaml");
var yamlTxt = File.ReadAllText(yamlPath);
var phonemes_list = Yaml.DefaultDeserializer.Deserialize<Phoneme_list>(yamlTxt);
//Prepared for planned changes or additions to phonemizers.
foreach (var str in phonemes_list.vowels) {
phonemes.Add(str);
//foreach (var str in VoicevoxUtils.phoneme_List.vowels) {
// phonemes.Add(str);
//}
//foreach (var str in VoicevoxUtils.phoneme_List.consonants) {
// phonemes.Add(str);
//}
foreach (var str in VoicevoxUtils.phoneme_List.kanas) {
phonemes.Add(str.Key);
}
foreach (var str in phonemes_list.consonants) {
phonemes.Add(str);
}
foreach (var str in phonemes_list.kana) {
phonemes.Add(str);
foreach (var str in VoicevoxUtils.phoneme_List.paus) {
phonemes.Add(str.Key);
}
} catch (Exception e) {
Log.Error(e, $"Failed to load phonemes.yaml for {Name}");
Expand Down
109 changes: 93 additions & 16 deletions OpenUtau.Core/Voicevox/VoicevoxUtils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -39,15 +40,97 @@ public class VoicevoxQueryNotes {
public class VoicevoxQueryMain {
public List<VoicevoxQueryNotes> notes = new List<VoicevoxQueryNotes>();
}
public class Phoneme_list {
public string[] vowels = "a i u e o A I U E O N pau cl".Split();
public string[] consonants = "b by ch d dy f g gw gy h hy j k kw ky m my n ny p py r ry s sh t ts ty v w y z".Split();
public Dictionary<string, string> kanas = new Dictionary<string, string>();
public Dictionary<string, string> paus = new Dictionary<string, string>();
public Phoneme_list() {
var kanaGroups = new List<string[]> {
"あ ば びゃ ちゃ だ でゃ ふぁ が ぐゎ ぎゃ は ひゃ じゃ か くゎ きゃ ま みゃ な にゃ ぱ ぴゃ ら りゃ さ しゃ た つぁ てゃ ゔぁ わ や ざ".Split(),
"い び ち ぢ でぃ ふぃ ぎ ひ じ き み に ぴ り すぃ し てぃ つぃ ゔぃ うぃ ずぃ".Split(),
"う ぶ びゅ ちゅ どぅ でゅ ふ ぐ ぎゅ ひゅ じゅ く きゅ む みゅ ぬ にゅ ぷ ぴゅ る りゅ す しゅ つ つ てゅ ゔ ゆ ず".Split(),
"え べ びぇ ちぇ で でぇ ふぇ げ ぎぇ へ ひぇ じぇ け きぇ め みぇ ね にぇ ぺ ぴぇ れ りぇ せ しぇ て つぇ ゔぇ うぇ いぇ ぜ".Split(),
"お ぼ びょ ちょ ど でょ ふぉ ご ぎょ ほ ひょ じょ こ きょ も みょ の にょ ぽ ぴょ ろ りょ そ しょ と つぉ てょ ゔぉ を よ ぞ".Split(),
"ん ン".Split(),
"っ ッ".Split()
};

foreach (var group in kanaGroups) {
foreach (var kana in group) {
if (!kanas.ContainsKey(kana)) {
kanas.Add(kana.Normalize(), group[0].Normalize());
}
}
}
string[] pauseGroups = "R pau AP SP".Split();

foreach (string group in pauseGroups) {
if (!paus.ContainsKey(group)) {
paus.Add(group.Normalize(), pauseGroups[0].Normalize());
}
}
}
}

public class Dictionary_list {
public Dictionary<string, string> dict = new Dictionary<string, string>();

public void Loaddic(string location) {
try {
var parentDirectory = Directory.GetParent(location).ToString();
var yamlPath = Path.Join(parentDirectory, "dictionary.yaml");
if (File.Exists(yamlPath)) {
var yamlTxt = File.ReadAllText(yamlPath);
var yamlObj = Yaml.DefaultDeserializer.Deserialize<Dictionary<string, List<Dictionary<string, string>>>>(yamlTxt);
var list = yamlObj["list"];
dict = new Dictionary<string, string>();

foreach (var item in list) {
foreach (var pair in item) {
dict[pair.Key] = pair.Value;
}
}

}
} catch (Exception e) {
Log.Error($"Failed to read dictionary file. : {e}");
}
}
public string Notetodic(Note[][] notes, int index) {
if (dict.TryGetValue(notes[index][0].lyric, out var lyric_)) {
if (string.IsNullOrEmpty(lyric_)) {
return "";
}
return lyric_;
}
return notes[index][0].lyric;
}

public string Lyrictodic(string lyric) {
if (dict.TryGetValue(lyric, out var lyric_)) {
if (string.IsNullOrEmpty(lyric_)) {
return "";
}
return lyric_;
}
return lyric;
}

public bool IsDic(string lyric) {
return dict.ContainsKey(lyric);
}
}


internal static class VoicevoxUtils {
public static class VoicevoxUtils {
public const string VOLC = "volc";
public const int headS = 1;
public const int tailS = 1;
public const double fps = 93.75;
public const string defaultID = "6000";
public static Dictionary_list dic = new Dictionary_list();
public static Phoneme_list phoneme_List = new Phoneme_list();

public static VoicevoxNote VoicevoxVoiceBase(VoicevoxQueryMain qNotes, string id) {
var queryurl = new VoicevoxURL() { method = "POST", path = "/sing_frame_audio_query", query = new Dictionary<string, string> { { "speaker", id } }, body = JsonConvert.SerializeObject(qNotes) };
Expand Down Expand Up @@ -83,11 +166,11 @@ public static VoicevoxQueryMain NoteGroupsToVoicevox(Note[][] notes, TimeAxis ti
string lyric = dic.Notetodic(notes, index);
int length = (int)Math.Round(((timeAxis.TickPosToMsPos(notes[index].Sum(n => n.duration)) / 1000f) * VoicevoxUtils.fps), MidpointRounding.AwayFromZero);
//Avoid synthesis without at least two frames.
if (length < 2 ) {
if (length < 2) {
length = 2;
}
int? tone = null;
if (!string.IsNullOrEmpty(lyric) || VoicevoxUtils.IsPau(lyric)) {
if (!string.IsNullOrEmpty(lyric)) {
if (notes[index][0].phonemeAttributes != null) {
if (notes[index][0].phonemeAttributes.Length > 0) {
tone = notes[index][0].tone + notes[index][0].phonemeAttributes[0].toneShift;
Expand All @@ -97,6 +180,8 @@ public static VoicevoxQueryMain NoteGroupsToVoicevox(Note[][] notes, TimeAxis ti
} else {
tone = notes[index][0].tone;
}
} else {
lyric = "";
}
qnotes.notes.Add(new VoicevoxQueryNotes {
lyric = lyric,
Expand Down Expand Up @@ -146,21 +231,13 @@ public static double[] SampleCurve(RenderPhrase phrase, float[] curve, double de
return result;
}


public static bool IsHiraKana(string s) {
foreach(char c in s.ToCharArray()) {
if (!('\u3041' <= c && c <= '\u309F') || ('\u30A0' <= c && c <= '\u30FF') || c == '\u30FC' || c == '\u30A0') {
return false;
}
}
return true;
public static bool IsPau(string s) {
return phoneme_List.paus.ContainsKey(s);
}

public static bool IsPau(string s) {
if (s.EndsWith("R") || s.ToLower().EndsWith("pau") || s.EndsWith("AP") || s.EndsWith("SP")) {
return true;
}
return false;
public static bool TryGetPau(string s, out string str) {
phoneme_List.paus.TryGetValue(s, out str);
return phoneme_List.paus.ContainsKey(s);
}

public static string getBaseSingerID(VoicevoxSinger singer) {
Expand Down
Loading

0 comments on commit 631f4e2

Please sign in to comment.