+def musicxml_words_to_lily_event (words):
+ event = musicexp.TextEvent ()
+ text = words.get_text ()
+ text = re.sub ('^ *\n? *', '', text)
+ text = re.sub (' *\n? *$', '', text)
+ event.text = text
+
+ if hasattr (words, 'default-y') and options.convert_directions:
+ offset = getattr (words, 'default-y')
+ try:
+ off = string.atoi (offset)
+ if off > 0:
+ event.force_direction = 1
+ else:
+ event.force_direction = -1
+ except ValueError:
+ event.force_direction = 0
+
+ if hasattr (words, 'font-weight'):
+ font_weight = { "normal": '', "bold": '\\bold' }.get (getattr (words, 'font-weight'), '')
+ if font_weight:
+ event.markup += font_weight
+
+ if hasattr (words, 'font-size'):
+ size = getattr (words, 'font-size')
+ font_size = {
+ "xx-small": '\\teeny',
+ "x-small": '\\tiny',
+ "small": '\\small',
+ "medium": '',
+ "large": '\\large',
+ "x-large": '\\huge',
+ "xx-large": '\\bigger\\huge'
+ }.get (size, '')
+ if font_size:
+ event.markup += font_size
+
+ if hasattr (words, 'color'):
+ color = getattr (words, 'color')
+ rgb = hex_to_color (color)
+ if rgb:
+ event.markup += "\\with-color #(rgb-color %s %s %s)" % (rgb[0], rgb[1], rgb[2])
+
+ if hasattr (words, 'font-style'):
+ font_style = { "italic": '\\italic' }.get (getattr (words, 'font-style'), '')
+ if font_style:
+ event.markup += font_style
+
+ # TODO: How should I best convert the font-family attribute?
+
+ # TODO: How can I represent the underline, overline and line-through
+ # attributes in Lilypond? Values of these attributes indicate
+ # the number of lines
+
+ return event
+
+
+# convert accordion-registration to lilypond.
+# Since lilypond does not have any built-in commands, we need to create
+# the markup commands manually and define our own variables.
+# Idea was taken from: http://lsr.dsi.unimi.it/LSR/Item?id=194
+def musicxml_accordion_to_markup (mxl_event):
+ commandname = "accReg"
+ command = ""
+
+ high = mxl_event.get_maybe_exist_named_child ('accordion-high')
+ if high:
+ commandname += "H"
+ command += """\\combine
+ \\raise #2.5 \\musicglyph #\"accordion.accDot\"
+ """
+ middle = mxl_event.get_maybe_exist_named_child ('accordion-middle')
+ if middle:
+ # By default, use one dot (when no or invalid content is given). The
+ # MusicXML spec is quiet about this case...
+ txt = 1
+ try:
+ txt = string.atoi (middle.get_text ())
+ except ValueError:
+ pass
+ if txt == 3:
+ commandname += "MMM"
+ command += """\\combine
+ \\raise #1.5 \\musicglyph #\"accordion.accDot\"
+ \\combine
+ \\raise #1.5 \\translate #(cons 1 0) \\musicglyph #\"accordion.accDot\"
+ \\combine
+ \\raise #1.5 \\translate #(cons -1 0) \\musicglyph #\"accordion.accDot\"
+ """
+ elif txt == 2:
+ commandname += "MM"
+ command += """\\combine
+ \\raise #1.5 \\translate #(cons 0.5 0) \\musicglyph #\"accordion.accDot\"
+ \\combine
+ \\raise #1.5 \\translate #(cons -0.5 0) \\musicglyph #\"accordion.accDot\"
+ """
+ elif not txt <= 0:
+ commandname += "M"
+ command += """\\combine
+ \\raise #1.5 \\musicglyph #\"accordion.accDot\"
+ """
+ low = mxl_event.get_maybe_exist_named_child ('accordion-low')
+ if low:
+ commandname += "L"
+ command += """\\combine
+ \\raise #0.5 \musicglyph #\"accordion.accDot\"
+ """
+
+ command += "\musicglyph #\"accordion.accDiscant\""
+ command = "\\markup { \\normalsize %s }" % command
+ # Define the newly built command \accReg[H][MMM][L]
+ additional_definitions[commandname] = "%s = %s" % (commandname, command)
+ needed_additional_definitions.append (commandname)
+ return "\\%s" % commandname
+
+def musicxml_accordion_to_ly (mxl_event):
+ txt = musicxml_accordion_to_markup (mxl_event)
+ if txt:
+ ev = musicexp.MarkEvent (txt)
+ return ev
+ return
+
+
+def musicxml_rehearsal_to_ly_mark (mxl_event):
+ text = mxl_event.get_text ()
+ if not text:
+ return
+ # default is boxed rehearsal marks!
+ encl = "box"
+ if hasattr (mxl_event, 'enclosure'):
+ encl = {"none": None, "square": "box", "circle": "circle" }.get (mxl_event.enclosure, None)
+ if encl:
+ text = "\\%s { %s }" % (encl, text)
+ ev = musicexp.MarkEvent ("\\markup { %s }" % text)
+ return ev
+
+def musicxml_harp_pedals_to_ly (mxl_event):
+ count = 0
+ result = "\\harp-pedal #\""
+ for t in mxl_event.get_named_children ('pedal-tuning'):
+ alter = t.get_named_child ('pedal-alter')
+ if alter:
+ val = int (alter.get_text ().strip ())
+ result += {1: "v", 0: "-", -1: "^"}.get (val, "")
+ count += 1
+ if count == 3:
+ result += "|"
+ ev = musicexp.MarkupEvent ()
+ ev.contents = result + "\""
+ return ev
+
+def musicxml_eyeglasses_to_ly (mxl_event):
+ needed_additional_definitions.append ("eyeglasses")
+ return musicexp.MarkEvent ("\\eyeglasses")
+
+def next_non_hash_index (lst, pos):
+ pos += 1
+ while pos < len (lst) and isinstance (lst[pos], musicxml.Hash_text):
+ pos += 1
+ return pos
+
+def musicxml_metronome_to_ly (mxl_event):
+ children = mxl_event.get_all_children ()
+ if not children:
+ return
+
+ index = -1
+ index = next_non_hash_index (children, index)
+ if isinstance (children[index], musicxml.BeatUnit):
+ # first form of metronome-mark, using unit and beats/min or other unit
+ ev = musicexp.TempoMark ()
+ if hasattr (mxl_event, 'parentheses'):
+ ev.set_parentheses (mxl_event.parentheses == "yes")
+
+ d = musicexp.Duration ()
+ d.duration_log = musicxml.musicxml_duration_to_log (children[index].get_text ())
+ index = next_non_hash_index (children, index)
+ if isinstance (children[index], musicxml.BeatUnitDot):
+ d.dots = 1
+ index = next_non_hash_index (children, index)
+ ev.set_base_duration (d)
+ if isinstance (children[index], musicxml.BeatUnit):
+ # Form "note = newnote"
+ newd = musicexp.Duration ()
+ newd.duration_log = musicxml.musicxml_duration_to_log (children[index].get_text ())
+ index = next_non_hash_index (children, index)
+ if isinstance (children[index], musicxml.BeatUnitDot):
+ newd.dots = 1
+ index = next_non_hash_index (children, index)
+ ev.set_new_duration (newd)
+ elif isinstance (children[index], musicxml.PerMinute):
+ # Form "note = bpm"
+ try:
+ beats = int (children[index].get_text ())
+ ev.set_beats_per_minute (beats)
+ except ValueError:
+ pass
+ else:
+ error_message (_ ("Unknown metronome mark, ignoring"))
+ return
+ return ev
+ else:
+ #TODO: Implement the other (more complex) way for tempo marks!
+ error_message (_ ("Metronome marks with complex relations (<metronome-note> in MusicXML) are not yet implemented."))
+ return
+
+# translate directions into Events, possible values:
+# -) string (MarkEvent with that command)
+# -) function (function(mxl_event) needs to return a full Event-derived object
+# -) (class, name) (like string, only that a different class than MarkEvent is used)
+directions_dict = {
+ 'accordion-registration' : musicxml_accordion_to_ly,
+ 'coda' : (musicexp.MusicGlyphMarkEvent, "coda"),
+# 'damp' : ???
+# 'damp-all' : ???
+ 'eyeglasses': musicxml_eyeglasses_to_ly,
+ 'harp-pedals' : musicxml_harp_pedals_to_ly,
+# 'image' : ???
+ 'metronome' : musicxml_metronome_to_ly,
+ 'rehearsal' : musicxml_rehearsal_to_ly_mark,
+# 'scordatura' : ???
+ 'segno' : (musicexp.MusicGlyphMarkEvent, "segno"),
+ 'words' : musicxml_words_to_lily_event,
+}
+directions_spanners = [ 'octave-shift', 'pedal', 'wedge', 'dashes', 'bracket' ]