Skip to content

Commit

Permalink
Merge pull request #2268 from andy840119/move-lrc-parser-logic-into-i…
Browse files Browse the repository at this point in the history
…ndividual-class

Replace all the `.lrc` file support to `.kar`
  • Loading branch information
andy840119 authored Aug 10, 2024
2 parents 6d45b0b + c5e9220 commit 55e7a30
Show file tree
Hide file tree
Showing 33 changed files with 473 additions and 262 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ private static KaraokeBeatmap decodeBeatmap(string fileName)
using var stream = new LineBufferedReader(resStream);

// Create karaoke beatmap decoder
var lrcDecoder = new KaraokeLegacyBeatmapDecoder();
var decoder = new KaraokeLegacyBeatmapDecoder();

// Create initial beatmap
var beatmap = lrcDecoder.Decode(stream);
var beatmap = decoder.Decode(stream);

// Convert to karaoke beatmap
return (KaraokeBeatmap)new KaraokeBeatmapConverter(beatmap, new KaraokeRuleset()).Convert();
Expand Down
74 changes: 0 additions & 74 deletions osu.Game.Rulesets.Karaoke.Tests/Beatmaps/Formats/LrcEncoderTest.cs

This file was deleted.

17 changes: 3 additions & 14 deletions osu.Game.Rulesets.Karaoke.Tests/Helper/TestCaseTagHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using osu.Framework.Graphics.Sprites;
using osu.Game.IO;
using osu.Game.Rulesets.Karaoke.Beatmaps;
using osu.Game.Rulesets.Karaoke.Beatmaps.Formats;
using osu.Game.Rulesets.Karaoke.Beatmaps.Metadatas;
using osu.Game.Rulesets.Karaoke.Extensions;
using osu.Game.Rulesets.Karaoke.Integration.Formats;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Tests.Extensions;

Expand Down Expand Up @@ -203,18 +201,9 @@ public static Lyric ParseLyricWithTimeTag(string? str)
if (string.IsNullOrEmpty(str))
return new Lyric();

using var stream = new MemoryStream();
using var writer = new StreamWriter(stream);
using var reader = new LineBufferedReader(stream);

// Create stream
writer.Write(str);
writer.Flush();
stream.Position = 0;

// Create karaoke note decoder
var decoder = new LrcDecoder();
return decoder.Decode(reader).HitObjects.OfType<Lyric>().First();
var decoder = new KarDecoder();
return decoder.Decode(str).First();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.IO;
using osu.Game.Rulesets.Karaoke.Beatmaps.Formats;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Integration.Formats;
using osu.Game.Rulesets.Karaoke.Tests.Asserts;
using osu.Game.Rulesets.Karaoke.Tests.Helper;

namespace osu.Game.Rulesets.Karaoke.Tests.Beatmaps.Formats;
namespace osu.Game.Rulesets.Karaoke.Tests.Integration.Formats;

[TestFixture]
public class LrcDecoderTest
public class KarDecoderTest
{
[TestCase("[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]", "からおけ", 1000, 5000)]
public void TestLyricTextAndTime(string lyricText, string expectedText, double expectedStartTime, double expectedEndTime)
{
var beatmap = decodeLrcLine(lyricText);

// Get first lyric from beatmap
var actual = beatmap.HitObjects.OfType<Lyric>().FirstOrDefault()!;
var lyrics = new KarDecoder().Decode(lyricText);
var actual = lyrics.FirstOrDefault()!;

Assert.IsNotNull(actual);
Assert.AreEqual(expectedText, actual.Text);
Assert.AreEqual(expectedStartTime, actual.LyricTimingInfo?.StartTime);
Expand All @@ -34,8 +29,8 @@ public void TestLyricTextAndTime(string lyricText, string expectedText, double e
public void TestLyricTimeTag(string text, string[] timeTags)
{
// Get first lyric from beatmap
var beatmap = decodeLrcLine(text);
var lyric = beatmap.HitObjects.OfType<Lyric>().FirstOrDefault();
var lyrics = new KarDecoder().Decode(text);
var lyric = lyrics.FirstOrDefault()!;

// Check time tag
var expected = TestCaseTagHelper.ParseTimeTags(timeTags);
Expand All @@ -47,29 +42,13 @@ public void TestLyricTimeTag(string text, string[] timeTags)
[TestCase("[00:04.00]か[00:04.00]ら[00:05.00]お[00:06.00]け[00:07.00]")]
public void TestDecodeLyricWithDuplicatedTimeTag(string text)
{
Assert.Throws<FormatException>(() => decodeLrcLine(text));
Assert.Throws<FormatException>(() => new KarDecoder().Decode(text));
}

[Ignore("Waiting for lyric parser update.")]
[TestCase("[00:04.00]か[00:03.00]ら[00:02.00]お[00:01.00]け[00:00.00]")]
public void TestDecodeLyricWithTimeTagNotOrder(string text)
{
Assert.Throws<FormatException>(() => decodeLrcLine(text));
}

private static Beatmap decodeLrcLine(string line)
{
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream);
using var reader = new LineBufferedReader(stream);

// Create stream
writer.Write(line);
writer.Flush();
stream.Position = 0;

// Create karaoke note decoder
var decoder = new LrcDecoder();
return decoder.Decode(reader);
Assert.Throws<FormatException>(() => new KarDecoder().Decode(text));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Karaoke.Integration.Formats;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Tests.Helper;
using osu.Game.Rulesets.Objects;

namespace osu.Game.Rulesets.Karaoke.Tests.Integration.Formats;

public class KarEncoderTest
{
[TestCase("からおけ", new string[] { }, "からおけ")]
[TestCase("からおけ", new[] { "[0,start]:1000", "[1,start]:2000", "[2,start]:3000", "[3,start]:4000", "[3,end]:5000" }, "[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]")]
public void TestLyricWithTimeTag(string lyricText, string[] timeTags, string expected)
{
var lyric = new Lyric
{
Text = lyricText,
TimeTags = TestCaseTagHelper.ParseTimeTags(timeTags),
};

string actual = new KarEncoder().Encode(new Beatmap
{
HitObjects = new List<HitObject>
{
lyric,
},
});

Assert.AreEqual(actual, expected);
}
}
61 changes: 61 additions & 0 deletions osu.Game.Rulesets.Karaoke.Tests/Integration/Formats/KarFileTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.IO;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets.Karaoke.Integration.Formats;
using osu.Game.Rulesets.Karaoke.Tests.Resources;
using osu.Game.Rulesets.Objects;

namespace osu.Game.Rulesets.Karaoke.Tests.Integration.Formats;

public class KarFileTest
{
private static IEnumerable<string> allKarFileNames => TestResources.GetStore().GetAvailableResources()
.Where(res => res.EndsWith(".kar", StringComparison.Ordinal)).Select(x => Path.GetFileNameWithoutExtension(x!));

[TestCaseSource(nameof(allKarFileNames))]
public void TestDecodeEncodedBeatmap(string fileName)
{
var decoded = decode(fileName, out var encoded);

// Note : this test case does not cover ruby property
Assert.That(decoded.HitObjects.Count, Is.EqualTo(encoded.HitObjects.Count));
Assert.That(encoded.Serialize(), Is.EqualTo(decoded.Serialize()));
}

private static Beatmap decode(string filename, out Beatmap encoded)
{
using var stream = TestResources.OpenKarResource(filename);
using var sr = new LineBufferedReader(stream);

// Read file and decode to file
var legacyDecoded = new Beatmap
{
HitObjects = new KarDecoder().Decode(sr.ReadToEnd()).OfType<HitObject>().ToList(),
};

using var ms = new MemoryStream();
using var sw = new StreamWriter(ms);
using var sr2 = new LineBufferedReader(ms);

// Then encode file to stream
string encodeResult = new KarEncoder().Encode(legacyDecoded);
sw.WriteLine(encodeResult);
sw.Flush();

ms.Position = 0;

encoded = new Beatmap
{
HitObjects = new KarDecoder().Decode(sr2.ReadToEnd()).OfType<HitObject>().ToList(),
};
return legacyDecoded;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Karaoke.Integration.Formats;
using osu.Game.Rulesets.Karaoke.Objects;
using osu.Game.Rulesets.Karaoke.Tests.Helper;
using osu.Game.Rulesets.Objects;

namespace osu.Game.Rulesets.Karaoke.Tests.Integration.Formats;

public class LrcDecoderTest
{
[TestCase("からおけ", new string[] { }, "[00:00.00] からおけ")] // todo: handle the start time.
[TestCase("からおけ", new[] { "[0,start]:1000", "[1,start]:2000", "[2,start]:3000", "[3,start]:4000", "[3,end]:5000" }, "[00:00.00] <00:01.00>か<00:02.00>ら<00:03.00>お<00:04.00>け<00:05.00>")]
public void TestLyricWithTimeTag(string lyricText, string[] timeTags, string expected)
{
var lyric = new Lyric
{
Text = lyricText,
TimeTags = TestCaseTagHelper.ParseTimeTags(timeTags),
};

string actual = new LrcEncoder().Encode(new Beatmap
{
HitObjects = new List<HitObject>
{
lyric,
},
});

Assert.AreEqual(actual, expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using NUnit.Framework;
using osu.Game.Rulesets.Karaoke.Integration.Formats;
using osu.Game.Rulesets.Karaoke.Tests.Asserts;
using osu.Game.Rulesets.Karaoke.Tests.Helper;

namespace osu.Game.Rulesets.Karaoke.Tests.Integration.Formats;

public class LrcEncoderTest
{
[TestCase("[00:01.00]<00:01.00>か<00:02.00>ら<00:03.00>お<00:04.00>け<00:05.00>", "からおけ", 1000, 5000)]
public void TestLyricTextAndTime(string lyricText, string expectedText, double expectedStartTime, double expectedEndTime)
{
// Get first lyric from beatmap
var lyrics = new LrcDecoder().Decode(lyricText);
var actual = lyrics.FirstOrDefault()!;

Assert.IsNotNull(actual);
Assert.AreEqual(expectedText, actual.Text);
Assert.AreEqual(expectedStartTime, actual.LyricTimingInfo?.StartTime);
Assert.AreEqual(expectedEndTime, actual.LyricTimingInfo?.EndTime);
}

[TestCase("[00:01.00]<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)
{
// Get first lyric from beatmap
var lyrics = new LrcDecoder().Decode(text);
var lyric = lyrics.FirstOrDefault()!;

// Check time tag
var expected = TestCaseTagHelper.ParseTimeTags(timeTags);
var actual = lyric?.TimeTags ?? throw new ArgumentNullException(nameof(lyric));
TimeTagAssert.ArePropertyEqual(expected, actual);
}

[Ignore("Time-tags with same time might be allowed.")]
[TestCase("[00:04.00]<00:04.00>か<00:04.00>ら<00:05.00>お<00:06.00>け<00:07.00>")]
public void TestDecodeLyricWithDuplicatedTimeTag(string text)
{
Assert.Throws<FormatException>(() => new LrcDecoder().Decode(text));
}

[Ignore("Waiting for lyric parser update.")]
[TestCase("[00:04.00]<00:04.00>か<00:03.00>ら<00:02.00>お<00:01.00>け<00:00.00>")]
public void TestDecodeLyricWithTimeTagNotOrder(string text)
{
Assert.Throws<FormatException>(() => new LrcDecoder().Decode(text));
}
}
Loading

0 comments on commit 55e7a30

Please sign in to comment.