Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/libse/Common/FixDurationLimits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private void FixShortDisplayTimes(Subtitle subtitle)
for (int i = 0; i < subtitle.Paragraphs.Count; i++)
{
var p = subtitle.Paragraphs[i];
var displayTime = p.DurationTotalMilliseconds;
var displayTime = p.Duration.TotalMilliseconds;
if (displayTime < _minDurationMs)
{
var next = subtitle.GetParagraphOrDefault(i + 1);
Expand Down Expand Up @@ -65,7 +65,7 @@ private void FixLongDisplayTimes(Subtitle subtitle)
for (int i = 0; i < subtitle.Paragraphs.Count; i++)
{
var p = subtitle.Paragraphs[i];
var displayTime = p.DurationTotalMilliseconds;
var displayTime = p.Duration.TotalMilliseconds;
if (displayTime > _maxDurationMs)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + _maxDurationMs;
Expand Down
16 changes: 7 additions & 9 deletions src/libse/Common/Paragraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Nikse.SubtitleEdit.Core.Common
{
public class Paragraph
public class Paragraph
{
public int Number { get; set; }

Expand All @@ -13,9 +13,7 @@ public class Paragraph

public TimeCode EndTime { get; set; }

public TimeCode Duration => new TimeCode(EndTime.TotalMilliseconds - StartTime.TotalMilliseconds);
public double DurationTotalMilliseconds => EndTime.TotalMilliseconds - StartTime.TotalMilliseconds;
public double DurationTotalSeconds => (EndTime.TotalMilliseconds - StartTime.TotalMilliseconds) / TimeCode.BaseUnit;
public TimeSpan Duration => TimeSpan.FromMilliseconds(EndTime.TotalMilliseconds - StartTime.TotalMilliseconds);

public bool Forced { get; set; }

Expand Down Expand Up @@ -121,28 +119,28 @@ public double WordsPerMinute
return 0;
}

return 60.0 / DurationTotalSeconds * Text.CountWords();
return 60.0 / Duration.TotalSeconds * Text.CountWords();
}
}

public double GetCharactersPerSecond()
{
if (DurationTotalMilliseconds < 1)
if (Duration.TotalMilliseconds < 1)
{
return 999;
}

return (double)Text.CountCharacters(true) / DurationTotalSeconds;
return (double)Text.CountCharacters(true) / Duration.TotalSeconds;
}

public double GetCharactersPerSecond(ICalcLength calc)
{
if (DurationTotalMilliseconds < 1)
if (Duration.TotalMilliseconds < 1)
{
return 999;
}

return (double)calc.CountCharacters(Text, true) / DurationTotalSeconds;
return (double)calc.CountCharacters(Text, true) / Duration.TotalSeconds;
}
}
}
6 changes: 3 additions & 3 deletions src/libse/Common/Subtitle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ public void RecalculateDisplayTime(double maxCharactersPerSecond, int index, dou

p.EndTime.TotalMilliseconds = wantedEndMs <= bestEndMs ? wantedEndMs : bestEndMs;

if (p.DurationTotalMilliseconds <= 0)
if (p.Duration.TotalMilliseconds <= 0)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + 1;
}
Expand Down Expand Up @@ -658,7 +658,7 @@ public void SetFixedDuration(List<int> selectedIndexes, double fixedDurationMill

p.EndTime.TotalMilliseconds = wantedEndMs <= bestEndMs ? wantedEndMs : bestEndMs;

if (p.DurationTotalMilliseconds <= 0)
if (p.Duration.TotalMilliseconds <= 0)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + 1;
}
Expand Down Expand Up @@ -857,7 +857,7 @@ public void Sort(SubtitleSortCriteria sortCriteria)
Paragraphs = Paragraphs.OrderBy(p => p.EndTime.TotalMilliseconds).ThenBy(p => p.Number).ToList();
break;
case SubtitleSortCriteria.Duration:
Paragraphs = Paragraphs.OrderBy(p => p.DurationTotalMilliseconds).ThenBy(p => p.Number).ToList();
Paragraphs = Paragraphs.OrderBy(p => p.Duration.TotalMilliseconds).ThenBy(p => p.Number).ToList();
break;
case SubtitleSortCriteria.Gap:
var lookupDictionary = new Dictionary<string, double>();
Expand Down
2 changes: 1 addition & 1 deletion src/libse/Common/TextEffect/KaraokeEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public IEnumerable<Paragraph> Transform(Paragraph paragraph, SKColor color, doub
var fontInsertIndex = CalculateColorInsertIndex(text);
text = text.Insert(fontInsertIndex, GetColor(color));
var result = _splitStrategy.Transform(text);
var duration = paragraph.DurationTotalMilliseconds - delay;
var duration = paragraph.Duration.TotalMilliseconds - delay;
var durationPerSentence = duration / result.Length;
var baseStartTime = paragraph.StartTime.TotalMilliseconds;

Expand Down
4 changes: 2 additions & 2 deletions src/libse/Common/TextSplit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,12 @@ public static Subtitle TryForWholeSentences(Subtitle inputSubtitle, string langu

public static double CalcDurationToMove(Paragraph oldCurrent, Paragraph current, Paragraph next)
{
if (current.DurationTotalMilliseconds < 0 || next.DurationTotalMilliseconds < 0)
if (current.Duration.TotalMilliseconds < 0 || next.Duration.TotalMilliseconds < 0)
{
return 0;
}

var totalDuration = current.DurationTotalMilliseconds + next.DurationTotalMilliseconds;
var totalDuration = current.Duration.TotalMilliseconds + next.Duration.TotalMilliseconds;
var totalChars = current.Text.Length + next.Text.Length;
var durChar = totalDuration / totalChars;

Expand Down
165 changes: 9 additions & 156 deletions src/libse/Common/TimeCode.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Nikse.SubtitleEdit.Core.SubtitleFormats;
using Nikse.SubtitleEdit.Core.Common.TimeFormatters;
using Nikse.SubtitleEdit.Core.SubtitleFormats;
using System;
using System.Globalization;

Expand Down Expand Up @@ -160,163 +161,15 @@ public TimeSpan TimeSpan

public override string ToString() => ToString(false);

public string ToString(bool localize)
{
var ts = TimeSpan;
var decimalSeparator = localize ? CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator : ",";
var s = $"{ts.Hours + ts.Days * 24:00}:{ts.Minutes:00}:{ts.Seconds:00}{decimalSeparator}{ts.Milliseconds:000}";

return PrefixSign(s);
}

public string ToShortString(bool localize = false)
{
var ts = TimeSpan;
var decimalSeparator = localize ? CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator : ",";
string s;
if (ts.Minutes == 0 && ts.Hours == 0 && ts.Days == 0)
{
s = $"{ts.Seconds:0}{decimalSeparator}{ts.Milliseconds:000}";

if (s == $"0{decimalSeparator}000")
{
return s; // no sign
}
}
else if (ts.Hours == 0 && ts.Days == 0)
{
s = $"{ts.Minutes:0}:{ts.Seconds:00}{decimalSeparator}{ts.Milliseconds:000}";

if (s == $"0:00{decimalSeparator}000")
{
return s; // no sign
}
}
else
{
s = $"{ts.Hours + ts.Days * 24:0}:{ts.Minutes:00}:{ts.Seconds:00}{decimalSeparator}{ts.Milliseconds:000}";

if (s == $"0:00:00{decimalSeparator}000")
{
return s; // no sign
}
}

return PrefixSign(s);
}

public string ToShortStringHHMMSSFF()
{
var s = ToHHMMSSFF();
var pre = string.Empty;
if (s.StartsWith('-'))
{
pre = "-";
s = s.TrimStart('-');
}

var j = 0;
var len = s.Length;
while (j + 6 < len && s[j] == '0' && s[j + 1] == '0' && s[j + 2] == ':')
{
j += 3;
}
s = j > 0 ? s.Substring(j) : s;
return pre + s;
}

public string ToHHMMSSFF()
{
string s;
var ts = TimeSpan;
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
{
var newTs = new TimeSpan(ts.Ticks);
newTs = newTs.Add(new TimeSpan(0, 0, 1));
s = $"{newTs.Days * 24 + newTs.Hours:00}:{newTs.Minutes:00}:{newTs.Seconds:00}:{0:00}";
}
else
{
s = $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}:{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
}

return PrefixSign(s);
}

public string ToHHMMSS()
{
string s;
var ts = TimeSpan;
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
{
var newTs = new TimeSpan(ts.Ticks);
newTs = newTs.Add(new TimeSpan(0, 0, 1));
s = $"{newTs.Days * 24 + newTs.Hours:00}:{newTs.Minutes:00}:{newTs.Seconds:00}";
}
else
{
s = $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}";
}
return PrefixSign(s);
}

public string ToHHMMSSFFDropFrame()
{
string s;
var ts = TimeSpan;
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
{
var newTs = new TimeSpan(ts.Ticks);
newTs = newTs.Add(new TimeSpan(0, 0, 1));
s = $"{newTs.Days * 24 + newTs.Hours:00}:{newTs.Minutes:00}:{newTs.Seconds:00};{0:00}";
}
else
{
s = $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00};{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
}
return PrefixSign(s);
}
public string ToString(bool localize) => TimeSpan.ToString(localize);

public string ToSSFF()
{
string s;
var ts = TimeSpan;
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
{
s = $"{ts.Seconds + 1:00}:{0:00}";
}
else
{
s = $"{ts.Seconds:00}:{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
}
public string ToShortString(bool localize = false) => TimeSpan.ToShortString(localize);

return PrefixSign(s);
}
public string ToString(ITimeFormatter formatter) => formatter.Format(TimeSpan);

public string ToHHMMSSPeriodFF()
{
string s;
var ts = TimeSpan;
var frames = Math.Round(ts.Milliseconds / (BaseUnit / Configuration.Settings.General.CurrentFrameRate));
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
{
var newTs = new TimeSpan(ts.Ticks);
newTs = newTs.Add(new TimeSpan(0, 0, 1));
s = $"{newTs.Days * 24 + newTs.Hours:00}:{newTs.Minutes:00}:{newTs.Seconds:00}.{0:00}";
}
else
{
s = $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{SubtitleFormat.MillisecondsToFramesMaxFrameRate(ts.Milliseconds):00}";
}

return PrefixSign(s);
}
internal static string PrefixSign(string time, double totalMilliseconds) => totalMilliseconds >= 0 ? time : $"-{time.RemoveChar('-')}";

private string PrefixSign(string time) => TotalMilliseconds >= 0 ? time : $"-{time.RemoveChar('-')}";
private string PrefixSign(string time) => PrefixSign(time, TotalMilliseconds);

public string ToDisplayString()
{
Expand All @@ -327,7 +180,7 @@ public string ToDisplayString()

if (Configuration.Settings?.General.UseTimeFormatHHMMSSFF == true)
{
return ToHHMMSSFF();
return ToString(TimeFormatter.HhMmSsFf);
}

return ToString(true);
Expand All @@ -342,7 +195,7 @@ public string ToShortDisplayString()

if (Configuration.Settings?.General.UseTimeFormatHHMMSSFF == true)
{
return ToShortStringHHMMSSFF();
return ToString(TimeFormatter.ShortHhMmSsFf);
}

return ToShortString(true);
Expand Down
30 changes: 30 additions & 0 deletions src/libse/Common/TimeFormatters/FrameBasedTimeFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Nikse.SubtitleEdit.Core.SubtitleFormats;
using System;

namespace Nikse.SubtitleEdit.Core.Common.TimeFormatters
{
/// <summary>
/// Base for formatters that convert milliseconds to frames using the current frame rate,
/// carrying over to the next second when the frame count rounds up to the frame rate.
/// </summary>
public abstract class FrameBasedTimeFormatter : ITimeFormatter
{
public string Format(TimeSpan timeSpan)
{
var frames = Math.Round(timeSpan.Milliseconds / (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate));
string s;
if (frames >= Configuration.Settings.General.CurrentFrameRate - 0.001)
{
s = FormatTime(timeSpan.Add(new TimeSpan(0, 0, 1)), 0);
}
else
{
s = FormatTime(timeSpan, SubtitleFormat.MillisecondsToFramesMaxFrameRate(timeSpan.Milliseconds));
}

return TimeCode.PrefixSign(s, timeSpan.TotalMilliseconds);
}

protected abstract string FormatTime(TimeSpan ts, int frames);
}
}
15 changes: 15 additions & 0 deletions src/libse/Common/TimeFormatters/HhMmSsFfDropFrameTimeFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Nikse.SubtitleEdit.Core.Common.TimeFormatters
{
/// <summary>
/// Formats as "HH:MM:SS;FF" (drop frame, semicolon before frames).
/// </summary>
public class HhMmSsFfDropFrameTimeFormatter : FrameBasedTimeFormatter
{
protected override string FormatTime(TimeSpan ts, int frames)
{
return $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00};{frames:00}";
}
}
}
15 changes: 15 additions & 0 deletions src/libse/Common/TimeFormatters/HhMmSsFfTimeFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Nikse.SubtitleEdit.Core.Common.TimeFormatters
{
/// <summary>
/// Formats as "HH:MM:SS:FF".
/// </summary>
public class HhMmSsFfTimeFormatter : FrameBasedTimeFormatter
{
protected override string FormatTime(TimeSpan ts, int frames)
{
return $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}:{frames:00}";
}
}
}
15 changes: 15 additions & 0 deletions src/libse/Common/TimeFormatters/HhMmSsPeriodFfTimeFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace Nikse.SubtitleEdit.Core.Common.TimeFormatters
{
/// <summary>
/// Formats as "HH:MM:SS.FF" (period before frames).
/// </summary>
public class HhMmSsPeriodFfTimeFormatter : FrameBasedTimeFormatter
{
protected override string FormatTime(TimeSpan ts, int frames)
{
return $"{ts.Days * 24 + ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{frames:00}";
}
}
}
Loading