]> git.donarmstrong.com Git - lilypond.git/commitdiff
MusicXML: Implement conversion of page layout options
authorReinhold Kainhofer <reinhold@kainhofer.com>
Sun, 4 Nov 2007 20:47:38 +0000 (21:47 +0100)
committerReinhold Kainhofer <reinhold@kainhofer.com>
Sun, 4 Nov 2007 20:47:38 +0000 (21:47 +0100)
A MusicXML contains page size, margins, font size, spacing
settings etc. inside the <defaults> element, which is now
converted to the \paper {..} block and some #(set-global-... ...)
commands in lilypond.

input/regression/musicxml/19a-PageLayout-PrintMusic.xml [new file with mode: 0755]
python/musicexp.py
scripts/musicxml2ly.py

diff --git a/input/regression/musicxml/19a-PageLayout-PrintMusic.xml b/input/regression/musicxml/19a-PageLayout-PrintMusic.xml
new file mode 100755 (executable)
index 0000000..95e2e00
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 1.1 Partwise//EN"\r
+                                "http://www.musicxml.org/dtds/partwise.dtd">\r
+<score-partwise version="1.1">\r
+  <movement-title>Layout options</movement-title>\r
+  <identification>\r
+    <encoding>\r
+      <software>PrintMusic 2008 for Windows</software>\r
+      <software>Dolet Light for PrintMusic 2008</software>\r
+      <encoding-date>2007-11-04</encoding-date>\r
+    </encoding>\r
+  </identification>\r
+  <defaults>\r
+    <scaling>\r
+      <millimeters>3.7703</millimeters>\r
+      <tenths>40</tenths>\r
+    </scaling>\r
+    <page-layout>\r
+      <page-height>954</page-height>\r
+      <page-width>1804</page-width>\r
+      <page-margins type="both">\r
+        <left-margin>318</left-margin>\r
+        <right-margin>212</right-margin>\r
+        <top-margin>53</top-margin>\r
+        <bottom-margin>74</bottom-margin>\r
+      </page-margins>\r
+    </page-layout>\r
+    <system-layout>\r
+      <system-margins>\r
+        <left-margin>248</left-margin>\r
+        <right-margin>206</right-margin>\r
+      </system-margins>\r
+      <system-distance>561</system-distance>\r
+      <top-system-distance>436</top-system-distance>\r
+    </system-layout>\r
+    <music-font font-family="Maestro" font-size="10.7"/>\r
+    <word-font font-family="Times New Roman" font-size="5.3"/>\r
+  </defaults>\r
+  <credit>\r
+    <credit-words default-x="955" default-y="876" font-size="18" font-weight="bold" justify="center" valign="top">Layout options</credit-words>\r
+  </credit>\r
+  <part-list>\r
+    <score-part id="P1">\r
+      <part-name print-object="no">MusicXML Part</part-name>\r
+      <score-instrument id="P1-I1">\r
+        <instrument-name>Grand Piano</instrument-name>\r
+      </score-instrument>\r
+      <midi-instrument id="P1-I1">\r
+        <midi-channel>1</midi-channel>\r
+        <midi-program>1</midi-program>\r
+      </midi-instrument>\r
+    </score-part>\r
+  </part-list>\r
+  <!--=========================================================-->\r
+  <part id="P1">\r
+    <measure number="1" width="441">\r
+      <print page-number="8"/>\r
+      <attributes>\r
+        <divisions>1</divisions>\r
+        <key>\r
+          <fifths>0</fifths>\r
+          <mode>major</mode>\r
+        </key>\r
+        <time symbol="common">\r
+          <beats>4</beats>\r
+          <beat-type>4</beat-type>\r
+        </time>\r
+        <clef>\r
+          <sign>G</sign>\r
+          <line>2</line>\r
+        </clef>\r
+      </attributes>\r
+      <sound tempo="120"/>\r
+      <note>\r
+        <rest/>\r
+        <duration>4</duration>\r
+        <voice>1</voice>\r
+      </note>\r
+    </measure>\r
+    <!--=======================================================-->\r
+    <measure number="2" width="378">\r
+      <note>\r
+        <rest/>\r
+        <duration>4</duration>\r
+        <voice>1</voice>\r
+      </note>\r
+    </measure>\r
+    <!--=======================================================-->\r
+    <measure number="3" width="819">\r
+      <print new-page="yes" page-number="9"/>\r
+      <note>\r
+        <rest/>\r
+        <duration>4</duration>\r
+        <voice>1</voice>\r
+      </note>\r
+      <barline location="right">\r
+        <bar-style>light-heavy</bar-style>\r
+      </barline>\r
+    </measure>\r
+  </part>\r
+  <!--=========================================================-->\r
+</score-partwise>\r
index 22891292890a442ebd72044d08ef2861106910eb..c70b396815939d4284ed384f51662f3f57e78027 100644 (file)
@@ -517,6 +517,46 @@ class Header:
         printer.newline ()
 
 
+class Paper:
+    def __init__ (self):
+        self.global_staff_size = -1
+        # page size
+        self.page_width = -1
+        self.page_height = -1
+        # page margins
+        self.top_margin = -1
+        self.bottom_margin = -1
+        self.left_margin = -1
+        self.right_margin = -1
+        self.system_left_margin = -1
+        self.system_right_margin = -1
+        self.system_distance = -1
+        self.top_system_distance = -1
+
+    def print_length_field (self, printer, field, value):
+        if value >= 0:
+            printer.dump ("%s = %s\\cm" % (field, value))
+            printer.newline ()
+    def print_ly (self, printer):
+        if self.global_staff_size > 0:
+            printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
+            printer.newline ()
+        printer.dump ('\\paper {')
+        printer.newline ()
+        self.print_length_field (printer, "paper-width", self.page_width)
+        self.print_length_field (printer, "paper-height", self.page_height)
+        self.print_length_field (printer, "top-margin", self.top_margin)
+        self.print_length_field (printer, "botton-margin", self.bottom_margin)
+        self.print_length_field (printer, "left-margin", self.left_margin)
+        # TODO: maybe set line-width instead of right-margin?
+        self.print_length_field (printer, "right-margin", self.right_margin)
+        # TODO: What's the corresponding setting for system_left_margin and
+        #        system_right_margin in Lilypond?
+        self.print_length_field (printer, "between-system-space", self.system_distance)
+        self.print_length_field (printer, "page-top-space", self.top_system_distance)
+
+        printer.dump ('}')
+        printer.newline ()
 
 
 class EventChord (NestedMusic):
index 18b351d272ed8416590c7ca7384b1a059f13fcf3..2c553a94d07215fb038b2b7886d843c94907134c 100644 (file)
@@ -49,6 +49,99 @@ additional_definitions = {
 """
 }
 
+def round_to_two_digits (val):
+    return round (val * 100) / 100
+
+def extract_layout_information (tree):
+    paper = musicexp.Paper ()
+    defaults = tree.get_maybe_exist_named_child ('defaults')
+    if not defaults:
+        return None
+    tenths = -1
+    scaling = defaults.get_maybe_exist_named_child ('scaling')
+    if scaling:
+        mm = scaling.get_named_child ('millimeters')
+        mm = string.atof (mm.get_text ())
+        tn = scaling.get_maybe_exist_named_child ('tenths')
+        tn = string.atof (tn.get_text ())
+        tenths = mm / tn
+        paper.global_staff_size = mm * 72.27 / 25.4
+    # We need the scaling (i.e. the size of staff tenths for everything!
+    if tenths < 0:
+        return None
+
+    def from_tenths (txt):
+        return round_to_two_digits (string.atof (txt) * tenths / 10)
+    def set_paper_variable (varname, parent, element_name):
+        el = parent.get_maybe_exist_named_child (element_name)
+        if el: # Convert to cm from tenths
+            setattr (paper, varname, from_tenths (el.get_text ()))
+
+    pagelayout = defaults.get_maybe_exist_named_child ('page-layout')
+    if pagelayout:
+        # TODO: How can one have different margins for even and odd pages???
+        set_paper_variable ("page_height", pagelayout, 'page-height')
+        set_paper_variable ("page_width", pagelayout, 'page-width')
+
+        pmargins = pagelayout.get_named_children ('page-margins')
+        for pm in pmargins:
+            set_paper_variable ("left_margin", pm, 'left-margin')
+            set_paper_variable ("right_margin", pm, 'right-margin')
+            set_paper_variable ("bottom_margin", pm, 'bottom-margin')
+            set_paper_variable ("top_margin", pm, 'top-margin')
+
+    systemlayout = defaults.get_maybe_exist_named_child ('system-layout')
+    if systemlayout:
+        sl = systemlayout.get_maybe_exist_named_child ('system-margins')
+        if sl:
+            set_paper_variable ("system_left_margin", sl, 'left-margin')
+            set_paper_variable ("system_right_margin", sl, 'right-margin')
+        set_paper_variable ("system_distance", systemlayout, 'system-distance')
+        set_paper_variable ("top_system_distance", systemlayout, 'top-system-distance')
+
+    stafflayout = defaults.get_named_children ('staff-layout')
+    for sl in stafflayout:
+        nr = getattr (sl, 'number', 1)
+        dist = sl.get_named_child ('staff-distance')
+        #TODO: the staff distance needs to be set in the Staff context!!!
+
+    # TODO: Finish appearance?, music-font?, word-font?, lyric-font*, lyric-language*
+    appearance = defaults.get_named_child ('appearance')
+    if appearance:
+        lws = appearance.get_named_children ('line-width')
+        for lw in lws:
+            # Possible types are: beam, bracket, dashes,
+            #    enclosure, ending, extend, heavy barline, leger,
+            #    light barline, octave shift, pedal, slur middle, slur tip,
+            #    staff, stem, tie middle, tie tip, tuplet bracket, and wedge
+            tp = lw.type
+            w = from_tenths (lw.get_data ())
+            # TODO: Do something with these values!
+        nss = appearance.get_named_children ('note-size')
+        for ns in nss:
+            # Possible types are: cue, grace and large
+            tp = ns.type
+            sz = from_tenths (ns.get_data ())
+            # TODO: Do something with these values!
+        # <other-appearance> elements have no specified meaning
+
+    rawmusicfont = defaults.get_named_child ('music-font')
+    if rawmusicfont:
+        # TODO: Convert the font
+        pass
+    rawwordfont = defaults.get_named_child ('word-font')
+    if rawwordfont:
+        # TODO: Convert the font
+        pass
+    rawlyricsfonts = defaults.get_named_children ('lyric-font')
+    for lyricsfont in rawlyricsfonts:
+        # TODO: Convert the font
+        pass
+
+    return paper
+
+
+
 # score information is contained in the <work>, <identification> or <movement-title> tags
 # extract those into a hash, indexed by proper lilypond header attributes
 def extract_score_information (tree):
@@ -1659,6 +1752,7 @@ def convert (filename, options):
 
     # score information is contained in the <work>, <identification> or <movement-title> tags
     score_information = extract_score_information (tree)
+    layout_information = extract_layout_information (tree)
     update_score_setup (score_structure, part_list, voices)
 
     if not options.output_name:
@@ -1677,7 +1771,10 @@ def convert (filename, options):
 
     print_ly_preamble (printer, filename)
     print_ly_additional_definitions (printer, filename)
-    score_information.print_ly (printer)
+    if score_information:
+        score_information.print_ly (printer)
+    if layout_information:
+        layout_information.print_ly (printer)
     print_voice_definitions (printer, part_list, voices)
     
     printer.close ()