mirror of
https://github.com/ppy/osu.git
synced 2025-01-06 21:12:55 +08:00
Better support multiple concurrent ducking operations
This commit is contained in:
parent
20ba6ca867
commit
717f7ba9f0
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
@ -62,8 +63,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private readonly BindableDouble audioDuckVolume = new BindableDouble(1);
|
private readonly BindableDouble audioDuckVolume = new BindableDouble(1);
|
||||||
|
|
||||||
private AudioFilter? audioDuckFilter;
|
private AudioFilter audioDuckFilter = null!;
|
||||||
private bool audioDuckActive;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
@ -259,41 +259,42 @@ namespace osu.Game.Overlays
|
|||||||
onSuccess?.Invoke();
|
onSuccess?.Invoke();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private readonly List<DuckParameters> duckOperations = new List<DuckParameters>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attenuates the volume and/or filters the currently playing track.
|
/// Applies ducking, attenuating the volume and/or low-pass cutoff of the currently playing track to make headroom for effects (or just to apply an effect).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="IDisposable"/> which will restore the duck operation when disposed, or <c>null</c> if another duck operation was already in progress.</returns>
|
/// <returns>A <see cref="IDisposable"/> which will restore the duck operation when disposed.</returns>
|
||||||
public IDisposable? Duck(DuckParameters? parameters = null)
|
public IDisposable Duck(DuckParameters? parameters = null)
|
||||||
{
|
{
|
||||||
parameters ??= new DuckParameters();
|
parameters ??= new DuckParameters();
|
||||||
|
|
||||||
if (audioDuckActive) return null;
|
if (duckOperations.Contains(parameters))
|
||||||
|
throw new ArgumentException("Ducking has already been applied for the provided parameters.", nameof(parameters));
|
||||||
|
|
||||||
audioDuckActive = true;
|
duckOperations.Add(parameters);
|
||||||
|
|
||||||
Schedule(() =>
|
DuckParameters volumeOperation = duckOperations.MinBy(p => p.DuckVolumeTo)!;
|
||||||
{
|
DuckParameters lowPassOperation = duckOperations.MinBy(p => p.DuckCutoffTo)!;
|
||||||
if (parameters.DuckCutoffTo != null)
|
|
||||||
audioDuckFilter?.CutoffTo(parameters.DuckCutoffTo.Value, parameters.DuckDuration, parameters.DuckEasing);
|
|
||||||
|
|
||||||
this.TransformBindableTo(audioDuckVolume, parameters.DuckVolumeTo, parameters.DuckDuration, parameters.DuckEasing);
|
audioDuckFilter.CutoffTo(lowPassOperation.DuckCutoffTo, lowPassOperation.DuckDuration, lowPassOperation.DuckEasing);
|
||||||
});
|
this.TransformBindableTo(audioDuckVolume, volumeOperation.DuckVolumeTo, volumeOperation.DuckDuration, volumeOperation.DuckEasing);
|
||||||
|
|
||||||
return new InvokeOnDisposal(restoreDucking);
|
return new InvokeOnDisposal(restoreDucking);
|
||||||
|
|
||||||
void restoreDucking()
|
void restoreDucking() => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (!audioDuckActive) return;
|
Debug.Assert(duckOperations.Contains(parameters));
|
||||||
|
duckOperations.Remove(parameters);
|
||||||
|
|
||||||
audioDuckActive = false;
|
DuckParameters? restoreVolumeOperation = duckOperations.MinBy(p => p.DuckVolumeTo);
|
||||||
|
DuckParameters? restoreLowPassOperation = duckOperations.MinBy(p => p.DuckCutoffTo);
|
||||||
|
|
||||||
Schedule(() =>
|
// If another duck operation is in the list, restore ducking to its level, else reset back to defaults.
|
||||||
{
|
audioDuckFilter.CutoffTo(restoreLowPassOperation?.DuckCutoffTo ?? AudioFilter.MAX_LOWPASS_CUTOFF, parameters.RestoreDuration, parameters.RestoreEasing);
|
||||||
audioDuckFilter?.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, parameters.RestoreDuration, parameters.RestoreEasing);
|
this.TransformBindableTo(audioDuckVolume, restoreVolumeOperation?.DuckVolumeTo ?? 1, 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, restores automatically.
|
/// A convenience method that ducks the currently playing track, then after a delay, restores automatically.
|
||||||
@ -304,10 +305,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
parameters ??= new DuckParameters();
|
parameters ??= new DuckParameters();
|
||||||
|
|
||||||
IDisposable? duckOperation = Duck(parameters);
|
IDisposable duckOperation = Duck(parameters);
|
||||||
|
|
||||||
if (duckOperation == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Scheduler.AddDelayed(() => duckOperation.Dispose(), delayUntilRestore);
|
Scheduler.AddDelayed(() => duckOperation.Dispose(), delayUntilRestore);
|
||||||
}
|
}
|
||||||
@ -485,7 +483,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record DuckParameters
|
public class DuckParameters
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The duration of the ducking transition in milliseconds.
|
/// The duration of the ducking transition in milliseconds.
|
||||||
@ -500,10 +498,10 @@ namespace osu.Game.Overlays
|
|||||||
public float DuckVolumeTo = 0.25f;
|
public float DuckVolumeTo = 0.25f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The low-pass cutoff frequency which should be reached during ducking. Use `null` to skip filter effect.
|
/// The low-pass cutoff frequency which should be reached during ducking. If not required, set to <see cref="AudioFilter.MAX_LOWPASS_CUTOFF"/>.
|
||||||
/// Defaults to 300 Hz.
|
/// Defaults to 300 Hz.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? DuckCutoffTo = 300;
|
public int DuckCutoffTo = 300;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The easing curve to be applied during ducking.
|
/// The easing curve to be applied during ducking.
|
||||||
|
Loading…
Reference in New Issue
Block a user