Add visual waveform split lanes for ASS/SSA metadata#10706
Add visual waveform split lanes for ASS/SSA metadata#10706Ironship wants to merge 5 commits intoSubtitleEdit:mainfrom
Conversation
686d428 to
3807eee
Compare
3807eee to
e299e97
Compare
There was a problem hiding this comment.
Pull request overview
Adds experimental multi-track subtitle editing for ASS/SSA by introducing track state into the core subtitle model and updating waveform editing + multiple tools/validators to operate on same-track neighbors only.
Changes:
- Introduces
TrackIndexin the subtitle model (Paragraph) and propagates it through UI view models and conversion paths. - Updates “neighbor-aware” operations (Fix Common Errors, bridge gaps, merge tools, duration tools, batch checks) to use previous/next paragraphs on the same track.
- Adds waveform multi-row rendering and a track header UI, plus regression tests for same-track behavior.
Reviewed changes
Copilot reviewed 44 out of 44 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/libse/Forms/FixCommonErrorsTrackTests.cs | Regression: FixShortGaps shouldn’t adjust across tracks. |
| tests/libse/Core/MergeShortLinesUtilsTest.cs | Regression: merge-short-lines should not merge across tracks. |
| tests/UI/Logic/SplitManagerTests.cs | Regression: split preserves TrackIndex. |
| tests/UI/Logic/InsertServiceTests.cs | Regression: insert-after inherits TrackIndex and ignores next different-track neighbor. |
| tests/UI/Logic/DurationsBridgeGaps2Tests.cs | Regression: bridge gaps uses same-track neighbor and doesn’t bridge across tracks. |
| tests/UI/Features/Tools/MergeShortLines/MergeShortLinesHelperTests.cs | Regression: UI merge helper doesn’t merge across tracks. |
| tests/UI/Features/Tools/AdjustDuration/AdjustDurationViewModelTests.cs | Regression: duration cap uses next subtitle on same track. |
| src/libse/Forms/FixCommonErrors/Helper.cs | Fix Common Errors: previous paragraph checks now same-track. |
| src/libse/Forms/FixCommonErrors/FixUnnecessaryLeadingDots.cs | Fix Common Errors: previous paragraph now same-track with null handling. |
| src/libse/Forms/FixCommonErrors/FixStartWithUppercaseLetterAfterParagraph.cs | Fix Common Errors: previous paragraph now same-track. |
| src/libse/Forms/FixCommonErrors/FixSpanishInvertedQuestionAndExclamationMarks.cs | Fix Common Errors: previous/next now same-track. |
| src/libse/Forms/FixCommonErrors/FixShortGaps.cs | Fix Common Errors: next paragraph now same-track with null handling. |
| src/libse/Forms/FixCommonErrors/FixShortDisplayTimes.cs | Fix Common Errors: prev/next/next-next now same-track. |
| src/libse/Forms/FixCommonErrors/FixOverlappingDisplayTimes.cs | Fix Common Errors: prev/next now same-track with null handling. |
| src/libse/Forms/FixCommonErrors/FixMissingPeriodsAtEndOfLine.cs | Fix Common Errors: next paragraph now same-track. |
| src/libse/Forms/FixCommonErrors/FixHyphensInDialog.cs | Fix Common Errors: previous paragraph now same-track. |
| src/libse/Forms/FixCommonErrors/FixContinuationStyle.cs | Fix Common Errors: next paragraph now same-track with null handling. |
| src/libse/Forms/FixCommonErrors/AddMissingQuotes.cs | Fix Common Errors: prev/next neighbors now same-track (incl. lookahead). |
| src/libse/Forms/DurationsBridgeGaps.cs | Bridge gaps: uses next subtitle on same track. |
| src/libse/Common/Utilities.cs | Utility display-time fix: next paragraph now same-track. |
| src/libse/Common/TextSplit.cs | Sentence splitting: next paragraph now same-track. |
| src/libse/Common/SubtitleTrack.cs | New model type for UI track metadata (name/color/index). |
| src/libse/Common/Subtitle.cs | Adds same-track neighbor helpers and uses them in duration adjustment paths. |
| src/libse/Common/Paragraph.cs | Adds TrackIndex and ensures copy ctor preserves it. |
| src/libse/Common/MergeShortLinesUtils.cs | Core merge-short-lines: require same TrackIndex to merge. |
| src/libse/Common/MergeLinesSameTextUtils.cs | Core merge-same-text: require same TrackIndex to merge. |
| src/libse/Common/FixDurationLimits.cs | Duration limits: next paragraph now same-track. |
| src/UI/Logic/NetflixQualityCheck/NetflixCheckDialogHyphenSpace.cs | Netflix QC: previous paragraph now same-track. |
| src/UI/Logic/Media/MpvReloader.cs | Ensures mpv refresh updates paused frame after reload. |
| src/UI/Logic/InsertService.cs | Insert logic: same-track prev/next + inherit TrackIndex for new subtitles. |
| src/UI/Logic/DurationsBridgeGaps2.cs | UI bridge gaps: uses next subtitle on same track. |
| src/UI/Logic/Config/Language/Waveform/LanguageWaveform.cs | Adds UI strings for track controls. |
| src/UI/Features/Tools/MergeSubtitlesWithSameText/MergeSameTextViewModel.cs | Preview merge-same-text now preserves and checks TrackIndex. |
| src/UI/Features/Tools/MergeShortLines/MergeShortLinesHelper.cs | UI merge-short-lines: stop merge group when track changes. |
| src/UI/Features/Tools/BatchConvert/BatchErrorList/BatchErrorListViewModel.cs | Batch error prev/next context now same-track. |
| src/UI/Features/Tools/BatchConvert/BatchConverter.cs | Same-timecode merging: avoid cross-track merges. |
| src/UI/Features/Tools/ApplyDurationLimits/ApplyDurationLimitsViewModel.cs | Apply duration limits: next subtitle now same-track. |
| src/UI/Features/Tools/AdjustDuration/AdjustDurationViewModel.cs | Adjust duration: next subtitle now same-track. |
| src/UI/Features/Main/SubtitleLineViewModel.cs | Adds TrackIndex and round-trips it to/from Paragraph. |
| src/UI/Features/Main/MainViewModel.cs | Adds track state, injects per-track ASS styles, track-aware paste/errors/insert/seek behavior. |
| src/UI/Features/Main/Layout/InitWaveform.cs | Adds track header panel + “Add Track” UI and wires active-track syncing. |
| src/UI/Controls/VideoPlayer/VideoPlayerControl.cs | Adds explicit seeking API (SetPosition) and property update tweaks. |
| src/UI/Controls/TrackHeaderControl/TrackHeaderPanel.cs | New control: renders track list and supports selecting/renaming tracks. |
| src/UI/Controls/AudioVisualizerControl/AudioVisualizer.cs | Multi-row rendering, hit testing, resizing/moving restricted to selected track; supports cross-track drag. |
|
I'm not really sure ASSA/SSA makes sense for multi-track - the mostly have 1 or like 20+ styles/actors. (sorry, renamed the "UI" folder to "ui") |
7e0db6d to
23e2848
Compare
|
@niksedk Good point. I had also been considering a smaller visual-only variant with fake tracks in parallel, and this was the kind of feedback I needed to decide which direction made more sense. I have replaced this PR with that second prototype: Now the subtitle model is unchanged, and ASS/SSA is split only visually in the waveform by existing metadata (actor, style, layer, or ASS position/alignment). Dragging/resizing still edits timing only; moving between virtual lanes is not a metadata-editing operation, so actor/style/layer/position should still be edited in the normal text/style UI as it was dane before :) The previous larger TrackIndex-based prototype is preserved in my fork as New / simplier version adds simple splitting view
This should make multi actors editing much easier. At least in my cases where I have 1 to 6 actors. I had lots of trouble when i had to add notes on top of video, and two actors were trying to speak at once. Posibility to change view improves readability. |
There was a problem hiding this comment.
Pull request overview
Introduces a visual-only “waveform split lanes” mode for ASS/SSA-style metadata so subtitle blocks can be displayed in separate lanes without changing the underlying subtitle model/data.
Changes:
- Adds a new waveform toolbar “Split” menu with multiple split modes (None/Actor/Style/Layer/ASS position+alignment).
- Adds
WaveformSplitModeand wires it intoAudioVisualizerrendering and hit-testing. - Updates movement/resizing constraints to consider only neighboring subtitles within the same visual lane.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/ui/Features/Main/Layout/InitWaveform.cs | Adds a Split menu button and menu items to control the visual lane split mode. |
| src/ui/Controls/AudioVisualizerControl/WaveformSplitMode.cs | Introduces the enum backing the split modes. |
| src/ui/Controls/AudioVisualizerControl/AudioVisualizer.cs | Implements lane mapping, lane-aware rendering, hit-testing, and neighbor constraints based on selected split mode. |
Comments suppressed due to low confidence (1)
src/ui/Controls/AudioVisualizerControl/AudioVisualizer.cs:1674
- When
WaveformSplitModeis enabled, existing paragraphs are rendered inside lane bounds, butDrawNewParagraphis still invoked and (currently) draws the new selection across the full height. This makes the “new selection” visual inconsistent with the lane split and can overlap multiple lanes. Consider making the new-selection rendering lane-aware (e.g., use the clicked lane or a computed lane forNewSelectionParagraph) or suppress lane dividers/labels while creating a new selection.
DrawSpectrogram(context, ref renderCtx);
DrawTimeLine(context, ref renderCtx);
DrawVisualLaneDividers(context, ref renderCtx);
DrawParagraphs(context, ref renderCtx);
DrawShotChanges(context, ref renderCtx);
DrawCurrentVideoPosition(context, ref renderCtx);
DrawNewParagraph(context, ref renderCtx);
|
Addressed the active Copilot review feedback in 49cf52e: cached the visual lane map for pointer-move/hit-test paths, moved Split waveform labels into Se.Language.Waveform, made Split button ordering deterministic, and changed Style splitting to use SubtitleLineViewModel.Style without falling back to Extra. |
|
OK, I tried this a bit and it looks cool, but I was unable to see anything useful for the ASSA files I tried with... either a lot of styles/actors/effects or just one style and zero actors. It could probably be useful for "Open second subitle" or subtitles with more than one language. |
# Conflicts: # ChangeLog.txt
Well in my use case with translations from war in Ukraine or translations for charities its usefull when I have 2-3 actors + additional notes. Another niche is Fansubs for anime. Usually they have 2-6 actors + double subs. Update:I’ve added logic so that the Split button in the waveform only appears when:
|
7ec87bf to
3d7059e
Compare

Summary
Replaces the earlier ASS/SSA multi-track editing prototype with a smaller visual-only waveform split mode.
This keeps the subtitle model and saved ASS/SSA data unchanged. Instead of adding real
TrackIndexstate, the waveform can be visually split into lanes based on existing subtitle metadata:The intent is to make complex ASS/SSA files easier to inspect in the waveform without introducing generated track styles or changing tools such as Fix Common Errors, merge, bridge gaps, or duration adjustment.
Behavior
Split: Nonemenu button to the waveform toolbar.Why this direction
This follows the feedback that ASS/SSA already has actors, styles, layers, and positioning, so a visual grouping mode fits the format better than adding real multi-track state to
Paragraph.The previous larger prototype is preserved in my fork at:
backup/pr-10706-multitrack-original-20260427Verification
dotnet build .\src\ui\UI.csproj -c Debug -v minimaldotnet test .\tests\UI\UITests.csproj -c Debug -v minimal(94 passed)Notes
Compared to previous more complex change we modify 3x less code.