Skip to content

Commit

Permalink
Merge pull request #1000 from oxygen-dioxide/g2p-glide
Browse files Browse the repository at this point in the history
G2p: add IsGlide method; EN ARPA: support glide phonemes.
  • Loading branch information
stakira authored Jan 25, 2024
2 parents 25e41fd + 9de093f commit 236f747
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 5 deletions.
22 changes: 20 additions & 2 deletions OpenUtau.Core/Api/G2pDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ class TrieNode {

TrieNode root;
Dictionary<string, bool> phonemeSymbols; // (phoneme, isVowel)
HashSet<string> glideSymbols;

G2pDictionary(TrieNode root, Dictionary<string, bool> phonemeSymbols) {
G2pDictionary(TrieNode root, Dictionary<string, bool> phonemeSymbols, HashSet<string> glideSymbols) {
this.root = root;
this.phonemeSymbols = phonemeSymbols;
this.glideSymbols = glideSymbols;
}

public bool IsValidSymbol(string symbol) {
Expand All @@ -30,6 +32,10 @@ public bool IsVowel(string symbol) {
return phonemeSymbols.TryGetValue(symbol, out var isVowel) && isVowel;
}

public bool IsGlide(string symbol) {
return glideSymbols.Contains(symbol);
}

public string[] Query(string grapheme) {
return QueryTrie(root, grapheme, 0);
}
Expand All @@ -56,23 +62,35 @@ string[] QueryTrie(TrieNode node, string word, int index) {
public class Builder {
TrieNode root;
Dictionary<string, bool> phonemeSymbols; // (phoneme, isVowel)
HashSet<string> glideSymbols;

internal Builder() {
root = new TrieNode();
phonemeSymbols = new Dictionary<string, bool>();
glideSymbols = new HashSet<string>();
}

/// <summary>
/// Add valid symbols of dictionary.
/// </summary>
public Builder AddSymbol(string symbol, string type) {
phonemeSymbols[symbol] = type == "vowel";
if(type == "semivowel" || type == "liquid") {
glideSymbols.Add(symbol);
}
return this;
}
public Builder AddSymbol(string symbol, bool isVowel) {
phonemeSymbols[symbol] = isVowel;
return this;
}
public Builder AddSymbol(string symbol, bool isVowel, bool isGlide) {
phonemeSymbols[symbol] = isVowel;
if (isGlide && !isVowel) {
glideSymbols.Add(symbol);
}
return this;
}

/// <summary>
/// Must finish adding symbols before adding entries, otherwise symbols get ignored.
Expand Down Expand Up @@ -123,7 +141,7 @@ public Builder Load(TextReader textReader) {
}

public G2pDictionary Build() {
return new G2pDictionary(root, phonemeSymbols);
return new G2pDictionary(root, phonemeSymbols, glideSymbols);
}
}

Expand Down
9 changes: 9 additions & 0 deletions OpenUtau.Core/Api/G2pFallbacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ public bool IsVowel(string symbol) {
return false;
}

public bool IsGlide(string symbol) {
foreach (var dict in dictionaries) {
if (dict.IsValidSymbol(symbol)) {
return dict.IsGlide(symbol);
}
}
return false;
}

public string[] Query(string grapheme) {
foreach (var dict in dictionaries) {
var result = dict.Query(grapheme);
Expand Down
4 changes: 4 additions & 0 deletions OpenUtau.Core/Api/G2pPack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public bool IsVowel(string symbol) {
return Dict.IsVowel(symbol);
}

public bool IsGlide(string symbol) {
return Dict.IsGlide(symbol);
}

public string[] Query(string grapheme) {
if (grapheme.Length == 0 || kAllPunct.IsMatch(grapheme)) {
return null;
Expand Down
9 changes: 8 additions & 1 deletion OpenUtau.Core/Api/G2pRemapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ namespace OpenUtau.Api {
public class G2pRemapper : IG2p {
private IG2p mapped;
private Dictionary<string, bool> phonemeSymbols; // (phoneme, isVowel)
private HashSet<string> glideSymbols;
private Dictionary<string, string> replacements;

public G2pRemapper(IG2p mapped,
Dictionary<string, bool> phonemeSymbols,
Dictionary<string, string> replacements) {
Dictionary<string, string> replacements,
HashSet<string> glideSymbols = null) {
this.mapped = mapped;
this.phonemeSymbols = phonemeSymbols;
this.replacements = replacements;
this.glideSymbols = glideSymbols ?? new HashSet<string>();
}

public bool IsValidSymbol(string symbol) {
Expand All @@ -23,6 +26,10 @@ public bool IsVowel(string symbol) {
return phonemeSymbols.TryGetValue(symbol, out var isVowel) && isVowel;
}

public bool IsGlide(string symbol) {
return glideSymbols.Contains(symbol);
}

public string[] Query(string grapheme) {
var phonemes = mapped.Query(grapheme);
if (phonemes == null) {
Expand Down
5 changes: 5 additions & 0 deletions OpenUtau.Core/Api/IG2p.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ public interface IG2p {
bool IsValidSymbol(string symbol);
bool IsVowel(string symbol);

/// <summary>
/// Returns true if the symbol is a semivowel or liquid phoneme, like y, w, l, r in English.
/// </summary>
bool IsGlide(string symbol);

/// <summary>
/// Produces a list of phonemes from grapheme.
/// </summary>
Expand Down
4 changes: 4 additions & 0 deletions OpenUtau.Plugin.Builtin/ChineseCVVPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ public bool IsVowel(string phoneme){
return !phoneme.StartsWith("_");
}

public bool IsGlide(string phoneme){
return false;
}

public string[] Query(string lyric){
// The overall logic is:
// 1. Remove consonant: "duang" -> "uang".
Expand Down
11 changes: 9 additions & 2 deletions OpenUtau.Plugin.Builtin/PhonemeBasedPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
return MakeSimpleResult(note.lyric);
}
// Find phone types of symbols.
var isVowel = symbols.Select(s => g2p.IsVowel(s)).ToArray();
var isVowel = symbols.Select(g2p.IsVowel).ToArray();
var isGlide = symbols.Select(g2p.IsGlide).ToArray();
// Arpasing aligns the first vowel at 0 and shifts leading consonants to negative positions,
// so we need to find the first vowel.
var phonemes = new Phoneme[symbols.Length];
Expand All @@ -94,7 +95,13 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
var nonExtensionNotes = notes.Where(n=>!IsSyllableVowelExtensionNote(n)).ToArray();
for (int i = 0; i < symbols.Length; i++) {
if (isVowel[i] && alignments.Count < nonExtensionNotes.Length) {
alignments.Add(Tuple.Create(i, nonExtensionNotes[alignments.Count].position - notes[0].position, false));
//Handle glide phonemes
//For "Consonant-Glide-Vowel" syllable, the glide phoneme is placed after the start position of the note.
if(i>=2 && isGlide[i-1] && !isVowel[i-2]){
alignments.Add(Tuple.Create(i-1, nonExtensionNotes[alignments.Count].position - notes[0].position, false));
} else{
alignments.Add(Tuple.Create(i, nonExtensionNotes[alignments.Count].position - notes[0].position, false));
}
}
}
int position = notes[0].duration;
Expand Down

0 comments on commit 236f747

Please sign in to comment.