Example #1
0
        [TestCase(new double[] { 1000, 3000 }, 0.3, 1, null)] // start + duration should not exceed 1
        public void TestSliceNoteTime(double[] time, double startPercentage, double durationPercentage, double[] actualTime)
        {
            var note = new Note
            {
                StartTime = time[0],
                Duration  = time[1],
            };

            try
            {
                var sliceNote = NoteUtils.SliceNote(note, startPercentage, durationPercentage);
                Assert.AreEqual(sliceNote.StartTime, actualTime[0]);
                Assert.AreEqual(sliceNote.Duration, actualTime[1]);
            }
            catch
            {
                Assert.IsNull(actualTime);
            }
        }
        private void processNotes(Beatmap beatmap, IList <string> lines)
        {
            // Remove all karaoke note
            beatmap.HitObjects.RemoveAll(x => x is Note);

            var lyrics = beatmap.HitObjects.OfType <Lyric>().ToList();

            for (int l = 0; l < lyrics.Count; l++)
            {
                var lyric = lyrics[l];
                var line  = lines.ElementAtOrDefault(l)?.Split('=').Last();

                // Create default note if not exist
                if (string.IsNullOrEmpty(line))
                {
                    beatmap.HitObjects.AddRange(LyricUtils.CreateDefaultNotes(lyric));
                    continue;
                }

                var notes         = line.Split(',');
                var defaultNotes  = LyricUtils.CreateDefaultNotes(lyric).ToList();
                var minNoteNumber = Math.Min(notes.Length, defaultNotes.Count);

                // Process each note
                for (int i = 0; i < minNoteNumber; i++)
                {
                    var note        = notes[i];
                    var defaultNote = defaultNotes[i];

                    // Support multi note in one time tag, format like ([1;0.5;か]|1#|...)
                    if (!note.StartsWith("(", StringComparison.Ordinal) || !note.EndsWith(")", StringComparison.Ordinal))
                    {
                        // Process and add note
                        applyNote(defaultNote, note);
                        beatmap.HitObjects.Add(defaultNote);
                    }
                    else
                    {
                        float startPercentage = 0;
                        var   rubyNotes       = note.Replace("(", "").Replace(")", "").Split('|');

                        for (int j = 0; j < rubyNotes.Length; j++)
                        {
                            string rubyNote = rubyNotes[j];

                            string tone;
                            float  percentage = (float)Math.Round((float)1 / rubyNotes.Length, 2, MidpointRounding.AwayFromZero);
                            string ruby       = defaultNote.AlternativeText?.ElementAtOrDefault(j).ToString();

                            // Format like [1;0.5;か]
                            if (note.StartsWith("[", StringComparison.Ordinal) && note.EndsWith("]", StringComparison.Ordinal))
                            {
                                var rubyNoteProperty = note.Replace("[", "").Replace("]", "").Split(';');

                                // Copy tome property
                                tone = rubyNoteProperty[0];

                                // Copy percentage property
                                if (rubyNoteProperty.Length >= 2)
                                {
                                    float.TryParse(rubyNoteProperty[1], out percentage);
                                }

                                // Copy text property
                                if (rubyNoteProperty.Length >= 3)
                                {
                                    ruby = rubyNoteProperty[2];
                                }
                            }
                            else
                            {
                                tone = rubyNote;
                            }

                            // Split note and apply them
                            var splitDefaultNote = NoteUtils.SliceNote(defaultNote, startPercentage, percentage);
                            startPercentage += percentage;
                            if (!string.IsNullOrEmpty(ruby))
                            {
                                splitDefaultNote.Text = ruby;
                            }

                            // Process and add note
                            applyNote(splitDefaultNote, tone);
                            beatmap.HitObjects.Add(splitDefaultNote);
                        }
                    }
                }
            }

            void applyNote(Note note, string noteStr, string ruby = null, double?duration = null)
            {
                if (noteStr == "-")
                {
                    note.Display = false;
                }
                else
                {
                    note.Display = true;
                    note.Tone    = convertTone(noteStr);
                }

                if (!string.IsNullOrEmpty(ruby))
                {
                    note.Text = ruby;
                }

                if (duration != null)
                {
                    note.Duration = duration.Value;
                }

                //Support format : 1  1.  1.5  1+  1#
                Tone convertTone(string tone)
                {
                    var half = false;

                    if (tone.Contains(".") || tone.Contains("#"))
                    {
                        half = true;

                        // only get digit part
                        tone = tone.Split('.').FirstOrDefault()?.Split('#').FirstOrDefault();
                    }

                    if (!int.TryParse(tone, out int scale))
                    {
                        throw new ArgumentOutOfRangeException($"{tone} does not support in {nameof(KaraokeLegacyBeatmapDecoder)}");
                    }

                    return(new Tone
                    {
                        Scale = scale,
                        Half = half
                    });
                }
            }
        }