]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge branch 'master' of ssh://kainhofer@git.sv.gnu.org/srv/git/lilypond into kainhofer
authorReinhold Kainhofer <reinhold@kainhofer.com>
Thu, 15 Nov 2007 11:57:56 +0000 (12:57 +0100)
committerReinhold Kainhofer <reinhold@kainhofer.com>
Thu, 15 Nov 2007 11:57:56 +0000 (12:57 +0100)
input/regression/musicxml/20a-Compressed-MusicXML-Sample.mxl [new file with mode: 0644]
python/musicexp.py
scripts/musicxml2ly.py

diff --git a/input/regression/musicxml/20a-Compressed-MusicXML-Sample.mxl b/input/regression/musicxml/20a-Compressed-MusicXML-Sample.mxl
new file mode 100644 (file)
index 0000000..0d41bf3
Binary files /dev/null and b/input/regression/musicxml/20a-Compressed-MusicXML-Sample.mxl differ
index c70b396815939d4284ed384f51662f3f57e78027..168be1a33077a20bb639e37f15f0f1a0d1ecc208 100644 (file)
@@ -127,8 +127,8 @@ class Output_printer:
         self.newline ()
         self._file.close ()
         self._file = None
-        
-        
+
+
 class Duration:
     def __init__ (self):
         self.duration_log = 0
@@ -183,7 +183,71 @@ class Duration:
 
         return base * dot_fact * self.factor
 
-    
+
+# Implement the different note names for the various languages
+def pitch_generic (pitch, notenames, accidentals):
+    str = notenames[pitch.step]
+    if pitch.alteration < 0:
+        str += accidentals[0] * (-pitch.alteration)
+    elif pitch.alteration > 0:
+        str += accidentals[3] * (pitch.alteration)
+    return str
+
+def pitch_general (pitch):
+    str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is'])
+    return str.replace ('aes', 'as').replace ('ees', 'es')
+
+def pitch_nederlands (pitch):
+    return pitch_general (pitch)
+
+def pitch_english (pitch):
+    str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's'])
+    return str.replace ('aes', 'as').replace ('ees', 'es')
+
+def pitch_deutsch (pitch):
+    str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is'])
+    return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es')
+
+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'])
+    return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es')
+
+def pitch_italiano (pitch):
+    str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd'])
+    return str
+
+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'])
+    return str
+
+def pitch_vlaams (pitch):
+    str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k'])
+    return str
+
+def set_pitch_language (language):
+    global pitch_generating_function
+    function_dict = {
+        "nederlands": pitch_nederlands,
+        "english": pitch_english,
+        "deutsch": pitch_deutsch,
+        "norsk": pitch_norsk,
+        "svenska": pitch_svenska,
+        "italiano": pitch_italiano,
+        "catalan": pitch_catalan,
+        "espanol": pitch_espanol,
+        "vlaams": pitch_vlaams}
+    pitch_generating_function = function_dict.get (language, pitch_general)
+
+# global variable to hold the formatting function.
+pitch_generating_function = pitch_general
+
+
 class Pitch:
     def __init__ (self):
         self.alteration = 0
@@ -230,13 +294,7 @@ class Pitch:
         return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
     
     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')
+        return pitch_generating_function (self)
     
     def ly_expression (self):
         str = self.ly_step_expression ()
index 2c553a94d07215fb038b2b7886d843c94907134c..8f3b42a3967aaf8cc376f6e95b2ae5468e30e1f8 100644 (file)
@@ -6,6 +6,8 @@ import re
 import os
 import string
 import codecs
+import zipfile
+import StringIO
 from gettext import gettext as _
 
 """
@@ -19,6 +21,8 @@ import musicexp
 
 from rational import Rational
 
+# Store command-line options in a global variable, so we can access them everythwere
+options = None
 
 def progress (str):
     sys.stderr.write (str + '\n')
@@ -115,13 +119,13 @@ def extract_layout_information (tree):
             #    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 ())
+            w = from_tenths (lw.get_text  ())
             # 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 ())
+            sz = from_tenths (ns.get_text ())
             # TODO: Do something with these values!
         # <other-appearance> elements have no specified meaning
 
@@ -753,21 +757,21 @@ def musicxml_spanner_to_lily_event (mxl_event):
     return ev
 
 def musicxml_direction_to_indicator (direction):
-    return { "above": 1, "upright": 1, "below": -1, "downright": -1 }.get (direction, '')
+    return { "above": 1, "upright": 1, "up":1, "below": -1, "downright": -1, "down": -1 }.get (direction, 0)
 
 def musicxml_fermata_to_lily_event (mxl_event):
     ev = musicexp.ArticulationEvent ()
     ev.type = "fermata"
     if hasattr (mxl_event, 'type'):
       dir = musicxml_direction_to_indicator (mxl_event.type)
-      if dir:
+      if dir and options.convert_directions:
         ev.force_direction = dir
     return ev
 
 
 def musicxml_arpeggiate_to_lily_event (mxl_event):
     ev = musicexp.ArpeggioEvent ()
-    ev.direction = {"up": 1, "down": -1}.get (getattr (mxl_event, 'direction', None), 0)
+    ev.direction = musicxml_direction_to_indicator (getattr (mxl_event, 'direction', None))
     return ev
 
 
@@ -896,10 +900,12 @@ def musicxml_articulation_to_lily_event (mxl_event):
 
     # Some articulations use the type attribute, other the placement...
     dir = None
-    if hasattr (mxl_event, 'type'):
+    if hasattr (mxl_event, 'type') and options.convert_directions:
         dir = musicxml_direction_to_indicator (mxl_event.type)
-    if hasattr (mxl_event, 'placement'):
+    if hasattr (mxl_event, 'placement') and options.convert_directions:
         dir = musicxml_direction_to_indicator (mxl_event.placement)
+    if dir:
+        ev.force_direction = dir
     return ev
 
 
@@ -938,7 +944,7 @@ def musicxml_words_to_lily_event (words):
     text = re.sub (' *\n? *$', '', text)
     event.text = text
 
-    if hasattr (words, 'default-y'):
+    if hasattr (words, 'default-y') and options.convert_directions:
         offset = getattr (words, 'default-y')
         try:
             off = string.atoi (offset)
@@ -1619,7 +1625,23 @@ Copyright (c) 2005--2007 by
                   default=False,
                   dest="use_lxml",
                   help=_ ("Use lxml.etree; uses less memory and cpu time."))
-    
+
+    p.add_option ('-z', '--compressed',
+                  action = "store_true",
+                  dest = 'compressed',
+                  default = False,
+                  help = _ ("Input file is a zip-compressed MusicXML file."))
+
+    p.add_option ('-l', '--language',
+                  action = "store",
+                  help = _ ("Use a different language file, e.g. 'deutsch' for deutsch.ly."))
+
+    p.add_option ('--no-articulation-directions', '--nd',
+                  action = "store_false",
+                  default = True,
+                  dest = "convert_directions",
+                  help = _ ("Do not convert directions (^, _ or -) for articulations."))
+
     p.add_option ('-o', '--output',
                   metavar=_ ("FILE"),
                   action="store",
@@ -1718,29 +1740,56 @@ def print_ly_additional_definitions (printer, filename):
         printer.newline ()
     for a in set(needed_additional_definitions):
         printer.print_verbatim (additional_definitions.get (a, ''))
+    printer.newline ()
 
-
-def read_musicxml (filename, use_lxml):
+# Read in the tree from the given I/O object (either file or string) and 
+# demarshall it using the classes from the musicxml.py file
+def read_xml (io_object, use_lxml):
     if use_lxml:
         import lxml.etree
-        
-        tree = lxml.etree.parse (filename)
+        tree = lxml.etree.parse (io_object)
         mxl_tree = musicxml.lxml_demarshal_node (tree.getroot ())
         return mxl_tree
     else:
         from xml.dom import minidom, Node
-        
-        doc = minidom.parse(filename)
+        doc = minidom.parse(io_object)
         node = doc.documentElement
         return musicxml.minidom_demarshal_node (node)
-
     return None
 
 
+def read_musicxml (filename, compressed, use_lxml):
+    raw_string = None
+    if compressed:
+        progress ("Input file %s is compressed, extracting raw MusicXML data" % filename)
+        z = zipfile.ZipFile (filename, "r")
+        container_xml = z.read ("META-INF/container.xml")
+        if not container_xml:
+            return None
+        container = read_xml (StringIO.StringIO (container_xml), use_lxml)
+        if not container:
+            return None
+        rootfiles = container.get_maybe_exist_named_child ('rootfiles')
+        if not rootfiles:
+            return None
+        rootfile_list = rootfiles.get_named_children ('rootfile')
+        mxml_file = None
+        if len (rootfile_list) > 0:
+            mxml_file = getattr (rootfile_list[0], 'full-path', None)
+        if mxml_file:
+            raw_string = z.read (mxml_file)
+
+    io_object = filename
+    if raw_string:
+        io_object = StringIO.StringIO (raw_string)
+
+    return read_xml (io_object, use_lxml)
+
+
 def convert (filename, options):
     progress ("Reading MusicXML from %s ..." % filename)
     
-    tree = read_musicxml (filename, options.use_lxml)
+    tree = read_musicxml (filename, options.compressed, options.use_lxml)
     parts = tree.get_typed_children (musicxml.Part)
     (voices, staff_info) = get_all_voices (parts)
 
@@ -1793,10 +1842,10 @@ def convert (filename, options):
 def get_existing_filename_with_extension (filename, ext):
     if os.path.exists (filename):
         return filename
-    newfilename = filename + ".xml"
+    newfilename = filename + "." + ext
     if os.path.exists (newfilename):
         return newfilename;
-    newfilename = filename + "xml"
+    newfilename = filename + ext
     if os.path.exists (newfilename):
         return newfilename;
     return ''
@@ -1804,13 +1853,22 @@ def get_existing_filename_with_extension (filename, ext):
 def main ():
     opt_parser = option_parser()
 
+    global options
     (options, args) = opt_parser.parse_args ()
     if not args:
         opt_parser.print_usage()
         sys.exit (2)
-    
+
+    if options.language:
+        musicexp.set_pitch_language (options.language)
+        needed_additional_definitions.append (options.language)
+        additional_definitions[options.language] = "\\include \"%s.ly\"\n" % options.language
+
     # Allow the user to leave out the .xml or xml on the filename
     filename = get_existing_filename_with_extension (args[0], "xml")
+    if not filename:
+        filename = get_existing_filename_with_extension (args[0], "mxl")
+        options.compressed = True
     if filename and os.path.exists (filename):
         voices = convert (filename, options)
     else: