Implement adjusting functions

This commit is contained in:
Martijn van Berkel (Flitskikker) 2023-05-20 23:32:10 +02:00
parent 198954b175
commit db6b8af630
6 changed files with 121 additions and 35 deletions

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
namespace Nikse.SubtitleEdit.Core.Common
@ -72,5 +73,15 @@ namespace Nikse.SubtitleEdit.Core.Common
File.Delete(shotChangesFileName);
}
}
// Util functions
public static double GetNextShotChangeMinusGapInMs(List<double> shotChanges, TimeCode currentTime)
{
var nextShotChangeInSeconds = shotChanges.Concat(new[] { double.MaxValue }).First(x => x >= currentTime.TotalSeconds); // will return maxValue if empty
var outCueGapInMs = (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate) * Configuration.Settings.BeautifyTimeCodes.Profile.OutCuesGap;
return (nextShotChangeInSeconds * 1000) - outCueGapInMs;
}
}
}

View File

@ -393,7 +393,7 @@ namespace Nikse.SubtitleEdit.Core.Common
}
}
public void AdjustDisplayTimeUsingPercent(double percent, List<int> selectedIndexes)
public void AdjustDisplayTimeUsingPercent(double percent, List<int> selectedIndexes, List<double> shotChanges = null)
{
for (int i = 0; i < Paragraphs.Count; i++)
{
@ -412,6 +412,15 @@ namespace Nikse.SubtitleEdit.Core.Common
newEndMilliseconds = nextStartMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
}
if (shotChanges != null)
{
double nextShotChangeMilliseconds = ShotChangeHelper.GetNextShotChangeMinusGapInMs(shotChanges, Paragraphs[i].EndTime);
if (newEndMilliseconds > nextShotChangeMilliseconds)
{
newEndMilliseconds = nextShotChangeMilliseconds;
}
}
if (percent > 100 && newEndMilliseconds > Paragraphs[i].EndTime.TotalMilliseconds || percent < 100)
{
Paragraphs[i].EndTime.TotalMilliseconds = newEndMilliseconds;
@ -420,7 +429,7 @@ namespace Nikse.SubtitleEdit.Core.Common
}
}
public void AdjustDisplayTimeUsingSeconds(double seconds, List<int> selectedIndexes)
public void AdjustDisplayTimeUsingSeconds(double seconds, List<int> selectedIndexes, List<double> shotChanges = null)
{
if (Math.Abs(seconds) < 0.001)
{
@ -432,19 +441,19 @@ namespace Nikse.SubtitleEdit.Core.Common
{
foreach (var idx in selectedIndexes)
{
AdjustDisplayTimeUsingMilliseconds(idx, adjustMs);
AdjustDisplayTimeUsingMilliseconds(idx, adjustMs, shotChanges);
}
}
else
{
for (int idx = 0; idx < Paragraphs.Count; idx++)
{
AdjustDisplayTimeUsingMilliseconds(idx, adjustMs);
AdjustDisplayTimeUsingMilliseconds(idx, adjustMs, shotChanges);
}
}
}
private void AdjustDisplayTimeUsingMilliseconds(int idx, double ms)
private void AdjustDisplayTimeUsingMilliseconds(int idx, double ms, List<double> shotChanges = null)
{
var p = Paragraphs[idx];
var nextStartTimeInMs = double.MaxValue;
@ -467,6 +476,12 @@ namespace Nikse.SubtitleEdit.Core.Common
newEndTimeInMs = nextStartTimeInMs - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
}
// handle shot change if supplied -- keep earliest time
if (shotChanges != null)
{
newEndTimeInMs = Math.Min(newEndTimeInMs, ShotChangeHelper.GetNextShotChangeMinusGapInMs(shotChanges, p.EndTime));
}
// max duration
var dur = newEndTimeInMs - p.StartTime.TotalMilliseconds;
if (dur > Configuration.Settings.General.SubtitleMaximumDisplayMilliseconds)
@ -482,25 +497,25 @@ namespace Nikse.SubtitleEdit.Core.Common
p.EndTime.TotalMilliseconds = newEndTimeInMs;
}
public void RecalculateDisplayTimes(double maxCharPerSec, List<int> selectedIndexes, double optimalCharPerSec, bool extendOnly = false)
public void RecalculateDisplayTimes(double maxCharPerSec, List<int> selectedIndexes, double optimalCharPerSec, bool extendOnly = false, List<double> shotChanges = null)
{
if (selectedIndexes != null)
{
foreach (var index in selectedIndexes)
{
RecalculateDisplayTime(maxCharPerSec, index, optimalCharPerSec, extendOnly);
RecalculateDisplayTime(maxCharPerSec, index, optimalCharPerSec, extendOnly, false, shotChanges);
}
}
else
{
for (int i = 0; i < Paragraphs.Count; i++)
{
RecalculateDisplayTime(maxCharPerSec, i, optimalCharPerSec, extendOnly);
RecalculateDisplayTime(maxCharPerSec, i, optimalCharPerSec, extendOnly, false, shotChanges);
}
}
}
public void RecalculateDisplayTime(double maxCharactersPerSecond, int index, double optimalCharactersPerSeconds, bool extendOnly = false, bool onlyOptimal = false)
public void RecalculateDisplayTime(double maxCharactersPerSecond, int index, double optimalCharactersPerSeconds, bool extendOnly = false, bool onlyOptimal = false, List<double> shotChanges = null)
{
var p = GetParagraphOrDefault(index);
if (p == null)
@ -524,17 +539,30 @@ namespace Nikse.SubtitleEdit.Core.Common
}
var next = GetParagraphOrDefault(index + 1);
if (next != null && p.StartTime.TotalMilliseconds + duration + Configuration.Settings.General.MinimumMillisecondsBetweenLines > next.StartTime.TotalMilliseconds)
var wantedEndMs = p.EndTime.TotalMilliseconds;
var bestEndMs = double.MaxValue;
// First check for next subtitle
if (next != null)
{
p.EndTime.TotalMilliseconds = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
if (p.Duration.TotalMilliseconds <= 0)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + 1;
}
bestEndMs = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
}
// Then check for next shot change (if option is checked, and if any are supplied) -- keeping earliest time
if (shotChanges != null)
{
bestEndMs = Math.Min(bestEndMs, ShotChangeHelper.GetNextShotChangeMinusGapInMs(shotChanges, new TimeCode(originalEndTime)));
}
p.EndTime.TotalMilliseconds = wantedEndMs <= bestEndMs ? wantedEndMs : bestEndMs;
if (p.Duration.TotalMilliseconds <= 0)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + 1;
}
}
public void SetFixedDuration(List<int> selectedIndexes, double fixedDurationMilliseconds)
public void SetFixedDuration(List<int> selectedIndexes, double fixedDurationMilliseconds, List<double> shotChanges = null)
{
for (int i = 0; i < Paragraphs.Count; i++)
{
@ -546,16 +574,27 @@ namespace Nikse.SubtitleEdit.Core.Common
continue;
}
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + fixedDurationMilliseconds;
var next = GetParagraphOrDefault(i + 1);
if (next != null && p.StartTime.TotalMilliseconds + fixedDurationMilliseconds + Configuration.Settings.General.MinimumMillisecondsBetweenLines > next.StartTime.TotalMilliseconds)
var wantedEndMs = p.StartTime.TotalMilliseconds + fixedDurationMilliseconds;
var bestEndMs = double.MaxValue;
// First check for next subtitle
if (next != null)
{
p.EndTime.TotalMilliseconds = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
if (p.Duration.TotalMilliseconds <= 0)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + 1;
}
bestEndMs = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
}
// Then check for next shot change (if option is checked, and if any are supplied) -- keeping earliest time
if (shotChanges != null)
{
bestEndMs = Math.Min(bestEndMs, ShotChangeHelper.GetNextShotChangeMinusGapInMs(shotChanges, p.EndTime));
}
p.EndTime.TotalMilliseconds = wantedEndMs <= bestEndMs ? wantedEndMs : bestEndMs;
if (p.Duration.TotalMilliseconds <= 0)
{
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + 1;
}
}
}

View File

@ -308,6 +308,7 @@
this.checkBoxCheckShotChanges.TabIndex = 111;
this.checkBoxCheckShotChanges.Text = "Check shot changes";
this.checkBoxCheckShotChanges.UseVisualStyleBackColor = true;
this.checkBoxCheckShotChanges.CheckedChanged += new System.EventHandler(this.checkBoxCheckShotChanges_CheckedChanged);
//
// ApplyDurationLimits
//

View File

@ -1,7 +1,9 @@
using Nikse.SubtitleEdit.Core.Common;
using Nikse.SubtitleEdit.Logic;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace Nikse.SubtitleEdit.Forms
@ -16,6 +18,7 @@ namespace Nikse.SubtitleEdit.Forms
private readonly Timer _refreshTimer = new Timer();
private readonly Color _warningColor = Color.FromArgb(255, 253, 145);
private Subtitle _unfixables = new Subtitle();
private List<double> _shotChanges = new List<double>();
public ApplyDurationLimits()
{
@ -74,9 +77,20 @@ namespace Nikse.SubtitleEdit.Forms
UiUtil.FixLargeFonts(this, buttonOK);
}
public void Initialize(Subtitle subtitle)
public void Initialize(Subtitle subtitle, List<double> shotChanges = null)
{
_subtitle = subtitle;
if (shotChanges != null)
{
_shotChanges = shotChanges;
checkBoxCheckShotChanges.Enabled = true;
}
else
{
checkBoxCheckShotChanges.Enabled = false;
}
GeneratePreview();
}
@ -154,16 +168,29 @@ namespace Nikse.SubtitleEdit.Forms
{
var next = _working.GetParagraphOrDefault(i + 1);
var wantedEndMs = p.StartTime.TotalMilliseconds + minDisplayTime;
if (next == null || wantedEndMs < next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines)
var bestEndMs = double.MaxValue;
// First check for next subtitle
if (next != null)
{
bestEndMs = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
}
// Then check for next shot change (if option is checked, and if any are supplied) -- keeping earliest time
if (checkBoxCheckShotChanges.Checked && _shotChanges.Count > 0)
{
bestEndMs = Math.Min(bestEndMs, ShotChangeHelper.GetNextShotChangeMinusGapInMs(_shotChanges, p.EndTime));
}
if (wantedEndMs <= bestEndMs)
{
AddFix(p, wantedEndMs, DefaultBackColor);
}
else
{
var nextBestEndMs = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MinimumMillisecondsBetweenLines;
if (nextBestEndMs > p.EndTime.TotalMilliseconds)
if (bestEndMs > p.EndTime.TotalMilliseconds)
{
AddFix(p, nextBestEndMs, _warningColor);
AddFix(p, bestEndMs, _warningColor);
_unfixables.Paragraphs.Add(new Paragraph(p) { Extra = "Warning" });
}
else
@ -327,5 +354,10 @@ namespace Nikse.SubtitleEdit.Forms
item.Checked = !item.Checked;
}
}
private void checkBoxCheckShotChanges_CheckedChanged(object sender, EventArgs e)
{
GeneratePreview();
}
}
}

View File

@ -1943,6 +1943,7 @@ namespace Nikse.SubtitleEdit.Forms
if (IsActionEnabled(CommandLineConverter.BatchAction.AdjustDisplayDuration))
{
// TODO shot changes
var adjustmentType = comboBoxAdjustDurationVia.Text;
if (adjustmentType == LanguageSettings.Current.AdjustDisplayDuration.Percent)
{

View File

@ -7470,27 +7470,29 @@ namespace Nikse.SubtitleEdit.Forms
if (adjustDisplayTime.ShowDialog(this) == DialogResult.OK)
{
MakeHistoryForUndo(_language.BeforeDisplayTimeAdjustment);
List<double> shotChanges = adjustDisplayTime.CheckShotChanges ? audioVisualizer.ShotChanges : new List<double>();
if (adjustDisplayTime.AdjustUsingPercent)
{
double percent = double.Parse(adjustDisplayTime.AdjustValue);
_subtitle.AdjustDisplayTimeUsingPercent(percent, selectedIndices);
_subtitle.AdjustDisplayTimeUsingPercent(percent, selectedIndices, shotChanges);
ShowStatus(string.Format(_language.DisplayTimesAdjustedX, double.Parse(adjustDisplayTime.AdjustValue, CultureInfo.InvariantCulture) + "%"));
}
else if (adjustDisplayTime.AdjustUsingSeconds)
{
double seconds = double.Parse(adjustDisplayTime.AdjustValue, CultureInfo.InvariantCulture);
_subtitle.AdjustDisplayTimeUsingSeconds(seconds, selectedIndices);
_subtitle.AdjustDisplayTimeUsingSeconds(seconds, selectedIndices, shotChanges);
ShowStatus(string.Format(_language.DisplayTimesAdjustedX, double.Parse(adjustDisplayTime.AdjustValue, CultureInfo.InvariantCulture)));
}
else if (adjustDisplayTime.AdjustUsingRecalc)
{
double maxCharSeconds = (double)(adjustDisplayTime.MaxCharactersPerSecond);
_subtitle.RecalculateDisplayTimes(maxCharSeconds, selectedIndices, (double)adjustDisplayTime.OptimalCharactersPerSecond, adjustDisplayTime.ExtendOnly);
_subtitle.RecalculateDisplayTimes(maxCharSeconds, selectedIndices, (double)adjustDisplayTime.OptimalCharactersPerSecond, adjustDisplayTime.ExtendOnly, shotChanges);
ShowStatus(string.Format(_language.DisplayTimesAdjustedX, adjustDisplayTime.AdjustValue));
}
else
{ // fixed duration
_subtitle.SetFixedDuration(selectedIndices, adjustDisplayTime.FixedMilliseconds);
_subtitle.SetFixedDuration(selectedIndices, adjustDisplayTime.FixedMilliseconds, shotChanges);
ShowStatus(string.Format(_language.DisplayTimesAdjustedX, adjustDisplayTime.FixedMilliseconds));
}
@ -30305,11 +30307,11 @@ namespace Nikse.SubtitleEdit.Forms
selectedLines.Paragraphs.Add(_subtitle.Paragraphs[index]);
}
applyDurationLimits.Initialize(selectedLines);
applyDurationLimits.Initialize(selectedLines, audioVisualizer.ShotChanges);
}
else
{
applyDurationLimits.Initialize(_subtitle);
applyDurationLimits.Initialize(_subtitle, audioVisualizer.ShotChanges);
}
if (applyDurationLimits.ShowDialog(this) == DialogResult.OK)