2006-05-09 Han-Wen Nienhuys <hanwen@lilypond.org>
+ * scripts/musicxml2ly.py (musicxml_clef_to_lily): use new
+ Attributes methods
+ (musicxml_time_to_lily): idem
+ (musicxml_key_to_lily): idem
+ (instrument_drumtype_dict): dict for supported drumtypes.
+ (LilyPondVoiceBuilder.__init__): new class: sanely keep track of
+ moments and pending mm rests
+ (musicxml_voice_to_lily_voice): rewrite to use LilyPondVoiceBuilder
+ (musicxml_voice_to_lily_voice): strip KeyChangeEvents for drums.
+ (musicxml_voice_to_lily_voice): add mode change.
+ (option_parser): lxml.etree (http://codespeak.net/lxml/) for more
+ speed and less memory usage (factor 5 to 10).
+ (convert): write -defs.ly and driver file separately so people
+ can script their own part extraction.
+
+ * python/musicxml.py (minidom_demarshal_node): new function:
+ separate minidom handling.
+ (lxml_demarshal_node): new function: support lxml.etree too.
+ (Xml_node.message): new function: verbose error message, with XML
+ path to offending node.
+ (Attributes.get_measure_length): sane interface to MusicXML attributes.
+ (Part_list.generate_id_instrument_dict): new method: collect
+ instrument names, to be able to set drum_type.
+ (Part.interpret): handle underfull measures
+ (Part.interpret): assign instrument names.
+
+ * python/musicexp.py (Output_printer.close): new method
+ (MusicWrapper.print_ly): new class: support other modes,
+ eg. \drummode
+ (BarCheck.print_ly): new class. Support bar checks, with comments
+ and fancy barchecks.
+ (NoteEvent.__init__): also set drum_type for drum notes.
+ (MultiMeasureRest.lisp_expression): dump mm rests.
+
* lily/paper-column-engraver.cc (stop_translation_timestep): set
line-break-permission if forbidBreak is not set.
self.dump (arg)
def dump (self, str):
-
if self._skipspace:
self._skipspace = False
self.unformatted_output (str)
for w in words:
self.add_word (w)
+
+ def close (self):
+ self.newline ()
+ self._file.close ()
+ self._file = None
+
+
class Duration:
def __init__ (self):
self.duration_log = 0
def get_length (self):
dot_fact = Rational( (1 << (1 + self.dots))-1,
- 1 << self.dots)
+ 1 << self.dots)
log = abs (self.duration_log)
dur = 1 << log
c.octave += c.step / 7
c.step = c.step % 7
-
def lisp_expression (self):
return '(ly:make-pitch %d %d %d)' % (self.octave,
- self.step,
- self.alteration)
+ self.step,
+ self.alteration)
def copy (self):
p = Pitch ()
str += "," * (-self.octave - 1)
return str
+
def print_ly (self, outputter):
outputter (self.ly_expression())
name = self.name()
props = self.get_properties ()
-# props += 'start %f ' % self.start
return "(make-music '%s %s)" % (name, props)
if not text:
return
-
if text == '\n':
printer.newline ()
return
+
lines = string.split (text, '\n')
for l in lines:
if l:
- printer.dump ('% ' + l)
+ printer.unformatted_output ('% ' + l)
printer.newline ()
def print_ly (self, func):
self.element.print_ly (func)
+class ModeChangingMusicWrapper (MusicWrapper):
+ def __init__ (self):
+ MusicWrapper.__init__ (self)
+ self.mode = 'notemode'
+
+ def print_ly (self, func):
+ func ('\\%s' % self.mode)
+ MusicWrapper.print_ly (self, func)
+
class TimeScaledMusic (MusicWrapper):
def print_ly (self, func):
func ('\\times %d/%d ' %
else:
pass
- # print 'huh', rest_events, note_events, other_events
for e in other_events:
e.print_ly (printer)
self.print_comment (printer)
+
+class BarCheck (Music):
+ def __init__ (self):
+ Music.__init__ (self)
+ self.bar_number = 0
+
+ def print_ly (self, printer):
+ if self.bar_number > 0 and (self.bar_number % 10) == 0:
+ printer.dump ("| \\barNumberCheck #%d " % self.bar_number)
+ printer.newline ()
+ else:
+ printer.dump ("| ")
+ printer.print_verbatim (' %% %d' % self.bar_number)
+ printer.newline ()
+
+
+ def ly_expression (self):
+ return " | "
+
class Event(Music):
pass
def get_properties (self):
return ("'duration %s"
- % self.duration.lisp_expression ())
+ % self.duration.lisp_expression ())
class RestEvent (RhythmicEvent):
def ly_expression (self):
class NoteEvent(RhythmicEvent):
def __init__ (self):
RhythmicEvent.__init__ (self)
- self.pitch = Pitch()
+ self.pitch = None
+ self.drum_type = None
self.cautionary = False
self.forced_accidental = False
def get_properties (self):
- return ("'pitch %s\n 'duration %s"
- % (self.pitch.lisp_expression (),
- self.duration.lisp_expression ()))
+ str = RhythmicEvent.get_properties ()
+
+ if self.pitch:
+ str += self.pitch.lisp_expression ()
+ elif self.drum_type:
+ str += "'drum-type '%s" % self.drum_type
+ return str
+
def pitch_mods (self):
excl_question = ''
if self.cautionary:
return excl_question
def ly_expression (self):
- return '%s%s%s' % (self.pitch.ly_expression (),
- self.pitch_mods(),
- self.duration.ly_expression ())
+ if self.pitch:
+ return '%s%s%s' % (self.pitch.ly_expression (),
+ self.pitch_mods(),
+ self.duration.ly_expression ())
+ elif self.drum_type:
+ return '%s%s' (self.drum_type,
+ self.duration.ly_expression ())
def print_ly (self, printer):
- self.pitch.print_ly (printer)
- printer (self.pitch_mods ())
+ if self.pitch:
+ self.pitch.print_ly (printer)
+ printer (self.pitch_mods ())
+ else:
+ printer (self.drum_type)
+
self.duration.print_ly (printer)
class KeySignatureChange (Music):
return clefsetting
+class MultiMeasureRest(Music):
+
+ def lisp_expression (self):
+ return """
+(make-music
+ 'MultiMeasureRestMusicGroup
+ 'elements
+ (list (make-music (quote BarCheck))
+ (make-music
+ 'EventChord
+ 'elements
+ (list (make-music
+ 'MultiMeasureRestEvent
+ 'duration
+ %s)))
+ (make-music (quote BarCheck))))
+""" % self.duration.lisp_expression ()
+
+ def ly_expression (self):
+ return 'R%s' % self.duration.ly_expression ()
+
+
def test_pitch ():
bflat = Pitch()
bflat.alteration = -1
-import sys
import new
-import re
-import string
-from rational import Rational
-
-from xml.dom import minidom, Node
+from rational import *
class Xml_node:
def __init__ (self):
self._name = 'xml_node'
self._parent = None
+ def get_parent (self):
+ return self._parent
+
def is_first (self):
return self._parent.get_typed_children (self.__class__)[0] == self
return ''.join ([c.get_text () for c in self._children])
+ def message (self, msg):
+ print msg
+
+ p = self
+ while p:
+ print ' In: <%s %s>' % (p._name, ' '.join (['%s=%s' % item for item in p._original.attrib.items()]))
+ p = p._parent
+
def get_typed_children (self, klass):
return [c for c in self._children if isinstance(c, klass)]
class Duration (Music_xml_node):
def get_length (self):
- dur = string.atoi (self.get_text ()) * Rational (1,4)
+ dur = int (self.get_text ()) * Rational (1,4)
return dur
class Hash_comment (Music_xml_node):
ch = self.get_unique_typed_child (class_dict[u'octave'])
step = ch.get_text ().strip ()
- return string.atoi (step)
+ return int (step)
def get_alteration (self):
ch = self.get_maybe_exist_typed_child (class_dict[u'alter'])
alter = 0
if ch:
- alter = string.atoi (ch.get_text ().strip ())
+ alter = int (ch.get_text ().strip ())
return alter
class Measure_element (Music_xml_node):
def set_attributes_from_previous (self, dict):
self._dict.update (dict)
+
def read_self (self):
for c in self.get_all_children ():
self._dict[c.get_name()] = c
def get_named_attribute (self, name):
return self._dict[name]
+ def get_measure_length (self):
+ (n,d) = self.get_time_signature ()
+ return Rational (n,d)
+
+ def get_time_signature (self):
+ "return time sig as a (beat, beat-type) tuple"
+
+ try:
+ mxl = self.get_named_attribute ('time')
+
+ beats = mxl.get_maybe_exist_named_child ('beats')
+ type = mxl.get_maybe_exist_named_child ('beat-type')
+ return (int (beats.get_text ()),
+ int (type.get_text ()))
+ except KeyError:
+ print 'error: requested time signature, but time sig unknown'
+ return (4, 4)
+
+ def get_clef_sign (self):
+ mxl = self.get_named_attribute ('clef')
+ sign = mxl.get_maybe_exist_named_child ('sign')
+ if sign:
+ return sign.get_text ()
+ else:
+ print 'clef requested, but unknow'
+ return 'G'
+
+ def get_key_signature (self):
+ "return (fifths, mode) tuple"
+
+ key = self.get_named_attribute ('key')
+ mode_node = self.get_maybe_exist_named_child ('mode')
+ mode = 'major'
+ if mode_node:
+ mode = mode_node.get_text ()
+
+ fifths = int (key.get_maybe_exist_named_child ('fifths').get_text ())
+ return (fifths, mode)
+
+
class Note (Measure_element):
+ def __init__ (self):
+ Measure_element.__init__ (self)
+ self.instrument_name = ''
+
def get_duration_log (self):
ch = self.get_maybe_exist_typed_child (class_dict[u'type'])
if ch:
log = ch.get_text ().strip()
- return {'eighth': 3,
- 'quarter': 2,
- 'half': 1,
- '16th': 4,
- '32nd': 5,
+ return {'eighth': 3,
+ 'quarter': 2,
+ 'half': 1,
+ '16th': 4,
+ '32nd': 5,
'breve': -1,
- 'long': -2,
- 'whole': 0} [log]
+ 'long': -2,
+ 'whole': 0} [log]
else:
return 0
return self.get_typed_children (class_dict[u'pitch'])
class Part_list (Music_xml_node):
- pass
-
+ def __init__ (self):
+ Music_xml_node.__init__ (self)
+ self._id_instrument_name_dict = {}
+
+ def generate_id_instrument_dict (self):
+
+ ## not empty to make sure this happens only once.
+ mapping = {1: 1}
+ for score_part in self.get_named_children ('score-part'):
+ for instr in score_part.get_named_children ('score-instrument'):
+ id = instr.id
+ name = instr.get_named_child ("instrument-name")
+ mapping[id] = name.get_text ()
+
+ self._id_instrument_name_dict = mapping
+
+ def get_instrument (self, id):
+ if not self._id_instrument_name_dict:
+ self.generate_id_instrument_dict()
+
+ try:
+ return self._id_instrument_name_dict[id]
+ except KeyError:
+ print "Opps, couldn't find instrument for ID=", id
+ return "Grand Piano"
+
class Measure(Music_xml_node):
def get_notes (self):
return self.get_typed_children (class_dict[u'note'])
-
+
class Musicxml_voice:
def __init__ (self):
self._elements = []
def __init__ (self):
self._voices = []
+ def get_part_list (self):
+ n = self
+ while n and n.get_name() != 'score-partwise':
+ n = n._parent
+
+ return n.get_named_child ('part-list')
+
def interpret (self):
"""Set durations and starting points."""
-
+
+ part_list = self.get_part_list ()
+
now = Rational (0)
factor = Rational (1)
- attr_dict = {}
+ attributes_dict = {}
+ attributes_object = None
measures = self.get_typed_children (Measure)
-
+
for m in measures:
+ measure_start_moment = now
+ measure_position = Rational (0)
for n in m.get_all_children ():
dur = Rational (0)
- if n.__class__ == Attributes:
- n.set_attributes_from_previous (attr_dict)
+ if n.__class__ == Attributes:
+ n.set_attributes_from_previous (attributes_dict)
n.read_self ()
- attr_dict = n._dict.copy ()
-
+ attributes_dict = n._dict.copy ()
+ attributes_object = n
+
factor = Rational (1,
- string.atoi (attr_dict['divisions']
- .get_text ()))
+ int (attributes_dict['divisions'].get_text ()))
elif (n.get_maybe_exist_typed_child (Duration)
and not n.get_maybe_exist_typed_child (Chord)):
+
mxl_dur = n.get_maybe_exist_typed_child (Duration)
dur = mxl_dur.get_length () * factor
+
if n.get_name() == 'backup':
dur = - dur
if n.get_maybe_exist_typed_child (Grace):
dur = Rational (0)
+ rest = n.get_maybe_exist_typed_child (Rest)
+ if (rest
+ and attributes_object
+ and attributes_object.get_measure_length () == dur):
+
+ rest._is_whole_measure = True
+
+
n._when = now
+ n._measure_position = measure_position
n._duration = dur
now += dur
+ measure_position += dur
+ if n._name == 'note':
+ instrument = n.get_maybe_exist_named_child ('instrument')
+ if instrument:
+ n.instrument_name = part_list.get_instrument (instrument.id)
+
+ if attributes_object:
+ length = attributes_object.get_measure_length ()
+ new_now = measure_start_moment + length
+
+ if now <> new_now:
+ problem = 'incomplete'
+ if now > new_now:
+ problem = 'overfull'
+
+ m.message ('%s measure? Expected: %s, Difference: %s' % (problem, now, new_now - now))
+
+ now = new_now
def extract_voices (part):
voices = {}
def get_fraction (self):
b = self.get_maybe_exist_typed_child (class_dict['actual-notes'])
a = self.get_maybe_exist_typed_child (class_dict['normal-notes'])
- return (string.atoi(a.get_text ()), string.atoi (b.get_text ()))
+ return (int(a.get_text ()), int (b.get_text ()))
class Accidental (Music_xml_node):
def __init__ (self):
class Beam (Music_xml_node):
def get_type (self):
return self.get_text ()
-
+ def is_primary (self):
+ return self.number == "1"
+
class Chord (Music_xml_node):
pass
pass
class Rest (Music_xml_node):
- pass
+ def __init__ (self):
+ Music_xml_node.__init__ (self)
+ self._is_whole_measure = False
+ def is_whole_measure (self):
+ return self._is_whole_measure
+
class Mode (Music_xml_node):
pass
class Tied (Music_xml_node):
class Staff (Music_xml_node):
pass
+class Instrument (Music_xml_node):
+ pass
+
+## need this, not all classes are instantiated
+## for every input file.
class_dict = {
'#comment': Hash_comment,
'accidental': Accidental,
'dot': Dot,
'duration': Duration,
'grace': Grace,
+ 'instrument': Instrument,
'mode' : Mode,
'measure': Measure,
'notations': Notations,
return str (name)
-def create_classes (names, dict):
- for n in names:
- if dict.has_key (n):
- continue
-
- class_name = name2class_name (n)
+def get_class (name):
+ try:
+ return class_dict[name]
+ except KeyError:
+ class_name = name2class_name (name)
klass = new.classobj (class_name, (Music_xml_node,) , {})
- dict[n] = klass
+ class_dict[name] = klass
+ return klass
+
+def lxml_demarshal_node (node):
+ name = node.tag
+
+ if name is None:
+ return None
+ klass = get_class (name)
+ py_node = klass()
+
+ py_node._original = node
+ py_node._name = name
+ py_node._data = node.text
+ py_node._children = [lxml_demarshal_node (cn) for cn in node.getchildren()]
+ py_node._children = filter (lambda x: x, py_node._children)
+
+ for c in py_node._children:
+ c._parent = py_node
-def element_names (node, dict):
- dict[node.nodeName] = 1
- for cn in node.childNodes:
- element_names (cn, dict)
- return dict
+ for (k,v) in node.items ():
+ py_node.__dict__[k] = v
+
+ return py_node
-def demarshal_node (node):
+def minidom_demarshal_node (node):
name = node.nodeName
- klass = class_dict[name]
+
+ klass = get_class (name)
py_node = klass()
py_node._name = name
- py_node._children = [demarshal_node (cn) for cn in node.childNodes]
+ py_node._children = [minidom_demarshal_node (cn) for cn in node.childNodes]
for c in py_node._children:
c._parent = py_node
if node.attributes:
-
for (nm, value) in node.attributes.items():
py_node.__dict__[nm] = value
py_node._original = node
return py_node
-def strip_white_space (node):
- node._children = \
- [c for c in node._children
- if not (c._original.nodeType == Node.TEXT_NODE and
- re.match (r'^\s*$', c._data))]
-
- for c in node._children:
- strip_white_space (c)
-
-def create_tree (name):
- doc = minidom.parse(name)
- node = doc.documentElement
- names = element_names (node, {}).keys()
- create_classes (names, class_dict)
-
- return demarshal_node (node)
-
-def test_musicxml (tree):
- m = tree._children[-2]
- print m
-
-def read_musicxml (name):
- tree = create_tree (name)
- strip_white_space (tree)
- return tree
if __name__ == '__main__':
- tree = read_musicxml ('BeetAnGeSample.xml')
- test_musicxml (tree)
-
-
+ import lxml.etree
+
+ tree = lxml.etree.parse ('beethoven.xml')
+ mxl_tree = lxml_demarshal_node (tree.getroot ())
+ ks = class_dict.keys()
+ ks.sort()
+ print '\n'.join (ks)
import os
import string
from gettext import gettext as _
+import musicxml
+
+
datadir = '@local_lilypond_datadir@'
sys.path.insert (0, datadir)
+import lilylib as ly
import musicxml
import musicexp
-import lilylib as ly
from rational import Rational
return new_list
-def musicxml_clef_to_lily (mxl):
- sign = mxl.get_maybe_exist_named_child ('sign')
+def musicxml_clef_to_lily (attributes):
change = musicexp.ClefChange ()
- if sign:
- change.type = sign.get_text ()
+ change.type = attributes.get_clef_sign ()
return change
-
-def musicxml_time_to_lily (mxl):
- beats = mxl.get_maybe_exist_named_child ('beats')
- type = mxl.get_maybe_exist_named_child ('beat-type')
+def musicxml_time_to_lily (attributes):
+ (beats, type) = attributes.get_time_signature ()
+
change = musicexp.TimeSignatureChange()
- change.fraction = (string.atoi(beats.get_text ()),
- string.atoi(type.get_text ()))
+ change.fraction = (beats, type)
return change
-def musicxml_key_to_lily (mxl):
+def musicxml_key_to_lily (attributes):
start_pitch = musicexp.Pitch ()
+ (fifths, mode) = attributes.get_key_signature ()
try:
- mode = mxl.get_maybe_exist_named_child ('mode')
- if mode:
- mode = mode.get_text ()
- else:
- mode = 'major'
-
- (n,a) = { 'major' : (0,0),
- 'minor' : (6,0),
+ (n,a) = {
+ 'major' : (0,0),
+ 'minor' : (6,0),
}[mode]
start_pitch.step = n
start_pitch.alteration = a
except KeyError:
print 'unknown mode', mode
-
- fifths = string.atoi (mxl.get_maybe_exist_named_child ('fifths').get_text ())
fifth = musicexp.Pitch()
fifth.step = 4
## ugh: you get clefs spread over staves for piano
if childs:
- elts.append (func (childs[0]))
+ elts.append (func (attrs))
return elts
-def create_skip_music (duration):
- skip = musicexp.SkipEvent()
- skip.duration.duration_log = 0
- skip.duration.factor = duration
-
- evc = musicexp.EventChord ()
- evc.append (skip)
- return evc
-
spanner_event_dict = {
'slur' : musicexp.SlurEvent,
'beam' : musicexp.BeamEvent,
return ev
+instrument_drumtype_dict = {
+ 'Acoustic Snare Drum': 'acousticsnare',
+ 'Side Stick': 'sidestick',
+ 'Open Triangle': 'opentriangle',
+ 'Tambourine': 'tambourine',
+
+}
+
def musicxml_note_to_lily_main_event (n):
pitch = None
duration = None
elif n.get_maybe_exist_typed_child (musicxml.Rest):
event = musicexp.RestEvent()
+ elif n.instrument_name:
+ event = musicexp.NoteEvent ()
+ event.drum_type = instrument_drumtype_dict[n.instrument_name]
+
+
+ if not event:
+ n.message ("could not find suitable event")
event.duration = musicxml_duration_to_lily (n)
return event
-def musicxml_voice_to_lily_voice (voice):
- ly_voice = []
- ly_now = Rational (0)
- pending_skip = Rational (0)
+## todo
+class NegativeSkip:
+ def __init__ (self, here, dest):
+ self.here = here
+ self.dest = dest
+
+class LilyPondVoiceBuilder:
+ def __init__ (self):
+ self.elements = []
+ self.end_moment = Rational (0)
+ self.begin_moment = Rational (0)
+ self.pending_multibar = Rational (0)
+
+ def _insert_multibar (self):
+ r = musicexp.MultiMeasureRest ()
+ r.duration = musicexp.Duration()
+ r.duration.duration_log = 0
+ r.duration.factor = self.pending_multibar
+ self.elements.append (r)
+ self.begin_moment = self.end_moment
+ self.end_moment = self.begin_moment + self.pending_multibar
+ self.pending_multibar = Rational (0)
+
+ def add_multibar_rest (self, duration):
+ self.pending_multibar += duration
+
+
+ def add_music (self, music, duration):
+ assert isinstance (music, musicexp.Music)
+ if self.pending_multibar > Rational (0):
+ self._insert_multibar ()
+
+ self.elements.append (music)
+ self.begin_moment = self.end_moment
+ self.end_moment = self.begin_moment + duration
+
+ def add_bar_check (self, number):
+ b = musicexp.BarCheck ()
+ b.bar_number = number
+ self.add_music (b, Rational (0))
+
+ def jumpto (self, moment):
+ current_end = self.end_moment + self.pending_multibar
+ diff = moment - current_end
+
+ if diff < Rational (0):
+ raise NegativeSkip(current_end, moment)
+
+ if diff > Rational (0):
+ skip = musicexp.SkipEvent()
+ skip.duration.duration_log = 0
+ skip.duration.factor = diff
+
+ evc = musicexp.EventChord ()
+ evc.elements.append (skip)
+ self.add_music (evc, diff)
+
+ def last_event_chord (self, starting_at):
+ if (self.elements
+ and isinstance (self.elements[-1], musicexp.EventChord)
+ and self.begin_moment == starting_at):
+ return self.elements[-1]
+ else:
+ self.jumpto (starting_at)
+ return None
+ def correct_negative_skip (self, goto):
+ self.end_moment = goto
+ self.begin_moment = goto
+ evc = musicexp.EventChord ()
+ self.elements.append (evc)
+
+def musicxml_voice_to_lily_voice (voice):
tuplet_events = []
+ modes_found = {}
+ voice_builder = LilyPondVoiceBuilder()
for n in voice._elements:
if n.get_name () == 'forward':
continue
-
- if isinstance (n, musicxml.Attributes):
- ly_now += pending_skip
- pending_skip = Rational (0)
+
+ try:
+ voice_builder.jumpto (n._when)
+ except NegativeSkip, neg:
+ voice_builder.correct_negative_skip (n._when)
+ n.message ("Negative skip? from %s to %s, diff %s" % (neg.here, neg.dest, neg.dest - neg.here))
- ly_voice.extend (musicxml_attributes_to_lily (n))
+ if isinstance (n, musicxml.Attributes):
+ if n.is_first () and n._measure_position == Rational (0):
+ voice_builder.add_bar_check (int (n.get_parent ().number))
+ for a in musicxml_attributes_to_lily (n):
+ voice_builder.add_music (a, Rational (0))
continue
-
+
if not n.__class__.__name__ == 'Note':
print 'not a Note or Attributes?', n
continue
- if n.is_first () and ly_voice:
- ly_voice[-1].comment += '\n'
-
+ rest = n.get_maybe_exist_typed_child (musicxml.Rest)
+ if (rest
+ and rest.is_whole_measure ()):
+ voice_builder.add_multibar_rest (n._duration)
+ continue
+
+ if n.is_first () and n._measure_position == Rational (0):
+ num = int (n.get_parent ().number)
+ voice_builder.add_bar_check (num)
+
main_event = musicxml_note_to_lily_main_event (n)
- ev_chord = None
- if None == n.get_maybe_exist_typed_child (musicxml.Chord):
- ly_now += pending_skip
- pending_skip = main_event.get_length ()
+ try:
+ if main_event.drum_type:
+ modes_found['drummode'] = True
+ except AttributeError:
+ pass
- if ly_now <> n._when:
- diff = n._when - ly_now
- if diff < Rational (0):
- print 'huh: negative skip', n._when, ly_now, n._duration
- diff = Rational (1,314159265)
+ ev_chord = voice_builder.last_event_chord (n._when)
+ if not ev_chord:
+ ev_chord = musicexp.EventChord()
- ly_voice.append (create_skip_music (diff))
- ly_now = n._when
-
- ly_voice.append (musicexp.EventChord())
- else:
- pass
- ev_chord = ly_voice[-1]
ev_chord.append (main_event)
+ voice_builder.add_music (ev_chord, n._duration)
notations = n.get_maybe_exist_typed_child (musicxml.Notations)
tuplet_event = None
ev_chord.append (musicexp.TieEvent ())
mxl_beams = [b for b in n.get_named_children ('beam')
- if b.get_type () in ('begin', 'end')]
+ if (b.get_type () in ('begin', 'end')
+ and b.is_primary ())]
if mxl_beams:
beam_ev = musicxml_spanner_to_lily_event (mxl_beams[0])
if beam_ev:
tuplet_events.append ((ev_chord, tuplet_event, frac))
- ly_voice = group_tuplets (ly_voice, tuplet_events)
+ ## force trailing mm rests to be written out.
+ voice_builder.add_music (musicexp.EventChord ())
+
+ ly_voice = group_tuplets (voice_builder.elements, tuplet_events)
seq_music = musicexp.SequentialMusic()
+
+ if 'drummode' in modes_found.keys ():
+ ## \key <pitch> barfs in drummode.
+ ly_voice = [e for e in ly_voice
+ if not isinstance(e, musicexp.KeySignatureChange)]
seq_music.elements = ly_voice
- return seq_music
+
+
+
+ if len (modes_found) > 1:
+ print 'Too many modes found', modes_found.keys ()
+
+ return_value = seq_music
+ for mode in modes_found.keys ():
+ v = musicexp.ModeChangingMusicWrapper()
+ v.element = return_value
+ v.mode = mode
+ return_value = v
+
+ return return_value
def musicxml_id_to_lily (id):
digits = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
- 'nine', 'ten']
+ 'nine', 'ten']
for dig in digits:
d = digits.index (dig) + 1
p.octave = mxl_pitch.get_octave () - 4
return p
-
-
def voices_in_part (part):
"""Return a Name -> Voice dictionary for PART"""
part.interpret ()
- part.extract_voices ()
+ part.extract_voices ()
voice_dict = part.get_voices ()
return voice_dict
information.
Copyright (c) 2005--2006 by
- Han-Wen Nienhuys <hanwen@xs4all.nl> and
- Jan Nieuwenhuizen <janneke@gnu.org>
+ Han-Wen Nienhuys <hanwen@xs4all.nl> and
+ Jan Nieuwenhuizen <janneke@gnu.org>
""",
description =
"""
)
p.add_option ('-v', '--verbose',
- action = "store_true",
- dest = 'verbose',
- help = 'be verbose')
+ action = "store_true",
+ dest = 'verbose',
+ help = 'be verbose')
+
+ p.add_option ('', '--lxml',
+ action="store_true",
+ default=False,
+ dest="use_lxml",
+ help="Use lxml.etree; uses less memory and cpu time.")
+
p.add_option ('-o', '--output',
- metavar = 'FILE',
- action = "store",
- default = None,
- type = 'string',
- dest = 'output',
- help = 'set output file')
+ metavar = 'FILE',
+ action="store",
+ default=None,
+ type='string',
+ dest='output_name',
+ help='set output file')
p.add_option_group ('', description = '''Report bugs via http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs
''')
def print_voice_definitions (printer, voices):
for (part, nv_dict) in voices.items():
+
for (name, (voice, mxlvoice)) in nv_dict.items ():
k = music_xml_voice_name_to_lily_name (part, name)
printer.dump ('%s = ' % k)
voice.print_ly (printer)
printer.newline()
+
+
def uniq_list (l):
return dict ([(elt,1) for elt in l]).keys ()
printer ('>>')
printer.newline ()
-
printer ('>>')
printer.newline ()
-
-
def print_ly_preamble (printer, filename):
printer.dump_version ()
printer.print_verbatim ('%% converted from %s\n' % filename)
-def convert (filename, output_name):
- printer = musicexp.Output_printer()
- progress ("Reading MusicXML...")
+def read_musicxml (filename, use_lxml):
+ if use_lxml:
+ import lxml.etree
+
+ tree = lxml.etree.parse (filename)
+ mxl_tree = musicxml.lxml_demarshal_node (tree.getroot ())
+ return mxl_tree
+ else:
+ from xml.dom import minidom, Node
+
+ doc = minidom.parse(filename)
+ node = doc.documentElement
+ return musicxml.minidom_demarshal_node (node)
+
+ return None
+
+
+def convert (filename, options):
+ progress ("Reading MusicXML from %s ..." % filename)
- tree = musicxml.read_musicxml (filename)
- parts = tree.get_typed_children (musicxml.Part)
- voices = get_all_voices (parts)
+ tree = read_musicxml (filename, options.use_lxml)
part_list = []
+ id_instrument_map = {}
if tree.get_maybe_exist_typed_child (musicxml.Part_list):
- pl = tree.get_maybe_exist_typed_child (musicxml.Part_list)
- part_list = pl.get_named_children ("score-part")
+ mxl_pl = tree.get_maybe_exist_typed_child (musicxml.Part_list)
+ part_list = mxl_pl.get_named_children ("score-part")
- if not output_name:
- output_name = os.path.basename (filename)
- output_name = os.path.splitext (output_name)[0] + '.ly'
+ parts = tree.get_typed_children (musicxml.Part)
+ voices = get_all_voices (parts)
-
- if output_name:
- progress ("Output to `%s'" % output_name)
- printer.set_file (open (output_name, 'w'))
-
- progress ("Printing as .ly...")
+ if not options.output_name:
+ options.output_name = os.path.basename (filename)
+ options.output_name = os.path.splitext (options.output_name)[0]
+
+ defs_ly_name = options.output_name + '-defs.ly'
+ driver_ly_name = options.output_name + '.ly'
+
+ printer = musicexp.Output_printer()
+ progress ("Output to `%s'" % defs_ly_name)
+ printer.set_file (open (defs_ly_name, 'w'))
+
+ print_ly_preamble (printer, filename)
+ print_voice_definitions (printer, voices)
+
+ printer.close ()
+
+
+ progress ("Output to `%s'" % driver_ly_name)
+ printer = musicexp.Output_printer()
+ printer.set_file (open (driver_ly_name, 'w'))
print_ly_preamble (printer, filename)
- print_voice_definitions (printer, voices)
+ printer.dump (r'\include "%s"' % defs_ly_name)
print_score_setup (printer, part_list, voices)
printer.newline ()
+
return voices
opt_parser.print_usage()
sys.exit (2)
- voices = convert (args[0], options.output)
+ voices = convert (args[0], options)
if __name__ == '__main__':
main()