Fix Generation
ci / checks (push) Successful in 1h10m16s

This commit is contained in:
khodowany
2026-09-26 23:28:13 -05:00
parent 3beeb87549
commit a416a80dd9
6 changed files with 36 additions and 19 deletions
+29 -13
View File
@@ -46,7 +46,7 @@ class VoicingTests(unittest.TestCase):
def test_root_precedes_physical_cost_without_covering_the_melody(self):
self.assertEqual(ranked('CM7', (67,))[0], grip((2, 4, 1, 3)))
rooted = generator.guitar.voicing_cost(grip((2, 4, 1, 3)), 'electric', (0, 4, 7, 11), 0, (67,))
rootless = generator.guitar.voicing_cost(grip((2, 0, 0, 3)), 'electric', (0, 4, 7, 11), 0, (67,))
rootless = generator.guitar.voicing_cost(grip((5, 4, 5, 3)), 'electric', (0, 4, 7, 11), 0, (67,))
self.assertGreater(rooted.effort, rootless.effort)
self.assertLess(rooted, rootless)
def test_essential_extensions_are_never_relaxed_to_add_the_root(self):
@@ -68,25 +68,41 @@ class VoicingTests(unittest.TestCase):
candidates = list(generator.guitar.attack_candidates([note], tones, {}, {}, False))
self.assertTrue(candidates)
self.assertTrue(all(c.cost.missing_root == 0 and all(p.midi % 12 != 0 for p in c.shape) for c in candidates))
def test_lower_frets_and_small_spans_have_explicit_costs(self):
def test_frets_zero_through_twelve_have_no_height_cost(self):
for profile in ('', 'electric', 'acoustic'):
low = generator.guitar.voicing_cost(grip((3, 3, 3, 3)), profile)
high = generator.guitar.voicing_cost(grip((15, 15, 15, 15)), profile)
self.assertLess(low, high)
self.assertEqual(high.effort - low.effort, 24)
for fret in range(13):
with self.subTest(profile=profile, fret=fret):
self.assertEqual(generator.guitar.voicing_cost(grip((fret,) * 4), profile).effort, 0)
self.assertEqual(generator.guitar.voicing_cost((), profile).effort, 0)
def test_height_cost_only_counts_frets_above_twelve(self):
for profile in ('', 'electric', 'acoustic'):
for fret in range(13, 21):
with self.subTest(profile=profile, fret=fret):
self.assertEqual(generator.guitar.voicing_cost(grip((fret,) * 4), profile).effort, 2 * (fret - 12))
crossing = grip((11, 12, 13, 14))
self.assertEqual(generator.guitar.voicing_cost(crossing).effort, 7)
self.assertEqual(generator.guitar.voicing_cost(crossing, 'acoustic').effort, 19)
def test_span_and_acoustic_simplicity_costs_remain_unchanged(self):
shape = grip((0, 2, 3, 4))
self.assertEqual(generator.guitar.voicing_cost(shape).effort, 12)
self.assertEqual(generator.guitar.voicing_cost(shape, 'acoustic').effort, 26)
self.assertEqual(generator.guitar.voicing_cost(shape).effort, 4)
self.assertEqual(generator.guitar.voicing_cost(shape, 'acoustic').effort, 18)
for profile in ('', 'electric', 'acoustic'):
self.assertLess(generator.guitar.voicing_cost(grip((8, 8, 8, 8)), profile), generator.guitar.voicing_cost(grip((2, 4, 1, 3)), profile))
def test_acoustic_simpler_three_note_shape_can_beat_four_notes(self):
candidates = ranked('C7', profile='acoustic')
candidates = ranked('C6', profile='acoustic')
best = candidates[0]
self.assertEqual(len(best), 3)
self.assertTrue(any(len(c) == 4 for c in candidates))
required, _, _ = generator.guitar.chord_requirements(generator.harmony.parse_symbol('C7'), 'acoustic')
required, _, _ = generator.guitar.chord_requirements(generator.harmony.parse_symbol('C6'), 'acoustic')
self.assertTrue(set(required) <= {p.midi % 12 for p in best})
def test_nearby_position_can_balance_lower_fret_preference(self):
low, nearby, previous = (grip((f,), (1,)) for f in (3, 4, 5))
self.assertEqual(generator.guitar.voicing_cost(low).moved(generator.guitar.movement(previous, low)), generator.guitar.voicing_cost(nearby).moved(generator.guitar.movement(previous, nearby)))
def test_nearby_position_beats_lower_frets_within_comfort_range(self):
low, nearby, previous = (grip((f,) * 4) for f in (3, 8, 9))
for profile in ('', 'electric', 'acoustic'):
self.assertLess(generator.guitar.voicing_cost(nearby, profile).moved(generator.guitar.movement(previous, nearby)), generator.guitar.voicing_cost(low, profile).moved(generator.guitar.movement(previous, low)))
def test_above_threshold_is_a_soft_cost_not_a_range_priority(self):
low, high = (grip((f,) * 4) for f in (3, 13))
for profile in ('', 'electric', 'acoustic'):
self.assertLess(generator.guitar.voicing_cost(high, profile), generator.guitar.voicing_cost(low, profile).moved(generator.guitar.movement(high, low)))
def test_candidate_pruning_uses_full_cost_and_preserves_each_center(self):
for symbol, profile, melody in (('FM7', 'electric', (69,)), ('C7', 'acoustic', ()), ('Gm7', 'electric', (67,))):
best = {}