# rules for directories with MusicXML files.
-# empty
-
-# UGH UGH
-include $(make-dir)/lilypond-vars.make
-
-# huh ? these are for documentation?!
MUSICXML_FILES := $(call src-wildcard,*.xml)
# LY_FILES=$(addprefix $(outdir)/, $(addsuffix .ly, $(MUSICXML_FILE)))
# LY_FILES = $(MUSICXML_FILES:%.xml=$(outdir)/%.ly)
class SpanEvent (Event):
def __init__(self):
Event.__init__ (self)
- self.span_direction = 0
- self.line_type = 0
- self.size = 0
+ self.span_direction = 0 # start/stop
+ self.line_type = 'solid'
+ self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
+ self.size = 0 # size of e.g. ocrave shift
def wait_for_note (self):
return True
def get_properties(self):
return "'span-direction %d" % self.span_direction
-
+ def set_span_type (self, type):
+ self.span_type = type
+
class SlurEvent (SpanEvent):
def ly_expression (self):
before = ''
# TODO: setting dashed/dotted line style does not work, because that
# command needs to be written before the note, not when the
# event is observed after the note!
- #if self.line_type == 1:
- #before = '\\slurDotted'
- #elif self.line_type == 2:
- #before = '\\slurDashed'
+ #before = {'dotted': '\\slurDotted',
+ # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
#if before:
#after = '\\slurSolid'
return {-1: before + '(' + after,
- 0:'',
1:')'}.get (self.span_direction, '')
class BeamEvent (SpanEvent):
def ly_expression (self):
return {-1: '[',
- 0:'',
1:']'}.get (self.span_direction, '')
class PedalEvent (SpanEvent):
def ly_expression (self):
return {-1: '\\sustainDown',
- 0:'',
1:'\\sustainUp'}.get (self.span_direction, '')
# type==-1 means octave up, type==-2 means octave down
class OctaveShiftEvent (SpanEvent):
def wait_for_note (self):
return False;
+ def set_span_type (self, type):
+ self.span_type = {'up': 1, 'down': -1}.get (type, 0)
def ly_octave_shift_indicator (self):
- if self.size == 8:
- value = 1
- elif self.size == 15:
- value = 2
- else:
- value = 0
- # -2 means up
- if self.span_direction == -2:
- value = -value
+ # convert 8/15 to lilypond indicators (+-1/+-2)
+ value = {8: 1, 15: 2}.get (self.size, 0)
+ # negative values go up!
+ value *= -1*self.span_type
return value
def ly_expression (self):
dir = self.ly_octave_shift_indicator ()
value = ''
if dir:
value = '#(set-octavation %s)' % dir
- return {-2: value,
- -1: value,
- 0: '',
+ return {
+ -1: value,
1: '#(set-octavation 0)'}.get (self.span_direction, '')
class TrillSpanEvent (SpanEvent):
def ly_expression (self):
return {-1: '\\startTrillSpan',
- 0:'',
+ 0: '', # no need to write out anything for type='continue'
1:'\\stopTrillSpan'}.get (self.span_direction, '')
class GlissandoEvent (SpanEvent):
style = ''
# TODO: wavy-line glissandos don't work, becasue the style has to be
# set before the note, at the \glissando it's already too late!
- #if self.line_type == 3: # wavy-line:
+ #if self.line_type == 'wavy':
#style = "\once\override Glissando #'style = #'zigzag"
# In lilypond, glissando is NOT a spanner, unlike MusicXML.
return {-1: style + '\\glissando',
- 0:'',
1:''}.get (self.span_direction, '')
class ArpeggioEvent(Event):
class HairpinEvent (SpanEvent):
- def __init__ (self, type):
- self.type = type
+ def set_span_type (self, type):
+ self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
def hairpin_to_ly (self):
- return { 0: '\!', 1: '\<', -1: '\>' }.get (self.type, '')
+ if self.span_direction == 1:
+ return '\!'
+ else:
+ return {1: '\<', -1: '\>'}.get (self.span_type, '')
def ly_expression (self):
return self.hairpin_to_ly ()
def escape_ly_output_string (input_string):
return_string = input_string
- needs_quotes = re.search ("[-0-9\" ,._()]", return_string);
- return_string = string.replace (return_string, "\"", "\\\"")
+ needs_quotes = not re.match ("^[a-zA-ZäöüÜÄÖßñ]*$", return_string);
if needs_quotes:
- return_string = "\"" + return_string + "\""
+ return_string = "\"" + string.replace (return_string, "\"", "\\\"") + "\""
return return_string
self.instrument_name = ''
def get_duration_log (self):
- ch = self.get_maybe_exist_typed_child (get_class (u'type'))
+ ch = self.get_maybe_exist_typed_child (get_class (u'type'))
- if ch:
- log = ch.get_text ().strip()
- return {'eighth': 3,
+ if ch:
+ log = ch.get_text ().strip()
+ return {'256th': 8,
+ '128th': 7,
+ '64th': 6,
+ '32nd': 5,
+ '16th': 4,
+ 'eighth': 3,
'quarter': 2,
'half': 1,
- '16th': 4,
- '32nd': 5,
- 'breve': -1,
- 'long': -2,
- 'whole': 0}.get (log)
- else:
- return 0
+ 'whole': 0,
+ 'breve': -1,
+ 'long': -2}.get (log, 0)
+ else:
+ sys.stderr.write ("Encountered note without duration (no <type> element): %s\n" % self)
+ return 0
def get_factor (self):
- return 1
+ return 1
def get_pitches (self):
- return self.get_typed_children (get_class (u'pitch'))
+ return self.get_typed_children (get_class (u'pitch'))
class Part_list (Music_xml_node):
def __init__ (self):
else:
return 0
-class Tuplet(Music_xml_spanner):
+class Wedge (Music_xml_spanner):
+ pass
+
+class Tuplet (Music_xml_spanner):
pass
class Slur (Music_xml_spanner):
'tuplet': Tuplet,
'type': Type,
'wavy-line': Wavy_line,
+ 'wedge': Wedge,
'work': Work,
}
def musicxml_duration_to_lily (mxl_note):
d = musicexp.Duration ()
- if mxl_note.get_maybe_exist_typed_child (musicxml.Type):
- duration_log = mxl_note.get_duration_log ()
- if duration_log:
- d.duration_log = mxl_note.get_duration_log ()
- else:
- d.duration_log = 0
- else:
- d.duration_log = 0
+ # if the note has no Type child, then that method spits out a warning and
+ # returns 0, i.e. a whole note
+ d.duration_log = mxl_note.get_duration_log ()
d.dots = len (mxl_note.get_typed_children (musicxml.Dot))
d.factor = mxl_note._duration / d.get_length ()
'glissando' : musicexp.GlissandoEvent,
'pedal' : musicexp.PedalEvent,
'wavy-line' : musicexp.TrillSpanEvent,
- 'octave-shift' : musicexp.OctaveShiftEvent
+ 'octave-shift' : musicexp.OctaveShiftEvent,
+ 'wedge' : musicexp.HairpinEvent
}
spanner_type_dict = {
'start': -1,
'begin': -1,
- 'up': -2,
+ 'crescendo': -1,
+ 'decreschendo': -1,
+ 'diminuendo': -1,
+ 'continue': 0,
+ 'up': -1,
'down': -1,
'stop': 1,
'end' : 1
}
-spanner_line_type_dict = {
- 'solid': 0,
- 'dashed': 1,
- 'dotted': 2,
- 'wavy': 3
-}
def musicxml_spanner_to_lily_event (mxl_event):
ev = None
print 'unknown span event ', mxl_event
- key = mxl_event.get_type ()
- span_direction = spanner_type_dict.get (key)
- if span_direction:
+ type = mxl_event.get_type ()
+ span_direction = spanner_type_dict.get (type)
+ # really check for None, because some types will be translated to 0, which
+ # would otherwise also lead to the unknown span warning
+ if span_direction != None:
ev.span_direction = span_direction
else:
- print 'unknown span type', key, 'for', name
+ print 'unknown span type', type, 'for', name
+
+ ev.set_span_type (type)
+ ev.line_type = getattr (mxl_event, 'line-type', 'solid')
- if hasattr (mxl_event, 'line-type'):
- span_line_type = spanner_line_type_dict.get (getattr (mxl_event, 'line-type'))
- if span_line_type:
- ev.line_type = span_line_type
# assign the size, which is used for octave-shift, etc.
ev.size = mxl_event.get_size ()
return event
-direction_spanners = [ 'octave-shift', 'pedal' ]
+direction_spanners = [ 'octave-shift', 'pedal', 'wedge' ]
def musicxml_direction_to_lily (n):
# TODO: Handle the <staff> element!
ev = musicxml_dynamics_to_lily_event (dynentry)
if ev:
res.append (ev)
-
- if entry.get_name() == "wedge":
- if hasattr (entry, 'type'):
- wedgetype = entry.type;
- wedgetypeval = {"crescendo" : 1, "decrescendo" : -1,
- "diminuendo" : -1, "stop" : 0 }.get (wedgetype)
- # Really check for != None, becaus otherwise 0 will also cause
- # the code to be executed!
- if wedgetypeval != None:
- event = musicexp.HairpinEvent (wedgetypeval)
- res.append (event)
-
-
- # octave shifts. pedal marks etc. are spanners:
+
+ # octave shifts. pedal marks, hairpins etc. are spanners:
if entry.get_name() in direction_spanners:
event = musicxml_spanner_to_lily_event (entry)
if event:
printer = musicexp.Output_printer()
printer.set_file (open (driver_ly_name, 'w'))
print_ly_preamble (printer, filename)
- printer.dump (r'\include "%s"' % defs_ly_name)
+ printer.dump (r'\include "%s"' % os.path.basename (defs_ly_name))
print_score_setup (printer, part_list, voices)
printer.newline ()
return voices
def get_existing_filename_with_extension (filename, ext):
- if not os.path.exists (filename):
- if filename[-1] == '.':
- filename += "xml"
- elif not re.match ("\.xml$", filename):
- filename += ".xml"
- return filename
+ if os.path.exists (filename):
+ return filename
+ newfilename = filename + ".xml"
+ if os.path.exists (newfilename):
+ return newfilename;
+ newfilename = filename + "xml"
+ if os.path.exists (newfilename):
+ return newfilename;
+ return ''
def main ():
opt_parser = option_parser()
opt_parser.print_usage()
sys.exit (2)
- # Allow the user to leave out the .xml on the filename
+ # Allow the user to leave out the .xml or xml on the filename
filename = get_existing_filename_with_extension (args[0], "xml")
- if not os.path.exists (filename):
- print "Unable to find input file %s" % args[0]
- else:
+ if filename and os.path.exists (filename):
voices = convert (filename, options)
+ else:
+ progress ("Unable to find input file %s" % args[0])
if __name__ == '__main__':
main()