1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 08:55:35 +08:00

Re-implement the SampleBank/Sample structure. No parsing support yet.

This commit is contained in:
smoogipooo 2017-04-05 21:34:28 +09:00
parent 1d4a371ded
commit 2d8239a3f7
18 changed files with 126 additions and 138 deletions

View File

@ -43,7 +43,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Slider return new Slider
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, SampleBank = original.SampleBank,
CurveObject = curveData, CurveObject = curveData,
Position = positionData?.Position ?? Vector2.Zero, Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false NewCombo = comboData?.NewCombo ?? false
@ -55,7 +55,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new Spinner return new Spinner
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, SampleBank = original.SampleBank,
Position = new Vector2(512, 384) / 2, Position = new Vector2(512, 384) / 2,
EndTime = endTimeData.EndTime EndTime = endTimeData.EndTime
}; };
@ -64,7 +64,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
return new HitCircle return new HitCircle
{ {
StartTime = original.StartTime, StartTime = original.StartTime,
Sample = original.Sample, SampleBank = original.SampleBank,
Position = positionData?.Position ?? Vector2.Zero, Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false NewCombo = comboData?.NewCombo ?? false
}; };

View File

@ -67,7 +67,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ComboIndex = s.ComboIndex, ComboIndex = s.ComboIndex,
Scale = s.Scale, Scale = s.Scale,
ComboColour = s.ComboColour, ComboColour = s.ComboColour,
Sample = s.Sample, SampleBank = s.SampleBank,
}), }),
}; };
@ -111,7 +111,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
if (repeat > currentRepeat) if (repeat > currentRepeat)
{ {
if (repeat < slider.RepeatCount && ball.Tracking) if (repeat < slider.RepeatCount && ball.Tracking)
PlaySample(); PlaySamples();
currentRepeat = repeat; currentRepeat = repeat;
} }

View File

@ -58,12 +58,10 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
string sampleSet = (HitObject.Sample?.Set ?? SampleSet.Normal).ToString().ToLower(); sample = audio.Sample.Get($@"Gameplay/{HitObject.SampleBank.Name.ToLower()}-slidertick");
sample = audio.Sample.Get($@"Gameplay/{sampleSet}-slidertick");
} }
protected override void PlaySample() protected override void PlaySamples()
{ {
sample?.Play(); sample?.Play();
} }

View File

@ -95,11 +95,7 @@ namespace osu.Game.Modes.Osu.Objects
StackHeight = StackHeight, StackHeight = StackHeight,
Scale = Scale, Scale = Scale,
ComboColour = ComboColour, ComboColour = ComboColour,
Sample = new HitSampleInfo SampleBank = SampleBank
{
Type = SampleType.None,
Set = SampleSet.Soft,
},
}; };
} }
} }

View File

@ -57,9 +57,9 @@ namespace osu.Game.Modes.Taiko.Beatmaps
var endTimeData = obj as IHasEndTime; var endTimeData = obj as IHasEndTime;
// Old osu! used hit sounding to determine various hit type information // Old osu! used hit sounding to determine various hit type information
SampleType sample = obj.Sample?.Type ?? SampleType.None; SampleBank sampleBank = obj.SampleBank;
bool strong = (sample & SampleType.Finish) > 0; bool strong = sampleBank.Sets.Any(s => s.Type == SampleType.Finish);
if (distanceData != null) if (distanceData != null)
{ {
@ -98,7 +98,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new CentreHit yield return new CentreHit
{ {
StartTime = j, StartTime = j,
Sample = obj.Sample, SampleBank = obj.SampleBank,
IsStrong = strong, IsStrong = strong,
VelocityMultiplier = legacy_velocity_multiplier VelocityMultiplier = legacy_velocity_multiplier
}; };
@ -109,7 +109,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new DrumRoll yield return new DrumRoll
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, SampleBank = obj.SampleBank,
IsStrong = strong, IsStrong = strong,
Distance = distance, Distance = distance,
TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4, TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4,
@ -124,7 +124,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new Swell yield return new Swell
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, SampleBank = obj.SampleBank,
IsStrong = strong, IsStrong = strong,
EndTime = endTimeData.EndTime, EndTime = endTimeData.EndTime,
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier), RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
@ -133,14 +133,14 @@ namespace osu.Game.Modes.Taiko.Beatmaps
} }
else else
{ {
bool isCentre = (sample & ~(SampleType.Finish | SampleType.Normal)) == 0; bool isCentre = sampleBank.Sets.Any(s => s.Type == SampleType.Normal);
if (isCentre) if (isCentre)
{ {
yield return new CentreHit yield return new CentreHit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, SampleBank = obj.SampleBank,
IsStrong = strong, IsStrong = strong,
VelocityMultiplier = legacy_velocity_multiplier VelocityMultiplier = legacy_velocity_multiplier
}; };
@ -150,7 +150,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new RimHit yield return new RimHit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Sample = obj.Sample, SampleBank = obj.SampleBank,
IsStrong = strong, IsStrong = strong,
VelocityMultiplier = legacy_velocity_multiplier VelocityMultiplier = legacy_velocity_multiplier
}; };

View File

@ -95,11 +95,7 @@ namespace osu.Game.Modes.Taiko.Objects
TickSpacing = tickSpacing, TickSpacing = tickSpacing,
StartTime = t, StartTime = t,
IsStrong = IsStrong, IsStrong = IsStrong,
Sample = new HitSampleInfo SampleBank = SampleBank
{
Type = SampleType.None,
Set = SampleSet.Soft
}
}); });
first = false; first = false;

View File

@ -136,12 +136,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(slider); Assert.IsNotNull(slider);
Assert.AreEqual(new Vector2(192, 168), slider.Position); Assert.AreEqual(new Vector2(192, 168), slider.Position);
Assert.AreEqual(956, slider.StartTime); Assert.AreEqual(956, slider.StartTime);
Assert.AreEqual(SampleType.None, slider.Sample.Type); Assert.AreEqual(SampleType.None, slider.SampleBank.Type);
var hit = beatmap.HitObjects[1] as LegacyHit; var hit = beatmap.HitObjects[1] as LegacyHit;
Assert.IsNotNull(hit); Assert.IsNotNull(hit);
Assert.AreEqual(new Vector2(304, 56), hit.Position); Assert.AreEqual(new Vector2(304, 56), hit.Position);
Assert.AreEqual(1285, hit.StartTime); Assert.AreEqual(1285, hit.StartTime);
Assert.AreEqual(SampleType.Clap, hit.Sample.Type); Assert.AreEqual(SampleType.Clap, hit.SampleBank.Type);
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace osu.Game.Beatmaps.Formats
// TODO: Not sure how far back to go, or differences between versions // TODO: Not sure how far back to go, or differences between versions
} }
private SampleSet defaultSampleSet; private Sample defaultSampleSet;
private int defaultSampleVolume = 100; private int defaultSampleVolume = 100;
private bool samplesMatchPlaybackRate; private bool samplesMatchPlaybackRate;
@ -77,7 +77,7 @@ namespace osu.Game.Beatmaps.Formats
beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1; beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
break; break;
case @"SampleSet": case @"SampleSet":
defaultSampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val); defaultSampleSet = (Sample)Enum.Parse(typeof(Sample), val);
break; break;
case @"SampleVolume": case @"SampleVolume":
defaultSampleVolume = int.Parse(val); defaultSampleVolume = int.Parse(val);
@ -222,9 +222,9 @@ namespace osu.Game.Beatmaps.Formats
if (split.Length >= 3) if (split.Length >= 3)
timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]); timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]);
SampleSet sampleSet = defaultSampleSet; Sample sampleSet = defaultSampleSet;
if (split.Length >= 4) if (split.Length >= 4)
sampleSet = (SampleSet)int.Parse(split[3]); sampleSet = (Sample)int.Parse(split[3]);
SampleBank sampleBank = SampleBank.Default; SampleBank sampleBank = SampleBank.Default;
if (split.Length >= 5) if (split.Length >= 5)

View File

@ -1,10 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public class HitSampleInfo : SampleInfo
{
public SampleType Type;
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
/// <summary>
/// A <see cref="Sample"/> defines a type of sound that is to be played.
/// </summary>
public class Sample
{
/// <summary>
/// The type of sound to be played.
/// </summary>
public SampleType Type;
/// <summary>
/// The volume to be played at.
/// </summary>
public int? Volume;
}
}

View File

@ -1,12 +1,29 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
namespace osu.Game.Beatmaps.Samples namespace osu.Game.Beatmaps.Samples
{ {
public enum SampleBank /// <summary>
/// Wraps a list of <see cref="Sample"/> to change which bank of files are used for each <see cref="Sample"/>.
/// </summary>
public class SampleBank
{ {
Default = 0, /// <summary>
Custom1 = 1, /// The list of samples that are to be played to be played from this bank.
Custom2 = 2 /// </summary>
public List<Sample> Sets;
/// <summary>
/// In conversion from osu-stable, this is equivalent to SampleSet (_not_ CustomSampleSet).
/// i.e. None/Normal/Soft/Drum
/// </summary>
public string Name;
/// <summary>
/// Default sample volume.
/// </summary>
public int Volume;
} }
} }

View File

@ -1,12 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public class SampleInfo
{
public SampleBank Bank;
public SampleSet Set;
public int Volume;
}
}

View File

@ -1,13 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps.Samples
{
public enum SampleSet
{
None = 0,
Normal = 1,
Soft = 2,
Drum = 3
}
}

View File

@ -1,17 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Beatmaps.Samples namespace osu.Game.Beatmaps.Samples
{ {
[Flags]
public enum SampleType public enum SampleType
{ {
None = 0, None,
Normal = 1, Normal,
Whistle = 2, Whistle,
Finish = 4, Finish,
Clap = 8 Clap
}; }
} }

View File

@ -15,7 +15,7 @@ using OpenTK.Graphics;
namespace osu.Game.Modes.Objects.Drawables namespace osu.Game.Modes.Objects.Drawables
{ {
public abstract class DrawableHitObject<TJudgement> : Container, IStateful<ArmedState> public abstract class DrawableHitObject<TJudgement> : Container
where TJudgement : Judgement where TJudgement : Judgement
{ {
public override bool HandleInput => Interactive; public override bool HandleInput => Interactive;
@ -24,9 +24,44 @@ namespace osu.Game.Modes.Objects.Drawables
public TJudgement Judgement; public TJudgement Judgement;
protected abstract TJudgement CreateJudgement(); protected override void LoadComplete()
{
base.LoadComplete();
protected abstract void UpdateState(ArmedState state); // We may be setting a custom judgement in test cases or what not
if (Judgement == null)
Judgement = CreateJudgement();
}
protected abstract TJudgement CreateJudgement();
}
public abstract class DrawableHitObject<TObject, TJudgement> : DrawableHitObject<TJudgement>, IStateful<ArmedState>
where TObject : HitObject
where TJudgement : Judgement
{
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
/// <summary>
/// The colour used for various elements of this DrawableHitObject.
/// </summary>
public Color4 AccentColour { get; protected set; }
public TObject HitObject;
private readonly List<SampleChannel> samples = new List<SampleChannel>();
protected DrawableHitObject(TObject hitObject)
{
HitObject = hitObject;
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
foreach (var sample in HitObject.SampleBank.Sets)
samples.Add(audio.Sample.Get($@"Gameplay/{sample.Type.ToString().ToLower()}-hit{HitObject.SampleBank.Name.ToLower()}"));
}
private ArmedState state; private ArmedState state;
public ArmedState State public ArmedState State
@ -45,47 +80,17 @@ namespace osu.Game.Modes.Objects.Drawables
UpdateState(state); UpdateState(state);
if (State == ArmedState.Hit) if (State == ArmedState.Hit)
PlaySample(); PlaySamples();
} }
} }
protected SampleChannel Sample;
protected virtual void PlaySample()
{
Sample?.Play();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
//we may be setting a custom judgement in test cases or what not. // Force application of the state that was set before we loaded
if (Judgement == null)
Judgement = CreateJudgement();
//force application of the state that was set before we loaded.
UpdateState(State); UpdateState(State);
} }
}
public abstract class DrawableHitObject<TObject, TJudgement> : DrawableHitObject<TJudgement>
where TObject : HitObject
where TJudgement : Judgement
{
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
public TObject HitObject;
/// <summary>
/// The colour used for various elements of this DrawableHitObject.
/// </summary>
public Color4 AccentColour { get; protected set; }
protected DrawableHitObject(TObject hitObject)
{
HitObject = hitObject;
}
/// <summary> /// <summary>
/// Process a hit of this hitobject. Carries out judgement. /// Process a hit of this hitobject. Carries out judgement.
@ -149,16 +154,9 @@ namespace osu.Game.Modes.Objects.Drawables
UpdateJudgement(false); UpdateJudgement(false);
} }
[BackgroundDependencyLoader] protected virtual void PlaySamples()
private void load(AudioManager audio)
{ {
SampleType type = HitObject.Sample?.Type ?? SampleType.None; samples.ForEach(s => s?.Play());
if (type == SampleType.None)
type = SampleType.Normal;
SampleSet sampleSet = HitObject.Sample?.Set ?? SampleSet.Normal;
Sample = audio.Sample.Get($@"Gameplay/{sampleSet.ToString().ToLower()}-hit{type.ToString().ToLower()}");
} }
private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects; private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects;
@ -173,5 +171,7 @@ namespace osu.Game.Modes.Objects.Drawables
h.OnJudgement += d => OnJudgement?.Invoke(d); h.OnJudgement += d => OnJudgement?.Invoke(d);
nestedHitObjects.Add(h); nestedHitObjects.Add(h);
} }
protected abstract void UpdateState(ArmedState state);
} }
} }

View File

@ -21,9 +21,9 @@ namespace osu.Game.Modes.Objects
public double StartTime { get; set; } public double StartTime { get; set; }
/// <summary> /// <summary>
/// The sample to be played when this HitObject is hit. /// The sample bank to be played when this hit object is hit.
/// </summary> /// </summary>
public HitSampleInfo Sample { get; set; } public SampleBank SampleBank { get; set; }
/// <summary> /// <summary>
/// Applies default values to this HitObject. /// Applies default values to this HitObject.

View File

@ -105,10 +105,10 @@ namespace osu.Game.Modes.Objects
throw new InvalidOperationException($@"Unknown hit object type {type}"); throw new InvalidOperationException($@"Unknown hit object type {type}");
result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
result.Sample = new HitSampleInfo result.SampleBank = new HitSampleInfo
{ {
Type = (SampleType)int.Parse(split[4]), Type = (SampleType)int.Parse(split[4]),
Set = SampleSet.Soft, Set = Sample.Soft,
}; };
// TODO: "addition" field // TODO: "addition" field

View File

@ -76,6 +76,9 @@
<Compile Include="Beatmaps\IBeatmapCoverter.cs" /> <Compile Include="Beatmaps\IBeatmapCoverter.cs" />
<Compile Include="Beatmaps\IBeatmapProcessor.cs" /> <Compile Include="Beatmaps\IBeatmapProcessor.cs" />
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" /> <Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
<Compile Include="Beatmaps\Samples\SampleBank.cs" />
<Compile Include="Beatmaps\Samples\Sample.cs" />
<Compile Include="Beatmaps\Samples\SampleType.cs" />
<Compile Include="Beatmaps\Timing\TimeSignatures.cs" /> <Compile Include="Beatmaps\Timing\TimeSignatures.cs" />
<Compile Include="Beatmaps\Timing\TimingInfo.cs" /> <Compile Include="Beatmaps\Timing\TimingInfo.cs" />
<Compile Include="Database\ScoreDatabase.cs" /> <Compile Include="Database\ScoreDatabase.cs" />
@ -148,11 +151,6 @@
<Compile Include="Beatmaps\Drawables\Panel.cs" /> <Compile Include="Beatmaps\Drawables\Panel.cs" />
<Compile Include="Modes\Objects\Drawables\DrawableHitObject.cs" /> <Compile Include="Modes\Objects\Drawables\DrawableHitObject.cs" />
<Compile Include="Modes\Objects\HitObject.cs" /> <Compile Include="Modes\Objects\HitObject.cs" />
<Compile Include="Beatmaps\Samples\HitSampleInfo.cs" />
<Compile Include="Beatmaps\Samples\SampleBank.cs" />
<Compile Include="Beatmaps\Samples\SampleInfo.cs" />
<Compile Include="Beatmaps\Samples\SampleSet.cs" />
<Compile Include="Beatmaps\Samples\SampleType.cs" />
<Compile Include="Beatmaps\Timing\ControlPoint.cs" /> <Compile Include="Beatmaps\Timing\ControlPoint.cs" />
<Compile Include="Configuration\OsuConfigManager.cs" /> <Compile Include="Configuration\OsuConfigManager.cs" />
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" /> <Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />