Add whisper timestamp auto shorten/adjust (requires silence between speak)

Add raw whsiper output as subtitle format
This commit is contained in:
niksedk 2022-11-27 23:11:16 +01:00
parent d37cc0a3de
commit 040b18de00
16 changed files with 574 additions and 102 deletions

View File

@ -192,6 +192,7 @@ Read more info (web)?</WhisperNotFound>
<TranscribingXOfY>Transcribing audio to text - file {0} of {1}...</TranscribingXOfY>
<XFilesSavedToVideoSourceFolder>{0} files saved to video source folder</XFilesSavedToVideoSourceFolder>
<UsePostProcessing>Use post-processing (line merge, fix casing, punctuation, and more)</UsePostProcessing>
<AutoAdjustTimings>Auto adjust timings</AutoAdjustTimings>
<BatchMode>Batch mode</BatchMode>
<KeepPartialTranscription>Keep partial transcription</KeepPartialTranscription>
<TranslateToEnglish>Translate to English</TranslateToEnglish>

View File

@ -40,7 +40,7 @@ namespace Nikse.SubtitleEdit.Core.AudioToText
}
}
public Subtitle Generate(Engine engine, List<ResultText> resultTexts, bool usePostProcessing, bool addPeriods, bool mergeLines, bool fixCasing, bool fixShortDuration, bool splitLines)
public Subtitle Generate(Engine engine, List<ResultText> 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);
}

View File

@ -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;
}
}
}

View File

@ -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));

View File

@ -236,6 +236,7 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
new VocapiaSplit(),
new WebVTT(),
new WebVTTFileWithLineNumber(),
new WhisperRaw(),
new Xif(),
new Xmp(),
new YouTubeAnnotations(),

View File

@ -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<string> 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);
}
}
}

View File

@ -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)]

View File

@ -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);

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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<string>();
@ -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;
}
}
}

View File

@ -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);

View File

@ -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)
{
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;
SaveSubtitleListviewIndices();
SubtitleListview1.Fill(_subtitle, _subtitleOriginal);
RestoreSubtitleListviewIndices();
RefreshSelectedParagraph();
SubtitleListview1.SetStartTimeAndDuration(index, p, _subtitle.GetParagraphOrDefault(index + 1), _subtitle.GetParagraphOrDefault(index - 1));
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 startPosBack = startPos ;
var startPosForward = startPosBack;
for (var ms = 50; ms < 250; ms += 50)
{
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)
{
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)
{
p.StartTime.TotalSeconds = startPosBack + 0.05;
}
else
{
p.StartTime.TotalSeconds = startPosBack + 0.025 + + 0.05;
}
break;
}
startPosBack -= 0.05;
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)
{
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)
{
p.StartTime.TotalSeconds = startPosForward + 0.05;
}
else
{
p.StartTime.TotalSeconds = startPosForward + 0.025 + +0.05;
}
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()

View File

@ -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",

View File

@ -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;

View File

@ -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; }