Construction
This commit is contained in:
@@ -35,12 +35,13 @@ class AcousticPairs(unittest.TestCase):
|
||||
self.assertEqual(tuple(e.start for e in events), tuple(map(F, onsets)))
|
||||
def test_pairing_uses_attack_spacing_not_written_duration(self):
|
||||
events = self.assign(('0', '1/2'), ('1', '1'))
|
||||
self.assertEqual([(e.lane, e.end) for e in events], [('bass', F(1)), ('upper', F(3, 2))])
|
||||
# Bass keeps ringing, without another bass attack under the upper chord.
|
||||
self.assertGreater(events[0].end, events[1].start)
|
||||
def test_same_strings_release_but_different_strings_can_ring(self):
|
||||
self.assertEqual([(e.lane, e.end) for e in events], [('bass', F(1, 2)), ('upper', F(3, 2))])
|
||||
self.assertEqual(events[0].end, events[1].start)
|
||||
def test_each_attack_releases_previous_sound_in_both_directions(self):
|
||||
events = self.assign(('0', '1/2', '1'), ('2', '2', '1'))
|
||||
self.assertEqual([(e.lane, e.end) for e in events], [('bass', F(1)), ('upper', F(1)), ('combined', F(2))])
|
||||
self.assertEqual([(e.lane, e.end) for e in events], [('bass', F(1, 2)), ('upper', F(1)), ('combined', F(2))])
|
||||
events = self.assign(('0', '1/2', '1', '3/2'), ('2', '2', '2', '2'))
|
||||
self.assertEqual([(e.lane, e.end) for e in events], [('bass', F(1, 2)), ('upper', F(1)), ('bass', F(3, 2)), ('upper', F(7, 2))])
|
||||
events = self.assign(('0', '1/2'), ('1', '3'))
|
||||
self.assertEqual(events[-1].end, F(7, 2))
|
||||
def test_chord_change_breaks_pair_but_repeated_label_does_not(self):
|
||||
@@ -66,17 +67,17 @@ class AcousticPairs(unittest.TestCase):
|
||||
{'onset': str(t), 'duration': '1', 'layer': 'acoustic'} for t in (F(beats) - F(1, 2), F(beats))]}
|
||||
events, _ = generator.comping_rhythm.fit(pattern, flat, None, 'acoustic')
|
||||
self.assertEqual([e.lane for e in events], ['bass', 'upper'])
|
||||
self.assertEqual(events[0].end, F(beats) + F(1, 2))
|
||||
def test_anticipated_pair_plays_same_future_harmony(self):
|
||||
self.assertEqual(events[0].end, F(beats))
|
||||
def test_release_rebinds_expired_anticipation_to_direct_harmony(self):
|
||||
source = tests.solo_fixtures.song(count=2, chords=('C7', 'FM7'))
|
||||
flat = generator.comping_rhythm.flatten(tuple((m, None, i) for i, m in enumerate(source['staves'][0]['measures'])))
|
||||
pattern = {'lengths': ['4', '4'], 'events': [
|
||||
{'onset': '7/2', 'duration': '1', 'layer': 'acoustic', 'anticipate': True},
|
||||
{'onset': '4', 'duration': '1', 'layer': 'acoustic'}]}
|
||||
events, _ = generator.comping_rhythm.fit(pattern, flat, None, 'acoustic', anticipate=True)
|
||||
self.assertEqual([e.lane for e in events], ['bass', 'upper'])
|
||||
self.assertEqual(events[0].harmonic_time, 4)
|
||||
self.assertGreater(events[0].end, 4)
|
||||
self.assertEqual([e.lane for e in events], ['combined', 'combined'])
|
||||
self.assertIsNone(events[0].harmonic_time)
|
||||
self.assertEqual(events[0].end, 4)
|
||||
# A participation break prevents pairing; an expired anticipation must
|
||||
# revert to the current harmony rather than keep an unresolved label.
|
||||
raw, _ = generator.comping_rhythm.fit(pattern, flat, None, 'acoustic', anticipate=True, assign=False)
|
||||
@@ -84,6 +85,11 @@ class AcousticPairs(unittest.TestCase):
|
||||
self.assertEqual([e.lane for e in broken], ['combined', 'combined'])
|
||||
self.assertIsNone(broken[0].harmonic_time)
|
||||
self.assertEqual(broken[0].end, 4)
|
||||
# With no intervening attack the bounded anticipated hold stays intact.
|
||||
pattern['events'].pop()
|
||||
held, _ = generator.comping_rhythm.fit(pattern, flat, None, 'acoustic', anticipate=True)
|
||||
self.assertEqual(held[0].harmonic_time, 4)
|
||||
self.assertEqual(held[0].end, F(9, 2))
|
||||
def resources(self):
|
||||
resources = copy.deepcopy(generator.vocabulary.load())
|
||||
policy = resources['accompaniment']['instruments']['acoustic']
|
||||
|
||||
Reference in New Issue
Block a user