Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions OpenUtau.Core/Classic/PresampWatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.IO;
using Serilog;

namespace OpenUtau.Core {
public class PresampWatcher : IDisposable {
public bool Paused { get; set; }

private FileSystemWatcher watcher;
private Action reloadCallback;

public PresampWatcher(string path, Action reloadCallback) {
this.reloadCallback = reloadCallback;

watcher = new FileSystemWatcher(path);
watcher.Changed += OnFileChanged;
watcher.Created += OnFileChanged;
watcher.Deleted += OnFileChanged;
watcher.Renamed += OnFileChanged;
watcher.Error += OnError;

watcher.Filter = "presamp.ini";
// Set to false since presamp.ini is always at the root of the voicebank
watcher.IncludeSubdirectories = false;
watcher.EnableRaisingEvents = true;
}

private void OnFileChanged(object sender, FileSystemEventArgs e) {
if (Paused) {
return;
}
Log.Information($"Presamp File \"{e.FullPath}\" {e.ChangeType}");
reloadCallback?.Invoke();
}

private void OnError(object sender, ErrorEventArgs e) {
Log.Error($"Presamp Watcher error {e}");
}
public void Dispose() {
if (watcher != null) {
watcher.Dispose();
}
}
}
}
48 changes: 48 additions & 0 deletions OpenUtau.Core/Classic/YamlWatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.IO;
using Serilog;

namespace OpenUtau.Core {
public class YamlWatcher : IDisposable {
public bool Paused { get; set; }

private FileSystemWatcher watcher;
private Action reloadCallback;

public YamlWatcher(string path, Action reloadCallback) {
this.reloadCallback = reloadCallback;

watcher = new FileSystemWatcher(path);
watcher.Changed += OnFileChanged;
watcher.Created += OnFileChanged;
watcher.Deleted += OnFileChanged;
watcher.Renamed += OnFileChanged;
watcher.Error += OnError;

// Filters specifically for .yaml.
watcher.Filter = "*.yaml";
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
}

private void OnFileChanged(object sender, FileSystemEventArgs e) {
if (Paused) {
return;
}
Log.Information($"YAML File \"{e.FullPath}\" {e.ChangeType}");

// Execute the refresh logic passed in during initialization
reloadCallback?.Invoke();
}

private void OnError(object sender, ErrorEventArgs e) {
Log.Error($"YAML Watcher error {e}");
}

public void Dispose() {
if (watcher != null) {
watcher.Dispose();
}
}
}
}
34 changes: 33 additions & 1 deletion OpenUtau.Core/DiffSinger/DiffSingerBasePhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public abstract class DiffSingerBasePhonemizer : MachineLearningPhonemizer
IG2p g2p;
Dictionary<string, int> phonemeTokens;
DiffSingerSpeakerEmbedManager speakerEmbedManager;
private static int globalDsGeneration = 0;
private int localDsGeneration = 0;
private static YamlWatcher dsWatcher;
private static string currentlyWatchedDsDir;

string defaultPause = "SP";
protected virtual string GetDictionaryName()=>"dsdict.yaml";
Expand All @@ -35,9 +39,11 @@ public abstract class DiffSingerBasePhonemizer : MachineLearningPhonemizer
private bool _singerLoaded;

public override void SetSinger(USinger singer) {
if (_singerLoaded && singer == this.singer) return;
if (_singerLoaded && singer == this.singer && localDsGeneration == globalDsGeneration) return;
try {
localDsGeneration = globalDsGeneration;
_singerLoaded = _executeSetSinger(singer);
SetupYamlWatcher(rootPath);
} catch {
_singerLoaded = false;
throw;
Expand Down Expand Up @@ -103,6 +109,32 @@ private bool _executeSetSinger(USinger singer) {
return true;
}

private void SetupYamlWatcher(string directory) {
if (string.IsNullOrEmpty(directory) || currentlyWatchedDsDir == directory) {
return;
}

if (dsWatcher != null) {
dsWatcher.Dispose();
dsWatcher = null;
}

currentlyWatchedDsDir = directory;

if (Directory.Exists(directory)) {
dsWatcher = new YamlWatcher(directory, () => {
Log.Information($"[DiffSingerBasePhonemizer] Detected YAML change in {directory}. Reloading globally...");
System.Threading.Thread.Sleep(200);
globalDsGeneration++;

// Signal OpenUtau to re-run the timeline runner
if (this.singer != null) {
OpenUtau.Core.SingerManager.Inst.ScheduleReload(this.singer);
}
});
}
}

protected virtual IG2p LoadG2p(string rootPath, bool useLangId = false) {
//Each phonemizer has a delicated dictionary name, such as dsdict-en.yaml, dsdict-ru.yaml.
//If this dictionary exists, load it.
Expand Down
4 changes: 3 additions & 1 deletion OpenUtau.Plugin.Builtin/ArpasingPlusPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ protected override IG2p LoadBaseDictionary() {
public override void SetSinger(USinger singer) {
base.SetSinger(singer);

if (this.singer != null && this.singer.Loaded) {
if (this.singer != singer || this.localYamlGeneration != globalYamlGeneration) {
this.singer = singer;
this.localYamlGeneration = globalYamlGeneration;

consExceptions.Clear();
if (stop != null) consExceptions.AddRange(stop);
Expand Down
4 changes: 3 additions & 1 deletion OpenUtau.Plugin.Builtin/EnglishCpVPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ protected override IG2p LoadBaseDictionary() {
public override void SetSinger(USinger singer) {
base.SetSinger(singer);

if (this.singer != null && this.singer.Loaded) {
if (this.singer != singer || this.localYamlGeneration != globalYamlGeneration) {
this.singer = singer;
this.localYamlGeneration = globalYamlGeneration;

string file = Path.Combine(this.singer.Location, YamlFileName);
if (!File.Exists(file)) {
Expand Down
4 changes: 3 additions & 1 deletion OpenUtau.Plugin.Builtin/FilipinoPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ protected override IG2p LoadBaseDictionary() {
public override void SetSinger(USinger singer) {
base.SetSinger(singer);

if (this.singer != null && this.singer.Loaded) {
if (this.singer != singer || this.localYamlGeneration != globalYamlGeneration) {
this.singer = singer;
this.localYamlGeneration = globalYamlGeneration;

consExceptions.Clear();
if (stop != null) consExceptions.AddRange(stop);
Expand Down
39 changes: 36 additions & 3 deletions OpenUtau.Plugin.Builtin/JapanesePresampPhonemizer.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Classic;
using OpenUtau.Api;
using OpenUtau.Core;
using OpenUtau.Core.Ustx;
//using Serilog;

Expand All @@ -23,6 +25,11 @@ public class JapanesePresampPhonemizer : Phonemizer {
private UProject project;
private UTrack track;

private static int globalPresampGeneration = 0;
private int localPresampGeneration = 0;
private static PresampWatcher presampWatcher;
private static string currentlyWatchedPresampDir;

// in case voicebank is missing certain symbols
static readonly string[] substitution = new string[] {
"ty,ch,ts=t", "j,dy=d", "gy=g", "ky=k", "py=p", "ny=n", "ry=r", "my=m", "hy,f=h", "by,v=b", "dz=z", "l=r", "ly=l"
Expand All @@ -45,16 +52,42 @@ public override void SetUp(Note[][] groups, UProject project, UTrack track) {
}

public override void SetSinger(USinger singer) {
if (this.singer == singer) {
bool generationChanged = this.localPresampGeneration != globalPresampGeneration;

if (this.singer == singer && !generationChanged) {
return;
}
this.singer = singer;
if (this.singer == null) {
return;
}
this.localPresampGeneration = globalPresampGeneration;

if (this.presamp == null || generationChanged) {
this.presamp = new Presamp();
this.presamp.ReadPresampIni(singer.Location, singer.TextFileEncoding);
}
SetupPresampWatcher(singer.Location);
}

presamp = new Presamp();
presamp.ReadPresampIni(singer.Location, singer.TextFileEncoding);
private void SetupPresampWatcher(string directory) {
if (string.IsNullOrEmpty(directory) || currentlyWatchedPresampDir == directory) {
return;
}
if (presampWatcher != null) {
presampWatcher.Dispose();
presampWatcher = null;
}
currentlyWatchedPresampDir = directory;
if (Directory.Exists(directory)) {
presampWatcher = new PresampWatcher(directory, () => {
System.Threading.Thread.Sleep(200);
globalPresampGeneration++;
if (this.singer != null) {
OpenUtau.Core.SingerManager.Inst.ScheduleReload(this.singer);
}
});
}
}

public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevNeighbour, Note? nextNeighbour, Note[] prevNeighbours) {
Expand Down
53 changes: 49 additions & 4 deletions OpenUtau.Plugin.Builtin/SyllableBasedPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Threading.Tasks;
using static OpenUtau.Api.Phonemizer;
using System.Collections;
using OpenUtau.Core;

namespace OpenUtau.Plugin.Builtin {
/// <summary>
Expand Down Expand Up @@ -256,8 +257,9 @@ private Result HandleError() {
}

public override void SetSinger(USinger singer) {
if (this.singer != singer) {
if (this.singer != singer || this.localYamlGeneration != globalYamlGeneration) {
this.singer = singer;
this.localYamlGeneration = globalYamlGeneration;

if (this.singer == null || !this.singer.Loaded) {
return;
Expand Down Expand Up @@ -291,6 +293,8 @@ public override void SetSinger(USinger singer) {
file = Path.Combine(PluginDir, YamlFileName);
}

SetupYamlWatcher(file);

if (!string.IsNullOrEmpty(file)) {
bool shouldWriteTemplate = false;
bool shouldBackupOldFile = false;
Expand Down Expand Up @@ -337,15 +341,15 @@ public override void SetSinger(USinger singer) {

if (File.Exists(file)) {
try {
var data = Core.Yaml.DefaultDeserializer.Deserialize<YAMLData>(File.ReadAllText(file));
var data = Core.Yaml.DefaultDeserializer.Deserialize<YAMLData>(File.ReadAllText(file)) ?? new YAMLData();

if (backupVowels == null) backupVowels = GetVowels() ?? Array.Empty<string>();
if (backupConsonants == null) backupConsonants = GetConsonants() ?? Array.Empty<string>();

var yamlVowels = data.symbols?.Where(s => s.type == "vowel" || s.type == "diphthong").Select(s => s.symbol).ToArray() ?? Array.Empty<string>();
vowels = backupVowels.Concat(yamlVowels).Distinct().ToArray();

tails = (tails ?? Array.Empty<string>()).Concat(data.symbols?.Where(s => s.type == "tail").Select(s => s.symbol) ?? Array.Empty<string>()).Distinct().ToArray();
tails = new string[] { "-", "R" }.Concat(data.symbols?.Where(s => s.type == "tail").Select(s => s.symbol) ?? Array.Empty<string>()).Distinct().ToArray();

fricative = data.symbols?.Where(s => s.type == "fricative").Select(s => s.symbol).Distinct().ToArray() ?? Array.Empty<string>();
aspirate = data.symbols?.Where(s => s.type == "aspirate").Select(s => s.symbol).Distinct().ToArray() ?? Array.Empty<string>();
Expand Down Expand Up @@ -384,7 +388,7 @@ public override void SetSinger(USinger singer) {
}
}
}

yamlFallbacks.Clear();
if (data?.fallbacks != null) {
yamlFallbacks.Clear();
foreach (var df in data.fallbacks) {
Expand Down Expand Up @@ -412,6 +416,10 @@ public override void SetSinger(USinger singer) {
protected IG2p dictionary => dictionaries[GetType()];
protected bool isDictionaryLoading => dictionaries[GetType()] == null;
protected double TransitionBasicLengthMs => 100;
public static YamlWatcher yamlWatcher;
public static string currentlyWatchedYaml;
public static int globalYamlGeneration = 0;
public int localYamlGeneration = 0;

private Dictionary<Type, IG2p> dictionaries = new Dictionary<Type, IG2p>();
private const string FORCED_ALIAS_SYMBOL = "?";
Expand Down Expand Up @@ -745,6 +753,43 @@ protected double GetTransitionBasicLengthMsByConstant() {
return TransitionBasicLengthMs * GetTempoNoteLengthFactor();
}

private void SetupYamlWatcher(string yamlFilePath) {
if (string.IsNullOrEmpty(yamlFilePath) || currentlyWatchedYaml == yamlFilePath) {
return;
}

if (yamlWatcher != null) {
yamlWatcher.Dispose();
yamlWatcher = null;
}

currentlyWatchedYaml = yamlFilePath;
string directory = Path.GetDirectoryName(yamlFilePath);

if (Directory.Exists(directory)) {
yamlWatcher = new YamlWatcher(directory, () => {
Log.Information($"[SyllableBasedPhonemizer] Detected change in {YamlFileName}, incrementing generation...");

System.Threading.Thread.Sleep(200);

lock (dictionaries) {
if (dictionaries.ContainsKey(this.GetType())) {
dictionaries.Remove(this.GetType());
}
}

backupVowels = null;
backupConsonants = null;
backupDictionaryReplacements = null;
globalYamlGeneration++;

if (this.singer != null) {
OpenUtau.Core.SingerManager.Inst.ScheduleReload(this.singer);
}
});
}
}

/// <summary>
/// a note length modifier, from 1 to 0.3. Used to make transition notes shorter on high tempo
/// </summary>
Expand Down
Loading