Skip to content

Commit eea982e

Browse files
MonophonePhonemizer todo:custom phoneme set support
1 parent cb6422d commit eea982e

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using OpenUtau.Api;
7+
using Serilog;
8+
9+
namespace OpenUtau.Plugin.Builtin
10+
{
11+
[Phonemizer("Chinese CVV Monophone Phonemizer", "ZH CVV MONO", "O3", language: "ZH")]
12+
public class ChineseCVVMonophonePhonemizer : MonophonePhonemizer
13+
{
14+
static readonly string pinyins = "a,ai,an,ang,ao,ba,bai,ban,bang,bao,bei,ben,beng,bi,bian,biao,bie,bin,bing,bo,bu,ca,cai,can,cang,cao,ce,cei,cen,ceng,cha,chai,chan,chang,chao,che,chen,cheng,chi,chong,chou,chu,chua,chuai,chuan,chuang,chui,chun,chuo,ci,cong,cou,cu,cuan,cui,cun,cuo,da,dai,dan,dang,dao,de,dei,den,deng,di,dia,dian,diao,die,ding,diu,dong,dou,du,duan,dui,dun,duo,e,ei,en,eng,er,fa,fan,fang,fei,fen,feng,fo,fou,fu,ga,gai,gan,gang,gao,ge,gei,gen,geng,gong,gou,gu,gua,guai,guan,guang,gui,gun,guo,ha,hai,han,hang,hao,he,hei,hen,heng,hong,hou,hu,hua,huai,huan,huang,hui,hun,huo,ji,jia,jian,jiang,jiao,jie,jin,jing,jiong,jiu,ju,jv,juan,jvan,jue,jve,jun,jvn,ka,kai,kan,kang,kao,ke,kei,ken,keng,kong,kou,ku,kua,kuai,kuan,kuang,kui,kun,kuo,la,lai,lan,lang,lao,le,lei,leng,li,lia,lian,liang,liao,lie,lin,ling,liu,lo,long,lou,lu,luan,lun,luo,lv,lve,ma,mai,man,mang,mao,me,mei,men,meng,mi,mian,miao,mie,min,ming,miu,mo,mou,mu,na,nai,nan,nang,nao,ne,nei,nen,neng,ni,nian,niang,niao,nie,nin,ning,niu,nong,nou,nu,nuan,nun,nuo,nv,nve,o,ou,pa,pai,pan,pang,pao,pei,pen,peng,pi,pian,piao,pie,pin,ping,po,pou,pu,qi,qia,qian,qiang,qiao,qie,qin,qing,qiong,qiu,qu,qv,quan,qvan,que,qve,qun,qvn,ran,rang,rao,re,ren,reng,ri,rong,rou,ru,rua,ruan,rui,run,ruo,sa,sai,san,sang,sao,se,sen,seng,sha,shai,shan,shang,shao,she,shei,shen,sheng,shi,shou,shu,shua,shuai,shuan,shuang,shui,shun,shuo,si,song,sou,su,suan,sui,sun,suo,ta,tai,tan,tang,tao,te,tei,teng,ti,tian,tiao,tie,ting,tong,tou,tu,tuan,tui,tun,tuo,wa,wai,wan,wang,wei,wen,weng,wo,wu,xi,xia,xian,xiang,xiao,xie,xin,xing,xiong,xiu,xu,xv,xuan,xvan,xue,xve,xun,xvn,ya,yan,yang,yao,ye,yi,yin,ying,yo,yong,you,yu,yv,yuan,yvan,yue,yve,yun,yvn,za,zai,zan,zang,zao,ze,zei,zen,zeng,zha,zhai,zhan,zhang,zhao,zhe,zhei,zhen,zheng,zhi,zhong,zhou,zhu,zhua,zhuai,zhuan,zhuang,zhui,zhun,zhuo,zi,zong,zou,zu,zuan,zui,zun";
15+
static readonly string tails = "_vn,_ing,_ong,_an,_ou,_er,_ao,_eng,_ang,_en,_en2,_ai,_iong,_in,_ei";
16+
17+
static readonly string[] pinyinList = pinyins.Split(',');
18+
static readonly string[] tailList = tails.Split(',');
19+
20+
protected override IG2p LoadBaseDictionary() {
21+
var g2ps = new List<IG2p>();
22+
23+
// Load dictionary from plugin folder.
24+
string path = Path.Combine(PluginDir, "zhcvv.yaml");
25+
if (File.Exists(path)) {
26+
g2ps.Add(G2pDictionary.NewBuilder().Load(File.ReadAllText(path)).Build());
27+
}
28+
29+
// Load dictionary from singer folder.
30+
if (singer != null && singer.Found && singer.Loaded) {
31+
string file = Path.Combine(singer.Location, "zhcvv.yaml");
32+
if (File.Exists(file)) {
33+
try {
34+
g2ps.Add(G2pDictionary.NewBuilder().Load(File.ReadAllText(file)).Build());
35+
} catch (Exception e) {
36+
Log.Error(e, $"Failed to load {file}");
37+
}
38+
}
39+
}
40+
g2ps.Add(new ChineseCVVG2p());
41+
return new G2pFallbacks(g2ps.ToArray());
42+
}
43+
44+
protected override string[] GetVowels(){
45+
return pinyinList;
46+
}
47+
48+
protected override string[] GetConsonants(){
49+
return tailList;
50+
}
51+
52+
Dictionary<string,string> AliasesFallback = new Dictionary<string, string>{{"_un","_en"}};
53+
protected override Dictionary<string, string> GetAliasesFallback()=>AliasesFallback;
54+
protected override Dictionary<string, string> GetDictionaryPhonemesReplacement() => new Dictionary<string, string>();
55+
}
56+
class ChineseCVVG2p : IG2p{
57+
/// <summary>
58+
/// The consonant table.
59+
/// </summary>
60+
static readonly string consonants = "b,p,m,f,d,t,n,l,g,k,h,j,q,x,z,c,s,zh,ch,sh,r,y,w";
61+
/// <summary>
62+
/// The vowel split table.
63+
/// </summary>
64+
static readonly string vowels = "ai=_ai,uai=_uai,an=_an,ian=_en2,uan=_an,van=_en2,ang=_ang,iang=_ang,uang=_ang,ao=_ao,iao=_ao,ou=_ou,iu=_ou,ong=_ong,iong=_ong,ei=_ei,ui=_ei,uei=_ei,en=_en,un=_un,uen=_un,eng=_eng,in=_in,ing=_ing,vn=_vn";
65+
66+
static HashSet<string> cSet;
67+
static Dictionary<string, string> vDict;
68+
69+
static ChineseCVVG2p() {
70+
cSet = new HashSet<string>(consonants.Split(','));
71+
vDict = vowels.Split(',')
72+
.Select(s => s.Split('='))
73+
.ToDictionary(a => a[0], a => a[1]);
74+
}
75+
76+
public bool IsVowel(string phoneme){
77+
return !phoneme.StartsWith("_");
78+
}
79+
80+
public string[] Query(string lyric){
81+
string consonant = string.Empty;
82+
string vowel = string.Empty;
83+
if (lyric.Length > 2 && cSet.Contains(lyric.Substring(0, 2))) {
84+
// First try to find consonant "zh", "ch" or "sh", and extract vowel.
85+
consonant = lyric.Substring(0, 2);
86+
vowel = lyric.Substring(2);
87+
} else if (lyric.Length > 1 && cSet.Contains(lyric.Substring(0, 1))) {
88+
// Then try to find single character consonants, and extract vowel.
89+
consonant = lyric.Substring(0, 1);
90+
vowel = lyric.Substring(1);
91+
} else {
92+
// Otherwise the lyric is a vowel.
93+
vowel = lyric;
94+
}
95+
if ((vowel == "un" || vowel == "uan") && (consonant == "j" || consonant == "q" || consonant == "x" || consonant == "y")) {
96+
vowel = "v" + vowel.Substring(1);
97+
}
98+
if ((vowel == "an") && (consonant == "y")) {
99+
vowel = "ian";
100+
}
101+
if(vDict.TryGetValue(vowel, out var tail)){
102+
return new string[] { lyric, tail };
103+
}else{
104+
return new string[] { lyric };
105+
}
106+
107+
}
108+
public bool IsValidSymbol(string symbol){
109+
return true;
110+
}
111+
112+
public string[] UnpackHint(string hint, char separator = ' ') {
113+
return hint.Split(separator)
114+
.ToArray();
115+
}
116+
}
117+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace OpenUtau.Plugin.Builtin
7+
{
8+
public abstract class MonophonePhonemizer : SyllableBasedPhonemizer
9+
{
10+
protected override string GetDictionaryName() => "";
11+
protected override List<string> ProcessSyllable(Syllable syllable){
12+
return syllable.cc.Append(syllable.v).ToList();
13+
}
14+
15+
protected override List<string> ProcessEnding(Ending ending){
16+
return ending.cc.ToList();
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)