-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #313 from andy840119/note-utils
Implement note utility to handle separate and combine notes.
- Loading branch information
Showing
5 changed files
with
231 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// 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 NUnit.Framework; | ||
using osu.Game.Rulesets.Karaoke.Objects; | ||
using osu.Game.Rulesets.Karaoke.Utils; | ||
|
||
namespace osu.Game.Rulesets.Karaoke.Tests.Utils | ||
{ | ||
public class NoteUtilsTest | ||
{ | ||
[TestCase(new double[] { 1000, 3000 }, 0, 1, new double[] { 1000, 3000 })] | ||
[TestCase(new double[] { 1000, 3000 }, 0, 0.5, new double[] { 1000, 1500 })] | ||
[TestCase(new double[] { 1000, 3000 }, 0.5, 0.5, new double[] { 2500, 1500 })] | ||
[TestCase(new double[] { 1000, 3000 }, 0.3, 0.4, new double[] { 1900, 1200 })] | ||
[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); | ||
} | ||
} | ||
|
||
[TestCase(new double[] { 1000, 5000 }, 0.2, new double[] { 1000, 1000 }, new double[] { 2000, 4000 })] | ||
[TestCase(new double[] { 1000, 5000 }, 0.5, new double[] { 1000, 2500 }, new double[] { 3500, 2500 })] | ||
[TestCase(new double[] { 1000, 0 }, 0.2, new double[] { 1000, 0 }, new double[] { 1000, 0 })] // it's ok to split if duration is 0. | ||
[TestCase(new double[] { 1000, 0 }, 0.7, new double[] { 1000, 0 }, new double[] { 1000, 0 })] | ||
[TestCase(new double[] { 1000, 5000 }, -1, null, null)] // should be in the range. | ||
[TestCase(new double[] { 1000, 5000 }, 3, null, null)] | ||
[TestCase(new double[] { 1000, 5000 }, 0, null, null)] // should not be 0 or 1. | ||
[TestCase(new double[] { 1000, 5000 }, 1, null, null)] | ||
public void TestSeparateNoteTime(double[] time, double percentage, double[] firstTime, double[] secondTime) | ||
{ | ||
var note = new Note | ||
{ | ||
StartTime = time[0], | ||
Duration = time[1], | ||
}; | ||
|
||
try | ||
{ | ||
var (firstNote, secondNote) = NoteUtils.SplitNote(note, percentage); | ||
Assert.AreEqual(firstNote.StartTime, firstTime[0]); | ||
Assert.AreEqual(firstNote.Duration, firstTime[1]); | ||
|
||
Assert.AreEqual(secondNote.StartTime, secondTime[0]); | ||
Assert.AreEqual(secondNote.Duration, secondTime[1]); | ||
} | ||
catch | ||
{ | ||
Assert.IsNull(firstTime); | ||
Assert.IsNull(secondTime); | ||
} | ||
} | ||
|
||
[Test] | ||
public void TestSeparateNoteOtherProperty() | ||
{ | ||
const double percentage = 0.3; | ||
var lyric = new Lyric(); | ||
|
||
var note = new Note | ||
{ | ||
StartTime = 1000, | ||
Duration = 2000, | ||
StartIndex = 1, | ||
EndIndex = 2, | ||
Text = "ka", | ||
Singers = new[] { 0 }, | ||
Display = false, | ||
Tone = new Tone(-1, true), | ||
ParentLyric = lyric | ||
}; | ||
|
||
// create other property and make sure other class is applied value. | ||
var (firstNote, secondNote) = NoteUtils.SplitNote(note, percentage); | ||
|
||
Assert.AreEqual(firstNote.StartTime, 1000); | ||
Assert.AreEqual(secondNote.StartTime, 1600); | ||
|
||
Assert.AreEqual(firstNote.Duration, 600); | ||
Assert.AreEqual(secondNote.Duration, 1400); | ||
|
||
testRemainProperty(firstNote, note); | ||
testRemainProperty(firstNote, note); | ||
|
||
static void testRemainProperty(Note expect, Note actual) | ||
{ | ||
Assert.AreEqual(expect.StartIndex, actual.StartIndex); | ||
Assert.AreEqual(expect.EndIndex, actual.EndIndex); | ||
Assert.AreEqual(expect.Text, actual.Text); | ||
|
||
Assert.AreEqual(expect.Singers, actual.Singers); | ||
Assert.AreNotSame(expect.Singers, actual.Singers); | ||
|
||
Assert.AreEqual(expect.Display, actual.Display); | ||
Assert.AreEqual(expect.Tone, actual.Tone); | ||
Assert.AreEqual(expect.ParentLyric, actual.ParentLyric); | ||
} | ||
} | ||
|
||
[TestCase(new double[] { 1000, 1000 }, new double[] { 2000, 4000 }, new double[] { 1000, 5000 })] | ||
[TestCase(new double[] { 1000, 2500 }, new double[] { 3500, 2500 }, new double[] { 1000, 5000 })] | ||
[TestCase(new double[] { 1000, 0 }, new double[] { 1000, 0 }, new double[] { 1000, 0 })] // it's ok to combine if duration is 0. | ||
public void TestCombineNoteTime(double[] firstTime, double[] secondTime, double[] actualTime) | ||
{ | ||
const int start_index = 3; | ||
const int end_index = 5; | ||
|
||
var lyric = new Lyric(); | ||
|
||
var firstNote = new Note | ||
{ | ||
StartIndex = start_index, | ||
EndIndex = end_index, | ||
ParentLyric = lyric, | ||
StartTime = firstTime[0], | ||
Duration = firstTime[1], | ||
}; | ||
|
||
var secondNote = new Note | ||
{ | ||
StartIndex = start_index, | ||
EndIndex = end_index, | ||
ParentLyric = lyric, | ||
StartTime = secondTime[0], | ||
Duration = secondTime[1], | ||
}; | ||
|
||
var combineNote = NoteUtils.CombineNote(firstNote, secondNote); | ||
Assert.AreEqual(combineNote.StartTime, actualTime[0]); | ||
Assert.AreEqual(combineNote.Duration, actualTime[1]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
// 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 osu.Framework.Allocation; | ||
using osu.Framework.Graphics; | ||
using osu.Framework.Graphics.UserInterface; | ||
using osu.Game.Graphics.UserInterface; | ||
using osu.Game.Rulesets.Karaoke.Edit.Blueprints.Notes.Components; | ||
using osu.Game.Rulesets.Karaoke.Objects; | ||
using osu.Game.Rulesets.Karaoke.Objects.Drawables; | ||
using osu.Game.Rulesets.Karaoke.Utils; | ||
using osu.Game.Screens.Edit; | ||
using osuTK; | ||
|
||
|
@@ -32,10 +34,10 @@ public class NoteSelectionBlueprint : KaraokeSelectionBlueprint<Note> | |
private void splitNote() | ||
{ | ||
// TODO : percentage should be enter by dialog | ||
var splittedNote = HitObject.CopyByPercentage(0.5); | ||
EditorBeatmap?.Add(splittedNote); | ||
// Change object's duration | ||
HitObject.Duration = HitObject.Duration - splittedNote.Duration; | ||
var (firstNote, secondNote) = NoteUtils.SplitNote(HitObject, 0.5); | ||
EditorBeatmap?.Add(firstNote); | ||
EditorBeatmap?.Add(secondNote); | ||
EditorBeatmap?.Remove(HitObject); | ||
} | ||
|
||
public void ChangeDisplay(bool display) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
// 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 Newtonsoft.Json; | ||
using osu.Framework.Bindables; | ||
using osu.Game.Rulesets.Judgements; | ||
|
@@ -88,36 +87,6 @@ public virtual Tone Tone | |
|
||
public Lyric ParentLyric { get; set; } | ||
|
||
public Note CopyByPercentage(double startPercentage = 0, double durationPercentage = 0.5) | ||
{ | ||
if (startPercentage < 0 || startPercentage + durationPercentage > 1) | ||
throw new ArgumentOutOfRangeException($"{nameof(Note)} cannot assign split range of start from {startPercentage} and duration {durationPercentage}"); | ||
|
||
var startTime = StartTime + Duration * startPercentage; | ||
var duration = Duration * durationPercentage; | ||
|
||
return CopyByTime(startTime, duration); | ||
} | ||
|
||
public Note CopyByTime(double startTime, double duration) | ||
{ | ||
if (startTime < StartTime || startTime + duration > EndTime) | ||
throw new ArgumentOutOfRangeException($"{nameof(Note)} cannot assign split range of start from {startTime} and duration {duration}"); | ||
|
||
return new Note | ||
{ | ||
StartTime = startTime, | ||
Duration = duration, | ||
StartIndex = StartIndex, | ||
EndIndex = EndIndex, | ||
Text = Text, | ||
Singers = Singers, | ||
Display = Display, | ||
Tone = Tone, | ||
ParentLyric = ParentLyric | ||
}; | ||
} | ||
|
||
public override Judgement CreateJudgement() => new KaraokeNoteJudgement(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using osu.Game.Rulesets.Karaoke.Objects; | ||
using System; | ||
|
||
namespace osu.Game.Rulesets.Karaoke.Utils | ||
{ | ||
public static class NoteUtils | ||
{ | ||
public static Note SliceNote(Note note, double startPercentage, double durationPercentage) | ||
{ | ||
if (startPercentage < 0 || startPercentage + durationPercentage > 1) | ||
throw new ArgumentOutOfRangeException($"{nameof(Note)} cannot assign split range of start from {startPercentage} and duration {durationPercentage}"); | ||
|
||
var startTime = note.StartTime + note.Duration * startPercentage; | ||
var duration = note.Duration * durationPercentage; | ||
|
||
return copyByTime(note, startTime, duration); | ||
} | ||
|
||
public static Tuple<Note, Note> SplitNote(Note note, double percentage = 0.5) | ||
{ | ||
if (percentage < 0 || percentage > 1) | ||
throw new ArgumentOutOfRangeException(nameof(Note)); | ||
|
||
if (percentage == 0 || percentage == 1) | ||
throw new InvalidOperationException($"{nameof(percentage)} cannot be {0} or {1}."); | ||
|
||
var firstNoteStartTime = note.StartTime; | ||
var firstNoteDuration = note.Duration * percentage; | ||
|
||
var secondNoteStartTime = firstNoteStartTime + firstNoteDuration; | ||
var secondNoteDuration = note.Duration * (1 - percentage); | ||
|
||
var firstNote = copyByTime(note, firstNoteStartTime, firstNoteDuration); | ||
var secondNote = copyByTime(note, secondNoteStartTime, secondNoteDuration); | ||
|
||
return new Tuple<Note, Note>(firstNote, secondNote); | ||
} | ||
|
||
public static Note CombineNote(Note firstLyric, Note secondLyric) | ||
{ | ||
if (firstLyric.ParentLyric != secondLyric.ParentLyric) | ||
throw new InvalidOperationException($"{nameof(firstLyric.ParentLyric)} and {nameof(secondLyric.ParentLyric)} should be same."); | ||
|
||
if (firstLyric.StartIndex != secondLyric.StartIndex) | ||
throw new InvalidOperationException($"{nameof(firstLyric.StartIndex)} and {nameof(secondLyric.StartIndex)} should be same."); | ||
|
||
if (firstLyric.EndIndex != secondLyric.EndIndex) | ||
throw new InvalidOperationException($"{nameof(firstLyric.EndIndex)} and {nameof(secondLyric.EndIndex)} should be same."); | ||
|
||
var startTime = Math.Min(firstLyric.StartTime, secondLyric.StartTime); | ||
var endTime = Math.Max(firstLyric.EndTime, secondLyric.EndTime); | ||
|
||
return copyByTime(firstLyric, startTime, endTime - startTime); | ||
} | ||
|
||
private static Note copyByTime(Note originNote, double startTime, double duration) | ||
{ | ||
return new Note | ||
{ | ||
StartTime = startTime, | ||
Duration = duration, | ||
StartIndex = originNote.StartIndex, | ||
EndIndex = originNote.EndIndex, | ||
Text = originNote.Text, | ||
Singers = originNote.Singers?.Clone() as int[], | ||
Display = originNote.Display, | ||
Tone = originNote.Tone, | ||
ParentLyric = originNote.ParentLyric | ||
}; | ||
} | ||
} | ||
} |