Skip to content

Commit 84f11e2

Browse files
committed
Improve BetterLyrics
1 parent df57e44 commit 84f11e2

5 files changed

Lines changed: 61 additions & 10 deletions

File tree

‎dev/DevWinUI.Gallery/Views/Pages/Win2d/BetterLyricPage.xaml.cs‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ public sealed partial class BetterLyricPage : Page
99
private DispatcherQueueTimer? _playbackTimer = App.Current.Resources.DispatcherQueue.CreateTimer();
1010
private bool _isDraggingSlider = false;
1111

12-
private int TotalMs => MyBetterLyric.CurrentLyricsData?.LyricsLines.Max(l => l.EndMs) ?? 0;
1312
public BetterLyricPage()
1413
{
1514
InitializeComponent();
@@ -32,7 +31,7 @@ private void OnLineClicked(object? sender, int lineIndex)
3231

3332
private void ApplyLyricsDataToSlider()
3433
{
35-
var totalMs = TotalMs;
34+
var totalMs = (int)MyBetterLyric?.CurrentLyricsData?.Duration.TotalMilliseconds;
3635
ProgressSlider.Minimum = 0;
3736
ProgressSlider.Maximum = totalMs;
3837
ProgressSlider.StepFrequency = 100;
@@ -52,7 +51,7 @@ private void StartPlaybackTimer()
5251
if (_isDraggingSlider) return;
5352

5453
var newMs = ProgressSlider.Value + 100;
55-
if (newMs > TotalMs) newMs = 0;
54+
if (newMs > (int)MyBetterLyric?.CurrentLyricsData?.Duration.TotalMilliseconds) newMs = 0;
5655

5756
ProgressSlider.Value = newMs;
5857
};
@@ -69,8 +68,7 @@ private void ProgressSlider_ValueChanged(object sender, Microsoft.UI.Xaml.Contro
6968
MyBetterLyric.CurrentPosition = TimeSpan.FromMilliseconds(ms);
7069

7170
var current = TimeSpan.FromMilliseconds(ms);
72-
var total = TimeSpan.FromMilliseconds(TotalMs);
73-
PositionText.Text = $"{(int)current.TotalMinutes}:{current.Seconds:D2} / {(int)total.TotalMinutes}:{total.Seconds:D2}";
71+
PositionText.Text = $"{(int)current.TotalMinutes}:{current.Seconds:D2} / {(int)(int)MyBetterLyric?.CurrentLyricsData?.Duration.TotalMinutes}:{(int)MyBetterLyric?.CurrentLyricsData?.Duration.Seconds:D2}";
7472
}
7573

7674
private void ProgressSlider_PointerPressed(object sender, PointerRoutedEventArgs e)

‎dev/DevWinUI/Controls/Win2DAndComposition/BetterLyric/BetterLyric.Animator.cs‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ double currentPositionMs
8080
? 1.15
8181
: lyricsScaleEffectAmount / 100.0;
8282

83-
var maxAnimationDurationMs = Math.Max(line.EndMs ?? 0 - currentPositionMs, 0);
83+
var maxAnimationDurationMs = Math.Max((line.EndMs ?? 0) - currentPositionMs, 0);
8484

8585
bool isSecondaryLinePlaying = line.GetIsPlaying(currentPositionMs);
8686
bool isSecondaryLinePlayingChanged = line.IsPlayingLastFrame != isSecondaryLinePlaying;
@@ -286,6 +286,8 @@ double currentPositionMs
286286
bool isSyllablePlaying = syllable.GetIsPlaying(currentPositionMs);
287287
bool isSyllablePlayingChanged = syllable.IsPlayingLastFrame != isSyllablePlaying;
288288

289+
var desiredAnimationDurationMs = Math.Max((syllable.EndMs ?? 0) - currentPositionMs, 0);
290+
289291
if (isSyllablePlayingChanged)
290292
{
291293
// 缩放
@@ -295,7 +297,7 @@ double currentPositionMs
295297
{
296298
if (syllable.DurationMs >= lyricsScaleEffectLongSyllableDuration)
297299
{
298-
var (inDuration, outDuration) = CalculateSegmentDuration(syllable.DurationMs / 1000.0, maxAnimationDurationMs / 1000.0);
300+
var (inDuration, outDuration) = CalculateSegmentDuration(desiredAnimationDurationMs / 1000.0, maxAnimationDurationMs / 1000.0);
299301
renderChar.ScaleTransition.Start(
300302
new BetterLyricKeyframe<double>(targetCharScale, inDuration),
301303
new BetterLyricKeyframe<double>(1.0, outDuration)
@@ -310,7 +312,7 @@ double currentPositionMs
310312
{
311313
foreach (var renderChar in syllable.ChildrenRenderLyricsChars)
312314
{
313-
var (inDuration, outDuration) = CalculateSegmentDuration(syllable.DurationMs / 1000.0, maxAnimationDurationMs / 1000.0);
315+
var (inDuration, outDuration) = CalculateSegmentDuration(desiredAnimationDurationMs / 1000.0, maxAnimationDurationMs / 1000.0);
314316
renderChar.GlowTransition.Start(
315317
new BetterLyricKeyframe<double>(targetCharGlow, inDuration),
316318
new BetterLyricKeyframe<double>(0, outDuration)
@@ -397,8 +399,14 @@ private static (double InDuration, double OutDuration) CalculateSegmentDuration(
397399
{
398400
// 缓入动画时长尽量接近 desiredDuration
399401
var inDuration = Math.Min(desiredDuration, maxDuration);
400-
// 缓出动画时长保证合法
402+
// 缓出动画时长保证有合理的时长
401403
var outDuration = Math.Min(maxDuration - inDuration, BetterLyricTimeSpanHelper.AnimationDuration.TotalSeconds);
404+
//// 缓出动画时长过短时调整缓入动画时长以保证有合理的缓出动画
405+
if (outDuration == 0)
406+
{
407+
outDuration = inDuration / 3 * 1;
408+
inDuration = outDuration * 2;
409+
}
402410
return (inDuration, outDuration);
403411
}
404412
}

‎dev/DevWinUI/Controls/Win2DAndComposition/BetterLyric/BetterLyric.EffectProperties.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ private static void OnIsLyricsGlowEffectEnabledChanged(DependencyObject d, Depen
119119
{
120120
var ctl = (BetterLyric)d;
121121
ctl.isLyricsGlowEffectEnabled = (bool)e.NewValue;
122+
ctl.RequestRelayout();
122123
}
123124

124125

@@ -151,6 +152,7 @@ private static void OnLyricsGlowEffectLongSyllableDurationChanged(DependencyObje
151152
{
152153
var ctl = (BetterLyric)d;
153154
ctl.lyricsGlowEffectLongSyllableDuration = (int)e.NewValue;
155+
ctl.RequestRelayout();
154156
}
155157

156158

@@ -215,6 +217,7 @@ private static void OnIsLyricsScaleEffectEnabledChanged(DependencyObject d, Depe
215217
{
216218
var ctl = (BetterLyric)d;
217219
ctl.isLyricsScaleEffectEnabled = (bool)e.NewValue;
220+
ctl.RequestRelayout();
218221
}
219222

220223

@@ -231,6 +234,7 @@ private static void OnLyricsScaleEffectLongSyllableDurationChanged(DependencyObj
231234
{
232235
var ctl = (BetterLyric)d;
233236
ctl.lyricsScaleEffectLongSyllableDuration = (int)e.NewValue;
237+
ctl.RequestRelayout();
234238
}
235239

236240

‎dev/DevWinUI/Controls/Win2DAndComposition/BetterLyric/BetterLyric.cs‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ private void TriggerRelayout()
377377
DisposeRenderLyricsLines();
378378
_renderLyricsLines = currentLyricsData?.LyricsLines.Select(x => new RenderLyricsLine(x)).ToList();
379379

380+
EnsureRenderLyricsLinesPreservedAnimation();
381+
380382
if (_renderLyricsLines == null) return;
381383

382384
CalculateLanes(_renderLyricsLines);
@@ -451,4 +453,43 @@ public void ApplyLayoutFromContainer(FrameworkElement lyricsContainer, Framework
451453
renderLyricsStartY += (renderLyricsWidth - renderLyricsHeight) / 2;
452454
}
453455
}
456+
457+
private void EnsureRenderLyricsLinesPreservedAnimation()
458+
{
459+
if (_renderLyricsLines == null) return;
460+
461+
if (!isLyricsScaleEffectEnabled && !isLyricsGlowEffectEnabled) return;
462+
463+
int animationPadding = (int)BetterLyricTimeSpanHelper.AnimationDuration.TotalMilliseconds;
464+
int longSyllableThreshold = Math.Max(
465+
lyricsScaleEffectLongSyllableDuration,
466+
lyricsGlowEffectLongSyllableDuration
467+
);
468+
469+
var lines = _renderLyricsLines;
470+
for (int i = 0; i < lines.Count; i++)
471+
{
472+
var line = lines[i];
473+
if (line == null) continue;
474+
475+
bool isLastLine = i + 1 >= lines.Count;
476+
var nextLineStartMs = isLastLine ? (int)currentLyricsData.Duration.TotalMilliseconds : lines[i + 1].StartMs;
477+
478+
bool isLongSyllable = line.PrimaryRenderSyllables.LastOrDefault()?.DurationMs > longSyllableThreshold;
479+
480+
if (line.EndMs.HasValue && isLongSyllable)
481+
{
482+
if (isLastLine || line.EndMs > nextLineStartMs)
483+
{
484+
line.EndMs += animationPadding;
485+
}
486+
else
487+
{
488+
int targetEndMs = line.EndMs.Value + animationPadding;
489+
490+
line.EndMs = Math.Max(line.EndMs.Value, Math.Min(targetEndMs, nextLineStartMs));
491+
}
492+
}
493+
}
494+
}
454495
}

‎dev/DevWinUI/Controls/Win2DAndComposition/BetterLyric/Lyric/LyricData.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public partial class LyricData
88
public bool AutoGenerated { get; set; } = false;
99
public string WrappedOriginalText => string.Join("\n", LyricsLines.Select(line => line.PrimaryText));
1010
public bool IsWordByWord => LyricsLines.Any(x => x.IsPrimaryHasRealSyllableInfo);
11-
11+
public TimeSpan Duration => TimeSpan.FromMilliseconds(LyricsLines?.Max(l => l.EndMs) ?? 0);
1212
public LyricData()
1313
{
1414
}

0 commit comments

Comments
 (0)