Skip to content

Commit

Permalink
Merge pull request #973 from lottev1991/ZhCvvcAutoEnding
Browse files Browse the repository at this point in the history
[ZH CVVC] Automatically add syllable ending if present (if next neighbor is null)
  • Loading branch information
stakira authored Dec 11, 2023
2 parents a444156 + 1c02267 commit 343d861
Showing 1 changed file with 102 additions and 5 deletions.
107 changes: 102 additions & 5 deletions OpenUtau.Plugin.Builtin/ChineseCVVCPhonemizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public class ChineseCVVCPhonemizer : BaseChinesePhonemizer {
private Dictionary<string, string> vowels = new Dictionary<string, string>();
private Dictionary<string, string> consonants = new Dictionary<string, string>();
private USinger singer;

public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevNeighbour, Note? nextNeighbour, Note[] prevNeighbours) {
var lyric = notes[0].lyric;
string consonant = consonants.TryGetValue(lyric, out consonant) ? consonant : lyric;
Expand All @@ -27,13 +26,31 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
};
var attr0 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 0) ?? default;
var attr1 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 1) ?? default;
var attr2 = notes[0].phonemeAttributes?.FirstOrDefault(attr => attr.index == 2) ?? default;
if (lyric == "-" || lyric.ToLowerInvariant() == "r") {
if (singer.TryGetMappedOto($"{prevVowel} R", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto1)) {
return MakeSimpleResult(oto1.Alias);
}
return MakeSimpleResult($"{prevVowel} R");
}
string currVowel = vowels.TryGetValue(lyric, out currVowel) ? currVowel : lyric;
int totalDuration = notes.Sum(n => n.duration); // totalDuration of current note

if (singer.TryGetMappedOto($"{prevVowel} {lyric}", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto)) {
if (nextNeighbour == null && singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr1.toneShift, attr1.voiceColor, out var oto1)) {
// automatically add ending if present
return new Result {
phonemes = new Phoneme[] {
new Phoneme() {
phoneme = oto.Alias,
},
new Phoneme() {
phoneme = oto1.Alias,
position = totalDuration - (totalDuration / 6),
},
},
};
}
return MakeSimpleResult(oto.Alias);
}
int vcLen = 120;
Expand All @@ -46,15 +63,20 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
vcLen = MsToTick(cvOto.Preutter - cvOto.Overlap);
}
}

if (singer.TryGetMappedOto(lyric, notes[0].tone + attr0.toneShift, attr0.voiceColor, out var cvOtoSimple)) {
lyric = cvOtoSimple.Alias;
}

var vcPhoneme = $"{prevVowel} {consonant}";
if (prevNeighbour != null) {
if (singer.TryGetMappedOto(vcPhoneme, prevNeighbour.Value.tone + attr0.toneShift, attr0.voiceColor, out oto)) {
vcPhoneme = oto.Alias;
}
// totalDuration calculated on basis of previous note length
int totalDuration = prevNeighbour.Value.duration;
// prevDuration calculated on basis of previous note length
int prevDuration = prevNeighbour.Value.duration;
// vcLength depends on the Vel of the current base note
vcLen = Convert.ToInt32(Math.Min(totalDuration / 1.5, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? 1))));
vcLen = Convert.ToInt32(Math.Min(prevDuration / 1.5, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? 1))));
} else {
if (singer.TryGetMappedOto(vcPhoneme, notes[0].tone + attr0.toneShift, attr0.voiceColor, out oto)) {
vcPhoneme = oto.Alias;
Expand All @@ -63,6 +85,81 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
vcLen = Convert.ToInt32(Math.Min(vcLen * 2, Math.Max(30, vcLen * (attr1.consonantStretchRatio ?? 1))));
}

if (nextNeighbour == null) { // automatically add ending if present
if (singer.TryGetMappedOto($"{prevVowel} {lyric}", notes[0].tone + attr0.toneShift, attr0.voiceColor, out var oto0)) {
if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr1.toneShift, attr1.voiceColor, out var otoEnd)) {
// automatically add ending if present
return new Result {
phonemes = new Phoneme[] {
new Phoneme() {
phoneme = oto0.Alias,
},
new Phoneme() {
phoneme = otoEnd.Alias,
position = totalDuration - (totalDuration / 6),
},
},
};
}
} else {
// use vc if present
if (prevNeighbour == null && singer.TryGetMappedOto(vcPhoneme, notes[0].tone + attr0.toneShift, attr0.voiceColor, out var vcOto1)) {
vcPhoneme = vcOto1.Alias;
// automatically add ending if present
if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr2.toneShift, attr2.voiceColor, out var otoEnd)) {
return new Result {
phonemes = new Phoneme[] {
new Phoneme() {
phoneme = vcPhoneme,
position = -vcLen,
},
new Phoneme() {
phoneme = cvOto?.Alias ?? lyric,
},
new Phoneme() {
phoneme = otoEnd.Alias,
position = totalDuration - (totalDuration / 6),
},
},
};
}
} else if (prevNeighbour != null && singer.TryGetMappedOto(vcPhoneme, prevNeighbour.Value.tone + attr0.toneShift, attr0.voiceColor, out var vcOto2)) {
vcPhoneme = vcOto2.Alias;
// automatically add ending if present
if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr2.toneShift, attr2.voiceColor, out var otoEnd)) {
return new Result {
phonemes = new Phoneme[] {
new Phoneme() {
phoneme = vcPhoneme,
position = -vcLen,
},
new Phoneme() {
phoneme = cvOto?.Alias ?? lyric,
},
new Phoneme() {
phoneme = otoEnd.Alias,
position = totalDuration - (totalDuration / 6),
},
},
};
}
} // just base note and ending
if (singer.TryGetMappedOto($"{currVowel} R", notes[0].tone + attr1.toneShift, attr1.voiceColor, out var otoEnd1)) {
return new Result {
phonemes = new Phoneme[] {
new Phoneme() {
phoneme = cvOtoSimple?.Alias ?? lyric,
},
new Phoneme() {
phoneme = otoEnd1.Alias,
position = totalDuration - (totalDuration / 6),
},
},
};
}
}
}

if (singer.TryGetMappedOto(vcPhoneme, notes[0].tone + attr0.toneShift, attr0.voiceColor, out oto)) {
return new Result {
phonemes = new Phoneme[] {
Expand All @@ -76,7 +173,7 @@ public override Result Process(Note[] notes, Note? prev, Note? next, Note? prevN
},
};
}
return MakeSimpleResult(cvOto?.Alias ?? lyric);
return MakeSimpleResult(cvOtoSimple?.Alias ?? lyric);
}

public override void SetSinger(USinger singer) {
Expand Down

0 comments on commit 343d861

Please sign in to comment.