options = None
def progress (str):
- sys.stderr.write (str + '\n')
+ ly.stderr_write (str + '\n')
sys.stderr.flush ()
def error_message (str):
- sys.stderr.write (str + '\n')
+ ly.stderr_write (str + '\n')
sys.stderr.flush ()
needed_additional_definitions = []
)
)
)
-)
-"""
+)"""
}
def round_to_two_digits (val):
error_message ("Unprocessed PartGroupInfo %s encountered" % self)
return ''
-
def staff_attributes_to_string_tunings (mxl_attr):
details = mxl_attr.get_maybe_exist_named_child ('staff-details')
if not details:
step = i.get_named_child (u'tuning-step')
step = step.get_text ().strip ()
- p.step = (ord (step) - ord ('A') + 7 - 2) % 7
+ p.step = musicxml_step_to_lily (step)
octave = i.get_named_child (u'tuning-octave')
octave = octave.get_text ().strip ()
d.duration_log = {1: 0, 2: 1, 4:2, 8:3, 16:4, 32:5, 64:6, 128:7, 256:8, 512:9}.get (rational_len.denominator (), -1)
d.factor = Rational (rational_len.numerator ())
if d.duration_log < 0:
- error_message ("Encountered rational duration with denominator %s, "
- "unable to convert to lilypond duration" %
+ error_message (_ ("Encountered rational duration with denominator %s, "
+ "unable to convert to lilypond duration") %
rational_len.denominator ())
# TODO: Test the above error message
return None
self.direction = 0
self.event = None
def print_ly (self, printer):
- sys.stderr.write ("Encountered unprocessed marker %s\n" % self)
+ ly.stderr_write (_ ("Encountered unprocessed marker %s\n") % self)
pass
def ly_expression (self):
return ""
return retval.values ()
spanner_event_dict = {
- 'slur' : musicexp.SlurEvent,
'beam' : musicexp.BeamEvent,
+ 'dashes' : musicexp.TextSpannerEvent,
+ 'bracket' : musicexp.BracketSpannerEvent,
'glissando' : musicexp.GlissandoEvent,
+ 'octave-shift' : musicexp.OctaveShiftEvent,
'pedal' : musicexp.PedalEvent,
+ 'slur' : musicexp.SlurEvent,
'wavy-line' : musicexp.TrillSpanEvent,
- 'octave-shift' : musicexp.OctaveShiftEvent,
'wedge' : musicexp.HairpinEvent
}
spanner_type_dict = {
'decreschendo': -1,
'diminuendo': -1,
'continue': 0,
+ 'change': 0,
'up': -1,
'down': -1,
'stop': 1,
if func:
ev = func()
else:
- error_message ('unknown span event %s' % mxl_event)
+ error_message (_ ('unknown span event %s') % mxl_event)
type = mxl_event.get_type ()
if span_direction != None:
ev.span_direction = span_direction
else:
- error_message ('unknown span type %s for %s' % (type, name))
+ error_message (_ ('unknown span type %s for %s') % (type, name))
ev.set_span_type (type)
ev.line_type = getattr (mxl_event, 'line-type', 'solid')
return ev
def musicxml_direction_to_indicator (direction):
- return { "above": 1, "upright": 1, "up":1, "below": -1, "downright": -1, "down": -1 }.get (direction, 0)
+ return { "above": 1, "upright": 1, "up":1, "below": -1, "downright": -1, "down": -1, "inverted": -1 }.get (direction, 0)
def musicxml_fermata_to_lily_event (mxl_event):
ev = musicexp.ArticulationEvent ()
- ev.type = "fermata"
+ txt = mxl_event.get_text ()
+ # The contents of the element defined the shape, possible are normal, angled and square
+ ev.type = { "angled": "shortfermata", "square": "longfermata" }.get (txt, "fermata")
if hasattr (mxl_event, 'type'):
dir = musicxml_direction_to_indicator (mxl_event.type)
if dir and options.convert_directions:
ev.force_direction = dir
return ev
-
def musicxml_arpeggiate_to_lily_event (mxl_event):
ev = musicexp.ArpeggioEvent ()
ev.direction = musicxml_direction_to_indicator (getattr (mxl_event, 'direction', None))
return ev
-
def musicxml_tremolo_to_lily_event (mxl_event):
ev = musicexp.TremoloEvent ()
- ev.bars = mxl_event.get_text ()
+ txt = mxl_event.get_text ()
+ if txt:
+ ev.bars = txt
+ else:
+ ev.bars = "3"
+ return ev
+
+def musicxml_falloff_to_lily_event (mxl_event):
+ ev = musicexp.BendEvent ()
+ ev.alter = -4
+ return ev
+
+def musicxml_doit_to_lily_event (mxl_event):
+ ev = musicexp.BendEvent ()
+ ev.alter = 4
return ev
def musicxml_bend_to_lily_event (mxl_event):
ev.alter = mxl_event.bend_alter ()
return ev
+def musicxml_caesura_to_lily_event (mxl_event):
+ ev = musicexp.MarkupEvent ()
+ # FIXME: default to straight or curved caesura?
+ ev.contents = "\\musicglyph #\"scripts.caesura.straight\""
+ ev.force_direction = 1
+ return ev
def musicxml_fingering_event (mxl_event):
ev = musicexp.ShortArticulationEvent ()
"accidental-mark": musicxml_accidental_mark,
"bend": musicxml_bend_to_lily_event,
"breath-mark": (musicexp.NoDirectionArticulationEvent, "breathe"),
- #"caesura": "caesura",
+ "caesura": musicxml_caesura_to_lily_event,
#"delayed-turn": "?",
"detached-legato": (musicexp.ShortArticulationEvent, "_"), # or "portato"
- #"doit": "",
+ "doit": musicxml_doit_to_lily_event,
#"double-tongue": "",
"down-bow": "downbow",
- #"falloff": "",
+ "falloff": musicxml_falloff_to_lily_event,
"fingering": musicxml_fingering_event,
#"fingernails": "",
#"fret": "",
"strong-accent": (musicexp.ShortArticulationEvent, "^"), # or "marcato"
#"tap": "",
"tenuto": (musicexp.ShortArticulationEvent, "-"), # or "tenuto"
- #"thumb-position": "",
+ "thumb-position": "thumb",
#"toe": "",
"turn": "turn",
"tremolo": musicxml_tremolo_to_lily_event,
return ev
+
def musicxml_dynamics_to_lily_event (dynentry):
- dynamics_available = ( "p", "pp", "ppp", "pppp", "ppppp", "pppppp",
- "f", "ff", "fff", "ffff", "fffff", "ffffff",
- "mp", "mf", "sf", "sfp", "sfpp", "fp",
- "rf", "rfz", "sfz", "sffz", "fz" )
- if not dynentry.get_name() in dynamics_available:
+ dynamics_available = (
+ "ppppp", "pppp", "ppp", "pp", "p", "mp", "mf",
+ "f", "ff", "fff", "ffff", "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" )
+ dynamicsname = dynentry.get_name ()
+ if dynamicsname == "other-dynamics":
+ dynamicsname = dynentry.get_text ()
+ if not dynamicsname or dynamicsname=="#text":
return
+
+ if not dynamicsname in dynamics_available:
+ # Get rid of - in tag names (illegal in ly tags!)
+ dynamicstext = dynamicsname
+ dynamicsname = string.replace (dynamicsname, "-", "")
+ additional_definitions[dynamicsname] = dynamicsname + \
+ " = #(make-dynamic-script \"" + dynamicstext + "\")"
+ needed_additional_definitions.append (dynamicsname)
event = musicexp.DynamicsEvent ()
- event.type = dynentry.get_name ()
+ event.type = dynamicsname
return event
# Convert single-color two-byte strings to numbers 0.0 - 1.0
return event
-direction_spanners = [ 'octave-shift', 'pedal', 'wedge' ]
+# 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:
+ 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
+ additional_definitions[commandname] = "%s = %s" % (commandname, command)
+ print additional_definitions
+ 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
+
+# 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': ??????
+# 'harp-pedals' :
+# 'image' :
+# 'metronome' :
+ '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' ]
def musicxml_direction_to_lily (n):
# TODO: Handle the <staff> element!
res = []
+ # placement applies to all children!
+ dir = None
+ if hasattr (n, 'placement') and options.convert_directions:
+ dir = musicxml_direction_to_indicator (n.placement)
dirtype_children = []
+ # TODO: The direction-type is used for grouping (e.g. dynamics with text),
+ # so we can't simply flatten them out!
for dt in n.get_typed_children (musicxml.DirType):
dirtype_children += dt.get_all_children ()
for entry in dirtype_children:
+ # backets, dashes, octave shifts. pedal marks, hairpins etc. are spanners:
+ if entry.get_name() in directions_spanners:
+ event = musicxml_spanner_to_lily_event (entry)
+ if event:
+ res.append (event)
+ continue
+
+ # now treat all the "simple" ones, that can be translated using the dict
+ ev = None
+ tmp_tp = directions_dict.get (entry.get_name (), None)
+ if isinstance (tmp_tp, str): # string means MarkEvent
+ ev = musicexp.MarkEvent (tmp_tp)
+ elif isinstance (tmp_tp, tuple): # tuple means (EventClass, "text")
+ ev = tmp_tp[0] (tmp_tp[1])
+ elif tmp_tp:
+ ev = tmp_tp (entry)
+ if ev:
+ # TODO: set the correct direction! Unfortunately, \mark in ly does
+ # not seem to support directions!
+ res.append (ev)
+ continue
if entry.get_name () == "dynamics":
for dynentry in entry.get_all_children ():
if ev:
res.append (ev)
- if entry.get_name () == "words":
- ev = musicxml_words_to_lily_event (entry)
- if ev:
- res.append (ev)
-
- # octave shifts. pedal marks, hairpins etc. are spanners:
- if entry.get_name() in direction_spanners:
- event = musicxml_spanner_to_lily_event (entry)
- if event:
- res.append (event)
-
-
return res
def musicxml_frame_to_lily_event (frame):
def musicxml_note_to_lily_main_event (n):
pitch = None
duration = None
-
- mxl_pitch = n.get_maybe_exist_typed_child (musicxml.Pitch)
event = None
+
+ mxl_pitch = n.get_maybe_exist_typed_child (musicxml.Pitch)
if mxl_pitch:
pitch = musicxml_pitch_to_lily (mxl_pitch)
- event = musicexp.NoteEvent()
+ event = musicexp.NoteEvent ()
event.pitch = pitch
acc = n.get_maybe_exist_named_child ('accidental')
if acc:
# let's not force accs everywhere.
event.cautionary = acc.editorial
+
+ elif n.get_maybe_exist_typed_child (musicxml.Unpitched):
+ # Unpitched elements have display-step and can also have
+ # display-octave.
+ unpitched = n.get_maybe_exist_typed_child (musicxml.Unpitched)
+ event = musicexp.NoteEvent ()
+ event.pitch = musicxml_unpitched_to_lily (unpitched)
elif n.get_maybe_exist_typed_child (musicxml.Rest):
# rests can have display-octave and display-step, which are
# treated like an ordinary note pitch
rest = n.get_maybe_exist_typed_child (musicxml.Rest)
- event = musicexp.RestEvent()
+ event = musicexp.RestEvent ()
pitch = musicxml_restdisplay_to_lily (rest)
event.pitch = pitch
+
elif n.instrument_name:
event = musicexp.NoteEvent ()
drum_type = instrument_drumtype_dict.get (n.instrument_name)
else:
n.message ("drum %s type unknown, please add to instrument_drumtype_dict" % n.instrument_name)
event.drum_type = 'acousticsnare'
-
- if not event:
+
+ else:
n.message ("cannot find suitable event")
- event.duration = musicxml_duration_to_lily (n)
+ if event:
+ event.duration = musicxml_duration_to_lily (n)
+
return event
self.set_duration (duration)
# Insert all pending dynamics right after the note/rest:
- if isinstance (music, musicexp.EventChord) and self.pending_dynamics:
+ if isinstance (music, musicexp.ChordEvent) and self.pending_dynamics:
for d in self.pending_dynamics:
music.append (d)
self.pending_dynamics = []
skip.duration.factor = duration_factor
skip.duration.dots = duration_dots
- evc = musicexp.EventChord ()
+ evc = musicexp.ChordEvent ()
evc.elements.append (skip)
self.add_music (evc, diff)
value = None
- # if the position matches, find the last EventChord, do not cross a bar line!
+ # if the position matches, find the last ChordEvent, do not cross a bar line!
at = len( self.elements ) - 1
while (at >= 0 and
- not isinstance (self.elements[at], musicexp.EventChord) and
+ not isinstance (self.elements[at], musicexp.ChordEvent) and
not isinstance (self.elements[at], musicexp.BarLine)):
at -= 1
if (self.elements
and at >= 0
- and isinstance (self.elements[at], musicexp.EventChord)
+ and isinstance (self.elements[at], musicexp.ChordEvent)
and self.begin_moment == starting_at):
value = self.elements[at]
else:
def correct_negative_skip (self, goto):
self.end_moment = goto
self.begin_moment = goto
- evc = musicexp.EventChord ()
+ evc = musicexp.ChordEvent ()
self.elements.append (evc)
self.lyrics_dict = {}
self.lyrics_order = []
+def musicxml_step_to_lily (step):
+ if step:
+ return (ord (step) - ord ('A') + 7 - 2) % 7
+ else:
+ return None
+
def musicxml_voice_to_lily_voice (voice):
tuplet_events = []
modes_found = {}
continue
if not n.__class__.__name__ == 'Note':
- error_message ('not a Note or Attributes? %s' % n)
+ error_message (_ ('unexpected %s; expected %s or %s or %s') % (n, 'Note', 'Attributes', 'Barline'))
continue
rest = n.get_maybe_exist_typed_child (musicxml.Rest)
first_pitch = main_event.pitch
ignore_lyrics = inside_slur or is_tied or is_chord
- if hasattr (main_event, 'drum_type') and main_event.drum_type:
+ if main_event and hasattr (main_event, 'drum_type') and main_event.drum_type:
modes_found['drummode'] = True
-
ev_chord = voice_builder.last_event_chord (n._when)
if not ev_chord:
- ev_chord = musicexp.EventChord()
+ ev_chord = musicexp.ChordEvent()
voice_builder.add_music (ev_chord, n._duration)
grace = n.get_maybe_exist_typed_child (musicxml.Grace)
if n.get_maybe_exist_typed_child (musicxml.Chord) and ev_chord.grace_elements:
grace_chord = ev_chord.grace_elements.get_last_event_chord ()
if not grace_chord:
- grace_chord = musicexp.EventChord ()
+ grace_chord = musicexp.ChordEvent ()
ev_chord.append_grace (grace_chord)
if hasattr (grace, 'slash'):
# TODO: use grace_type = "appoggiatura" for slurred grace notes
if grace.slash == "yes":
ev_chord.grace_type = "acciaccatura"
- elif grace.slash == "no":
- ev_chord.grace_type = "grace"
# now that we have inserted the chord into the grace music, insert
# everything into that chord instead of the ev_chord
ev_chord = grace_chord
# +fermata | arpeggiate | non-arpeggiate |
# accidental-mark | other-notation
for notations in notations_children:
- if notations.get_tuplet():
- tuplet_event = notations.get_tuplet()
+ for tuplet_event in notations.get_tuplets():
mod = n.get_maybe_exist_typed_child (musicxml.Time_modification)
frac = (1,1)
if mod:
if s.get_type () in ('start','stop')]
if slurs:
if len (slurs) > 1:
- error_message ('more than 1 slur?')
+ error_message (_ ('cannot have two simultaneous slurs'))
# record the slur status for the next note in the loop
if not grace:
if slurs[0].get_type () == 'start':
# shake | wavy-line | mordent | inverted-mordent |
# schleifer | tremolo | other-ornament, accidental-mark
ornaments = notations.get_named_children ('ornaments')
- for a in ornaments:
- for ch in a.get_named_children ('tremolo'):
- ev = musicxml_tremolo_to_lily_event (ch)
- if ev:
- ev_chord.append (ev)
-
ornaments += notations.get_named_children ('articulations')
ornaments += notations.get_named_children ('technical')
tuplet_events.append ((ev_chord, tuplet_event, frac))
## force trailing mm rests to be written out.
- voice_builder.add_music (musicexp.EventChord (), Rational (0))
+ voice_builder.add_music (musicexp.ChordEvent (), Rational (0))
ly_voice = group_tuplets (voice_builder.elements, tuplet_events)
ly_voice = group_repeats (ly_voice)
if len (modes_found) > 1:
- error_message ('Too many modes found %s' % modes_found.keys ())
+ error_message (_ ('cannot simultaneously have more than one mode: %s') % modes_found.keys ())
if options.relative:
v = musicexp.RelativeMusic ()
return return_value
-
def musicxml_id_to_lily (id):
digits = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five',
'Six', 'Seven', 'Eight', 'Nine', 'Ten']
id = re.sub ('[^a-zA-Z]', 'X', id)
return id
-
def musicxml_pitch_to_lily (mxl_pitch):
- p = musicexp.Pitch()
+ p = musicexp.Pitch ()
p.alteration = mxl_pitch.get_alteration ()
- p.step = (ord (mxl_pitch.get_step ()) - ord ('A') + 7 - 2) % 7
+ p.step = musicxml_step_to_lily (mxl_pitch.get_step ())
p.octave = mxl_pitch.get_octave () - 4
return p
+def musicxml_unpitched_to_lily (mxl_unpitched):
+ p = None
+ step = mxl_unpitched.get_step ()
+ if step:
+ p = musicexp.Pitch ()
+ p.step = musicxml_step_to_lily (step)
+ octave = mxl_unpitched.get_octave ()
+ if octave and p:
+ p.octave = octave - 4
+ return p
+
def musicxml_restdisplay_to_lily (mxl_rest):
p = None
step = mxl_rest.get_step ()
if step:
- p = musicexp.Pitch()
- p.step = (ord (step) - ord ('A') + 7 - 2) % 7
+ p = musicexp.Pitch ()
+ p.step = musicxml_step_to_lily (step)
octave = mxl_rest.get_octave ()
if octave and p:
p.octave = octave - 4
part_ly_voices = {}
for n, v in name_voice.items ():
- progress ("Converting to LilyPond expressions...")
+ progress (_ ("Converting to LilyPond expressions..."))
# musicxml_voice_to_lily_voice returns (lily_voice, {nr->lyrics, nr->lyrics})
part_ly_voices[n] = musicxml_voice_to_lily_voice (v)
type='string',
dest='output_name',
help=_ ("set output filename to FILE"))
- p.add_option_group ('bugs',
+ p.add_option_group ( _('Bugs'),
description=(_ ("Report bugs via")
+ ''' http://post.gmane.org/post.php'''
'''?group=gmane.comp.gnu.lilypond.bugs\n'''))
printer.newline ()
for a in set(needed_additional_definitions):
printer.print_verbatim (additional_definitions.get (a, ''))
+ printer.newline ()
printer.newline ()
# Read in the tree from the given I/O object (either file or string) and
def read_musicxml (filename, compressed, use_lxml):
raw_string = None
if compressed:
- progress ("Input file %s is compressed, extracting raw MusicXML data" % filename)
+ progress (_ ("Input file %s is compressed, extracting raw MusicXML data") % filename)
z = zipfile.ZipFile (filename, "r")
container_xml = z.read ("META-INF/container.xml")
if not container_xml:
def convert (filename, options):
- progress ("Reading MusicXML from %s ..." % filename)
+ progress (_ ("Reading MusicXML from %s ...") % filename)
tree = read_musicxml (filename, options.compressed, options.use_lxml)
parts = tree.get_typed_children (musicxml.Part)
driver_ly_name = options.output_name + '.ly'
printer = musicexp.Output_printer()
- progress ("Output to `%s'" % defs_ly_name)
+ progress (_ ("Output to `%s'") % defs_ly_name)
printer.set_file (codecs.open (defs_ly_name, 'wb', encoding='utf-8'))
print_ly_preamble (printer, filename)
printer.close ()
- progress ("Output to `%s'" % driver_ly_name)
+ progress (_ ("Output to `%s'") % driver_ly_name)
printer = musicexp.Output_printer()
printer.set_file (codecs.open (driver_ly_name, 'wb', encoding='utf-8'))
print_ly_preamble (printer, filename)
if filename and os.path.exists (filename):
voices = convert (filename, options)
else:
- progress ("Unable to find input file %s" % args[0])
+ progress (_ ("Unable to find input file %s") % args[0])
if __name__ == '__main__':
main()