private Dictionary <TimeTagInvalid, TimeTag[]> checkInvalidTimeTags(Lyric lyric) { var result = new Dictionary <TimeTagInvalid, TimeTag[]>(); // todo : check out of range. var outOfRangeTags = TimeTagsUtils.FindOutOfRange(lyric.TimeTags, lyric.Text); if (outOfRangeTags?.Length > 0) { result.Add(TimeTagInvalid.OutOfRange, outOfRangeTags); } // Check overlapping. var groupCheck = config.TimeTagTimeGroupCheck; var selfCheck = config.TimeTagTimeSelfCheck; var overlappingTimeTags = TimeTagsUtils.FindOverlapping(lyric.TimeTags, groupCheck, selfCheck); if (overlappingTimeTags?.Length > 0) { result.Add(TimeTagInvalid.Overlapping, overlappingTimeTags); } // Check time-tag should have time. var noTimeTimeTags = TimeTagsUtils.FindNoneTime(lyric.TimeTags); if (noTimeTimeTags?.Length > 0) { result.Add(TimeTagInvalid.EmptyTime, noTimeTimeTags); } return(result); }
[TestCase("", new[] { "[0,start]:1000", "[0,end]:2000" }, false)] // empty lyric should always count as missing. public void TestHasStartTimeTagInLyric(string text, string[] timeTagTexts, bool actual) { var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var missing = TimeTagsUtils.HasStartTimeTagInLyric(timeTags, text); Assert.AreEqual(missing, actual); }
//[TestCase(new[] { "[0,start]:4000", "[0,end]:3000", "[1,start]:2000", "[1,end]:1000" }, new double[] { 4000, 4000, 4000, 4000 })] public void TestToDictionary(string[] timeTagTexts, double[] actualTimes) { var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var dictionary = TimeTagsUtils.ToDictionary(timeTags); Assert.AreEqual(dictionary.Values.ToArray(), actualTimes); }
public void TestGetEndTime(string[] timeTagTexts, double?actualEndTime) { var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var endTime = TimeTagsUtils.GetEndTime(timeTags); Assert.AreEqual(endTime, actualEndTime); }
public void TestSort(string[] timeTagTexts, string[] actualTimeTags) { var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var sortedTimeTag = TimeTagsUtils.Sort(timeTags); TimeTagAssert.AreEqual(sortedTimeTag, TestCaseTagHelper.ParseTimeTags(actualTimeTags)); }
public void TestFindOutOfRange(string text, string[] timeTagTexts, string[] invalidTimeTags) { var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var outOfRangeTimeTags = TimeTagsUtils.FindOutOfRange(timeTags, text); TimeTagAssert.AreEqual(outOfRangeTimeTags, TestCaseTagHelper.ParseTimeTags(invalidTimeTags)); }
private LyricLine encodeLyric(Objects.Lyric lyric) => new LyricLine { Text = lyric.Text, // Note : save to lyric will lost some tags with no value. TimeTags = convertTimeTag(lyric.Text, TimeTagsUtils.ToDictionary(lyric.TimeTags)).ToArray(), };
protected override void ParseStreamInto(LineBufferedReader stream, Beatmap output) { // Clear all hitobjects output.HitObjects.Clear(); var lyricText = stream.ReadToEnd(); var result = new LrcParser().Decode(lyricText); // Convert line for (int i = 0; i < result.Lines.Length; i++) { // Empty line should not be imported var line = result.Lines[i]; if (string.IsNullOrEmpty(line.Text)) { continue; } try { // todo : check list ls sorted by time. 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 state = (Array.IndexOf(lrcTimeTag, k) - 1) % 2 == 0 ? TextIndex.IndexState.Start : TextIndex.IndexState.End; return(new TextIndex(index, state)); }, v => (double)v.Time); var startTime = timeTags.FirstOrDefault(x => x.Value > 0).Value; var duration = timeTags.LastOrDefault(x => x.Value > 0).Value - startTime; var lyric = new Lyric { Order = output.HitObjects.Count + 1, // should create default order. Text = line.Text, // Start time and end time should be re-assigned StartTime = startTime, Duration = duration, TimeTags = TimeTagsUtils.ToTimeTagList(timeTags), RubyTags = result.QueryRubies(line.Text).Select(ruby => new RubyTag { Text = ruby.Ruby.Ruby, StartIndex = ruby.StartIndex, EndIndex = ruby.EndIndex }).ToArray() }; lyric.InitialWorkingTime(); output.HitObjects.Add(lyric); } catch (Exception ex) { var message = $"Parsing lyric '{line.Text}' got error in line:{i}" + "Please check time tag should be ordered and not duplicated." + "Then re-import again."; throw new FormatException(message, ex); } } }
//[TestCase(new[] { "[0,start]:4000", "[0,end]:3000", "[1,start]:2000", "[1,end]:1000" }, GroupCheck.Asc, SelfCheck.BasedOnStart, new double[] { "[0,start]:4000", "[0,end]:4000", "[1,start]:4000", "[1,end]:4000" })] //[TestCase(new[] { "[0,start]:4000", "[0,end]:3000", "[1,start]:2000", "[1,end]:1000" }, GroupCheck.Asc, SelfCheck.BasedOnEnd, new double[] { "[0,start]:3000", "[0,end]:3000", "[1,start]:3000", "[1,end]:3000" })] //[TestCase(new[] { "[0,start]:4000", "[0,end]:3000", "[1,start]:2000", "[1,end]:1000" }, GroupCheck.Desc, SelfCheck.BasedOnStart, new double[] { "[0,start]:2000", "[0,end]:2000", "[1,start]:2000", "[1,end]:2000" })] //[TestCase(new[] { "[0,start]:4000", "[0,end]:3000", "[1,start]:2000", "[1,end]:1000" }, GroupCheck.Desc, SelfCheck.BasedOnEnd, new double[] { "[0,start]:1000", "[0,end]:1000", "[1,start]:1000", "[1,end]:1000" })] public void TestFixInvalid(string[] timeTagTexts, GroupCheck other, SelfCheck self, string[] actualTimeTagTexts) { // check which part is fixed, using list of time to check result. var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var fixedTimeTag = TimeTagsUtils.FixInvalid(timeTags, other, self); TimeTagAssert.AreEqual(fixedTimeTag, TestCaseTagHelper.ParseTimeTags(actualTimeTagTexts)); }
public void TestFindOverlapping(string[] timeTagTexts, GroupCheck other, SelfCheck self, int[] errorIndex) { // run all and find overlapping indexes. var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var overlappingTimeTags = TimeTagsUtils.FindOverlapping(timeTags, other, self); var overlappingTimeTagIndexed = overlappingTimeTags.Select(v => timeTags.IndexOf(v)).ToArray(); Assert.AreEqual(overlappingTimeTagIndexed, errorIndex); }
public void TestFindInvalid(string[] timeTagTexts, GroupCheck other, SelfCheck self, int[] errorIndex) { // run all and find invalid indexes. var timeTags = TestCaseTagHelper.ParseTimeTags(timeTagTexts); var invalidTimeTag = TimeTagsUtils.FindInvalid(timeTags, other, self); var invalidIndexes = invalidTimeTag.Select(v => timeTags.IndexOf(v)).ToArray(); Assert.AreEqual(invalidIndexes, errorIndex); }
private Lyric createDefaultLyricLine() { var startTime = Time.Current; const double duration = 1000000; return(new Lyric { StartTime = startTime, Duration = duration, Text = "カラオケ!", TimeTags = TimeTagsUtils.ToTimeTagList(new Dictionary <TextIndex, double> { { new TextIndex(0), startTime + 500 }, { new TextIndex(1), startTime + 600 }, { new TextIndex(2), startTime + 1000 }, { new TextIndex(3), startTime + 1500 }, { new TextIndex(4), startTime + 2000 }, }), RubyTags = new[] { new RubyTag { StartIndex = 0, EndIndex = 1, Text = "か" }, new RubyTag { StartIndex = 2, EndIndex = 3, Text = "お" } }, RomajiTags = new[] { new RomajiTag { StartIndex = 1, EndIndex = 2, Text = "ra" }, new RomajiTag { StartIndex = 3, EndIndex = 4, Text = "ke" } } }); }
private Lyric createDefaultLyric(string text, string[] ruby, string[] romaji, string translate) { var startTime = Time.Current; const double duration = 1000000; using (var stream = new MemoryStream()) using (var writer = new StreamWriter(stream)) using (var reader = new LineBufferedReader(stream)) { writer.WriteLine("karaoke file format v1"); writer.WriteLine("[HitObjects]"); writer.WriteLine(text); ruby?.ForEach(x => writer.WriteLine(x)); romaji?.ForEach(x => writer.WriteLine(x)); writer.WriteLine("end"); writer.Flush(); stream.Position = 0; var lyric = new KaraokeLegacyBeatmapDecoder().Decode(reader).HitObjects.OfType <Lyric>().FirstOrDefault(); // Check is not null if (lyric == null) { throw new ArgumentNullException(); } // Apply property lyric.StartTime = startTime; lyric.Duration = duration; // todo : implementation var defaultLanguage = new CultureInfo("en-US"); lyric.Translates.Add(defaultLanguage, translate); lyric.TimeTags = TimeTagsUtils.ToTimeTagList(new Dictionary <TextIndex, double> { { new TextIndex(0), startTime }, { new TextIndex(4), startTime + duration }, }); return(lyric); } }
[TestCase(null, null, 2, null)] // should not be null. public void GenerateTimeTag(string startTag, string endTag, int index, string result) { try { var generatedTimeTag = TimeTagsUtils.GenerateCenterTimeTag( TestCaseTagHelper.ParseTimeTag(startTag), TestCaseTagHelper.ParseTimeTag(endTag), index); var actualTimeTag = TestCaseTagHelper.ParseTimeTag(result); Assert.AreEqual(generatedTimeTag.Index, actualTimeTag.Index); Assert.AreEqual(generatedTimeTag.Time, actualTimeTag.Time); } catch { Assert.IsNull(result); } }
public Note[] CreateNotes(Lyric lyric) { var timeTags = TimeTagsUtils.ToDictionary(lyric.TimeTags); var notes = new List <Note>(); foreach (var timeTag in timeTags) { var(key, endTime) = timeTags.GetNext(timeTag); if (key.Index <= 0) { continue; } var startTime = timeTag.Value; int startIndex = timeTag.Key.Index; int endIndex = TextIndexUtils.ToStringIndex(key); var text = lyric.Text[startIndex..endIndex];
private void load() { Scale = new Vector2(2f); AutoSizeAxes = Axes.Both; AddInternal(KaraokeText = new KaraokeSpriteText()); AddInternal(translateText = new OsuSpriteText { Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, }); TextBindable.BindValueChanged(text => { KaraokeText.Text = text.NewValue; }); TimeTagsBindable.BindValueChanged(timeTags => { KaraokeText.TimeTags = TimeTagsUtils.ToDictionary(timeTags.NewValue); }); RubyTagsBindable.BindValueChanged(rubyTags => { ApplyRuby(); }); RomajiTagsBindable.BindValueChanged(romajiTags => { ApplyRomaji(); }); SingersBindable.BindValueChanged(index => { ApplySkin(CurrentSkin, false); }); LayoutIndexBindable.BindValueChanged(index => { ApplySkin(CurrentSkin, false); }); TranslateTextBindable.BindCollectionChanged((_, args) => { ApplyTranslate(); }); }
public void TestDecodeLyric() { const string lyric_text = "[00:01.00]か[00:02.00]ら[00:03.00]お[00:04.00]け[00:05.00]"; var beatmap = decodeLrcLine(lyric_text); // Get first beatmap var lyric = beatmap.HitObjects.OfType <Lyric>().FirstOrDefault(); // Check lyric Assert.AreEqual(lyric?.Text, "からおけ"); Assert.AreEqual(lyric?.StartTime, 1000); Assert.AreEqual(lyric?.EndTime, 5000); // 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"); }
public Dictionary <TimeTagInvalid, TimeTag[]> CheckInvalidTimeTags(Lyric lyric) { var result = new Dictionary <TimeTagInvalid, TimeTag[]>(); // todo : check out of range. var outOfRangeTags = TimeTagsUtils.FindOutOfRange(lyric.TimeTags, lyric.Text); if (outOfRangeTags?.Length > 0) { result.Add(TimeTagInvalid.OutOfRange, outOfRangeTags); } // Check overlapping. var groupCheck = config.TimeTagTimeGroupCheck; var selfCheck = config.TimeTagTimeSelfCheck; var invalidTimeTags = TimeTagsUtils.FindInvalid(lyric.TimeTags, groupCheck, selfCheck); if (invalidTimeTags?.Length > 0) { result.Add(TimeTagInvalid.Overlapping, invalidTimeTags); } return(result); }
private void sortingTimeTag(Lyric lyric) => lyric.TimeTags = TimeTagsUtils.Sort(lyric.TimeTags);
public void TestEncodeBeatmapLyric() { // Because encoder is not fully implemented, so just test not crash during encoding. const int start_time = 1000; const int duration = 2500; var beatmap = new Beatmap { HitObjects = new List <HitObject> { new Lyric { StartTime = start_time, Duration = duration, Text = "カラオケ!", TimeTags = TimeTagsUtils.ToTimeTagList(new Dictionary <TextIndex, double> { { new TextIndex(0), start_time + 500 }, { new TextIndex(1), start_time + 600 }, { new TextIndex(2), start_time + 1000 }, { new TextIndex(3), start_time + 1500 }, { new TextIndex(4), start_time + 2000 }, }), RubyTags = new[] { new RubyTag { StartIndex = 0, EndIndex = 1, Text = "か" }, new RubyTag { StartIndex = 2, EndIndex = 3, Text = "お" } }, RomajiTags = new[] { new RomajiTag { StartIndex = 1, EndIndex = 2, Text = "ra" }, new RomajiTag { StartIndex = 3, EndIndex = 4, Text = "ke" } }, } } }; using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms)) { var encoder = new KaraokeLegacyBeatmapEncoder(); var encodeResult = encoder.Encode(beatmap); sw.WriteLine(encodeResult); } }
private bool checkMissingEndTimeTag(Lyric lyric) => !TimeTagsUtils.HasEndTimeTagInLyric(lyric.TimeTags, lyric.Text);
private Drawable testSingle(bool auto = false, double timeOffset = 0) { var startTime = Time.Current + 1000 + timeOffset; const double duration = 2500; var lyric = new Lyric { StartTime = startTime, Duration = duration, Text = "カラオケ!", TimeTags = TimeTagsUtils.ToTimeTagList(new Dictionary <TextIndex, double> { { new TextIndex(0), startTime + 500 }, { new TextIndex(1), startTime + 600 }, { new TextIndex(2), startTime + 1000 }, { new TextIndex(3), startTime + 1500 }, { new TextIndex(4), startTime + 2000 }, }), RubyTags = new[] { new RubyTag { StartIndex = 0, EndIndex = 1, Text = "か" }, new RubyTag { StartIndex = 2, EndIndex = 3, Text = "お" } }, RomajiTags = new[] { new RomajiTag { StartIndex = 1, EndIndex = 2, Text = "ra" }, new RomajiTag { StartIndex = 3, EndIndex = 4, Text = "ke" } }, }; var defaultLanguage = new CultureInfo("en-US"); lyric.Translates.Add(defaultLanguage, "karaoke"); lyric.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); var drawable = CreateDrawableLyric(lyric, auto); drawable.DisplayTranslateLanguage = defaultLanguage; foreach (var mod in SelectedMods.Value.OfType <IApplicableToDrawableHitObjects>()) { mod.ApplyToDrawableHitObjects(new[] { drawable }); } return(drawable); }