progress = ly.progress
warning = ly.warning
error = ly.error
+debug = ly.debug_output
def filter_pipe (self, input, cmd):
"""Pass input through cmd, and return the result."""
- if self.global_options.verbose:
- progress (_ ("Running through filter `%s'\n") % cmd)
+ debug (_ ("Running through filter `%s'") % cmd, True)
# TODO: Use Popen once we resolve the problem with msvcrt in Windows:
(stdin, stdout, stderr) = os.popen3 (cmd)
ly.stderr_write (stderr.read ())
exit (status)
- if self.global_options.verbose:
- progress ('\n')
+ debug ('\n')
return output
# execute the command and pipe stdout to the parameter_string:
cmd = 'LC_ALL=C %s -c -o %s %s' % (global_options.texinfo_program, outfile, tmpfile);
- if (global_options.verbose):
- progress ("Executing: %s\n" % cmd);
+ ly.debug_output ("Executing: %s\n" % cmd);
proc = subprocess.Popen (cmd,
universal_newlines=True, shell=True,
exampleindent = "0.4\\in"
retval = {LINE_WIDTH: textwidth, EXAMPLEINDENT: exampleindent}
- if (global_options.verbose):
- progress ("Auto-detected values are: %s\n" % retval);
+ ly.debug_output ("Auto-detected values are: %s\n" % retval);
return retval;
else:
program_version = "unknown"
+
+# Logging framework: We have the following output functions:
+# error
+# warning
+# progress
+# debug
+
+loglevels = {"NONE":0, "ERROR":1, "WARN":2, "BASIC":3, "PROGRESS":4, "INFO":5, "DEBUG":6}
+
+loglevel = loglevels["PROGRESS"]
+
+def set_loglevel (l):
+ global loglevel
+ newlevel = loglevels.get (l, -1)
+ if newlevel > 0:
+ debug_output (_ ("Setting loglevel to %s") % l)
+ loglevel = newlevel
+ else:
+ error (_ ("Unknown or invalid loglevel '%s'") % l)
+
+
+def handle_loglevel_option (option, opt_str, value, parser, *args):
+ if value:
+ set_loglevel (value);
+ elif args:
+ set_loglevel (args[0]);
+
+def is_loglevel (l):
+ global loglevel
+ return loglevel >= loglevels[l];
+
+def is_verbose ():
+ return is_loglevel ("DEBUG")
+
def stderr_write (s):
encoded_write (sys.stderr, s)
-def warning (s):
- stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n')
+def print_logmessage (level, s, fullmessage = True):
+ if (is_loglevel (level)):
+ if fullmessage:
+ stderr_write (program_name + ": " + s + '\n')
+ else:
+ stderr_write (s)
def error (s):
- stderr_write (program_name + ": " + _ ("error: %s") % s + '\n')
+ print_logmessage ("ERROR", _ ("error: %s") % s);
+
+def warning (s):
+ print_logmessage ("WARN", _ ("warning: %s") % s);
+
+def basic_progress (s):
+ print_logmessage ("BASIC", s);
+
+def progress (s, fullmessage = False):
+ print_logmessage ("PROGRESS", s, fullmessage);
+
+def debug_output (s, fullmessage = False):
+ print_logmessage ("DEBUG", s, fullmessage);
-progress = stderr_write
def require_python_version ():
if sys.hexversion < 0x02040000:
- stderr_write ("Python 2.4 or newer is required to run this program.\n\
+ error ("Python 2.4 or newer is required to run this program.\n\
Please upgrade Python from http://python.org/download/, and if you use MacOS X,\n\
please read 'Setup for MacOS X' in Application Usage.")
os.system ("open http://python.org/download/")
previous_pitch = None
relative_pitches = False
-def warning (str):
- ly.stderr_write ((_ ("warning: %s") % str) + "\n")
-
def escape_instrument_string (input_string):
retstring = string.replace (input_string, "\"", "\\\"")
# Handle remaining fraction to pitch.alteration (for microtones)
if (halftones != pitch.alteration):
if None in accidentals[1:3]:
- warning (_ ("Language does not support microtones contained in the piece"))
+ ly.warning (_ ("Language does not support microtones contained in the piece"))
else:
try:
str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones]
except KeyError:
- warning (_ ("Language does not support microtones contained in the piece"))
+ ly.warning (_ ("Language does not support microtones contained in the piece"))
return str
def pitch_general (pitch):
func ("\\once \\override TupletBracket #'stencil = ##f")
func.newline ()
elif self.display_bracket == "curved":
- warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
+ ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
func.newline ()
self.music = SequentialMusic ()
self.music.elements = music
else:
- warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
+ ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
{'music':music, 'repeat':self})
def add_ending (self, music):
self.endings.append (music)
if self.music:
self.music.print_ly (printer)
else:
- warning (_ ("encountered repeat without body"))
+ ly.warning (_ ("encountered repeat without body"))
printer.dump ('{}')
if self.endings:
printer.dump ('\\alternative {')
# don't print newlines after the { and } braces
self.grace_elements.print_ly (printer, False)
elif self.grace_elements: # no self.elements!
- warning (_ ("Grace note with no following music: %s") % self.grace_elements)
+ ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
if self.grace_type:
printer ('\\%s' % self.grace_type)
else:
try:
value = {8: 1, 15: 2}[self.size]
except KeyError:
- warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
+ ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
value = 0
# negative values go up!
value *= -1*self.span_type
try:
accidental = alter_dict[a[1]]
except KeyError:
- warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
+ ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
return ''
if len (a) == 2:
return "( %s . %s )" % (a[0], accidental)
_ = ly._
-def error (str):
- ly.stderr_write ((_ ("error: %s") % str) + "\n")
-
def escape_ly_output_string (input_string):
return_string = input_string
return ''.join ([c.get_text () for c in self._children])
def message (self, msg):
- ly.stderr_write (msg+'\n')
+ ly.warning (msg)
p = self
while p:
- sys.stderr.write (' In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
+ ly.progress (' In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
p = p.get_parent ()
def dump (self, indent = ''):
- sys.stderr.write ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
+ ly.debug_output ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
non_text_children = [c for c in self._children if not isinstance (c, Hash_text)]
if non_text_children:
- sys.stderr.write ('\n')
+ ly.debug_output ('\n')
for c in self._children:
c.dump (indent + " ")
if non_text_children:
- sys.stderr.write (indent)
- sys.stderr.write ('</%s>\n' % self._name)
+ ly.debug_output (indent)
+ ly.debug_output ('</%s>\n' % self._name)
def get_typed_children (self, klass):
def get_unique_typed_child (self, klass):
cn = self.get_typed_children(klass)
if len (cn) <> 1:
- sys.stderr.write (self.__dict__ + '\n')
+ ly.error (self.__dict__)
raise 'Child is not unique for', (klass, 'found', cn)
return cn[0]
pass
class Hash_text (Music_xml_node):
def dump (self, indent = ''):
- sys.stderr.write ('%s' % string.strip (self._data))
+ ly.debug_output ('%s' % string.strip (self._data))
class Pitch (Music_xml_node):
def get_step (self):
if mxl.get_maybe_exist_named_child ('senza-misura'):
# TODO: Handle pieces without a time signature!
- error (_ ("Senza-misura time signatures are not yet supported!"))
+ ly.warning (_ ("Senza-misura time signatures are not yet supported!"))
return (4, 4)
else:
signature = []
if instrument_name:
return instrument_name
else:
- ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
+ ly.warning (_ ("Unable to find instrument for ID=%s\n") % id)
return "Grand Piano"
class Part_group (Music_xml_node):
authors = ('Jan Nieuwenhuizen <janneke@gnu.org>',
'Han-Wen Nienhuys <hanwen@xs4all.nl>')
-error_file_write = ly.stderr_write
-
-def warning (s):
- ly.stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n')
-
-def error (s):
- ly.stderr_write (program_name + ": " + _ ("error: %s") % s + '\n')
-
-def identify (port=sys.stderr):
- ly.encoded_write (port, '%s (GNU LilyPond) %s\n' % (program_name, program_version))
+def identify ():
+ ly.progress ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
def warranty ():
identify ()
p.add_option ('-e', '--edit', help=_ ("edit in place"),
action='store_true')
+ p.add_option ("-l", "--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 ('-n', '--no-version',
help=_ ("do not add \\version command if missing"),
action='store_true',
string."""
conv_list = get_conversions (from_version, to_version)
- error_file_write (_ ("Applying conversion: "))
+ ly.progress (_ ("Applying conversion: "))
last_conversion = ()
try:
if not conv_list:
last_conversion = to_version
for x in conv_list:
- error_file_write (tup_to_str (x[0]))
+ ly.progress (tup_to_str (x[0]))
if x != conv_list[-1]:
- error_file_write (', ')
+ ly.progress (', ')
str = x[1] (str)
last_conversion = x[0]
except convertrules.FatalConversionError:
- error_file_write ('\n'
- + _ ("Error while converting")
- + '\n'
- + _ ("Stopping at last successful rule")
- + '\n')
+ ly.error (_ ("Error while converting")
+ + '\n'
+ + _ ("Stopping at last successful rule"))
return (last_conversion, str)
self.version = version
def do_one_file (infile_name):
- ly.stderr_write (_ ("Processing `%s\'... ") % infile_name)
- sys.stderr.write ('\n')
+ ly.progress (_ ("Processing `%s\'... ") % infile_name, True)
if infile_name:
infile = open (infile_name, 'r')
'\\' + newversion, result)
elif not global_options.skip_version_add:
result = newversion + '\n' + result
-
- error_file_write ('\n')
+
+ ly.progress ('\n')
if global_options.edit:
try:
show_rules (sys.stdout, global_options.from_version, global_options.to_version)
sys.exit (0)
- identify (sys.stderr)
+ identify ()
for f in files:
if f == '-':
f = ''
elif not os.path.isfile (f):
- error (_ ("%s: Unable to open file") % f)
+ ly.error (_ ("%s: Unable to open file") % f)
if len (files) == 1:
sys.exit (1)
continue
try:
do_one_file (f)
except UnknownVersion:
- error (_ ("%s: Unable to determine version. Skipping") % f)
+ ly.error (_ ("%s: Unable to determine version. Skipping") % f)
except InvalidVersion:
# Compat code for 2.x and 3.0 syntax ("except .. as v" doesn't
# work in python 2.4!):
t, v, b = sys.exc_info ()
- error (_ ("%s: Invalid version string `%s' \n"
- "Valid version strings consist of three numbers, "
- "separated by dots, e.g. `2.8.12'") % (f, v.version) )
+ ly.error (_ ("%s: Invalid version string `%s' \n"
+ "Valid version strings consist of three numbers, "
+ "separated by dots, e.g. `2.8.12'") % (f, v.version) )
- sys.stderr.write ('\n')
+ ly.progress ('\n')
main ()
################################################################
def exit (i):
- if global_options.verbose:
+ if ly.is_verbose ():
raise Exception (_ ('Exiting (%d)...') % i)
else:
sys.exit (i)
_ ("Distributed under terms of the GNU General Public License."),
_ ("It comes with NO WARRANTY.")))
+
def get_option_parser ():
p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'lilypond-book',
description=help_summary,
type="float",
default=3.0)
+ p.add_option ('--lily-loglevel',
+ help=_ ("Print lilypond log messages according to LOGLEVEL"),
+ metavar=_ ("LOGLEVEL"),
+ action='store', dest='lily_loglevel',
+ default=os.environ.get ("LILYPOND_LOGLEVEL", None))
+
p.add_option ('--lily-output-dir',
help=_ ("write lily-XXX files to DIR, link into --output dir"),
metavar=_ ("DIR"),
action='append', dest='custom_packages',
default=[])
+ p.add_option ("-l", "--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 ("-o", '--output', help=_ ("write output to DIR"),
metavar=_ ("DIR"),
action='store', dest='output_dir',
default=False)
p.add_option ('-V', '--verbose', help=_ ("be verbose"),
- action="store_true",
- default=False,
- dest="verbose")
+ action="callback",
+ callback=ly.handle_loglevel_option,
+ callback_args=("DEBUG",))
p.version = "@TOPLEVEL_VERSION@"
p.add_option("--version",
current = os.getcwd()
os.chdir (directory)
ly.system(cmd,
- be_verbose=global_options.verbose,
+ be_verbose=ly.is_verbose (),
redirect_output=global_options.redirect_output,
log_file=logfile,
progress_p=1)
def main ():
# FIXME: 85 lines of `main' macramee??
+ if (os.environ.has_key ("LILYPOND_BOOK_LOGLEVEL")):
+ ly.set_loglevel (os.environ["LILYPOND_BOOK_LOGLEVEL"])
files = do_options ()
basename = os.path.splitext (files[0])[0]
global_options.formatter.process_options (global_options)
- if global_options.verbose:
- global_options.process_cmd += " --verbose "
+ if global_options.lily_loglevel:
+ ly.debug_output (_ ("Setting LilyPond's loglevel to %s") % global_options.lily_loglevel, True)
+ global_options.process_cmd += " --loglevel=%s" % global_options.lily_loglevel
+ elif ly.is_verbose ():
+ if os.environ.get ("LILYPOND_LOGLEVEL", None):
+ ly.debug_output (_ ("Setting LilyPond's loglevel to %s (from environment variable LILYPOND_LOGLEVEL)") % os.environ.get ("LILYPOND_LOGLEVEL", None), True)
+ global_options.process_cmd += " --loglevel=%s" % os.environ.get ("LILYPOND_LOGLEVEL", None)
+ else:
+ ly.debug_output (_ ("Setting LilyPond's output to --verbose, implied by lilypond-book's setting"), True)
+ global_options.process_cmd += " --verbose"
if global_options.padding_mm:
global_options.process_cmd += " -deps-box-padding=%f " % global_options.padding_mm
# 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 = {
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
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):
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
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()
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()
self.direction = 0
self.event = None
def print_ly (self, printer):
- ly.stderr_write (_ ("Encountered unprocessed marker %s\n") % self)
+ ly.warning (_ ("Encountered unprocessed marker %s\n") % self)
pass
def ly_expression (self):
return ""
if func:
ev = func()
else:
- error_message (_ ('unknown span event %s') % mxl_event)
+ ly.warning (_ ('unknown span event %s') % mxl_event)
type = mxl_event.get_type ()
if span_direction != None:
ev.span_direction = span_direction
else:
- error_message (_ ('unknown span type %s for %s') % (type, name))
+ ly.warning (_ ('unknown span type %s for %s') % (type, name))
ev.set_span_type (type)
ev.line_type = getattr (mxl_event, 'line-type', 'solid')
except ValueError:
pass
else:
- error_message (_ ("Unknown metronome mark, ignoring"))
+ ly.warning (_ ("Unknown metronome mark, ignoring"))
return
return ev
else:
#TODO: Implement the other (more complex) way for tempo marks!
- error_message (_ ("Metronome marks with complex relations (<metronome-note> in MusicXML) are not yet implemented."))
+ ly.warning (_ ("Metronome marks with complex relations (<metronome-note> in MusicXML) are not yet implemented."))
return
# translate directions into Events, possible values:
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):
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):
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 ()
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)
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',
action = "store",
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",
default = True,
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,
raw_string = None
if compressed:
if filename == "-":
- progress (_ ("Input is compressed, extracting raw MusicXML data from 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.
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:
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)
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:
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()