X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=scripts%2Fmusicxml2ly.py;h=c6e0b64c530f24aa8106975f7605423790861ece;hb=c4d028afdec2ee6e3cbbd661ed750ee9f5cf4c8f;hp=aa91e9fc6857373799bfb02a63e5a7ccc1a17202;hpb=4e0ce47ff8a670d60bab732a460f3cea87324c61;p=lilypond.git diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index aa91e9fc68..c6e0b64c53 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -7,6 +7,7 @@ import os import string import codecs import zipfile +import tempfile import StringIO """ @@ -34,14 +35,6 @@ conversion_settings = Conversion_Settings () # this layout and add the corresponding settings layout_information = musicexp.Layout () -def progress (str): - ly.stderr_write (str + '\n') - sys.stderr.flush () - -def error_message (str): - ly.stderr_write (str + '\n') - sys.stderr.flush () - needed_additional_definitions = [] additional_definitions = { @@ -67,109 +60,8 @@ additional_definitions = { (let* ((ev (event-cause grob)) (den (if denominator denominator (ly:event-property ev 'denominator))) (num (if numerator numerator (ly:event-property ev 'numerator)))) - (format "~a:~a" den num))) + (format #f "~a:~a" den num))) """, - - "compound-time-signature": """%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Formatting of (possibly complex) compound time signatures -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -#(define-public (insert-markups l m) - (let* ((ll (reverse l))) - (let join-markups ((markups (list (car ll))) - (remaining (cdr ll))) - (if (pair? remaining) - (join-markups (cons (car remaining) (cons m markups)) (cdr remaining)) - markups)))) - -% Use a centered-column inside a left-column, because the centered column -% moves its reference point to the center, which the left-column undoes. -% The center-column also aligns its contented centered, which is not undone... -#(define-public (format-time-fraction time-sig-fraction) - (let* ((revargs (reverse (map number->string time-sig-fraction))) - (den (car revargs)) - (nums (reverse (cdr revargs)))) - (make-override-markup '(baseline-skip . 0) - (make-number-markup - (make-left-column-markup (list - (make-center-column-markup (list - (make-line-markup (insert-markups nums "+")) - den)))))))) - -#(define-public (format-complex-compound-time time-sig) - (let* ((sigs (map format-time-fraction time-sig))) - (make-override-markup '(baseline-skip . 0) - (make-number-markup - (make-line-markup - (insert-markups sigs (make-vcenter-markup "+"))))))) - -#(define-public (format-compound-time time-sig) - (cond - ((not (pair? time-sig)) (null-markup)) - ((pair? (car time-sig)) (format-complex-compound-time time-sig)) - (else (format-time-fraction time-sig)))) - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Measure length calculation of (possibly complex) compound time signatures -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -#(define-public (calculate-time-fraction time-sig-fraction) - (let* ((revargs (reverse time-sig-fraction)) - (den (car revargs)) - (nums (cdr revargs))) - (ly:make-moment (apply + nums) den))) - -#(define-public (calculate-complex-compound-time time-sig) - (let* ((sigs (map calculate-time-fraction time-sig))) - (let add-moment ((moment ZERO-MOMENT) - (remaining sigs)) - (if (pair? remaining) - (add-moment (ly:moment-add moment (car remaining)) (cdr remaining)) - moment)))) - -#(define-public (calculate-compound-measure-length time-sig) - (cond - ((not (pair? time-sig)) (ly:make-moment 4 4)) - ((pair? (car time-sig)) (calculate-complex-compound-time time-sig)) - (else (calculate-time-fraction time-sig)))) - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Base beat lenth -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -#(define-public (calculate-compound-base-beat-full time-sig) - (let* ((den (map last time-sig))) - (apply max den))) - -#(define-public (calculate-compound-base-beat time-sig) - (ly:make-moment 1 (cond - ((not (pair? time-sig)) 4) - ((pair? (car time-sig)) (calculate-compound-base-beat-full time-sig)) - (else (calculate-compound-base-beat-full (list time-sig)))))) - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% The music function to set the complex time signature -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -compoundMeter = -#(define-music-function (parser location args) (pair?) - (let ((mlen (calculate-compound-measure-length args)) - (beat (calculate-compound-base-beat args))) - #{ -\once \override Staff.TimeSignature #'stencil = #ly:text-interface::print -\once \override Staff.TimeSignature #'text = #(format-compound-time $args) -% \set Staff.beatGrouping = #(reverse (cdr (reverse $args))) -\set Timing.measureLength = $mlen -\set Timing.timeSignatureFraction = #(cons (ly:moment-main-numerator $mlen) - (ly:moment-main-denominator $mlen)) -\set Timing.beatLength = $beat - -% TODO: Implement beatGrouping and auto-beam-settings!!! -#} )) -""" } def round_to_two_digits (val): @@ -273,16 +165,26 @@ def extract_score_information (tree): if value: header.set_field (field, musicxml.escape_ly_output_string (value)) - movement_title = tree.get_maybe_exist_named_child ('movement-title') - if movement_title: - set_if_exists ('title', movement_title.get_text ()) work = tree.get_maybe_exist_named_child ('work') if work: - # Overwrite the title from movement-title with work->title - set_if_exists ('title', work.get_work_title ()) set_if_exists ('worknumber', work.get_work_number ()) set_if_exists ('opus', work.get_opus ()) + movement_title = tree.get_maybe_exist_named_child ('movement-title') + + # use either work-title or movement-title as title. + # if both exist use movement-title as subtitle. + # if there is only a movement-title (or work-title is empty or missing) the movement-title should be typeset as a title + if work: + work_title = work.get_work_title () + set_if_exists ('title', work_title) + if work_title == '': + set_if_exists ('title', movement_title.get_text ()) + elif movement_title: + set_if_exists ('subtitle', movement_title.get_text ()) + elif movement_title: + set_if_exists ('title', movement_title.get_text ()) + identifications = tree.get_named_children ('identification') for ids in identifications: set_if_exists ('copyright', ids.get_rights ()) @@ -291,12 +193,14 @@ def extract_score_information (tree): set_if_exists ('editor', ids.get_editor ()) set_if_exists ('poet', ids.get_poet ()) - set_if_exists ('tagline', ids.get_encoding_software ()) set_if_exists ('encodingsoftware', ids.get_encoding_software ()) set_if_exists ('encodingdate', ids.get_encoding_date ()) set_if_exists ('encoder', ids.get_encoding_person ()) set_if_exists ('encodingdescription', ids.get_encoding_description ()) + set_if_exists ('source', ids.get_source ()) + + # miscellaneous --> texidoc set_if_exists ('texidoc', ids.get_file_description ()); # Finally, apply the required compatibility modes @@ -321,7 +225,10 @@ def extract_score_information (tree): app_description = ignore_beaming_software.get (s, False); if app_description: conversion_settings.ignore_beaming = True - progress (_ ("Encountered file created by %s, containing wrong beaming information. All beaming information in the MusicXML file will be ignored") % app_description) + ly.warning (_ ("Encountered file created by %s, containing " + "wrong beaming information. All beaming " + "information in the MusicXML file will be " + "ignored") % app_description) # TODO: Check for other unsupported features return header @@ -337,11 +244,18 @@ class PartGroupInfo: def add_end (self, g): self.end[getattr (g, 'number', "1")] = g def print_ly (self, printer): - error_message (_ ("Unprocessed PartGroupInfo %s encountered") % self) + ly.warning (_ ("Unprocessed PartGroupInfo %s encountered") % self) def ly_expression (self): - error_message (_ ("Unprocessed PartGroupInfo %s encountered") % self) + ly.warning (_ ("Unprocessed PartGroupInfo %s encountered") % self) return '' +def musicxml_step_to_lily (step): + if step: + return (ord (step) - ord ('A') + 7 - 2) % 7 + else: + return None + + def staff_attributes_to_string_tunings (mxl_attr): details = mxl_attr.get_maybe_exist_named_child ('staff-details') if not details: @@ -351,7 +265,7 @@ def staff_attributes_to_string_tunings (mxl_attr): if staff_lines: lines = string.atoi (staff_lines.get_text ()) - tunings = [0]*lines + tunings = [musicexp.Pitch()]*lines staff_tunings = details.get_named_children ('staff-tuning') for i in staff_tunings: p = musicexp.Pitch() @@ -401,6 +315,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 +328,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 @@ -439,9 +358,20 @@ def extract_score_structure (part_list, staffinfo): # Finale gives unnamed parts the name "MusicXML Part" automatically! if partname and partname.get_text() != "MusicXML Part": staff.instrument_name = partname.get_text () - if el.get_maybe_exist_named_child ('part-abbreviation'): - staff.short_instrument_name = el.get_maybe_exist_named_child ('part-abbreviation').get_text () + # part-name-display overrides part-name! + partname = el.get_maybe_exist_named_child ("part-name-display") + if partname: + staff.instrument_name = extract_display_text (partname) + + partdisplay = el.get_maybe_exist_named_child ('part-abbreviation') + if partdisplay: + staff.short_instrument_name = partdisplay.get_text () + # part-abbreviation-display overrides part-abbreviation! + partdisplay = el.get_maybe_exist_named_child ("part-abbreviation-display") + if partdisplay: + staff.short_instrument_name = extract_display_text (partdisplay) # TODO: Read in the MIDI device / instrument + return staff def read_score_group (el): @@ -580,17 +510,18 @@ def rational_to_lily_duration (rational_len): d_log = {1: 0, 2: 1, 4:2, 8:3, 16:4, 32:5, 64:6, 128:7, 256:8, 512:9}.get (rational_len.denominator (), -1) # Duration of the form 1/2^n or 3/2^n can be converted to a simple lilypond duration - if (d_log >= 0 and rational_len.numerator() in (1,3,5,7) ): + dots = {1: 0, 3: 1, 7: 2, 15: 3, 31: 4, 63: 5, 127: 6}.get (rational_len.numerator(), -1) + if ( d_log >= dots >= 0 ): # account for the dots! - d.dots = (rational_len.numerator()-1)/2 - d.duration_log = d_log - d.dots + d.duration_log = d_log - dots + d.dots = dots elif (d_log >= 0): d.duration_log = d_log d.factor = Rational (rational_len.numerator ()) else: - error_message (_ ("Encountered rational duration with denominator %s, " + ly.warning (_ ("Encountered rational duration with denominator %s, " "unable to convert to lilypond duration") % - rational_len.denominator ()) + rational_len.denominator ()) # TODO: Test the above error message return None @@ -815,8 +746,6 @@ def musicxml_time_to_lily (attributes): return None change = musicexp.TimeSignatureChange() change.fractions = sig - if (len(sig) != 2) or isinstance (sig[0], list): - needed_additional_definitions.append ("compound-time-signature") time_elm = attributes.get_maybe_exist_named_child ('time') if time_elm and hasattr (time_elm, 'symbol'): @@ -837,7 +766,7 @@ def musicxml_time_to_lily (attributes): def musicxml_key_to_lily (attributes): key_sig = attributes.get_key_signature () if not key_sig or not (isinstance (key_sig, list) or isinstance (key_sig, tuple)): - error_message (_ ("Unable to extract key signature!")) + ly.warning (_ ("Unable to extract key signature!")) return None change = musicexp.KeySignatureChange() @@ -864,7 +793,7 @@ def musicxml_key_to_lily (attributes): start_pitch.step = n start_pitch.alteration = a except KeyError: - error_message (_ ("unknown mode %s, expecting 'major' or 'minor' " + ly.warning (_ ("unknown mode %s, expecting 'major' or 'minor' " "or a church mode!") % mode) fifth = musicexp.Pitch() @@ -879,7 +808,12 @@ def musicxml_key_to_lily (attributes): else: # Non-standard key signature of the form [[step,alter<,octave>],...] - change.non_standard_alterations = key_sig + # MusicXML contains C,D,E,F,G,A,B as steps, lily uses 0-7, so convert + alterations = [] + for k in key_sig: + k[0] = musicxml_step_to_lily (k[0]) + alterations.append (k) + change.non_standard_alterations = alterations return change def musicxml_transpose_to_lily (attributes): @@ -914,6 +848,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 = [] @@ -922,16 +872,28 @@ 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 +def extract_display_text (el): + child = el.get_maybe_exist_named_child ("display-text") + if child: + return child.get_text () + else: + return False + + def musicxml_print_to_lily (el): # TODO: Implement other print attributes # in MusicXML) are not yet implemented.")) + ly.warning (_ ("Metronome marks with complex relations ( in MusicXML) are not yet implemented.")) return # translate directions into Events, possible values: @@ -1546,6 +1516,7 @@ def musicxml_direction_to_lily (n): if ev: # TODO: set the correct direction! Unfortunately, \mark in ly does # not seem to support directions! + ev.force_direction = dir res.append (ev) continue @@ -1691,7 +1662,7 @@ def musicxml_chordkind_to_lily (kind): res = chordkind_dict.get (kind, None) # Check for None, since a major chord is converted to '' if res == None: - error_message (_ ("Unable to convert chord type %s to lilypond.") % kind) + ly.warning (_ ("Unable to convert chord type %s to lilypond.") % kind) return res def musicxml_harmony_to_lily_chordname (n): @@ -1814,14 +1785,16 @@ def musicxml_note_to_lily_main_event (n): acc = n.get_maybe_exist_named_child ('accidental') if acc: # let's not force accs everywhere. - event.cautionary = acc.editorial + event.cautionary = acc.cautionary + # TODO: Handle editorial accidentals + # TODO: Handle the level-display setting for displaying brackets/parentheses elif n.get_maybe_exist_typed_child (musicxml.Unpitched): - # Unpitched elements have display-step and can also have - # display-octave. - unpitched = n.get_maybe_exist_typed_child (musicxml.Unpitched) - event = musicexp.NoteEvent () - event.pitch = musicxml_unpitched_to_lily (unpitched) + # Unpitched elements have display-step and can also have + # display-octave. + unpitched = n.get_maybe_exist_typed_child (musicxml.Unpitched) + event = musicexp.NoteEvent () + event.pitch = musicxml_unpitched_to_lily (unpitched) elif n.get_maybe_exist_typed_child (musicxml.Rest): # rests can have display-octave and display-step, which are @@ -1990,8 +1963,8 @@ class LilyPondVoiceBuilder: diff = moment - current_end if diff < Rational (0): - error_message (_ ('Negative skip %s (from position %s to %s)') % - (diff, current_end, moment)) + ly.warning (_ ('Negative skip %s (from position %s to %s)') % + (diff, current_end, moment)) diff = Rational (0) if diff > Rational (0) and not (self.ignore_skips and moment == 0): @@ -2060,12 +2033,6 @@ class VoiceData: self.lyrics_dict = {} self.lyrics_order = [] -def musicxml_step_to_lily (step): - if step: - return (ord (step) - ord ('A') + 7 - 2) % 7 - else: - return None - def measure_length_from_attributes (attr, current_measure_length): len = attr.get_measure_length () if not len: @@ -2473,7 +2440,7 @@ def musicxml_voice_to_lily_voice (voice): if len (modes_found) > 1: - error_message (_ ('cannot simultaneously have more than one mode: %s') % modes_found.keys ()) + ly.warning (_ ('cannot simultaneously have more than one mode: %s') % modes_found.keys ()) if options.relative: v = musicexp.RelativeMusic () @@ -2530,11 +2497,11 @@ def musicxml_unpitched_to_lily (mxl_unpitched): p = None step = mxl_unpitched.get_step () if step: - p = musicexp.Pitch () - p.step = musicxml_step_to_lily (step) + p = musicexp.Pitch () + p.step = musicxml_step_to_lily (step) octave = mxl_unpitched.get_octave () if octave and p: - p.octave = octave - 4 + p.octave = octave - 4 return p def musicxml_restdisplay_to_lily (mxl_rest): @@ -2581,7 +2548,7 @@ def get_all_voices (parts): part_ly_voices = {} for n, v in name_voice.items (): - progress (_ ("Converting to LilyPond expressions...")) + ly.progress (_ ("Converting to LilyPond expressions..."), True) # musicxml_voice_to_lily_voice returns (lily_voice, {nr->lyrics, nr->lyrics}) part_ly_voices[n] = musicxml_voice_to_lily_voice (v) @@ -2604,7 +2571,7 @@ If the given filename is -, musicxml2ly reads from the command line. p.version = ('''%prog (LilyPond) @TOPLEVEL_VERSION@\n\n''' + -_ ("""Copyright (c) 2005--2009 by +_ ("""Copyright (c) 2005--2011 by Han-Wen Nienhuys , Jan Nieuwenhuizen and Reinhold Kainhofer @@ -2621,8 +2588,9 @@ information.""") % 'lilypond') help=_ ("show version number and exit")) p.add_option ('-v', '--verbose', - action = "store_true", - dest = 'verbose', + action="callback", + callback=ly.handle_loglevel_option, + callback_args=("DEBUG",), help = _ ("be verbose")) p.add_option ('', '--lxml', @@ -2651,7 +2619,15 @@ information.""") % 'lilypond') p.add_option ('-l', '--language', metavar = _ ("LANG"), action = "store", - help = _ ("use a different language file 'LANG.ly' and corresponding pitch names, e.g. 'deutsch' for deutsch.ly")) + help = _ ("use LANG for pitch names, e.g. 'deutsch' for note names in German")) + + p.add_option ("--loglevel", + help=_ ("Print log messages according to LOGLEVEL " + "(NONE, ERROR, WARNING, PROGRESS (default), DEBUG)"), + metavar=_ ("LOGLEVEL"), + action='callback', + callback=ly.handle_loglevel_option, + type='string') p.add_option ('--nd', '--no-articulation-directions', action = "store_false", @@ -2684,6 +2660,13 @@ information.""") % 'lilypond') type = 'string', dest = 'output_name', help = _ ("set output filename to FILE, stdout if -")) + + p.add_option ('-m', '--midi', + action = "store_true", + default = False, + dest = "midi", + help = _("add midi-block to .ly file")) + p.add_option_group ('', description = ( _ ("Report bugs via %s") @@ -2766,7 +2749,7 @@ def update_score_setup (score_structure, part_list, voices): part_id = part_definition.id nv_dict = voices.get (part_id) if not nv_dict: - error_message (_ ('unknown part in part-list: %s') % part_id) + ly.warning (_ ('unknown part in part-list: %s') % part_id) continue staves = reduce (lambda x,y: x+ y, @@ -2796,7 +2779,7 @@ def update_layout_information (): def print_ly_preamble (printer, filename): printer.dump_version () - printer.print_verbatim ('%% automatically converted from %s\n' % filename) + printer.print_verbatim ('%% automatically converted by musicxml2ly from %s\n' % filename) def print_ly_additional_definitions (printer, filename): if needed_additional_definitions: @@ -2828,10 +2811,20 @@ def read_musicxml (filename, compressed, use_lxml): raw_string = None if compressed: if filename == "-": - progress (_ ("Input is compressed, extracting raw MusicXML data from stdin") ) - z = zipfile.ZipFile (sys.stdin) + ly.progress (_ ("Input is compressed, extracting raw MusicXML data from stdin"), True) + # unfortunately, zipfile.ZipFile can't read directly from + # stdin, so copy everything from stdin to a temp file and read + # that. TemporaryFile() will remove the file when it is closed. + tmp = tempfile.TemporaryFile() + sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0) # Make sys.stdin binary + bytes_read = sys.stdin.read (8192) + while bytes_read: + for b in bytes_read: + tmp.write(b) + bytes_read = sys.stdin.read (8192) + z = zipfile.ZipFile (tmp, "r") else: - progress (_ ("Input file %s is compressed, extracting raw MusicXML data") % filename) + ly.progress (_ ("Input file %s is compressed, extracting raw MusicXML data") % filename, True) z = zipfile.ZipFile (filename, "r") container_xml = z.read ("META-INF/container.xml") if not container_xml: @@ -2861,9 +2854,9 @@ def read_musicxml (filename, compressed, use_lxml): def convert (filename, options): if filename == "-": - progress (_ ("Reading MusicXML from Standard input ...") ) + ly.progress (_ ("Reading MusicXML from Standard input ..."), True) else: - progress (_ ("Reading MusicXML from %s ...") % filename) + ly.progress (_ ("Reading MusicXML from %s ...") % filename, True) tree = read_musicxml (filename, options.compressed, options.use_lxml) score_information = extract_score_information (tree) @@ -2896,9 +2889,9 @@ def convert (filename, options): else: output_ly_name = options.output_name + '.ly' - progress (_ ("Output to `%s'") % output_ly_name) + ly.progress (_ ("Output to `%s'") % output_ly_name, True) printer = musicexp.Output_printer() - #progress (_ ("Output to `%s'") % defs_ly_name) + #ly.progress (_ ("Output to `%s'") % defs_ly_name, True) if (options.output_name == "-"): printer.set_file (codecs.getwriter ("utf-8")(sys.stdout)) else: @@ -2941,17 +2934,20 @@ def main (): opt_parser.print_usage() sys.exit (2) + if options.midi: + musicexp.set_create_midi (options.midi) + 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 + additional_definitions[options.language] = "\\language \"%s\"\n" % options.language conversion_settings.ignore_beaming = not options.convert_beaming conversion_settings.convert_page_layout = options.convert_page_layout # Allow the user to leave out the .xml or xml on the filename basefilename = args[0].decode('utf-8') if basefilename == "-": # Read from stdin - basefilename = "-" + filename = "-" else: filename = get_existing_filename_with_extension (basefilename, "xml") if not filename: @@ -2963,7 +2959,7 @@ def main (): if filename and (filename == "-" or os.path.exists (filename)): voices = convert (filename, options) else: - progress (_ ("Unable to find input file %s") % basefilename) + ly.error (_ ("Unable to find input file %s") % basefilename) if __name__ == '__main__': main()