diff --git a/OpenUtau.Core/Classic/ClassicSingerLoader.cs b/OpenUtau.Core/Classic/ClassicSingerLoader.cs index fd79a64cd..13848b5da 100644 --- a/OpenUtau.Core/Classic/ClassicSingerLoader.cs +++ b/OpenUtau.Core/Classic/ClassicSingerLoader.cs @@ -17,11 +17,7 @@ static USinger AdjustSingerType(Voicebank v) { } public static IEnumerable FindAllSingers() { List singers = new List(); - foreach (var path in new string[] { - PathManager.Inst.SingersPathOld, - PathManager.Inst.SingersPath, - PathManager.Inst.AdditionalSingersPath, - }) { + foreach (var path in PathManager.Inst.SingersPaths) { var loader = new VoicebankLoader(path); singers.AddRange(loader.SearchAll() .Select(AdjustSingerType)); diff --git a/OpenUtau.Core/Classic/VoicebankLoader.cs b/OpenUtau.Core/Classic/VoicebankLoader.cs index 20eaa7c04..92df3097d 100644 --- a/OpenUtau.Core/Classic/VoicebankLoader.cs +++ b/OpenUtau.Core/Classic/VoicebankLoader.cs @@ -6,6 +6,7 @@ using System.Text; using OpenUtau.Core; using OpenUtau.Core.Ustx; +using OpenUtau.Core.Util; using Serilog; namespace OpenUtau.Classic { @@ -45,7 +46,15 @@ public IEnumerable SearchAll() { if (!Directory.Exists(basePath)) { return result; } - result.AddRange(Directory.EnumerateFiles(basePath, kCharTxt, SearchOption.AllDirectories) + IEnumerable files; + if (Preferences.Default.LoadDeepFolderSinger) { + files = Directory.EnumerateFiles(basePath, kCharTxt, SearchOption.AllDirectories); + } else { + // TopDirectoryOnly + files = Directory.GetDirectories(basePath) + .SelectMany(path => Directory.EnumerateFiles(path, kCharTxt)); + } + result.AddRange(files .Select(filePath => { try { var voicebank = new Voicebank(); diff --git a/OpenUtau.Core/SingerManager.cs b/OpenUtau.Core/SingerManager.cs index 250088514..52cb18347 100644 --- a/OpenUtau.Core/SingerManager.cs +++ b/OpenUtau.Core/SingerManager.cs @@ -32,7 +32,8 @@ public void SearchAllSingers() { Directory.CreateDirectory(PathManager.Inst.SingersPath); var stopWatch = Stopwatch.StartNew(); var singers = ClassicSingerLoader.FindAllSingers() - .Concat(Vogen.VogenSingerLoader.FindAllSingers()); + .Concat(Vogen.VogenSingerLoader.FindAllSingers()) + .Distinct(); Singers = singers .ToLookup(s => s.Id) .ToDictionary(g => g.Key, g => g.First()); diff --git a/OpenUtau.Core/Ustx/USinger.cs b/OpenUtau.Core/Ustx/USinger.cs index 736875662..b82ee1fd3 100644 --- a/OpenUtau.Core/Ustx/USinger.cs +++ b/OpenUtau.Core/Ustx/USinger.cs @@ -187,7 +187,7 @@ private static void AddToneRange(string range, SortedSet set) { [Flags] public enum USingerType { Classic = 0x1, Enunu = 0x2, Vogen = 0x4, DiffSinger=0x5 } - public class USinger : INotifyPropertyChanged { + public class USinger : INotifyPropertyChanged, IEquatable { protected static readonly List emptyOtos = new List(); public virtual string Id { get; } @@ -268,6 +268,16 @@ public virtual bool TryGetMappedOto(string phoneme, int tone, string color, out public virtual byte[] LoadPortrait() => null; public virtual byte[] LoadSample() => null; public override string ToString() => Name; + public bool Equals(USinger other) { + // Tentative: Since only the singer's Id is recorded in ustx and preferences, singers with the same Id are considered identical. + // Singer with the same directory name in different locations may be identical. + if (other != null && other.Id == this.Id) { + return true; + } else { + return false; + } + } + public override int GetHashCode() => Id.GetHashCode(); public static USinger CreateMissing(string name) { return new USinger() { diff --git a/OpenUtau.Core/Util/PathManager.cs b/OpenUtau.Core/Util/PathManager.cs index fcba680f7..fac5d9cae 100644 --- a/OpenUtau.Core/Util/PathManager.cs +++ b/OpenUtau.Core/Util/PathManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; @@ -85,6 +86,19 @@ public PathManager() { public string NotePresetsFilePath => Path.Combine(DataPath, "notepresets.json"); public string BackupsPath => Path.Combine(DataPath, "Backups"); + public List SingersPaths { + get { + var list = new List { SingersPath }; + if (Directory.Exists(SingersPathOld)) { + list.Add(SingersPathOld); + } + if (Directory.Exists(AdditionalSingersPath)) { + list.Add(AdditionalSingersPath); + } + return list.Distinct().ToList(); + } + } + Regex invalid = new Regex("[\\x00-\\x1f<>:\"/\\\\|?*]|^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9]|CLOCK\\$)(\\.|$)|[\\.]$", RegexOptions.IgnoreCase); public string GetPartSavePath(string exportPath, string partName, int partNo) { diff --git a/OpenUtau.Core/Util/Preferences.cs b/OpenUtau.Core/Util/Preferences.cs index c5b5fc648..1a4e0da44 100644 --- a/OpenUtau.Core/Util/Preferences.cs +++ b/OpenUtau.Core/Util/Preferences.cs @@ -149,6 +149,7 @@ public class SerializablePreferences { public string SkipUpdate = string.Empty; public string AdditionalSingerPath = string.Empty; public bool InstallToAdditionalSingersPath = true; + public bool LoadDeepFolderSinger = true; public bool PreferCommaSeparator = false; public bool ResamplerLogging = false; public List RecentSingers = new List(); diff --git a/OpenUtau.Core/Vogen/VogenSingerLoader.cs b/OpenUtau.Core/Vogen/VogenSingerLoader.cs index 8361c09bd..583ce8281 100644 --- a/OpenUtau.Core/Vogen/VogenSingerLoader.cs +++ b/OpenUtau.Core/Vogen/VogenSingerLoader.cs @@ -30,11 +30,7 @@ class VogenSingerLoader { public static IEnumerable FindAllSingers() { List singers = new List(); - foreach (var path in new string[] { - PathManager.Inst.SingersPathOld, - PathManager.Inst.SingersPath, - PathManager.Inst.AdditionalSingersPath, - }) { + foreach (var path in PathManager.Inst.SingersPaths) { var loader = new VogenSingerLoader(path); singers.AddRange(loader.SearchAll()); } @@ -50,7 +46,15 @@ public IEnumerable SearchAll() { if (!Directory.Exists(basePath)) { return result; } - result.AddRange(Directory.EnumerateFiles(basePath, "*.vogeon", SearchOption.AllDirectories) + IEnumerable files; + if (Preferences.Default.LoadDeepFolderSinger) { + files = Directory.EnumerateFiles(basePath, "*.vogeon", SearchOption.AllDirectories); + } else { + // TopDirectoryOnly + files = Directory.GetDirectories(basePath) + .SelectMany(path => Directory.EnumerateFiles(path, "*.vogeon")); + } + result.AddRange(files .Select(filePath => { try { return LoadSinger(filePath); diff --git a/OpenUtau/Strings/Strings.axaml b/OpenUtau/Strings/Strings.axaml index 855a46717..548cbfe5b 100644 --- a/OpenUtau/Strings/Strings.axaml +++ b/OpenUtau/Strings/Strings.axaml @@ -317,6 +317,7 @@ Warning: this option removes custom presets. Paths Additional Singer Path Install to Additional Singer Path + Load all depth folders Reset Select Playback diff --git a/OpenUtau/Strings/Strings.ja-JP.axaml b/OpenUtau/Strings/Strings.ja-JP.axaml index ea446ebd4..582d50a20 100644 --- a/OpenUtau/Strings/Strings.ja-JP.axaml +++ b/OpenUtau/Strings/Strings.ja-JP.axaml @@ -313,6 +313,7 @@ ファイルの場所 シンガーの場所(追加) シンガーの場所(追加)にインストール + 深い階層のフォルダも読み込む リセット 選択 再生 diff --git a/OpenUtau/ViewModels/PreferencesViewModel.cs b/OpenUtau/ViewModels/PreferencesViewModel.cs index d4ed0f449..7c0b658f5 100644 --- a/OpenUtau/ViewModels/PreferencesViewModel.cs +++ b/OpenUtau/ViewModels/PreferencesViewModel.cs @@ -29,6 +29,7 @@ public AudioOutputDevice? AudioOutputDevice { [Reactive] public int LockStartTime { get; set; } public string AdditionalSingersPath => !string.IsNullOrWhiteSpace(PathManager.Inst.AdditionalSingersPath)? PathManager.Inst.AdditionalSingersPath : "(None)"; [Reactive] public bool InstallToAdditionalSingersPath { get; set; } + [Reactive] public bool LoadDeepFolders { get; set; } [Reactive] public bool PreRender { get; set; } public List DefaultRendererOptions { get; set; } [Reactive] public string DefaultRenderer { get; set; } @@ -111,6 +112,7 @@ public PreferencesViewModel() { PlayPosMarkerMargin = Preferences.Default.PlayPosMarkerMargin; LockStartTime = Preferences.Default.LockStartTime; InstallToAdditionalSingersPath = Preferences.Default.InstallToAdditionalSingersPath; + LoadDeepFolders = Preferences.Default.LoadDeepFolderSinger; ToolsManager.Inst.Initialize(); var pattern = new Regex(@"Strings\.([\w-]+)\.axaml"); Languages = App.GetLanguages().Keys @@ -189,6 +191,11 @@ public PreferencesViewModel() { Preferences.Default.InstallToAdditionalSingersPath = additionalSingersPath; Preferences.Save(); }); + this.WhenAnyValue(vm => vm.LoadDeepFolders) + .Subscribe(loadDeepFolders => { + Preferences.Default.LoadDeepFolderSinger = loadDeepFolders; + Preferences.Save(); + }); this.WhenAnyValue(vm => vm.PreRender) .Subscribe(preRender => { Preferences.Default.PreRender = preRender; diff --git a/OpenUtau/Views/PreferencesDialog.axaml b/OpenUtau/Views/PreferencesDialog.axaml index 0423cacda..55165059a 100644 --- a/OpenUtau/Views/PreferencesDialog.axaml +++ b/OpenUtau/Views/PreferencesDialog.axaml @@ -88,6 +88,10 @@ + + + +