]> git.donarmstrong.com Git - lilypond.git/commitdiff
MusicXML: Implement staff-lines setting (i.e. # of lines of a staff)
authorReinhold Kainhofer <reinhold@kainhofer.com>
Mon, 12 Apr 2010 17:39:39 +0000 (19:39 +0200)
committerReinhold Kainhofer <reinhold@kainhofer.com>
Mon, 12 Apr 2010 17:44:41 +0000 (19:44 +0200)
-) Add possible context modifications to staves
-) convert a global staff-lines attribute to a contex mod inside \with
-) Convert a staff-lines attribute midway through the part as
    \stopStaff \override ... \startStaff
-) Add regtest for all these cases

input/regression/musicxml/14a-StaffDetails-LineChanges.xml [new file with mode: 0644]
python/musicexp.py
scripts/musicxml2ly.py

diff --git a/input/regression/musicxml/14a-StaffDetails-LineChanges.xml b/input/regression/musicxml/14a-StaffDetails-LineChanges.xml
new file mode 100644 (file)
index 0000000..e297d5c
--- /dev/null
@@ -0,0 +1,154 @@
+<?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">The number of staff lines can be
+      modified by using the staff-lines child of the staff-details attribute.
+      This can happen globally (the first staff has one line globally) or
+      during the part at the beginning of a measure and even inside a measure
+      (the second part has 5 lines initially, 4 at the beginning of the
+      second measure, and 3 starting in the middle of the third
+      measure).</miscellaneous-field>
+    </miscellaneous>
+  </identification>
+  <part-list>
+    <part-group number="1" type="start">
+      <group-symbol>bracket</group-symbol>
+      <group-barline>yes</group-barline>
+    </part-group>
+    <score-part id="P1">
+      <part-name>Part 1</part-name>
+    </score-part>
+    <score-part id="P2">
+      <part-name>Part 2</part-name>
+    </score-part>
+    <part-group number="1" type="stop"/>
+  </part-list>
+  <!--=========================================================-->
+  <part id="P1">
+    <measure number="1">
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+          <mode>major</mode>
+        </key>
+        <staff-details>
+          <staff-lines>1</staff-lines>
+        </staff-details>
+      </attributes>
+      <note>
+        <pitch>
+          <step>D</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="2">
+      <note>
+        <pitch>
+          <step>D</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="3">
+      <note>
+        <pitch>
+          <step>D</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+      </note>
+    </measure>
+  </part>
+  <!--=========================================================-->
+  <part id="P2">
+    <measure number="1">
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+          <mode>major</mode>
+        </key>
+        <staff-details>
+          <staff-lines>5</staff-lines>
+        </staff-details>
+      </attributes>
+      <note>
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="2">
+      <attributes>
+        <staff-details>
+          <staff-lines>4</staff-lines>
+        </staff-details>
+      </attributes>
+      <note>
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+      <note>
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="3">
+      <note>
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+      <attributes>
+        <staff-details>
+          <staff-lines>2</staff-lines>
+        </staff-details>
+      </attributes>
+      <note>
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+    </measure>
+  </part>
+  <!--=========================================================-->
+</score-partwise>
index b49ee658af6bb2aedf34894e7bb81214a6c6f9e0..1c9f3effb18ac9fb0b9d67754560e1064420c62a 100644 (file)
@@ -1598,6 +1598,16 @@ class SetEvent (Music):
         else:
             return ''
 
+class StaffLinesEvent (Music):
+    def __init__ (self, lines):
+        Music.__init__ (self)
+        self.lines = lines
+    def ly_expression (self):
+        if (self.lines > 0):
+          return "\\stopStaff \\override Staff.StaffSymbol #'line-count = #%s \\startStaff" % self.lines
+        else:
+          return "\\stopStaff \\revert Staff.StaffSymbol #'line-count \\startStaff"
+
 class TempoMark (Music):
     def __init__ (self):
         Music.__init__ (self)
@@ -1738,6 +1748,7 @@ class StaffGroup:
         self.spanbar = None
         self.children = []
         self.is_group = True
+        self.context_modifications = []
         # part_information is a list with entries of the form
         #     [staffid, voicelist]
         # where voicelist is a list with entries of the form
@@ -1754,27 +1765,38 @@ class StaffGroup:
             for c in self.children:
                 c.set_part_information (part_name, staves_info)
 
+    def add_context_modification (self, modification):
+        self.context_modifications.append (modification)
+
     def print_ly_contents (self, printer):
         for c in self.children:
             if c:
                 c.print_ly (printer)
-    def print_ly_overrides (self, printer):
+    def needs_with (self):
         needs_with = False
         needs_with |= self.spanbar == "no"
         needs_with |= self.instrument_name != None
         needs_with |= self.short_instrument_name != None
         needs_with |= (self.symbol != None) and (self.symbol != "bracket")
+        return needs_with
+    def print_ly_context_mods (self, printer):
+        if self.instrument_name or self.short_instrument_name:
+            printer.dump ("\\consists \"Instrument_name_engraver\"")
+        if self.spanbar == "no":
+            printer.dump ("\\override SpanBar #'transparent = ##t")
+        brack = {"brace": "SystemStartBrace",
+                 "none": "f",
+                 "line": "SystemStartSquare"}.get (self.symbol, None)
+        if brack:
+            printer.dump ("systemStartDelimiter = #'%s" % brack)
+
+    def print_ly_overrides (self, printer):
+        needs_with = self.needs_with () | (len (self.context_modifications) > 0);
         if needs_with:
             printer.dump ("\\with {")
-            if self.instrument_name or self.short_instrument_name:
-                printer.dump ("\\consists \"Instrument_name_engraver\"")
-            if self.spanbar == "no":
-                printer.dump ("\\override SpanBar #'transparent = ##t")
-            brack = {"brace": "SystemStartBrace",
-                     "none": "f",
-                     "line": "SystemStartSquare"}.get (self.symbol, None)
-            if brack:
-                printer.dump ("systemStartDelimiter = #'%s" % brack)
+            self.print_ly_context_mods (printer)
+            for m in self.context_modifications:
+                printer.dump (m)
             printer.dump ("}")
 
     def print_ly (self, printer):
@@ -1805,7 +1827,9 @@ class Staff (StaffGroup):
         self.voice_command = "Voice"
         self.substafftype = None
 
-    def print_ly_overrides (self, printer):
+    def needs_with (self):
+        return False
+    def print_ly_context_mods (self, printer):
         pass
 
     def print_ly_contents (self, printer):
index b0f8284d864cb511d3903c637051666261a01d42..318020d8b5079d9ebf0bb92a5fd624cec22794f5 100644 (file)
@@ -401,6 +401,8 @@ def staff_attributes_to_lily_staff (mxl_attr):
         if staff_lines:
             lines = string.atoi (staff_lines.get_text ())
 
+    # TODO: Handle other staff attributes like staff-space, etc.
+
     staff = None
     if clef_sign == "percussion" and lines == 1:
         staff = musicexp.RhythmicStaff ()
@@ -412,8 +414,11 @@ def staff_attributes_to_lily_staff (mxl_attr):
         staff.string_tunings = staff_attributes_to_string_tunings (attributes)
         # staff.tablature_format = ???
     else:
-        # TODO: Handle case with lines <> 5!
         staff = musicexp.Staff ()
+        # TODO: Handle case with lines <> 5!
+        if (lines != 5):
+            staff.add_context_modification ("\\override StaffSymbol #'line-count = #%s" % lines)
+
 
     return staff
 
@@ -926,6 +931,22 @@ def musicxml_transpose_to_lily (attributes):
     transposition.pitch = musicexp.Pitch ().transposed (shift)
     return transposition
 
+def musicxml_staff_details_to_lily (attributes):
+    details = attributes.get_maybe_exist_named_child ('staff-details')
+    if not details:
+        return None
+
+    ## TODO: Handle staff-type, staff-lines, staff-tuning, capo, staff-size
+    ret = []
+
+    stafflines = details.get_maybe_exist_named_child ('staff-lines')
+    if stafflines:
+        lines = string.atoi (stafflines.get_text ());
+        lines_event = musicexp.StaffLinesEvent (lines);
+        ret.append (lines_event);
+
+    return ret;
+
 
 def musicxml_attributes_to_lily (attrs):
     elts = []
@@ -934,12 +955,16 @@ def musicxml_attributes_to_lily (attrs):
         'time': musicxml_time_to_lily,
         'key': musicxml_key_to_lily,
         'transpose': musicxml_transpose_to_lily,
+        'staff-details': musicxml_staff_details_to_lily,
     }
     for (k, func) in attr_dispatch.items ():
         children = attrs.get_named_children (k)
         if children:
             ev = func (attrs)
-            if ev:
+            if isinstance (ev, list):
+              for e in ev:
+                elts.append (e)
+            elif ev:
                 elts.append (ev)
 
     return elts