+24
-24
@@ -9,7 +9,7 @@ import generator.harmony
|
||||
import generator.model
|
||||
import generator.parts
|
||||
import generator.playback
|
||||
import generator.practice.generate
|
||||
import tests.arrangement_fixtures
|
||||
import generator.rhythm
|
||||
import tests.rhythm_fixtures
|
||||
import tests.test_accompaniment
|
||||
@@ -17,9 +17,9 @@ import tests.test_musicxml
|
||||
import tests.test_parts
|
||||
|
||||
class GuitarPartTests(unittest.TestCase):
|
||||
def practice(self, content, part='electric', divisions=1):
|
||||
def section(self, content, part='electric', divisions=1):
|
||||
source = tests.test_musicxml.parse(tests.test_musicxml.xml_score(content, divisions=divisions))
|
||||
result = generator.practice.generate.practice_document(source, part, rhythms=tests.rhythm_fixtures.library())
|
||||
result = tests.arrangement_fixtures.section_document(source, part, rhythms=tests.rhythm_fixtures.library())
|
||||
generator.model.validate_document(result)
|
||||
return result
|
||||
def test_profile_shapes_cover_defining_chord_tones(self):
|
||||
@@ -40,7 +40,7 @@ class GuitarPartTests(unittest.TestCase):
|
||||
candidates = generator.guitar.chord_positions(*generator.guitar.chord_requirements(chord, 'electric'), profile='electric')
|
||||
self.assertTrue(any(all(p.midi % 12 != 0 for p in c) for c in candidates))
|
||||
def test_acoustic_combines_independent_rhythms_with_a_fixed_grip(self):
|
||||
result = self.practice(tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note(), 'acoustic')
|
||||
result = self.section(tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note(), 'acoustic')
|
||||
measure = result['staves'][0]['measures'][0]
|
||||
self.assertEqual(len(measure['voices']), 1)
|
||||
notes = measure['voices'][0]['notes']
|
||||
@@ -70,15 +70,15 @@ class GuitarPartTests(unittest.TestCase):
|
||||
source = tests.test_musicxml.parse(tests.test_musicxml.xml_score(tests.test_musicxml.xml_note()))
|
||||
chord = generator.harmony.parse_symbol(symbol)
|
||||
source['staves'][0]['measures'][0]['harmonies'] = [{**chord, 'id': 'h1', 'onset': generator.model.rational(0)}]
|
||||
result = generator.practice.generate.practice_document(source, 'acoustic', rhythms=tests.rhythm_fixtures.library())
|
||||
result = tests.arrangement_fixtures.section_document(source, 'acoustic', rhythms=tests.rhythm_fixtures.library())
|
||||
notes = tests.test_musicxml.notes(result)
|
||||
self.assertEqual({generator.model.pitch_number(p) % 12 for n in notes for p in n['pitches'] if p['tablature']['string'] >= 5}, {expected})
|
||||
def test_acoustic_bass_and_upper_chord_can_attack_together(self):
|
||||
source = tests.test_musicxml.parse(tests.test_musicxml.xml_score(tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note()))
|
||||
prepared = generator.parts.prepare_document(source, practice=True)
|
||||
prepared = generator.parts.prepare_document(source)
|
||||
bar = tests.test_accompaniment.quarter_bar(4, {0, 2})
|
||||
plan = generator.accompaniment.Plan((bar,), (bar,), ())
|
||||
result = generator.practice.generate._practice_document(prepared, 'acoustic', plan)
|
||||
result = tests.arrangement_fixtures.section_document(prepared, 'acoustic', rhythms=tests.rhythm_fixtures.library(), plan=plan)
|
||||
generator.model.validate_document(result)
|
||||
self.assertEqual(len(result['staves'][0]['measures'][0]['voices']), 1)
|
||||
notes = tests.test_musicxml.notes(result)
|
||||
@@ -89,15 +89,15 @@ class GuitarPartTests(unittest.TestCase):
|
||||
self.assertIn(tuple(sorted((p.string_number for p in positions), reverse=True)), generator.guitar.ACOUSTIC_STRINGS)
|
||||
self.assertTrue(generator.guitar.within_fret_span(positions))
|
||||
def test_long_melody_chords_and_short_notes(self):
|
||||
content = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('E', 2, 'half', octave=5) + tests.test_musicxml.xml_note('G', 1, 'quarter', octave=5) + tests.test_musicxml.xml_note('C', 1, 'quarter', octave=6)
|
||||
notes = tests.test_musicxml.notes(self.practice(content))
|
||||
content = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('E', 2, 'half', octave=4) + tests.test_musicxml.xml_note('G', 1, 'quarter', octave=4) + tests.test_musicxml.xml_note('C', 1, 'quarter', octave=5)
|
||||
notes = tests.test_musicxml.notes(self.section(content))
|
||||
self.assertIn(len(notes[0]['pitches']), (3, 4))
|
||||
self.assertEqual([len(n['pitches']) for n in notes[1:]], [1, 1])
|
||||
self.assertEqual(generator.model.pitch_number(notes[0]['pitches'][0]), 76)
|
||||
self.assertIn(sorted(p['tablature']['string'] for p in notes[0]['pitches']), ([1, 2, 3], [1, 2, 3, 4]))
|
||||
def test_tied_quarters_qualify_and_keep_all_strings(self):
|
||||
content = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('E', 1, 'quarter', octave=5, extra='<tie type="start"/>') + tests.test_musicxml.xml_note('E', 1, 'quarter', octave=5, extra='<tie type="stop"/>') + '<note><rest/><duration>2</duration><type>half</type></note>'
|
||||
result = self.practice(content)
|
||||
content = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('E', 1, 'quarter', octave=4, extra='<tie type="start"/>') + tests.test_musicxml.xml_note('E', 1, 'quarter', octave=4, extra='<tie type="stop"/>') + '<note><rest/><duration>2</duration><type>half</type></note>'
|
||||
result = self.section(content)
|
||||
first, second = tests.test_musicxml.notes(result)[:2]
|
||||
self.assertIn(len(first['pitches']), (3, 4))
|
||||
self.assertEqual(len(first['pitches']), len(second['pitches']))
|
||||
@@ -106,8 +106,8 @@ class GuitarPartTests(unittest.TestCase):
|
||||
self.assertEqual(after['tablature'], before['tablature'])
|
||||
self.assertEqual({generator.model.fraction(e['duration']) for e in generator.playback.compile_timeline(result)['events']}, {2})
|
||||
def test_chord_change_reattacks_even_for_final_eighth(self):
|
||||
content = tests.test_parts.xml_harmony() + tests.test_parts.xml_harmony('F', offset=7) + tests.test_musicxml.xml_note('G', 8, 'whole', octave=5)
|
||||
result = self.practice(content, divisions=2)
|
||||
content = tests.test_parts.xml_harmony() + tests.test_parts.xml_harmony('F', offset=7) + tests.test_musicxml.xml_note('G', 8, 'whole', octave=4)
|
||||
result = self.section(content, divisions=2)
|
||||
notes = tests.test_musicxml.notes(result)
|
||||
self.assertEqual([generator.model.fraction(n['duration']) for n in notes], [fractions.Fraction(7, 2), fractions.Fraction(1, 2)])
|
||||
for note in notes:
|
||||
@@ -118,10 +118,10 @@ class GuitarPartTests(unittest.TestCase):
|
||||
def test_cross_measure_ties_continue_only_without_a_chord_change(self):
|
||||
for root in ('C', 'F'):
|
||||
with self.subTest(root=root):
|
||||
first = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('E', octave=5, extra='<tie type="start"/>')
|
||||
second = tests.test_parts.xml_harmony(root) + tests.test_musicxml.xml_note('E', octave=5, extra='<tie type="stop"/>')
|
||||
first = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('E', octave=4, extra='<tie type="start"/>')
|
||||
second = tests.test_parts.xml_harmony(root) + tests.test_musicxml.xml_note('E', octave=4, extra='<tie type="stop"/>')
|
||||
source = tests.test_musicxml.parse(tests.test_accompaniment.xml_bars([first, second]))
|
||||
result = generator.practice.generate.practice_document(source, 'electric', rhythms=tests.rhythm_fixtures.library())
|
||||
result = tests.arrangement_fixtures.section_document(source, 'electric', rhythms=tests.rhythm_fixtures.library())
|
||||
generator.model.validate_document(result)
|
||||
notes = [n for m in result['staves'][0]['measures'] for v in m['voices'] for n in v['notes']]
|
||||
self.assertTrue(all(len(n['pitches']) in (3, 4) for n in notes))
|
||||
@@ -133,16 +133,16 @@ class GuitarPartTests(unittest.TestCase):
|
||||
extra = '<time-modification><actual-notes>3</actual-notes><normal-notes>2</normal-notes><normal-type>half</normal-type></time-modification>'
|
||||
if index != 1:
|
||||
extra += '<notations><tuplet type="' + ('start' if index == 0 else 'stop') + '"/></notations>'
|
||||
content += tests.test_musicxml.xml_note('E', 4, 'half', octave=5, extra=extra)
|
||||
result = self.practice(content, divisions=3)
|
||||
content += tests.test_musicxml.xml_note('E', 4, 'half', octave=4, extra=extra)
|
||||
result = self.section(content, divisions=3)
|
||||
notes = tests.test_musicxml.notes(result)
|
||||
self.assertEqual([generator.model.fraction(n['duration']) for n in notes], [fractions.Fraction(4, 3)] * 2 + [fractions.Fraction(2, 3)] * 2)
|
||||
self.assertEqual(result['staves'][0]['tuplets'][0]['end'], notes[-1]['id'])
|
||||
self.assertTrue(all(len(n['pitches']) in (3, 4) for n in notes))
|
||||
self.assertFalse(notes[-1]['pitches'][0].get('tie_from'))
|
||||
def test_no_chord_releases_harmony_without_reattacking_melody(self):
|
||||
content = tests.test_parts.xml_harmony() + tests.test_parts.xml_harmony(kind='none', offset=2) + tests.test_musicxml.xml_note('E', octave=5)
|
||||
result = self.practice(content)
|
||||
content = tests.test_parts.xml_harmony() + tests.test_parts.xml_harmony(kind='none', offset=2) + tests.test_musicxml.xml_note('E', octave=4)
|
||||
result = self.section(content)
|
||||
first, second = tests.test_musicxml.notes(result)
|
||||
self.assertIn(len(first['pitches']), (3, 4))
|
||||
self.assertEqual(len(second['pitches']), 1)
|
||||
@@ -151,20 +151,20 @@ class GuitarPartTests(unittest.TestCase):
|
||||
self.assertEqual(sum(generator.model.fraction(e['duration']) == 4 for e in timeline), 1)
|
||||
self.assertTrue(all(generator.model.fraction(e['onset']) == 0 for e in timeline))
|
||||
def test_unplayable_harmonization_preserves_low_melody(self):
|
||||
content = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('C', octave=4)
|
||||
content = tests.test_parts.xml_harmony() + tests.test_musicxml.xml_note('C', octave=3)
|
||||
with self.assertLogs('generator.guitar', level='WARNING'):
|
||||
result = self.practice(content)
|
||||
result = self.section(content)
|
||||
note = tests.test_musicxml.notes(result)[0]
|
||||
self.assertEqual(len(note['pitches']), 1)
|
||||
self.assertEqual(note['pitches'][0]['tablature'], {'string': 5, 'fret': 3})
|
||||
def test_song_melody_only_is_raised_an_octave(self):
|
||||
source = tests.test_musicxml.parse(tests.test_musicxml.xml_score(tests.test_musicxml.xml_note('E', octave=4)))
|
||||
before = copy.deepcopy(source)
|
||||
for builder in (generator.practice.generate.practice_document, generator.arrange.generate.arrange_document):
|
||||
for builder in (tests.arrangement_fixtures.section_document, generator.arrange.generate.arrange_document):
|
||||
for part in ('electric', 'vocal'):
|
||||
result = builder(source, part, rhythms=tests.rhythm_fixtures.library())
|
||||
notes = [n for m in result['staves'][0]['measures'] for v in m['voices'] for n in v['notes'] if n['pitches']]
|
||||
expected = 76 if part == 'electric' and builder is generator.arrange.generate.arrange_document else 64
|
||||
expected = 76 if part == 'electric' else 64
|
||||
self.assertEqual({generator.model.pitch_number(n['pitches'][0]) for n in notes}, {expected})
|
||||
self.assertEqual(source, before)
|
||||
def test_electric_stabs_are_capped_and_do_not_continue(self):
|
||||
|
||||
Reference in New Issue
Block a user