def get_time_signature (self): "Return time sig as a (beat, beat-type) tuple. For compound signatures," "return either (beat, beat,..., beat-type) or ((beat,..., type), " "(beat,..., type), ...)." if self._time_signature_cache: return self._time_signature_cache try: mxl = self.get_named_attribute ('time') if not mxl: return None if mxl.get_maybe_exist_named_child ('senza-misura'): # TODO: Handle pieces without a time signature! ly.warning (_ ("Senza-misura time signatures are not yet supported!")) return (4, 4) else: signature = [] current_sig = [] for i in mxl.get_all_children (): if isinstance (i, Beats): beats = string.split (i.get_text ().strip (), "+") current_sig = [int (j) for j in beats] elif isinstance (i, BeatType): current_sig.append (int (i.get_text ())) signature.append (current_sig) current_sig = [] if isinstance (signature[0], list) and len (signature) == 1: signature = signature[0] self._time_signature_cache = signature return signature except (KeyError, ValueError): self.message (_ ("Unable to interpret time signature! Falling back to 4/4.")) return (4, 4)
def message (self, msg): ly.warning (msg) p = self while p: ly.progress (' In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()]))) p = p.get_parent ()
def main(): files = do_options() # should parse files[] to read \version? if global_options.show_rules: show_rules(sys.stdout, global_options.from_version, global_options.to_version) sys.exit(0) identify() errors = 0 for f in files: if f == '-': f = '' elif not os.path.isfile(f): ly.error(_("%s: Unable to open file") % f) errors += 1 continue try: errors += do_one_file(f) except UnknownVersion: ly.error(_("%s: Unable to determine version. Skipping") % f) errors += 1 except InvalidVersion as v: 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)) errors += 1 if errors: ly.warning(gettext.ngettext("There was %d error.", "There were %d errors.", errors) % errors) sys.exit(1)
def message(self, msg): ly.warning(msg) p = self while p: ly.progress(' In: <%s %s>\n' % (p._name, ' '.join( ['%s=%s' % item for item in p._attribute_dict.items()]))) p = p.get_parent()
def get_instrument(self, id): if not self._id_instrument_name_dict: self.generate_id_instrument_dict() instrument_name = self._id_instrument_name_dict.get(id) if instrument_name: return instrument_name else: ly.warning(_("Unable to find instrument for ID=%s\n") % id) return "Grand Piano"
def get_instrument (self, id): if not self._id_instrument_name_dict: self.generate_id_instrument_dict() instrument_name = self._id_instrument_name_dict.get (id) if instrument_name: return instrument_name else: ly.warning (_ ("Unable to find instrument for ID=%s\n") % id) return "Grand Piano"
def rational_to_lily_duration(rational_len): d = musicexp.Duration() rational_len.normalize_self() 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 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.duration_log = d_log - dots d.dots = dots elif (d_log >= 0): d.duration_log = d_log d.factor = Rational(rational_len.numerator()) else: ly.warning( _("Encountered rational duration with denominator %s, " "unable to convert to lilypond duration") % rational_len.denominator()) # TODO: Test the above error message return None return d
def write_ly(self): base = self.basename() path = os.path.join(self.global_options.lily_output_dir, base) directory = os.path.split(path)[0] os.makedirs(directory, exist_ok=True) filename = path + '.ly' if os.path.exists(filename): existing = open(filename, 'r', encoding='utf-8').read() if self.relevant_contents(existing) != self.relevant_contents(self.full_ly()): ly.warning("%s: duplicate filename but different contents of original file,\n\ printing diff against existing file." % filename) encoded = self.full_ly().encode('utf-8') cmd = 'diff -u %s -' % filename sys.stderr.write(self.filter_pipe( encoded, cmd).decode('utf-8')) else: out = open(filename, 'w', encoding='utf-8') out.write(self.full_ly())
def main(): files = do_options() # should parse files[] to read \version? if global_options.show_rules: show_rules(sys.stdout, global_options.from_version, global_options.to_version) sys.exit(0) identify() errors = 0 for f in files: f = f.decode(sys.stdin.encoding or "utf-8") if f == "-": f = "" elif not os.path.isfile(f): ly.error(_(u"%s: Unable to open file") % f) errors += 1 continue try: errors += do_one_file(f) except UnknownVersion: ly.error(_(u"%s: Unable to determine version. Skipping") % f) errors += 1 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() ly.error( _( u"%s: Invalid version string `%s' \n" "Valid version strings consist of three numbers, " "separated by dots, e.g. `2.8.12'" ) % (f, v.version) ) errors += 1 if errors: ly.warning(ly.ungettext("There was %d error.", "There were %d errors.", errors) % errors) sys.exit(1)
def main(): files = do_options() # should parse files[] to read \version? if global_options.show_rules: show_rules(sys.stdout, global_options.from_version, global_options.to_version) sys.exit(0) identify() errors = 0 for f in files: f = f.decode(sys.stdin.encoding or "utf-8") if f == '-': f = '' elif not os.path.isfile(f): ly.error(_(u"%s: Unable to open file") % f) errors += 1 continue try: errors += do_one_file(f) except UnknownVersion: ly.error(_(u"%s: Unable to determine version. Skipping") % f) errors += 1 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() ly.error( _(u"%s: Invalid version string `%s' \n" "Valid version strings consist of three numbers, " "separated by dots, e.g. `2.8.12'") % (f, v.version)) errors += 1 if errors: ly.warning( ly.ungettext("There was %d error.", "There were %d errors.", errors) % errors) sys.exit(1)
def write_ly(self): base = self.basename() path = os.path.join(self.global_options.lily_output_dir, base) directory = os.path.split(path)[0] os.makedirs(directory, exist_ok=True) # First write the XML to a file (so we can link it!) if self.compressed: xmlfilename = path + '.mxl' else: xmlfilename = path + '.xml' if os.path.exists(xmlfilename): diff_against_existing = self.filter_pipe( self.get_contents(), 'diff -u %s - ' % xmlfilename) if diff_against_existing: ly.warning(_("%s: duplicate filename but different contents of original file,\n\ printing diff against existing file.") % xmlfilename) sys.stderr.write(diff_against_existing.decode('utf-8')) else: out = open(xmlfilename, 'wb') out.write(self.get_contents()) out.close() # also write the converted lilypond filename = path + '.ly' if os.path.exists(filename): encoded = self.full_ly().encode('utf-8') cmd = 'diff -u %s -' % filename diff_against_existing = self.filter_pipe( encoded, cmd).decode('utf-8') if diff_against_existing: ly.warning(_("%s: duplicate filename but different contents of converted lilypond file,\n\ printing diff against existing file.") % filename) sys.stderr.write(diff_against_existing.decode('utf-8')) else: out = open(filename, 'w', encoding='utf-8') out.write(self.full_ly()) out.close()
def get_time_signature(self): "Return time sig as a (beat, beat-type) tuple. For compound signatures," "return either (beat, beat,..., beat-type) or ((beat,..., type), " "(beat,..., type), ...)." if self._time_signature_cache: return self._time_signature_cache try: mxl = self.get_named_attribute('time') if not mxl: return None if mxl.get_maybe_exist_named_child('senza-misura'): # TODO: Handle pieces without a time signature! ly.warning( _("Senza-misura time signatures are not yet supported!")) return (4, 4) else: signature = [] current_sig = [] for i in mxl.get_all_children(): if isinstance(i, Beats): beats = string.split(i.get_text().strip(), "+") current_sig = [int(j) for j in beats] elif isinstance(i, BeatType): current_sig.append(int(i.get_text())) signature.append(current_sig) current_sig = [] if isinstance(signature[0], list) and len(signature) == 1: signature = signature[0] self._time_signature_cache = signature return signature except (KeyError, ValueError): self.message( _("Unable to interpret time signature! Falling back to 4/4.")) return (4, 4)
def parse_snippet_options(self, option_string, type): self.snippet_option_dict = {} # Split option string and create raw option_dict from it options = self.split_options(option_string) for option in options: (key, value) = (option, None) if '=' in option: (key, value) = re.split(r'\s*=\s*', option) else: # a no... option removes a previous option if present! if key in no_options: if no_options[key] in self.option_dict: del self.snippet_option_dict[no_options[key]] key = None # Check for deprecated options, replace them by new ones (c_key, c_value) = classic_lilypond_book_compatibility(key, value) if c_key: if c_value: ly.warning( _("deprecated ly-option used: %s=%s") % (key, value)) ly.warning( _("compatibility mode translation: %s=%s") % (c_key, c_value)) else: ly.warning( _("deprecated ly-option used: %s") % key) ly.warning( _("compatibility mode translation: %s") % c_key) (key, value) = (c_key, c_value) # Finally, insert the option: if key: self.snippet_option_dict[key] = value # If LINE_WIDTH is used without parameter, set it to default. has_line_width = LINE_WIDTH in self.snippet_option_dict if has_line_width and self.snippet_option_dict[LINE_WIDTH] is None: del self.snippet_option_dict[LINE_WIDTH] # RELATIVE does not work without FRAGMENT, so imply that if RELATIVE in self.snippet_option_dict: self.snippet_option_dict[FRAGMENT] = None # Now get the default options from the formatter object (HTML, latex, # texinfo, etc.) and insert the explicit snippet options to get the # list of all options for this snippet # first, make sure we have an INDENT value as a fallback self.option_dict = {INDENT: '0\\mm'} self.option_dict.update(self.formatter.default_snippet_options) self.option_dict.update(self.snippet_option_dict) # also construct a list of all options (as strings) that influence the # visual appearance of the snippet lst = [x_y for x_y in iter(self.option_dict.items()) if x_y[0] not in PROCESSING_INDEPENDENT_OPTIONS] option_list = [] for (key, value) in lst: if value is None: option_list.append(key) else: option_list.append(key + "=" + value) option_list.sort() self.outputrelevant_option_list = option_list
def get_latex_textwidth(source, global_options): # default value textwidth = 550.0 m = re.search(r'''(?P<preamble>\\begin\s*{document})''', source) if m is None: ly.warning(_("cannot find \\begin{document} in LaTeX document")) return textwidth preamble = source[:m.start(0)] latex_document = LATEX_INSPECTION_DOCUMENT % {'preamble': preamble} (handle, tmpfile) = tempfile.mkstemp('.tex') tmpfileroot = os.path.splitext(tmpfile)[0] tmpfileroot = os.path.split(tmpfileroot)[1] auxfile = tmpfileroot + '.aux' logfile = tmpfileroot + '.log' tmp_handle = os.fdopen(handle, 'w') tmp_handle.write(latex_document) tmp_handle.close() ly.progress( _("Running `%s' on file `%s' to detect default page settings.\n") % (global_options.latex_program, tmpfile)) cmd = '%s %s' % (global_options.latex_program, tmpfile) ly.debug_output("Executing: %s\n" % cmd) run_env = os.environ.copy() run_env['LC_ALL'] = 'C' run_env['TEXINPUTS'] = os.path.pathsep.join( (global_options.input_dir, run_env.get('TEXINPUTS', ''))) # unknown why this is necessary universal_newlines = True if sys.platform == 'mingw32': universal_newlines = False # use os.system to avoid weird sleep() problems on # GUB's python 2.4.2 on mingw # make file to write to output_dir = tempfile.mkdtemp() output_filename = os.path.join(output_dir, 'output.txt') # call command cmd += " > %s" % output_filename oldtexinputs = os.environ.get('TEXINPUTS') os.environ['TEXINPUTS'] = run_env['TEXINPUTS'] returncode = os.system(cmd) if oldtexinputs: os.environ['TEXINPUTS'] = oldtexinputs else: del os.environ['TEXINPUTS'] parameter_string = open(output_filename, encoding="utf8").read() if returncode != 0: ly.warning(_("Unable to auto-detect default settings:\n")) # clean up os.remove(output_filename) os.rmdir(output_dir) else: proc = subprocess.Popen(cmd, env=run_env, universal_newlines=universal_newlines, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (parameter_string, error_string) = proc.communicate() if proc.returncode != 0: ly.warning( _("Unable to auto-detect default settings:\n%s") % error_string) os.unlink(tmpfile) if os.path.exists(auxfile): os.unlink(auxfile) if os.path.exists(logfile): parameter_string = open(logfile, encoding="utf8").read() os.unlink(logfile) columns = 0 m = re.search('columns=([0-9.]+)', parameter_string) if m: columns = int(m.group(1)) columnsep = 0 m = re.search('columnsep=([0-9.]+)pt', parameter_string) if m: columnsep = float(m.group(1)) m = re.search('textwidth=([0-9.]+)pt', parameter_string) if m: textwidth = float(m.group(1)) else: ly.warning(_("cannot detect textwidth from LaTeX")) return textwidth ly.debug_output('Detected values:') ly.debug_output(' columns = %s' % columns) ly.debug_output(' columnsep = %s' % columnsep) ly.debug_output(' textwidth = %s' % textwidth) if m and columns: textwidth = (textwidth - columnsep) / columns ly.debug_output('Adjusted value:') ly.debug_output(' textwidth = %s' % textwidth) return textwidth
def dump_track(track, n): s = '\n' track_name = get_track_name(n) average_pitch = track_average_pitch(track) voices = len([x for x in average_pitch[1:] if x]) clef = get_best_clef(average_pitch[0]) c = 0 vv = 0 for channel in track: v = 0 channel_name = get_channel_name(c) c += 1 for voice in channel: voice_name = get_voice_name(v) voice_id = track_name + channel_name + voice_name item = voice_first_item(voice) if item and item.__class__ == Note: skip = 'r' if global_options.skip: skip = 's' s += '%(voice_id)s = ' % locals() if not global_options.absolute_pitches: s += '\\relative c ' elif item and item.__class__ == Text: skip = '" "' s += '%(voice_id)s = \\lyricmode ' % locals() else: skip = '\\skip ' s += '%(voice_id)s = ' % locals() s += '{\n' if not n and not vv and global_options.key: s += global_options.key.dump() if average_pitch[vv+1] and voices > 1: vl = get_voice_layout(average_pitch[1:])[vv] if vl: s += ' \\voice' + vl + '\n' else: if not global_options.quiet: ly.warning( _('found more than 5 voices on a staff, expect bad output')) s += ' ' + dump_voice(voice, skip) s += '}\n\n' v += 1 vv += 1 s += '%(track_name)s = <<\n' % locals() if clef.type != 2: s += clef.dump() + '\n' c = 0 vv = 0 for channel in track: v = 0 channel_name = get_channel_name(c) c += 1 for voice in channel: voice_context_name = get_voice_name(vv, zero_too_p=True) voice_name = get_voice_name(v) v += 1 vv += 1 voice_id = track_name + channel_name + voice_name item = voice_first_item(voice) context = 'Voice' if item and item.__class__ == Text: context = 'Lyrics' s += ' \\context %(context)s = %(voice_context_name)s \\%(voice_id)s\n' % locals() s += '>>\n\n' return s
def compose_ly(self, code): # Defaults. relative = 1 override = {} # The original concept of the `exampleindent' option is broken. # It is not possible to get a sane value for @exampleindent at all # without processing the document itself. Saying # # @exampleindent 0 # @example # ... # @end example # @exampleindent 5 # # causes ugly results with the TeX backend of texinfo since the # default value for @exampleindent isn't 5em but 0.4in (or a smaller # value). Executing the above code changes the environment # indentation to an unknown value because we don't know the amount # of 1em in advance since it is font-dependent. Modifying # @exampleindent in the middle of a document is simply not # supported within texinfo. # # As a consequence, the only function of @exampleindent is now to # specify the amount of indentation for the `quote' option. # # To set @exampleindent locally to zero, we use the @format # environment for non-quoted snippets. # # Update: since July 2011 we are running texinfo on a test file # to detect the default exampleindent, so we might reintroduce # further usage of exampleindent again. # # First, make sure we have some falback default value, auto-detected # values and explicitly specified values will always override them: override[EXAMPLEINDENT] = r'0.4\in' override[LINE_WIDTH] = '5\\in' override.update(self.formatter.default_snippet_options) override['padding_mm'] = self.global_options.padding_mm option_string = ','.join(self.get_outputrelevant_option_strings()) compose_dict = {} compose_types = [NOTES, PREAMBLE, LAYOUT, PAPER] for a in compose_types: compose_dict[a] = [] option_names = sorted(self.option_dict.keys()) for key in option_names: value = self.option_dict[key] if value: override[key] = value else: if key not in override: override[key] = None found = 0 for typ in compose_types: if key in snippet_options[typ]: compose_dict[typ].append(snippet_options[typ][key]) found = 1 break if not found and key not in simple_options and key not in self.snippet_options(): ly.warning(_("ignoring unknown ly option: %s") % key) # URGS if RELATIVE in override and override[RELATIVE]: relative = int(override[RELATIVE]) relative_quotes = '' # 1 = central C if relative < 0: relative_quotes += ',' * (- relative) elif relative > 0: relative_quotes += "'" * relative if INLINE in override: # For inline images, try to make left and right padding equal, # ignoring the `--left-padding` value. # # URGH Value 0 makes LilyPond apply no left padding at all, but # still having some right padding. This is a bug (#6116). override['padding_mm'] = 0.0001 # put paper-size first, if it exists for i, elem in enumerate(compose_dict[PAPER]): if elem.startswith("#(set-paper-size"): compose_dict[PAPER].insert(0, compose_dict[PAPER].pop(i)) break paper_string = '\n '.join(compose_dict[PAPER]) % override layout_string = '\n '.join(compose_dict[LAYOUT]) % override notes_string = '\n '.join(compose_dict[NOTES]) % vars() preamble_string = '\n '.join(compose_dict[PREAMBLE]) % override padding_mm = override['padding_mm'] if padding_mm != 0: padding_mm_string = \ "#(ly:set-option 'eps-box-padding %f)" % padding_mm else: padding_mm_string = "" if self.global_options.safe_mode: safe_mode_string = "#(ly:set-option 'safe #t)" else: safe_mode_string = "" d = globals().copy() d.update(locals()) d.update(self.global_options.information) if FRAGMENT in self.option_dict: body = FRAGMENT_LY else: body = FULL_LY return (PREAMBLE_LY + body) % d
def print_ly(self, printer): ly.warning(_("Encountered unprocessed marker %s\n") % self) pass
def get_texinfo_width_indent(source, global_options): #TODO: Check for end of header command "@c %**end of header" # only use material before that comment ? # extract all relevant papter settings from the input: pagesize = None texinfo_paper_size_regexp = r'''(@(?:afourpaper|afourwide|afourlatex|afivepaper|smallbook|letterpaper))''' m = re.search(texinfo_paper_size_regexp, source) if m: pagesize = m.group(1) relevant_settings_regexp = r'''(@(?:fonttextsize|pagesizes|cropmarks|exampleindent).*)\n''' m = re.findall(relevant_settings_regexp, source) if pagesize: m.insert(0, pagesize) # all relevant options to insert into the test document: preamble = "\n".join(m) texinfo_document = TEXINFO_INSPECTION_DOCUMENT % {'preamble': preamble} (handle, tmpfile) = tempfile.mkstemp('.texi') outfile = os.path.splitext(tmpfile)[0] + '.pdf' tmp_handle = os.fdopen(handle, 'w') tmp_handle.write(texinfo_document) tmp_handle.close() # Work around a texi2pdf bug: if LANG=C is not given, a broken regexp is # used to detect relative/absolute paths, so the absolute path is not # detected as such and this command fails: ly.progress( _("Running texi2pdf on file %s to detect default page settings.\n") % tmpfile) # execute the command and pipe stdout to the parameter_string: cmd = '%s --batch -c -o %s %s' % (global_options.texinfo_program, outfile, tmpfile) ly.debug_output("Executing: %s\n" % cmd) run_env = os.environ.copy() run_env['LC_ALL'] = 'C' ### unknown why this is necessary universal_newlines = True if sys.platform == 'mingw32': universal_newlines = False ### use os.system to avoid weird sleep() problems on ### GUB's python 2.4.2 on mingw # make file to write to output_dir = tempfile.mkdtemp() output_filename = os.path.join(output_dir, 'output.txt') # call command cmd += " > %s" % output_filename returncode = os.system(cmd) parameter_string = open(output_filename).read() if returncode != 0: ly.warning(_("Unable to auto-detect default settings:\n")) # clean up os.remove(output_filename) os.rmdir(output_dir) else: proc = subprocess.Popen(cmd, env=run_env, universal_newlines=universal_newlines, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (parameter_string, error_string) = proc.communicate() if proc.returncode != 0: ly.warning( _("Unable to auto-detect default settings:\n%s") % error_string) os.unlink(tmpfile) if os.path.exists(outfile): os.unlink(outfile) # Find textwidth and exampleindent and format it as \\mm or \\in # Use defaults if they cannot be extracted textwidth = 0 m = re.search('textwidth=([0-9.]+)pt', parameter_string) if m: val = float(m.group(1)) / 72.27 if pagesize and pagesize.startswith("@afour"): textwidth = "%g\\mm" % round(val * 25.4, 3) else: textwidth = "%g\\in" % round(val, 3) else: textwidth = texinfo_line_widths.get(pagesize, "6\\in") exampleindent = 0 m = re.search('exampleindent=([0-9.]+)pt', parameter_string) if m: val = float(m.group(1)) / 72.27 if pagesize and pagesize.startswith("@afour"): exampleindent = "%g\\mm" % round(val * 25.4, 3) else: exampleindent = "%g\\in" % round(val, 3) else: exampleindent = "0.4\\in" retval = { book_snippets.LINE_WIDTH: textwidth, book_snippets.EXAMPLEINDENT: exampleindent } ly.debug_output("Auto-detected values are: %s\n" % retval) return retval