2023-10-18 07:55:27 +00:00
|
|
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
|
2023-10-18 08:38:11 +00:00
|
|
|
using System;
|
2023-10-18 07:55:27 +00:00
|
|
|
using osu.Framework.Audio;
|
|
|
|
using osu.Framework.Bindables;
|
|
|
|
|
|
|
|
namespace osu.Game.Rulesets.Mods
|
|
|
|
{
|
2023-10-18 08:23:14 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Provides common functionality shared across various rate adjust mods.
|
|
|
|
/// </summary>
|
2023-10-18 07:55:27 +00:00
|
|
|
public class RateAdjustModHelper : IApplicableToTrack
|
|
|
|
{
|
2023-10-18 08:39:11 +00:00
|
|
|
public readonly IBindableNumber<double> SpeedChange;
|
2023-10-18 08:38:11 +00:00
|
|
|
|
2023-10-18 07:55:27 +00:00
|
|
|
private IAdjustableAudioComponent? track;
|
|
|
|
|
2023-10-18 08:38:11 +00:00
|
|
|
private BindableBool? adjustPitch;
|
|
|
|
|
2023-10-18 08:39:11 +00:00
|
|
|
/// <summary>
|
|
|
|
/// The score multiplier for the current <see cref="SpeedChange"/>.
|
|
|
|
/// </summary>
|
|
|
|
public double ScoreMultiplier
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
// Round to the nearest multiple of 0.1.
|
|
|
|
double value = (int)(SpeedChange.Value * 10) / 10.0;
|
|
|
|
|
|
|
|
// Offset back to 0.
|
|
|
|
value -= 1;
|
|
|
|
|
|
|
|
if (SpeedChange.Value >= 1)
|
2023-12-13 06:51:26 +00:00
|
|
|
return 1 + value / 5;
|
|
|
|
else
|
|
|
|
return 0.6 + value;
|
2023-10-18 08:39:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-18 08:38:11 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Construct a new <see cref="RateAdjustModHelper"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="speedChange">The main speed adjust parameter which is exposed to the user.</param>
|
2023-10-18 08:39:11 +00:00
|
|
|
public RateAdjustModHelper(IBindableNumber<double> speedChange)
|
2023-10-18 07:55:27 +00:00
|
|
|
{
|
2023-10-18 08:39:11 +00:00
|
|
|
SpeedChange = speedChange;
|
2023-10-18 08:38:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Setup audio track adjustments for a rate adjust mod.
|
|
|
|
/// Importantly, <see cref="ApplyToTrack"/> must be called when a track is obtained/changed for this to work.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="adjustPitch">The "adjust pitch" setting as exposed to the user.</param>
|
|
|
|
public void HandleAudioAdjustments(BindableBool adjustPitch)
|
|
|
|
{
|
2023-10-18 07:55:27 +00:00
|
|
|
this.adjustPitch = adjustPitch;
|
|
|
|
|
|
|
|
// When switching between pitch adjust, we need to update adjustments to time-shift or frequency-scale.
|
2023-10-18 08:38:11 +00:00
|
|
|
adjustPitch.BindValueChanged(adjustPitchSetting =>
|
2023-10-18 07:55:27 +00:00
|
|
|
{
|
2023-10-18 08:39:11 +00:00
|
|
|
track?.RemoveAdjustment(adjustmentForPitchSetting(adjustPitchSetting.OldValue), SpeedChange);
|
|
|
|
track?.AddAdjustment(adjustmentForPitchSetting(adjustPitchSetting.NewValue), SpeedChange);
|
2023-10-18 07:55:27 +00:00
|
|
|
|
|
|
|
AdjustableProperty adjustmentForPitchSetting(bool adjustPitchSettingValue)
|
|
|
|
=> adjustPitchSettingValue ? AdjustableProperty.Frequency : AdjustableProperty.Tempo;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-10-18 08:38:11 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Should be invoked when a track is obtained / changed.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="track">The new track.</param>
|
|
|
|
/// <exception cref="InvalidOperationException">If this method is called before <see cref="HandleAudioAdjustments"/>.</exception>
|
2023-10-18 07:55:27 +00:00
|
|
|
public void ApplyToTrack(IAdjustableAudioComponent track)
|
|
|
|
{
|
2023-10-18 08:38:11 +00:00
|
|
|
if (adjustPitch == null)
|
|
|
|
throw new InvalidOperationException($"Must call {nameof(HandleAudioAdjustments)} first");
|
|
|
|
|
2023-10-18 07:55:27 +00:00
|
|
|
this.track = track;
|
2023-10-18 08:38:11 +00:00
|
|
|
adjustPitch.TriggerChange();
|
2023-10-18 07:55:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|