diff --git a/LanguageMaster.xml b/LanguageMaster.xml
index 5ea9edf2a..072db5cff 100644
--- a/LanguageMaster.xml
+++ b/LanguageMaster.xml
@@ -2021,6 +2021,7 @@ can edit in same subtitle file (collaboration)
Go to previous scene change
Go to next scene change
Toggle scene change
+ Auto adjust start via volume/scene change
One frame back
One frame forward
One frame back (with play)
diff --git a/libse/Language.cs b/libse/Language.cs
index f308ccf44..1b18fec68 100644
--- a/libse/Language.cs
+++ b/libse/Language.cs
@@ -2317,6 +2317,7 @@ can edit in same subtitle file (collaboration)",
WaveformGoToPreviousSceneChange = "Go to previous scene change",
WaveformGoToNextSceneChange = "Go to next scene change",
WaveformToggleSceneChange = "Toggle scene change",
+ WaveformGuessStart = "Auto adjust start via volume/scene change",
GoBack1Frame = "One frame back",
GoForward1Frame = "One frame forward",
GoBack1FrameWithPlay = "One frame back (with play)",
diff --git a/libse/LanguageDeserializer.cs b/libse/LanguageDeserializer.cs
index bbc576eba..b19e25c5b 100644
--- a/libse/LanguageDeserializer.cs
+++ b/libse/LanguageDeserializer.cs
@@ -5485,6 +5485,9 @@ namespace Nikse.SubtitleEdit.Core
case "Settings/WaveformToggleSceneChange":
language.Settings.WaveformToggleSceneChange = reader.Value;
break;
+ case "Settings/WaveformGuessStart":
+ language.Settings.WaveformGuessStart = reader.Value;
+ break;
case "Settings/GoBack1Frame":
language.Settings.GoBack1Frame = reader.Value;
break;
diff --git a/libse/LanguageStructure.cs b/libse/LanguageStructure.cs
index e9d4d9e54..bdaf1b36f 100644
--- a/libse/LanguageStructure.cs
+++ b/libse/LanguageStructure.cs
@@ -2186,6 +2186,7 @@
public string WaveformGoToPreviousSceneChange { get; set; }
public string WaveformGoToNextSceneChange { get; set; }
public string WaveformToggleSceneChange { get; set; }
+ public string WaveformGuessStart { get; set; }
public string GoBack1Frame { get; set; }
public string GoForward1Frame { get; set; }
public string GoBack1FrameWithPlay { get; set; }
diff --git a/libse/Settings.cs b/libse/Settings.cs
index b3031a786..7621e0d77 100644
--- a/libse/Settings.cs
+++ b/libse/Settings.cs
@@ -1557,6 +1557,7 @@ $HorzAlign = Center
public string WaveformGoToPreviousSceneChange { get; set; }
public string WaveformGoToNextSceneChange { get; set; }
public string WaveformToggleSceneChange { get; set; }
+ public string WaveformGuessStart { get; set; }
public string MainTranslateGoogleIt { get; set; }
public string MainTranslateGoogleTranslate { get; set; }
public string MainTranslateCustomSearch1 { get; set; }
@@ -6103,6 +6104,12 @@ $HorzAlign = Center
settings.Shortcuts.WaveformToggleSceneChange = subNode.InnerText;
}
+ subNode = node.SelectSingleNode("WaveformGuessStart");
+ if (subNode != null)
+ {
+ settings.Shortcuts.WaveformGuessStart = subNode.InnerText;
+ }
+
subNode = node.SelectSingleNode("MainTranslateGoogleIt");
if (subNode != null)
{
@@ -7109,6 +7116,7 @@ $HorzAlign = Center
textWriter.WriteElementString("WaveformGoToPreviousSceneChange", settings.Shortcuts.WaveformGoToPreviousSceneChange);
textWriter.WriteElementString("WaveformGoToNextSceneChange", settings.Shortcuts.WaveformGoToNextSceneChange);
textWriter.WriteElementString("WaveformToggleSceneChange", settings.Shortcuts.WaveformToggleSceneChange);
+ textWriter.WriteElementString("WaveformGuessStart", settings.Shortcuts.WaveformGuessStart);
textWriter.WriteElementString("MainTranslateGoogleIt", settings.Shortcuts.MainTranslateGoogleIt);
textWriter.WriteElementString("MainTranslateGoogleTranslate", settings.Shortcuts.MainTranslateGoogleTranslate);
textWriter.WriteElementString("MainTranslateCustomSearch1", settings.Shortcuts.MainTranslateCustomSearch1);
diff --git a/src/Controls/AudioVisualizer.cs b/src/Controls/AudioVisualizer.cs
index a78cd837e..e52ca0343 100644
--- a/src/Controls/AudioVisualizer.cs
+++ b/src/Controls/AudioVisualizer.cs
@@ -1926,6 +1926,7 @@ namespace Nikse.SubtitleEdit.Controls
return -1;
}
+ /// video position in seconds, -1 if not found
public double FindDataBelowThresholdBack(double thresholdPercent, double durationInSeconds)
{
int begin = SecondsToSampleIndex(_currentVideoPositionSeconds - 1);
@@ -1946,7 +1947,7 @@ namespace Nikse.SubtitleEdit.Controls
if (hitCount > length)
{
- double seconds = SampleIndexToSeconds(i + (length / 2));
+ double seconds = SampleIndexToSeconds(i + length / 2);
if (seconds >= 0)
{
StartPositionSeconds = seconds;
@@ -1968,6 +1969,36 @@ namespace Nikse.SubtitleEdit.Controls
return -1;
}
+ ///
+ /// Seeks silence in volume
+ ///
+ /// video position in seconds, -1 if not found
+ public double FindDataBelowThresholdBackForStart(double thresholdPercent, double durationInSeconds, double startSeconds)
+ {
+ var min = SecondsToSampleIndex(startSeconds - 1);
+ var max = SecondsToSampleIndex(startSeconds + durationInSeconds + 0.05);
+ int length = SecondsToSampleIndex(durationInSeconds);
+ var threshold = thresholdPercent / 100.0 * _wavePeaks.HighestPeak;
+ int hitCount = 0;
+ for (int i = max; i > min; i--)
+ {
+ if (i > 0 && i < _wavePeaks.Peaks.Count && _wavePeaks.Peaks[i].Abs <= threshold)
+ {
+ hitCount++;
+ }
+ else
+ {
+ hitCount = 0;
+ }
+
+ if (hitCount > length)
+ {
+ return Math.Max(0, SampleIndexToSeconds(i + length) - 0.01);
+ }
+ }
+ return -1;
+ }
+
public void ZoomIn()
{
ZoomFactor += 0.1;
diff --git a/src/Forms/Main.cs b/src/Forms/Main.cs
index 16faae211..2c5ee0f9f 100644
--- a/src/Forms/Main.cs
+++ b/src/Forms/Main.cs
@@ -14245,6 +14245,11 @@ namespace Nikse.SubtitleEdit.Forms
e.SuppressKeyPress = true;
}
+ else if (audioVisualizer.SceneChanges != null && mediaPlayer.IsPaused && e.KeyData == _shortcuts.WaveformGuessStart)
+ {
+ AutoGuessStartTime(_subtitleListViewIndex);
+ e.SuppressKeyPress = true;
+ }
else if (audioVisualizer.Focused && e.KeyCode == Keys.Delete)
{
ToolStripMenuItemDeleteClick(null, null);
@@ -14602,6 +14607,76 @@ namespace Nikse.SubtitleEdit.Forms
// put new entries above tabs
}
+ private void AutoGuessStartTime(int index)
+ {
+ var silenceLengthInSeconds = 0.11;
+ var p = _subtitle.GetParagraphOrDefault(index);
+ for (var startVolume = 8.5; 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 + Configuration.Settings.General.MinimumMillisecondsBetweenLines >= newStartTimeMs)
+ {
+ newStartTimeMs = prev.EndTime.TotalMilliseconds + Configuration.Settings.General.MinimumMillisecondsBetweenLines;
+ if (newStartTimeMs >= p.StartTime.TotalMilliseconds)
+ {
+ break; // cannot move start time
+ }
+ }
+
+ // check for scene changes
+ if (audioVisualizer.SceneChanges != null)
+ {
+ var matchingSceneChanges = audioVisualizer.SceneChanges
+ .Where(sc => sc > p.StartTime.TotalSeconds - 0.3 && sc < p.StartTime.TotalSeconds + 0.2)
+ .OrderBy(sc => Math.Abs(sc - p.StartTime.TotalSeconds));
+ if (matchingSceneChanges.Count() > 0)
+ {
+ newStartTimeMs = matchingSceneChanges.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 + Configuration.Settings.General.MinimumMillisecondsBetweenLines)
+ {
+ newEndTimeMs = newStartTimeMs + p.Duration.TotalMilliseconds;
+ }
+ }
+ }
+
+ MakeHistoryForUndo(string.Format(Configuration.Settings.Language.Main.BeforeX, Configuration.Settings.Language.Settings.WaveformGuessStart));
+ 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()
{
using (var form = new BookmarksGoTo(_subtitle))
diff --git a/src/Forms/Settings.cs b/src/Forms/Settings.cs
index 3b55d9112..db8bfb9a8 100644
--- a/src/Forms/Settings.cs
+++ b/src/Forms/Settings.cs
@@ -1270,6 +1270,7 @@ namespace Nikse.SubtitleEdit.Forms
AddNode(audioVisualizerNode, language.WaveformGoToPreviousSceneChange, nameof(Configuration.Settings.Shortcuts.WaveformGoToPreviousSceneChange));
AddNode(audioVisualizerNode, language.WaveformGoToNextSceneChange, nameof(Configuration.Settings.Shortcuts.WaveformGoToNextSceneChange));
AddNode(audioVisualizerNode, language.WaveformToggleSceneChange, nameof(Configuration.Settings.Shortcuts.WaveformToggleSceneChange));
+ AddNode(audioVisualizerNode, language.WaveformGuessStart, nameof(Configuration.Settings.Shortcuts.WaveformGuessStart));
if (audioVisualizerNode.Nodes.Count > 0)
{
_shortcuts.Nodes.Add(audioVisualizerNode);
diff --git a/src/Logic/MainShortcuts.cs b/src/Logic/MainShortcuts.cs
index 8a0b25158..7d7bde778 100644
--- a/src/Logic/MainShortcuts.cs
+++ b/src/Logic/MainShortcuts.cs
@@ -132,6 +132,7 @@ namespace Nikse.SubtitleEdit.Logic
public Keys WaveformGoToPreviousSceneChange { get; set; }
public Keys WaveformGoToNextSceneChange { get; set; }
public Keys WaveformToggleSceneChange { get; set; }
+ public Keys WaveformGuessStart { get; set; }
public Keys MainTranslateGoogleIt { get; set; }
public Keys MainTranslateGoogleTranslate { get; set; }
public Keys MainTranslateCustomSearch1 { get; set; }
@@ -269,6 +270,7 @@ namespace Nikse.SubtitleEdit.Logic
WaveformGoToPreviousSceneChange = UiUtil.GetKeys(Configuration.Settings.Shortcuts.WaveformGoToPreviousSceneChange);
WaveformGoToNextSceneChange = UiUtil.GetKeys(Configuration.Settings.Shortcuts.WaveformGoToNextSceneChange);
WaveformToggleSceneChange = UiUtil.GetKeys(Configuration.Settings.Shortcuts.WaveformToggleSceneChange);
+ WaveformGuessStart = UiUtil.GetKeys(Configuration.Settings.Shortcuts.WaveformGuessStart);
MainTranslateGoogleIt = UiUtil.GetKeys(Configuration.Settings.Shortcuts.MainTranslateGoogleIt);
MainTranslateGoogleTranslate = UiUtil.GetKeys(Configuration.Settings.Shortcuts.MainTranslateGoogleTranslate);
MainTranslateCustomSearch1 = UiUtil.GetKeys(Configuration.Settings.Shortcuts.MainTranslateCustomSearch1);
diff --git a/src/UpdateLanguageFiles/Program.cs b/src/UpdateLanguageFiles/Program.cs
index ce9ddf0f6..a5d66bb86 100644
--- a/src/UpdateLanguageFiles/Program.cs
+++ b/src/UpdateLanguageFiles/Program.cs
@@ -66,7 +66,15 @@ namespace UpdateLanguageFiles
if (oldLanguageDeserializerContent != languageDeserializerContent)
{
- File.WriteAllText(args[1], languageDeserializerContent, Encoding.UTF8);
+ try
+ {
+ File.WriteAllText(args[1], languageDeserializerContent, Encoding.UTF8);
+ }
+ catch
+ {
+ System.Threading.Thread.Sleep(100);
+ File.WriteAllText(args[1], languageDeserializerContent, Encoding.UTF8);
+ }
noOfChanges++;
Console.Write(" {0} generated...", Path.GetFileName(args[1]));
}