1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-15 17:03:21 +08:00

Adjust ducking API to use a parameters record

This commit is contained in:
Dean Herbert 2024-07-05 14:41:50 +09:00
parent 0d858ce8f8
commit 554740af10
No known key found for this signature in database
3 changed files with 86 additions and 44 deletions

View File

@ -24,7 +24,7 @@ namespace osu.Game.Collections
protected override string PopInSampleName => @"UI/overlay-big-pop-in"; protected override string PopInSampleName => @"UI/overlay-big-pop-in";
protected override string PopOutSampleName => @"UI/overlay-big-pop-out"; protected override string PopOutSampleName => @"UI/overlay-big-pop-out";
private IDisposable? audioDucker; private IDisposable? duckOperation;
[Resolved] [Resolved]
private MusicController? musicController { get; set; } private MusicController? musicController { get; set; }
@ -120,12 +120,17 @@ namespace osu.Game.Collections
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
audioDucker?.Dispose(); duckOperation?.Dispose();
} }
protected override void PopIn() protected override void PopIn()
{ {
audioDucker = musicController?.Duck(100, 1f, unduckDuration: 100); duckOperation = musicController?.Duck(new DuckParameters
{
DuckDuration = 100,
DuckVolumeTo = 1,
RestoreDuration = 100,
});
this.FadeIn(enter_duration, Easing.OutQuint); this.FadeIn(enter_duration, Easing.OutQuint);
this.ScaleTo(0.9f).Then().ScaleTo(1f, enter_duration, Easing.OutQuint); this.ScaleTo(0.9f).Then().ScaleTo(1f, enter_duration, Easing.OutQuint);
@ -135,7 +140,7 @@ namespace osu.Game.Collections
{ {
base.PopOut(); base.PopOut();
audioDucker?.Dispose(); duckOperation?.Dispose();
this.FadeOut(exit_duration, Easing.OutQuint); this.FadeOut(exit_duration, Easing.OutQuint);
this.ScaleTo(0.9f, exit_duration); this.ScaleTo(0.9f, exit_duration);

View File

@ -32,7 +32,7 @@ namespace osu.Game.Overlays
|| dialogContainer.Children.Count > 0; || dialogContainer.Children.Count > 0;
[CanBeNull] [CanBeNull]
private IDisposable audioDucker; private IDisposable duckOperation;
public DialogOverlay() public DialogOverlay()
{ {
@ -53,7 +53,7 @@ namespace osu.Game.Overlays
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
audioDucker?.Dispose(); duckOperation?.Dispose();
} }
public void Push(PopupDialog dialog) public void Push(PopupDialog dialog)
@ -106,13 +106,18 @@ namespace osu.Game.Overlays
protected override void PopIn() protected override void PopIn()
{ {
audioDucker = musicController.Duck(100, 1f, unduckDuration: 100); duckOperation = musicController?.Duck(new DuckParameters
{
DuckDuration = 100,
DuckVolumeTo = 1,
RestoreDuration = 100,
});
} }
protected override void PopOut() protected override void PopOut()
{ {
base.PopOut(); base.PopOut();
audioDucker?.Dispose(); duckOperation?.Dispose();
// PopOut gets called initially, but we only want to hide dialog when we have been loaded and are present. // PopOut gets called initially, but we only want to hide dialog when we have been loaded and are present.
if (IsLoaded && CurrentDialog?.State.Value == Visibility.Visible) if (IsLoaded && CurrentDialog?.State.Value == Visibility.Visible)

View File

@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -263,59 +262,53 @@ namespace osu.Game.Overlays
/// <summary> /// <summary>
/// Attenuates the volume and/or filters the currently playing track. /// Attenuates the volume and/or filters the currently playing track.
/// </summary> /// </summary>
/// <param name="duration">Duration of the ducking transition, in ms.</param> public IDisposable? Duck(DuckParameters? parameters = null)
/// <param name="duckVolumeTo">Level to drop volume to (1.0 = 100%).</param>
/// <param name="duckCutoffTo">Cutoff frequency to drop `AudioFilter` to. Use `null` to skip filter effect.</param>
/// <param name="easing">Easing for the ducking transition.</param>
/// <param name="unduckDuration">Duration of the unducking transition, in ms.</param>
/// <param name="unduckEasing">Easing for the unducking transition.</param>
public IDisposable? Duck(int duration = 0, float duckVolumeTo = 0.25f, int? duckCutoffTo = 300, Easing easing = Easing.Out, int unduckDuration = 500, Easing unduckEasing = Easing.In)
{ {
parameters ??= new DuckParameters();
if (audioDuckActive) return null; if (audioDuckActive) return null;
audioDuckActive = true; audioDuckActive = true;
Schedule(() => Schedule(() =>
{ {
if (duckCutoffTo.IsNotNull()) if (parameters.DuckCutoffTo != null)
audioDuckFilter?.CutoffTo((int)duckCutoffTo, duration, easing); audioDuckFilter?.CutoffTo(parameters.DuckCutoffTo.Value, parameters.DuckDuration, parameters.DuckEasing);
this.TransformBindableTo(audioDuckVolume, duckVolumeTo, duration, easing); this.TransformBindableTo(audioDuckVolume, parameters.DuckVolumeTo, parameters.DuckDuration, parameters.DuckEasing);
}); });
return new InvokeOnDisposal(() => unduck(unduckDuration, unduckEasing)); return new InvokeOnDisposal(restoreDucking);
void restoreDucking()
{
if (!audioDuckActive) return;
audioDuckActive = false;
Schedule(() =>
{
audioDuckFilter?.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, parameters.RestoreDuration, parameters.RestoreEasing);
this.TransformBindableTo(audioDuckVolume, 1, parameters.RestoreDuration, parameters.RestoreEasing);
});
}
} }
/// <summary> /// <summary>
/// A convenience method that ducks the currently playing track, then after a delay, unducks it. /// A convenience method that ducks the currently playing track, then after a delay, restores automatically.
/// </summary> /// </summary>
/// <param name="delay">Delay after audio is ducked before unducking begins, in ms.</param> /// <param name="delayUntilRestore">A delay in milliseconds which defines how long to delay restoration after ducking completes.</param>
/// <param name="unduckDuration">Duration of the unducking transition, in ms.</param> /// <param name="parameters">Parameters defining the ducking operation.</param>
/// <param name="unduckEasing">Easing for the unducking transition.</param> public void DuckMomentarily(double delayUntilRestore, DuckParameters? parameters = null)
/// <param name="duckVolumeTo">Level to drop volume to (1.0 = 100%).</param>
/// <param name="duckCutoffTo">Cutoff frequency to drop `AudioFilter` to. Use `null` to skip filter effect.</param>
/// <param name="duckDuration">Duration of the ducking transition, in ms.</param>
/// <param name="duckEasing">Easing for the ducking transition.</param>
public void DuckMomentarily(int delay, int unduckDuration = 500, Easing unduckEasing = Easing.In, float duckVolumeTo = 0.25f, int? duckCutoffTo = 300, int duckDuration = 0,
Easing duckEasing = Easing.Out)
{ {
if (audioDuckActive) return; parameters ??= new DuckParameters();
Duck(duckDuration, duckVolumeTo, duckCutoffTo, duckEasing); IDisposable? duckOperation = Duck(parameters);
Scheduler.AddDelayed(() => unduck(unduckDuration, unduckEasing), delay);
}
private void unduck(int duration, Easing easing) if (duckOperation == null)
{ return;
if (!audioDuckActive) return;
audioDuckActive = false; Scheduler.AddDelayed(() => duckOperation.Dispose(), delayUntilRestore);
Schedule(() =>
{
audioDuckFilter?.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, duration, easing);
this.TransformBindableTo(audioDuckVolume, 1, duration, easing);
});
} }
private bool next() private bool next()
@ -491,6 +484,45 @@ namespace osu.Game.Overlays
} }
} }
public record DuckParameters
{
/// <summary>
/// The duration of the ducking transition in milliseconds.
/// Defaults to no duration (immediate ducking).
/// </summary>
public double DuckDuration = 0;
/// <summary>
/// The final volume which should be reached during ducking, when 0 is silent and 1 is original volume.
/// Defaults to 25%.
/// </summary>
public float DuckVolumeTo = 0.25f;
/// <summary>
/// The low-pass cutoff frequency which should be reached during ducking. Use `null` to skip filter effect.
/// Defaults to 300 Hz.
/// </summary>
public int? DuckCutoffTo = 300;
/// <summary>
/// The easing curve to be applied during ducking.
/// Defaults to <see cref="Easing.Out"/>.
/// </summary>
public Easing DuckEasing = Easing.Out;
/// <summary>
/// The duration of the restoration transition in milliseconds.
/// Defaults to 500 ms.
/// </summary>
public double RestoreDuration = 500;
/// <summary>
/// The easing curve to be applied during restoration.
/// Defaults to <see cref="Easing.In"/>.
/// </summary>
public Easing RestoreEasing = Easing.In;
}
public enum TrackChangeDirection public enum TrackChangeDirection
{ {
None, None,