@itemize @bullet
@item Texts set in a TrueType font are now kerned. This requires CVS
-Pango or Pango 2.12.
+Pango or Pango 1.12.
@item Using the @TeX{} no longer requires linking or dynamically
opening the kpathsea library, making the backend more easily usable on
--- /dev/null
+import inspect
+import sys
+import string
+from rational import Rational
+
+def flatten_list (fl):
+ if type(fl) == type((1,)):
+ return
+
+ flattened = []
+ for f in fl:
+ flattened += flatten_list (fl)
+
+def is_derived (deriv_class, maybe_base):
+ if deriv_class == maybe_base:
+ return True
+
+ for c in deriv_class.__bases__:
+ if is_derived (c, maybe_base):
+ return True
+
+ return False
+
+class Output_printer:
+ def __init__ (self):
+ self.line = ''
+ self.indent = 0
+ self.file = sys.stdout
+ self.line_len = 72
+
+ def add_word (self, str):
+ if (len (str) + 1 + len (self.line) > self.line_len):
+ self.newline()
+
+ self.indent += str.count ('<') + str.count ('{')
+ self.indent -= str.count ('>') + str.count ('}')
+ self.line += ' ' + str
+
+ def newline (self):
+ self.file.write (self.line + '\n')
+ self.line = ' ' * self.indent
+
+ def dump (self, str):
+ words = string.split (str)
+ for w in words:
+ self.add_word (w)
+
+class Duration:
+ def __init__ (self):
+ self.duration_log = 2
+ self.dots = 0
+ self.factor = Rational (1)
+
+ def lisp_expression (self):
+ return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
+ self.dots,
+ self.factor.numerator (),
+ self.factor.denominator ())
+
+ def ly_expression (self):
+ str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
+
+ if self.factor <> Rational (1,1):
+ str += '*%d/%d' % (self.factor.numerator (),self.factor.denominator ())
+
+ return str
+
+ def copy (self):
+ d = Duration ()
+ d.dots = self.dots
+ d.duration_log = self.duration_log
+ d.factor = self.factor
+ return d
+
+ def get_length (self):
+ dot_fact = Rational( (1 << (1 + self.dots))-1,
+ 1 << self.dots)
+
+ log = abs (self.duration_log)
+ dur = 1 << log
+ if self.duration_log < 0:
+ base = Rational (dur)
+ else:
+ base = Rational (1, dur)
+
+ return base * dot_fact * self.factor
+
+class Pitch:
+ def __init__ (self):
+ self.alteration = 0
+ self.step = 0
+ self.octave = 0
+
+ def lisp_expression (self):
+ return '(ly:make-pitch %d %d %d)' % (self.octave,
+ self.step,
+ self.alteration)
+
+ def copy (self):
+ p = Pitch ()
+ p.alteration = self.alteration
+ p.step = self.step
+ p.octave = self.octave
+ return p
+
+ def steps (self):
+ return self.step + self.octave * 7
+
+ def ly_step_expression (self):
+ str = 'cdefgab'[self.step]
+ if self.alteration > 0:
+ str += 'is'* (self.alteration)
+ elif self.alteration < 0:
+ str += 'es'* (-self.alteration)
+
+ return str.replace ('aes', 'as').replace ('ees', 'es')
+
+ def ly_expression (self):
+ str = self.ly_step_expression ()
+ if self.octave >= 0:
+ str += "'" * (self.octave + 1)
+ elif self.octave < -1:
+ str += "," * (-self.octave - 1)
+
+ return str
+
+class Music:
+ def __init__ (self):
+ self.tag = None
+ self.parent = None
+ self.start = Rational (0)
+ pass
+
+ def get_length(self):
+ return Rational (0)
+
+ def set_tag (self, counter, tag_dict):
+ self.tag = counter
+ tag_dict [counter] = self
+ return counter + 1
+
+ def get_properties (self):
+ return ''
+
+ def has_children (self):
+ return False
+
+ def get_index (self):
+ if self.parent:
+ return self.parent.elements.index (self)
+ else:
+ return None
+
+ def lisp_expression (self):
+ name = self.name()
+ tag = ''
+ if self.tag:
+ tag = "'input-tag %d" % self.tag
+
+ props = self.get_properties ()
+# props += 'start %f ' % self.start
+
+ return "(make-music '%s %s %s)" % (name, tag, props)
+
+ def set_start (self, start):
+ self.start = start
+
+ def find_first (self, predicate):
+ if predicate (self):
+ return self
+ return None
+
+ def print_ly (self, printer):
+ printer (self.ly_expression ())
+
+class Music_document:
+ def __init__ (self):
+ self.music = test_expr ()
+ self.tag_dict = {}
+ self.touched = True
+
+ def recompute (self):
+ self.tag_dict = {}
+ self.music.set_tag (0, self.tag_dict)
+ self.music.set_start (Rational (0))
+
+class NestedMusic(Music):
+ def __init__ (self):
+ Music.__init__ (self)
+ self.elements = []
+ def has_children (self):
+ return self.elements
+ def set_tag (self, counter, dict):
+ counter = Music.set_tag (self, counter, dict)
+ for e in self.elements :
+ counter = e.set_tag (counter, dict)
+ return counter
+
+ def insert_around (self, succ, elt, dir):
+ assert elt.parent == None
+ assert succ == None or succ in self.elements
+
+
+ idx = 0
+ if succ:
+ idx = self.elements.index (succ)
+ if dir > 0:
+ idx += 1
+ else:
+ if dir < 0:
+ idx = 0
+ elif dir > 0:
+ idx = len (self.elements)
+
+ self.elements.insert (idx, elt)
+ elt.parent = self
+
+ def get_properties (self):
+ return ("'elements (list %s)"
+ % string.join (map (lambda x: x.lisp_expression(),
+ self.elements)))
+
+ def get_subset_properties (self, predicate):
+ return ("'elements (list %s)"
+ % string.join (map (lambda x: x.lisp_expression(),
+ filter ( predicate, self.elements))))
+ def get_neighbor (self, music, dir):
+ assert music.parent == self
+ idx = self.elements.index (music)
+ idx += dir
+ idx = min (idx, len (self.elements) -1)
+ idx = max (idx, 0)
+
+ return self.elements[idx]
+
+ def delete_element (self, element):
+ assert element in self.elements
+
+ self.elements.remove (element)
+ element.parent = None
+
+ def set_start (self, start):
+ self.start = start
+ for e in self.elements:
+ e.set_start (start)
+
+ def find_first (self, predicate):
+ r = Music.find_first (self, predicate)
+ if r:
+ return r
+
+ for e in self.elements:
+ r = e.find_first (predicate)
+ if r:
+ return r
+ return None
+
+class SequentialMusic (NestedMusic):
+ def name(self):
+ return 'SequentialMusic'
+
+ def print_ly (self, printer):
+ printer ('{')
+ for e in self.elements:
+ e.print_ly (printer)
+ printer ('}')
+
+ def lisp_sub_expression (self, pred):
+ name = self.name()
+ tag = ''
+ if self.tag:
+ tag = "'input-tag %d" % self.tag
+
+
+ props = self.get_subset_properties (pred)
+
+ return "(make-music '%s %s %s)" % (name, tag, props)
+
+ def set_start (self, start):
+ for e in self.elements:
+ e.set_start (start)
+ start += e.get_length()
+
+class EventChord(NestedMusic):
+ def name(self):
+ return "EventChord"
+
+ def get_length (self):
+ l = Rational (0)
+ for e in self.elements:
+ l = max(l, e.get_length())
+ return l
+
+ def print_ly (self, printer):
+ note_events = [e for e in self.elements if
+ is_derived (e.__class__, NoteEvent)]
+ rest_events = [e for e in self.elements if
+ is_derived (e.__class__, RhythmicEvent)
+ and not is_derived (e.__class__, NoteEvent)]
+
+ other_events = [e for e in self.elements if
+ not is_derived (e.__class__, RhythmicEvent)]
+
+ if rest_events:
+ printer (rest_events[0].ly_expression ())
+ elif len (note_events) == 1:
+ printer (note_events[0].ly_expression ())
+ elif note_events:
+ pitches = [x.pitch.ly_expression () for x in note_events]
+ printer ('<%s>' % string.join (pitches)
+ + note_events[0].duration.ly_expression ())
+ else:
+ pass
+ # print 'huh', rest_events, note_events, other_events
+
+ for e in other_events:
+ e.print_ly (printer)
+
+
+class Event(Music):
+ def __init__ (self):
+ Music.__init__ (self)
+
+ def name (self):
+ return "Event"
+
+class ArpeggioEvent(Music):
+ def name (self):
+ return 'ArpeggioEvent'
+
+ def ly_expression (self):
+ return ('\\arpeggio')
+
+class RhythmicEvent(Event):
+ def __init__ (self):
+ Event.__init__ (self)
+ self.duration = Duration()
+
+ def get_length (self):
+ return self.duration.get_length()
+
+ def get_properties (self):
+ return ("'duration %s"
+ % self.duration.lisp_expression ())
+
+ def name (self):
+ return 'RhythmicEvent'
+
+class RestEvent (RhythmicEvent):
+ def name (self):
+ return 'RestEvent'
+ def ly_expression (self):
+ return 'r%s' % self.duration.ly_expression ()
+
+class SkipEvent (RhythmicEvent):
+ def name (self):
+ return 'SkipEvent'
+ def ly_expression (self):
+ return 's%s' % self.duration.ly_expression ()
+
+class NoteEvent(RhythmicEvent):
+ def __init__ (self):
+ RhythmicEvent.__init__ (self)
+ self.pitch = Pitch()
+
+ def name (self):
+ return 'NoteEvent'
+
+ def get_properties (self):
+ return ("'pitch %s\n 'duration %s"
+ % (self.pitch.lisp_expression (),
+ self.duration.lisp_expression ()))
+
+ def ly_expression (self):
+ return '%s%s' % (self.pitch.ly_expression (),
+ self.duration.ly_expression ())
+
+
+
+class KeySignatureEvent (Event):
+ def __init__ (self, tonic, scale):
+ Event.__init__ (self)
+ self.scale = scale
+ self.tonic = tonic
+ def name (self):
+ return 'KeySignatureEvent'
+ def ly_expression (self):
+ return '\\key %s \\major' % self.tonic.ly_step_expression ()
+
+ def lisp_expression (self):
+ pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
+ scale_str = ("'(%s)" % string.join (pairs))
+
+ return """ (make-music 'KeyChangeEvent
+ 'pitch-alist %s) """ % scale_str
+
+class ClefEvent (Event):
+ def __init__ (self, t):
+ Event.__init__ (self)
+ self.type = t
+
+ def name (self):
+ return 'ClefEvent'
+ def ly_expression (self):
+ return '\\clef "%s"' % self.type
+ clef_dict = {
+ "G": ("clefs.G", -2, -6),
+ "C": ("clefs.C", 0, 0),
+ "F": ("clefs.F", 2, 6),
+ }
+
+ def lisp_expression (self):
+ (glyph, pos, c0) = self.clef_dict [self.type]
+ clefsetting = """
+ (make-music 'SequentialMusic
+ 'elements (list
+ (context-spec-music
+ (make-property-set 'clefGlyph "%s") 'Staff)
+ (context-spec-music
+ (make-property-set 'clefPosition %d) 'Staff)
+ (context-spec-music
+ (make-property-set 'middleCPosition %d) 'Staff)))
+""" % (glyph, pos, c0)
+ return clefsetting
+
+def test_expr ():
+ m = SequentialMusic()
+ l = 2
+ evc = EventChord()
+ n = NoteEvent()
+ n.duration.duration_log = l
+ n.pitch.step = 1
+ evc.insert_around (None, n, 0)
+ m.insert_around (None, evc, 0)
+
+ evc = EventChord()
+ n = NoteEvent()
+ n.duration.duration_log = l
+ n.pitch.step = 3
+ evc.insert_around (None, n, 0)
+ m.insert_around (None, evc, 0)
+
+ evc = EventChord()
+ n = NoteEvent()
+ n.duration.duration_log = l
+ n.pitch.step = 2
+ evc.insert_around (None, n, 0)
+ m.insert_around (None, evc, 0)
+
+ evc = ClefEvent("G")
+ m.insert_around (None, evc, 0)
+
+ evc = EventChord()
+ tonic = Pitch ()
+ tonic.step = 2
+ tonic.alteration = -2
+ n = KeySignatureEvent(tonic, [0, 0, -2, 0, 0,-2,-2] )
+ evc.insert_around (None, n, 0)
+ m.insert_around (None, evc, 0)
+
+ return m
+
+
+if __name__ == '__main__':
+ expr = test_expr()
+ expr.set_start (Rational (0))
+ print expr.ly_expression()
+ start = Rational (0,4)
+ stop = Rational (4,2)
+ def sub(x, start=start, stop=stop):
+ ok = x.start >= start and x.start +x.get_length() <= stop
+ return ok
+
+ print expr.lisp_sub_expression(sub)
+
--- /dev/null
+import sys
+import new
+import re
+import string
+from rational import Rational
+
+from xml.dom import minidom, Node
+
+
+class Xml_node:
+ def __init__ (self):
+ self._children = []
+ self._data = None
+ self._original = None
+ self._name = 'xml_node'
+
+ def original (self):
+ return self._original
+ def get_name (self):
+ return self._name
+
+ def get_text (self):
+ if self._data:
+ return self._data
+
+ if not self._children:
+ return ''
+
+ return ''.join ([c.get_text () for c in self._children])
+
+ def get_typed_children (self, klass):
+ return [c for c in self._children if c.__class__ == klass]
+
+ def get_children (self, predicate):
+ return [c for c in self._children if predicate(c)]
+
+ def get_all_children (self):
+ return self._children
+
+ def get_maybe_exist_typed_child (self, klass):
+ cn = self.get_typed_children (klass)
+ if len (cn)==0:
+ return None
+ elif len (cn) == 1:
+ return cn[0]
+ else:
+ raise "More than 1 child", klass
+
+ def get_unique_typed_child (self, klass):
+ cn = self.get_typed_children(klass)
+ if len (cn) <> 1:
+ print self.__dict__
+ raise 'Child is not unique for', (klass, 'found', cn)
+
+ return cn[0]
+
+class Music_xml_node (Xml_node):
+ def __init__ (self):
+ Xml_node.__init__ (self)
+ self.duration = Rational (0)
+ self.start = Rational (0)
+
+class Attributes (Music_xml_node):
+ def __init__ (self):
+ self._dict = {}
+
+ 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]
+
+class Duration (Music_xml_node):
+ def get_length (self):
+ dur = string.atoi (self.get_text ()) * Rational (1,4)
+ return dur
+
+class Hash_comment (Music_xml_node):
+ def to_ly (self, output_func):
+ output_func ('%% %s\n ' % self.get_text())
+
+class Pitch (Music_xml_node):
+ def get_step (self):
+ ch = self.get_unique_typed_child (class_dict[u'step'])
+ step = ch.get_text ().strip ()
+ return step
+ def get_octave (self):
+ ch = self.get_unique_typed_child (class_dict[u'octave'])
+
+ step = ch.get_text ().strip ()
+ return string.atoi (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 ())
+ return alter
+
+ def to_ly (self, output_func):
+ oct = (self.get_octave () - 4)
+ oct_str = ''
+ if oct > 0:
+ oct_str = "'" * oct
+ elif oct < 0:
+ oct_str = "," * -oct
+
+ alt = self.get_alteration ()
+ alt_str = ''
+ if alt > 0:
+ alt_str = 'is' * alt
+ elif alt < 0:
+ alt_str = 'es' * alt
+
+ output_func ('%s%s%s' % (self.get_step ().lower(), alt_str, oct_str))
+
+class Note (Music_xml_node):
+ 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,
+ 'breve': -1,
+ 'long': -2,
+ 'whole': 0} [log]
+ else:
+ return 0
+
+ def get_factor (self):
+ return 1
+
+ def get_pitches (self):
+ return self.get_typed_children (class_dict[u'pitch'])
+
+ def to_ly (self, func):
+ ps = self.get_pitches ()
+
+ if len (ps) == 0:
+ func ('r')
+ else:
+ func ('<')
+ for p in ps:
+ p.to_ly (func)
+ func ('>')
+
+ func ('%d ' % (1 << self.get_duration_log ()))
+
+
+
+
+class Measure(Music_xml_node):
+ def get_notes (self):
+ return self.get_typed_children (class_dict[u'note'])
+ def to_ly (self, func):
+ func (' { % measure \n ')
+ for c in self._children:
+ c.to_ly (func)
+ func (' } \n ')
+
+class Part (Music_xml_node):
+ def to_ly (self, func):
+ func (' { %% part %s \n ' % self.name)
+ for c in self._children:
+ c.to_ly (func)
+ func (' } \n ')
+
+ def interpret (self):
+ """Set durations and starting points."""
+
+ now = Rational (0)
+ factor = Rational (1)
+ attr_dict = {}
+ measures = self.get_typed_children (Measure)
+
+ for m in measures:
+ for n in m.get_all_children ():
+ dur = Rational (0)
+
+ if n.__class__ == Attributes:
+ n.set_attributes_from_previous (attr_dict)
+ n.read_self ()
+ attr_dict = n._dict.copy ()
+
+ factor = Rational (1,
+ string.atoi (attr_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)
+
+ n._when = now
+ n._duration = dur
+ now += dur
+
+ def extract_voices (part):
+ voices = {}
+ measures = part.get_typed_children (Measure)
+ elements = []
+ for m in measures:
+ elements.extend (m.get_typed_children (Note))
+
+ for n in elements:
+ voice_id = n.get_maybe_exist_typed_child (class_dict['voice'])
+
+ if not voice_id:
+ continue
+
+ id = voice_id.get_text ()
+ if not voices.has_key (id):
+ voices[id] = []
+
+ voices[id].append (n)
+
+ part._voices = voices
+ def get_voices (self):
+ return self._voices
+
+class Chord (Music_xml_node):
+ pass
+
+class Dot (Music_xml_node):
+ pass
+
+class Rest (Music_xml_node):
+ pass
+
+class Type (Music_xml_node):
+ pass
+class Grace (Music_xml_node):
+ pass
+
+class_dict = {
+ 'grace': Grace,
+ 'rest':Rest,
+ 'dot': Dot,
+ 'chord': Chord,
+ 'duration': Duration,
+ 'attributes': Attributes,
+ 'note': Note,
+ 'pitch': Pitch,
+ 'part': Part,
+ 'measure': Measure,
+ 'type': Type,
+ '#comment': Hash_comment,
+}
+
+def name2class_name (name):
+ name = name.replace ('-', '_')
+ name = name.replace ('#', 'hash_')
+ name = name[0].upper() + name[1:].lower()
+
+ return str (name)
+
+def create_classes (names, dict):
+ for n in names:
+ if dict.has_key (n):
+ continue
+
+ class_name = name2class_name (n)
+ klass = new.classobj (class_name, (Music_xml_node,) , {})
+ dict[n] = klass
+
+def element_names (node, dict):
+ dict[node.nodeName] = 1
+ for cn in node.childNodes:
+ element_names (cn, dict)
+ return dict
+
+def demarshal_node (node):
+ name = node.nodeName
+ klass = class_dict[name]
+ py_node = klass()
+ py_node._name = name
+ py_node._children = [demarshal_node (cn) for cn in node.childNodes]
+ if node.attributes:
+ for (name, value) in node.attributes.items():
+ py_node.name = value
+
+ py_node._data = None
+ if node.nodeType == node.TEXT_NODE and node.data:
+ py_node._data = node.data
+
+ 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 oldtest ():
+ n = tree._children[-2]._children[-1]._children[0]
+ print n
+ print n.get_duration_log()
+ print n.get_pitches()
+ print n.get_pitches()[0].get_alteration()
+
+
+def test_musicxml (tree):
+ m = tree._children[-2]
+ print m
+
+ m.to_ly (lambda str: sys.stdout.write (str))
+
+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)
+
--- /dev/null
+"""Implementation of rational arithmetic."""
+
+from __future__ import division
+
+import decimal as _decimal
+import math as _math
+
+def _gcf(a, b):
+ """Returns the greatest common factor of a and b."""
+ a = abs(a)
+ b = abs(b)
+ while b:
+ a, b = b, a % b
+ return a
+
+class Rational(object):
+ """
+ This class provides an exact representation of rational numbers.
+
+ All of the standard arithmetic operators are provided. In mixed-type
+ expressions, an int or a long can be converted to a Rational without
+ loss of precision, and will be done as such.
+
+ Rationals can be implicity (using binary operators) or explicity
+ (using float(x) or x.decimal()) converted to floats or Decimals;
+ this may cause a loss of precision. The reverse conversions can be
+ done without loss of precision, and are performed with the
+ from_exact_float and from_exact_decimal static methods. However,
+ because of rounding error in the original values, this tends to
+ produce "ugly" fractions. "Nicer" conversions to Rational can be made
+ with approx_smallest_denominator or approx_smallest_error.
+ """
+
+ def __init__(self, numerator, denominator=1):
+ """Contructs the Rational object for numerator/denominator."""
+ if not isinstance(numerator, (int, long)):
+ raise TypeError('numerator must have integer type')
+ if not isinstance(denominator, (int, long)):
+ raise TypeError('denominator must have integer type')
+ if not denominator:
+ raise ZeroDivisionError('rational construction')
+ # Store the fraction in reduced form as _n/_d
+ factor = _gcf(numerator, denominator)
+ self._n = numerator // factor
+ self._d = denominator // factor
+ if self._d < 0:
+ self._n = -self._n
+ self._d = -self._d
+ def numerator(self):
+ return self._n
+
+ def denominator(self):
+ return self._d
+
+ def __repr__(self):
+ if self._d == 1:
+ return "Rational(%d)" % self._n
+ else:
+ return "Rational(%d, %d)" % (self._n, self._d)
+ def __str__(self):
+ if self._d == 1:
+ return str(self._n)
+ else:
+ return "%d/%d" % (self._n, self._d)
+ def __hash__(self):
+ try:
+ return hash(float(self))
+ except OverflowError:
+ return hash(long(self))
+ def __float__(self):
+ return self._n / self._d
+ def __int__(self):
+ if self._n < 0:
+ return -int(-self._n // self._d)
+ else:
+ return int(self._n // self._d)
+ def __long__(self):
+ return long(int(self))
+ def __nonzero__(self):
+ return bool(self._n)
+ def __pos__(self):
+ return self
+ def __neg__(self):
+ return Rational(-self._n, self._d)
+ def __abs__(self):
+ if self._n < 0:
+ return -self
+ else:
+ return self
+ def __add__(self, other):
+ if isinstance(other, Rational):
+ return Rational(self._n * other._d + self._d * other._n,
+ self._d * other._d)
+ elif isinstance(other, (int, long)):
+ return Rational(self._n + self._d * other, self._d)
+ elif isinstance(other, (float, complex)):
+ return float(self) + other
+ elif isinstance(other, _decimal.Decimal):
+ return self.decimal() + other
+ else:
+ return NotImplemented
+ __radd__ = __add__
+ def __sub__(self, other):
+ if isinstance(other, Rational):
+ return Rational(self._n * other._d - self._d * other._n,
+ self._d * other._d)
+ elif isinstance(other, (int, long)):
+ return Rational(self._n - self._d * other, self._d)
+ elif isinstance(other, (float, complex)):
+ return float(self) - other
+ elif isinstance(other, _decimal.Decimal):
+ return self.decimal() - other
+ else:
+ return NotImplemented
+ def __rsub__(self, other):
+ if isinstance(other, (int, long)):
+ return Rational(other * self._d - self._n, self._d)
+ elif isinstance(other, (float, complex)):
+ return other - float(self)
+ elif isinstance(other, _decimal.Decimal):
+ return other - self.decimal()
+ else:
+ return NotImplemented
+ def __mul__(self, other):
+ if isinstance(other, Rational):
+ return Rational(self._n * other._n, self._d * other._d)
+ elif isinstance(other, (int, long)):
+ return Rational(self._n * other, self._d)
+ elif isinstance(other, (float, complex)):
+ return float(self) * other
+ elif isinstance(other, _decimal.Decimal):
+ return self.decimal() * other
+ else:
+ return NotImplemented
+ __rmul__ = __mul__
+ def __truediv__(self, other):
+ if isinstance(other, Rational):
+ return Rational(self._n * other._d, self._d * other._n)
+ elif isinstance(other, (int, long)):
+ return Rational(self._n, self._d * other)
+ elif isinstance(other, (float, complex)):
+ return float(self) / other
+ elif isinstance(other, _decimal.Decimal):
+ return self.decimal() / other
+ else:
+ return NotImplemented
+ __div__ = __truediv__
+ def __rtruediv__(self, other):
+ if isinstance(other, (int, long)):
+ return Rational(other * self._d, self._n)
+ elif isinstance(other, (float, complex)):
+ return other / float(self)
+ elif isinstance(other, _decimal.Decimal):
+ return other / self.decimal()
+ else:
+ return NotImplemented
+ __rdiv__ = __rtruediv__
+ def __floordiv__(self, other):
+ truediv = self / other
+ if isinstance(truediv, Rational):
+ return truediv._n // truediv._d
+ else:
+ return truediv // 1
+ def __rfloordiv__(self, other):
+ return (other / self) // 1
+ def __mod__(self, other):
+ return self - self // other * other
+ def __rmod__(self, other):
+ return other - other // self * self
+ def __divmod__(self, other):
+ return self // other, self % other
+ def __cmp__(self, other):
+ if other == 0:
+ return cmp(self._n, 0)
+ else:
+ return cmp(self - other, 0)
+ def __pow__(self, other):
+ if isinstance(other, (int, long)):
+ if other < 0:
+ return Rational(self._d ** -other, self._n ** -other)
+ else:
+ return Rational(self._n ** other, self._d ** other)
+ else:
+ return float(self) ** other
+ def __rpow__(self, other):
+ return other ** float(self)
+ def decimal(self):
+ """Return a Decimal approximation of self in the current context."""
+ return _decimal.Decimal(self._n) / _decimal.Decimal(self._d)
+ def round(self, denominator):
+ """Return self rounded to nearest multiple of 1/denominator."""
+ int_part, frac_part = divmod(self * denominator, 1)
+ round_direction = cmp(frac_part * 2, 1)
+ if round_direction == 0:
+ numerator = int_part + (int_part & 1) # round to even
+ elif round_direction < 0:
+ numerator = int_part
+ else:
+ numerator = int_part + 1
+ return Rational(numerator, denominator)
+ @staticmethod
+ def from_exact_float(x):
+ """Returns the exact Rational equivalent of x."""
+ mantissa, exponent = _math.frexp(x)
+ mantissa = int(mantissa * 2 ** 53)
+ exponent -= 53
+ if exponent < 0:
+ return Rational(mantissa, 2 ** (-exponent))
+ else:
+ return Rational(mantissa * 2 ** exponent)
+ @staticmethod
+ def from_exact_decimal(x):
+ """Returns the exact Rational equivalent of x."""
+ sign, mantissa, exponent = x.as_tuple()
+ sign = (1, -1)[sign]
+ mantissa = sign * reduce(lambda a, b: 10 * a + b, mantissa)
+ if exponent < 0:
+ return Rational(mantissa, 10 ** (-exponent))
+ else:
+ return Rational(mantissa * 10 ** exponent)
+ @staticmethod
+ def approx_smallest_denominator(x, tolerance):
+ """
+ Returns a Rational approximation of x.
+ Minimizes the denominator given a constraint on the error.
+
+ x = the float or Decimal value to convert
+ tolerance = maximum absolute error allowed,
+ must be of the same type as x
+ """
+ tolerance = abs(tolerance)
+ n = 1
+ while True:
+ m = int(round(x * n))
+ result = Rational(m, n)
+ if abs(result - x) < tolerance:
+ return result
+ n += 1
+ @staticmethod
+ def approx_smallest_error(x, maxDenominator):
+ """
+ Returns a Rational approximation of x.
+ Minimizes the error given a constraint on the denominator.
+
+ x = the float or Decimal value to convert
+ maxDenominator = maximum denominator allowed
+ """
+ result = None
+ minError = x
+ for n in xrange(1, maxDenominator + 1):
+ m = int(round(x * n))
+ r = Rational(m, n)
+ error = abs(r - x)
+ if error == 0:
+ return r
+ elif error < minError:
+ result = r
+ minError = error
+ return result
+
+def divide(x, y):
+ """Same as x/y, but returns a Rational if both are ints."""
+ if isinstance(x, (int, long)) and isinstance(y, (int, long)):
+ return Rational(x, y)
+ else:
+ return x / y
+
--- /dev/null
+import sys
+import re
+import os
+
+datadir = '@local_lilypond_datadir@'
+if not os.path.isdir (datadir):
+ datadir = '@lilypond_datadir@'
+if os.environ.has_key ('LILYPONDPREFIX'):
+ datadir = os.environ['LILYPONDPREFIX']
+ while datadir[-1] == os.sep:
+ datadir = datadir[:-1]
+
+if os.path.exists (os.path.join (datadir, 'share/lilypond/@TOPLEVEL_VERSION@/')):
+ datadir = os.path.join (datadir, 'share/lilypond/@TOPLEVEL_VERSION@/')
+
+sys.path.insert (0, os.path.join (datadir, 'python'))
+
+import musicxml
+import musicexp
+from rational import Rational
+
+def musicxml_duration_to_lily (mxl_note):
+ d = musicexp.Duration ()
+ if mxl_note.get_maybe_exist_typed_child (musicxml.Type):
+ d.duration_log = mxl_note.get_duration_log ()
+ else:
+ d.factor = mxl_note._duration
+ d.duration_log = 0
+
+ d.dots = len (mxl_note.get_typed_children (musicxml.Dot))
+ d.factor = mxl_note._duration / d.get_length ()
+
+ return d
+
+def musicxml_voice_to_lily_voice (voice):
+
+ ly_voice = []
+ ly_now = Rational (0)
+ for n in voice:
+ if not n.__class__.__name__ == 'Note':
+ print 'not a note?'
+ continue
+
+ pitch = None
+ duration = None
+
+ mxl_pitch = n.get_maybe_exist_typed_child (musicxml.Pitch)
+ event = None
+
+ if mxl_pitch:
+ pitch = musicxml_pitch_to_lily (mxl_pitch)
+ event = musicexp.NoteEvent()
+ event.pitch = pitch
+ elif n.get_maybe_exist_typed_child (musicxml.Rest):
+ event = musicexp.RestEvent()
+
+ event.duration = musicxml_duration_to_lily (n)
+ ev_chord = None
+ if None == n.get_maybe_exist_typed_child (musicxml.Chord):
+ if ly_voice:
+ ly_now += ly_voice[-1].get_length ()
+
+ 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)
+
+
+ skip = musicexp.SkipEvent()
+ skip.duration.duration_log = 0
+ skip.duration.factor = diff
+
+ evc = musicexp.EventChord ()
+ evc.elements.append (skip)
+ ly_voice.append (evc)
+ ly_now = n._when
+
+ ly_voice.append (musicexp.EventChord())
+ else:
+ pass
+ #print 'append'
+ ev_chord = ly_voice[-1]
+ ev_chord.elements.append (event)
+
+
+ seq_music = musicexp.SequentialMusic()
+
+
+ seq_musicexp.elements = ly_voice
+ return seq_music
+
+
+def musicxml_id_to_lily (id):
+ digits = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
+ 'nine', 'ten']
+
+ for dig in digits:
+ d = digits.index (dig) + 1
+ dig = dig[0].upper() + dig[1:]
+ id = re.sub ('%d' % d, dig, id)
+
+ id = re.sub ('[^a-zA-Z]', 'X', id)
+ return id
+
+
+def musicxml_pitch_to_lily (mxl_pitch):
+ p = musicexp.Pitch()
+ p.alteration = mxl_pitch.get_alteration ()
+ p.step = (ord (mxl_pitch.get_step ()) - ord ('A') + 7 - 2) % 7
+ p.octave = mxl_pitch.get_octave () -4
+ return p
+
+def get_all_voices (parts):
+ all_voices = {}
+ for p in parts:
+ p.interpret ()
+ p.extract_voices ()
+ voice_dict = p.get_voices ()
+
+ for (id, voice) in voice_dict.items ():
+ m = musicxml_voice_to_lily_voice (voice)
+ m_name = 'Part' + p.name + 'Voice' + id
+ m_name = musicxml_id_to_lily (m_name)
+ all_voices[m_name] = m
+
+ return all_voices
+
+printer = musicexp.Output_printer()
+
+
+tree = musicxml.read_musicxml (sys.argv[1])
+parts = tree.get_typed_children (musicxml.Part)
+
+voices = get_all_voices (parts)
+for (k,v) in voices.items():
+ print '%s = \n' % k
+ v.print_ly (printer.dump)
+ printer.newline()
+
+