import copy import fractions import pathlib import unittest import generator.engraving.fonts import generator.engraving.layout import generator.engraving.notation import generator.engraving.types import generator.model import generator.playback import generator.scat import tests.test_musicxml class ScatTests(unittest.TestCase): def test_syllables_use_duration_pulse_phrase_and_previous_consonant(self): self.assertEqual(generator.scat.syllable(fractions.Fraction(2), fractions.Fraction(1), False, True, ''), 'doo') self.assertEqual(generator.scat.syllable(fractions.Fraction(1, 2), fractions.Fraction(1), True, False, ''), 'ba') self.assertEqual(generator.scat.syllable(fractions.Fraction(1, 2), fractions.Fraction(1), False, False, ''), 'dit') self.assertEqual(generator.scat.syllable(fractions.Fraction(1, 2), fractions.Fraction(1), False, False, 'dit'), 'da') self.assertEqual(generator.scat.syllable(fractions.Fraction(1, 2), fractions.Fraction(1), True, True, ''), 'dat') self.assertEqual(generator.scat.syllable(fractions.Fraction(1, 2), None, False, False, ''), 'ba') def test_compound_additive_meter_and_pickups(self): measure = {'meter': {'groups': [{'beats': [6], 'unit': 8}]}, 'duration': generator.model.rational(3)} self.assertEqual(generator.scat.pulse(measure, fractions.Fraction(3, 2)), (fractions.Fraction(3, 2), True)) measure['meter']['groups'][0]['beats'] = [3, 2] self.assertEqual(generator.scat.pulse(measure, fractions.Fraction(3, 2)), (fractions.Fraction(1), True)) measure.update(implicit=True, duration=generator.model.rational(fractions.Fraction(1, 2))) self.assertEqual(generator.scat.pulse(measure, fractions.Fraction()), (fractions.Fraction(1), False)) def test_ties_sustain_one_syllable_and_stop_before_rests(self): content = tests.test_musicxml.xml_note(duration=1, kind='quarter', extra='') + tests.test_musicxml.xml_note(duration=1, kind='quarter', extra='') content += '2half' document = tests.test_musicxml.parse(tests.test_musicxml.xml_score(content)) original = copy.deepcopy(document) before = generator.playback.compile_timeline(document) generator.scat.add_scat(document) self.assertEqual(generator.playback.compile_timeline(document), before) self.assertEqual(tests.test_musicxml.notes(document)[0]['lyric'], 'doo') self.assertEqual(tests.test_musicxml.notes(document)[0]['lyrics'][0]['extend_to'], generator.model.rational(2)) self.assertNotIn('lyric', tests.test_musicxml.notes(document)[1]) self.assertNotIn('lyrics', tests.test_musicxml.notes(document)[2]) again = copy.deepcopy(original) generator.scat.add_scat(again) self.assertEqual(document, again) fonts = generator.engraving.fonts.Fonts(pathlib.Path('package/assets/fonts/petaluma')) layout = generator.engraving.layout.layout_score(document, generator.engraving.types.Style(), fonts) system = layout.pages[0].systems[0] rest = next(a.x for a in system.anchors if a.fragment.kind == 'rest') self.assertTrue(all(p.box.right < rest for p in system.primitives if p.role == 'lyric-extension')) def test_cross_bar_tie_has_one_lyric_and_page_continuations(self): text = tests.test_musicxml.xml_score(tests.test_musicxml.xml_note(extra='')) text = text.replace('', '' + tests.test_musicxml.xml_note(extra='') + '') document = tests.test_musicxml.parse(text) generator.scat.add_scat(document) self.assertEqual(sum(bool(n.get('lyric')) for n in tests.test_musicxml.notes(document)), 1) fonts = generator.engraving.fonts.Fonts(pathlib.Path('package/assets/fonts/petaluma')) for start, end in ((0, 4), (4, 8)): system = generator.engraving.layout.make_system(generator.engraving.notation.ScoreIndex(document), start, end, fonts, generator.engraving.types.Style()) self.assertTrue(any(p.role == 'lyric-extension' for p in system.primitives)) def test_long_tie_chain_draws_one_extender_per_system(self): text = tests.test_musicxml.xml_score(tests.test_musicxml.xml_note(extra='')) text = text.replace('', '' + tests.test_musicxml.xml_note(extra='') + '' + tests.test_musicxml.xml_note(extra='') + '') document = tests.test_musicxml.parse(text) generator.scat.add_scat(document) fonts = generator.engraving.fonts.Fonts(pathlib.Path('package/assets/fonts/petaluma')) index = generator.engraving.notation.ScoreIndex(document) for start, end in ((0, 4), (4, 8), (8, 12), (0, 12)): system = generator.engraving.layout.make_system(index, start, end, fonts, generator.engraving.types.Style()) self.assertEqual(sum(p.role == 'lyric-extension' for p in system.primitives), 1) def test_straight_offbeat_attacks_and_cues(self): document = tests.test_musicxml.parse(tests.test_musicxml.xml_score(''.join(tests.test_musicxml.xml_note(duration=1, kind='eighth') for _ in range(8)), divisions=2)) before = generator.playback.compile_timeline(document) generator.scat.add_scat(document) self.assertEqual([n['lyric'] for n in tests.test_musicxml.notes(document)], ['ba', 'dit', 'ba', 'dit', 'ba', 'dit', 'ba', 'dat']) self.assertEqual(generator.playback.compile_timeline(document), before) document = tests.test_musicxml.parse(tests.test_musicxml.xml_score(tests.test_musicxml.xml_note(prefix=''))) generator.scat.add_scat(document) self.assertNotIn('lyrics', tests.test_musicxml.notes(document)[0])