fix: guard unusable bpm and empty notes, pin line-break tie ordering

This commit is contained in:
2026-07-25 20:51:19 -07:00
parent ba78587a54
commit 0f09e6702b
2 changed files with 21 additions and 4 deletions
+4 -2
View File
@@ -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
View File
@@ -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, [])