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

Merge pull request #594 from smoogipooo/better-hitsounds

Better hitsounds
This commit is contained in:
Dean Herbert 2017-04-06 16:12:40 +09:00 committed by GitHub
commit 85dfd8297b
22 changed files with 253 additions and 193 deletions

View File

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

View File

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

View File

@ -2,12 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
@ -53,22 +49,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
};
}
private SampleChannel sample;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
string sampleSet = (HitObject.Sample?.Set ?? SampleSet.Normal).ToString().ToLower();
sample = audio.Sample.Get($@"Gameplay/{sampleSet}-slidertick");
}
protected override void PlaySample()
{
sample?.Play();
}
protected override void CheckJudgement(bool userTriggered)
{
if (Judgement.TimeOffset >= 0)

View File

@ -2,13 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using osu.Game.Modes.Objects;
using osu.Game.Database;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Modes.Osu.Objects
{
@ -95,11 +96,12 @@ namespace osu.Game.Modes.Osu.Objects
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
Sample = new HitSampleInfo
Samples = Samples.Select(s => new SampleInfo
{
Type = SampleType.None,
Set = SampleSet.Soft,
},
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList()
};
}
}

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Taiko.Objects;
@ -12,6 +11,7 @@ using System.Linq;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Beatmaps
{
@ -60,9 +60,9 @@ namespace osu.Game.Modes.Taiko.Beatmaps
var endTimeData = obj as IHasEndTime;
// Old osu! used hit sounding to determine various hit type information
SampleType sample = obj.Sample?.Type ?? SampleType.None;
List<SampleInfo> samples = obj.Samples;
bool strong = (sample & SampleType.Finish) > 0;
bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH);
if (distanceData != null)
{
@ -101,7 +101,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new CentreHit
{
StartTime = j,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
};
}
@ -111,7 +111,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new DrumRoll
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
Duration = taikoDuration,
TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4,
@ -125,7 +125,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps
yield return new Swell
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
Duration = endTimeData.Duration,
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
@ -133,23 +133,23 @@ namespace osu.Game.Modes.Taiko.Beatmaps
}
else
{
bool isCentre = (sample & ~(SampleType.Finish | SampleType.Normal)) == 0;
bool isRim = samples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE);
if (isCentre)
if (isRim)
{
yield return new CentreHit
yield return new RimHit
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
};
}
else
{
yield return new RimHit
yield return new CentreHit
{
StartTime = obj.StartTime,
Sample = obj.Sample,
Samples = obj.Samples,
IsStrong = strong,
};
}

View File

@ -1,13 +1,13 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Audio;
namespace osu.Game.Modes.Taiko.Objects
{
@ -82,11 +82,12 @@ namespace osu.Game.Modes.Taiko.Objects
TickSpacing = tickSpacing,
StartTime = t,
IsStrong = IsStrong,
Sample = new HitSampleInfo
Samples = Samples.Select(s => new SampleInfo
{
Type = SampleType.None,
Set = SampleSet.Soft
}
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList()
});
first = false;

View File

@ -6,11 +6,12 @@ using NUnit.Framework;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes;
using osu.Game.Tests.Resources;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Objects.Legacy;
using System.Linq;
using osu.Game.Audio;
namespace osu.Game.Tests.Beatmaps.Formats
{
@ -55,7 +56,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo;
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(false, beatmapInfo.Countdown);
Assert.AreEqual(SampleSet.Soft, beatmapInfo.SampleSet);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
Assert.AreEqual(PlayMode.Osu, beatmapInfo.Mode);
@ -137,12 +137,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(slider);
Assert.AreEqual(new Vector2(192, 168), slider.Position);
Assert.AreEqual(956, slider.StartTime);
Assert.AreEqual(SampleType.None, slider.Sample.Type);
Assert.IsTrue(slider.Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
var hit = beatmap.HitObjects[1] as LegacyHit;
Assert.IsNotNull(hit);
Assert.AreEqual(new Vector2(304, 56), hit.Position);
Assert.AreEqual(1285, hit.StartTime);
Assert.AreEqual(SampleType.Clap, hit.Sample.Type);
Assert.IsTrue(hit.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
}
}
}

View File

@ -0,0 +1,28 @@
// 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.Audio
{
public class SampleInfo
{
public const string HIT_WHISTLE = @"hitwhistle";
public const string HIT_FINISH = @"hitfinish";
public const string HIT_NORMAL = @"hitnormal";
public const string HIT_CLAP = @"hitclap";
/// <summary>
/// The bank to load the sample from.
/// </summary>
public string Bank;
/// <summary>
/// The name of the sample to load.
/// </summary>
public string Name;
/// <summary>
/// The sample volume.
/// </summary>
public int Volume;
}
}

View File

@ -6,7 +6,6 @@ using System.Globalization;
using System.IO;
using OpenTK.Graphics;
using osu.Game.Beatmaps.Events;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using osu.Game.Modes;
using osu.Game.Modes.Objects;
@ -31,6 +30,9 @@ namespace osu.Game.Beatmaps.Formats
// TODO: Not sure how far back to go, or differences between versions
}
private LegacySampleBank defaultSampleBank;
private int defaultSampleVolume = 100;
private readonly int beatmapVersion;
public OsuLegacyDecoder()
@ -73,7 +75,10 @@ namespace osu.Game.Beatmaps.Formats
beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
break;
case @"SampleSet":
beatmap.BeatmapInfo.SampleSet = (SampleSet)Enum.Parse(typeof(SampleSet), val);
defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), val);
break;
case @"SampleVolume":
defaultSampleVolume = int.Parse(val);
break;
case @"StackLeniency":
beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
@ -203,28 +208,56 @@ namespace osu.Game.Beatmaps.Formats
private void handleTimingPoints(Beatmap beatmap, string val)
{
ControlPoint cp = null;
string[] split = val.Split(',');
if (split.Length > 2)
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
if (split.Length >= 3)
timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]);
LegacySampleBank sampleSet = defaultSampleBank;
if (split.Length >= 4)
sampleSet = (LegacySampleBank)int.Parse(split[3]);
//SampleBank sampleBank = SampleBank.Default;
//if (split.Length >= 5)
// sampleBank = (SampleBank)int.Parse(split[4]);
int sampleVolume = defaultSampleVolume;
if (split.Length >= 6)
sampleVolume = int.Parse(split[5]);
bool timingChange = true;
if (split.Length >= 7)
timingChange = split[6][0] == '1';
bool kiaiMode = false;
bool omitFirstBarSignature = false;
if (split.Length >= 8)
{
int effectFlags = split.Length > 7 ? Convert.ToInt32(split[7], NumberFormatInfo.InvariantInfo) : 0;
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
cp = new ControlPoint
{
Time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo),
BeatLength = beatLength > 0 ? beatLength : 0,
SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
TimingChange = split.Length <= 6 || split[6][0] == '1',
KiaiMode = (effectFlags & 1) > 0,
OmitFirstBarLine = (effectFlags & 8) > 0,
TimeSignature = (TimeSignatures)int.Parse(split[2])
};
int effectFlags = int.Parse(split[7]);
kiaiMode = (effectFlags & 1) > 0;
omitFirstBarSignature = (effectFlags & 8) > 0;
}
if (cp != null)
beatmap.TimingInfo.ControlPoints.Add(cp);
string stringSampleSet = sampleSet.ToString().ToLower();
if (stringSampleSet == @"none")
stringSampleSet = @"normal";
beatmap.TimingInfo.ControlPoints.Add(new ControlPoint
{
Time = time,
BeatLength = beatLength,
SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
TimingChange = timingChange,
TimeSignature = timeSignature,
SampleBank = stringSampleSet,
SampleVolume = sampleVolume,
KiaiMode = kiaiMode,
OmitFirstBarLine = omitFirstBarSignature
});
}
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
@ -271,7 +304,7 @@ namespace osu.Game.Beatmaps.Formats
{
beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion;
HitObjectParser parser = null;
HitObjectParser parser = new LegacyHitObjectParser();
Section section = Section.None;
bool hasCustomColours = false;
@ -305,7 +338,6 @@ namespace osu.Game.Beatmaps.Formats
{
case Section.General:
handleGeneral(beatmap, key, val);
parser = new LegacyHitObjectParser();
break;
case Section.Editor:
handleEditor(beatmap, key, val);
@ -326,7 +358,7 @@ namespace osu.Game.Beatmaps.Formats
handleColours(beatmap, key, val, ref hasCustomColours);
break;
case Section.HitObjects:
var obj = parser?.Parse(val);
var obj = parser.Parse(val);
if (obj != null)
beatmap.HitObjects.Add(obj);
@ -335,5 +367,13 @@ namespace osu.Game.Beatmaps.Formats
}
}
}
internal enum LegacySampleBank
{
None = 0,
Normal = 1,
Soft = 2,
Drum = 3
}
}
}

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 { get; set; }
}
}

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 enum SampleBank
{
Default = 0,
Custom1 = 1,
Custom2 = 2
}
}

View File

@ -1,11 +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;
}
}

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 +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
using System;
namespace osu.Game.Beatmaps.Samples
{
[Flags]
public enum SampleType
{
None = 0,
Normal = 1,
Whistle = 2,
Finish = 4,
Clap = 8
};
}

View File

@ -5,6 +5,8 @@ namespace osu.Game.Beatmaps.Timing
{
public class ControlPoint
{
public string SampleBank;
public int SampleVolume;
public TimeSignatures TimeSignature;
public double Time;
public double BeatLength = 500;

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
using osu.Game.Beatmaps.Samples;
namespace osu.Game.Beatmaps.Timing
{
public class SampleChange : ControlPoint
{
public SampleInfo Sample;
}
}

View File

@ -1,15 +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.Timing
{
internal class TimingChange : ControlPoint
{
public TimingChange(double beatLength)
{
BeatLength = beatLength;
}
public double BPM => 60000 / BeatLength;
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
@ -47,7 +46,6 @@ namespace osu.Game.Database
// General
public int AudioLeadIn { get; set; }
public bool Countdown { get; set; }
public SampleSet SampleSet { get; set; }
public float StackLeniency { get; set; }
public bool SpecialStyle { get; set; }
public PlayMode Mode { get; set; }

View File

@ -7,11 +7,11 @@ using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Judgements;
using Container = osu.Framework.Graphics.Containers.Container;
using osu.Game.Modes.Objects.Types;
using OpenTK.Graphics;
using osu.Game.Audio;
namespace osu.Game.Modes.Objects.Drawables
{
@ -45,15 +45,15 @@ namespace osu.Game.Modes.Objects.Drawables
UpdateState(state);
if (State == ArmedState.Hit)
PlaySample();
PlaySamples();
}
}
protected SampleChannel Sample;
protected List<SampleChannel> Samples = new List<SampleChannel>();
protected virtual void PlaySample()
protected void PlaySamples()
{
Sample?.Play();
Samples.ForEach(s => s?.Play());
}
[BackgroundDependencyLoader]
@ -156,13 +156,16 @@ namespace osu.Game.Modes.Objects.Drawables
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
SampleType type = HitObject.Sample?.Type ?? SampleType.None;
if (type == SampleType.None)
type = SampleType.Normal;
foreach (SampleInfo sample in HitObject.Samples)
{
SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}");
SampleSet sampleSet = HitObject.Sample?.Set ?? SampleSet.Normal;
if (channel == null)
continue;
Sample = audio.Sample.Get($@"Gameplay/{sampleSet.ToString().ToLower()}-hit{type.ToString().ToLower()}");
channel.Volume.Value = sample.Volume;
Samples.Add(channel);
}
}
private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects;

View File

@ -1,9 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Samples;
using osu.Game.Audio;
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using System.Collections.Generic;
namespace osu.Game.Modes.Objects
{
@ -21,15 +22,31 @@ namespace osu.Game.Modes.Objects
public double StartTime { get; set; }
/// <summary>
/// The sample to be played when this HitObject is hit.
/// The samples to be played when this hit object is hit.
/// </summary>
public HitSampleInfo Sample { get; set; }
public List<SampleInfo> Samples = new List<SampleInfo>();
/// <summary>
/// Applies default values to this HitObject.
/// </summary>
/// <param name="difficulty">The difficulty settings to use.</param>
/// <param name="timing">The timing settings to use.</param>
public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty) { }
public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
ControlPoint overridePoint;
ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
foreach (var sample in Samples)
{
if (sample.Volume == 0)
sample.Volume = (overridePoint ?? timingPoint)?.SampleVolume ?? 0;
// If the bank is not assigned a name, assign it from the control point
if (!string.IsNullOrEmpty(sample.Bank))
continue;
sample.Bank = (overridePoint ?? timingPoint)?.SampleBank ?? @"normal";
}
}
}
}

View File

@ -2,12 +2,13 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Types;
using System;
using System.Collections.Generic;
using System.Globalization;
using osu.Game.Modes.Objects.Legacy;
using osu.Game.Beatmaps.Formats;
using osu.Game.Audio;
namespace osu.Game.Modes.Objects
{
@ -20,6 +21,10 @@ namespace osu.Game.Modes.Objects
bool combo = type.HasFlag(LegacyHitObjectType.NewCombo);
type &= ~LegacyHitObjectType.NewCombo;
int sampleVolume = 0;
string normalSampleBank = null;
string addSampleBank = null;
HitObject result;
if ((type & LegacyHitObjectType.Circle) > 0)
@ -29,6 +34,9 @@ namespace osu.Game.Modes.Objects
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
NewCombo = combo
};
if (split.Length > 5)
readCustomSampleBanks(split[5], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Slider) > 0)
{
@ -84,6 +92,9 @@ namespace osu.Game.Modes.Objects
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
NewCombo = combo
};
if (split.Length > 10)
readCustomSampleBanks(split[10], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Spinner) > 0)
{
@ -91,10 +102,17 @@ namespace osu.Game.Modes.Objects
{
EndTime = Convert.ToDouble(split[5], CultureInfo.InvariantCulture)
};
if (split.Length > 6)
readCustomSampleBanks(split[6], ref normalSampleBank, ref addSampleBank, ref sampleVolume);
}
else if ((type & LegacyHitObjectType.Hold) > 0)
{
// Note: Hold is generated by BMS converts
// Todo: Apparently end time is determined by samples??
// Shouldn't need implementation until mania
result = new LegacyHold
{
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])),
@ -105,15 +123,82 @@ namespace osu.Game.Modes.Objects
throw new InvalidOperationException($@"Unknown hit object type {type}");
result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
result.Sample = new HitSampleInfo
{
Type = (SampleType)int.Parse(split[4]),
Set = SampleSet.Soft,
};
// TODO: "addition" field
var soundType = (LegacySoundType)int.Parse(split[4]);
result.Samples.Add(new SampleInfo
{
Bank = normalSampleBank,
Name = SampleInfo.HIT_NORMAL,
Volume = sampleVolume
});
if ((soundType & LegacySoundType.Finish) > 0)
{
result.Samples.Add(new SampleInfo
{
Bank = addSampleBank,
Name = SampleInfo.HIT_FINISH,
Volume = sampleVolume
});
}
if ((soundType & LegacySoundType.Whistle) > 0)
{
result.Samples.Add(new SampleInfo
{
Bank = addSampleBank,
Name = SampleInfo.HIT_WHISTLE,
Volume = sampleVolume
});
}
if ((soundType & LegacySoundType.Clap) > 0)
{
result.Samples.Add(new SampleInfo
{
Bank = addSampleBank,
Name = SampleInfo.HIT_CLAP,
Volume = sampleVolume
});
}
return result;
}
private void readCustomSampleBanks(string str, ref string normalSampleBank, ref string addSampleBank, ref int sampleVolume)
{
if (string.IsNullOrEmpty(str))
return;
string[] split = str.Split(':');
var bank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]);
var addbank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]);
// Let's not implement this for now, because this doesn't fit nicely into the bank structure
//string sampleFile = split2.Length > 4 ? split2[4] : string.Empty;
string stringBank = bank.ToString().ToLower();
if (stringBank == @"none")
stringBank = null;
string stringAddBank = addbank.ToString().ToLower();
if (stringAddBank == @"none")
stringAddBank = null;
normalSampleBank = stringBank;
addSampleBank = stringAddBank;
sampleVolume = split.Length > 3 ? int.Parse(split[3]) : 0;
}
[Flags]
private enum LegacySoundType
{
None = 0,
Normal = 1,
Whistle = 2,
Finish = 4,
Clap = 8
}
}
}

View File

@ -71,6 +71,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Audio\SampleInfo.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
<Compile Include="Beatmaps\IBeatmapCoverter.cs" />
@ -148,14 +149,7 @@
<Compile Include="Beatmaps\Drawables\Panel.cs" />
<Compile Include="Modes\Objects\Drawables\DrawableHitObject.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\SampleChange.cs" />
<Compile Include="Beatmaps\Timing\TimingChange.cs" />
<Compile Include="Configuration\OsuConfigManager.cs" />
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
<Compile Include="Overlays\Notifications\Notification.cs" />