Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MusicXML: recognize \sustain{On,Off} and pedalSustainStyle #92

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ly/musicxml/create_musicxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,11 @@ def add_octave_shift(self, plac, octdir, size):
dirtypenode = etree.SubElement(direction, "direction-type")
dyn_node = etree.SubElement(dirtypenode, "octave-shift", oct_dict)

def add_sustain(self, type, line, sign):
direction = etree.SubElement(self.current_bar, "direction", placement='below')
dirtypenode = etree.SubElement(direction, "direction-type")
pedal = etree.SubElement(dirtypenode, "pedal", type=type, line=line, sign=sign)

def add_dirwords(self, words):
"""Add words in direction, e. g. a tempo mark."""
dirtypenode = etree.SubElement(self.direction, "direction-type")
Expand Down
24 changes: 24 additions & 0 deletions ly/musicxml/ly2xml_mediator.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def __init__(self):
self.prev_tremolo = 8
self.tupl_dur = 0
self.tupl_sum = 0
self.sustain_style = 'text'

def new_header_assignment(self, name, value):
"""Distributing header information."""
Expand Down Expand Up @@ -717,6 +718,24 @@ def new_trill_spanner(self, end=None):
end = "start"
self.current_note.add_adv_ornament('wavy-line', end)

def new_sustain(self, type=None):
if not type:
type = 'start'
if self.current_note.sustain and \
self.current_note.sustain.type == 'stop' and type == 'start':
type = 'change'

# implied that self.sustain_style == 'text'
line = 'no'
sign = 'yes'
if self.sustain_style == 'mixed':
line = 'yes'
elif self.sustain_style == 'bracket':
line = 'yes'
sign = 'no'

self.current_note.set_sustain(type, line, sign)

def new_ottava(self, octdiff):
octdiff = int(octdiff)
if self.octdiff == octdiff:
Expand Down Expand Up @@ -777,6 +796,8 @@ def set_by_property(self, prprty, value, group=False):
self.new_lyric_nr(value)
elif prprty == 'systemStartDelimiter':
self.change_group_bracket(value)
elif prprty == 'pedalSustainStyle':
self.set_sustain_style(value)

def set_partname(self, name):
if self.score.is_empty():
Expand All @@ -801,6 +822,9 @@ def set_partmidi(self, midi):
self.new_part()
self.part.midi = midi

def set_sustain_style(self, style):
self.sustain_style = style

def new_lyric_nr(self, num):
self.lyric_nr = num

Expand Down
9 changes: 9 additions & 0 deletions ly/musicxml/lymus2musxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@ def Set(self, cont_set):
self.mediator.unset_tuplspan_dur()
return
val = cont_set.value().get_string()

if cont_set.property() == 'pedalSustainStyle':
# access #'value
# FIXME: find a safer way to get a string
val = cont_set.value()[0][0].token
else:
val = cont_set.value().value()
if cont_set.context() in part_contexts:
Expand Down Expand Up @@ -497,6 +502,10 @@ def Command(self, command):
if self.tupl_span:
self.mediator.unset_tuplspan_dur()
self.tupl_span = False
elif command.token == '\\sustainOn':
self.mediator.new_sustain('start')
elif command.token == '\\sustainOff':
self.mediator.new_sustain('stop')
else:
if command.token not in excls:
print("Unknown command:", command.token)
Expand Down
12 changes: 12 additions & 0 deletions ly/musicxml/xml_objs.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ def before_note(self, obj):
self._add_dynamics([d for d in obj.dynamic if d.before])
if obj.oct_shift and not obj.oct_shift.octdir == 'stop':
self.musxml.add_octave_shift(obj.oct_shift.plac, obj.oct_shift.octdir, obj.oct_shift.size)
if obj.sustain:
self.musxml.add_sustain(obj.sustain.type, obj.sustain.line, obj.sustain.sign)

def after_note(self, obj):
"""Xml-nodes after note."""
Expand Down Expand Up @@ -510,6 +512,7 @@ def __init__(self, duration, voice=1):
self.other_notation = None
self.dynamic = []
self.oct_shift = None
self.sustain = None

def __repr__(self):
return '<{0} {1}>'.format(self.__class__.__name__, self.duration)
Expand Down Expand Up @@ -541,6 +544,9 @@ def set_dynamics_dashes(self, sign, before=True):
def set_oct_shift(self, plac, octdir, size):
self.oct_shift = OctaveShift(plac, octdir, size)

def set_sustain(self, type, line='no', sign='yes'):
self.sustain = Sustain(type, line, sign)

def has_attr(self):
return False

Expand Down Expand Up @@ -600,6 +606,12 @@ def __init__(self, nr, slurtype):
self.nr = nr
self.slurtype = slurtype

class Sustain():
"""Stores information about sustain."""
def __init__(self, type, line='no', sign='yes'):
self.type = type
self.line = line
self.sign = sign

##
# Subclasses of BarMus
Expand Down
3 changes: 3 additions & 0 deletions tests/test_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ def test_tuplet():
compare_output('tuplet')


def test_sustain():
compare_output('sustain')

def ly_to_xml(filename):
"""Read Lilypond file and return XML string."""
writer = ly.musicxml.writer()
Expand Down
19 changes: 19 additions & 0 deletions tests/test_xml_files/sustain.ly
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
\score {
\relative c' {
c4\sustainOn d e\sustainOff f |
c8\sustainOn c d d\sustainOff\sustainOn e e f f \sustainOff |

\set Staff.pedalSustainStyle = #'mixed
c4\sustainOn d e\sustainOff f |
c8\sustainOn c d d\sustainOff\sustainOn e e f f\sustainOff |

\set Staff.pedalSustainStyle = #'bracket
c4\sustainOn d e\sustainOff f |
c8\sustainOn c d d\sustainOff\sustainOn e e f f\sustainOff |

\set Staff.pedalSustainStyle = #'text
c4\sustainOn d e\sustainOff f |
c8\sustainOn c d d\sustainOff\sustainOn e e f f\sustainOff |
}
\layout{}
}
Loading