Skip to content

Commit

Permalink
#124 XML: Handling \bar
Browse files Browse the repository at this point in the history
With this commit \bar is inserted properly.
Previously any mid-measure bar would end up to the right,
any at-measure bar would create a new measure.

Now mid-measure bars are inserted in place (with location="middle")
while at-measure barlines will be moved to the end of the *previous*
measure.
  • Loading branch information
uliska committed May 7, 2018
1 parent 79eae64 commit fdd963c
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 12 deletions.
34 changes: 34 additions & 0 deletions ly/musicxml/create_musicxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ def create_measure(self, pickup = False, **bar_attrs):
if bar_attrs:
self.new_bar_attr(**bar_attrs)

def get_previous_bar(self):
""" Return the previous bar or False if we're in the first. """
siblings = self.current_part.getchildren()
curr_index = siblings.index(self.current_bar)
if curr_index == 0:
return False
else:
return siblings[curr_index - 1]

def get_next_bar(self):
""" Return the next bar or False if we're in the last. """
siblings = self.current_part.getchildren()
curr_index = siblings.index(self.current_bar)
if curr_index == len(siblings) - 1:
return False
else:
return siblings[curr_index + 1]


##
# High-level node creation
##
Expand Down Expand Up @@ -504,6 +523,21 @@ def create_bar_attr(self):
"""Create node attributes """
self.bar_attr = etree.SubElement(self.current_bar, "attributes")

def create_barline(self, bar_style, ends_bar):
"""Create a barline, either at the current position
or at the end of the previous bar. """
if ends_bar:
# This is necessary because when the user writes \bar as a bar end
# we are already in the next measure.
bar = self.get_previous_bar()
location = 'right'
else:
bar = self.current_bar
location = 'middle'
bl = etree.SubElement(bar, "barline", {'location': location})
bs = etree.SubElement(bl, 'bar-style')
bs.text = bar_style

def add_divisions(self, div):
division = etree.SubElement(self.bar_attr, "divisions")
division.text = str(div)
Expand Down
11 changes: 6 additions & 5 deletions ly/musicxml/ly2xml_mediator.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,12 @@ def add_to_bar(self, obj):
self.new_bar()
self.bar.add(obj)

def create_barline(self, bl):
barline = xml_objs.BarAttr()
barline.set_barline(bl)
self.bar.add(barline)
self.new_bar()
def new_barline(self, bl):
if not self.bar:
# \bar at the very beginning is ignored
return
ends_bar = not self.bar.has_music()
self.bar.add(xml_objs.BarLine(bl, ends_bar))

def new_repeat(self, rep):
barline = xml_objs.BarAttr()
Expand Down
12 changes: 6 additions & 6 deletions ly/musicxml/lymus2musxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,22 @@ def __init__(self):

def parse_text(self, ly_text, filename=None):
"""Parse the LilyPond source specified as text.
If you specify a filename, it can be used to resolve \\include commands
correctly.
"""
doc = ly.document.Document(ly_text)
doc.filename = filename
self.parse_document(doc)

def parse_document(self, ly_doc, relative_first_pitch_absolute=False):
"""Parse the LilyPond source specified as a ly.document document.
If relative_first_pitch_absolute is set to True, the first pitch in a
\relative expression without startpitch is considered to be absolute
(LilyPond 2.18+ behaviour).
"""
# The document is copied and the copy is converted to absolute mode to
# facilitate the export. The original document is unchanged.
Expand Down Expand Up @@ -540,7 +540,7 @@ def MarkupList(self, markuplist):
def String(self, string):
prev = self.get_previous_node(string)
if prev and prev.token == '\\bar':
self.mediator.create_barline(string.value())
self.mediator.new_barline(string.value())

def LyricsTo(self, lyrics_to):
r"""A \lyricsto expression. """
Expand Down Expand Up @@ -682,7 +682,7 @@ def End(self, end):

def get_previous_node(self, node):
""" Returns the nodes previous node
or false if the node is first in its branch. """
or False if the node is first in its branch. """
parent = node.parent()
i = parent.index(node)
if i > 0:
Expand Down
15 changes: 14 additions & 1 deletion ly/musicxml/xml_objs.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,13 @@ def iterate_bar(self, bar):
elif isinstance(obj, BarBackup):
divdur = self.count_duration(obj.duration, self.divisions)
self.musxml.add_backup(divdur)
elif isinstance(obj, BarLine):
self.musxml.create_barline(obj.bar_style, obj.ends_bar)

def new_xml_bar_attr(self, obj):
"""Create bar attribute xml-nodes."""
if obj.has_attr():
self.musxml.new_bar_attr(obj.clef, obj.time, obj.key, obj.mode,
self.musxml.new_bar_attr(obj.clef, obj.time, obj.key, obj.mode,
obj.divs, obj.multirest)
if obj.new_system:
self.musxml.new_system(obj.new_system)
Expand Down Expand Up @@ -523,6 +525,17 @@ def inject_voice(self, new_voice, override=False):
self.add(bl)


class BarLine():
""" Represents a manual bar line, needed for in-measure barlines
or for special-style barlines."""
def __init__(self, bar_style, ends_bar):
self.bar_style = convert_barl(bar_style)
self.ends_bar = ends_bar

def __repr__(self):
return '<{0} {1}>'.format(self.__class__.__name__, self.bar_style)


class BarMus():
""" Common class for notes and rests. """
def __init__(self, duration, voice=1):
Expand Down

0 comments on commit fdd963c

Please sign in to comment.