# Store command-line options in a global variable, so we can access them everythwere
options = None
+class Conversion_Settings:
+ def __init__(self):
+ self.ignore_beaming = False
+
+conversion_settings = Conversion_Settings ()
+# Use a global variable to store the setting needed inside a \layout block.
+# whenever we need to change a setting or add/remove an engraver, we can access
+# this layout and add the corresponding settings
+layout_information = musicexp.Layout ()
+
def progress (str):
ly.stderr_write (str + '\n')
sys.stderr.flush ()
def round_to_two_digits (val):
return round (val * 100) / 100
-def extract_layout_information (tree):
+def extract_paper_information (tree):
paper = musicexp.Paper ()
defaults = tree.get_maybe_exist_named_child ('defaults')
if not defaults:
set_if_exists ('encoder', ids.get_encoding_person ())
set_if_exists ('encodingdescription', ids.get_encoding_description ())
+ # Finally, apply the required compatibility modes
+ # Some applications created wrong MusicXML files, so we need to
+ # apply some compatibility mode, e.g. ignoring some features/tags
+ # in those files
+ software = ids.get_encoding_software_list ()
+
+ # Case 1: "Sibelius 5.1" with the "Dolet 3.4 for Sibelius" plugin
+ # is missing all beam ends => ignore all beaming information
+ if "Dolet 3.4 for Sibelius" in software:
+ conversion_settings.ignore_beaming = True
+ progress (_ ("Encountered file created by Dolet 3.4 for Sibelius, containing wrong beaming information. All beaming information in the MusicXML file will be ignored"))
+ # TODO: Check for other unsupported features
+
return header
class PartGroupInfo:
clef_sign = {"percussion": "percussion", "TAB": "tab"}.get (sign.get_text (), None)
lines = 5
- details = attributes.get_maybe_exist_named_child ('staff-details')
- if details:
- staff_lines = details.get_maybe_exist_named_child ('staff-lines')
+ details = attributes.get_named_children ('staff-details')
+ for d in details:
+ staff_lines = d.get_maybe_exist_named_child ('staff-lines')
if staff_lines:
lines = string.atoi (staff_lines.get_text ())
return staff
-def extract_score_layout (part_list, staffinfo):
- layout = musicexp.StaffGroup (None)
+def extract_score_structure (part_list, staffinfo):
+ structure = musicexp.StaffGroup (None)
if not part_list:
- return layout
+ return structure
def read_score_part (el):
if not isinstance (el, musicxml.Score_part):
if len (staves) == 1:
return staves[0]
for i in staves:
- layout.append_staff (i)
- return layout
+ structure.append_staff (i)
+ return structure
if drum_type:
event.drum_type = drum_type
else:
- n.message ("drum %s type unknown, please add to instrument_drumtype_dict" % n.instrument_name)
+ n.message (_ ("drum %s type unknown, please add to instrument_drumtype_dict") % n.instrument_name)
event.drum_type = 'acousticsnare'
else:
- n.message ("cannot find suitable event")
+ n.message (_ ("cannot find suitable event"))
if event:
event.duration = musicxml_duration_to_lily (n)
voice_builder.jumpto (n._when)
except NegativeSkip, neg:
voice_builder.correct_negative_skip (n._when)
- n.message ("Negative skip? from %s to %s, diff %s" % (neg.here, neg.dest, neg.dest - neg.here))
+ n.message (_ ("Negative skip found: from %s to %s, difference is %s") % (neg.here, neg.dest, neg.dest - neg.here))
if isinstance (n, musicxml.Attributes):
if n.is_first () and n._measure_position == Rational (0):
mxl_beams = [b for b in n.get_named_children ('beam')
if (b.get_type () in ('begin', 'end')
and b.is_primary ())]
- if mxl_beams:
+ if mxl_beams and not conversion_settings.ignore_beaming:
beam_ev = musicxml_spanner_to_lily_event (mxl_beams[0])
if beam_ev:
ev_chord.append (beam_ev)
dest = "convert_directions",
help = _ ("do not convert directions (^, _ or -) for articulations, dynamics, etc."))
+ p.add_option ('--no-beaming',
+ action = "store_false",
+ default = True,
+ dest = "convert_beaming",
+ help = _ ("do not convert beaming information, use lilypond's automatic beaming instead"))
+
p.add_option ('-o', '--output',
metavar = _ ("FILE"),
action = "store",
staves_info.append (format_staff_info (part_id, None, thisstaff_raw_voices))
score_structure.set_part_information (part_id, staves_info)
+# Set global values in the \layout block, like auto-beaming etc.
+def update_layout_information ():
+ if not conversion_settings.ignore_beaming and layout_information:
+ layout_information.set_context_item ('Score', 'autoBeaming = ##f')
+
def print_ly_preamble (printer, filename):
printer.dump_version ()
printer.print_verbatim ('%% automatically converted from %s\n' % filename)
def convert (filename, options):
progress (_ ("Reading MusicXML from %s ...") % filename)
-
+
tree = read_musicxml (filename, options.compressed, options.use_lxml)
+ score_information = extract_score_information (tree)
+ paper_information = extract_paper_information (tree)
+
parts = tree.get_typed_children (musicxml.Part)
(voices, staff_info) = get_all_voices (parts)
score_structure = None
mxl_pl = tree.get_maybe_exist_typed_child (musicxml.Part_list)
if mxl_pl:
- score_structure = extract_score_layout (mxl_pl, staff_info)
+ score_structure = extract_score_structure (mxl_pl, staff_info)
part_list = mxl_pl.get_named_children ("score-part")
# 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)
+ # After the conversion, update the list of settings for the \layout block
+ update_layout_information ()
if not options.output_name:
options.output_name = os.path.basename (filename)
print_ly_additional_definitions (printer, filename)
if score_information:
score_information.print_ly (printer)
+ if paper_information:
+ paper_information.print_ly (printer)
if layout_information:
layout_information.print_ly (printer)
print_voice_definitions (printer, part_list, voices)
musicexp.set_pitch_language (options.language)
needed_additional_definitions.append (options.language)
additional_definitions[options.language] = "\\include \"%s.ly\"\n" % options.language
+ conversion_settings.ignore_beaming = not options.convert_beaming
# Allow the user to leave out the .xml or xml on the filename
filename = get_existing_filename_with_extension (args[0], "xml")