From 6c63e18be00b09ba8430bfe656db65ab533c3f79 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Thu, 3 Jun 2021 23:37:40 +0900 Subject: [PATCH 1/3] Fix might cause crash if new value is null. Might happen if switch to view mode. --- .../Edit/Lyrics/Extends/RubyRomaji/RomajiTagEditSection.cs | 2 +- .../Edit/Lyrics/Extends/RubyRomaji/RubyTagEditSection.cs | 2 +- .../Edit/Lyrics/Extends/RubyRomaji/TextTagEditSection.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RomajiTagEditSection.cs b/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RomajiTagEditSection.cs index 2b09f6084..f3c34b899 100644 --- a/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RomajiTagEditSection.cs +++ b/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RomajiTagEditSection.cs @@ -15,7 +15,7 @@ private void load(ILyricEditorState state) { state.BindableCaretPosition.BindValueChanged(e => { - Lyric = e.NewValue.Lyric; + Lyric = e.NewValue?.Lyric; if (e.OldValue?.Lyric != null) { diff --git a/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RubyTagEditSection.cs b/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RubyTagEditSection.cs index 6f73f79fd..3e6cafbd8 100644 --- a/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RubyTagEditSection.cs +++ b/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/RubyTagEditSection.cs @@ -15,7 +15,7 @@ private void load(ILyricEditorState state) { state.BindableCaretPosition.BindValueChanged(e => { - Lyric = e.NewValue.Lyric; + Lyric = e.NewValue?.Lyric; if (e.OldValue?.Lyric != null) { diff --git a/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/TextTagEditSection.cs b/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/TextTagEditSection.cs index 92537af03..76cb562bd 100644 --- a/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/TextTagEditSection.cs +++ b/osu.Game.Rulesets.Karaoke/Edit/Lyrics/Extends/RubyRomaji/TextTagEditSection.cs @@ -32,7 +32,7 @@ protected TextTagEditSection() TextTags.BindValueChanged(e => { Content.RemoveAll(x => x is LabelledTextTagTextBox); - Content.AddRange(e.NewValue.Select(x => + Content.AddRange(e.NewValue?.Select(x => { var relativeToLyricText = TextTagUtils.GetTextFromLyric(x, Lyric?.Text); var range = TextTagUtils.PositionFormattedString(x); From 5bde7601e7efe9421509c7e6eb6d9053411be326 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Jun 2021 16:02:34 +0900 Subject: [PATCH 2/3] update nuget package. --- osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj b/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj index 60d44b8f0..40d28c312 100644 --- a/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj +++ b/osu.Game.Rulesets.Karaoke/osu.Game.Rulesets.Karaoke.csproj @@ -13,7 +13,7 @@ - + From b199c139449b3bab4a3e8015ffc13af7aa979404 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Jun 2021 19:47:02 +0900 Subject: [PATCH 3/3] Fix time-tag should be in the right position while parsing lyric. --- .../Beatmaps/Formats/LrcDecoderTest.cs | 48 ++++++++++--------- .../Utils/LyricUtilsTest.cs | 15 +++++- .../Beatmaps/Formats/LrcDecoder.cs | 2 +- .../Beatmaps/Formats/LrcEncoder.cs | 14 +++++- osu.Game.Rulesets.Karaoke/Utils/LyricUtils.cs | 6 +-- 5 files changed, 56 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs index 09d7e4f24..fca698d02 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs @@ -9,49 +9,51 @@ using osu.Game.IO; using osu.Game.Rulesets.Karaoke.Beatmaps.Formats; using osu.Game.Rulesets.Karaoke.Objects; -using osu.Game.Rulesets.Karaoke.Utils; +using osu.Game.Rulesets.Karaoke.Tests.Asserts; +using osu.Game.Rulesets.Karaoke.Tests.Helper; namespace osu.Game.Rulesets.Karaoke.Tests.Beatmaps.Formats { [TestFixture] public class LrcDecoderTest { - [Test] - public void TestDecodeLyric() + [TestCase("[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]", "からおけ", 1000, 5000)] + public void TestLyricTextAndTime(string lyricText, string text, double startTime, double endTime) { - const string lyric_text = "[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]"; - var beatmap = decodeLrcLine(lyric_text); + var beatmap = decodeLrcLine(lyricText); - // Get first beatmap + // Get first lyric from beatmap var lyric = beatmap.HitObjects.OfType().FirstOrDefault(); // Check lyric - Assert.AreEqual(lyric?.Text, "からおけ"); - Assert.AreEqual(lyric?.StartTime, 1000); - Assert.AreEqual(lyric?.EndTime, 5000); + Assert.AreEqual(lyric?.Text, text); + Assert.AreEqual(lyric?.StartTime, startTime); + Assert.AreEqual(lyric?.EndTime, endTime); + } + + [TestCase("[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]", new[] { "[0,start]:1000", "[1,start]:2000", "[2,start]:3000", "[3,start]:4000", "[3,end]:5000" })] + public void TestLyricTimeTag(string text, string[] timeTags) + { + var beatmap = decodeLrcLine(text); + + // Get first lyric from beatmap + var lyric = beatmap.HitObjects.OfType().FirstOrDefault(); // Check time tag - var tags = TimeTagsUtils.ToDictionary(lyric?.TimeTags); - var checkedTags = tags.ToArray(); - Assert.AreEqual(tags.Count, 5); - Assert.AreEqual(checkedTags.Length, 5); - Assert.AreEqual(string.Join(',', tags.Select(x => x.Key.Index)), "0,1,2,3,4"); - Assert.AreEqual(string.Join(',', tags.Select(x => x.Value)), "1000,2000,3000,4000,5000"); + TimeTagAssert.ArePropertyEqual(lyric?.TimeTags, TestCaseTagHelper.ParseTimeTags(timeTags)); } - [Test] - public void TestDecodeLyricWithDuplicatedTimeTag() + [TestCase("[00:04.00]か[00:04.00]ら[00:05.00]お[00:06.00]け[00:07.00]")] + public void TestDecodeLyricWithDuplicatedTimeTag(string text) { - const string wrong_lyric_text = "[00:04.00]か[00:04.00]ら[00:05.00]お[00:06.00]け[00:07.00]"; - Assert.Throws(() => decodeLrcLine(wrong_lyric_text)); + Assert.Throws(() => decodeLrcLine(text)); } - [Test] [Ignore("Waiting for lyric parser update.")] - public void TestDecodeLyricWithTimeTagNotOrder() + [TestCase("[00:04.00]か[00:03.00]ら[00:02.00]お[00:01.00]け[00:00.00]")] + public void TestDecodeLyricWithTimeTagNotOrder(string text) { - const string wrong_lyric_text = "[00:04.00]か[00:03.00]ら[00:02.00]お[00:01.00]け[00:00.00]"; - Assert.Throws(() => decodeLrcLine(wrong_lyric_text)); + Assert.Throws(() => decodeLrcLine(text)); } private static Beatmap decodeLrcLine(string line) diff --git a/osu.Game.Rulesets.Karaoke.Tests/Utils/LyricUtilsTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Utils/LyricUtilsTest.cs index 1b2c92b1e..4e2777531 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Utils/LyricUtilsTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Utils/LyricUtilsTest.cs @@ -23,7 +23,7 @@ public class LyricUtilsTest [TestCase("カラオケ", 0, 100, "")] // test end position not in the range [TestCase("", 0, 0, "")] [TestCase(null, 0, 0, null)] - public void TestRemoveTextText(string text, int position, int count, string actualText) + public void TestRemoveText(string text, int position, int count, string actualText) { try { @@ -142,6 +142,19 @@ public void TestAddTextTimeTag(string[] timeTags, int position, string addedText #region create default + [TestCase(new[] { "[0,start]:1000", "[1,start]:2000", "[2,start]:3000", "[3,start]:4000", "[3,end]:5000" }, new[] { "カ", "ラ", "オ", "ケ" })] + public void TestCreateDefaultNotes(string[] timeTags, string[] noteTexts) + { + var lyric = new Lyric + { + Text = "カラオケ", + TimeTags = TestCaseTagHelper.ParseTimeTags(timeTags), + }; + + var notes = LyricUtils.CreateDefaultNotes(lyric); + Assert.AreEqual(notes.Select(x => x.Text).ToArray(), noteTexts); + } + #endregion #region Time tag diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs index a88058953..7a974ee18 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs @@ -44,7 +44,7 @@ protected override void ParseStreamInto(LineBufferedReader stream, Beatmap outpu var lrcTimeTag = line.TimeTags; var timeTags = line.TimeTags.Where(x => x.Check).ToDictionary(k => { - var index = (int)Math.Ceiling((double)(Array.IndexOf(lrcTimeTag, k) - 1) / 2); + var index = (Array.IndexOf(lrcTimeTag, k) - 1) / 2; var state = (Array.IndexOf(lrcTimeTag, k) - 1) % 2 == 0 ? TextIndex.IndexState.Start : TextIndex.IndexState.End; return new TextIndex(index, state); }, v => (double)v.Time); diff --git a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcEncoder.cs b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcEncoder.cs index 12aed9dda..4ed9afe61 100644 --- a/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcEncoder.cs +++ b/osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcEncoder.cs @@ -34,13 +34,23 @@ private LyricLine encodeLyric(Objects.Lyric lyric) => private IEnumerable convertTimeTag(string text, IReadOnlyDictionary tags) { + // total time-tag amount in lyric maker. var totalTags = text.Length * 2 + 2; for (int i = 0; i < totalTags; i++) { + // should return empty tag if no time-tag in lyric. + if (tags.Count == 0) + { + yield return new TimeTag(); + + continue; + } + var (lastTag, lastTagTime) = tags.LastOrDefault(); - if (lastTag.Index * 2 == i) + // create end time-tag + if ((lastTag.Index + 1) * 2 == i) { yield return new TimeTag { @@ -54,6 +64,7 @@ private IEnumerable convertTimeTag(string text, IReadOnlyDictionary x.Key.Index * 2 + 1 == i); + // create start time-tag if (firstTagTime > 0 && firstTag != lastTag) { yield return new TimeTag @@ -66,6 +77,7 @@ private IEnumerable convertTimeTag(string text, IReadOnlyDictionary CreateDefaultNotes(Lyric lyric) var startTime = timeTag.Value; int startIndex = timeTag.Key.Index; - int endIndex = key.Index; + int endIndex = TextIndexUtils.ToStringIndex(key); var text = lyric.Text[startIndex..endIndex]; var ruby = lyric.RubyTags?.Where(x => x.StartIndex == startIndex && x.EndIndex == endIndex).FirstOrDefault()?.Text; @@ -184,9 +184,9 @@ public static string GetTimeTagIndexDisplayText(Lyric lyric, TextIndex index) if (index.State == TextIndex.IndexState.Start) { - var previousTimeTag = timeTags.FirstOrDefault(x => x.Index > index); + var nextTimeTag = timeTags.FirstOrDefault(x => x.Index > index); var startIndex = index.Index; - var endIndex = previousTimeTag?.Index.Index ?? text.Length; + var endIndex = TextIndexUtils.ToStringIndex(nextTimeTag?.Index ?? new TextIndex(text.Length)); return $"{text.Substring(startIndex, endIndex - startIndex)}-"; }