Skip to content

Commit 631f4e2

Browse files
authored
Merge pull request #1242 from rokujyushi/AddPhonemizer
Add SimpleVOICEVOX ENtoJA Phonemizer
2 parents a25ac24 + e102ca7 commit 631f4e2

File tree

5 files changed

+481
-92
lines changed

5 files changed

+481
-92
lines changed

OpenUtau.Core/Voicevox/Phonemizers/SimpleVoicevoxPhonemizer.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Voicevox {
77
[Phonemizer("Simple Voicevox Japanese Phonemizer", "S-VOICEVOX JA", language: "JA")]
88
public class SimpleVoicevoxPhonemizer : Phonemizer {
99

10-
protected VoicevoxSinger singer;
10+
protected VoicevoxSinger singer;
1111

1212
public override void SetSinger(USinger singer) {
1313
this.singer = singer as VoicevoxSinger;
@@ -18,7 +18,7 @@ public override void SetSinger(USinger singer) {
1818
}
1919

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

2424
public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevNeighbour, Note? nextNeighbour, Note[] prevNeighbours) {
@@ -32,15 +32,17 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
3232
notes[i].lyric = lyricList[1];
3333
}
3434
if (!IsSyllableVowelExtensionNote(notes[i])) {
35-
if (VoicevoxUtils.IsHiraKana(notes[i].lyric)) {
36-
phonemes.Add(new Phoneme { phoneme = notes[i].lyric });
37-
} else if (VoicevoxUtils.IsPau(notes[i].lyric)) {
38-
phonemes.Add(new Phoneme { phoneme = "R" });
39-
} else if (VoicevoxUtils.dic.IsDic(notes[i].lyric)) {
40-
phonemes.Add(new Phoneme { phoneme = VoicevoxUtils.dic.Lyrictodic(notes[i].lyric) });
41-
} else {
42-
phonemes.Add(new Phoneme { phoneme = "error"});
35+
string val = "error";
36+
if (VoicevoxUtils.phoneme_List.kanas.ContainsKey(notes[i].lyric) || VoicevoxUtils.phoneme_List.paus.ContainsKey(notes[i].lyric)) {
37+
if (VoicevoxUtils.phoneme_List.paus.TryGetValue(notes[i].lyric, out string str)) {
38+
val = str;
39+
} else if (VoicevoxUtils.dic.IsDic(notes[i].lyric)) {
40+
val = VoicevoxUtils.dic.Lyrictodic(notes[i].lyric);
41+
} else {
42+
val = notes[i].lyric;
43+
}
4344
}
45+
phonemes.Add(new Phoneme { phoneme = val });
4446
}
4547
}
4648
return new Result { phonemes = phonemes.ToArray() };

OpenUtau.Core/Voicevox/VoicevoxConfig.cs

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -167,61 +167,6 @@ public void SaveLicenses(string location) {
167167
}
168168
}
169169

170-
public class Phoneme_list {
171-
public string[] vowels;
172-
public string[] consonants;
173-
public string[] kana;
174-
}
175-
176-
public class Dictionary_list {
177-
public Dictionary<string, string> dict = new Dictionary<string, string>();
178-
179-
public void Loaddic(string location) {
180-
try {
181-
var parentDirectory = Directory.GetParent(location).ToString();
182-
var yamlPath = Path.Join(parentDirectory, "dictionary.yaml");
183-
if (File.Exists(yamlPath)) {
184-
var yamlTxt = File.ReadAllText(yamlPath);
185-
var yamlObj = Yaml.DefaultDeserializer.Deserialize<Dictionary<string, List<Dictionary<string, string>>>>(yamlTxt);
186-
var list = yamlObj["list"];
187-
dict = new Dictionary<string, string>();
188-
189-
foreach (var item in list) {
190-
foreach (var pair in item) {
191-
dict[pair.Key] = pair.Value;
192-
}
193-
}
194-
195-
}
196-
} catch (Exception e) {
197-
Log.Error($"Failed to read dictionary file. : {e}");
198-
}
199-
}
200-
public string Notetodic(Note[][] notes, int index) {
201-
if (dict.TryGetValue(notes[index][0].lyric, out var lyric_)) {
202-
if (string.IsNullOrEmpty(lyric_)) {
203-
return "";
204-
}
205-
return lyric_;
206-
}
207-
return notes[index][0].lyric;
208-
}
209-
210-
public string Lyrictodic(string lyric) {
211-
if (dict.TryGetValue(lyric, out var lyric_)) {
212-
if (string.IsNullOrEmpty(lyric_)) {
213-
return "";
214-
}
215-
return lyric_;
216-
}
217-
return lyric;
218-
}
219-
220-
public bool IsDic(string lyric) {
221-
return dict.ContainsKey(lyric);
222-
}
223-
}
224-
225170
public class Style_infos {
226171
public int id;
227172
public string icon = string.Empty;

OpenUtau.Core/Voicevox/VoicevoxSinger.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,19 +81,18 @@ void Load() {
8181
table.Clear();
8282
otos.Clear();
8383
try {
84-
var parentDirectory = Directory.GetParent(this.Location).ToString();
85-
var yamlPath = Path.Join(parentDirectory, "phonemes.yaml");
86-
var yamlTxt = File.ReadAllText(yamlPath);
87-
var phonemes_list = Yaml.DefaultDeserializer.Deserialize<Phoneme_list>(yamlTxt);
8884
//Prepared for planned changes or additions to phonemizers.
89-
foreach (var str in phonemes_list.vowels) {
90-
phonemes.Add(str);
85+
//foreach (var str in VoicevoxUtils.phoneme_List.vowels) {
86+
// phonemes.Add(str);
87+
//}
88+
//foreach (var str in VoicevoxUtils.phoneme_List.consonants) {
89+
// phonemes.Add(str);
90+
//}
91+
foreach (var str in VoicevoxUtils.phoneme_List.kanas) {
92+
phonemes.Add(str.Key);
9193
}
92-
foreach (var str in phonemes_list.consonants) {
93-
phonemes.Add(str);
94-
}
95-
foreach (var str in phonemes_list.kana) {
96-
phonemes.Add(str);
94+
foreach (var str in VoicevoxUtils.phoneme_List.paus) {
95+
phonemes.Add(str.Key);
9796
}
9897
} catch (Exception e) {
9998
Log.Error(e, $"Failed to load phonemes.yaml for {Name}");

OpenUtau.Core/Voicevox/VoicevoxUtils.cs

Lines changed: 93 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO;
34
using System.Linq;
45
using Newtonsoft.Json;
56
using Newtonsoft.Json.Linq;
@@ -39,15 +40,97 @@ public class VoicevoxQueryNotes {
3940
public class VoicevoxQueryMain {
4041
public List<VoicevoxQueryNotes> notes = new List<VoicevoxQueryNotes>();
4142
}
43+
public class Phoneme_list {
44+
public string[] vowels = "a i u e o A I U E O N pau cl".Split();
45+
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();
46+
public Dictionary<string, string> kanas = new Dictionary<string, string>();
47+
public Dictionary<string, string> paus = new Dictionary<string, string>();
48+
public Phoneme_list() {
49+
var kanaGroups = new List<string[]> {
50+
"あ ば びゃ ちゃ だ でゃ ふぁ が ぐゎ ぎゃ は ひゃ じゃ か くゎ きゃ ま みゃ な にゃ ぱ ぴゃ ら りゃ さ しゃ た つぁ てゃ ゔぁ わ や ざ".Split(),
51+
"い び ち ぢ でぃ ふぃ ぎ ひ じ き み に ぴ り すぃ し てぃ つぃ ゔぃ うぃ ずぃ".Split(),
52+
"う ぶ びゅ ちゅ どぅ でゅ ふ ぐ ぎゅ ひゅ じゅ く きゅ む みゅ ぬ にゅ ぷ ぴゅ る りゅ す しゅ つ つ てゅ ゔ ゆ ず".Split(),
53+
"え べ びぇ ちぇ で でぇ ふぇ げ ぎぇ へ ひぇ じぇ け きぇ め みぇ ね にぇ ぺ ぴぇ れ りぇ せ しぇ て つぇ ゔぇ うぇ いぇ ぜ".Split(),
54+
"お ぼ びょ ちょ ど でょ ふぉ ご ぎょ ほ ひょ じょ こ きょ も みょ の にょ ぽ ぴょ ろ りょ そ しょ と つぉ てょ ゔぉ を よ ぞ".Split(),
55+
"ん ン".Split(),
56+
"っ ッ".Split()
57+
};
58+
59+
foreach (var group in kanaGroups) {
60+
foreach (var kana in group) {
61+
if (!kanas.ContainsKey(kana)) {
62+
kanas.Add(kana.Normalize(), group[0].Normalize());
63+
}
64+
}
65+
}
66+
string[] pauseGroups = "R pau AP SP".Split();
67+
68+
foreach (string group in pauseGroups) {
69+
if (!paus.ContainsKey(group)) {
70+
paus.Add(group.Normalize(), pauseGroups[0].Normalize());
71+
}
72+
}
73+
}
74+
}
75+
76+
public class Dictionary_list {
77+
public Dictionary<string, string> dict = new Dictionary<string, string>();
78+
79+
public void Loaddic(string location) {
80+
try {
81+
var parentDirectory = Directory.GetParent(location).ToString();
82+
var yamlPath = Path.Join(parentDirectory, "dictionary.yaml");
83+
if (File.Exists(yamlPath)) {
84+
var yamlTxt = File.ReadAllText(yamlPath);
85+
var yamlObj = Yaml.DefaultDeserializer.Deserialize<Dictionary<string, List<Dictionary<string, string>>>>(yamlTxt);
86+
var list = yamlObj["list"];
87+
dict = new Dictionary<string, string>();
88+
89+
foreach (var item in list) {
90+
foreach (var pair in item) {
91+
dict[pair.Key] = pair.Value;
92+
}
93+
}
94+
95+
}
96+
} catch (Exception e) {
97+
Log.Error($"Failed to read dictionary file. : {e}");
98+
}
99+
}
100+
public string Notetodic(Note[][] notes, int index) {
101+
if (dict.TryGetValue(notes[index][0].lyric, out var lyric_)) {
102+
if (string.IsNullOrEmpty(lyric_)) {
103+
return "";
104+
}
105+
return lyric_;
106+
}
107+
return notes[index][0].lyric;
108+
}
109+
110+
public string Lyrictodic(string lyric) {
111+
if (dict.TryGetValue(lyric, out var lyric_)) {
112+
if (string.IsNullOrEmpty(lyric_)) {
113+
return "";
114+
}
115+
return lyric_;
116+
}
117+
return lyric;
118+
}
119+
120+
public bool IsDic(string lyric) {
121+
return dict.ContainsKey(lyric);
122+
}
123+
}
42124

43125

44-
internal static class VoicevoxUtils {
126+
public static class VoicevoxUtils {
45127
public const string VOLC = "volc";
46128
public const int headS = 1;
47129
public const int tailS = 1;
48130
public const double fps = 93.75;
49131
public const string defaultID = "6000";
50132
public static Dictionary_list dic = new Dictionary_list();
133+
public static Phoneme_list phoneme_List = new Phoneme_list();
51134

52135
public static VoicevoxNote VoicevoxVoiceBase(VoicevoxQueryMain qNotes, string id) {
53136
var queryurl = new VoicevoxURL() { method = "POST", path = "/sing_frame_audio_query", query = new Dictionary<string, string> { { "speaker", id } }, body = JsonConvert.SerializeObject(qNotes) };
@@ -83,11 +166,11 @@ public static VoicevoxQueryMain NoteGroupsToVoicevox(Note[][] notes, TimeAxis ti
83166
string lyric = dic.Notetodic(notes, index);
84167
int length = (int)Math.Round(((timeAxis.TickPosToMsPos(notes[index].Sum(n => n.duration)) / 1000f) * VoicevoxUtils.fps), MidpointRounding.AwayFromZero);
85168
//Avoid synthesis without at least two frames.
86-
if (length < 2 ) {
169+
if (length < 2) {
87170
length = 2;
88171
}
89172
int? tone = null;
90-
if (!string.IsNullOrEmpty(lyric) || VoicevoxUtils.IsPau(lyric)) {
173+
if (!string.IsNullOrEmpty(lyric)) {
91174
if (notes[index][0].phonemeAttributes != null) {
92175
if (notes[index][0].phonemeAttributes.Length > 0) {
93176
tone = notes[index][0].tone + notes[index][0].phonemeAttributes[0].toneShift;
@@ -97,6 +180,8 @@ public static VoicevoxQueryMain NoteGroupsToVoicevox(Note[][] notes, TimeAxis ti
97180
} else {
98181
tone = notes[index][0].tone;
99182
}
183+
} else {
184+
lyric = "";
100185
}
101186
qnotes.notes.Add(new VoicevoxQueryNotes {
102187
lyric = lyric,
@@ -146,21 +231,13 @@ public static double[] SampleCurve(RenderPhrase phrase, float[] curve, double de
146231
return result;
147232
}
148233

149-
150-
public static bool IsHiraKana(string s) {
151-
foreach(char c in s.ToCharArray()) {
152-
if (!('\u3041' <= c && c <= '\u309F') || ('\u30A0' <= c && c <= '\u30FF') || c == '\u30FC' || c == '\u30A0') {
153-
return false;
154-
}
155-
}
156-
return true;
234+
public static bool IsPau(string s) {
235+
return phoneme_List.paus.ContainsKey(s);
157236
}
158237

159-
public static bool IsPau(string s) {
160-
if (s.EndsWith("R") || s.ToLower().EndsWith("pau") || s.EndsWith("AP") || s.EndsWith("SP")) {
161-
return true;
162-
}
163-
return false;
238+
public static bool TryGetPau(string s, out string str) {
239+
phoneme_List.paus.TryGetValue(s, out str);
240+
return phoneme_List.paus.ContainsKey(s);
164241
}
165242

166243
public static string getBaseSingerID(VoicevoxSinger singer) {

0 commit comments

Comments
 (0)