Skip to content

Commit

Permalink
Added en-US Phonemizer
Browse files Browse the repository at this point in the history
  • Loading branch information
EX3exp committed Sep 26, 2024
1 parent 732519a commit 5c5a1f1
Show file tree
Hide file tree
Showing 15 changed files with 135,236 additions and 27 deletions.
134,879 changes: 134,879 additions & 0 deletions Mirivoice/Assets/Plugin.Datas/cmudict.txt

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions Mirivoice/Mirivoice.Core/Editor/VoicerSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;

namespace Mirivoice.Mirivoice.Core.Editor
Expand Down Expand Up @@ -175,7 +176,8 @@ public void UpdateVoicerCollection()
}

bool Undobackuped = false;

CultureInfo lastCulture;
public bool CultureChanged = false;
public int CurrentDefaultVoicerIndex
{
get
Expand All @@ -193,7 +195,8 @@ public int CurrentDefaultVoicerIndex
return;
}
lastDefaultVoicerIndex = _currentDefaultVoicerIndex;


lastCulture = new CultureInfo(CurrentVoicer.Info.LangCode);
//Log.Debug("CurrentDefaultVoicerIndex: {value}", value);

//Log.Debug($"LastDefaultVoicerIndex: {lastDefaultVoicerIndex}");
Expand Down Expand Up @@ -221,11 +224,20 @@ public int CurrentDefaultVoicerIndex
this.RaiseAndSetIfChanged(ref _currentDefaultVoicerIndex, value);
_currentVoicer = Voicers[_currentDefaultVoicerIndex];
_currentVoicer.RefreshNickAndStyle();

v.OnVoicerChanged(_currentVoicer);
OnPropertyChanged(nameof(CurrentVoicer));
OnPropertyChanged(nameof(CurrentDefaultVoicerIndex));


if (lastCulture != new CultureInfo(CurrentVoicer.Info.LangCode))
{
CultureChanged = true;
v.OnVoicerCultureChanged(new CultureInfo(CurrentVoicer.Info.LangCode));
}
else
{
CultureChanged = false;
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions Mirivoice/Mirivoice.Core/Format/MResult.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Mirivoice.Mirivoice.Core.Editor;
using Mirivoice.ViewModels;
using System.Globalization;
using VYaml.Annotations;

namespace Mirivoice.Mirivoice.Core.Format
Expand Down Expand Up @@ -48,5 +49,6 @@ public MResult(MResultPrototype mResultPrototype): base(mResultPrototype.Phoneme

}
public override void OnVoicerChanged(Voicer value) { }
public override void OnVoicerCultureChanged(CultureInfo culture) { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Mirivoice.Mirivoice.Plugins.Builtin.Phonemizers.Utils;
using Serilog;
using System.Collections.Generic;
using System.Linq;
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Collections.Generic;

Check warning on line 10 in Mirivoice/Mirivoice.Plugins.Builtin/IPAConverters/EnglishUSIPAConverter.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

The using directive for 'System.Collections.Generic' appeared previously in this namespace

Check warning on line 10 in Mirivoice/Mirivoice.Plugins.Builtin/IPAConverters/EnglishUSIPAConverter.cs

View workflow job for this annotation

GitHub Actions / build (linux-x64)

The using directive for 'System.Collections.Generic' appeared previously in this namespace

Check warning on line 10 in Mirivoice/Mirivoice.Plugins.Builtin/IPAConverters/EnglishUSIPAConverter.cs

View workflow job for this annotation

GitHub Actions / build (osx-x64)

The using directive for 'System.Collections.Generic' appeared previously in this namespace

namespace Mirivoice.Mirivoice.Plugins.Builtin.IPAConverters
{
public class EnglishUSIPAConverter : BaseIPAConverter
{
// Many things are from https://github.com/wwesantos/arpabet-to-ipa/tree/master

private readonly Dictionary<string, string> ArpaToIPA = new Dictionary<string, string>
{
{ "AO", "ɔ" },
{ "AA", "ɑ" },
{ "IY", "i" },
{ "UW", "u" },
{ "EH", "e" }, // modern versions use 'e' instead of 'ɛ'
{ "IH", "ɪ" },
{ "UH", "ʊ" },
{ "AH", "ʌ" },
{ "AH0", "ə" },
{ "AE", "æ" },
{ "AX", "ə" },
{ "EY", "eɪ" },
{ "AY", "aɪ" },
{ "OW", "oʊ" },
{ "AW", "aʊ" },
{ "OY", "ɔɪ" },
{ "P", "p" },
{ "B", "b" },
{ "T", "t" },
{ "D", "d" },
{ "K", "k" },
{ "G", "g" },
{ "CH", "tʃ" },
{ "JH", "dʒ" },
{ "F", "f" },
{ "V", "v" },
{ "TH", "θ" },
{ "DH", "ð" },
{ "S", "s" },
{ "Z", "z" },
{ "SH", "ʃ" },
{ "ZH", "ʒ" },
{ "HH", "h" },
{ "M", "m" },
{ "N", "n" },
{ "NG", "ŋ" },
{ "L", "l" },
{ "R", "r" },
{ "ER", "ɜr" },
{ "AXR", "ər" },
{ "W", "w" },
{ "Y", "j" }
};


public override string ConvertToIPA(string phoneme, bool isFirstPhoneme)
{
List<string> IPA = new List<string>();
foreach (string phone in phoneme.Split(" ", StringSplitOptions.RemoveEmptyEntries))
{
if (ArpaToIPA.ContainsKey(phone.ToUpper()))
{
IPA.Add(ArpaToIPA[phone.ToUpper()]);
}
else
{
IPA.Add(phone);
}
}
string res = string.Join("\t", IPA);
//Log.Debug($"Converted {phoneme} to {res}");
return res;
}
}
}
21 changes: 9 additions & 12 deletions Mirivoice/Mirivoice.Plugins.Builtin/Phonemizers/BasePhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public abstract class BasePhonemizer
private List<string> endPuncs = new List<string> { ".", "!", "?", "。" };
protected virtual string[] SplitToWords(string sentence)
{
// In default, split sentence to words by character
// you can override if needed
char[] charArr = sentence.ToCharArray();
List<string> words = new List<string>();
Expand All @@ -33,8 +34,10 @@ protected virtual string[] SplitToWords(string sentence)

protected virtual string[] VariateAndSplitToWords(string sentence)
{
// In default, apply variation(e.g. Phoneme Variation in Korean) and split variated sentence to words by character
// you can override if needed
// split sentences with punctuation
// to fix variating mechanism, you can override Variate method
string[] unitSentences = Regex.Split(sentence, @"([^\w\s])");

List<string> newSentences = new List<string>();
Expand All @@ -47,13 +50,7 @@ protected virtual string[] VariateAndSplitToWords(string sentence)
}
}

char[] charArr = string.Join("", newSentences).ToCharArray();
List<string> words = new List<string>();
foreach (char c in charArr)
{
words.Add(c.ToString());
}
return words.ToArray();
return SplitToWords(string.Join("", newSentences));
}

protected virtual string Variate(string sentence)
Expand All @@ -71,16 +68,16 @@ public bool IsPunctuation(string word)
}


protected virtual string[] ToPhonemes(string word, out bool isEditable)
protected virtual string ToPhoneme(string word, out bool isEditable)
{
if (word.Trim() == string.Empty)
{

isEditable = false;
return new string[] { string.Empty };
return string.Empty;
}
isEditable = true;
return new string[] { word };
return word;
}


Expand Down Expand Up @@ -111,7 +108,7 @@ await Dispatcher.UIThread.InvokeAsync(async () =>
var wordTasks = variatedWords
.Select(async (word, index) => await Task.Run(()=>
{
string phoneme = string.Join("", ToPhonemes(word, out _));
string phoneme = ToPhoneme(word, out _);
if (words.Length != variatedWords.Length)
{
Log.Error($"[ConvertToIPA: Variated Sentence({words.Length})] - [Sentence length({variatedWords.Length})] mismatch");
Expand Down Expand Up @@ -245,7 +242,7 @@ await Dispatcher.UIThread.InvokeAsync(async () =>
.Select(async (word, index) =>
{

string phoneme = string.Join("", ToPhonemes(word, out editable));
string phoneme = ToPhoneme(word, out editable);
if (words.Length != variatedWords.Length)
{
Log.Error($"[Variated Sentence({words.Length})] - [Sentence length({variatedWords.Length})] mismatch");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Mirivoice.Mirivoice.Plugins.Builtin.IPAConverters;
using Mirivoice.Mirivoice.Plugins.Builtin.Phonemizers.Utils;
using Serilog;
using System;
using System.Collections.Generic;
using System.Text;

namespace Mirivoice.Mirivoice.Plugins.Builtin.Phonemizers
{
public class EnglishUSPhonemizer : BasePhonemizer
{
public override BaseIPAConverter IPAConverter { get; set; } = new EnglishUSIPAConverter();
public override bool UseWordDivider { get; set; } = true;

protected override string[] SplitToWords(string sentence)
{
List<string> words = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (string word in sentence.Split())
{
char[] charArr = word.ToCharArray();
bool LastWasPunctuation = false;
foreach (char c in charArr)
{
if (IsPunctuation(c.ToString()))
{
words.Add(sb.ToString());
sb.Clear();

sb.Append(c);
LastWasPunctuation = true;
continue;
}
if (!IsPunctuation(c.ToString()))
{
if (LastWasPunctuation)
{
words.Add(sb.ToString());
sb.Clear();
LastWasPunctuation = false;
}

sb.Append(c);
}

}
words.Add(sb.ToString());
sb.Clear();
}
return words.ToArray();
}

protected override string ToPhoneme(string word, out bool isEditable)
{
if (word.Trim() == string.Empty)
{

isEditable = false;
return word;
}
isEditable = true;
return EnglishUSPhonemizerUtil.WordToArpabet(word); // k ae t
}
}
}
57 changes: 57 additions & 0 deletions Mirivoice/Mirivoice.Plugins.Builtin/Phonemizers/Utils/CmuDict.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Avalonia.Platform;
using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mirivoice.Mirivoice.Plugins.Builtin.Phonemizers.Utils
{
public class CmuDict
{
public Dictionary<string, string> CMUDict;

public CmuDict()
{
CMUDict = new Dictionary<string, string>();
var uri = new Uri("avares://Mirivoice/Assets/Plugin.Datas/cmudict.txt");
var assets = AssetLoader.Open(uri);

using (var stream = assets)
{
using (var reader = new StreamReader(stream))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
var parts = line.Split(" ", 2);
if (parts.Length == 2)
{
string phone = parts[1].ToLower().Trim();
foreach (string p in phone.Split())
{
// Remove stress markers, except ah0
if (p.EndsWith("0") && p != "ah0")
{
phone = phone.Replace(p, p.Substring(0, p.Length - 1));
}
else if (p.EndsWith("1") || p.EndsWith("2"))
{
phone = phone.Replace(p, p.Substring(0, p.Length - 1));
}
}
CMUDict[parts[0].Trim().ToLower()] = phone;
}

}
}
}

Log.Information("CMU Dict loaded");


}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Avalonia.Media;
using Avalonia.Platform;
using Serilog;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mirivoice.Mirivoice.Plugins.Builtin.Phonemizers.Utils
{
/// <summary>
/// Should call InitCMUDict() before using WordToArpabet
/// </summary>
public static class EnglishUSPhonemizerUtil
{
private static CmuDict cmuDict = new CmuDict();


public static string WordToArpabet(string word)
{
// use the CMU Pronouncing Dictionary to convert words to ARPAbet
string arpabetRes = cmuDict.CMUDict.TryGetValue(word.ToLower(), out string arpabet) ? arpabet.ToLower() : word;
//Log.Debug($"WordToArpabet: {word} -> {arpabetRes}");
return arpabetRes;

}
}
}
Loading

0 comments on commit 5c5a1f1

Please sign in to comment.