--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 1.0 Partwise//EN"
+ "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise>
+ <identification>
+ <miscellaneous>
+ <miscellaneous-field name="description">Non-traditional key signatures,
+ where each alteration is separately given. Here we have (f sharp,
+ a flat, b flat) and (c flatflat, g sharp sharp, d flat, b sharp, f
+ natural), where in the second case an explicit octave is given for
+ each alteration.</miscellaneous-field>
+ </miscellaneous>
+ </identification>
+ <part-list>
+ <score-part id="P1">
+ <part-name>MusicXML Part</part-name>
+ </score-part>
+ </part-list>
+ <!--=========================================================-->
+ <part id="P1">
+ <measure number="1">
+ <attributes>
+ <divisions>1</divisions>
+ <key>
+ <key-step>3</key-step>
+ <key-alter>1</key-alter>
+ <key-step>5</key-step>
+ <key-alter>-1</key-alter>
+ <key-step>6</key-step>
+ <key-alter>-1</key-alter>
+ </key>
+ <time>
+ <beats>2</beats>
+ <beat-type>4</beat-type>
+ </time>
+ <clef>
+ <sign>G</sign>
+ <line>2</line>
+ </clef>
+ </attributes>
+ <note>
+ <pitch>
+ <step>C</step>
+ <octave>4</octave>
+ </pitch>
+ <duration>2</duration>
+ <voice>1</voice>
+ <type>half</type>
+ </note>
+ </measure>
+ <measure number="2">
+ <attributes>
+ <key>
+ <key-step>0</key-step>
+ <key-alter>-2</key-alter>
+ <key-step>4</key-step>
+ <key-alter>2</key-alter>
+ <key-step>1</key-step>
+ <key-alter>-1</key-alter>
+ <key-step>6</key-step>
+ <key-alter>1</key-alter>
+ <key-step>5</key-step>
+ <key-alter>0</key-alter>
+ <key-octave number="1">2</key-octave>
+ <key-octave number="2">3</key-octave>
+ <key-octave number="3">4</key-octave>
+ <key-octave number="4">5</key-octave>
+ <key-octave number="5">6</key-octave>
+ </key>
+ </attributes>
+ <note>
+ <pitch>
+ <step>C</step>
+ <octave>4</octave>
+ </pitch>
+ <duration>2</duration>
+ <voice>1</voice>
+ <type>half</type>
+ </note>
+ <barline location="right">
+ <bar-style>light-heavy</bar-style>
+ </barline>
+ </measure>
+ </part>
+</score-partwise>
+
# Implement the different note names for the various languages
def pitch_generic (pitch, notenames, accidentals):
str = notenames[pitch.step]
+ # TODO: Handle microtones!
if pitch.alteration < 0:
str += accidentals[0] * (-pitch.alteration)
elif pitch.alteration > 0:
class KeySignatureChange (Music):
def __init__ (self):
Music.__init__ (self)
- self.scale = []
- self.tonic = Pitch()
+ self.tonic = None
self.mode = 'major'
-
+ self.non_standard_alterations = None
+
+ def format_non_standard_alteration (self, a):
+ alter_dict = { -2: ",DOUBLE-FLAT",
+ -1: ",FLAT",
+ 0: ",NATURAL",
+ 1: ",SHARP",
+ 2: ",DOUBLE-SHARP"}
+ if len (a) == 2:
+ return "( %s . %s )" % (a[0], alter_dict.get (a[1], a[1]))
+ elif len (a) == 3:
+ return "(( %s . %s ) . %s )" % (a[2], a[0], alter_dict.get (a[1], a[1]))
+ else:
+ return ''
+
def ly_expression (self):
- return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
+ if self.tonic:
+ return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
self.mode)
-
- 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
+ elif self.non_standard_alterations:
+ alterations = [self.format_non_standard_alteration (a) for
+ a in self.non_standard_alterations]
+ # TODO: Check if the alterations should really be given in reverse
+ # order of if that's just a bug in Lilypond. If it's a bug,
+ # fix it and remove the following call, otherwise add a
+ # proper comment here!
+ alterations.reverse ()
+ print "Non-Standard alterations printed out: %s" % alterations
+ return "\\set Staff.keySignature = #`(%s)" % string.join (alterations, " ")
+ else:
+ return ''
class TimeSignatureChange (Music):
def __init__ (self):
return clefinfo
def get_key_signature (self):
- "return (fifths, mode) tuple"
+ "return (fifths, mode) tuple if the key signatures is given as "
+ "major/minor in the Circle of fifths. Otherwise return an alterations"
+ "list of the form [[step,alter<,octave>], [step,alter<,octave>], ...], "
+ "where the octave values are optional."
key = self.get_named_attribute ('key')
- mode_node = key.get_maybe_exist_named_child ('mode')
- mode = None
- if mode_node:
- mode = mode_node.get_text ()
- if not mode or mode == '':
- mode = 'major'
-
- fifths = int (key.get_maybe_exist_named_child ('fifths').get_text ())
- return (fifths, mode)
-
+ if not key:
+ return None
+ fifths_elm = key.get_maybe_exist_named_child ('fifths')
+ if fifths_elm:
+ mode_node = key.get_maybe_exist_named_child ('mode')
+ mode = None
+ if mode_node:
+ mode = mode_node.get_text ()
+ if not mode or mode == '':
+ mode = 'major'
+ fifths = int (fifths_elm.get_text ())
+ # TODO: Shall we try to convert the key-octave and the cancel, too?
+ return (fifths, mode)
+ else:
+ alterations = []
+ current_step = 0
+ for i in key.get_all_children ():
+ if isinstance (i, KeyStep):
+ current_step = int (i.get_text ())
+ elif isinstance (i, KeyAlter):
+ alterations.append ([current_step, int (i.get_text ())])
+ elif isinstance (i, KeyOctave):
+ nr = -1
+ if hasattr (i, 'number'):
+ nr = int (i.number)
+ if (nr > 0) and (nr <= len (alterations)):
+ # MusicXML Octave 4 is middle C -> shift to 0
+ alterations[nr-1].append (int (i.get_text ())-4)
+ else:
+ i.message (_ ("Key alteration octave given for a "
+ "non-existing alteration nr. %s, available numbers: %s!") % (nr, len(alterations)))
+ i.message ( "Non-standard key signature (after octave %s for alter nr %s): %s" % (i.get_text (), nr, alterations))
+ i.message ( "Non-standard key signature with alterations %s found!" % alterations)
+ return alterations
+
def get_transposition (self):
return self.get_named_attribute ('transpose')
-
+
+class KeyAlter (Music_xml_node):
+ pass
+class KeyStep (Music_xml_node):
+ pass
+class KeyOctave (Music_xml_node):
+ pass
class Barline (Measure_element):
'grace': Grace,
'harmony': Harmony,
'identification': Identification,
+ 'key-alter': KeyAlter,
+ 'key-octave': KeyOctave,
+ 'key-step': KeyStep,
'lyric': Lyric,
'measure': Measure,
'notations': Notations,
return change
def musicxml_key_to_lily (attributes):
- start_pitch = musicexp.Pitch ()
- (fifths, mode) = attributes.get_key_signature ()
- try:
- (n,a) = {
- 'major' : (0,0),
- 'minor' : (5,0),
- 'ionian' : (0,0),
- 'dorian' : (1,0),
- 'phrygian' : (2,0),
- 'lydian' : (3,0),
- 'mixolydian': (4,0),
- 'aeolian' : (5,0),
- 'locrian' : (6,0),
- }[mode]
- start_pitch.step = n
- start_pitch.alteration = a
- except KeyError:
- error_message (_ ("unknown mode %s, expecting 'major' or 'minor'") % mode)
-
- fifth = musicexp.Pitch()
- fifth.step = 4
- if fifths < 0:
- fifths *= -1
- fifth.step *= -1
- fifth.normalize ()
+ key_sig = attributes.get_key_signature ()
+ if not key_sig or not (isinstance (key_sig, list) or isinstance (key_sig, tuple)):
+ error_message (_ ("Unable to extract key signature!"))
+ return None
+
+ change = musicexp.KeySignatureChange()
- for x in range (fifths):
- start_pitch = start_pitch.transposed (fifth)
+ if len (key_sig) == 2 and not isinstance (key_sig[0], list):
+ # standard key signature, (fifths, mode)
+ (fifths, mode) = key_sig
+ change.mode = mode
- start_pitch.octave = 0
+ start_pitch = musicexp.Pitch ()
+ start_pitch.octave = 0
+ try:
+ (n,a) = {
+ 'major' : (0,0),
+ 'minor' : (5,0),
+ 'ionian' : (0,0),
+ 'dorian' : (1,0),
+ 'phrygian' : (2,0),
+ 'lydian' : (3,0),
+ 'mixolydian': (4,0),
+ 'aeolian' : (5,0),
+ 'locrian' : (6,0),
+ }[mode]
+ start_pitch.step = n
+ start_pitch.alteration = a
+ except KeyError:
+ error_message (_ ("unknown mode %s, expecting 'major' or 'minor' "
+ "or a church mode!") % mode)
+
+ fifth = musicexp.Pitch()
+ fifth.step = 4
+ if fifths < 0:
+ fifths *= -1
+ fifth.step *= -1
+ fifth.normalize ()
+ for x in range (fifths):
+ start_pitch = start_pitch.transposed (fifth)
+ change.tonic = start_pitch
- change = musicexp.KeySignatureChange()
- change.mode = mode
- change.tonic = start_pitch
+ else:
+ # Non-standard key signature of the form [[step,alter<,octave>],...]
+ change.non_standard_alterations = key_sig
return change
def musicxml_transpose_to_lily (attributes):