diff --git a/src/ui/Forms/Main.cs b/src/ui/Forms/Main.cs index 9030fc6a6..e579a6fc9 100644 --- a/src/ui/Forms/Main.cs +++ b/src/ui/Forms/Main.cs @@ -19027,7 +19027,7 @@ namespace Nikse.SubtitleEdit.Forms } else if (e.Modifiers == (Keys.Alt | Keys.Shift | Keys.Control) && e.KeyCode == Keys.T) { - using (var form = new TextToSpeech(_subtitle, _videoFileName)) + using (var form = new TextToSpeech(_subtitle, _videoFileName, _videoInfo)) { if (form.ShowDialog(this) != DialogResult.OK) { diff --git a/src/ui/Forms/TextToSpeech.Designer.cs b/src/ui/Forms/TextToSpeech.Designer.cs index d819778f5..8160cbb0d 100644 --- a/src/ui/Forms/TextToSpeech.Designer.cs +++ b/src/ui/Forms/TextToSpeech.Designer.cs @@ -29,9 +29,15 @@ private void InitializeComponent() { this.buttonOK = new System.Windows.Forms.Button(); - this.labelDescription = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); - this.textBox1 = new Nikse.SubtitleEdit.Controls.NikseTextBox(); + this.labelProgress = new System.Windows.Forms.Label(); + this.buttonGenerateTTS = new System.Windows.Forms.Button(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.labelEngine = new System.Windows.Forms.Label(); + this.groupBoxMsSettings = new System.Windows.Forms.GroupBox(); + this.labelMsVoice = new System.Windows.Forms.Label(); + this.nikseComboBoxVoice = new Nikse.SubtitleEdit.Controls.NikseComboBox(); + this.nikseComboBoxEngine = new Nikse.SubtitleEdit.Controls.NikseComboBox(); + this.groupBoxMsSettings.SuspendLayout(); this.SuspendLayout(); // // buttonOK @@ -46,50 +52,144 @@ this.buttonOK.UseVisualStyleBackColor = true; this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); // - // labelDescription + // labelProgress // - this.labelDescription.AutoSize = true; - this.labelDescription.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.labelDescription.Location = new System.Drawing.Point(9, 33); - this.labelDescription.Name = "labelDescription"; - this.labelDescription.Size = new System.Drawing.Size(76, 13); - this.labelDescription.TabIndex = 9; - this.labelDescription.Text = "Name of voice"; + this.labelProgress.AutoSize = true; + this.labelProgress.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.labelProgress.Location = new System.Drawing.Point(12, 384); + this.labelProgress.Name = "labelProgress"; + this.labelProgress.Size = new System.Drawing.Size(70, 13); + this.labelProgress.TabIndex = 9; + this.labelProgress.Text = "labelProgress"; // - // button1 + // buttonGenerateTTS // - this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button1.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.button1.Location = new System.Drawing.Point(12, 75); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 11; - this.button1.Text = "Go"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + this.buttonGenerateTTS.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonGenerateTTS.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.buttonGenerateTTS.Location = new System.Drawing.Point(571, 374); + this.buttonGenerateTTS.Name = "buttonGenerateTTS"; + this.buttonGenerateTTS.Size = new System.Drawing.Size(228, 23); + this.buttonGenerateTTS.TabIndex = 11; + this.buttonGenerateTTS.Text = "Generate speech from text"; + this.buttonGenerateTTS.UseVisualStyleBackColor = true; + this.buttonGenerateTTS.Click += new System.EventHandler(this.ButtonGenerateTtsClick); // - // textBox1 + // progressBar1 // - this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBox1.FocusedColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215))))); - this.textBox1.Location = new System.Drawing.Point(12, 49); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(229, 20); - this.textBox1.TabIndex = 10; - this.textBox1.Text = "Hello, how are you?"; + this.progressBar1.Location = new System.Drawing.Point(12, 407); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(706, 23); + this.progressBar1.TabIndex = 12; + // + // labelEngine + // + this.labelEngine.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelEngine.AutoSize = true; + this.labelEngine.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.labelEngine.Location = new System.Drawing.Point(405, 12); + this.labelEngine.Name = "labelEngine"; + this.labelEngine.Size = new System.Drawing.Size(40, 13); + this.labelEngine.TabIndex = 14; + this.labelEngine.Text = "Engine"; + // + // groupBoxMsSettings + // + this.groupBoxMsSettings.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBoxMsSettings.Controls.Add(this.labelMsVoice); + this.groupBoxMsSettings.Controls.Add(this.nikseComboBoxVoice); + this.groupBoxMsSettings.Location = new System.Drawing.Point(408, 57); + this.groupBoxMsSettings.Name = "groupBoxMsSettings"; + this.groupBoxMsSettings.Size = new System.Drawing.Size(391, 311); + this.groupBoxMsSettings.TabIndex = 15; + this.groupBoxMsSettings.TabStop = false; + this.groupBoxMsSettings.Text = "Settings"; + // + // labelMsVoice + // + this.labelMsVoice.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelMsVoice.AutoSize = true; + this.labelMsVoice.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.labelMsVoice.Location = new System.Drawing.Point(14, 25); + this.labelMsVoice.Name = "labelMsVoice"; + this.labelMsVoice.Size = new System.Drawing.Size(34, 13); + this.labelMsVoice.TabIndex = 16; + this.labelMsVoice.Text = "Voice"; + // + // nikseComboBoxVoice + // + this.nikseComboBoxVoice.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.nikseComboBoxVoice.BackColor = System.Drawing.SystemColors.Window; + this.nikseComboBoxVoice.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.nikseComboBoxVoice.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179))))); + this.nikseComboBoxVoice.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120))))); + this.nikseComboBoxVoice.ButtonForeColor = System.Drawing.SystemColors.ControlText; + this.nikseComboBoxVoice.ButtonForeColorDown = System.Drawing.Color.Orange; + this.nikseComboBoxVoice.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215))))); + this.nikseComboBoxVoice.DropDownHeight = 400; + this.nikseComboBoxVoice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.nikseComboBoxVoice.DropDownWidth = 195; + this.nikseComboBoxVoice.FormattingEnabled = false; + this.nikseComboBoxVoice.Location = new System.Drawing.Point(17, 41); + this.nikseComboBoxVoice.MaxLength = 32767; + this.nikseComboBoxVoice.Name = "nikseComboBoxVoice"; + this.nikseComboBoxVoice.SelectedIndex = -1; + this.nikseComboBoxVoice.SelectedItem = null; + this.nikseComboBoxVoice.SelectedText = ""; + this.nikseComboBoxVoice.Size = new System.Drawing.Size(351, 23); + this.nikseComboBoxVoice.TabIndex = 15; + this.nikseComboBoxVoice.UsePopupWindow = false; + // + // nikseComboBoxEngine + // + this.nikseComboBoxEngine.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.nikseComboBoxEngine.BackColor = System.Drawing.SystemColors.Window; + this.nikseComboBoxEngine.BackColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.nikseComboBoxEngine.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(171)))), ((int)(((byte)(173)))), ((int)(((byte)(179))))); + this.nikseComboBoxEngine.BorderColorDisabled = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120))))); + this.nikseComboBoxEngine.ButtonForeColor = System.Drawing.SystemColors.ControlText; + this.nikseComboBoxEngine.ButtonForeColorDown = System.Drawing.Color.Orange; + this.nikseComboBoxEngine.ButtonForeColorOver = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(120)))), ((int)(((byte)(215))))); + this.nikseComboBoxEngine.DropDownHeight = 400; + this.nikseComboBoxEngine.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDown; + this.nikseComboBoxEngine.DropDownWidth = 195; + this.nikseComboBoxEngine.FormattingEnabled = false; + this.nikseComboBoxEngine.Location = new System.Drawing.Point(408, 28); + this.nikseComboBoxEngine.MaxLength = 32767; + this.nikseComboBoxEngine.Name = "nikseComboBoxEngine"; + this.nikseComboBoxEngine.SelectedIndex = -1; + this.nikseComboBoxEngine.SelectedItem = null; + this.nikseComboBoxEngine.SelectedText = ""; + this.nikseComboBoxEngine.Size = new System.Drawing.Size(391, 23); + this.nikseComboBoxEngine.TabIndex = 13; + this.nikseComboBoxEngine.TabStop = false; + this.nikseComboBoxEngine.Text = "nikseComboBox1"; + this.nikseComboBoxEngine.UsePopupWindow = false; + this.nikseComboBoxEngine.SelectedIndexChanged += new System.EventHandler(this.nikseComboBoxEngine_SelectedIndexChanged); // // TextToSpeech // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(811, 442); - this.Controls.Add(this.button1); - this.Controls.Add(this.textBox1); - this.Controls.Add(this.labelDescription); + this.Controls.Add(this.groupBoxMsSettings); + this.Controls.Add(this.labelEngine); + this.Controls.Add(this.nikseComboBoxEngine); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.buttonGenerateTTS); + this.Controls.Add(this.labelProgress); this.Controls.Add(this.buttonOK); + this.KeyPreview = true; + this.MinimumSize = new System.Drawing.Size(827, 481); this.Name = "TextToSpeech"; - this.Text = "TextToSpeach"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Text to speach"; + this.groupBoxMsSettings.ResumeLayout(false); + this.groupBoxMsSettings.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -97,8 +197,13 @@ #endregion private System.Windows.Forms.Button buttonOK; - private Controls.NikseTextBox textBox1; - private System.Windows.Forms.Label labelDescription; - private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label labelProgress; + private System.Windows.Forms.Button buttonGenerateTTS; + private System.Windows.Forms.ProgressBar progressBar1; + private Controls.NikseComboBox nikseComboBoxEngine; + private System.Windows.Forms.Label labelEngine; + private System.Windows.Forms.GroupBox groupBoxMsSettings; + private System.Windows.Forms.Label labelMsVoice; + private Controls.NikseComboBox nikseComboBoxVoice; } } \ No newline at end of file diff --git a/src/ui/Forms/TextToSpeech.cs b/src/ui/Forms/TextToSpeech.cs index 32e75df05..2f3a8f0c7 100644 --- a/src/ui/Forms/TextToSpeech.cs +++ b/src/ui/Forms/TextToSpeech.cs @@ -1,5 +1,10 @@ -using Nikse.SubtitleEdit.Logic; +using Nikse.SubtitleEdit.Core.Common; +using Nikse.SubtitleEdit.Logic; using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; using System.Speech.Synthesis; using System.Windows.Forms; @@ -7,33 +12,322 @@ namespace Nikse.SubtitleEdit.Forms { public partial class TextToSpeech : Form { - public TextToSpeech(Core.Common.Subtitle subtitle, string videoFileName) + private readonly Subtitle _subtitle; + private readonly string _videoFileName; + private readonly VideoInfo _videoInfo; + private string _waveFolder; + + public TextToSpeech(Subtitle subtitle, string videoFileName, VideoInfo videoInfo) { UiUtil.PreInitialize(this); InitializeComponent(); UiUtil.FixFonts(this); + _subtitle = subtitle; + _videoFileName = videoFileName; + _videoInfo = videoInfo; + buttonOK.Text = LanguageSettings.Current.General.Ok; UiUtil.FixLargeFonts(this, buttonOK); + + progressBar1.Visible = false; + labelProgress.Text = string.Empty; + + nikseComboBoxEngine.DropDownStyle = ComboBoxStyle.DropDownList; + nikseComboBoxEngine.Items.Clear(); + nikseComboBoxEngine.Items.Add("Microsoft SpeechSynthesizer (fast/robotic)"); + nikseComboBoxEngine.Items.Add("Tortoise TTS (very slow/very good)"); + nikseComboBoxEngine.Items.Add("Mimic3"); + nikseComboBoxEngine.SelectedIndex = 0; } - private void button1_Click(object sender, EventArgs e) + private void ButtonGenerateTtsClick(object sender, EventArgs e) { - var text = textBox1.Text; + _waveFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + Directory.CreateDirectory(_waveFolder); - using (SpeechSynthesizer synth = new SpeechSynthesizer()) + if (nikseComboBoxEngine.SelectedIndex == 0) { - synth.SetOutputToWaveFile(@"C:\data\Sample.wav"); - synth.SelectVoiceByHints(VoiceGender.Male, VoiceAge.Adult); - var builder = new PromptBuilder(); - builder.AppendText(text); - synth.Speak(builder); + GenerateParagraphAudioMs(); } + else if (nikseComboBoxEngine.SelectedIndex == 1) + { + GenerateParagraphAudioTortoiseTts(); + } + + var fileNames = FixParagraphAudioSpeed(); + + // rename result file + var tempAudioFile = MergeAudioParagraphs(fileNames); + var resultAudioFileName = Path.Combine(Path.GetDirectoryName(tempAudioFile), Path.GetFileNameWithoutExtension(_videoFileName) + ".wav"); + File.Move(tempAudioFile, resultAudioFileName); + + Cleanup(_waveFolder, resultAudioFileName); + + UiUtil.OpenFolder(_waveFolder); + } + + private static void Cleanup(string waveFolder, string resultAudioFile) + { + foreach (var fileName in Directory.GetFiles(waveFolder, "*.wav")) + { + if (!fileName.Equals(resultAudioFile, StringComparison.OrdinalIgnoreCase)) + { + File.Delete(fileName); + } + } + } + + private List FixParagraphAudioSpeed() + { + var fileNames = new List(_subtitle.Paragraphs.Count); + + labelProgress.Text = "Adjusting speed..."; + labelProgress.Refresh(); + Application.DoEvents(); + + progressBar1.Value = 0; + progressBar1.Maximum = _subtitle.Paragraphs.Count; + progressBar1.Visible = true; + for (var index = 0; index < _subtitle.Paragraphs.Count; index++) + { + progressBar1.Value = index + 1; + labelProgress.Text = $"Adjusting speed: {index + 1} / {_subtitle.Paragraphs.Count}..."; + var p = _subtitle.Paragraphs[index]; + var next = _subtitle.GetParagraphOrDefault(index + 1); + var pFileName = Path.Combine(_waveFolder, index + ".wav"); + + var addDuration = 0d; + if (next != null && p.EndTime.TotalMilliseconds < next.StartTime.TotalMilliseconds) + { + var diff = next.StartTime.TotalMilliseconds - p.EndTime.TotalMilliseconds; + addDuration = Math.Max(1000, diff); + } + + var outputFileName1 = Path.Combine(_waveFolder, index + "_u.wav"); + var trimProcess = VideoPreviewGenerator.TrimSilenceStartAndEnd(pFileName, outputFileName1); + trimProcess.Start(); + trimProcess.WaitForExit(); + + var waveInfo = UiUtil.GetVideoInfo(outputFileName1); + if (waveInfo.TotalMilliseconds <= p.DurationTotalMilliseconds + addDuration) + { + fileNames.Add(outputFileName1); + continue; + } + + var factor = waveInfo.TotalMilliseconds / (p.DurationTotalMilliseconds + addDuration); + var outputFileName2 = Path.Combine(_waveFolder, index + "_t.wav"); + fileNames.Add(outputFileName2); + var mergeProcess = VideoPreviewGenerator.ChangeSpeed(outputFileName1, outputFileName2, (float)factor); + mergeProcess.Start(); + mergeProcess.WaitForExit(); + } + + return fileNames; + } + + private string MergeAudioParagraphs(List fileNames) + { + labelProgress.Text = "Merging audio track..."; + labelProgress.Refresh(); + Application.DoEvents(); + var silenceFileName = Path.Combine(_waveFolder, "silence.wav"); + var silenceProcess = VideoPreviewGenerator.GenerateEmptyAudio(silenceFileName, (float)_videoInfo.TotalSeconds); + silenceProcess.Start(); + silenceProcess.WaitForExit(); + + progressBar1.Value = 0; + progressBar1.Maximum = _subtitle.Paragraphs.Count; + progressBar1.Visible = true; + var inputFileName = silenceFileName; + var outputFileName = string.Empty; + for (var index = 0; index < fileNames.Count; index++) + { + progressBar1.Value = index + 1; + labelProgress.Text = $"Merging audio track: {index + 1} / {_subtitle.Paragraphs.Count}..."; + var p = _subtitle.Paragraphs[index]; + var pFileName = fileNames[index]; + outputFileName = Path.Combine(_waveFolder, $"silence{index}.wav"); + var mergeProcess = VideoPreviewGenerator.MergeAudioTracks(inputFileName, pFileName, outputFileName, (float)p.StartTime.TotalSeconds); + inputFileName = outputFileName; + mergeProcess.Start(); + mergeProcess.WaitForExit(); + } + + progressBar1.Visible = false; + labelProgress.Text = string.Empty; + + return outputFileName; + } + + private void GenerateParagraphAudioMs() + { + progressBar1.Value = 0; + progressBar1.Maximum = _subtitle.Paragraphs.Count; + progressBar1.Visible = true; + + using (var synthesizer = new SpeechSynthesizer()) + { + VoiceInfo voiceInfo = null; + var vs = synthesizer.GetInstalledVoices().Where(p => p.Enabled).ToList(); + for (var index = 0; index < vs.Count; index++) + { + var v = vs[index]; + if (index == nikseComboBoxVoice.SelectedIndex) + { + synthesizer.SelectVoice(v.VoiceInfo.Name); + voiceInfo = v.VoiceInfo; + } + } + + for (var index = 0; index < _subtitle.Paragraphs.Count; index++) + { + progressBar1.Value = index + 1; + labelProgress.Text = $"Generating audio texts: {index + 1} / {_subtitle.Paragraphs.Count}..."; + var p = _subtitle.Paragraphs[index]; + synthesizer.SetOutputToWaveFile(Path.Combine(_waveFolder, index + ".wav")); + var builder = new PromptBuilder(); + if (voiceInfo != null) + { + builder.StartVoice(voiceInfo); + } + + builder.AppendText(p.Text); + if (voiceInfo != null) + { + builder.EndVoice(); + } + + synthesizer.Speak(builder); + + progressBar1.Refresh(); + labelProgress.Refresh(); + Application.DoEvents(); + } + } + + progressBar1.Visible = false; + labelProgress.Text = string.Empty; + } + + private bool GenerateParagraphAudioTortoiseTts() + { + var pythonFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + "AppData", + "Local", + "Programs", + "Python"); + + var pyFileName = "do_tts.py"; + var voice = nikseComboBoxVoice.Text; + var files = Directory.EnumerateFiles(pythonFolder, pyFileName, SearchOption.AllDirectories).ToList(); + if (files.Count == 0) + { + MessageBox.Show($"{pyFileName} not found under {pythonFolder}"); + return false; + } + + var pythonFolderVersionFolder = files[0].Substring(pythonFolder.Length).Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); + var pythonExe = Path.Combine(pythonFolder, pythonFolderVersionFolder[0], "python.exe"); + if (!File.Exists(pythonExe)) + { + pythonExe = "python.exe"; + } + + progressBar1.Value = 0; + progressBar1.Maximum = _subtitle.Paragraphs.Count; + progressBar1.Visible = true; + + + for (var index = 0; index < _subtitle.Paragraphs.Count; index++) + { + progressBar1.Value = index + 1; + labelProgress.Text = $"Generating audio texts: {index + 1} / {_subtitle.Paragraphs.Count}..."; + var p = _subtitle.Paragraphs[index]; + var outputFileName = Path.Combine(_waveFolder, index + ".wav"); + + var processTortoiseTts = new Process + { + StartInfo = + { + WorkingDirectory = Path.GetDirectoryName(files[0]), + FileName = pythonExe, + Arguments = $"do_tts.py --output_path \"{_waveFolder}\" --preset ultra_fast --voice {voice} --text \"{p.Text.RemoveChar('"')}\"", + UseShellExecute = false, + CreateNoWindow = true, + } + }; + + processTortoiseTts.Start(); + processTortoiseTts.WaitForExit(); + + var inputFile = Path.Combine(_waveFolder, $"{voice}_0_2.wav"); + File.Move(inputFile, outputFileName); + + progressBar1.Refresh(); + labelProgress.Refresh(); + Application.DoEvents(); + } + + progressBar1.Visible = false; + labelProgress.Text = string.Empty; + + return true; } private void buttonOK_Click(object sender, EventArgs e) { DialogResult = DialogResult.OK; } + + private void nikseComboBoxEngine_SelectedIndexChanged(object sender, EventArgs e) + { + nikseComboBoxVoice.Items.Clear(); + + if (nikseComboBoxEngine.SelectedIndex == 0) + { + using (var synthesizer = new SpeechSynthesizer()) + { + foreach (var v in synthesizer.GetInstalledVoices()) + { + if (v.Enabled) + { + nikseComboBoxVoice.Items.Add(v.VoiceInfo.Name); + } + } + } + } + + if (nikseComboBoxEngine.SelectedIndex == 1) + { + nikseComboBoxVoice.Items.Add("angie"); + nikseComboBoxVoice.Items.Add("applejack"); + nikseComboBoxVoice.Items.Add("daniel"); + nikseComboBoxVoice.Items.Add("deniro"); + nikseComboBoxVoice.Items.Add("emma"); + nikseComboBoxVoice.Items.Add("freeman"); + nikseComboBoxVoice.Items.Add("geralt"); + nikseComboBoxVoice.Items.Add("halle"); + nikseComboBoxVoice.Items.Add("jlaw"); + nikseComboBoxVoice.Items.Add("lj"); + nikseComboBoxVoice.Items.Add("mol"); + nikseComboBoxVoice.Items.Add("myself"); + nikseComboBoxVoice.Items.Add("pat"); + nikseComboBoxVoice.Items.Add("pat2"); + nikseComboBoxVoice.Items.Add("rainbow"); + nikseComboBoxVoice.Items.Add("Update rainbow"); + nikseComboBoxVoice.Items.Add("snakes"); + nikseComboBoxVoice.Items.Add("tim_reynolds"); + nikseComboBoxVoice.Items.Add("tom"); + nikseComboBoxVoice.Items.Add("weaver"); + nikseComboBoxVoice.Items.Add("william"); + } + + if (nikseComboBoxVoice.Items.Count > 0) + { + nikseComboBoxVoice.SelectedIndex = 0; + } + } } -} +} \ No newline at end of file diff --git a/src/ui/Logic/VideoPreviewGenerator.cs b/src/ui/Logic/VideoPreviewGenerator.cs index 355ffe75d..3db6f84b0 100644 --- a/src/ui/Logic/VideoPreviewGenerator.cs +++ b/src/ui/Logic/VideoPreviewGenerator.cs @@ -75,6 +75,42 @@ namespace Nikse.SubtitleEdit.Logic return processMakeVideo; } + public static Process GenerateEmptyAudio(string outputFileName, float seconds, DataReceivedEventHandler dataReceivedHandler = null) + { + var processMakeVideo = new Process + { + StartInfo = + { + FileName = GetFfmpegLocation(), + Arguments = $"-f lavfi -i anullsrc -t {seconds.ToString(CultureInfo.InvariantCulture)} \"{outputFileName}\"", + UseShellExecute = false, + CreateNoWindow = true + } + }; + + SetupDataReceiveHandler(dataReceivedHandler, processMakeVideo); + + return processMakeVideo; + } + + public static Process MergeAudioTracks(string inputFileName1, string inputFileName2, string outputFileName, float startSeconds, DataReceivedEventHandler dataReceivedHandler = null) + { + var processMakeVideo = new Process + { + StartInfo = + { + FileName = GetFfmpegLocation(), + Arguments = $"-i \"{inputFileName1}\" -i \"{inputFileName2}\" -filter_complex \"aevalsrc=0:d={startSeconds.ToString(CultureInfo.InvariantCulture)}[s1];[s1][1:a]concat=n=2:v=0:a=1[ac1];[0:a][ac1]amix=2:normalize=false[aout]\" -map [aout] \"{outputFileName}\"", + UseShellExecute = false, + CreateNoWindow = true + } + }; + + SetupDataReceiveHandler(dataReceivedHandler, processMakeVideo); + + return processMakeVideo; + } + private static void SetupDataReceiveHandler(DataReceivedEventHandler dataReceivedHandler, Process processMakeVideo) { if (dataReceivedHandler != null) @@ -546,5 +582,45 @@ namespace Nikse.SubtitleEdit.Logic SetupDataReceiveHandler(outputHandler, processMakeVideo); return processMakeVideo; } + + public static Process ChangeSpeed(string inputFileName, string outputFileName, float inputSpeed, DataReceivedEventHandler dataReceivedHandler = null) + { + var speed = Math.Max(0.5f, inputSpeed); + speed = Math.Min(100, speed); + speed = (float)Math.Round(speed, 3, MidpointRounding.AwayFromZero); + + var processMakeVideo = new Process + { + StartInfo = + { + FileName = GetFfmpegLocation(), + Arguments = $"-i \"{inputFileName}\" -filter:a \"atempo={speed.ToString(CultureInfo.InvariantCulture)}\" \"{outputFileName}\"", + UseShellExecute = false, + CreateNoWindow = true + } + }; + + SetupDataReceiveHandler(dataReceivedHandler, processMakeVideo); + + return processMakeVideo; + } + + public static Process TrimSilenceStartAndEnd(string inputFileName, string outputFileName, DataReceivedEventHandler dataReceivedHandler = null) + { + var processMakeVideo = new Process + { + StartInfo = + { + FileName = GetFfmpegLocation(), + Arguments = $"-i \"{inputFileName}\" -af silenceremove=start_periods=1:start_silence=0.01,areverse,silenceremove=start_periods=1:start_silence=0.01,areverse \"{outputFileName}\"", + UseShellExecute = false, + CreateNoWindow = true + } + }; + + SetupDataReceiveHandler(dataReceivedHandler, processMakeVideo); + + return processMakeVideo; + } } }