Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions tests/ui/dialogs/test_select_harmony_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,37 @@ def test_parse_with_extensions_does_not_crash(self, extension, qtui):
# extensions are not currently supported
params = parse_text("C" + extension)
assert params["step"] == 0


class TestRomanNumeralParsing:
# Regression guard: a roman-numeral seventh used to select the triad
# quality (e.g. "V7" -> "major") because the parser read music21's
# `impliedQuality`, which only reflects the triad, instead of the full
# chord type computed from the chord's pitches.
@pytest.mark.parametrize(
"text, quality, step, inversion",
[
("V", "major", 4, 0),
("V7", "dominant-seventh", 4, 0),
("V65", "dominant-seventh", 4, 1),
("V43", "dominant-seventh", 4, 2),
("V42", "dominant-seventh", 4, 3),
("ii7", "minor-seventh", 1, 0),
("viio7", "diminished-seventh", 6, 0),
],
)
def test_quality_step_and_inversion(self, text, quality, step, inversion, qtui):
params = parse_text(text)
assert params["quality"] == quality
assert params["step"] == step
assert params["inversion"] == inversion

def test_seventh_quality_is_not_collapsed_to_triad(self, qtui):
# Direct guard for the reported bug: typing "V7" selected "Major".
assert parse_text("V7")["quality"] == "dominant-seventh"

def test_applied_seventh(self, qtui):
params = parse_text("V7/V")
assert params["quality"] == "dominant-seventh"
assert params["applied_to"] == 4
assert params["step"] == 1
4 changes: 1 addition & 3 deletions tests/ui/timelines/hierarchy/test_hierarchy_timeline_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,7 @@ def test_pre_start_not_in_menu_when_room_below_min_length(self, tlui):
menu = HierarchyContextMenu(tlui[0])
assert self.PRE_START not in get_command_names(menu)

def test_post_end_not_in_menu_when_room_below_min_length(
self, tlui, tilia_state
):
def test_post_end_not_in_menu_when_room_below_min_length(self, tlui, tilia_state):
tilia_state.duration = 100
tlui.create_hierarchy(
0, tilia_state.duration - HierarchyUI.MIN_FRAME_LENGTH / 2, 1
Expand Down
6 changes: 3 additions & 3 deletions tilia/timelines/harmony/components/harmony.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ def _get_music21_object_from_text(
elif text.startswith(("I", "i", "V", "v")):
try:
roman_numeral = music21.roman.RomanNumeral(prefixed_accidental + text, key)
letter_common_name = music21.chord.Chord(roman_numeral.pitches).commonName
roman_numeral.letter_type = CHORD_COMMON_NAME_TO_TYPE[letter_common_name]
if roman_numeral.commonName not in CHORD_COMMON_NAME_TO_TYPE:
raise KeyError(roman_numeral.commonName)
return roman_numeral, "roman"
except (ValueError, KeyError):
pass
Expand All @@ -194,7 +194,7 @@ def _get_params_from_music21_object(
accidental = int(obj.root().alter)
inversion = obj.inversion() if obj.inversion() else 0
if kind == "roman":
quality = obj.impliedQuality
quality = CHORD_COMMON_NAME_TO_TYPE[obj.commonName]
applied_to = (
ROMAN_TO_INT[obj.secondaryRomanNumeral.figure.upper()]
if obj.secondaryRomanNumeral
Expand Down
1 change: 0 additions & 1 deletion tilia/ui/qtui.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ def _tilia_theme_name() -> str:
scheme = QApplication.styleHints().colorScheme()
return "tiliaDark" if scheme == Qt.ColorScheme.Dark else "tiliaLight"


def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
if event is None:
return
Expand Down