Chord Families

This commit is contained in:
khodowany
2026-10-06 03:18:02 -05:00
parent e71385dad1
commit 8423f3d788
14 changed files with 196 additions and 57 deletions
+10 -5
View File
@@ -32,20 +32,20 @@ class GuitarTests(unittest.TestCase):
self.assertFalse(generator.fretboard.positions_for_pitch(fractions.Fraction(85)))
self.assertFalse(generator.fretboard.positions_for_pitch(fractions.Fraction(129, 2)))
self.assertTrue(generator.fretboard.within_fret_span((generator.fretboard.TabPosition(4, 11, 61), generator.fretboard.TabPosition(3, 12, 67), generator.fretboard.TabPosition(2, 13, 72))))
self.assertFalse(generator.fretboard.within_fret_span((generator.fretboard.TabPosition(4, 11, 61), generator.fretboard.TabPosition(3, 12, 67), generator.fretboard.TabPosition(2, 14, 73))))
self.assertTrue(generator.fretboard.within_fret_span((generator.fretboard.TabPosition(4, 11, 61), generator.fretboard.TabPosition(3, 12, 67), generator.fretboard.TabPosition(2, 14, 73))))
self.assertFalse(generator.fretboard.within_fret_span((generator.fretboard.TabPosition(6, 0, 40), generator.fretboard.TabPosition(1, 20, 84))))
self.assertFalse(generator.fretboard.within_fret_span((generator.fretboard.TabPosition(4, 10, 60), generator.fretboard.TabPosition(1, 20, 84))))
def test_fretted_positions_keep_span_and_proximity_scoring(self):
for frets, valid in (((1, 2, 3), True), ((1, 4), False), ((1, 5), False), ((7, 9), True), ((7, 10), False), ((7, 11), False), ((12, 1, 11), False), ((3, 3), True), ((18, 20), True)):
for frets, valid in (((1, 2, 3), True), ((1, 4), True), ((1, 5), False), ((7, 9), True), ((7, 10), True), ((7, 11), False), ((12, 1, 11), False), ((3, 3), True), ((18, 20), True)):
with self.subTest(frets=frets):
positions = tuple(generator.fretboard.TabPosition(6 - i, fret, 0) for i, fret in enumerate(frets))
self.assertEqual(generator.fretboard.within_fret_span(positions), valid)
self.assertEqual(generator.guitar.compactness(positions), max(frets) - min(frets))
self.assertEqual(generator.guitar.position_center(positions)[0], min(frets) + max(frets))
self.assertTrue(generator.fretboard.within_fret_span(()))
def test_held_notes_obey_the_shared_three_fret_limit(self):
def test_held_notes_obey_the_shared_four_fret_limit(self):
held = {'held': generator.fretboard.TabPosition(4, 7, 57)}
for fret, valid in ((9, True), (10, False), (11, False)):
for fret, valid in ((9, True), (10, True), (11, False)):
with self.subTest(fret=fret):
pending = [('attack', (generator.fretboard.TabPosition(2, fret, 59 + fret),))]
self.assertEqual(bool(list(generator.guitar.extend_positions(held, pending))), valid)
@@ -194,8 +194,13 @@ class GuitarTests(unittest.TestCase):
content = tests.test_musicxml.xml_note('E', 1, 'quarter', octave=4, extra='<tie type="start"/>') + tests.test_musicxml.xml_note('E', 3, 'half', octave=4, extra='<dot/><tie type="stop"/>')
content += '<backup><duration>4</duration></backup><forward><duration>1</duration></forward>' + tests.test_musicxml.xml_note('F', 3, 'half', octave=4, extra='<dot/><voice>2</voice>')
document = tests.test_musicxml.parse(tests.test_musicxml.xml_score(content))
# These fixed E/F positions span five frets; a tie cannot move to a
# different E position to make the incoming F fit.
for note in tests.test_musicxml.notes(document):
for pitch in note['pitches']:
pitch['tablature'] = {'string': 2, 'fret': 5} if pitch['letter'] == 'e' else {'string': 1, 'fret': 1}
before = copy.deepcopy(document)
with self.assertRaisesRegex(ValueError, '3 consecutive fret positions.*held/tied strings'):
with self.assertRaisesRegex(ValueError, '4 consecutive fret positions.*held/tied strings'):
generator.guitar.place_guitar(document)
self.assertEqual(document, before)
def test_proximity_chooses_a_path_without_relocating_tied_notes(self):