Skip to content

Commit

Permalink
Fix time-tag should be in the right position while parsing lyric.
Browse files Browse the repository at this point in the history
  • Loading branch information
andy840119 committed Jun 5, 2021
1 parent 5bde760 commit b199c13
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 29 deletions.
48 changes: 25 additions & 23 deletions osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcDecoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Lyric>().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<Lyric>().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<FormatException>(() => decodeLrcLine(wrong_lyric_text));
Assert.Throws<FormatException>(() => 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<FormatException>(() => decodeLrcLine(wrong_lyric_text));
Assert.Throws<FormatException>(() => decodeLrcLine(text));
}

private static Beatmap decodeLrcLine(string line)
Expand Down
15 changes: 14 additions & 1 deletion osu.Game.Rulesets.Karaoke.Tests/Utils/LyricUtilsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 13 additions & 1 deletion osu.Game.Rulesets.Karaoke/Beatmaps/Formats/LrcEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,23 @@ private LyricLine encodeLyric(Objects.Lyric lyric) =>

private IEnumerable<TimeTag> convertTimeTag(string text, IReadOnlyDictionary<TextIndex, double> 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
{
Expand All @@ -54,6 +64,7 @@ private IEnumerable<TimeTag> convertTimeTag(string text, IReadOnlyDictionary<Tex

var (firstTag, firstTagTime) = tags.FirstOrDefault(x => x.Key.Index * 2 + 1 == i);

// create start time-tag
if (firstTagTime > 0 && firstTag != lastTag)
{
yield return new TimeTag
Expand All @@ -66,6 +77,7 @@ private IEnumerable<TimeTag> convertTimeTag(string text, IReadOnlyDictionary<Tex
continue;
}

// if has no match tag in lyric, should return empty one.
yield return new TimeTag();
}
}
Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Rulesets.Karaoke/Utils/LyricUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public static IEnumerable<Note> 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;
Expand Down Expand Up @@ -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)}-";
}

Expand Down

0 comments on commit b199c13

Please sign in to comment.