from rational import Rational
+# Store previously converted pitch for \relative conversion as a global state variable
+previous_pitch = None
+relative_pitches = False
def escape_instrument_string (input_string):
retstring = string.replace (input_string, "\"", "\\\"")
def ly_step_expression (self):
return pitch_generating_function (self)
-
- def ly_expression (self):
- str = self.ly_step_expression ()
+
+ def absolute_pitch (self):
if self.octave >= 0:
- str += "'" * (self.octave + 1)
+ return "'" * (self.octave + 1)
elif self.octave < -1:
- str += "," * (-self.octave - 1)
-
+ return "," * (-self.octave - 1)
+ else:
+ return ''
+
+ def relative_pitch (self):
+ global previous_pitch
+ if not previous_pitch:
+ previous_pitch = self
+ return self.absolute_pitch ()
+ previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step
+ this_pitch_steps = self.octave * 7 + self.step
+ pitch_diff = (this_pitch_steps - previous_pitch_steps)
+ previous_pitch = self
+ if pitch_diff > 3:
+ return "'" * ((pitch_diff + 3) / 7)
+ elif pitch_diff < -3:
+ return "," * ((-pitch_diff + 3) / 7)
+ else:
+ return ""
+
+ def ly_expression (self):
+ str = self.ly_step_expression ()
+ if relative_pitches:
+ str += self.relative_pitch ()
+ else:
+ str += self.absolute_pitch ()
+
return str
def print_ly (self, outputter):
func ('\\%s' % self.mode)
MusicWrapper.print_ly (self, func)
+class RelativeMusic (MusicWrapper):
+ def __init__ (self):
+ MusicWrapper.__init__ (self)
+ self.basepitch = None
+
+ def print_ly (self, func):
+ global previous_pitch
+ global relative_pitches
+ prev_relative_pitches = relative_pitches
+ relative_pitches = True
+ previous_pitch = self.basepitch
+ if not previous_pitch:
+ previous_pitch = Pitch ()
+ func ('\\relative %s%s' % (pitch_generating_function (previous_pitch),
+ previous_pitch.absolute_pitch ()))
+ MusicWrapper.print_ly (self, func)
+ relative_pitches = prev_relative_pitches
+
class TimeScaledMusic (MusicWrapper):
def print_ly (self, func):
func ('\\times %d/%d ' %
elif len (note_events) == 1:
note_events[0].print_ly (printer)
elif note_events:
- pitches = [x.pitch.ly_expression () for x in note_events]
+ global previous_pitch
+ pitches = []
+ basepitch = None
+ for x in note_events:
+ pitches.append (x.pitch.ly_expression ())
+ if not basepitch:
+ basepitch = previous_pitch
printer ('<%s>' % string.join (pitches))
+ previous_pitch = basepitch
note_events[0].duration.print_ly (printer)
else:
pass
lyrics = {}
return_value = VoiceData ()
return_value.voicedata = voice
+
+ # First pitch needed for relative mode (if selected in command-line options)
+ first_pitch = None
# Needed for melismata detection (ignore lyrics on those notes!):
inside_slur = False
voice_builder.add_bar_check (num)
main_event = musicxml_note_to_lily_main_event (n)
+ if main_event and not first_pitch:
+ 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 len (modes_found) > 1:
error_message ('Too many modes found %s' % modes_found.keys ())
+
+ if options.relative:
+ v = musicexp.RelativeMusic ()
+ v.element = seq_music
+ v.basepitch = first_pitch
+ seq_music = v
return_value.ly_voice = seq_music
for mode in modes_found.keys ():
def option_parser ():
- p = ly.get_option_parser(usage=_ ("musicxml2ly FILE.xml"),
+ p = ly.get_option_parser(usage=_ ("musicxml2ly [options] FILE.xml"),
version=('''%prog (LilyPond) @TOPLEVEL_VERSION@\n\n'''
+
_ ("""This program is free software. It is covered by the GNU General Public
information.""") % 'lilypond'
+ """
Copyright (c) 2005--2007 by
- Han-Wen Nienhuys <hanwen@xs4all.nl> and
- Jan Nieuwenhuizen <janneke@gnu.org>
+ Han-Wen Nienhuys <hanwen@xs4all.nl>,
+ Jan Nieuwenhuizen <janneke@gnu.org> and
+ Reinhold Kainhofer <reinhold@kainhofer.com>
"""),
description=_ ("Convert %s to LilyPond input.") % 'MusicXML' + "\n")
p.add_option ('-v', '--verbose',
default = False,
help = _ ("Input file is a zip-compressed MusicXML file."))
+ p.add_option ('-r', '--relative',
+ action = "store_true",
+ dest = "relative",
+ help = _ ("Convert pitches in relative mode."))
+
p.add_option ('-l', '--language',
action = "store",
help = _ ("Use a different language file, e.g. 'deutsch' for deutsch.ly."))