self.newline ()
self._file.close ()
self._file = None
-
-
+
+
class Duration:
def __init__ (self):
self.duration_log = 0
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
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 ()
import os
import string
import codecs
+import zipfile
+import StringIO
from gettext import gettext as _
"""
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')
# 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
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
# 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
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)
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",
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)
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 ''
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: