+14
-14
@@ -40,7 +40,7 @@ def tied_library(continuation_duration):
|
||||
second += '<note><rest/><duration>2</duration><type>half</type></note>'
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = pathlib.Path(temporary)
|
||||
path = root / '4-4/2/tied.xml'
|
||||
path = root / '4_4/2/tied.xml'
|
||||
path.parent.mkdir(parents=True)
|
||||
path.write_text(xml_bars([first, second]), encoding='utf-8')
|
||||
return generator.rhythm.load_library(root)
|
||||
@@ -57,7 +57,7 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
extra = '<time-modification><actual-notes>3</actual-notes><normal-notes>2</normal-notes></time-modification>'
|
||||
source = xml_bars([tests.test_musicxml.xml_note(duration=2, kind='quarter', extra=extra) * 6], divisions=3)
|
||||
with self.assertRaisesRegex(ValueError, 'time modifications'):
|
||||
self.load({'4-4/1/ratio.xml': source})
|
||||
self.load({'4_4/1/ratio.xml': source})
|
||||
def load(self, sources):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = pathlib.Path(temporary)
|
||||
@@ -71,9 +71,9 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
content += tests.test_musicxml.xml_note(duration=1, kind='16th', extra='<beam number="1">end</beam><beam number="2">backward hook</beam>')
|
||||
content += '<note><rest/><duration>4</duration><type>quarter</type></note>'
|
||||
content += tests.test_musicxml.xml_note(duration=8, kind='half')
|
||||
library = self.load({'4-4/1/dotted.xml': xml_bars([content], divisions=4)})
|
||||
library = self.load({'4_4/1/dotted.xml': xml_bars([content], divisions=4)})
|
||||
snippet = library.for_meter('4/4')[0]
|
||||
self.assertEqual((snippet.id, snippet.meter), ('4-4/1/dotted.xml', '4/4'))
|
||||
self.assertEqual((snippet.id, snippet.meter), ('4_4/1/dotted.xml', '4/4'))
|
||||
self.assertEqual(snippet.bars, (generator.rhythm.Bar((
|
||||
generator.rhythm.Event(fractions.Fraction(0), fractions.Fraction(3, 4), True, 'eighth', 1, ((1, 'begin'),)),
|
||||
generator.rhythm.Event(fractions.Fraction(3, 4), fractions.Fraction(1, 4), True, '16th', 0, ((1, 'end'), (2, 'backward hook'))),
|
||||
@@ -84,7 +84,7 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
self.assertTrue(all(type(e.onset) is fractions.Fraction and type(e.duration) is fractions.Fraction for e in snippet.bars[0].events))
|
||||
def test_two_bar_ties_are_continuations_without_new_attacks(self):
|
||||
content = xml_bars([tests.test_musicxml.xml_note(extra='<tie type="start"/>'), tests.test_musicxml.xml_note(extra='<tie type="stop"/>')])
|
||||
snippet = self.load({'4-4/2/tied.xml': content}).for_meter('4/4')[0]
|
||||
snippet = self.load({'4_4/2/tied.xml': content}).for_meter('4/4')[0]
|
||||
self.assertEqual(len(snippet.bars), 2)
|
||||
self.assertEqual([bar.attacks() for bar in snippet.bars], [(0,), ()])
|
||||
self.assertEqual([bar.events[0].continuation for bar in snippet.bars], [False, True])
|
||||
@@ -96,13 +96,13 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
content = tests.test_musicxml.xml_note(duration=duration, kind=kind, extra='<dot/>' if dots else '') if sounding else f'<note><rest/><duration>{duration}</duration><type>{kind}</type>{"<dot/>" if dots else ""}</note>'
|
||||
if beats == 5:
|
||||
content += tests.test_musicxml.xml_note(duration=1, kind='quarter')
|
||||
snippet = self.load({f'{beats}-4/3/0001.xml': xml_bars([content], beats=beats)}).for_meter(f'{beats}/4')[0]
|
||||
snippet = self.load({f'{beats}_4/3/0001.xml': xml_bars([content], beats=beats)}).for_meter(f'{beats}/4')[0]
|
||||
self.assertEqual(snippet.bars[0].events[0], generator.rhythm.Event(fractions.Fraction(), fractions.Fraction(duration), sounding, kind, dots))
|
||||
self.assertEqual(snippet.bars[0].length, beats)
|
||||
def test_all_three_series_participate_in_deterministic_long_note_selection(self):
|
||||
silence = '<note><rest/><duration>4</duration><type>whole</type></note>'
|
||||
halves = tests.test_musicxml.xml_note(duration=2, kind='half') * 2
|
||||
library = self.load({'4-4/1/0001.xml': xml_bars([silence] * 2), '4-4/2/0001.xml': xml_bars([silence]), '4-4/3/0001.xml': xml_bars([halves])})
|
||||
library = self.load({'4_4/1/0001.xml': xml_bars([silence] * 2), '4_4/2/0001.xml': xml_bars([silence]), '4_4/3/0001.xml': xml_bars([halves])})
|
||||
self.assertEqual(len(library.for_meter('4/4')), 3)
|
||||
measures = melody_measures(8)
|
||||
plan = generator.accompaniment.plan_section(measures, library)
|
||||
@@ -134,10 +134,10 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
for beats in (2, 3, 4, 5):
|
||||
content = xml_bars([''.join(tests.test_musicxml.xml_note(duration=1, kind='quarter') for _ in range(beats))], beats=beats)
|
||||
for name in ('z', 'a'):
|
||||
sources[f'{beats}-4/1/{name}.xml'] = content
|
||||
sources[f'{beats}_4/1/{name}.xml'] = content
|
||||
library = self.load(sources)
|
||||
for beats in (2, 3, 4, 5):
|
||||
self.assertEqual([s.id for s in library.for_meter(f'{beats}/4')], [f'{beats}-4/1/a.xml', f'{beats}-4/1/z.xml'])
|
||||
self.assertEqual([s.id for s in library.for_meter(f'{beats}/4')], [f'{beats}_4/1/a.xml', f'{beats}_4/1/z.xml'])
|
||||
self.assertTrue(all(s.bars[0].length == beats for s in library.for_meter(f'{beats}/4')))
|
||||
def test_missing_empty_unsupported_and_misfiled_libraries_fail(self):
|
||||
with tempfile.TemporaryDirectory() as temporary, self.assertRaisesRegex(ValueError, 'not found'):
|
||||
@@ -145,12 +145,12 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
with self.assertRaisesRegex(ValueError, 'empty'):
|
||||
self.load({})
|
||||
source = xml_bars([tests.test_musicxml.xml_note()])
|
||||
for path in ('snippet.xml', '4-4/snippet.xml', '4-4/4/snippet.xml', '4-4/1/nested/snippet.xml', '6-8/1/snippet.xml'):
|
||||
for path in ('snippet.xml', '4_4/snippet.xml', '4_4/4/snippet.xml', '4_4/1/nested/snippet.xml', '6-8/1/snippet.xml'):
|
||||
with self.subTest(path=path), self.assertRaisesRegex(ValueError, 'meter/series'):
|
||||
self.load({path: source})
|
||||
with self.assertRaisesRegex(ValueError, 'meter disagrees'):
|
||||
self.load({'3-4/1/snippet.xml': source})
|
||||
library = self.load({'4-4/1/snippet.xml': source})
|
||||
self.load({'3_4/1/snippet.xml': source})
|
||||
library = self.load({'4_4/1/snippet.xml': source})
|
||||
for meter in ('2/4', '6/8', '7/4', '4/8', 'invalid'):
|
||||
with self.subTest(meter=meter), self.assertRaisesRegex(ValueError, 'rhythm snippets'):
|
||||
library.for_meter(meter)
|
||||
@@ -175,7 +175,7 @@ class RhythmLibraryTests(unittest.TestCase):
|
||||
}
|
||||
for name, content in cases.items():
|
||||
with self.subTest(source=name), self.assertRaises(ValueError):
|
||||
self.load({'4-4/1/invalid.xml': content})
|
||||
self.load({'4_4/1/invalid.xml': content})
|
||||
|
||||
class AccompanimentPlanningTests(unittest.TestCase):
|
||||
def test_pickup_coverage_excludes_notes_that_ended_before_the_excerpt(self):
|
||||
@@ -251,7 +251,7 @@ class AccompanimentPlanningTests(unittest.TestCase):
|
||||
self.assertTrue(attacks <= melody)
|
||||
self.assertTrue(any(bar.attacks() for bar in plan.electric))
|
||||
def test_section_and_local_meter_changes_restart_the_motif(self):
|
||||
library = generator.rhythm.Library(tuple(generator.rhythm.Snippet(f'{beats}-4/pair', f'{beats}/4', (quarter_bar(beats, {0}), quarter_bar(beats, {1}))) for beats in (3, 4)))
|
||||
library = generator.rhythm.Library(tuple(generator.rhythm.Snippet(f'{beats}_4/pair', f'{beats}/4', (quarter_bar(beats, {0}), quarter_bar(beats, {1}))) for beats in (3, 4)))
|
||||
segments = [melody_measures(3), melody_measures(2, beats=3), melody_measures(3), melody_measures(4)]
|
||||
segments[-1][0]['section_label'] = 'Bridge'
|
||||
measures = [m for segment in segments for m in segment]
|
||||
|
||||
Reference in New Issue
Block a user