From 040b18de00d59c7f2bae7061ef6cb1aa281846a3 Mon Sep 17 00:00:00 2001 From: niksedk Date: Sun, 27 Nov 2022 23:11:16 +0100 Subject: [PATCH] Add whisper timestamp auto shorten/adjust (requires silence between speak) Add raw whsiper output as subtitle format --- LanguageBaseEnglish.xml | 1 + .../AudioToText/AudioToTextPostProcessor.cs | 8 +- src/libse/AudioToText/WhisperTimingFixer.cs | 202 ++++++++++++++ src/libse/Common/Settings.cs | 9 + src/libse/SubtitleFormats/SubtitleFormat.cs | 1 + src/libse/SubtitleFormats/WhisperRaw.cs | 76 +++++ src/ui/Controls/AudioVisualizer.cs | 4 +- src/ui/Forms/AudioToText/VoskAudioToText.cs | 4 +- .../VoskAudioToTextSelectedLines.cs | 2 +- .../WhisperAudioToText.Designer.cs | 58 ++-- .../Forms/AudioToText/WhisperAudioToText.cs | 43 ++- .../WhisperAudioToTextSelectedLines.cs | 2 +- src/ui/Forms/Main.cs | 261 +++++++++++++----- src/ui/Logic/Language.cs | 1 + src/ui/Logic/LanguageDeserializer.cs | 3 + src/ui/Logic/LanguageStructure.cs | 1 + 16 files changed, 574 insertions(+), 102 deletions(-) create mode 100644 src/libse/AudioToText/WhisperTimingFixer.cs create mode 100644 src/libse/SubtitleFormats/WhisperRaw.cs diff --git a/LanguageBaseEnglish.xml b/LanguageBaseEnglish.xml index 2351dddf9..c2cd1b1b7 100644 --- a/LanguageBaseEnglish.xml +++ b/LanguageBaseEnglish.xml @@ -192,6 +192,7 @@ Read more info (web)? Transcribing audio to text - file {0} of {1}... {0} files saved to video source folder Use post-processing (line merge, fix casing, punctuation, and more) + Auto adjust timings Batch mode Keep partial transcription Translate to English diff --git a/src/libse/AudioToText/AudioToTextPostProcessor.cs b/src/libse/AudioToText/AudioToTextPostProcessor.cs index 118328f04..8bd7b6370 100644 --- a/src/libse/AudioToText/AudioToTextPostProcessor.cs +++ b/src/libse/AudioToText/AudioToTextPostProcessor.cs @@ -40,7 +40,7 @@ namespace Nikse.SubtitleEdit.Core.AudioToText } } - public Subtitle Generate(Engine engine, List resultTexts, bool usePostProcessing, bool addPeriods, bool mergeLines, bool fixCasing, bool fixShortDuration, bool splitLines) + public Subtitle Generate(Engine engine, List resultTexts, bool usePostProcessing, bool addPeriods, bool mergeLines, bool fixCasing, bool fixShortDuration, bool splitLines, bool autoAdjustTimings, WavePeakData wavePeaks) { _resultTexts = resultTexts; var subtitle = new Subtitle(); @@ -57,6 +57,12 @@ namespace Nikse.SubtitleEdit.Core.AudioToText } } + if (autoAdjustTimings && wavePeaks != null) + { + subtitle = WhisperTimingFixer.ShortenLongTexts(subtitle); + subtitle = WhisperTimingFixer.ShortenViaWavePeaks(subtitle, wavePeaks); + } + return Generate(subtitle, usePostProcessing, addPeriods, mergeLines, fixCasing, fixShortDuration, splitLines); } diff --git a/src/libse/AudioToText/WhisperTimingFixer.cs b/src/libse/AudioToText/WhisperTimingFixer.cs new file mode 100644 index 000000000..3339dfe6c --- /dev/null +++ b/src/libse/AudioToText/WhisperTimingFixer.cs @@ -0,0 +1,202 @@ +using Nikse.SubtitleEdit.Core.Common; +using System; + +namespace Nikse.SubtitleEdit.Core.AudioToText +{ + public static class WhisperTimingFixer + { + private static int SecondsToSampleIndex(double seconds, int sampleRate) + { + return (int)Math.Round(seconds * sampleRate, MidpointRounding.AwayFromZero); + } + + private static double FindPercentage(double startSeconds, double endSeconds, WavePeakData wavePeaks) + { + var min = Math.Max(0, SecondsToSampleIndex(startSeconds, wavePeaks.SampleRate)); + var max = Math.Min(wavePeaks.Peaks.Count, SecondsToSampleIndex(endSeconds, wavePeaks.SampleRate)); + + var minPeak = int.MaxValue; + var maxPeak = int.MinValue; + var count = 0; + for (var i = min; i < max; i++) + { + var v = wavePeaks.Peaks[i].Abs; + count++; + if (v < minPeak) + { + minPeak = v; + } + if (v > maxPeak) + { + maxPeak = v; + } + } + + if (count == 0) + { + return -1; + } + + var pctMin = minPeak * 100.0 / wavePeaks.HighestPeak; + var pctMax = maxPeak * 100.0 / wavePeaks.HighestPeak; + return (pctMin + pctMax) / 2.0; + } + + public static Subtitle ShortenViaWavePeaks(Subtitle subtitle, WavePeakData wavePeaks) + { + var s = new Subtitle(subtitle); + const double percentageMax = 7.0; + + for (var index = 0; index < s.Paragraphs.Count; index++) + { + var p = s.Paragraphs[index]; + var prevEndSecs = -1.0; + if (index > 0) + { + prevEndSecs = s.Paragraphs[index].EndTime.TotalSeconds; + } + + // Find nearest silence + var startPos = p.StartTime.TotalSeconds; + var pctHere = FindPercentage(startPos - 0.05, startPos + 0.05, wavePeaks); + if (Math.Abs(pctHere - 1) < 0.01) + { + return s; + } + + if (pctHere > percentageMax) + { + var startPosBack = startPos; + var startPosForward = startPos; + for (var ms = 50; ms < 255; ms += 50) + { + var pct = FindPercentage(startPosBack - 0.05, startPosBack + 0.05, wavePeaks); + if (Math.Abs(pct - 1) < 0.01) + { + return s; + } + + if (pct < percentageMax + 1 && p.Duration.TotalSeconds < 5) + { + startPosBack -= 0.025; + var pct2 = FindPercentage(startPosBack - 0.05, startPosBack + 0.05, wavePeaks); + if (pct2 < pct && pct2 >= 0) + { + var x = startPosBack + 0.05; + if (x < 0) + { + x = 0; + } + + if (x > prevEndSecs) + { + p.StartTime.TotalMilliseconds = x * 1000.0; + } + } + else + { + var x = startPosBack + 0.025 + 0.05; + if (x < 0) + { + x = 0; + } + + if (x > prevEndSecs) + { + p.StartTime.TotalMilliseconds = x * 1000.0; + } + } + + break; + } + + startPosBack -= 0.05; + + + + var pctF = FindPercentage(startPosForward - 0.05, startPosForward + 0.05, wavePeaks); + if (Math.Abs(pctHere - 1) < 0.01) + { + return s; + } + + if (pctF < percentageMax) + { + startPosForward -= 0.025; + var pct2 = FindPercentage(startPosForward - 0.05, startPosForward + 0.05, wavePeaks); + if (pct2 < pctF && pct2 >= 0) + { + p.StartTime.TotalSeconds = startPosForward + 0.05; + } + else + { + p.StartTime.TotalSeconds = startPosForward + 0.025 + 0.05; + } + + break; + } + + startPosForward += 0.05; + } + } + + // find next non-silence + startPos = p.StartTime.TotalSeconds; + pctHere = FindPercentage(startPos - 0.05, startPos + 0.05, wavePeaks); + if (pctHere < percentageMax) + { + var startPosForward = p.StartTime.TotalSeconds; + while (pctHere < percentageMax && startPos < p.EndTime.TotalSeconds - 1) + { + pctHere = FindPercentage(startPosForward - 0.05, startPosForward + 0.05, wavePeaks); + if (Math.Abs(pctHere - 1) < 0.01) + { + return s; + } + + p.StartTime.TotalSeconds = startPosForward; + if (pctHere >= percentageMax) + { + startPosForward -= 0.025; + var pct2 = FindPercentage(startPosForward - 0.05, startPosForward + 0.05, wavePeaks); + if (pct2 < pctHere && pct2 >= 0) + { + p.StartTime.TotalSeconds -= 0.025; + + pctHere = pct2; + startPosForward -= 0.025; + pct2 = FindPercentage(startPosForward - 0.05, startPosForward + 0.05, wavePeaks); + if (pct2 < pctHere && pct2 >= 0) + { + p.StartTime.TotalSeconds -= 0.025; + } + } + + break; + } + + startPosForward += 0.05; + } + } + } + + return s; + } + + public static Subtitle ShortenLongTexts(Subtitle subtitle) + { + var s = new Subtitle(subtitle); + + for (var i = 0; i < subtitle.Paragraphs.Count; i++) + { + var p = subtitle.Paragraphs[i]; + if (p.Duration.TotalSeconds > 5) + { + p.StartTime.TotalMilliseconds = p.EndTime.TotalMilliseconds - 5000; + } + } + + return s; + } + } +} diff --git a/src/libse/Common/Settings.cs b/src/libse/Common/Settings.cs index fbf60d617..55fd6ab8b 100644 --- a/src/libse/Common/Settings.cs +++ b/src/libse/Common/Settings.cs @@ -417,6 +417,7 @@ namespace Nikse.SubtitleEdit.Core.Common public string WhisperLanguageCode { get; set; } public string WhisperLocation { get; set; } public string WhisperExtraSettings { get; set; } + public bool WhisperAutoAdjustTimings { get; set; } public int AudioToTextLineMaxChars { get; set; } public int AudioToTextLineMaxCharsJp { get; set; } public int AudioToTextLineMaxCharsCn { get; set; } @@ -621,6 +622,7 @@ namespace Nikse.SubtitleEdit.Core.Common WhisperDeleteTempFiles = true; WhisperExtraSettings = ""; WhisperLanguageCode = "en"; + WhisperAutoAdjustTimings = true; AudioToTextLineMaxChars = 86; AudioToTextLineMaxCharsJp = 32; AudioToTextLineMaxCharsCn = 36; @@ -6177,6 +6179,12 @@ $HorzAlign = Center settings.Tools.WhisperLanguageCode = subNode.InnerText; } + subNode = node.SelectSingleNode("WhisperAutoAdjustTimings"); + if (subNode != null) + { + settings.Tools.WhisperAutoAdjustTimings = Convert.ToBoolean(subNode.InnerText, CultureInfo.InvariantCulture); + } + subNode = node.SelectSingleNode("AudioToTextLineMaxChars"); if (subNode != null) { @@ -10429,6 +10437,7 @@ $HorzAlign = Center textWriter.WriteElementString("WhisperLocation", settings.Tools.WhisperLocation); textWriter.WriteElementString("WhisperExtraSettings", settings.Tools.WhisperExtraSettings); textWriter.WriteElementString("WhisperLanguageCode", settings.Tools.WhisperLanguageCode); + textWriter.WriteElementString("WhisperAutoAdjustTimings", settings.Tools.WhisperAutoAdjustTimings.ToString(CultureInfo.InvariantCulture)); textWriter.WriteElementString("AudioToTextLineMaxChars", settings.Tools.AudioToTextLineMaxChars.ToString(CultureInfo.InvariantCulture)); textWriter.WriteElementString("AudioToTextLineMaxCharsJp", settings.Tools.AudioToTextLineMaxCharsJp.ToString(CultureInfo.InvariantCulture)); textWriter.WriteElementString("AudioToTextLineMaxCharsCn", settings.Tools.AudioToTextLineMaxCharsCn.ToString(CultureInfo.InvariantCulture)); diff --git a/src/libse/SubtitleFormats/SubtitleFormat.cs b/src/libse/SubtitleFormats/SubtitleFormat.cs index be07e0cea..f1ad6d3a3 100644 --- a/src/libse/SubtitleFormats/SubtitleFormat.cs +++ b/src/libse/SubtitleFormats/SubtitleFormat.cs @@ -236,6 +236,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats new VocapiaSplit(), new WebVTT(), new WebVTTFileWithLineNumber(), + new WhisperRaw(), new Xif(), new Xmp(), new YouTubeAnnotations(), diff --git a/src/libse/SubtitleFormats/WhisperRaw.cs b/src/libse/SubtitleFormats/WhisperRaw.cs new file mode 100644 index 000000000..4cd466d04 --- /dev/null +++ b/src/libse/SubtitleFormats/WhisperRaw.cs @@ -0,0 +1,76 @@ +using Nikse.SubtitleEdit.Core.Common; +using Nikse.SubtitleEdit.Core.Enums; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace Nikse.SubtitleEdit.Core.SubtitleFormats +{ + public class WhisperRaw : SubtitleFormat + { + private readonly Regex _timeRegexShort = new Regex(@"^\[\d\d:\d\d[\.,]\d\d\d --> \d\d:\d\d[\.,]\d\d\d\]", RegexOptions.Compiled); + private readonly Regex _timeRegexLong = new Regex(@"^\[\d\d:\d\d:\d\d[\.,]\d\d\d --> \d\d:\d\d:\d\d[\.,]\d\d\d]", RegexOptions.Compiled); + public override string Extension => ".txt"; + public override string Name => "Whisper Raw"; + + public override string ToText(Subtitle subtitle, string title) + { + var sb = new StringBuilder(); + const string writeFormat = "[{0} --> {1}] {2}"; + foreach (var p in subtitle.Paragraphs) + { + sb.AppendLine(string.Format(writeFormat, EncodeEndTimeCode(p.StartTime), EncodeEndTimeCode(p.EndTime), HtmlUtil.RemoveHtmlTags(p.Text.Replace(Environment.NewLine, " "), true))); + sb.AppendLine(); + } + + return sb.ToString(); + } + + private static string EncodeEndTimeCode(TimeCode time) + { + return $"{time.ToDisplayString()}"; + } + + public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) + { + subtitle.Paragraphs.Clear(); + _errorCount = 0; + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + if (trimmedLine.StartsWith('[')) + { + if (_timeRegexShort.IsMatch(trimmedLine)) + { + var start = trimmedLine.Substring(1, 10); + var end = trimmedLine.Substring(14, 10); + var text = trimmedLine.Remove(0, 25).Trim(); + if (!string.IsNullOrEmpty(text)) + { + subtitle.Paragraphs.Add(new Paragraph(text, GetMs(start), GetMs(end))); + } + } + else if (_timeRegexLong.IsMatch(trimmedLine)) + { + var start = trimmedLine.Substring(1, 12); + var end = trimmedLine.Substring(18, 12); + var text = trimmedLine.Remove(0, 31).Trim(); + if (!string.IsNullOrEmpty(text)) + { + subtitle.Paragraphs.Add(new Paragraph(text, GetMs(start), GetMs(end))); + } + } + } + } + + subtitle.Sort(SubtitleSortCriteria.StartTime); + subtitle.Renumber(); + } + + private static double GetMs(string timeCode) + { + return TimeCode.ParseToMilliseconds(timeCode); + } + } +} diff --git a/src/ui/Controls/AudioVisualizer.cs b/src/ui/Controls/AudioVisualizer.cs index 52b9549f9..2bb3a1b2f 100644 --- a/src/ui/Controls/AudioVisualizer.cs +++ b/src/ui/Controls/AudioVisualizer.cs @@ -1158,13 +1158,13 @@ namespace Nikse.SubtitleEdit.Controls [MethodImpl(MethodImplOptions.AggressiveInlining)] private int SecondsToXPosition(double seconds) { - return (int)Math.Round(seconds * _wavePeaks.SampleRate * _zoomFactor); + return (int)Math.Round(seconds * _wavePeaks.SampleRate * _zoomFactor, MidpointRounding.AwayFromZero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private int SecondsToSampleIndex(double seconds) { - return (int)Math.Round(seconds * _wavePeaks.SampleRate); + return (int)Math.Round(seconds * _wavePeaks.SampleRate, MidpointRounding.AwayFromZero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ui/Forms/AudioToText/VoskAudioToText.cs b/src/ui/Forms/AudioToText/VoskAudioToText.cs index 0514d0619..c2e33d5c1 100644 --- a/src/ui/Forms/AudioToText/VoskAudioToText.cs +++ b/src/ui/Forms/AudioToText/VoskAudioToText.cs @@ -156,7 +156,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText { ParagraphMaxChars = Configuration.Settings.General.SubtitleLineMaximumLength * 2, }; - TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Vosk, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, false); + TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Vosk, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, false, false, null); DialogResult = DialogResult.OK; } @@ -218,7 +218,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText { ParagraphMaxChars = Configuration.Settings.General.SubtitleLineMaximumLength * 2, }; - TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Vosk, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, false); + TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Vosk, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, false, false, null); SaveToSourceFolder(videoFileName); TaskbarList.SetProgressValue(_parentForm.Handle, _batchFileNumber, listViewInputFiles.Items.Count); diff --git a/src/ui/Forms/AudioToText/VoskAudioToTextSelectedLines.cs b/src/ui/Forms/AudioToText/VoskAudioToTextSelectedLines.cs index 689653498..2c4e7d5ea 100644 --- a/src/ui/Forms/AudioToText/VoskAudioToTextSelectedLines.cs +++ b/src/ui/Forms/AudioToText/VoskAudioToTextSelectedLines.cs @@ -127,7 +127,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText return; } - TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Vosk, transcript, checkBoxUsePostProcessing.Checked, false, true, false, false, false); + TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Vosk, transcript, checkBoxUsePostProcessing.Checked, false, true, false, false, false, false, null); progressBar1.Value = (int)Math.Round(_batchFileNumber * 100.0 / _audioClips.Count, MidpointRounding.AwayFromZero); progressBar1.Refresh(); diff --git a/src/ui/Forms/AudioToText/WhisperAudioToText.Designer.cs b/src/ui/Forms/AudioToText/WhisperAudioToText.Designer.cs index 12e061ada..7e20acd04 100644 --- a/src/ui/Forms/AudioToText/WhisperAudioToText.Designer.cs +++ b/src/ui/Forms/AudioToText/WhisperAudioToText.Designer.cs @@ -62,6 +62,7 @@ this.whisperCppCToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.removeTemporaryFilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.checkBoxAutoAdjustTimings = new System.Windows.Forms.CheckBox(); this.groupBoxModels.SuspendLayout(); this.groupBoxInputFiles.SuspendLayout(); this.contextMenuStripWhisperAdvanced.SuspendLayout(); @@ -72,10 +73,10 @@ this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.buttonCancel.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.buttonCancel.Location = new System.Drawing.Point(622, 427); + this.buttonCancel.Location = new System.Drawing.Point(622, 457); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(75, 23); - this.buttonCancel.TabIndex = 10; + this.buttonCancel.TabIndex = 8; this.buttonCancel.Text = "C&ancel"; this.buttonCancel.UseVisualStyleBackColor = true; this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); @@ -84,10 +85,10 @@ // this.buttonGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonGenerate.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.buttonGenerate.Location = new System.Drawing.Point(373, 427); + this.buttonGenerate.Location = new System.Drawing.Point(373, 457); this.buttonGenerate.Name = "buttonGenerate"; this.buttonGenerate.Size = new System.Drawing.Size(125, 23); - this.buttonGenerate.TabIndex = 8; + this.buttonGenerate.TabIndex = 6; this.buttonGenerate.Text = "&Generate"; this.buttonGenerate.UseVisualStyleBackColor = true; this.buttonGenerate.Click += new System.EventHandler(this.ButtonGenerate_Click); @@ -96,7 +97,7 @@ // this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.progressBar1.Location = new System.Drawing.Point(12, 427); + this.progressBar1.Location = new System.Drawing.Point(12, 457); this.progressBar1.Name = "progressBar1"; this.progressBar1.Size = new System.Drawing.Size(355, 12); this.progressBar1.TabIndex = 7; @@ -106,7 +107,7 @@ // this.labelProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelProgress.AutoSize = true; - this.labelProgress.Location = new System.Drawing.Point(12, 409); + this.labelProgress.Location = new System.Drawing.Point(12, 439); this.labelProgress.Name = "labelProgress"; this.labelProgress.Size = new System.Drawing.Size(70, 13); this.labelProgress.TabIndex = 6; @@ -121,7 +122,7 @@ this.textBoxLog.Multiline = true; this.textBoxLog.Name = "textBoxLog"; this.textBoxLog.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.textBoxLog.Size = new System.Drawing.Size(168, 258); + this.textBoxLog.Size = new System.Drawing.Size(168, 288); this.textBoxLog.TabIndex = 0; // // labelInfo @@ -146,7 +147,7 @@ this.groupBoxModels.Location = new System.Drawing.Point(15, 59); this.groupBoxModels.Name = "groupBoxModels"; this.groupBoxModels.Size = new System.Drawing.Size(682, 83); - this.groupBoxModels.TabIndex = 3; + this.groupBoxModels.TabIndex = 1; this.groupBoxModels.TabStop = false; this.groupBoxModels.Text = "Language and models"; // @@ -166,7 +167,7 @@ this.comboBoxLanguages.Location = new System.Drawing.Point(6, 44); this.comboBoxLanguages.Name = "comboBoxLanguages"; this.comboBoxLanguages.Size = new System.Drawing.Size(240, 21); - this.comboBoxLanguages.TabIndex = 5; + this.comboBoxLanguages.TabIndex = 0; this.comboBoxLanguages.SelectedIndexChanged += new System.EventHandler(this.comboBoxLanguages_SelectedIndexChanged); // // buttonDownload @@ -215,7 +216,7 @@ this.linkLabeWhisperWebSite.Location = new System.Drawing.Point(12, 26); this.linkLabeWhisperWebSite.Name = "linkLabeWhisperWebSite"; this.linkLabeWhisperWebSite.Size = new System.Drawing.Size(85, 13); - this.linkLabeWhisperWebSite.TabIndex = 2; + this.linkLabeWhisperWebSite.TabIndex = 0; this.linkLabeWhisperWebSite.TabStop = true; this.linkLabeWhisperWebSite.Text = "Whisper website"; this.linkLabeWhisperWebSite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelWhisperWebsite_LinkClicked); @@ -224,7 +225,7 @@ // this.labelTime.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelTime.AutoSize = true; - this.labelTime.Location = new System.Drawing.Point(12, 442); + this.labelTime.Location = new System.Drawing.Point(12, 472); this.labelTime.Name = "labelTime"; this.labelTime.Size = new System.Drawing.Size(88, 13); this.labelTime.TabIndex = 6; @@ -237,21 +238,22 @@ // checkBoxUsePostProcessing // this.checkBoxUsePostProcessing.AutoSize = true; - this.checkBoxUsePostProcessing.Location = new System.Drawing.Point(15, 177); + this.checkBoxUsePostProcessing.Location = new System.Drawing.Point(15, 185); this.checkBoxUsePostProcessing.Name = "checkBoxUsePostProcessing"; this.checkBoxUsePostProcessing.Size = new System.Drawing.Size(312, 17); this.checkBoxUsePostProcessing.TabIndex = 4; this.checkBoxUsePostProcessing.Text = "Use post-processing (line merge, fix casing, and punctuation)"; this.checkBoxUsePostProcessing.UseVisualStyleBackColor = true; + this.checkBoxUsePostProcessing.CheckedChanged += new System.EventHandler(this.checkBoxUsePostProcessing_CheckedChanged); // // buttonBatchMode // this.buttonBatchMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonBatchMode.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.buttonBatchMode.Location = new System.Drawing.Point(504, 427); + this.buttonBatchMode.Location = new System.Drawing.Point(504, 457); this.buttonBatchMode.Name = "buttonBatchMode"; this.buttonBatchMode.Size = new System.Drawing.Size(112, 23); - this.buttonBatchMode.TabIndex = 9; + this.buttonBatchMode.TabIndex = 7; this.buttonBatchMode.Text = "Batch mode"; this.buttonBatchMode.UseVisualStyleBackColor = true; this.buttonBatchMode.Click += new System.EventHandler(this.buttonBatchMode_Click); @@ -265,9 +267,9 @@ this.groupBoxInputFiles.Controls.Add(this.buttonRemoveFile); this.groupBoxInputFiles.Controls.Add(this.buttonAddFile); this.groupBoxInputFiles.Controls.Add(this.listViewInputFiles); - this.groupBoxInputFiles.Location = new System.Drawing.Point(15, 200); + this.groupBoxInputFiles.Location = new System.Drawing.Point(15, 246); this.groupBoxInputFiles.Name = "groupBoxInputFiles"; - this.groupBoxInputFiles.Size = new System.Drawing.Size(682, 185); + this.groupBoxInputFiles.Size = new System.Drawing.Size(682, 169); this.groupBoxInputFiles.TabIndex = 5; this.groupBoxInputFiles.TabStop = false; this.groupBoxInputFiles.Text = "Input files"; @@ -317,7 +319,7 @@ this.listViewInputFiles.HideSelection = false; this.listViewInputFiles.Location = new System.Drawing.Point(6, 18); this.listViewInputFiles.Name = "listViewInputFiles"; - this.listViewInputFiles.Size = new System.Drawing.Size(591, 150); + this.listViewInputFiles.Size = new System.Drawing.Size(591, 134); this.listViewInputFiles.TabIndex = 0; this.listViewInputFiles.UseCompatibleStateImageBehavior = false; this.listViewInputFiles.View = System.Windows.Forms.View.Details; @@ -334,7 +336,7 @@ // this.labelFC.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.labelFC.ForeColor = System.Drawing.Color.Gray; - this.labelFC.Location = new System.Drawing.Point(247, 442); + this.labelFC.Location = new System.Drawing.Point(247, 472); this.labelFC.Name = "labelFC"; this.labelFC.Size = new System.Drawing.Size(120, 17); this.labelFC.TabIndex = 19; @@ -347,7 +349,7 @@ this.checkBoxTranslateToEnglish.Location = new System.Drawing.Point(15, 153); this.checkBoxTranslateToEnglish.Name = "checkBoxTranslateToEnglish"; this.checkBoxTranslateToEnglish.Size = new System.Drawing.Size(119, 17); - this.checkBoxTranslateToEnglish.TabIndex = 20; + this.checkBoxTranslateToEnglish.TabIndex = 2; this.checkBoxTranslateToEnglish.Text = "Translate to English"; this.checkBoxTranslateToEnglish.UseVisualStyleBackColor = true; // @@ -365,7 +367,7 @@ // labelElapsed // this.labelElapsed.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.labelElapsed.Location = new System.Drawing.Point(215, 409); + this.labelElapsed.Location = new System.Drawing.Point(215, 439); this.labelElapsed.Name = "labelElapsed"; this.labelElapsed.Size = new System.Drawing.Size(152, 13); this.labelElapsed.TabIndex = 22; @@ -380,7 +382,7 @@ this.toolStripSeparator1, this.removeTemporaryFilesToolStripMenuItem}); this.contextMenuStripWhisperAdvanced.Name = "contextMenuStripWhisperAdvanced"; - this.contextMenuStripWhisperAdvanced.Size = new System.Drawing.Size(200, 98); + this.contextMenuStripWhisperAdvanced.Size = new System.Drawing.Size(200, 76); // // whisperPhpOriginalToolStripMenuItem // @@ -408,11 +410,22 @@ this.removeTemporaryFilesToolStripMenuItem.Text = "Remove temporary files"; this.removeTemporaryFilesToolStripMenuItem.Click += new System.EventHandler(this.removeTemporaryFilesToolStripMenuItem_Click); // + // checkBoxAutoAdjustTimings + // + this.checkBoxAutoAdjustTimings.AutoSize = true; + this.checkBoxAutoAdjustTimings.Location = new System.Drawing.Point(42, 208); + this.checkBoxAutoAdjustTimings.Name = "checkBoxAutoAdjustTimings"; + this.checkBoxAutoAdjustTimings.Size = new System.Drawing.Size(114, 17); + this.checkBoxAutoAdjustTimings.TabIndex = 3; + this.checkBoxAutoAdjustTimings.Text = "Auto adjust timings"; + this.checkBoxAutoAdjustTimings.UseVisualStyleBackColor = true; + // // WhisperAudioToText // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(709, 464); + this.ClientSize = new System.Drawing.Size(709, 494); + this.Controls.Add(this.checkBoxAutoAdjustTimings); this.Controls.Add(this.labelElapsed); this.Controls.Add(this.labelCpp); this.Controls.Add(this.checkBoxTranslateToEnglish); @@ -485,5 +498,6 @@ private System.Windows.Forms.ToolStripMenuItem whisperCppCToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripMenuItem removeTemporaryFilesToolStripMenuItem; + private System.Windows.Forms.CheckBox checkBoxAutoAdjustTimings; } } \ No newline at end of file diff --git a/src/ui/Forms/AudioToText/WhisperAudioToText.cs b/src/ui/Forms/AudioToText/WhisperAudioToText.cs index d1b39f6b2..b8e4b0e6a 100644 --- a/src/ui/Forms/AudioToText/WhisperAudioToText.cs +++ b/src/ui/Forms/AudioToText/WhisperAudioToText.cs @@ -56,6 +56,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText linkLabelOpenModelsFolder.Text = LanguageSettings.Current.AudioToText.OpenModelsFolder; checkBoxTranslateToEnglish.Text = LanguageSettings.Current.AudioToText.TranslateToEnglish; checkBoxUsePostProcessing.Text = LanguageSettings.Current.AudioToText.UsePostProcessing; + checkBoxAutoAdjustTimings.Text = LanguageSettings.Current.AudioToText.AutoAdjustTimings; buttonGenerate.Text = LanguageSettings.Current.Watermark.Generate; buttonCancel.Text = LanguageSettings.Current.General.Cancel; buttonBatchMode.Text = LanguageSettings.Current.AudioToText.BatchMode; @@ -69,6 +70,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText columnHeaderFileName.Text = LanguageSettings.Current.JoinSubtitles.FileName; checkBoxUsePostProcessing.Checked = Configuration.Settings.Tools.VoskPostProcessing; + checkBoxAutoAdjustTimings.Checked = Configuration.Settings.Tools.WhisperAutoAdjustTimings; _filesToDelete = new List(); @@ -193,7 +195,20 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText { ParagraphMaxChars = Configuration.Settings.General.SubtitleLineMaximumLength * 2, }; - TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Whisper, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, true); + + WavePeakData wavePeaks = null; + if (checkBoxAutoAdjustTimings.Checked) + { + using (var waveFile = new WavePeakGenerator(waveFileName)) + { + var wavePeakFileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".wav"); + waveFile.GeneratePeaks(0, wavePeakFileName); + wavePeaks = WavePeakData.FromDisk(wavePeakFileName); + _filesToDelete.Add(wavePeakFileName); + } + } + + TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Whisper, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, true, checkBoxAutoAdjustTimings.Checked, wavePeaks); if (transcript == null || transcript.Count == 0) { @@ -264,11 +279,23 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText return; } + WavePeakData wavePeaks = null; + if (checkBoxAutoAdjustTimings.Checked) + { + using (var waveFile = new WavePeakGenerator(waveFileName)) + { + var wavePeakFileName = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".wav"); + waveFile.GeneratePeaks(0, wavePeakFileName); + wavePeaks = WavePeakData.FromDisk(wavePeakFileName); + _filesToDelete.Add(wavePeakFileName); + } + } + var postProcessor = new AudioToTextPostProcessor(_languageCode) { ParagraphMaxChars = Configuration.Settings.General.SubtitleLineMaximumLength * 2, }; - TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Whisper, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, true); + TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Whisper, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, true, checkBoxAutoAdjustTimings.Checked, wavePeaks); SaveToSourceFolder(videoFileName); TaskbarList.SetProgressValue(_parentForm.Handle, _batchFileNumber, listViewInputFiles.Items.Count); @@ -670,7 +697,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText } translateToEnglish = $"--max-len {maxChars} "; - translateToEnglish = string.Empty; //TODO: remove line when "--max-len" is working! + //translateToEnglish = string.Empty; //TODO: remove line when "--max-len" is working! } var outputSrt = string.Empty; @@ -744,6 +771,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText } Configuration.Settings.Tools.VoskPostProcessing = checkBoxUsePostProcessing.Checked; + Configuration.Settings.Tools.WhisperAutoAdjustTimings = checkBoxAutoAdjustTimings.Checked; DeleteTemporaryFiles(_filesToDelete); } @@ -912,7 +940,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText if (_batchMode) { groupBoxInputFiles.Enabled = true; - Height = checkBoxUsePostProcessing.Bottom + progressBar1.Height + buttonCancel.Height + 450; + Height = checkBoxAutoAdjustTimings.Bottom + progressBar1.Height + buttonCancel.Height + 450; listViewInputFiles.Visible = true; buttonBatchMode.Text = LanguageSettings.Current.Split.Basic; MinimumSize = new Size(MinimumSize.Width, Height - 75); @@ -923,7 +951,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText else { groupBoxInputFiles.Enabled = false; - var h = checkBoxUsePostProcessing.Bottom + progressBar1.Height + buttonCancel.Height + 70; + var h = checkBoxAutoAdjustTimings.Bottom + progressBar1.Height + buttonCancel.Height + 70; MinimumSize = new Size(MinimumSize.Width, h - 10); Height = h; Width = _initialWidth; @@ -1067,5 +1095,10 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText Configuration.Settings.Tools.WhisperDeleteTempFiles = !Configuration.Settings.Tools.WhisperDeleteTempFiles; removeTemporaryFilesToolStripMenuItem.Checked = Configuration.Settings.Tools.WhisperDeleteTempFiles; } + + private void checkBoxUsePostProcessing_CheckedChanged(object sender, EventArgs e) + { + checkBoxAutoAdjustTimings.Enabled = checkBoxUsePostProcessing.Checked; + } } } diff --git a/src/ui/Forms/AudioToText/WhisperAudioToTextSelectedLines.cs b/src/ui/Forms/AudioToText/WhisperAudioToTextSelectedLines.cs index 7dd42b3f5..0d34ddaa4 100644 --- a/src/ui/Forms/AudioToText/WhisperAudioToTextSelectedLines.cs +++ b/src/ui/Forms/AudioToText/WhisperAudioToTextSelectedLines.cs @@ -149,7 +149,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText return; } - TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Whisper, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, false); + TranscribedSubtitle = postProcessor.Generate(AudioToTextPostProcessor.Engine.Whisper, transcript, checkBoxUsePostProcessing.Checked, true, true, true, true, false, false, null); SaveToAudioClip(_batchFileNumber - 1); TaskbarList.SetProgressValue(_parentForm.Handle, _batchFileNumber, listViewInputFiles.Items.Count); diff --git a/src/ui/Forms/Main.cs b/src/ui/Forms/Main.cs index 4169d2ed1..860eac9ee 100644 --- a/src/ui/Forms/Main.cs +++ b/src/ui/Forms/Main.cs @@ -18702,94 +18702,219 @@ namespace Nikse.SubtitleEdit.Forms return; } - var silenceLengthInSeconds = 0.08; - var lowPercent = audioVisualizer.FindLowPercentage(p.StartTime.TotalSeconds - 0.3, p.StartTime.TotalSeconds + 0.1); - var highPercent = audioVisualizer.FindHighPercentage(p.StartTime.TotalSeconds - 0.3, p.StartTime.TotalSeconds + 0.4); - var add = 5.0; - if (highPercent > 40) - { - add = 8; - } - else if (highPercent < 5) - { - add = highPercent - lowPercent - 0.3; - } + _subtitle = WhisperTimingFixer.ShortenViaWavePeaks(_subtitle, audioVisualizer.WavePeaks); - for (var startVolume = lowPercent + add; startVolume < 14; startVolume += 0.3) + SaveSubtitleListviewIndices(); + SubtitleListview1.Fill(_subtitle, _subtitleOriginal); + RestoreSubtitleListviewIndices(); + RefreshSelectedParagraph(); + return; + + var pctCheck = 10; + + // Find nearest silence + var startPos = p.StartTime.TotalSeconds; + var lowPercentx = audioVisualizer.FindLowPercentage(startPos - 0.05, startPos + 0.05); + var highPercentx = audioVisualizer.FindHighPercentage(startPos - 0.05, startPos + 0.05); + var pctHere = lowPercentx + highPercentx / 2; + if (pctHere > pctCheck) { - var pos = audioVisualizer.FindDataBelowThresholdBackForStart(startVolume, silenceLengthInSeconds, p.StartTime.TotalSeconds); - var pos2 = audioVisualizer.FindDataBelowThresholdBackForStart(startVolume + 0.3, silenceLengthInSeconds, p.StartTime.TotalSeconds); - if (pos >= 0 && pos > p.StartTime.TotalSeconds - 1) + var startPosBack = startPos ; + var startPosForward = startPosBack; + for (var ms = 50; ms < 250; ms += 50) { - if (pos2 > pos && pos2 >= 0 && pos2 > p.StartTime.TotalSeconds - 1) + var lowPercentBack = audioVisualizer.FindLowPercentage(startPosBack - 0.05, startPosBack + 0.05); + var highPercentBack = audioVisualizer.FindHighPercentage(startPosBack - 0.05, startPosBack + 0.05); + var pct = lowPercentBack + highPercentBack / 2; + if (pct < pctCheck) { - pos = pos2; - } - - var newStartTimeMs = pos * TimeCode.BaseUnit; - var prev = _subtitle.GetParagraphOrDefault(index - 1); - if (prev != null && prev.EndTime.TotalMilliseconds + MinGapBetweenLines >= newStartTimeMs) - { - newStartTimeMs = prev.EndTime.TotalMilliseconds + MinGapBetweenLines; - if (newStartTimeMs >= p.StartTime.TotalMilliseconds) + startPosBack -= 0.025; + var lowPercentBack2 = audioVisualizer.FindLowPercentage(startPosBack - 0.05, startPosBack + 0.05); + var highPercentBack2 = audioVisualizer.FindHighPercentage(startPosBack - 0.05, startPosBack + 0.05); + var pct2 = lowPercentBack2 + highPercentBack2 / 2; + if (pct2 < pct) { - break; // cannot move start time + p.StartTime.TotalSeconds = startPosBack + 0.05; } - } - - // check for shot changes - if (audioVisualizer.ShotChanges != null) - { - var matchingShotChanges = audioVisualizer.ShotChanges - .Where(sc => sc > p.StartTime.TotalSeconds - 0.3 && sc < p.StartTime.TotalSeconds + 0.2) - .OrderBy(sc => Math.Abs(sc - p.StartTime.TotalSeconds)); - if (matchingShotChanges.Any()) + else { - newStartTimeMs = matchingShotChanges.First() * TimeCode.BaseUnit; + p.StartTime.TotalSeconds = startPosBack + 0.025 + + 0.05; } + + break; } - if (Math.Abs(p.StartTime.TotalMilliseconds - newStartTimeMs) < 10) - { - break; // diff too small - } + startPosBack -= 0.05; - var newEndTimeMs = p.EndTime.TotalMilliseconds; - if (newStartTimeMs > p.StartTime.TotalMilliseconds) + + + var lowPercentForward = audioVisualizer.FindLowPercentage(startPosForward - 0.05, startPosForward + 0.05); + var highPercentForward = audioVisualizer.FindHighPercentage(startPosForward - 0.05, startPosForward + 0.05); + var pctF = lowPercentForward + highPercentForward / 2; + if (pctF < pctCheck) { - var temp = new Paragraph(p); - temp.StartTime.TotalMilliseconds = newStartTimeMs; - if (temp.Duration.TotalMilliseconds < Configuration.Settings.General.SubtitleMinimumDisplayMilliseconds || - Utilities.GetCharactersPerSecond(temp) > Configuration.Settings.General.SubtitleMaximumCharactersPerSeconds) + startPosForward -= 0.025; + var lowPercentForward2 = audioVisualizer.FindLowPercentage(startPosForward - 0.05, startPosForward + 0.05); + var highPercentForward2 = audioVisualizer.FindHighPercentage(startPosForward - 0.05, startPosForward + 0.05); + var pct2 = lowPercentForward2 + highPercentForward2 / 2; + if (pct2 < pctF) { - var next = _subtitle.GetParagraphOrDefault(index + 1); - if (next == null || - next.StartTime.TotalMilliseconds > newStartTimeMs + p.Duration.TotalMilliseconds + MinGapBetweenLines) - { - newEndTimeMs = newStartTimeMs + p.Duration.TotalMilliseconds; - } + p.StartTime.TotalSeconds = startPosForward + 0.05; } - } - - MakeHistoryForUndo(string.Format(LanguageSettings.Current.Main.BeforeX, LanguageSettings.Current.Settings.WaveformGuessStart)); - - if (IsOriginalEditable) - { - var original = Utilities.GetOriginalParagraph(index, p, _subtitleOriginal.Paragraphs); - if (original != null) + else { - original.StartTime.TotalMilliseconds = newStartTimeMs; - original.EndTime.TotalMilliseconds = newEndTimeMs; + p.StartTime.TotalSeconds = startPosForward + 0.025 + +0.05; } + + break; } - p.StartTime.TotalMilliseconds = newStartTimeMs; - p.EndTime.TotalMilliseconds = newEndTimeMs; - RefreshSelectedParagraph(); - SubtitleListview1.SetStartTimeAndDuration(index, p, _subtitle.GetParagraphOrDefault(index + 1), _subtitle.GetParagraphOrDefault(index - 1)); - break; + startPosForward += 0.05; } } + + + startPos = p.StartTime.TotalSeconds; + lowPercentx = audioVisualizer.FindLowPercentage(startPos - 0.05, startPos + 0.05); + highPercentx = audioVisualizer.FindHighPercentage(startPos - 0.05, startPos + 0.05); + pctHere = lowPercentx + highPercentx / 2; + if (pctHere < pctCheck) + { + var startPosForward = p.StartTime.TotalSeconds; + while (pctHere < pctCheck && startPos < p.EndTime.TotalSeconds - 1) + { + var lowPercentForward = audioVisualizer.FindLowPercentage(startPosForward - 0.05, startPosForward + 0.05); + var highPercentForward = audioVisualizer.FindHighPercentage(startPosForward - 0.05, startPosForward + 0.05); + pctHere = lowPercentForward + highPercentForward / 2; + + p.StartTime.TotalSeconds = startPosForward; + + if (pctHere >= pctCheck) + { + startPosForward -= 0.025; + var lowPercentForward2 = audioVisualizer.FindLowPercentage(startPosForward - 0.05, startPosForward + 0.05); + var highPercentForward2 = audioVisualizer.FindHighPercentage(startPosForward - 0.05, startPosForward + 0.05); + var pct2 = lowPercentForward2 + highPercentForward2 / 2; + if (pct2 < pctHere) + { + p.StartTime.TotalSeconds -= 0.025; + + pctHere = pct2; + startPosForward -= 0.025; + lowPercentForward2 = audioVisualizer.FindLowPercentage(startPosForward - 0.05, startPosForward + 0.05); + highPercentForward2 = audioVisualizer.FindHighPercentage(startPosForward - 0.05, startPosForward + 0.05); + pct2 = lowPercentForward2 + highPercentForward2 / 2; + if (pct2 < pctHere) + { + p.StartTime.TotalSeconds -= 0.025; + } + } + + break; + } + + startPosForward += 0.05; + } + } + + + RefreshSelectedParagraph(); + SubtitleListview1.SetStartTimeAndDuration(index, p, _subtitle.GetParagraphOrDefault(index + 1), _subtitle.GetParagraphOrDefault(index - 1)); + + //var p = _subtitle.GetParagraphOrDefault(index); + //if (p == null) + //{ + // return; + //} + + //var silenceLengthInSeconds = 0.08; + //var lowPercent = audioVisualizer.FindLowPercentage(p.StartTime.TotalSeconds - 0.3, p.StartTime.TotalSeconds + 0.1); + //var highPercent = audioVisualizer.FindHighPercentage(p.StartTime.TotalSeconds - 0.3, p.StartTime.TotalSeconds + 0.4); + //var add = 5.0; + //if (highPercent > 40) + //{ + // add = 8; + //} + //else if (highPercent < 5) + //{ + // add = highPercent - lowPercent - 0.3; + //} + + //for (var startVolume = lowPercent + add; startVolume < 14; startVolume += 0.3) + //{ + // var pos = audioVisualizer.FindDataBelowThresholdBackForStart(startVolume, silenceLengthInSeconds, p.StartTime.TotalSeconds); + // var pos2 = audioVisualizer.FindDataBelowThresholdBackForStart(startVolume + 0.3, silenceLengthInSeconds, p.StartTime.TotalSeconds); + // if (pos >= 0 && pos > p.StartTime.TotalSeconds - 1) + // { + // if (pos2 > pos && pos2 >= 0 && pos2 > p.StartTime.TotalSeconds - 1) + // { + // pos = pos2; + // } + + // var newStartTimeMs = pos * TimeCode.BaseUnit; + // var prev = _subtitle.GetParagraphOrDefault(index - 1); + // if (prev != null && prev.EndTime.TotalMilliseconds + MinGapBetweenLines >= newStartTimeMs) + // { + // newStartTimeMs = prev.EndTime.TotalMilliseconds + MinGapBetweenLines; + // if (newStartTimeMs >= p.StartTime.TotalMilliseconds) + // { + // break; // cannot move start time + // } + // } + + // // check for shot changes + // if (audioVisualizer.ShotChanges != null) + // { + // var matchingShotChanges = audioVisualizer.ShotChanges + // .Where(sc => sc > p.StartTime.TotalSeconds - 0.3 && sc < p.StartTime.TotalSeconds + 0.2) + // .OrderBy(sc => Math.Abs(sc - p.StartTime.TotalSeconds)); + // if (matchingShotChanges.Any()) + // { + // newStartTimeMs = matchingShotChanges.First() * TimeCode.BaseUnit; + // } + // } + + // if (Math.Abs(p.StartTime.TotalMilliseconds - newStartTimeMs) < 10) + // { + // break; // diff too small + // } + + // var newEndTimeMs = p.EndTime.TotalMilliseconds; + // if (newStartTimeMs > p.StartTime.TotalMilliseconds) + // { + // var temp = new Paragraph(p); + // temp.StartTime.TotalMilliseconds = newStartTimeMs; + // if (temp.Duration.TotalMilliseconds < Configuration.Settings.General.SubtitleMinimumDisplayMilliseconds || + // Utilities.GetCharactersPerSecond(temp) > Configuration.Settings.General.SubtitleMaximumCharactersPerSeconds) + // { + // var next = _subtitle.GetParagraphOrDefault(index + 1); + // if (next == null || + // next.StartTime.TotalMilliseconds > newStartTimeMs + p.Duration.TotalMilliseconds + MinGapBetweenLines) + // { + // newEndTimeMs = newStartTimeMs + p.Duration.TotalMilliseconds; + // } + // } + // } + + // MakeHistoryForUndo(string.Format(LanguageSettings.Current.Main.BeforeX, LanguageSettings.Current.Settings.WaveformGuessStart)); + + // if (IsOriginalEditable) + // { + // var original = Utilities.GetOriginalParagraph(index, p, _subtitleOriginal.Paragraphs); + // if (original != null) + // { + // original.StartTime.TotalMilliseconds = newStartTimeMs; + // original.EndTime.TotalMilliseconds = newEndTimeMs; + // } + // } + + // p.StartTime.TotalMilliseconds = newStartTimeMs; + // p.EndTime.TotalMilliseconds = newEndTimeMs; + // RefreshSelectedParagraph(); + // SubtitleListview1.SetStartTimeAndDuration(index, p, _subtitle.GetParagraphOrDefault(index + 1), _subtitle.GetParagraphOrDefault(index - 1)); + // break; + // } + //} } private void GoToBookmark() diff --git a/src/ui/Logic/Language.cs b/src/ui/Logic/Language.cs index 18d25a28e..c6088aa4d 100644 --- a/src/ui/Logic/Language.cs +++ b/src/ui/Logic/Language.cs @@ -337,6 +337,7 @@ namespace Nikse.SubtitleEdit.Logic Transcribing = "Transcribing audio to text...", TranscribingXOfY = "Transcribing audio to text - file {0} of {1}...", UsePostProcessing = "Use post-processing (line merge, fix casing, punctuation, and more)", + AutoAdjustTimings = "Auto adjust timings", BatchMode = "Batch mode", XFilesSavedToVideoSourceFolder = "{0} files saved to video source folder", KeepPartialTranscription = "Keep partial transcription", diff --git a/src/ui/Logic/LanguageDeserializer.cs b/src/ui/Logic/LanguageDeserializer.cs index 32fd8028d..66de5fe30 100644 --- a/src/ui/Logic/LanguageDeserializer.cs +++ b/src/ui/Logic/LanguageDeserializer.cs @@ -517,6 +517,9 @@ namespace Nikse.SubtitleEdit.Logic case "AudioToText/UsePostProcessing": language.AudioToText.UsePostProcessing = reader.Value; break; + case "AudioToText/AutoAdjustTimings": + language.AudioToText.AutoAdjustTimings = reader.Value; + break; case "AudioToText/BatchMode": language.AudioToText.BatchMode = reader.Value; break; diff --git a/src/ui/Logic/LanguageStructure.cs b/src/ui/Logic/LanguageStructure.cs index 305a7ccef..854c049af 100644 --- a/src/ui/Logic/LanguageStructure.cs +++ b/src/ui/Logic/LanguageStructure.cs @@ -196,6 +196,7 @@ namespace Nikse.SubtitleEdit.Logic public string TranscribingXOfY { get; set; } public string XFilesSavedToVideoSourceFolder { get; set; } public string UsePostProcessing { get; set; } + public string AutoAdjustTimings { get; set; } public string BatchMode { get; set; } public string KeepPartialTranscription { get; set; } public string TranslateToEnglish { get; set; }