From: Reinhold Kainhofer <reinhold@kainhofer.com> Date: Sun, 30 Nov 2008 19:56:42 +0000 (+0100) Subject: MusicXML: Add support for microtone (pitches and key signatures) X-Git-Tag: release/2.12.0-1~40^2~9 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=bb641f642aef4866223930498de213573d3fc52a;p=lilypond.git MusicXML: Add support for microtone (pitches and key signatures) --- diff --git a/input/regression/musicxml/00q-Basics-Microtones.xml b/input/regression/musicxml/00q-Basics-Microtones.xml new file mode 100644 index 0000000000..659d11c3ce --- /dev/null +++ b/input/regression/musicxml/00q-Basics-Microtones.xml @@ -0,0 +1,132 @@ +<?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">Some microtones: c + flat-and-a-half, d half-flat, e half-sharp, f sharp-and-a half. + Once in the lower and once in the upper region of the + staff.</miscellaneous-field> + </miscellaneous> + </identification> + <part-list> + <score-part id="P1"> + <part-name>MusicXML Part</part-name> + <score-instrument id="P1-I1"> + <instrument-name>Acoustic Grand Piano</instrument-name> + </score-instrument> + <midi-instrument id="P1-I1"> + <midi-channel>1</midi-channel> + <midi-program>1</midi-program> + </midi-instrument> + </score-part> + </part-list> + <!--=========================================================--> + <part id="P1"> + <measure number="1"> + <attributes> + <divisions>1</divisions> + <key> + <fifths>0</fifths> + <mode>major</mode> + </key> + <time symbol="common"> + <beats>4</beats> + <beat-type>4</beat-type> + </time> + <clef> + <sign>G</sign> + <line>2</line> + </clef> + </attributes> + <note> + <pitch> + <step>C</step> + <alter>-1.5</alter> + <octave>4</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <note> + <pitch> + <step>D</step> + <alter>-0.5</alter> + <octave>4</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <note> + <pitch> + <step>E</step> + <alter>0.5</alter> + <octave>4</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <note> + <pitch> + <step>F</step> + <alter>1.5</alter> + <octave>4</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + </measure> + <!--=======================================================--> + <measure number="2"> + <note> + <pitch> + <step>C</step> + <alter>-1.5</alter> + <octave>5</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <note> + <pitch> + <step>D</step> + <alter>-0.5</alter> + <octave>5</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <note> + <pitch> + <step>E</step> + <alter>0.5</alter> + <octave>5</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <note> + <pitch> + <step>F</step> + <alter>1.5</alter> + <octave>5</octave> + </pitch> + <duration>1</duration> + <voice>1</voice> + <type>quarter</type> + </note> + <barline location="right"> + <bar-style>light-heavy</bar-style> + </barline> + </measure> + </part> + <!--=========================================================--> +</score-partwise> diff --git a/input/regression/musicxml/21c-KeySignatures-Microtones.xml b/input/regression/musicxml/21c-KeySignatures-Microtones.xml new file mode 100644 index 0000000000..0819bcf5ed --- /dev/null +++ b/input/regression/musicxml/21c-KeySignatures-Microtones.xml @@ -0,0 +1,63 @@ +<?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 + with microtone alterations: (g flat-and-a-half, + a flat, b half-flat, c natural, d half-sharp, e sharp, f + sharp-and-a-half).</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>4</key-step> + <key-alter>-1.5</key-alter> + <key-step>5</key-step> + <key-alter>-1</key-alter> + <key-step>6</key-step> + <key-alter>-0.5</key-alter> + <key-step>0</key-step> + <key-alter>0</key-alter> + <key-step>1</key-step> + <key-alter>0.5</key-alter> + <key-step>2</key-step> + <key-alter>1</key-alter> + <key-step>3</key-step> + <key-alter>1.5</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> + <barline location="right"> + <bar-style>light-heavy</bar-style> + </barline> + </measure> + </part> +</score-partwise> + diff --git a/python/musicexp.py b/python/musicexp.py index a2d405973b..9672a29fa7 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -43,7 +43,6 @@ class Output_printer: Music expression as a .ly file. """ - ## TODO: support for \relative. def __init__ (self): self._line = '' @@ -205,11 +204,20 @@ class Duration: # 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) + halftones = int (pitch.alteration) + if halftones < 0: + str += accidentals[0] * (-halftones) elif pitch.alteration > 0: - str += accidentals[3] * (pitch.alteration) + str += accidentals[3] * (halftones) + # Handle remaining fraction to pitch.alteration (for microtones) + if (halftones != pitch.alteration): + if None in accidentals[1:3]: + warning (_ ("Language does not support microtones contained in the piece")) + else: + try: + str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones] + except KeyError: + warning (_ ("Language does not support microtones contained in the piece")) return str def pitch_general (pitch): @@ -231,7 +239,7 @@ def pitch_norsk (pitch): return pitch_deutsch (pitch) def pitch_svenska (pitch): - str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss']) + str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', None, None, 'iss']) return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es') def pitch_italiano (pitch): @@ -242,11 +250,11 @@ def pitch_catalan (pitch): return pitch_italiano (pitch) def pitch_espanol (pitch): - str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's']) + str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 's']) return str def pitch_vlaams (pitch): - str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k']) + str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', None, None, 'k']) return str def set_pitch_language (language): @@ -1298,9 +1306,9 @@ class TremoloEvent (ArticulationEvent): class BendEvent (ArticulationEvent): def __init__ (self): Event.__init__ (self) - self.alter = 0 + self.alter = None def ly_expression (self): - if self.alter: + if self.alter != None: return "-\\bendAfter #%s" % self.alter else: return '' @@ -1428,15 +1436,24 @@ class KeySignatureChange (Music): 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"} + alter_dict = { -2: ",DOUBLE-FLAT", + -1.5: ",THREE-Q-FLAT", + -1: ",FLAT", + -0.5: ",SEMI-FLAT", + 0: ",NATURAL", + 0.5: ",SEMI-SHARP", + 1: ",SHARP", + 1.5: ",THREE-Q-SHARP", + 2: ",DOUBLE-SHARP"} + try: + accidental = alter_dict[a[1]] + except KeyError: + warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1]) + return '' if len (a) == 2: - return "( %s . %s )" % (a[0], alter_dict.get (a[1], a[1])) + return "( %s . %s )" % (a[0], accidental) elif len (a) == 3: - return "(( %s . %s ) . %s )" % (a[2], a[0], alter_dict.get (a[1], a[1])) + return "(( %s . %s ) . %s )" % (a[2], a[0], accidental) else: return '' diff --git a/python/musicxml.py b/python/musicxml.py index 8413480aef..5c845f841a 100644 --- a/python/musicxml.py +++ b/python/musicxml.py @@ -35,6 +35,13 @@ def musicxml_duration_to_log (dur): 'longa': -2, 'long': -2}.get (dur, 0) +def interpret_alter_element (alter_elm): + alter = 0 + if alter_elm: + val = eval(alter_elm.get_text ()) + if type (val) in (int, float): + alter = val + return alter class Xml_node: @@ -252,10 +259,7 @@ class Pitch (Music_xml_node): def get_alteration (self): ch = self.get_maybe_exist_typed_child (get_class (u'alter')) - alter = 0 - if ch: - alter = int (ch.get_text ().strip ()) - return alter + return interpret_alter_element (ch) class Unpitched (Music_xml_node): def get_step (self): @@ -415,7 +419,7 @@ class Attributes (Measure_element): if isinstance (i, KeyStep): current_step = int (i.get_text ()) elif isinstance (i, KeyAlter): - alterations.append ([current_step, int (i.get_text ())]) + alterations.append ([current_step, interpret_alter_element (i)]) elif isinstance (i, KeyOctave): nr = -1 if hasattr (i, 'number'): @@ -1059,10 +1063,7 @@ class DirType (Music_xml_node): class Bend (Music_xml_node): def bend_alter (self): alter = self.get_maybe_exist_named_child ('bend-alter') - if alter: - return alter.get_text() - else: - return 0 + return interpret_alter_element (alter) class Words (Music_xml_node): pass @@ -1080,10 +1081,7 @@ class ChordPitch (Music_xml_node): return ch.get_text ().strip () def get_alteration (self): ch = self.get_maybe_exist_typed_child (get_class (self.alter_class_name ())) - alter = 0 - if ch: - alter = int (ch.get_text ().strip ()) - return alter + return interpret_alter_element (ch) class Root (ChordPitch): pass @@ -1106,10 +1104,7 @@ class ChordModification (Music_xml_node): return value def get_alter (self): ch = self.get_maybe_exist_typed_child (get_class (u'degree-alter')) - value = 0 - if ch: - value = int (ch.get_text ().strip ()) - return value + return interpret_alter_element (ch) class Frame (Music_xml_node):