fix: guard unusable bpm and empty notes, pin line-break tie ordering
This commit is contained in:
@@ -15,8 +15,8 @@ def detect_bpm(instrumental_path: Path) -> float:
|
||||
|
||||
def scale_bpm(bpm: float) -> float:
|
||||
"""Fold a tempo into UltraStar's usual [200, 400) file-BPM range."""
|
||||
if bpm <= 0:
|
||||
raise ValueError(f"cannot scale non-positive bpm {bpm}")
|
||||
if not math.isfinite(bpm) or bpm <= 0:
|
||||
raise ValueError(f"cannot scale bpm {bpm}")
|
||||
while bpm < 200:
|
||||
bpm *= 2
|
||||
while bpm >= 400:
|
||||
@@ -26,6 +26,8 @@ def scale_bpm(bpm: float) -> float:
|
||||
|
||||
def to_ultrastar(notes: list[dict], breaks: list[float], file_bpm: float,
|
||||
headers: list[tuple[str, str]]) -> UltraStarSong:
|
||||
if not notes:
|
||||
raise ValueError("no notes to place on the beat grid")
|
||||
gap_ms = round(notes[0]["start"] * 1000)
|
||||
spb = 60 / (4 * file_bpm)
|
||||
|
||||
|
||||
+17
-2
@@ -36,9 +36,15 @@ def test_scale_bpm():
|
||||
assert scale_bpm(450.0) == 225.0
|
||||
|
||||
|
||||
def test_scale_bpm_rejects_non_positive():
|
||||
@pytest.mark.parametrize("bpm", [0.0, -120.0, float("inf"), float("nan")])
|
||||
def test_scale_bpm_rejects_unusable_tempo(bpm):
|
||||
with pytest.raises(ValueError):
|
||||
scale_bpm(0.0)
|
||||
scale_bpm(bpm)
|
||||
|
||||
|
||||
def test_to_ultrastar_rejects_empty_notes():
|
||||
with pytest.raises(ValueError):
|
||||
to_ultrastar([], [], 240.0, [])
|
||||
|
||||
|
||||
def test_to_ultrastar_conversion():
|
||||
@@ -90,6 +96,15 @@ def test_line_break_pushed_past_the_preceding_note():
|
||||
assert_ordered(song.body)
|
||||
|
||||
|
||||
def test_line_break_on_a_note_start_precedes_that_note():
|
||||
"""No gap across a line boundary puts the break exactly on the next onset."""
|
||||
notes = [note(0.0, 0.5, 0, "end"), note(0.5, 0.5, 2, "New")]
|
||||
song = to_ultrastar(notes, [0.5], 240.0, [])
|
||||
assert song.body[1] == LineBreak(beat=8)
|
||||
assert [n.text for n in song.body if isinstance(n, Note)] == ["end", "New"]
|
||||
assert_ordered(song.body)
|
||||
|
||||
|
||||
def test_line_break_not_after_the_following_note():
|
||||
notes = [note(0.0, 0.02, 0, "a"), note(0.03, 0.02, 1, "b")]
|
||||
song = to_ultrastar(notes, [0.025], 240.0, [])
|
||||
|
||||
Reference in New Issue
Block a user