Skip to content

Commit

Permalink
Merge branch 'AddVoicevox' of https://github.com/rokujyushi/OpenUtau
Browse files Browse the repository at this point in the history
…into AddVoicevox
  • Loading branch information
rokujyushi committed Mar 23, 2024
2 parents e0a3ad0 + 8c0a329 commit b174a0e
Show file tree
Hide file tree
Showing 56 changed files with 1,141 additions and 585 deletions.
2 changes: 2 additions & 0 deletions OpenUtau.Core/Api/Phonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ public struct Phoneme {
/// </summary>
public PhonemeAttributes attributes;

public int? index;

public override string ToString() => $"\"{phoneme}\" pos:{position}";
}

Expand Down
2 changes: 1 addition & 1 deletion OpenUtau.Core/Classic/ClassicSinger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public override void Reload() {
void Load() {
if (Avatar != null && File.Exists(Avatar)) {
try {
using (var stream = new FileStream(Avatar, FileMode.Open)) {
using (var stream = new FileStream(Avatar, FileMode.Open, FileAccess.Read)) {
using (var memoryStream = new MemoryStream()) {
stream.CopyTo(memoryStream);
avatarData = memoryStream.ToArray();
Expand Down
52 changes: 34 additions & 18 deletions OpenUtau.Core/Classic/VoicebankErrorChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,15 @@ public void Check() {
message = $"There are duplicate aliases.{message}"
});
}
//Cross platform check
//Windows path is case insensitive, while MacOS path and Linux path are case sensitive.
//On Windows, check if the wave filename in oto.ini is the same as the filename in the file system.
if(OS.IsWindows()){
foreach(var otoSet in voicebank.OtoSets) {
WindowsCaseCheck(otoSet);
}
WindowsCaseCheck(voicebank.BasePath, new string[]{
"chatacter.txt",
"character.yaml",
"prefix.map",
});
foreach(var otoSet in voicebank.OtoSets) {
CheckCaseMatchForFileReference(otoSet);
CheckDuplicatedNameIgnoringCase(otoSet);
}
//TODO: On MacOS and Linux, check if there are files that have the same name but different case.
CheckCaseMatchForFileReference(voicebank.BasePath, new string[]{
"chatacter.txt",
"character.yaml",
"prefix.map",
});
}

bool TryGetFileDuration(string filePath, Oto oto, out double fileDuration) {
Expand Down Expand Up @@ -260,16 +255,16 @@ bool FindDuplication(out List<Oto> duplicates) {
/// </summary>
/// <param name="otoSet">otoSet to be checked</param>
/// <returns></returns>
bool WindowsCaseCheck(OtoSet otoSet) {
return WindowsCaseCheck(
bool CheckCaseMatchForFileReference(OtoSet otoSet) {
return CheckCaseMatchForFileReference(
Directory.GetParent(otoSet.File).FullName,
otoSet.Otos
.Select(oto => oto.Wav)
.Append(otoSet.File)//oto.ini itself
.ToHashSet());
}

bool WindowsCaseCheck(string folder, IEnumerable<string> correctFileNames){
bool CheckCaseMatchForFileReference(string folder, IEnumerable<string> correctFileNames){
bool valid = true;
Dictionary<string, string> fileNamesLowerToActual = Directory.GetFiles(folder)
.Select(Path.GetFileName)
Expand All @@ -280,15 +275,36 @@ bool WindowsCaseCheck(string folder, IEnumerable<string> correctFileNames){
}
if (fileNamesLowerToActual[fileName.ToLower()] != fileName) {
valid = false;
Infos.Add(new VoicebankError() {
Errors.Add(new VoicebankError() {
message = $"Wrong case in file name: \n"
+ $"expected: {Path.Join(folder,fileName)}\n"
+ $"Actual: {Path.Join(folder,fileNamesLowerToActual[fileName.ToLower()])}\n"
+ $"voicebank may not work on another OS."
+ $"The voicebank may not work on another OS."
});
}
}
return valid;
}

/// <summary>
/// Check if the file names are duplicated when converted to lower case.
/// </summary>
/// <param name="otoSet">otoSet to be checked</param>
/// <returns></returns>
bool CheckDuplicatedNameIgnoringCase(OtoSet otoSet) {
var wavNames = otoSet.Otos.Select(x => x.Wav).Distinct().ToList();
var duplicatedGroups = wavNames.GroupBy(x => x.ToLower())
.Where(group => group.Count() > 1)
.ToList();
foreach (var group in duplicatedGroups) {
Errors.Add(new VoicebankError() {
message = $"Duplicated file names found when ignoreing case in oto set \"{otoSet.Name}\":"
+ string.Join(", ", group.Select(x => $"\"{x}\""))
+ ".\n"
+ "The voicebank may not work on another OS with case-sensitivity."
});
}
return duplicatedGroups.Count == 0;
}
}
}
83 changes: 83 additions & 0 deletions OpenUtau.Core/Classic/VoicebankPublisher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Ignore;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;

using OpenUtau.Core.Ustx;

namespace OpenUtau.Classic {
public class VoicebankPublisher {
private readonly Action<double, string> progress;
private readonly Ignore.Ignore? ignore;

public VoicebankPublisher(Action<double, string> progress, string? gitIgnore) {
this.progress = progress;
if(gitIgnore != null) {
ignore = new Ignore.Ignore();
ignore.Add(gitIgnore.Split("\n"));
}
}

private static void ModifyConfig(USinger singer, Action<VoicebankConfig> modify) {
var yamlFile = Path.Combine(singer.Location, "character.yaml");
VoicebankConfig? config = null;
if (File.Exists(yamlFile)) {
using (var stream = File.OpenRead(yamlFile)) {
config = VoicebankConfig.Load(stream);
}
}
if (config == null) {
config = new VoicebankConfig();
}
modify(config);
using (var stream = File.Open(yamlFile, FileMode.Create)) {
config.Save(stream);
}
}

private bool IsIgnored(string relativePath){
return ignore?.IsIgnored(relativePath.Replace('\\', '/')) ?? false;
}

private List<string> GetFilesToPack(string singerPath)
{
List<string> fileList = Directory.EnumerateFiles(singerPath, "*.*", SearchOption.AllDirectories).ToList();
List<string> packList = fileList.FindAll(x => !IsIgnored(System.IO.Path.GetRelativePath(singerPath, x)));
return packList;
}

///<summary>
///Compress a voicebank into an optimized zip archive for distribution.
///This function only supports voicebanks that follow the classic packaging model,
///including utau, enunu and diffsinger.
///Vogen voicebanks aren't supported.
///</summary>
public void Publish(USinger singer, string outputFile){
var location = singer.Location;
if(!Directory.Exists(location)){
return;
}
progress.Invoke(0, $"Publishing {singer.Name}");
//Write singer type into character.yaml
try {
ModifyConfig(singer, config => config.SingerType = singer.SingerType.ToString().ToLower());
} catch (Exception e) { }
var packList = GetFilesToPack(location);
int index = 0;
int fileCount = packList.Count();
using(ZipArchive archive = new ZipArchive(File.Create(outputFile), ZipArchiveMode.Create))
{
foreach (var absFilePath in packList)
{
index++;
progress.Invoke(100.0 * index / fileCount, $"Compressing {absFilePath}");
string reFilePath = Path.GetRelativePath(location, absFilePath);
archive.CreateEntryFromFile(absFilePath, reFilePath);
}
}
progress.Invoke(0, $"Published {singer.Name} to {outputFile}");
}
}
}
22 changes: 13 additions & 9 deletions OpenUtau.Core/Commands/ExpCommands.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;

using OpenUtau.Core.Ustx;
using OpenUtau.Core.Util;

Expand All @@ -24,15 +23,15 @@ public ExpCommand(UVoicePart part) {
public class SetNoteExpressionCommand : ExpCommand {
public readonly UProject project;
public readonly UTrack track;
public readonly float[] newValue;
public readonly float[] oldValue;
public SetNoteExpressionCommand(UProject project, UTrack track, UVoicePart part, UNote note, string abbr, float[] values) : base(part) {
public readonly float?[] newValue;
public readonly float?[] oldValue;
public SetNoteExpressionCommand(UProject project, UTrack track, UVoicePart part, UNote note, string abbr, float?[] values) : base(part) {
this.project = project;
this.track = track;
this.Note = note;
Key = abbr;
newValue = values;
oldValue = note.GetExpression(project, track, abbr).Select(t => t.Item1).ToArray();
oldValue = note.GetExpressionNoteHas(project, track, abbr);
}
public override string ToString() => $"Set note expression {Key}";
public override void Execute() => Note.SetExpression(project, track, Key, newValue);
Expand All @@ -47,21 +46,26 @@ public class SetPhonemeExpressionCommand : ExpCommand {
public readonly UProject project;
public readonly UTrack track;
public readonly UPhoneme phoneme;
public readonly float newValue;
public readonly float oldValue;
public readonly float? newValue;
public readonly float? oldValue;
public override ValidateOptions ValidateOptions
=> new ValidateOptions {
SkipTiming = true,
Part = Part,
SkipPhonemizer = !needsPhonemizer.Contains(Key),
};
public SetPhonemeExpressionCommand(UProject project, UTrack track, UVoicePart part, UPhoneme phoneme, string abbr, float value) : base(part) {
public SetPhonemeExpressionCommand(UProject project, UTrack track, UVoicePart part, UPhoneme phoneme, string abbr, float? value) : base(part) {
this.project = project;
this.track = track;
this.phoneme = phoneme;
Key = abbr;
newValue = value;
oldValue = phoneme.GetExpression(project, track, abbr).Item1;
var oldExp = phoneme.GetExpression(project, track, abbr);
if (oldExp.Item2) {
oldValue = oldExp.Item1;
} else {
oldValue = null;
}
}
public override string ToString() => $"Set phoneme expression {Key}";
public override void Execute() {
Expand Down
48 changes: 30 additions & 18 deletions OpenUtau.Core/DiffSinger/DiffSingerBasePhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ string[] GetSymbols(Note note) {
//1. phonetic hint
//2. query from g2p dictionary
//3. treat lyric as phonetic hint, including single phoneme
//4. default pause
//4. empty
if (!string.IsNullOrEmpty(note.phoneticHint)) {
// Split space-separated symbols into an array.
return note.phoneticHint.Split()
Expand All @@ -108,7 +108,7 @@ string[] GetSymbols(Note note) {
if (lyricSplited.Length > 0) {
return lyricSplited;
}
return new string[] { defaultPause };
return new string[] { };
}

string GetSpeakerAtIndex(Note note, int index){
Expand All @@ -122,21 +122,20 @@ string GetSpeakerAtIndex(Note note, int index){
return speaker.Suffix;
}

dsPhoneme[] GetDsPhonemes(Note note){
return GetSymbols(note)
.Select((symbol, index) => new dsPhoneme(symbol, GetSpeakerAtIndex(note, index)))
.ToArray();
}

protected bool IsSyllableVowelExtensionNote(Note note) {
return note.lyric.StartsWith("+~") || note.lyric.StartsWith("+*");
}

List<phonemesPerNote> ProcessWord(Note[] notes){
/// <summary>
/// distribute phonemes to each note inside the group
/// </summary>
List<phonemesPerNote> ProcessWord(Note[] notes, string[] symbols){
var wordPhonemes = new List<phonemesPerNote>{
new phonemesPerNote(-1, notes[0].tone)
};
var dsPhonemes = GetDsPhonemes(notes[0]);
var dsPhonemes = symbols
.Select((symbol, index) => new dsPhoneme(symbol, GetSpeakerAtIndex(notes[0], index)))
.ToArray();
var isVowel = dsPhonemes.Select(s => g2p.IsVowel(s.Symbol)).ToArray();
var isGlide = dsPhonemes.Select(s => g2p.IsGlide(s.Symbol)).ToArray();
var nonExtensionNotes = notes.Where(n=>!IsSyllableVowelExtensionNote(n)).ToArray();
Expand Down Expand Up @@ -217,8 +216,17 @@ protected override void ProcessPart(Note[][] phrase) {
new phonemesPerNote(-1,phrase[0][0].tone, new List<dsPhoneme>{new dsPhoneme("SP", GetSpeakerAtIndex(phrase[0][0], 0))})
};
var notePhIndex = new List<int> { 1 };
foreach (var word in phrase) {
var wordPhonemes = ProcessWord(word);
var wordFound = new bool[phrase.Length];
foreach (int wordIndex in Enumerable.Range(0, phrase.Length)) {
Note[] word = phrase[wordIndex];
var symbols = GetSymbols(word[0]);
if (symbols == null || symbols.Length == 0) {
symbols = new string[] { defaultPause };
wordFound[wordIndex] = false;
} else {
wordFound[wordIndex] = true;
}
var wordPhonemes = ProcessWord(word, symbols);
phrasePhonemes[^1].Phonemes.AddRange(wordPhonemes[0].Phonemes);
phrasePhonemes.AddRange(wordPhonemes.Skip(1));
notePhIndex.Add(notePhIndex[^1]+wordPhonemes.SelectMany(n=>n.Phonemes).Count());
Expand Down Expand Up @@ -310,20 +318,24 @@ protected override void ProcessPart(Note[][] phrase) {

//Convert the position sequence to tick and fill into the result list
int index = 1;
foreach (int groupIndex in Enumerable.Range(0, phrase.Length)) {
Note[] group = phrase[groupIndex];
foreach (int wordIndex in Enumerable.Range(0, phrase.Length)) {
Note[] word = phrase[wordIndex];
var noteResult = new List<Tuple<string, int>>();
if (group[0].lyric.StartsWith("+")) {
if (!wordFound[wordIndex]){
//partResult[word[0].position] = noteResult;
continue;
}
if (word[0].lyric.StartsWith("+")) {
continue;
}
double notePos = timeAxis.TickPosToMsPos(group[0].position);//start position of the note, ms
for (int phIndex = notePhIndex[groupIndex]; phIndex < notePhIndex[groupIndex + 1]; ++phIndex) {
double notePos = timeAxis.TickPosToMsPos(word[0].position);//start position of the note, ms
for (int phIndex = notePhIndex[wordIndex]; phIndex < notePhIndex[wordIndex + 1]; ++phIndex) {
if (!String.IsNullOrEmpty(phs[phIndex].Symbol)) {
noteResult.Add(Tuple.Create(phs[phIndex].Symbol, timeAxis.TicksBetweenMsPos(
notePos, positions[phIndex - 1])));
}
}
partResult[group[0].position] = noteResult;
partResult[word[0].position] = noteResult;
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion OpenUtau.Core/DiffSinger/DiffSingerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public class DsConfig {
public bool useKeyShiftEmbed = false;
public bool useSpeedEmbed = false;
public bool useEnergyEmbed = false;
public bool useBreathinessEmbed= false;
public bool useBreathinessEmbed = false;
public bool useVoicingEmbed = false;
public bool useTensionEmbed = false;
public AugmentationArgs augmentationArgs;
public bool useShallowDiffusion = false;
public int maxDepth = -1;
Expand All @@ -34,6 +36,10 @@ public class DsConfig {
public int hop_size = 512;
public int sample_rate = 44100;
public bool predict_dur = true;
public bool predict_energy = true;
public bool predict_breathiness = true;
public bool predict_voicing = false;
public bool predict_tension = false;
public bool use_expr = false;
public bool use_note_rest = false;
public float frameMs(){
Expand Down
2 changes: 1 addition & 1 deletion OpenUtau.Core/DiffSinger/DiffSingerPitch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public RenderPitchResult Process(RenderPhrase phrase){
new DenseTensor<Int64>(word_dur, new int[] { word_dur.Length }, false)
.Reshape(new int[] { 1, word_dur.Length })));
}else{
//if predict_dur is true, use phoneme encode mode
//if predict_dur is false, use phoneme encode mode
linguisticInputs.Add(NamedOnnxValue.CreateFromTensor("ph_dur",
new DenseTensor<Int64>(ph_dur.Select(x=>(Int64)x).ToArray(), new int[] { ph_dur.Length }, false)
.Reshape(new int[] { 1, ph_dur.Length })));
Expand Down
Loading

0 comments on commit b174a0e

Please sign in to comment.