diff --git a/Mirivoice/Assets/Lang/strings-en-US.axaml b/Mirivoice/Assets/Lang/strings-en-US.axaml index 9a331a2..30efc08 100644 --- a/Mirivoice/Assets/Lang/strings-en-US.axaml +++ b/Mirivoice/Assets/Lang/strings-en-US.axaml @@ -44,8 +44,11 @@ An Error occured during export. Please Check Log file for more informations. Select Directory to export - Export audio merged (.wav) + Export merged audio (.wav) Set Filename to export + + Export SubRip Text for merged audio (.srt) + Set Filename to export diff --git a/Mirivoice/Mirivoice.Core/Managers/AudioManager.cs b/Mirivoice/Mirivoice.Core/Managers/AudioManager.cs index 39cbfe9..8be83f1 100644 --- a/Mirivoice/Mirivoice.Core/Managers/AudioManager.cs +++ b/Mirivoice/Mirivoice.Core/Managers/AudioManager.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Text; using System.Threading.Tasks; using Mirivoice.ViewModels; using Mirivoice.Views; @@ -62,7 +63,13 @@ string SetSuffixToUnique(string filepath, int suffix) } else return filepath; } - + public TimeSpan GetAudioDuration(string audioFilePath) + { + using (var reader = new AudioFileReader(audioFilePath)) + { + return reader.TotalTime; + } + } List GetAllCacheFiles() { return Directory.GetFiles(MainManager.Instance.PathM.CachePath, "*.wav").ToList(); @@ -79,7 +86,7 @@ List GetAllCacheFiles() /// /// /// - public async void PlayAllCacheFiles(int startIndex, bool exportOnlyAndDoNotPlay=false, bool exportPerTrack=true, string fileName="", string DirPath="") + public async void PlayAllCacheFiles(int startIndex, bool exportOnlyAndDoNotPlay=false, bool exportPerTrack=true, string fileName="", string DirPath="", bool exportSrtInsteadOfAudio = false) { MainViewModelPlaying = true; if ( _waveOut != null && _waveOut.PlaybackState == PlaybackState.Paused) @@ -88,6 +95,8 @@ public async void PlayAllCacheFiles(int startIndex, bool exportOnlyAndDoNotPlay= return; } List caches = new List(); + List lines = new List(); + List voicerNames = new List(); int index = 0; v.SingleTextBoxEditorEnabled = false; @@ -95,9 +104,13 @@ public async void PlayAllCacheFiles(int startIndex, bool exportOnlyAndDoNotPlay= var tasks = new List(); caches.Clear(); + lines.Clear(); + voicerNames.Clear(); for (int i = startIndex - 1; i < v.LineBoxCollection.Count; ++i) { caches.Add(v.LineBoxCollection[i].CurrentCacheName); + lines.Add(v.LineBoxCollection[i].viewModel.LineText); + voicerNames.Add(v.LineBoxCollection[i].viewModel.voicerSelector.CurrentVoicer.Info.Name); } v.MainWindowGetInput = false; for (int i = 0; i < v.LineBoxCollection.Count; ++i) @@ -165,8 +178,45 @@ public async void PlayAllCacheFiles(int startIndex, bool exportOnlyAndDoNotPlay= } else { + string exportPath; + // export srt for mixdown + if (exportSrtInsteadOfAudio) + { + exportPath = Path.Combine(DirPath, $"{fileName}.srt"); // for srt with line texts + string exportPathNamesSrt = Path.Combine(DirPath, $"{fileName}-voicer names.srt"); // for srt with voicer names + exportPath = SetSuffixToUnique(exportPath, 1); + exportPathNamesSrt = SetSuffixToUnique(exportPathNamesSrt, 1); + + TimeSpan lastTs = TimeSpan.Zero; + StringBuilder sb1 = new StringBuilder(); + StringBuilder sb2 = new StringBuilder(); + for (int i = 0; i < caches.Count; ++i) + { + sb1.AppendLine((i + 1).ToString()); + sb2.AppendLine((i + 1).ToString()); + TimeSpan currTs = GetAudioDuration(caches[i]); + + string lastTime = lastTs.ToString(@"hh\:mm\:ss\,fff"); + string currTime = currTs.ToString(@"hh\:mm\:ss\,fff"); + sb1.AppendLine($"{lastTime} --> {currTime}"); // hours:minutes:seconds,milliseconds (00:00:00,000) + sb2.AppendLine($"{lastTime} --> {currTime}"); + sb1.AppendLine(lines[i]); + sb2.AppendLine(voicerNames[i]); + sb1.AppendLine(); + sb2.AppendLine(); + + + + lastTs = currTs; + } + File.WriteAllText(exportPath, sb1.ToString()); + File.WriteAllText(exportPathNamesSrt, sb2.ToString()); + + return; + } + // export mixdown - string exportPath = Path.Combine(DirPath, $"{fileName}.wav"); + exportPath = Path.Combine(DirPath, $"{fileName}.wav"); exportPath = SetSuffixToUnique(exportPath, 1); using (var outputWaveFile = new WaveFileWriter(exportPath, new WaveFormat(48000, 1))) { diff --git a/Mirivoice/ViewModels/MainViewModel.cs b/Mirivoice/ViewModels/MainViewModel.cs index ccf53c8..0f77413 100644 --- a/Mirivoice/ViewModels/MainViewModel.cs +++ b/Mirivoice/ViewModels/MainViewModel.cs @@ -40,6 +40,10 @@ public class MainViewModel : VoicerSelectingViewModelBase Patterns = new[] { "*.wav" } }; + public static FilePickerFileType MiriVoiceExportSubRip { get; } = new("SubRip File") + { + Patterns = new[] { "*.srt" } + }; public static FilePickerFileType MiriVoiceVoicer { get; } = new("Zip File") { Patterns = new[] { "*.zip" } @@ -816,6 +820,36 @@ public void OnVoicersButtonClick() window.Show(); } + public async void OnExportSrtClick() + { + if (LineBoxCollection.Count == 0) + { + return; + } + var topLevel = TopLevel.GetTopLevel(mainWindow); + var file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + Title = (string)mainWindow.FindResource("menu.files.export.srt.desc"), + DefaultExtension = "srt", + ShowOverwritePrompt = true, + FileTypeChoices = new[] { MiriVoiceExportSubRip }, + SuggestedFileName = System.IO.Path.GetFileNameWithoutExtension(CurrentProjectPath) + ".srt" + }); + + if (file is not null) + { + string path = file.Path.LocalPath; + try + { + MainManager.Instance.AudioM.PlayAllCacheFiles(1, true, false, System.IO.Path.GetFileNameWithoutExtension(path), System.IO.Path.GetDirectoryName(path), true); + } + catch (Exception e) + { + Log.Error($"[Failed to export srt for merged audio]{e.ToString}: {e.Message} \n>> traceback: \n\t{e.StackTrace}"); + var res = await ShowConfirmWindow("menu.files.export.failed"); + } + } + } public async void OnVoicerInstallButtonClick() { VoicerInstaller voicerInstaller = new VoicerInstaller(this); diff --git a/Mirivoice/ViewModels/ViewModelBase.cs b/Mirivoice/ViewModels/ViewModelBase.cs index 6fb5478..c1f5834 100644 --- a/Mirivoice/ViewModels/ViewModelBase.cs +++ b/Mirivoice/ViewModels/ViewModelBase.cs @@ -9,7 +9,7 @@ public class ViewModelBase : ReactiveObject, INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; public virtual void OnPropertyChanged(string propertyName) { - Log.Debug("[Property Changed]: {propertyName}", propertyName); + //Log.Debug("[Property Changed]: {propertyName}", propertyName); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } diff --git a/Mirivoice/ViewModels/VoicersVoicerButtonViewModel.cs b/Mirivoice/ViewModels/VoicersVoicerButtonViewModel.cs index 17d11e4..68490e1 100644 --- a/Mirivoice/ViewModels/VoicersVoicerButtonViewModel.cs +++ b/Mirivoice/ViewModels/VoicersVoicerButtonViewModel.cs @@ -105,7 +105,6 @@ public void OnButtonClick() foreach (var meta in voicerMetas ) { Log.Debug($"VoicerMeta {i}: {meta.Style}"); - Voicer.CurrentVoicerMeta = meta; voicersStyleBoxes.Add(new VoicersStyleBox(Voicer, i, mv)); ++i; } diff --git a/Mirivoice/Views/MainView.axaml b/Mirivoice/Views/MainView.axaml index 84a2deb..4d73445 100644 --- a/Mirivoice/Views/MainView.axaml +++ b/Mirivoice/Views/MainView.axaml @@ -36,6 +36,8 @@ + + diff --git a/Mirivoice/Views/VoicersStyleBox.axaml b/Mirivoice/Views/VoicersStyleBox.axaml index 41cbd82..e2d67a7 100644 --- a/Mirivoice/Views/VoicersStyleBox.axaml +++ b/Mirivoice/Views/VoicersStyleBox.axaml @@ -20,9 +20,9 @@ - + diff --git a/Mirivoice/Views/VoicersStyleBox.axaml.cs b/Mirivoice/Views/VoicersStyleBox.axaml.cs index b737643..e396d0b 100644 --- a/Mirivoice/Views/VoicersStyleBox.axaml.cs +++ b/Mirivoice/Views/VoicersStyleBox.axaml.cs @@ -56,6 +56,7 @@ public async void OnSamplePlayButtonClick(object sender, RoutedEventArgs e) if (File.Exists(cachePath)) { isPlaying = true; + v.PlayAudio(cachePath); return; } if (voicer != null)