diff --git a/osu.Game.Rulesets.Karaoke.Tests/Edit/Generator/TimeTags/Zh/ZhTimeTagGeneratorTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Edit/Generator/TimeTags/Zh/ZhTimeTagGeneratorTest.cs new file mode 100644 index 000000000..24e4603ff --- /dev/null +++ b/osu.Game.Rulesets.Karaoke.Tests/Edit/Generator/TimeTags/Zh/ZhTimeTagGeneratorTest.cs @@ -0,0 +1,75 @@ +// Copyright (c) andy840119 . 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.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Karaoke.Edit.Generator.TimeTags.Zh; +using osu.Game.Rulesets.Karaoke.Objects; + +namespace osu.Game.Rulesets.Karaoke.Tests.Edit.Generator.TimeTags.Zh +{ + [TestFixture] + public class ZhTimeTagGeneratorTest + { + [TestCase("測試一些歌詞", new double[] { 0, 1, 2, 3, 4, 5, 5.5 })] + [TestCase("拉拉拉~~~", new double[] { 0, 1, 2, 5.5 })] + [TestCase("拉~拉~拉~", new double[] { 0, 2, 4, 5.5 })] + public void TestLyricWithCheckLineEndKeyUp(string lyric, double[] index) + { + var config = generatorConfig(nameof(ZhTimeTagGeneratorConfig.CheckLineEndKeyUp)); + RunTimeTagCheckTest(lyric, index, config); + } + + #region test helper + + protected void RunTimeTagCheckTest(string lyricText, double[] index, ZhTimeTagGeneratorConfig config) + { + var generator = new ZhTimeTagGenerator(config); + var lyric = generateLyric(lyricText); + + // create time tag and actually time tag. + var timeTags = getTimeTagIndex(generator.CreateTimeTags(lyric)); + var actualIndexed = getTimeTagIndexByArray(index); + + // check should be equal + Assert.AreEqual(timeTags, actualIndexed); + } + + private TimeTagIndex[] getTimeTagIndex(Tuple[] timeTags) + => timeTags.Select((v, i) => v.Item1).ToArray(); + + private ZhTimeTagGeneratorConfig generatorConfig(params string[] properties) + { + var config = new ZhTimeTagGeneratorConfig(); + + foreach (var propertyName in properties) + { + if (propertyName == null) + continue; + + var theMethod = config.GetType().GetProperty(propertyName); + if (theMethod == null) + throw new MissingMethodException("Config is not exist."); + + theMethod.SetValue(config, true); + } + + return config; + } + + private TimeTagIndex[] getTimeTagIndexByArray(double[] timeTags) + => timeTags.Select(timeTag => + { + var state = Math.Abs(timeTag) % 1 == 0.5 ? TimeTagIndex.IndexState.End : TimeTagIndex.IndexState.Start; + var index = (int)timeTag; + return new TimeTagIndex(index, state); + }).ToArray(); + + private Lyric generateLyric(string text) + => new Lyric { Text = text }; + + #endregion + } +} diff --git a/osu.Game.Rulesets.Karaoke.Tests/Utils/CharUtilsTest.cs b/osu.Game.Rulesets.Karaoke.Tests/Utils/CharUtilsTest.cs index 0fac62491..27d244fa4 100644 --- a/osu.Game.Rulesets.Karaoke.Tests/Utils/CharUtilsTest.cs +++ b/osu.Game.Rulesets.Karaoke.Tests/Utils/CharUtilsTest.cs @@ -48,5 +48,24 @@ public void TestIsAsciiSymbol(char c, bool match) var isAsciiSymbol = CharUtils.IsAsciiSymbol(c); Assert.AreEqual(isAsciiSymbol, match); } + + [TestCase('你', true)] + [TestCase('好', true)] + [TestCase('世', true)] + [TestCase('界', true)] + [TestCase('A', false)] + [TestCase('a', false)] + [TestCase('A', false)] + [TestCase('a', false)] + [TestCase('~', false)] + [TestCase('~', false)] + [TestCase('ハ', false)] + [TestCase('は', false)] + [TestCase('ハ', false)] + public void TestIsChinese(char c, bool result) + { + var isChinses = CharUtils.IsChinese(c); + Assert.AreEqual(isChinses, result); + } } } diff --git a/osu.Game.Rulesets.Karaoke/Edit/Generator/TimeTags/Zh/ZhTimeTagGenerator.cs b/osu.Game.Rulesets.Karaoke/Edit/Generator/TimeTags/Zh/ZhTimeTagGenerator.cs new file mode 100644 index 000000000..44fbfea62 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Edit/Generator/TimeTags/Zh/ZhTimeTagGenerator.cs @@ -0,0 +1,31 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Karaoke.Objects; +using osu.Game.Rulesets.Karaoke.Utils; +using System; +using System.Collections.Generic; + +namespace osu.Game.Rulesets.Karaoke.Edit.Generator.TimeTags.Zh +{ + public class ZhTimeTagGenerator : TimeTagGenerator + { + public ZhTimeTagGenerator(ZhTimeTagGeneratorConfig config) + : base(config) + { + } + + protected override void TimeTagLogic(Lyric lyric, List> timeTags) + { + var text = lyric.Text; + for (var i = 1; i < text.Length; i++) + { + if (CharUtils.IsChinese(text[i])) + { + timeTags.Add(TimeTagsUtils.Create(new TimeTagIndex(i, TimeTagIndex.IndexState.Start), null)); + } + } + } + } +} diff --git a/osu.Game.Rulesets.Karaoke/Edit/Generator/TimeTags/Zh/ZhTimeTagGeneratorConfig.cs b/osu.Game.Rulesets.Karaoke/Edit/Generator/TimeTags/Zh/ZhTimeTagGeneratorConfig.cs new file mode 100644 index 000000000..0474bc169 --- /dev/null +++ b/osu.Game.Rulesets.Karaoke/Edit/Generator/TimeTags/Zh/ZhTimeTagGeneratorConfig.cs @@ -0,0 +1,9 @@ +// Copyright (c) andy840119 . Licensed under the GPL Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Karaoke.Edit.Generator.TimeTags.Zh +{ + public class ZhTimeTagGeneratorConfig : TimeTagGeneratorConfig + { + } +} diff --git a/osu.Game.Rulesets.Karaoke/Utils/CharUtils.cs b/osu.Game.Rulesets.Karaoke/Utils/CharUtils.cs index cf4c2aeb9..54a4c5558 100644 --- a/osu.Game.Rulesets.Karaoke/Utils/CharUtils.cs +++ b/osu.Game.Rulesets.Karaoke/Utils/CharUtils.cs @@ -1,6 +1,8 @@ // Copyright (c) andy840119 . Licensed under the GPL Licence. // See the LICENCE file in the repository root for full licence text. +using System.Text.Unicode; + namespace osu.Game.Rulesets.Karaoke.Utils { public static class CharUtils @@ -43,5 +45,18 @@ public static bool IsAsciiSymbol(char c) c >= '[' && c <= '`' || c >= '{' && c <= '~'; } + + /// + /// Check this char is chinese character + /// + /// + /// + public static bool IsChinese(char character) + { + // From : https://stackoverflow.com/a/61738863/4105113 + var minValue = UnicodeRanges.CjkUnifiedIdeographs.FirstCodePoint; + var maxValue = minValue + UnicodeRanges.CjkUnifiedIdeographs.Length; + return character >= minValue && character < maxValue; + } } }