Comping Gen
This commit is contained in:
@@ -19,6 +19,7 @@ import generator.score
|
||||
import generator.vocabulary
|
||||
import tests.solo_fixtures
|
||||
import tests.test_acoustic_voicing
|
||||
import tests.test_voicing
|
||||
|
||||
def options(symbol, part):
|
||||
return generator.comping.voicings(generator.comping.semantic_key(generator.harmony.parse_symbol(symbol)), part)
|
||||
@@ -30,6 +31,29 @@ def path_cost(path, costs, part, left=(), right=(), close=False):
|
||||
return tuple(total)
|
||||
|
||||
class CompingVoicings(unittest.TestCase):
|
||||
def test_electric_prefers_lower_grip_but_can_avoid_a_large_shift(self):
|
||||
low, high = (tests.test_voicing.grip(f) for f in ((2, 3, 1, 3), (10, 12, 11, 12)))
|
||||
key = generator.comping.semantic_key(generator.harmony.parse_symbol('C7'))
|
||||
self.assertTrue(all(v in options('C7', 'electric') for v in (low, high)))
|
||||
costs = {v: generator.comping.local_cost('electric', key, v, 60) for v in (low, high)}
|
||||
self.assertEqual(costs[low][:2], costs[high][:2])
|
||||
self.assertLess(costs[low], costs[high])
|
||||
path, _ = generator.comping.select_grips(((low, high),), (costs,), 'electric', 'lower')
|
||||
self.assertEqual(path, (low,))
|
||||
path, _ = generator.comping.select_grips(((low, high),), (costs,), 'electric', 'lower', left=high, right=high)
|
||||
self.assertEqual(path, (high,))
|
||||
def test_electric_voicing_policy_does_not_reseed_rhythm(self):
|
||||
source = generator.production.SourceAnalysis.read(tests.solo_fixtures.song(count=4, chords=('C7', 'FM7', 'Dm7', 'G7')))
|
||||
root = pathlib.Path('data')
|
||||
current = generator.production.generate_role(source, 'electric_accompaniment', root)
|
||||
with tempfile.TemporaryDirectory() as cache:
|
||||
settings = {'voicing': {'register_weight': 0, 'high_position_weight': 0}}
|
||||
other = generator.production.generate_role(source, 'electric_accompaniment', root, settings, cache)
|
||||
warm = generator.production.generate_role(source, 'electric_accompaniment', root, settings, cache)
|
||||
self.assertTrue(warm['cache_hit'])
|
||||
self.assertEqual(other['document'], warm['document'])
|
||||
self.assertNotEqual(current['trace']['cache_key'], other['trace']['cache_key'])
|
||||
self.assertEqual(current['details']['accompaniment_rhythm'], other['details']['accompaniment_rhythm'])
|
||||
def test_lower_progression_can_outweigh_extra_boundary_travel(self):
|
||||
symbols = ('Em7b5', 'A7b9', 'Dm7', 'G7', 'Cm7', 'F7')
|
||||
low = tuple(tests.test_acoustic_voicing.voicing(f) for f in ((7, 8, 7, 8), (7, 8, 6, 8), (5, 7, 5, 6), (5, 5, 4, 6), (3, 5, 3, 4), (3, 3, 2, 4)))
|
||||
@@ -61,8 +85,8 @@ class CompingVoicings(unittest.TestCase):
|
||||
low = tests.test_acoustic_voicing.voicing((7, 8, 7, 8))
|
||||
resources = generator.vocabulary.load()
|
||||
key = generator.comping.semantic_key(generator.harmony.parse_symbol('Em7b5'))
|
||||
self.assertEqual(generator.comping.acoustic_preferences(high, 53), (fractions.Fraction(39, 4), fractions.Fraction(11, 4)))
|
||||
self.assertEqual(generator.comping.acoustic_preferences(low, 53)[1], 0)
|
||||
self.assertEqual(generator.comping.voicing_preferences('acoustic', high, 53), (fractions.Fraction(39, 4), fractions.Fraction(11, 4)))
|
||||
self.assertEqual(generator.comping.voicing_preferences('acoustic', low, 53)[1], 0)
|
||||
baseline = generator.comping.local_cost('acoustic', key, high, 53)
|
||||
for field, expected in (('register_weight', fractions.Fraction(39, 4)), ('high_position_weight', fractions.Fraction(11, 4)), ('comfortable_max_fret', -1)):
|
||||
policy = dict(resources['roles']['roles']['acoustic_accompaniment']['voicing'])
|
||||
@@ -159,7 +183,7 @@ class CompingVoicings(unittest.TestCase):
|
||||
def test_complete_path_beats_greedy_and_matches_exhaustive_search(self):
|
||||
for part in ('acoustic', 'electric'):
|
||||
with self.subTest(part=part):
|
||||
chords = ('C', 'Dm7', 'A7b9') if part == 'acoustic' else ('C', 'C', 'Dm7')
|
||||
chords = ('C', 'Dm7', 'A7b9') if part == 'acoustic' else ('C', 'FM7', 'C')
|
||||
layers = tuple(options(s, part) for s in chords)
|
||||
costs = tuple({v: generator.comping.local_cost(part, generator.comping.semantic_key(generator.harmony.parse_symbol(s)), v, 55) for v in layer} for s, layer in zip(chords, layers))
|
||||
path, cost = generator.comping.select_grips(layers, costs, part, 'test')
|
||||
|
||||
Reference in New Issue
Block a user