diff --git a/ly/musicxml/create_musicxml.py b/ly/musicxml/create_musicxml.py index 8fb82b7b..13b940dc 100644 --- a/ly/musicxml/create_musicxml.py +++ b/ly/musicxml/create_musicxml.py @@ -112,8 +112,10 @@ def create_part(self, name="unnamed", abbr=False, midi=False): self.part_count += 1 self.bar_nr = 1 - def create_measure(self, **bar_attrs): + def create_measure(self, pickup = False, **bar_attrs): """Create new measure """ + if pickup and self.bar_nr == 1: + self.bar_nr = 0 self.current_bar = etree.SubElement(self.current_part, "measure", number=str(self.bar_nr)) self.bar_nr +=1 if bar_attrs: diff --git a/ly/musicxml/ly2xml_mediator.py b/ly/musicxml/ly2xml_mediator.py index a9ec6951..1023f6c8 100644 --- a/ly/musicxml/ly2xml_mediator.py +++ b/ly/musicxml/ly2xml_mediator.py @@ -76,6 +76,7 @@ def __init__(self): self.prev_tremolo = 8 self.tupl_dur = 0 self.tupl_sum = 0 + self.bar_is_pickup = False def new_header_assignment(self, name, value): """Distributing header information.""" @@ -309,11 +310,17 @@ def get_first_var(self): if self.sections: return self.sections[0].barlist + def set_pickup(self): + self.bar_is_pickup = True + def new_bar(self, fill_prev=True): if self.bar and fill_prev: self.bar.list_full = True self.current_attr = xml_objs.BarAttr() self.bar = xml_objs.Bar() + if self.bar_is_pickup: + self.bar.pickup = True + self.bar_is_pickup = False self.bar.obj_list = [self.current_attr] self.insert_into.barlist.append(self.bar) diff --git a/ly/musicxml/lymus2musxml.py b/ly/musicxml/lymus2musxml.py index 13dfb733..8d9e64d0 100644 --- a/ly/musicxml/lymus2musxml.py +++ b/ly/musicxml/lymus2musxml.py @@ -89,6 +89,7 @@ def __init__(self): self.slurcount = 0 self.slurnr = 0 self.phrslurnr = 0 + self.pickup = False def parse_text(self, ly_text, filename=None): """Parse the LilyPond source specified as text. @@ -266,6 +267,9 @@ def Relative(self, relative): r"""A \relative music expression.""" self.relative = True + def Partial(self, partial): + self.pickup = True + def Note(self, note): """ notename, e.g. c, cis, a bes ... """ #print(note.token) @@ -340,6 +344,9 @@ def Duration(self, duration): elif self.tupl_span: self.mediator.set_tuplspan_dur(duration.token, duration.tokens) self.tupl_span = False + elif self.pickup: + self.mediator.set_pickup() + self.pickup = False else: self.mediator.new_duration_token(duration.token, duration.tokens) if self.trem_rep: diff --git a/ly/musicxml/xml_objs.py b/ly/musicxml/xml_objs.py index bad1e057..991e3cf1 100644 --- a/ly/musicxml/xml_objs.py +++ b/ly/musicxml/xml_objs.py @@ -102,7 +102,7 @@ def iterate_part(self, part): def iterate_bar(self, bar): """The objects in the bar are output to the xml-file.""" - self.musxml.create_measure() + self.musxml.create_measure(pickup = bar.pickup) for obj in bar.obj_list: if isinstance(obj, BarAttr): self.new_xml_bar_attr(obj) @@ -432,6 +432,7 @@ class Bar(): Contains also information about how complete it is.""" def __init__(self): self.obj_list = [] + self.pickup = False self.list_full = False def __repr__(self): diff --git a/tests/test_xml.py b/tests/test_xml.py index e25f6ae5..e447ffe1 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -31,6 +31,10 @@ def test_tuplet(): compare_output('tuplet') +def test_partial(): + compare_output('partial') + + def ly_to_xml(filename): """Read Lilypond file and return XML string.""" writer = ly.musicxml.writer() diff --git a/tests/test_xml_files/partial.ly b/tests/test_xml_files/partial.ly new file mode 100644 index 00000000..9094f655 --- /dev/null +++ b/tests/test_xml_files/partial.ly @@ -0,0 +1,5 @@ +score{ + \partial 8 f8 | + c2 d2 | + \partial 8 f8 +} \ No newline at end of file diff --git a/tests/test_xml_files/partial.xml b/tests/test_xml_files/partial.xml new file mode 100644 index 00000000..0bea07cf --- /dev/null +++ b/tests/test_xml_files/partial.xml @@ -0,0 +1,71 @@ + + + + + + python-ly 0.9.5 + 2017-05-28 + + + + + + + + + + + 2 + + + G + 2 + + + + + F + 3 + + 1 + 1 + eighth + + + + + + C + 3 + + 4 + 1 + half + + + + D + 3 + + 4 + 1 + half + + + + + + F + 3 + + 1 + 1 + eighth + + + +