diff --git a/Mirivoice/Assets/Lang/en-US.axaml b/Mirivoice/Assets/Lang/en-US.axaml index 02c975c..0d09a80 100644 --- a/Mirivoice/Assets/Lang/en-US.axaml +++ b/Mirivoice/Assets/Lang/en-US.axaml @@ -27,10 +27,11 @@ (Line is empty) Phonemes - diff --git a/Mirivoice/Assets/Lang/ko-KR.axaml b/Mirivoice/Assets/Lang/ko-KR.axaml index ddf5810..0a10c45 100644 --- a/Mirivoice/Assets/Lang/ko-KR.axaml +++ b/Mirivoice/Assets/Lang/ko-KR.axaml @@ -32,10 +32,12 @@ (대사가 비어 있어요) 음소 - diff --git a/Mirivoice/Commands/DelLineBoxReceiver.cs b/Mirivoice/Commands/DelLineBoxReceiver.cs index bbe8b8d..de8a306 100644 --- a/Mirivoice/Commands/DelLineBoxReceiver.cs +++ b/Mirivoice/Commands/DelLineBoxReceiver.cs @@ -20,6 +20,7 @@ public class DelLineBoxReceiver : MReceiver private SingleLineEditorView lastEditor; + public DelLineBoxReceiver(MainViewModel mainViewModel, LineBoxView l) { this.l = l; @@ -45,6 +46,12 @@ public override void DoAction() v.CurrentSingleLineEditor = null; lastResults = new ObservableCollection(l.MResultsCollection); v.MResultsCollection.Clear(); + + if (v.CurrentEditIndex == 1) + { + v.CurrentEdit = null; + v.OnPropertyChanged(nameof(v.CurrentEdit)); + } } RefreshLineNos(control); @@ -64,6 +71,12 @@ public override void UndoAction() l.MResultsCollection = lastResults; v.MResultsCollection = lastResults; v.OnPropertyChanged(nameof(v.MResultsCollection)); + if (v.CurrentEditIndex == 1) + { + v.CurrentEdit = l.ExpressionEditor; + v.OnPropertyChanged(nameof(v.CurrentEdit)); + } + } } diff --git a/Mirivoice/Engines/TTS/BaseEngine.cs b/Mirivoice/Engines/TTS/BaseEngine.cs index d96a91b..f091274 100644 --- a/Mirivoice/Engines/TTS/BaseEngine.cs +++ b/Mirivoice/Engines/TTS/BaseEngine.cs @@ -30,7 +30,7 @@ protected string ReadTxtFile(string txtPath) } } - public virtual void Inference(string ipaText, string cacheFilePath, int spkid) + public virtual void Inference(string ipaText, string cacheFilePath, int spkid, MExpressionsWrapper expression) { } diff --git a/Mirivoice/Engines/TTS/EngineVITS2.cs b/Mirivoice/Engines/TTS/EngineVITS2.cs index ffc6a73..46c6f45 100644 --- a/Mirivoice/Engines/TTS/EngineVITS2.cs +++ b/Mirivoice/Engines/TTS/EngineVITS2.cs @@ -126,7 +126,7 @@ private Tensor Intersperse(Tensor sequence, long interspersedValue) return interspersed; } - public override void Inference(string ipaText, string cacheFilePath, int spkid) + public override void Inference(string ipaText, string cacheFilePath, int spkid, MExpressionsWrapper expression) { if (!init) { @@ -160,9 +160,9 @@ public override void Inference(string ipaText, string cacheFilePath, int spkid) // scales array Tensor scalesTensor = new DenseTensor(3); - scalesTensor[0] = 0.667f; // noise_scale - scalesTensor[1] = 1.0f; // length_scale. If increased, the speed of the speech will be faster - scalesTensor[2] = 0.8f; // noise_scale_w + scalesTensor[0] = expression.VITS2Noise1; // Noise1 / noise_scale + scalesTensor[1] = expression.VITS2Speed; // Speed / length_scale. If increased, the speed of the speech will be faster + scalesTensor[2] = expression.VITS2Noise2; // Noise2 / noise_scale_w var inputs = new List diff --git a/Mirivoice/Mirivoice.Core/Format/MExpressionsWrapper.cs b/Mirivoice/Mirivoice.Core/Format/MExpressionsWrapper.cs new file mode 100644 index 0000000..9fea6ef --- /dev/null +++ b/Mirivoice/Mirivoice.Core/Format/MExpressionsWrapper.cs @@ -0,0 +1,32 @@ +using Avalonia.Threading; +using Mirivoice.Engines; +using Mirivoice.ViewModels; +using Mirivoice.Views; +using R3; +using Serilog; +using System; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using VYaml.Annotations; +using VYaml.Serialization; +using Mirivoice.Mirivoice.Core.Format; +using Mirivoice.Mirivoice.Plugins.Builtin.Phonemizers; + +namespace Mirivoice.Mirivoice.Core.Format +{ + [YamlObject] + public partial class MExpressionsWrapper + { + // For VITS2 + public float VITS2Speed { get; set; } = 1.0f; + public float VITS2Noise1 { get; set; } = 0.667f; + public float VITS2Noise2 { get; set; } = 0.8f; + + public MExpressionsWrapper() + { + + } + } +} diff --git a/Mirivoice/Mirivoice.Core/Format/Mrp.cs b/Mirivoice/Mirivoice.Core/Format/Mrp.cs index 3d793ee..2fdb8d4 100644 --- a/Mirivoice/Mirivoice.Core/Format/Mrp.cs +++ b/Mirivoice/Mirivoice.Core/Format/Mrp.cs @@ -56,6 +56,7 @@ public partial class MLinePrototype public int voicerStyleId { get; set; } public string IPAText { get; set; } public string cacheName { get; set; } + public MExpressionsWrapper Exp { get; set; } = new MExpressionsWrapper(); [YamlConstructor] public MLinePrototype() @@ -75,7 +76,7 @@ public MLinePrototype(LineBoxView l) { cacheName = l.CurrentCacheName; } - + this.Exp = l.Exp; } } @@ -127,6 +128,7 @@ public async Task Load(MainViewModel v) foreach (var m in mLines) { m.PhonemeEdit = BasePhonemizer.SetUpProsody(null, m.PhonemeEdit.ToList(), false); + m.Exp = new MExpressionsWrapper(); } } diff --git a/Mirivoice/Mirivoice.Core/Format/Voicer.cs b/Mirivoice/Mirivoice.Core/Format/Voicer.cs index 5b088d8..e6c2417 100644 --- a/Mirivoice/Mirivoice.Core/Format/Voicer.cs +++ b/Mirivoice/Mirivoice.Core/Format/Voicer.cs @@ -82,7 +82,8 @@ public void Inference(string ipaText, string cacheFilePath, LineBoxView l, int s Log.Error("Engine is not initialized."); return; } - Engine.Inference(ipaText, cacheFilePath, sid); + Log.Debug($"speed: {l.Exp.VITS2Speed}, noise1: {l.Exp.VITS2Noise1}, noise2: {l.Exp.VITS2Noise2}"); + Engine.Inference(ipaText, cacheFilePath, sid, l.Exp); if (l != null) { l.IsCacheIsVaild = true; diff --git a/Mirivoice/Mirivoice.csproj b/Mirivoice/Mirivoice.csproj index 3cfd7e4..c824569 100644 --- a/Mirivoice/Mirivoice.csproj +++ b/Mirivoice/Mirivoice.csproj @@ -82,6 +82,9 @@ LineBoxView.axaml + + ExpressionEditViewVITS2.axaml + Code PhonemeEditView.axaml diff --git a/Mirivoice/ViewModels/ExpressionEditViewModelVITS2.cs b/Mirivoice/ViewModels/ExpressionEditViewModelVITS2.cs new file mode 100644 index 0000000..296c464 --- /dev/null +++ b/Mirivoice/ViewModels/ExpressionEditViewModelVITS2.cs @@ -0,0 +1,105 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Layout; +using Mirivoice.Engines; +using Mirivoice.Mirivoice.Core.Format; +using Mirivoice.Views; +using ReactiveUI; +using System; + +namespace Mirivoice.ViewModels +{ + public class ExpressionEditViewModelVITS2: ViewModelBase + { + public StackPanel CurrentExpression { get; set; } + private readonly LineBoxView l; + public int MaxSpeed { get; set; } = 100; + public int MinSpeed { get; set; } = 0; + + public int MaxNoise1 { get; set; } = 100; + public int MinNoise1 { get; set; } = 0; + + public int MaxNoise2 { get; set; } = 100; + public int MinNoise2 { get; set; } = 0; + + private int _vits2Speed; + public int VITS2Speed + { + get => _vits2Speed; + set + { + this.RaiseAndSetIfChanged(ref _vits2Speed, value); + l.Exp.VITS2Speed = ScaleValue(100 - value, 0.5f, 1.5f); + l.IsCacheIsVaild = false; + OnPropertyChanged(nameof(VITS2Speed)); + OnPropertyChanged(nameof(l.Exp.VITS2Speed)); + } + } + + private int _vits2Noise1; + public int VITS2Noise1 + { + get => _vits2Noise1; + set + { + this.RaiseAndSetIfChanged(ref _vits2Noise1, value); + l.Exp.VITS2Noise1 = ScaleValue(value, -0.3335f, 1.6675f); + l.IsCacheIsVaild = false; + OnPropertyChanged(nameof(VITS2Noise1)); + OnPropertyChanged(nameof(l.Exp.VITS2Noise1)); + } + } + + private int _vits2Noise2; + public int VITS2Noise2 + { + get => _vits2Noise2; + set + { + this.RaiseAndSetIfChanged(ref _vits2Noise2, value); + + l.Exp.VITS2Noise2 = ScaleValue(value, -0.4f, 2f); + l.IsCacheIsVaild = false; + OnPropertyChanged(nameof(VITS2Noise2)); + OnPropertyChanged(nameof(l.Exp.VITS2Noise2)); + } + } + public ExpressionEditViewModelVITS2(LineBoxView l) + { + this.l = l; + + VITS2Speed = 100 - GetSliderValue(l.Exp.VITS2Speed, 0.5f, 1.5f); + VITS2Noise1 = GetSliderValue(l.Exp.VITS2Noise1, -0.3335f, 1.6675f); + VITS2Noise2 = GetSliderValue(l.Exp.VITS2Noise2, -0.4f, 2f); + + } + + + + public static float ScaleValue(int input, float minValue, float maxValue) + { + + return minValue + input / 100f * (maxValue - minValue); + + } + + public static int GetSliderValue(float value, float minValue, float maxValue) + { + return (int)((value - minValue) / (maxValue - minValue) * 100f); + } + public void ClrVITS2Speed() + { + VITS2Speed = 50; + } + + public void ClrVITS2Noise1() + { + VITS2Noise1 = 50; + } + + public void ClrVITS2Noise2() + { + VITS2Noise2 = 50; + } + } +} diff --git a/Mirivoice/ViewModels/LineBoxViewModel.cs b/Mirivoice/ViewModels/LineBoxViewModel.cs index 5f51148..07ab013 100644 --- a/Mirivoice/ViewModels/LineBoxViewModel.cs +++ b/Mirivoice/ViewModels/LineBoxViewModel.cs @@ -2,6 +2,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Mirivoice.Engines; using Mirivoice.Mirivoice.Core; using Mirivoice.Mirivoice.Core.Editor; using Mirivoice.Mirivoice.Core.Format; @@ -141,7 +142,7 @@ public ImageBrush Icon } public BasePhonemizer phonemizer; - + string lastType; public override void OnVoicerChanged(Voicer voicer) { //Log.Debug($"OnVoicerChanged: {voicer.NickAndStyle}"); @@ -151,7 +152,12 @@ public override void OnVoicerChanged(Voicer voicer) { phonemizer = GetPhonemizer(voicerSelector.CurrentVoicer.Info.LangCode); } - + if (lastType is not null && lastType != voicer.Info.Type) + { + Log.Debug("Type Changed: {0}", voicer.Info.Type); + l.ResetExpEditor(voicer.Info.Type); + } + l.IsCacheIsVaild = false; LangCode = voicer.Info.LangCode.ToUpper().Substring(0, 2); diff --git a/Mirivoice/ViewModels/MainViewModel.cs b/Mirivoice/ViewModels/MainViewModel.cs index 1ac8ecf..50a82c4 100644 --- a/Mirivoice/ViewModels/MainViewModel.cs +++ b/Mirivoice/ViewModels/MainViewModel.cs @@ -256,6 +256,8 @@ public bool StopButtonEnabled private int _valueProgressbar; private int _currentEditIndex; + + public int CurrentEditIndex { get => _currentEditIndex; @@ -272,7 +274,28 @@ public int CurrentEditIndex switch (_currentEditIndex) { case 0: - CurrentEdit = new PhonemeEditView(); + if (CurrentLineBox is not null) + { + CurrentEdit = new PhonemeEditView(); + + } + else + { + CurrentEdit = null; + } + + this.OnPropertyChanged(nameof(CurrentEdit)); + break; + case 1: + if (CurrentLineBox is not null) + { + CurrentEdit = CurrentLineBox.ExpressionEditor; + + } + else + { + CurrentEdit = null; + } this.OnPropertyChanged(nameof(CurrentEdit)); break; default: diff --git a/Mirivoice/Views/ExpressionEditViewVITS2.axaml b/Mirivoice/Views/ExpressionEditViewVITS2.axaml new file mode 100644 index 0000000..90c0704 --- /dev/null +++ b/Mirivoice/Views/ExpressionEditViewVITS2.axaml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mirivoice/Views/ExpressionEditViewVITS2.axaml.cs b/Mirivoice/Views/ExpressionEditViewVITS2.axaml.cs new file mode 100644 index 0000000..9f495ef --- /dev/null +++ b/Mirivoice/Views/ExpressionEditViewVITS2.axaml.cs @@ -0,0 +1,56 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Markup.Xaml; +using Mirivoice.Engines; +using Mirivoice.Mirivoice.Core.Format; +using Mirivoice.ViewModels; +using Mirivoice.Views; +using Org.BouncyCastle.Crmf; + +namespace Mirivoice; + +public partial class ExpressionEditViewVITS2 : UserControl +{ + public ExpressionEditViewModelVITS2 viewModel; + VoicerMetaType vMeta; + + public ExpressionEditViewVITS2(LineBoxView l) + { + this.vMeta = vMeta; + InitializeComponent(l); + + + } + + + private void ClearVITS2Speed(object sender, PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(this).Properties.IsRightButtonPressed) + { + viewModel.ClrVITS2Speed(); + } + + } + + private void ClearVITS2Noise1(object sender, PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(this).Properties.IsRightButtonPressed) + { + viewModel.ClrVITS2Noise1(); + } + } + + private void ClearVITS2Noise2(object sender, PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(this).Properties.IsRightButtonPressed) + { + viewModel.ClrVITS2Noise2(); + } + } + private void InitializeComponent(LineBoxView l) + { + AvaloniaXamlLoader.Load(this); + DataContext = viewModel = new ExpressionEditViewModelVITS2(l); + } + +} \ No newline at end of file diff --git a/Mirivoice/Views/LineBoxView.axaml.cs b/Mirivoice/Views/LineBoxView.axaml.cs index bceda5f..8562e6d 100644 --- a/Mirivoice/Views/LineBoxView.axaml.cs +++ b/Mirivoice/Views/LineBoxView.axaml.cs @@ -26,6 +26,8 @@ public partial class LineBoxView: UserControl private bool mouseEntered; private bool isDragging; + public MExpressionsWrapper Exp = new MExpressionsWrapper(); + public UserControl ExpressionEditor { get; set; } public readonly MainViewModel v; private bool dragInit; @@ -208,7 +210,7 @@ public LineBoxView(MainViewModel v, string line="") singleLineEditorView = new SingleLineEditorView(this); singleLineEditorView.SetLine(line); - + ResetExpEditor(v.voicerSelector.CurrentVoicer.Info.Type); } @@ -220,15 +222,14 @@ public LineBoxView(MainViewModel v, string line="") public LineBoxView(MLinePrototype mLinePrototype, MainViewModel v, int index, int voicerIndex, int metaIndex, bool isDuplicating) { this.v = v; - InitializeComponent(voicerIndex, metaIndex); viewModel.LineText = mLinePrototype.LineText; IPAText = mLinePrototype.IPAText; viewModel.SetLineNo(index + 1); _currentCacheName = AudioManager.GetUniqueCachePath(); this.CurrentCacheName = mLinePrototype.cacheName; - - + Exp = mLinePrototype.Exp; + //lockButton = this.FindControl("lockButton"); SetCommands(v); @@ -281,7 +282,7 @@ public LineBoxView(MLinePrototype mLinePrototype, MainViewModel v, int index, in // if phonemeEdit is empty, use newly phonemized one singleLineEditorView = new SingleLineEditorView(this); } - + ResetExpEditor(v.voicerSelector.CurrentVoicer.Info.Type); } // Commands public MCommand DelLineBoxCommand { get; set; } @@ -342,6 +343,20 @@ public void AutoScroll() } } + MExpressionsWrapper lastExp = new MExpressionsWrapper(); + + public void ResetExpEditor(string voicerMetaType ) + { + switch (voicerMetaType) + { + case "VITS2": //TODO resolve hardcoding + ExpressionEditor = new ExpressionEditViewVITS2(this); + break; + default: + ExpressionEditor = null; + break; + } + } public async Task StartInference() { if (viewModel.voicerSelector.CurrentVoicer is null) @@ -379,6 +394,11 @@ await Dispatcher.UIThread.InvokeAsync(async () => Log.Debug("meta changed"); IsCacheIsVaild = false; } + if (lastExp != Exp) + { + Log.Debug("exp changed"); + IsCacheIsVaild = false; + } if (!System.IO.Path.Exists(CurrentCacheName)) { IsCacheIsVaild = false; @@ -392,6 +412,7 @@ await Dispatcher.UIThread.InvokeAsync(async () => } lastInferencedVoicerMeta = viewModel.voicerSelector.CurrentVoicer.CurrentVoicerMeta; + lastExp = Exp; } else { @@ -461,6 +482,11 @@ private void OnEntered(object sender, PointerEventArgs e) private void OnDragStart(object sender, RoutedEventArgs e) { viewModel.IsSelected = true; + if (v.CurrentEdit is null) + { + v.CurrentEdit = new PhonemeEditView(); + v.OnPropertyChanged(nameof(v.CurrentEdit)); + } if (!mouseEntered) { diff --git a/Mirivoice/Views/MainView.axaml b/Mirivoice/Views/MainView.axaml index 88c35df..5b4361c 100644 --- a/Mirivoice/Views/MainView.axaml +++ b/Mirivoice/Views/MainView.axaml @@ -180,7 +180,7 @@ - +