From 310c4a7d6c04213b93a38082a3a225533a3cdc0d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Jul 2018 14:18:41 +0900 Subject: [PATCH 1/6] Make SampleInfo choose its own lookup name --- osu.Game/Audio/SampleInfo.cs | 7 +++++++ osu.Game/Skinning/SkinnableSound.cs | 18 ++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 53b6e439f5..7906a6012f 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; namespace osu.Game.Audio { @@ -33,6 +34,12 @@ namespace osu.Game.Audio /// public int Volume; + public virtual IEnumerable LookupNames => new[] + { + $"{Namespace}/{Bank}-{Name}", + $"{Bank}-{Name}" // Without namespace as a fallback + }; + public SampleInfo Clone() => (SampleInfo)MemberwiseClone(); } } diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 1a11b0c03e..2fc9cff463 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -44,19 +44,17 @@ namespace osu.Game.Skinning private SampleChannel loadChannel(SampleInfo info, Func getSampleFunction) { - SampleChannel ch = null; + foreach (var lookup in info.LookupNames) + { + var ch = getSampleFunction($"Gameplay/{lookup}"); + if (ch == null) + continue; - if (info.Namespace != null) - ch = getSampleFunction($"Gameplay/{info.Namespace}/{info.Bank}-{info.Name}"); - - // try without namespace as a fallback. - if (ch == null) - ch = getSampleFunction($"Gameplay/{info.Bank}-{info.Name}"); - - if (ch != null) ch.Volume.Value = info.Volume / 100.0; + return ch; + } - return ch; + return null; } } } From 73fac2115a286570e8673d0be0194a45037c8e61 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Jul 2018 14:20:35 +0900 Subject: [PATCH 2/6] Implement hitobject sample files --- .../Objects/Legacy/ConvertHitObjectParser.cs | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 9edd0f1f34..8a996cfe30 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -6,6 +6,7 @@ using osu.Game.Rulesets.Objects.Types; using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using osu.Game.Beatmaps.Formats; using osu.Game.Audio; using System.Linq; @@ -196,8 +197,7 @@ namespace osu.Game.Rulesets.Objects.Legacy var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]); var addbank = (LegacyBeatmapDecoder.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; + bankInfo.Filename = split.Length > 4 ? split[4] : null; string stringBank = bank.ToString().ToLower(); if (stringBank == @"none") @@ -252,6 +252,10 @@ namespace osu.Game.Rulesets.Objects.Legacy private List convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) { + // Todo: This should return the normal SampleInfos if the specified sample file isn't found, but that's a pretty edge-case scenario + if (!string.IsNullOrEmpty(bankInfo.Filename)) + return new List { new FileSampleInfo { Filename = bankInfo.Filename } }; + var soundTypes = new List { new SampleInfo @@ -297,14 +301,24 @@ namespace osu.Game.Rulesets.Objects.Legacy private class SampleBankInfo { + public string Filename; + public string Normal; public string Add; public int Volume; - public SampleBankInfo Clone() + public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone(); + } + + private class FileSampleInfo : SampleInfo + { + public string Filename; + + public override IEnumerable LookupNames => new[] { - return (SampleBankInfo)MemberwiseClone(); - } + Filename, + Path.ChangeExtension(Filename, null) + }; } [Flags] From 7f832e34c05fab9975b83f8b4f7a8e175510fd60 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Jul 2018 14:29:18 +0900 Subject: [PATCH 3/6] Reorder sample bank property setters --- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 8a996cfe30..95589d8953 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -197,8 +197,6 @@ namespace osu.Game.Rulesets.Objects.Legacy var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]); var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]); - bankInfo.Filename = split.Length > 4 ? split[4] : null; - string stringBank = bank.ToString().ToLower(); if (stringBank == @"none") stringBank = null; @@ -211,6 +209,8 @@ namespace osu.Game.Rulesets.Objects.Legacy if (split.Length > 3) bankInfo.Volume = int.Parse(split[3]); + + bankInfo.Filename = split.Length > 4 ? split[4] : null; } /// From 189194ee8d3e36261152760dc66a7437ec8adf49 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Jul 2018 14:35:03 +0900 Subject: [PATCH 4/6] Don't include empty namespace in sample lookup --- osu.Game/Audio/SampleInfo.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 7906a6012f..3d76184e09 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -34,11 +34,16 @@ namespace osu.Game.Audio /// public int Volume; - public virtual IEnumerable LookupNames => new[] + public virtual IEnumerable LookupNames { - $"{Namespace}/{Bank}-{Name}", - $"{Bank}-{Name}" // Without namespace as a fallback - }; + get + { + if (!string.IsNullOrEmpty(Namespace)) + yield return $"{Namespace}/{Bank}-{Name}"; + + yield return $"{Bank}-{Name}"; // Without namespace as a fallback even when we have a namespace + } + } public SampleInfo Clone() => (SampleInfo)MemberwiseClone(); } From c1b8799253e4ab2f4789306308925b9b20be326a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Jul 2018 14:40:43 +0900 Subject: [PATCH 5/6] Add simple testcase --- .../Formats/LegacyBeatmapDecoderTest.cs | 18 ++++++++++++++++++ .../Resources/custom-hitobject-samples.osu | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 osu.Game.Tests/Resources/custom-hitobject-samples.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index d3c61960bb..ad203d2107 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -230,5 +230,23 @@ namespace osu.Game.Tests.Beatmaps.Formats SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" }); } + + [Test] + public void TestDecodeCustomHitObjectSamples() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + using (var resStream = Resource.OpenResource("custom-hitobject-samples.osu")) + using (var stream = new StreamReader(resStream)) + { + var hitObjects = decoder.Decode(stream).HitObjects; + + Assert.AreEqual("hit_1.wav", hitObjects[0].Samples[0].LookupNames.First()); + Assert.AreEqual("hit_2.wav", hitObjects[1].Samples[0].LookupNames.First()); + Assert.AreEqual("hitnormal2", getTestableSampleInfo(hitObjects[2]).Name); + Assert.AreEqual("hit_1.wav", hitObjects[3].Samples[0].LookupNames.First()); + } + + SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(new SampleInfo { Name = "hitnormal" }); + } } } diff --git a/osu.Game.Tests/Resources/custom-hitobject-samples.osu b/osu.Game.Tests/Resources/custom-hitobject-samples.osu new file mode 100644 index 0000000000..588672e2d9 --- /dev/null +++ b/osu.Game.Tests/Resources/custom-hitobject-samples.osu @@ -0,0 +1,16 @@ +osu file format v14 + +[General] +SampleSet: Normal + +[TimingPoints] +2170,468.75,4,1,0,40,1,0 +2638,-100,4,1,1,40,0,0 +3107,-100,4,1,2,40,0,0 +3576,-100,4,1,0,40,0,0 + +[HitObjects] +255,193,2170,1,0,0:0:0:0:hit_1.wav +256,191,2638,5,0,0:0:0:0:hit_2.wav +255,193,3107,1,0,0:0:0:0: +256,191,3576,1,0,0:0:0:0:hit_1.wav From 8f04acc506bf5ae4474897f0f420d43583e4fcee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Jul 2018 20:16:55 +0900 Subject: [PATCH 6/6] Add missing xmldoc --- osu.Game/Audio/SampleInfo.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 3d76184e09..7e329ac651 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -34,6 +34,9 @@ namespace osu.Game.Audio /// public int Volume; + /// + /// Retrieve all possible filenames that can be used as a source, returned in order of preference (highest first). + /// public virtual IEnumerable LookupNames { get