Fix "seek silence" and "guess time codes".

This commit is contained in:
J.D. Purcell 2015-10-04 16:34:29 -04:00
parent c8ed603f9b
commit 898dc87665
2 changed files with 62 additions and 50 deletions

View File

@ -268,7 +268,7 @@ namespace Nikse.SubtitleEdit.Controls
{ {
get get
{ {
return XPositionToSeconds(Width); return RelativeXPositionToSeconds(Width);
} }
} }
@ -479,7 +479,7 @@ namespace Nikse.SubtitleEdit.Controls
}; };
for (int x = 0; x < Width; x++) for (int x = 0; x < Width; x++)
{ {
float pos = (float)XPositionToSeconds(x) * _wavePeaks.SampleRate; float pos = (float)RelativeXPositionToSeconds(x) * _wavePeaks.SampleRate;
int pos0 = (int)pos; int pos0 = (int)pos;
int pos1 = pos0 + 1; int pos1 = pos0 + 1;
if (pos1 >= _wavePeaks.Peaks.Count) if (pos1 >= _wavePeaks.Peaks.Count)
@ -629,7 +629,7 @@ namespace Nikse.SubtitleEdit.Controls
private void DrawTimeLine(Graphics graphics, int imageHeight) private void DrawTimeLine(Graphics graphics, int imageHeight)
{ {
double seconds = Math.Ceiling(StartPositionSeconds) - StartPositionSeconds; double seconds = Math.Ceiling(StartPositionSeconds) - StartPositionSeconds;
float position = SecondsToXPosition(seconds); int position = SecondsToXPosition(seconds);
using (var pen = new Pen(TextColor)) using (var pen = new Pen(TextColor))
using (var textBrush = new SolidBrush(TextColor)) using (var textBrush = new SolidBrush(TextColor))
using (var textFont = new Font(Font.FontFamily, 7)) using (var textFont = new Font(Font.FontFamily, 7))
@ -724,9 +724,9 @@ namespace Nikse.SubtitleEdit.Controls
} }
} }
private double XPositionToSeconds(double x) private double RelativeXPositionToSeconds(int x)
{ {
return StartPositionSeconds + (x / _wavePeaks.SampleRate) / _zoomFactor; return StartPositionSeconds + ((double)x / _wavePeaks.SampleRate) / _zoomFactor;
} }
private int SecondsToXPosition(double seconds) private int SecondsToXPosition(double seconds)
@ -734,6 +734,16 @@ namespace Nikse.SubtitleEdit.Controls
return (int)Math.Round(seconds * _wavePeaks.SampleRate * _zoomFactor); return (int)Math.Round(seconds * _wavePeaks.SampleRate * _zoomFactor);
} }
private int SecondsToSampleIndex(double seconds)
{
return (int)Math.Round(seconds * _wavePeaks.SampleRate);
}
private double SampleIndexToSeconds(int index)
{
return (double)index / _wavePeaks.SampleRate;
}
private void WaveformMouseDown(object sender, MouseEventArgs e) private void WaveformMouseDown(object sender, MouseEventArgs e)
{ {
if (_wavePeaks == null) if (_wavePeaks == null)
@ -748,7 +758,7 @@ namespace Nikse.SubtitleEdit.Controls
_buttonDownTimeTicks = DateTime.Now.Ticks; _buttonDownTimeTicks = DateTime.Now.Ticks;
Cursor = Cursors.VSplit; Cursor = Cursors.VSplit;
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
if (SetParagrapBorderHit(milliseconds, NewSelectionParagraph)) if (SetParagrapBorderHit(milliseconds, NewSelectionParagraph))
@ -816,7 +826,7 @@ namespace Nikse.SubtitleEdit.Controls
_mouseDownParagraph = p; _mouseDownParagraph = p;
oldMouseDownParagraph = new Paragraph(_mouseDownParagraph); oldMouseDownParagraph = new Paragraph(_mouseDownParagraph);
_mouseDownParagraphType = MouseDownParagraphType.Whole; _mouseDownParagraphType = MouseDownParagraphType.Whole;
_moveWholeStartDifferenceMilliseconds = (XPositionToSeconds(e.X) * TimeCode.BaseUnit) - p.StartTime.TotalMilliseconds; _moveWholeStartDifferenceMilliseconds = (RelativeXPositionToSeconds(e.X) * TimeCode.BaseUnit) - p.StartTime.TotalMilliseconds;
Cursor = Cursors.Hand; Cursor = Cursors.Hand;
SetMinAndMax(); SetMinAndMax();
} }
@ -858,13 +868,11 @@ namespace Nikse.SubtitleEdit.Controls
{ {
if (e.Button == MouseButtons.Right) if (e.Button == MouseButtons.Right)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
double currentRegionLeft = Math.Min(_mouseMoveStartX, _mouseMoveEndX); double currentRegionLeft = RelativeXPositionToSeconds(Math.Min(_mouseMoveStartX, _mouseMoveEndX));
double currentRegionRight = Math.Max(_mouseMoveStartX, _mouseMoveEndX); double currentRegionRight = RelativeXPositionToSeconds(Math.Max(_mouseMoveStartX, _mouseMoveEndX));
currentRegionLeft = XPositionToSeconds(currentRegionLeft);
currentRegionRight = XPositionToSeconds(currentRegionRight);
if (OnNewSelectionRightClicked != null && seconds > currentRegionLeft && seconds < currentRegionRight) if (OnNewSelectionRightClicked != null && seconds > currentRegionLeft && seconds < currentRegionRight)
{ {
@ -1112,7 +1120,7 @@ namespace Nikse.SubtitleEdit.Controls
if (e.Button == MouseButtons.None) if (e.Button == MouseButtons.None)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
if (IsParagrapBorderHit(milliseconds, NewSelectionParagraph)) if (IsParagrapBorderHit(milliseconds, NewSelectionParagraph))
@ -1136,7 +1144,7 @@ namespace Nikse.SubtitleEdit.Controls
{ {
if (_mouseDownParagraph != null) if (_mouseDownParagraph != null)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
var subtitleIndex = _subtitle.GetIndex(_mouseDownParagraph); var subtitleIndex = _subtitle.GetIndex(_mouseDownParagraph);
_prevParagraph = _subtitle.GetParagraphOrDefault(subtitleIndex - 1); _prevParagraph = _subtitle.GetParagraphOrDefault(subtitleIndex - 1);
@ -1278,8 +1286,8 @@ namespace Nikse.SubtitleEdit.Controls
int start = Math.Min(_mouseMoveStartX, _mouseMoveEndX); int start = Math.Min(_mouseMoveStartX, _mouseMoveEndX);
int end = Math.Max(_mouseMoveStartX, _mouseMoveEndX); int end = Math.Max(_mouseMoveStartX, _mouseMoveEndX);
var startTotalSeconds = XPositionToSeconds(start); var startTotalSeconds = RelativeXPositionToSeconds(start);
var endTotalSeconds = XPositionToSeconds(end); var endTotalSeconds = RelativeXPositionToSeconds(end);
if (PreventOverlap && endTotalSeconds * TimeCode.BaseUnit >= _wholeParagraphMaxMilliseconds) if (PreventOverlap && endTotalSeconds * TimeCode.BaseUnit >= _wholeParagraphMaxMilliseconds)
{ {
@ -1399,7 +1407,7 @@ namespace Nikse.SubtitleEdit.Controls
{ {
if (OnPause != null) if (OnPause != null)
OnPause.Invoke(sender, null); OnPause.Invoke(sender, null);
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
Paragraph p = GetParagraphAtMilliseconds(milliseconds); Paragraph p = GetParagraphAtMilliseconds(milliseconds);
@ -1441,7 +1449,7 @@ namespace Nikse.SubtitleEdit.Controls
{ {
if (ModifierKeys == Keys.Shift && _selectedParagraph != null) if (ModifierKeys == Keys.Shift && _selectedParagraph != null)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole) if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole)
{ {
@ -1458,7 +1466,7 @@ namespace Nikse.SubtitleEdit.Controls
} }
if (ModifierKeys == Keys.Control && _selectedParagraph != null) if (ModifierKeys == Keys.Control && _selectedParagraph != null)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole) if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole)
{ {
@ -1475,7 +1483,7 @@ namespace Nikse.SubtitleEdit.Controls
} }
if (ModifierKeys == (Keys.Control | Keys.Shift) && _selectedParagraph != null) if (ModifierKeys == (Keys.Control | Keys.Shift) && _selectedParagraph != null)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole) if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole)
{ {
_oldParagraph = new Paragraph(_selectedParagraph); _oldParagraph = new Paragraph(_selectedParagraph);
@ -1487,7 +1495,7 @@ namespace Nikse.SubtitleEdit.Controls
} }
if (ModifierKeys == Keys.Alt && _selectedParagraph != null) if (ModifierKeys == Keys.Alt && _selectedParagraph != null)
{ {
double seconds = XPositionToSeconds(e.X); double seconds = RelativeXPositionToSeconds(e.X);
var milliseconds = (int)(seconds * TimeCode.BaseUnit); var milliseconds = (int)(seconds * TimeCode.BaseUnit);
if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole) if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole)
{ {
@ -1503,7 +1511,7 @@ namespace Nikse.SubtitleEdit.Controls
} }
if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole) if (_mouseDownParagraphType == MouseDownParagraphType.None || _mouseDownParagraphType == MouseDownParagraphType.Whole)
OnSingleClick.Invoke(this, new ParagraphEventArgs(XPositionToSeconds(e.X), null)); OnSingleClick.Invoke(this, new ParagraphEventArgs(RelativeXPositionToSeconds(e.X), null));
} }
} }
} }
@ -1563,10 +1571,11 @@ namespace Nikse.SubtitleEdit.Controls
} }
} }
public double FindDataBelowThreshold(int threshold, double durationInSeconds) public double FindDataBelowThreshold(int thresholdPercent, double durationInSeconds)
{ {
int begin = SecondsToXPosition(_currentVideoPositionSeconds + 1); int begin = SecondsToSampleIndex(_currentVideoPositionSeconds + 1);
int length = SecondsToXPosition(durationInSeconds); int length = SecondsToSampleIndex(durationInSeconds);
int threshold = (int)(thresholdPercent / 100.0 * _wavePeaks.HighestPeak);
int hitCount = 0; int hitCount = 0;
for (int i = begin; i < _wavePeaks.Peaks.Count; i++) for (int i = begin; i < _wavePeaks.Peaks.Count; i++)
@ -1577,7 +1586,7 @@ namespace Nikse.SubtitleEdit.Controls
hitCount = 0; hitCount = 0;
if (hitCount > length) if (hitCount > length)
{ {
double seconds = ((i - (length / 2)) / (double)_wavePeaks.SampleRate) / _zoomFactor; double seconds = SampleIndexToSeconds(i - (length / 2));
if (seconds >= 0) if (seconds >= 0)
{ {
StartPositionSeconds = seconds; StartPositionSeconds = seconds;
@ -1592,10 +1601,11 @@ namespace Nikse.SubtitleEdit.Controls
return -1; return -1;
} }
public double FindDataBelowThresholdBack(int threshold, double durationInSeconds) public double FindDataBelowThresholdBack(int thresholdPercent, double durationInSeconds)
{ {
int begin = SecondsToXPosition(_currentVideoPositionSeconds - 1); int begin = SecondsToSampleIndex(_currentVideoPositionSeconds - 1);
int length = SecondsToXPosition(durationInSeconds); int length = SecondsToSampleIndex(durationInSeconds);
int threshold = (int)(thresholdPercent / 100.0 * _wavePeaks.HighestPeak);
int hitCount = 0; int hitCount = 0;
for (int i = begin; i > 0; i--) for (int i = begin; i > 0; i--)
@ -1606,7 +1616,7 @@ namespace Nikse.SubtitleEdit.Controls
hitCount = 0; hitCount = 0;
if (hitCount > length) if (hitCount > length)
{ {
double seconds = (i + (length / 2)) / (double)_wavePeaks.SampleRate / _zoomFactor; double seconds = SampleIndexToSeconds(i + (length / 2));
if (seconds >= 0) if (seconds >= 0)
{ {
StartPositionSeconds = seconds; StartPositionSeconds = seconds;
@ -1755,7 +1765,7 @@ namespace Nikse.SubtitleEdit.Controls
private double GetAverageVolumeForNextMilliseconds(int sampleIndex, int milliseconds) private double GetAverageVolumeForNextMilliseconds(int sampleIndex, int milliseconds)
{ {
int length = SecondsToXPosition(milliseconds / TimeCode.BaseUnit); int length = SecondsToSampleIndex(milliseconds / TimeCode.BaseUnit);
if (length < 9) if (length < 9)
length = 9; length = 9;
double v = 0; double v = 0;
@ -1773,31 +1783,31 @@ namespace Nikse.SubtitleEdit.Controls
return v / count; return v / count;
} }
internal void GenerateTimeCodes(double startFromSeconds, int minimumVolumePercent, int maximumVolumePercent, int defaultMilliseconds) internal void GenerateTimeCodes(Subtitle subtitle, double startFromSeconds, int blockSizeMilliseconds, int minimumVolumePercent, int maximumVolumePercent, int defaultMilliseconds)
{ {
int begin = SecondsToXPosition(startFromSeconds); int begin = SecondsToSampleIndex(startFromSeconds);
double average = 0; double average = 0;
for (int k = begin; k < _wavePeaks.Peaks.Count; k++) for (int k = begin; k < _wavePeaks.Peaks.Count; k++)
average += _wavePeaks.Peaks[k].Abs; average += _wavePeaks.Peaks[k].Abs;
average = average / (_wavePeaks.Peaks.Count - begin); average /= _wavePeaks.Peaks.Count - begin;
var maxThreshold = (int)(_wavePeaks.HighestPeak * (maximumVolumePercent / 100.0)); var maxThreshold = (int)(_wavePeaks.HighestPeak * (maximumVolumePercent / 100.0));
var silenceThreshold = (int)(average * (minimumVolumePercent / 100.0)); var silenceThreshold = (int)(average * (minimumVolumePercent / 100.0));
int length50Ms = SecondsToXPosition(0.050); int length50Ms = SecondsToSampleIndex(0.050);
double secondsPerParagraph = defaultMilliseconds / TimeCode.BaseUnit; double secondsPerParagraph = defaultMilliseconds / TimeCode.BaseUnit;
int minBetween = SecondsToXPosition(Configuration.Settings.General.MinimumMillisecondsBetweenLines / TimeCode.BaseUnit); int minBetween = SecondsToSampleIndex(Configuration.Settings.General.MinimumMillisecondsBetweenLines / TimeCode.BaseUnit);
bool subtitleOn = false; bool subtitleOn = false;
int i = begin; int i = begin;
while (i < _wavePeaks.Peaks.Count) while (i < _wavePeaks.Peaks.Count)
{ {
if (subtitleOn) if (subtitleOn)
{ {
var currentLengthInSeconds = XPositionToSeconds(i - begin) - StartPositionSeconds; var currentLengthInSeconds = SampleIndexToSeconds(i - begin);
if (currentLengthInSeconds > 1.0) if (currentLengthInSeconds > 1.0)
{ {
subtitleOn = EndParagraphDueToLowVolume(silenceThreshold, begin, true, i); subtitleOn = EndParagraphDueToLowVolume(subtitle, blockSizeMilliseconds, silenceThreshold, begin, true, i);
if (!subtitleOn) if (!subtitleOn)
{ {
begin = i + minBetween; begin = i + minBetween;
@ -1808,7 +1818,7 @@ namespace Nikse.SubtitleEdit.Controls
{ {
for (int j = 0; j < 20; j++) for (int j = 0; j < 20; j++)
{ {
subtitleOn = EndParagraphDueToLowVolume(silenceThreshold, begin, true, i + (j * length50Ms)); subtitleOn = EndParagraphDueToLowVolume(subtitle, blockSizeMilliseconds, silenceThreshold, begin, true, i + (j * length50Ms));
if (!subtitleOn) if (!subtitleOn)
{ {
i += (j * length50Ms); i += (j * length50Ms);
@ -1820,8 +1830,8 @@ namespace Nikse.SubtitleEdit.Controls
if (subtitleOn) // force break if (subtitleOn) // force break
{ {
var p = new Paragraph(string.Empty, (XPositionToSeconds(begin) - StartPositionSeconds) * TimeCode.BaseUnit, (XPositionToSeconds(i) - StartPositionSeconds) * TimeCode.BaseUnit); var p = new Paragraph(string.Empty, SampleIndexToSeconds(begin) * TimeCode.BaseUnit, SampleIndexToSeconds(i) * TimeCode.BaseUnit);
_subtitle.Paragraphs.Add(p); subtitle.Paragraphs.Add(p);
begin = i + minBetween; begin = i + minBetween;
i = begin; i = begin;
} }
@ -1829,7 +1839,7 @@ namespace Nikse.SubtitleEdit.Controls
} }
else else
{ {
double avgVol = GetAverageVolumeForNextMilliseconds(i, 100); double avgVol = GetAverageVolumeForNextMilliseconds(i, blockSizeMilliseconds);
if (avgVol > silenceThreshold) if (avgVol > silenceThreshold)
{ {
if (avgVol < maxThreshold) if (avgVol < maxThreshold)
@ -1841,15 +1851,17 @@ namespace Nikse.SubtitleEdit.Controls
} }
i++; i++;
} }
subtitle.Renumber();
} }
private bool EndParagraphDueToLowVolume(double silenceThreshold, int begin, bool subtitleOn, int i) private bool EndParagraphDueToLowVolume(Subtitle subtitle, int blockSizeMilliseconds, double silenceThreshold, int begin, bool subtitleOn, int i)
{ {
double avgVol = GetAverageVolumeForNextMilliseconds(i, 100); double avgVol = GetAverageVolumeForNextMilliseconds(i, blockSizeMilliseconds);
if (avgVol < silenceThreshold) if (avgVol < silenceThreshold)
{ {
var p = new Paragraph(string.Empty, (XPositionToSeconds(begin) - StartPositionSeconds) * TimeCode.BaseUnit, (XPositionToSeconds(i) - StartPositionSeconds) * TimeCode.BaseUnit); var p = new Paragraph(string.Empty, SampleIndexToSeconds(begin) * TimeCode.BaseUnit, SampleIndexToSeconds(i) * TimeCode.BaseUnit);
_subtitle.Paragraphs.Add(p); subtitle.Paragraphs.Add(p);
subtitleOn = false; subtitleOn = false;
} }
return subtitleOn; return subtitleOn;

View File

@ -18438,9 +18438,9 @@ namespace Nikse.SubtitleEdit.Forms
{ {
MakeHistoryForUndoOnlyIfNotResent(string.Format(_language.BeforeGuessingTimeCodes)); MakeHistoryForUndoOnlyIfNotResent(string.Format(_language.BeforeGuessingTimeCodes));
double startFrom = 0; double startFromSeconds = 0;
if (form.StartFromVideoPosition) if (form.StartFromVideoPosition)
startFrom = mediaPlayer.CurrentPosition; startFromSeconds = mediaPlayer.CurrentPosition;
if (form.DeleteAll) if (form.DeleteAll)
{ {
@ -18450,11 +18450,11 @@ namespace Nikse.SubtitleEdit.Forms
{ {
for (int i = _subtitle.Paragraphs.Count - 1; i > 0; i--) for (int i = _subtitle.Paragraphs.Count - 1; i > 0; i--)
{ {
if (_subtitle.Paragraphs[i].EndTime.TotalSeconds + 1 > startFrom) if (_subtitle.Paragraphs[i].EndTime.TotalSeconds + 1 > startFromSeconds)
_subtitle.Paragraphs.RemoveAt(i); _subtitle.Paragraphs.RemoveAt(i);
} }
} }
audioVisualizer.GenerateTimeCodes(form.BlockSize, form.VolumeMinimum, form.VolumeMaximum, form.DefaultMilliseconds); audioVisualizer.GenerateTimeCodes(_subtitle, startFromSeconds, form.BlockSize, form.VolumeMinimum, form.VolumeMaximum, form.DefaultMilliseconds);
if (IsFramesRelevant && CurrentFrameRate > 0) if (IsFramesRelevant && CurrentFrameRate > 0)
_subtitle.CalculateFrameNumbersFromTimeCodesNoCheck(CurrentFrameRate); _subtitle.CalculateFrameNumbersFromTimeCodesNoCheck(CurrentFrameRate);
SubtitleListview1.Fill(_subtitle, _subtitleAlternate); SubtitleListview1.Fill(_subtitle, _subtitleAlternate);