forked from LiuYunPlayer/DiffSingerForTuneLab
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVoicebankScanner.cs
More file actions
105 lines (86 loc) · 3.41 KB
/
Copy pathVoicebankScanner.cs
File metadata and controls
105 lines (86 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
using System;
using System.Collections.Generic;
using System.IO;
using TuneLab.Foundation;
using TuneLab.SDK;
namespace DiffSingerForTuneLab;
// 在给定的一组根目录下发现 DiffSinger 声库。
// 声库根判别:含声学主配置 dsconfig.yaml,且含 character 元数据文件。
// 预测器子目录(dsdur / dspitch / dsvariance)也各自带 dsconfig.yaml,但无 character.*——据此排除;
// 探到声库后即不再下钻其子目录。按解析后的全路径去重(重叠根重复命中只取一次),
// voiceId 取声库文件夹名、冲突时追加序号保唯一。
internal static class VoicebankScanner
{
const int MaxDepth = 6;
public static List<DiscoveredVoicebank> Scan(IEnumerable<string> roots, ILogger logger)
{
var result = new List<DiscoveredVoicebank>();
var seenPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var usedIds = new HashSet<string>(StringComparer.Ordinal);
foreach (var root in roots)
{
if (string.IsNullOrWhiteSpace(root))
continue;
string full;
try { full = Path.GetFullPath(root); }
catch { continue; }
if (!Directory.Exists(full))
continue;
try { Walk(full, 0, result, seenPaths, usedIds); }
catch (Exception ex) { logger.Warning($"扫描声库根目录失败 {full}: {ex.Message}"); }
}
return result;
}
static void Walk(string dir, int depth, List<DiscoveredVoicebank> result,
HashSet<string> seenPaths, HashSet<string> usedIds)
{
if (IsVoicebank(dir))
{
if (seenPaths.Add(Path.GetFullPath(dir)))
result.Add(Build(dir, usedIds));
return; // 不下钻:子目录是 dsdur / dspitch / dsvariance 等预测器
}
if (depth >= MaxDepth)
return;
string[] subDirs;
try { subDirs = Directory.GetDirectories(dir); }
catch { return; }
foreach (var sub in subDirs)
Walk(sub, depth + 1, result, seenPaths, usedIds);
}
static bool IsVoicebank(string dir)
{
if (!File.Exists(Path.Combine(dir, "dsconfig.yaml")))
return false;
return File.Exists(Path.Combine(dir, "character.yaml"))
|| File.Exists(Path.Combine(dir, "character.txt"));
}
static DiscoveredVoicebank Build(string bankDir, HashSet<string> usedIds)
{
var folderName = new DirectoryInfo(bankDir).Name;
var meta = CharacterMetadata.Read(bankDir);
var voiceId = UniqueId(folderName, usedIds);
ImageResource? portrait = null;
if (!string.IsNullOrWhiteSpace(meta.ImageFile))
{
var imagePath = Path.Combine(bankDir, meta.ImageFile);
if (File.Exists(imagePath))
portrait = new FileImageResource(imagePath);
}
var info = new VoiceSourceInfo
{
Name = string.IsNullOrWhiteSpace(meta.Name) ? folderName : meta.Name!,
Description = meta.Author ?? string.Empty,
Portrait = portrait,
};
return new DiscoveredVoicebank(voiceId, Path.GetFullPath(bankDir), info);
}
static string UniqueId(string baseName, HashSet<string> usedIds)
{
var id = baseName;
int n = 2;
while (!usedIds.Add(id))
id = $"{baseName} ({n++})";
return id;
}
}