Skip to content

Commit 201f874

Browse files
maiko3tattunMaiko
andauthored
(Re) MOD+ related bug fixes (#1610)
Co-authored-by: Maiko <[email protected]>
1 parent 2792646 commit 201f874

File tree

4 files changed

+74
-47
lines changed

4 files changed

+74
-47
lines changed

OpenUtau.Core/Classic/ClassicSinger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class ClassicSinger : USinger {
4444
OtoWatcher otoWatcher;
4545

4646
public bool? UseFilenameAsAlias { get => voicebank.UseFilenameAsAlias; set => voicebank.UseFilenameAsAlias = value; }
47-
public Dictionary<string, Frq> Frqs { get; set; } = new Dictionary<string, Frq>();
47+
public Dictionary<string, IFrqFiles> Frqs { get; set; } = new Dictionary<string, IFrqFiles>();
4848

4949
public ClassicSinger(Voicebank voicebank) {
5050
this.voicebank = voicebank;

OpenUtau.Core/Classic/Frq.cs

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,48 @@ public class OtoFrq {
1414
public int hopSize;
1515
public bool loaded = false;
1616

17-
public OtoFrq(UOto oto, Dictionary<string, Frq> dict) {
18-
if (!dict.TryGetValue(oto.File, out var frq)) {
19-
frq = new Frq();
20-
if (frq.Load(oto.File)){
17+
public OtoFrq(UOto oto, Dictionary<string, IFrqFiles> dict) {
18+
if (!dict.TryGetValue(oto.File, out IFrqFiles? frq)) {
19+
Load(oto.File, out frq);
20+
if (frq != null) {
2121
dict.Add(oto.File, frq);
22-
} else {
23-
frq = null;
2422
}
2523
}
26-
if(frq != null && frq.wavSampleLength != - 1) {
27-
this.hopSize = frq.hopSize;
28-
29-
if (frq.wavSampleLength == 0) {
30-
try {
31-
using (var waveStream = Core.Format.Wave.OpenFile(oto.File)) {
32-
var sampleProvider = waveStream.ToSampleProvider();
33-
if (sampleProvider.WaveFormat.SampleRate == 44100) {
34-
frq.wavSampleLength = Core.Format.Wave.GetSamples(sampleProvider).Length;
35-
} else {
36-
frq.wavSampleLength = -1;
37-
}
38-
}
39-
} catch {
40-
frq.wavSampleLength = - 1;
41-
}
42-
}
4324

44-
if (frq.wavSampleLength > 0) {
45-
int offset = (int)Math.Floor(oto.Offset * 44100 / 1000 / frq.hopSize); // frq samples
46-
int consonant = (int)Math.Floor((oto.Offset + oto.Consonant) * 44100 / 1000 / frq.hopSize);
47-
int cutoff = oto.Cutoff < 0 ?
48-
(int)Math.Floor((oto.Offset - oto.Cutoff) * 44100 / 1000 / frq.hopSize)
49-
: frq.wavSampleLength - (int)Math.Floor(oto.Cutoff * 44100 / 1000 / frq.hopSize);
50-
var completionF0 = Completion(frq.f0);
51-
var averageTone = MusicMath.FreqToTone(frq.averageF0);
52-
toneDiffFix = completionF0.Skip(offset).Take(consonant - offset).Select(f => MusicMath.FreqToTone(f) - averageTone).ToArray();
53-
toneDiffStretch = completionF0.Skip(consonant).Take(cutoff - consonant).Select(f => MusicMath.FreqToTone(f) - averageTone).ToArray();
54-
55-
loaded = true;
56-
}
25+
if(frq != null) {
26+
hopSize = frq.hopSize;
27+
int offset = ConvertMsToFrqLength(frq, oto.Offset);
28+
int consonant = ConvertMsToFrqLength(frq, oto.Offset + oto.Consonant);
29+
int cutoff = oto.Cutoff < 0 ?
30+
ConvertMsToFrqLength(frq, oto.Offset - oto.Cutoff)
31+
: frq.f0.Length - ConvertMsToFrqLength(frq, oto.Cutoff);
32+
var completionF0 = Completion(frq.f0);
33+
var averageTone = MusicMath.FreqToTone(frq.averageF0);
34+
toneDiffFix = completionF0.Skip(offset).Take(consonant - offset).Select(f => MusicMath.FreqToTone(f) - averageTone).ToArray();
35+
toneDiffStretch = completionF0.Skip(consonant).Take(cutoff - consonant).Select(f => MusicMath.FreqToTone(f) - averageTone).ToArray();
36+
37+
loaded = true;
38+
}
39+
}
40+
41+
private void Load(string otoPath, out IFrqFiles? frqFile) {
42+
var frq = new Frq();
43+
if (frq.Load(otoPath)) {
44+
frqFile = frq;
45+
return;
5746
}
47+
// Please write a code to read other frequency files!
48+
49+
frqFile = null;
5850
}
5951

52+
private int ConvertMsToFrqLength(IFrqFiles frq, double lengthMs) {
53+
return (int)Math.Floor(lengthMs * frq.wavSampleRate / 1000 / frq.hopSize);
54+
}
55+
56+
/// <summary>
57+
/// When a pitch is out of tune, it is complemented by the preceding and following pitches.
58+
/// </summary>
6059
private double[] Completion(double[] frqs) {
6160
var list = new List<double>();
6261
for (int i = 0; i < frqs.Length; i++) {
@@ -94,18 +93,39 @@ private double[] Completion(double[] frqs) {
9493
}
9594
}
9695

97-
public class Frq {
98-
public const int kHopSize = 256;
99-
100-
public int hopSize;
101-
public double averageF0;
102-
public double[] f0 = new double[0];
103-
public double[] amp = new double[0];
104-
public int wavSampleLength = 0;
96+
public interface IFrqFiles {
97+
public int hopSize { get; }
98+
public double averageF0 { get; }
99+
public double[] f0 { get; }
100+
public int wavSampleRate { get; set; }
105101

106102
/// <summary>
107103
/// If the wav path is null (machine learning voicebank), return false.
108-
/// <summary>
104+
/// </summary>
105+
public bool Load(string wavPath);
106+
107+
/* Might be needed in the future if the frequency files of engines that can handle wav's other than 44100Hz are supported.
108+
if (frq.wavSampleRate == 0) {
109+
try {
110+
using (var waveStream = Core.Format.Wave.OpenFile(oto.File)) {
111+
var sampleProvider = waveStream.ToSampleProvider();
112+
frq.wavSampleRate = sampleProvider.WaveFormat.SampleRate;
113+
}
114+
} catch {
115+
frq.wavSampleRate = 44100;
116+
}
117+
}*/
118+
}
119+
120+
public class Frq : IFrqFiles {
121+
public const int kHopSize = 256;
122+
123+
public int hopSize { get; private set; }
124+
public double averageF0 { get; private set; }
125+
public double[] f0 { get; private set; } = new double[0];
126+
public double[] amp { get; private set; } = new double[0];
127+
public int wavSampleRate { get; set; } = 44100; // Sample rate for .frq files is fixed
128+
109129
public bool Load(string wavPath) {
110130
if (string.IsNullOrEmpty(wavPath)) {
111131
return false;

OpenUtau.Core/Render/RenderPhrase.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,13 @@ public void DeleteCacheFiles() {
531531
}
532532
}
533533
cacheFiles.Clear();
534+
535+
if (singer is ClassicSinger cSinger && cSinger.Frqs != null) {
536+
foreach (var oto in phones.Select(p => p.oto).Distinct()) {
537+
oto.Frq = null;
538+
cSinger.Frqs.Remove(oto.File);
539+
}
540+
}
534541
}
535542
}
536543
}

OpenUtau.Core/Ustx/USinger.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public double Overlap {
5252
NotifyPropertyChanged(nameof(Overlap));
5353
}
5454
}
55-
public OtoFrq Frq { get;set; }
55+
public OtoFrq? Frq { get; set; }
5656
public List<string> SearchTerms { get; private set; }
5757

5858
public event PropertyChangedEventHandler PropertyChanged;

0 commit comments

Comments
 (0)