measure_position = Rational (0)
for n in m.get_all_children ():
+ # figured bass has a duration, but applies to the next note
+ # and should not change the current measure position!
+ if isinstance (n, FiguredBass):
+ n._divisions = factor.denominator ()
+ continue
+
if isinstance (n, Hash_text):
continue
dur = Rational (0)
if not (voice_id or isinstance (n, Attributes) or
isinstance (n, Direction) or isinstance (n, Partial) or
- isinstance (n, Barline) or isinstance (n, Harmony) ):
+ isinstance (n, Barline) or isinstance (n, Harmony) or
+ isinstance (n, FiguredBass) ):
continue
if isinstance (n, Attributes) and not start_attr:
voices[v].add_element (n)
continue
- if isinstance (n, Harmony):
- # store the harmony element until we encounter the next note
- # and assign it only to that one voice.
+ if isinstance (n, Harmony) or isinstance (n, FiguredBass):
+ # store the harmony or figured bass element until we encounter
+ # the next note and assign it only to that one voice.
assign_to_next_note.append (n)
continue
else:
return ''
+class FiguredBass (Music_xml_node):
+ pass
+
+
## need this, not all classes are instantiated
## for every input file. Only add those classes, that are either directly
'duration': Duration,
'frame': Frame,
'frame-note': Frame_Note,
+ 'figured-bass': FiguredBass,
'glissando': Glissando,
'grace': Grace,
'harmony': Harmony,
return structure
-
def musicxml_duration_to_lily (mxl_note):
d = musicexp.Duration ()
# if the note has no Type child, then that method spits out a warning and
def rational_to_lily_duration (rational_len):
d = musicexp.Duration ()
- 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:
+
+ rational_len.normalize_self ()
+ d_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)
+ print "d_log: %s, rational_len: %s\n" % (d_log, rational_len)
+
+ # Duration of the form 1/2^n or 3/2^n can be converted to a simple lilypond duration
+ if (d_log >= 0 and rational_len.numerator() in (1,3,5,7) ):
+ # account for the dots!
+ d.dots = (rational_len.numerator()-1)/2
+ d.duration_log = d_log - d.dots
+ elif (d_log >= 0):
+ d.duration_log = d_log
+ d.factor = Rational (rational_len.numerator ())
+ else:
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
- else:
- return d
+
+ return d
def musicxml_partial_to_lily (partial_len):
if partial_len > 0:
return res
+def musicxml_figured_bass_note_to_lily (n):
+ res = musicexp.FiguredBassNote ()
+ suffix_dict = { 'sharp' : "+",
+ 'flat' : "-",
+ 'natural' : "!",
+ 'double-sharp' : "++",
+ 'flat-flat' : "--",
+ 'sharp-sharp' : "++",
+ 'slash' : "/" }
+ prefix = n.get_maybe_exist_named_child ('prefix')
+ if prefix:
+ res.set_prefix (suffix_dict.get (prefix.get_text (), ""))
+ fnumber = n.get_maybe_exist_typed_child ('figure-number')
+ if fnumber:
+ print "figure-number: %s, text: %s" % (fnumber, fnumber.get_text ())
+ res.set_number (fnumber.get_text ())
+ suffix = n.get_maybe_exist_named_child ('suffix')
+ if suffix:
+ res.set_suffix (suffix_dict.get (suffix.get_text (), ""))
+ if n.get_maybe_exist_named_child ('extend'):
+ # TODO: Implement extender lines (unfortunately, in lilypond you have
+ # to use \set useBassFigureExtenders = ##t, which turns them on
+ # globally, while MusicXML has a property for each note...
+ # I'm not sure there is a proper way to implement this cleanly
+ #n.extend
+ pass
+ return res
+
+
+
+def musicxml_figured_bass_to_lily (n):
+ if not isinstance (n, musicxml.FiguredBass):
+ return
+ res = musicexp.FiguredBassEvent ()
+ for i in n.get_named_children ('figure'):
+ note = musicxml_figured_bass_note_to_lily (i)
+ if note:
+ res.append (note)
+ dur = n.get_maybe_exist_named_child ('duration')
+ if dur:
+ # TODO: implement duration (given in base steps!)
+ # apply the duration to res
+ print "duration: %s, divisions: %s" % (dur.get_text(), n._divisions)
+ length = Rational(int(dur.get_text()), n._divisions)*Rational(1,4)
+ res.set_real_duration (length)
+ duration = rational_to_lily_duration (length)
+ if duration:
+ res.set_duration (duration)
+ print "Converted to duration: %s" % duration.ly_expression ()
+ if hasattr (n, 'parentheses') and n.parentheses == "yes":
+ res.set_parentheses (True)
+ return res
+
instrument_drumtype_dict = {
'Acoustic Snare Drum': 'acousticsnare',
'Side Stick': 'sidestick',
def __init__ (self):
self.voicedata = None
self.ly_voice = None
+ self.figured_bass = None
self.lyrics_dict = {}
self.lyrics_order = []
ignore_lyrics = False
current_staff = None
+
+ pending_figured_bass = []
# Make sure that the keys in the dict don't get reordered, since
# we need the correct ordering of the lyrics stanzas! By default,
for k in return_value.lyrics_order:
lyrics[k] = []
- voice_builder = LilyPondVoiceBuilder()
+ voice_builder = LilyPondVoiceBuilder ()
+ figured_bass_builder = LilyPondVoiceBuilder ()
for n in voice._elements:
if n.get_name () == 'forward':
else:
voice_builder.add_command (a)
continue
+
+ if isinstance (n, musicxml.FiguredBass):
+ a = musicxml_figured_bass_to_lily (n)
+ print "Figured bass element: %s\n" % a
+ if a:
+ pending_figured_bass.append (a)
+ continue
is_chord = n.get_maybe_exist_named_child ('chord')
if not is_chord:
if voice_builder.current_duration () == 0 and n._duration > 0:
voice_builder.set_duration (n._duration)
+ # if we have a figured bass, set its voice builder to the correct position
+ # and insert the pending figures
+ if pending_figured_bass:
+ try:
+ figured_bass_builder.jumpto (n._when)
+ except NegativeSkip, neg:
+ pass
+ for fb in pending_figured_bass:
+ figured_bass_builder.add_music (fb, fb.real_duration)
+ pending_figured_bass = []
+
+
notations_children = n.get_typed_children (musicxml.Notations)
tuplet_event = None
span_events = []
v.mode = mode
return_value.ly_voice = v
+ # create \figuremode { figured bass elements }
+ if figured_bass_builder.elements:
+ fbass_music = musicexp.SequentialMusic ()
+ fbass_music.elements = figured_bass_builder.elements
+ v = musicexp.ModeChangingMusicWrapper()
+ v.mode = 'figuremode'
+ v.element = fbass_music
+
+ #printer = musicexp.Output_printer()
+ #debug_file = "debug.out"
+ #progress (_ ("FiguredBass debug output to `%s'") % debug_file)
+ #printer.set_file (codecs.open (debug_file, 'wb', encoding='utf-8'))
+ #v.print_ly( printer )
+ #printer.close ()
+
+ return_value.figured_bass = v
+
+
+ print figured_bass_builder.elements
return return_value
def musicxml_id_to_lily (id):
str = "Part%sVoice%sLyrics%s" % (part_id, name, lyricsnr)
return musicxml_id_to_lily (str)
+def music_xml_figuredbass_name_to_lily_name (part_id, name):
+ str = "Part%sVoice%sFiguredBass" % (part_id, name)
+ return musicxml_id_to_lily (str)
+
def print_voice_definitions (printer, part_list, voices):
for part in part_list:
part_id = part.id
printer.newline()
for l in voice.lyrics_order:
lname = music_xml_lyrics_name_to_lily_name (part_id, name, l)
- printer.dump ('%s = ' %lname )
+ printer.dump ('%s = ' % lname )
voice.lyrics_dict[l].print_ly (printer)
printer.newline()
+ if voice.figured_bass:
+ fbname = music_xml_figuredbass_name_to_lily_name (part_id, name)
+ printer.dump ('%s = ' % fbname )
+ voice.figured_bass.print_ly (printer)
+ printer.newline()
def uniq_list (l):