|
| 1 | +"""Combinations of features of the MusicXML export.""" |
| 2 | +from fractions import Fraction |
| 3 | + |
| 4 | +from .musicxml_helpers import ( |
| 5 | + convert, divisions, measure_lengths, measures, notes, pitch, pitches, |
| 6 | + quarters, validate) |
| 7 | + |
| 8 | + |
| 9 | +def test_after_grace_with_fraction_and_articulation(): |
| 10 | + root = convert(r"{ \afterGrace 7/8 c'2-> { d'16 } f'2 }") |
| 11 | + n = notes(root) |
| 12 | + assert pitches(root) == ['C4', 'D4', 'F4'] |
| 13 | + assert n[0].find('notations/articulations/accent') is not None |
| 14 | + assert n[1].find('grace').get('steal-time-previous') == '12.5' |
| 15 | + assert measure_lengths(root) == [4] |
| 16 | + validate(root) |
| 17 | + |
| 18 | + |
| 19 | +def test_transposed_chord_names(): |
| 20 | + root = convert(r"\transpose c d \chords { c1 f1/a bes1:7 }") |
| 21 | + h = root.findall('.//harmony') |
| 22 | + assert [(x.findtext('root/root-step'), x.findtext('bass/bass-step')) for x in h] == [ |
| 23 | + ('D', None), ('G', 'B'), ('C', None)] |
| 24 | + validate(root) |
| 25 | + |
| 26 | + |
| 27 | +def test_transposed_chordmode_notes(): |
| 28 | + root = convert(r"\transpose c d \new Staff \chordmode { c1:7 }") |
| 29 | + assert pitches(root) == ['D3', 'F#3', 'A3', 'C4'] |
| 30 | + |
| 31 | + |
| 32 | +def test_lyrics_on_split_notes(): |
| 33 | + root = convert(r"""\score { << |
| 34 | + \new Voice = "m" { \time 3/4 c'2 d'2 e'2 } |
| 35 | + \new Lyrics \lyricsto "m" { a b c } |
| 36 | +>> }""") |
| 37 | + assert [(pitch(n), [l.findtext('text') for l in n.findall('lyric')]) for n in notes(root)] == [ |
| 38 | + ('C4', ['a']), ('D4', ['b']), ('D4', []), ('E4', ['c'])] |
| 39 | + validate(root) |
| 40 | + |
| 41 | + |
| 42 | +def test_chord_name_offset_needs_finer_divisions(): |
| 43 | + root = convert(r"""\score { << |
| 44 | + \chords { c8 g2..:7 } |
| 45 | + \new Staff { c'1 } |
| 46 | +>> }""") |
| 47 | + h = root.findall('part/measure/harmony') |
| 48 | + assert len(h) == 2 |
| 49 | + assert divisions(root) == 2 |
| 50 | + assert h[1].findtext('offset') == '1' |
| 51 | + validate(root) |
| 52 | + |
| 53 | + |
| 54 | +def test_drum_chord_at_end_of_measure(): |
| 55 | + root = convert(r"\new DrumStaff \drummode { <bd hh>2 <sn hh>2 <bd hh>1 }") |
| 56 | + assert measure_lengths(root) == [4, 4] |
| 57 | + assert [len(m.findall('note')) for m in measures(root)] == [4, 2] |
| 58 | + validate(root) |
| 59 | + |
| 60 | + |
| 61 | +def test_tuplet_with_rest_at_barline(): |
| 62 | + root = convert(r"{ \time 2/4 \tuplet 3/2 { c'4 r c' } c'2 }") |
| 63 | + assert measure_lengths(root) == [2, 2] |
| 64 | + assert divisions(root) == 3 |
| 65 | + validate(root) |
| 66 | + |
| 67 | + |
| 68 | +def test_dynamic_on_empty_chord_in_measures(): |
| 69 | + root = convert(r"{ c'1 <>\p d'1 }") |
| 70 | + m = measures(root) |
| 71 | + assert measure_lengths(root) == [4, 4] |
| 72 | + assert m[0].find('direction') is None |
| 73 | + assert m[1].find('direction/direction-type/dynamics/p') is not None |
| 74 | + validate(root) |
| 75 | + |
| 76 | + |
| 77 | +def test_part_combine_across_barlines(): |
| 78 | + root = convert(r"\new Staff \partCombine { \time 3/4 c''2. c''2. } { a'2 a'1 }") |
| 79 | + assert measure_lengths(root) == [3, 3] |
| 80 | + q = quarters(root) |
| 81 | + assert [q(n.findtext('duration')) for n in notes(root) if n.findtext('voice') == '2'] == [2, 1, 3] |
| 82 | + validate(root) |
| 83 | + |
| 84 | + |
| 85 | +def test_repeat_with_chords_and_lyrics(): |
| 86 | + root = convert(r"""\score { << |
| 87 | + \chords { \repeat volta 2 { c1 } g1:7 } |
| 88 | + \new Voice = "m" { \repeat volta 2 { e'1 } d'1 } |
| 89 | + \new Lyrics \lyricsto "m" { la lo } |
| 90 | +>> }""") |
| 91 | + m = measures(root) |
| 92 | + assert len(m) == 2 |
| 93 | + assert m[0].find("barline[@location='left']/repeat").get('direction') == 'forward' |
| 94 | + assert m[0].find("barline[@location='right']/repeat").get('direction') == 'backward' |
| 95 | + assert [len(x.findall('harmony')) for x in m] == [1, 1] |
| 96 | + assert [[l.findtext('text') for l in n.findall('lyric')] for n in notes(root)] == [['la'], ['lo']] |
| 97 | + validate(root) |
| 98 | + |
| 99 | + |
| 100 | +def test_after_grace_in_transposed_variable(): |
| 101 | + root = convert(r""" |
| 102 | +orn = \afterGrace c'2 { d'16 } |
| 103 | +\score { \transpose c d { \orn e'2 } } |
| 104 | +""") |
| 105 | + assert pitches(root) == ['D4', 'E4', 'F#4'] |
| 106 | + assert measure_lengths(root) == [4] |
| 107 | + |
| 108 | + |
| 109 | +def test_addlyrics_for_voices_in_staff_group(): |
| 110 | + root = convert(r"""\score { |
| 111 | + \new StaffGroup << |
| 112 | + \new Voice = "S" { \set Staff.instrumentName = #"Cantus" c''2 d'' } |
| 113 | + \addlyrics { Du tout } |
| 114 | + \new Voice = "B" { \set Staff.instrumentName = #"Bassus" c2 g, } |
| 115 | + \addlyrics { plon giet } |
| 116 | + >> |
| 117 | +}""") |
| 118 | + assert [p.findtext('part-name') for p in root.findall('part-list/score-part')] == [ |
| 119 | + 'Cantus', 'Bassus'] |
| 120 | + assert [[(pitch(n), [l.findtext('text') for l in n.findall('lyric')]) for n in notes(root, i)] |
| 121 | + for i in range(2)] == [ |
| 122 | + [('C5', ['Du']), ('D5', ['tout'])], |
| 123 | + [('C3', ['plon']), ('G2', ['giet'])], |
| 124 | + ] |
| 125 | + validate(root) |
0 commit comments