From 3761f50a69bd34d6ff6da9c6a18d25c006d44362 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Mon, 1 May 2006 00:00:24 +0000 Subject: [PATCH] (dump_score): indent of 4 for python code. --- ChangeLog | 2 + python/musicexp.py | 1258 +++++++++--------- scripts/abc2ly.py | 2088 ++++++++++++++--------------- scripts/etf2ly.py | 2104 ++++++++++++++--------------- scripts/lilypond-book.py | 2718 +++++++++++++++++++------------------- scripts/midi2ly.py | 1670 +++++++++++------------ scripts/musicxml2ly.py | 824 ++++++------ 7 files changed, 5333 insertions(+), 5331 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5ab363e981..4bb107f705 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2006-05-01 Han-Wen Nienhuys + * scripts/abc2ly.py (dump_score): indent of 4 for python code. + * configure.in (LINK_GXX_STATICALLY): remove locate() call. 2006-04-30 Han-Wen Nienhuys diff --git a/python/musicexp.py b/python/musicexp.py index 5698c9f699..2f54f36b7b 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -6,683 +6,683 @@ import re from rational import Rational class Output_stack_element: - def __init__ (self): - self.factor = Rational (1) - def copy (self): - o = Output_stack_element() - o.factor = self.factor - return o + def __init__ (self): + self.factor = Rational (1) + def copy (self): + o = Output_stack_element() + o.factor = self.factor + return o class Output_printer: - """A class that takes care of formatting (eg.: indenting) a - Music expression as a .ly file. - - """ - ## TODO: support for \relative. - - def __init__ (self): - self._line = '' - self._indent = 4 - self._nesting = 0 - self._file = sys.stdout - self._line_len = 72 - self._output_state_stack = [Output_stack_element()] - self._skipspace = False - self._last_duration = None - - def set_file (self, file): - self._file = file - - def dump_version (self): - self.newline () - self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"') - self.newline () - - def get_indent (self): - return self._nesting * self._indent - - def override (self): - last = self._output_state_stack[-1] - self._output_state_stack.append (last.copy()) - - def add_factor (self, factor): - self.override() - self._output_state_stack[-1].factor *= factor - - def revert (self): - del self._output_state_stack[-1] - if not self._output_state_stack: - raise 'empty' - - def duration_factor (self): - return self._output_state_stack[-1].factor - - def print_verbatim (self, str): - self._line += str - - def unformatted_output (self, str): - self._nesting += str.count ('<') + str.count ('{') - self._nesting -= str.count ('>') + str.count ('}') - self.print_verbatim (str) - - def print_duration_string (self, str): - if self._last_duration == str: - return - - self.unformatted_output (str) - - def add_word (self, str): - if (len (str) + 1 + len (self._line) > self._line_len): - self.newline() - self._skipspace = True - - if not self._skipspace: - self._line += ' ' - self.unformatted_output (str) - self._skipspace = False - - def newline (self): - self._file.write (self._line + '\n') - self._line = ' ' * self._indent * self._nesting - self._skipspace = True - - def skipspace (self): - self._skipspace = True - - def __call__(self, arg): - self.dump (arg) - - def dump (self, str): - - if self._skipspace: - self._skipspace = False - self.unformatted_output (str) - else: - words = string.split (str) - for w in words: - self.add_word (w) + """A class that takes care of formatting (eg.: indenting) a + Music expression as a .ly file. + + """ + ## TODO: support for \relative. + + def __init__ (self): + self._line = '' + self._indent = 4 + self._nesting = 0 + self._file = sys.stdout + self._line_len = 72 + self._output_state_stack = [Output_stack_element()] + self._skipspace = False + self._last_duration = None + + def set_file (self, file): + self._file = file + + def dump_version (self): + self.newline () + self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"') + self.newline () + + def get_indent (self): + return self._nesting * self._indent + + def override (self): + last = self._output_state_stack[-1] + self._output_state_stack.append (last.copy()) + + def add_factor (self, factor): + self.override() + self._output_state_stack[-1].factor *= factor + + def revert (self): + del self._output_state_stack[-1] + if not self._output_state_stack: + raise 'empty' + + def duration_factor (self): + return self._output_state_stack[-1].factor + + def print_verbatim (self, str): + self._line += str + + def unformatted_output (self, str): + self._nesting += str.count ('<') + str.count ('{') + self._nesting -= str.count ('>') + str.count ('}') + self.print_verbatim (str) + + def print_duration_string (self, str): + if self._last_duration == str: + return + + self.unformatted_output (str) + + def add_word (self, str): + if (len (str) + 1 + len (self._line) > self._line_len): + self.newline() + self._skipspace = True + + if not self._skipspace: + self._line += ' ' + self.unformatted_output (str) + self._skipspace = False + + def newline (self): + self._file.write (self._line + '\n') + self._line = ' ' * self._indent * self._nesting + self._skipspace = True + + def skipspace (self): + self._skipspace = True + + def __call__(self, arg): + self.dump (arg) + + def dump (self, str): + + if self._skipspace: + self._skipspace = False + self.unformatted_output (str) + else: + words = string.split (str) + for w in words: + self.add_word (w) class Duration: - def __init__ (self): - self.duration_log = 0 - self.dots = 0 - self.factor = Rational (1) - - def lisp_expression (self): - return '(ly:make-duration %d %d %d %d)' % (self.duration_log, - self.dots, - self.factor.numerator (), - self.factor.denominator ()) - - - def ly_expression (self, factor = None): - if not factor: - factor = self.factor - - str = '%d%s' % (1 << self.duration_log, '.'*self.dots) - - if factor <> Rational (1,1): - str += '*%d/%d' % (factor.numerator (), factor.denominator ()) - - return str - - def print_ly (self, outputter): - str = self.ly_expression (self.factor / outputter.duration_factor ()) - outputter.print_duration_string (str) - - def __repr__(self): - return self.ly_expression() - - def copy (self): - d = Duration () - d.dots = self.dots - d.duration_log = self.duration_log - d.factor = self.factor - return d - - def get_length (self): - dot_fact = Rational( (1 << (1 + self.dots))-1, - 1 << self.dots) - - log = abs (self.duration_log) - dur = 1 << log - if self.duration_log < 0: - base = Rational (dur) - else: - base = Rational (1, dur) - - return base * dot_fact * self.factor - - + def __init__ (self): + self.duration_log = 0 + self.dots = 0 + self.factor = Rational (1) + + def lisp_expression (self): + return '(ly:make-duration %d %d %d %d)' % (self.duration_log, + self.dots, + self.factor.numerator (), + self.factor.denominator ()) + + + def ly_expression (self, factor = None): + if not factor: + factor = self.factor + + str = '%d%s' % (1 << self.duration_log, '.'*self.dots) + + if factor <> Rational (1,1): + str += '*%d/%d' % (factor.numerator (), factor.denominator ()) + + return str + + def print_ly (self, outputter): + str = self.ly_expression (self.factor / outputter.duration_factor ()) + outputter.print_duration_string (str) + + def __repr__(self): + return self.ly_expression() + + def copy (self): + d = Duration () + d.dots = self.dots + d.duration_log = self.duration_log + d.factor = self.factor + return d + + def get_length (self): + dot_fact = Rational( (1 << (1 + self.dots))-1, + 1 << self.dots) + + log = abs (self.duration_log) + dur = 1 << log + if self.duration_log < 0: + base = Rational (dur) + else: + base = Rational (1, dur) + + return base * dot_fact * self.factor + + class Pitch: - def __init__ (self): - self.alteration = 0 - self.step = 0 - self.octave = 0 - - def __repr__(self): - return self.ly_expression() - - def transposed (self, interval): - c = self.copy () - c.alteration += interval.alteration - c.step += interval.step - c.octave += interval.octave - c.normalize () - - target_st = self.semitones() + interval.semitones() - c.alteration += target_st - c.semitones() - return c - - def normalize (c): - while c.step < 0: - c.step += 7 - c.octave -= 1 - c.octave += c.step / 7 - c.step = c.step % 7 - - - def lisp_expression (self): - return '(ly:make-pitch %d %d %d)' % (self.octave, - self.step, - self.alteration) - - def copy (self): - p = Pitch () - p.alteration = self.alteration - p.step = self.step - p.octave = self.octave - return p - - def steps (self): - return self.step + self.octave *7 - - def semitones (self): - 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') - - def ly_expression (self): - str = self.ly_step_expression () - if self.octave >= 0: - str += "'" * (self.octave + 1) - elif self.octave < -1: - str += "," * (-self.octave - 1) - - return str - def print_ly (self, outputter): - outputter (self.ly_expression()) - + def __init__ (self): + self.alteration = 0 + self.step = 0 + self.octave = 0 + + def __repr__(self): + return self.ly_expression() + + def transposed (self, interval): + c = self.copy () + c.alteration += interval.alteration + c.step += interval.step + c.octave += interval.octave + c.normalize () + + target_st = self.semitones() + interval.semitones() + c.alteration += target_st - c.semitones() + return c + + def normalize (c): + while c.step < 0: + c.step += 7 + c.octave -= 1 + c.octave += c.step / 7 + c.step = c.step % 7 + + + def lisp_expression (self): + return '(ly:make-pitch %d %d %d)' % (self.octave, + self.step, + self.alteration) + + def copy (self): + p = Pitch () + p.alteration = self.alteration + p.step = self.step + p.octave = self.octave + return p + + def steps (self): + return self.step + self.octave *7 + + def semitones (self): + 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') + + def ly_expression (self): + str = self.ly_step_expression () + if self.octave >= 0: + str += "'" * (self.octave + 1) + elif self.octave < -1: + str += "," * (-self.octave - 1) + + return str + def print_ly (self, outputter): + outputter (self.ly_expression()) + class Music: - def __init__ (self): - self.parent = None - self.start = Rational (0) - self.comment = '' - self.identifier = None - - def get_length(self): - return Rational (0) - - def get_properties (self): - return '' - - def has_children (self): - return False - - def get_index (self): - if self.parent: - return self.parent.elements.index (self) - else: - return None - def name (self): - return self.__class__.__name__ - - def lisp_expression (self): - name = self.name() - - props = self.get_properties () -# props += 'start %f ' % self.start - - return "(make-music '%s %s)" % (name, props) - - def set_start (self, start): - self.start = start - - def find_first (self, predicate): - if predicate (self): - return self - return None - - def print_comment (self, printer, text = None): - if not text: - text = self.comment - - if not text: - return - - - if text == '\n': - printer.newline () - return - lines = string.split (text, '\n') - for l in lines: - if l: - printer.dump ('% ' + l) - printer.newline () - - - def print_with_identifier (self, printer): - if self.identifier: - printer ("\\%s" % self.identifier) - else: - self.print_ly (printer) - - def print_ly (self, printer): - printer (self.ly_expression ()) + def __init__ (self): + self.parent = None + self.start = Rational (0) + self.comment = '' + self.identifier = None + + def get_length(self): + return Rational (0) + + def get_properties (self): + return '' + + def has_children (self): + return False + + def get_index (self): + if self.parent: + return self.parent.elements.index (self) + else: + return None + def name (self): + return self.__class__.__name__ + + def lisp_expression (self): + name = self.name() + + props = self.get_properties () +# props += 'start %f ' % self.start + + return "(make-music '%s %s)" % (name, props) + + def set_start (self, start): + self.start = start + + def find_first (self, predicate): + if predicate (self): + return self + return None + + def print_comment (self, printer, text = None): + if not text: + text = self.comment + + if not text: + return + + + if text == '\n': + printer.newline () + return + lines = string.split (text, '\n') + for l in lines: + if l: + printer.dump ('% ' + l) + printer.newline () + + + def print_with_identifier (self, printer): + if self.identifier: + printer ("\\%s" % self.identifier) + else: + self.print_ly (printer) + + def print_ly (self, printer): + printer (self.ly_expression ()) class MusicWrapper (Music): - def __init__ (self): - Music.__init__(self) - self.element = None - def print_ly (self, func): - self.element.print_ly (func) + def __init__ (self): + Music.__init__(self) + self.element = None + def print_ly (self, func): + self.element.print_ly (func) class TimeScaledMusic (MusicWrapper): - def print_ly (self, func): - func ('\\times %d/%d ' % - (self.numerator, self.denominator)) - func.add_factor (Rational (self.numerator, self.denominator)) - MusicWrapper.print_ly (self, func) - func.revert () + def print_ly (self, func): + func ('\\times %d/%d ' % + (self.numerator, self.denominator)) + func.add_factor (Rational (self.numerator, self.denominator)) + MusicWrapper.print_ly (self, func) + func.revert () class NestedMusic(Music): - def __init__ (self): - Music.__init__ (self) - self.elements = [] - - def append (self, what): - if what: - self.elements.append (what) - - def has_children (self): - return self.elements - - def insert_around (self, succ, elt, dir): - assert elt.parent == None - assert succ == None or succ in self.elements - - - idx = 0 - if succ: - idx = self.elements.index (succ) - if dir > 0: - idx += 1 - else: - if dir < 0: - idx = 0 - elif dir > 0: - idx = len (self.elements) - - self.elements.insert (idx, elt) - elt.parent = self - - def get_properties (self): - return ("'elements (list %s)" - % string.join (map (lambda x: x.lisp_expression(), - self.elements))) - - def get_subset_properties (self, predicate): - return ("'elements (list %s)" - % string.join (map (lambda x: x.lisp_expression(), - filter ( predicate, self.elements)))) - def get_neighbor (self, music, dir): - assert music.parent == self - idx = self.elements.index (music) - idx += dir - idx = min (idx, len (self.elements) -1) - idx = max (idx, 0) - - return self.elements[idx] - - def delete_element (self, element): - assert element in self.elements - - self.elements.remove (element) - element.parent = None - - def set_start (self, start): - self.start = start - for e in self.elements: - e.set_start (start) - - def find_first (self, predicate): - r = Music.find_first (self, predicate) - if r: - return r - - for e in self.elements: - r = e.find_first (predicate) - if r: - return r - return None - + def __init__ (self): + Music.__init__ (self) + self.elements = [] + + def append (self, what): + if what: + self.elements.append (what) + + def has_children (self): + return self.elements + + def insert_around (self, succ, elt, dir): + assert elt.parent == None + assert succ == None or succ in self.elements + + + idx = 0 + if succ: + idx = self.elements.index (succ) + if dir > 0: + idx += 1 + else: + if dir < 0: + idx = 0 + elif dir > 0: + idx = len (self.elements) + + self.elements.insert (idx, elt) + elt.parent = self + + def get_properties (self): + return ("'elements (list %s)" + % string.join (map (lambda x: x.lisp_expression(), + self.elements))) + + def get_subset_properties (self, predicate): + return ("'elements (list %s)" + % string.join (map (lambda x: x.lisp_expression(), + filter ( predicate, self.elements)))) + def get_neighbor (self, music, dir): + assert music.parent == self + idx = self.elements.index (music) + idx += dir + idx = min (idx, len (self.elements) -1) + idx = max (idx, 0) + + return self.elements[idx] + + def delete_element (self, element): + assert element in self.elements + + self.elements.remove (element) + element.parent = None + + def set_start (self, start): + self.start = start + for e in self.elements: + e.set_start (start) + + def find_first (self, predicate): + r = Music.find_first (self, predicate) + if r: + return r + + for e in self.elements: + r = e.find_first (predicate) + if r: + return r + return None + class SequentialMusic (NestedMusic): - def print_ly (self, printer): - printer ('{') - if self.comment: - self.print_comment (printer) - - printer.newline() - for e in self.elements: - e.print_ly (printer) - - printer ('}') - printer.newline() - - def lisp_sub_expression (self, pred): - name = self.name() - - - props = self.get_subset_properties (pred) - - return "(make-music '%s %s)" % (name, props) - - def set_start (self, start): - for e in self.elements: - e.set_start (start) - start += e.get_length() - + def print_ly (self, printer): + printer ('{') + if self.comment: + self.print_comment (printer) + + printer.newline() + for e in self.elements: + e.print_ly (printer) + + printer ('}') + printer.newline() + + def lisp_sub_expression (self, pred): + name = self.name() + + + props = self.get_subset_properties (pred) + + return "(make-music '%s %s)" % (name, props) + + def set_start (self, start): + for e in self.elements: + e.set_start (start) + start += e.get_length() + class EventChord(NestedMusic): - def get_length (self): - l = Rational (0) - for e in self.elements: - l = max(l, e.get_length()) - return l - - def print_ly (self, printer): - note_events = [e for e in self.elements if - isinstance (e, NoteEvent)] - - rest_events = [e for e in self.elements if - isinstance (e, RhythmicEvent) - and not isinstance (e, NoteEvent)] - - other_events = [e for e in self.elements if - not isinstance (e, RhythmicEvent)] - - if rest_events: - rest_events[0].print_ly (printer) - elif len (note_events) == 1: - note_events[0].print_ly (printer) - elif note_events: - pitches = [x.pitch.ly_expression () for x in note_events] - printer ('<%s>' % string.join (pitches)) - note_events[0].duration.print_ly (printer) - else: - pass - - # print 'huh', rest_events, note_events, other_events - for e in other_events: - e.print_ly (printer) - - self.print_comment (printer) - + def get_length (self): + l = Rational (0) + for e in self.elements: + l = max(l, e.get_length()) + return l + + def print_ly (self, printer): + note_events = [e for e in self.elements if + isinstance (e, NoteEvent)] + + rest_events = [e for e in self.elements if + isinstance (e, RhythmicEvent) + and not isinstance (e, NoteEvent)] + + other_events = [e for e in self.elements if + not isinstance (e, RhythmicEvent)] + + if rest_events: + rest_events[0].print_ly (printer) + elif len (note_events) == 1: + note_events[0].print_ly (printer) + elif note_events: + pitches = [x.pitch.ly_expression () for x in note_events] + printer ('<%s>' % string.join (pitches)) + note_events[0].duration.print_ly (printer) + else: + pass + + # print 'huh', rest_events, note_events, other_events + for e in other_events: + e.print_ly (printer) + + self.print_comment (printer) + class Event(Music): - pass + pass class SpanEvent (Event): - def __init__(self): - Event.__init__ (self) - self.span_direction = 0 - def get_properties(self): - return "'span-direction %d" % self.span_direction - + def __init__(self): + Event.__init__ (self) + self.span_direction = 0 + def get_properties(self): + return "'span-direction %d" % self.span_direction + class SlurEvent (SpanEvent): - def ly_expression (self): - return {-1: '(', - 0:'', - 1:')'}[self.span_direction] + def ly_expression (self): + return {-1: '(', + 0:'', + 1:')'}[self.span_direction] class BeamEvent (SpanEvent): - def ly_expression (self): - return {-1: '[', - 0:'', - 1:']'}[self.span_direction] + def ly_expression (self): + return {-1: '[', + 0:'', + 1:']'}[self.span_direction] class ArpeggioEvent(Event): - def ly_expression (self): - return ('\\arpeggio') + def ly_expression (self): + return ('\\arpeggio') class TieEvent(Event): - def ly_expression (self): - return '~' + def ly_expression (self): + return '~' - + class RhythmicEvent(Event): - def __init__ (self): - Event.__init__ (self) - self.duration = Duration() - - def get_length (self): - return self.duration.get_length() - - def get_properties (self): - return ("'duration %s" - % self.duration.lisp_expression ()) - + def __init__ (self): + Event.__init__ (self) + self.duration = Duration() + + def get_length (self): + return self.duration.get_length() + + def get_properties (self): + return ("'duration %s" + % self.duration.lisp_expression ()) + class RestEvent (RhythmicEvent): - def ly_expression (self): - return 'r%s' % self.duration.ly_expression () - - def print_ly (self, printer): - printer('r') - self.duration.print_ly (printer) + def ly_expression (self): + return 'r%s' % self.duration.ly_expression () + + def print_ly (self, printer): + printer('r') + self.duration.print_ly (printer) class SkipEvent (RhythmicEvent): - def ly_expression (self): - return 's%s' % self.duration.ly_expression () + def ly_expression (self): + return 's%s' % self.duration.ly_expression () class NoteEvent(RhythmicEvent): - def __init__ (self): - RhythmicEvent.__init__ (self) - self.pitch = Pitch() - self.cautionary = False - self.forced_accidental = False - - def get_properties (self): - return ("'pitch %s\n 'duration %s" - % (self.pitch.lisp_expression (), - self.duration.lisp_expression ())) - - def pitch_mods (self): - excl_question = '' - if self.cautionary: - excl_question += '?' - if self.forced_accidental: - excl_question += '!' - - return excl_question - - def ly_expression (self): - return '%s%s%s' % (self.pitch.ly_expression (), - self.pitch_mods(), - self.duration.ly_expression ()) - - def print_ly (self, printer): - self.pitch.print_ly (printer) - printer (self.pitch_mods ()) - self.duration.print_ly (printer) + def __init__ (self): + RhythmicEvent.__init__ (self) + self.pitch = Pitch() + self.cautionary = False + self.forced_accidental = False + + def get_properties (self): + return ("'pitch %s\n 'duration %s" + % (self.pitch.lisp_expression (), + self.duration.lisp_expression ())) + + def pitch_mods (self): + excl_question = '' + if self.cautionary: + excl_question += '?' + if self.forced_accidental: + excl_question += '!' + + return excl_question + + def ly_expression (self): + return '%s%s%s' % (self.pitch.ly_expression (), + self.pitch_mods(), + self.duration.ly_expression ()) + + def print_ly (self, printer): + self.pitch.print_ly (printer) + printer (self.pitch_mods ()) + self.duration.print_ly (printer) class KeySignatureChange (Music): - def __init__ (self): - Music.__init__ (self) - self.scale = [] - self.tonic = Pitch() - self.mode = 'major' - - def ly_expression (self): - return '\\key %s \\%s' % (self.tonic.ly_step_expression (), - self.mode) - - def lisp_expression (self): - pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)] - scale_str = ("'(%s)" % string.join (pairs)) - - return """ (make-music 'KeyChangeEvent - 'pitch-alist %s) """ % scale_str + def __init__ (self): + Music.__init__ (self) + self.scale = [] + self.tonic = Pitch() + self.mode = 'major' + + def ly_expression (self): + return '\\key %s \\%s' % (self.tonic.ly_step_expression (), + self.mode) + + def lisp_expression (self): + pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)] + scale_str = ("'(%s)" % string.join (pairs)) + + return """ (make-music 'KeyChangeEvent + 'pitch-alist %s) """ % scale_str class TimeSignatureChange (Music): - def __init__ (self): - Music.__init__ (self) - self.fraction = (4,4) - def ly_expression (self): - return '\\time %d/%d ' % self.fraction - + def __init__ (self): + Music.__init__ (self) + self.fraction = (4,4) + def ly_expression (self): + return '\\time %d/%d ' % self.fraction + class ClefChange (Music): - def __init__ (self): - Music.__init__ (self) - self.type = 'G' - - - def ly_expression (self): - return '\\clef "%s"' % self.type - clef_dict = { - "G": ("clefs.G", -2, -6), - "C": ("clefs.C", 0, 0), - "F": ("clefs.F", 2, 6), - } - - def lisp_expression (self): - (glyph, pos, c0) = self.clef_dict [self.type] - clefsetting = """ - (make-music 'SequentialMusic - 'elements (list - (context-spec-music - (make-property-set 'clefGlyph "%s") 'Staff) - (context-spec-music - (make-property-set 'clefPosition %d) 'Staff) - (context-spec-music - (make-property-set 'middleCPosition %d) 'Staff))) + def __init__ (self): + Music.__init__ (self) + self.type = 'G' + + + def ly_expression (self): + return '\\clef "%s"' % self.type + clef_dict = { + "G": ("clefs.G", -2, -6), + "C": ("clefs.C", 0, 0), + "F": ("clefs.F", 2, 6), + } + + def lisp_expression (self): + (glyph, pos, c0) = self.clef_dict [self.type] + clefsetting = """ + (make-music 'SequentialMusic + 'elements (list + (context-spec-music + (make-property-set 'clefGlyph "%s") 'Staff) + (context-spec-music + (make-property-set 'clefPosition %d) 'Staff) + (context-spec-music + (make-property-set 'middleCPosition %d) 'Staff))) """ % (glyph, pos, c0) - return clefsetting + return clefsetting def test_pitch (): - bflat = Pitch() - bflat.alteration = -1 - bflat.step = 6 - bflat.octave = -1 - fifth = Pitch() - fifth.step = 4 - down = Pitch () - down.step = -4 - down.normalize () - - - print bflat.semitones() - print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth) - print bflat.transposed (fifth).transposed (fifth).transposed (fifth) - - print bflat.semitones(), 'down' - print bflat.transposed (down) - print bflat.transposed (down).transposed (down) - print bflat.transposed (down).transposed (down).transposed (down) + bflat = Pitch() + bflat.alteration = -1 + bflat.step = 6 + bflat.octave = -1 + fifth = Pitch() + fifth.step = 4 + down = Pitch () + down.step = -4 + down.normalize () + + + print bflat.semitones() + print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth) + print bflat.transposed (fifth).transposed (fifth).transposed (fifth) + + print bflat.semitones(), 'down' + print bflat.transposed (down) + print bflat.transposed (down).transposed (down) + print bflat.transposed (down).transposed (down).transposed (down) def test_printer (): - def make_note (): - evc = EventChord() - n = NoteEvent() - evc.append (n) - return n - - def make_tup (): - m = SequentialMusic() - m.append (make_note ()) - m.append (make_note ()) - m.append (make_note ()) - - - t = TimeScaledMusic () - t.numerator = 2 - t.denominator = 3 - t.element = m - return t - - m = SequentialMusic () - m.append (make_tup ()) - m.append (make_tup ()) - m.append (make_tup ()) - - printer = Output_printer() - m.print_ly (printer) - printer.newline () - + def make_note (): + evc = EventChord() + n = NoteEvent() + evc.append (n) + return n + + def make_tup (): + m = SequentialMusic() + m.append (make_note ()) + m.append (make_note ()) + m.append (make_note ()) + + + t = TimeScaledMusic () + t.numerator = 2 + t.denominator = 3 + t.element = m + return t + + m = SequentialMusic () + m.append (make_tup ()) + m.append (make_tup ()) + m.append (make_tup ()) + + printer = Output_printer() + m.print_ly (printer) + printer.newline () + def test_expr (): - m = SequentialMusic() - l = 2 - evc = EventChord() - n = NoteEvent() - n.duration.duration_log = l - n.pitch.step = 1 - evc.insert_around (None, n, 0) - m.insert_around (None, evc, 0) - - evc = EventChord() - n = NoteEvent() - n.duration.duration_log = l - n.pitch.step = 3 - evc.insert_around (None, n, 0) - m.insert_around (None, evc, 0) - - evc = EventChord() - n = NoteEvent() - n.duration.duration_log = l - n.pitch.step = 2 - evc.insert_around (None, n, 0) - m.insert_around (None, evc, 0) - - evc = ClefChange() - evc.type = 'treble' - m.insert_around (None, evc, 0) - - evc = EventChord() - tonic = Pitch () - tonic.step = 2 - tonic.alteration = -2 - n = KeySignatureChange() - n.tonic=tonic.copy() - n.scale = [0, 0, -2, 0, 0,-2,-2] - - evc.insert_around (None, n, 0) - m.insert_around (None, evc, 0) - - return m + m = SequentialMusic() + l = 2 + evc = EventChord() + n = NoteEvent() + n.duration.duration_log = l + n.pitch.step = 1 + evc.insert_around (None, n, 0) + m.insert_around (None, evc, 0) + + evc = EventChord() + n = NoteEvent() + n.duration.duration_log = l + n.pitch.step = 3 + evc.insert_around (None, n, 0) + m.insert_around (None, evc, 0) + + evc = EventChord() + n = NoteEvent() + n.duration.duration_log = l + n.pitch.step = 2 + evc.insert_around (None, n, 0) + m.insert_around (None, evc, 0) + + evc = ClefChange() + evc.type = 'treble' + m.insert_around (None, evc, 0) + + evc = EventChord() + tonic = Pitch () + tonic.step = 2 + tonic.alteration = -2 + n = KeySignatureChange() + n.tonic=tonic.copy() + n.scale = [0, 0, -2, 0, 0,-2,-2] + + evc.insert_around (None, n, 0) + m.insert_around (None, evc, 0) + + return m if __name__ == '__main__': - test_printer () - raise 'bla' - test_pitch() - - expr = test_expr() - expr.set_start (Rational (0)) - print expr.ly_expression() - start = Rational (0,4) - stop = Rational (4,2) - def sub(x, start=start, stop=stop): - ok = x.start >= start and x.start +x.get_length() <= stop - return ok - - print expr.lisp_sub_expression(sub) + test_printer () + raise 'bla' + test_pitch() + + expr = test_expr() + expr.set_start (Rational (0)) + print expr.ly_expression() + start = Rational (0,4) + stop = Rational (4,2) + def sub(x, start=start, stop=stop): + ok = x.start >= start and x.start +x.get_length() <= stop + return ok + + print expr.lisp_sub_expression(sub) diff --git a/scripts/abc2ly.py b/scripts/abc2ly.py index 1257182f71..664d73ec48 100644 --- a/scripts/abc2ly.py +++ b/scripts/abc2ly.py @@ -65,7 +65,7 @@ # # UNDEF -> None # - + import __main__ import getopt @@ -79,30 +79,30 @@ program_name = sys.argv[0] datadir = '@local_lilypond_datadir@' if not os.path.isdir (datadir): - datadir = '@lilypond_datadir@' + datadir = '@lilypond_datadir@' sys.path.insert (0, os.path.join (datadir, 'python')) if os.environ.has_key ('LILYPONDPREFIX'): - datadir = os.environ['LILYPONDPREFIX'] - while datadir[-1] == os.sep: - datadir= datadir[:-1] - - datadir = os.path.join (datadir, "share/lilypond/current/") + datadir = os.environ['LILYPONDPREFIX'] + while datadir[-1] == os.sep: + datadir= datadir[:-1] + + datadir = os.path.join (datadir, "share/lilypond/current/") sys.path.insert (0, os.path.join (datadir, 'python')) # dynamic relocation, for GUB binaries. bindir = os.path.split (sys.argv[0])[0] for p in ['share', 'lib']: - datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % p) - sys.path.insert (0, os.path.join (datadir)) + datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % p) + sys.path.insert (0, os.path.join (datadir)) import lilylib as ly global _;_=ly._ version = '@TOPLEVEL_VERSION@' if version == '@' + 'TOPLEVEL_VERSION' + '@': - version = '(unknown version)' # uGUHGUHGHGUGH + version = '(unknown version)' # uGUHGUHGHGUGH UNDEF = 255 state = UNDEF @@ -121,7 +121,7 @@ part_names = 0 default_len = 8 length_specified = 0 nobarlines = 0 -global_key = [0] * 7 # UGH +global_key = [0] * 7 # UGH names = ["One", "Two", "Three"] DIGITS='0123456789' HSPACE=' \t' @@ -129,959 +129,959 @@ midi_specs = '' def error (msg): - sys.stderr.write (msg) - if global_options.strict: - sys.exit (1) - + sys.stderr.write (msg) + if global_options.strict: + sys.exit (1) + def alphabet (i): - return chr (i + ord('A')) - + return chr (i + ord('A')) + def check_clef(s): - if not s: - return '' - if re.match('-8va', s) or re.match('treble8', s): - # treble8 is used by abctab2ps; -8va is used by barfly, - # and by my patch to abc2ps. If there's ever a standard - # about this we'll support that. - s = s[4:] - state.base_octave = -1 - voices_append("\\clef \"G_8\"\n") - elif re.match('^treble', s): - s = s[6:] - if re.match ('^-8', s): - s = s[2:] - state.base_octave = -2 - voices_append("\\clef \"G_8\"\n") - else: - state.base_octave = 0 - voices_append("\\clef treble\n") - elif re.match('^alto', s): - s = s[4:] - state.base_octave = -1 - voices_append ("\\clef alto\n" ) - elif re.match('^bass',s ): - s = s[4:] - state.base_octave = -2 - voices_append ("\\clef bass\n" ) - return s + if not s: + return '' + if re.match('-8va', s) or re.match('treble8', s): + # treble8 is used by abctab2ps; -8va is used by barfly, + # and by my patch to abc2ps. If there's ever a standard + # about this we'll support that. + s = s[4:] + state.base_octave = -1 + voices_append("\\clef \"G_8\"\n") + elif re.match('^treble', s): + s = s[6:] + if re.match ('^-8', s): + s = s[2:] + state.base_octave = -2 + voices_append("\\clef \"G_8\"\n") + else: + state.base_octave = 0 + voices_append("\\clef treble\n") + elif re.match('^alto', s): + s = s[4:] + state.base_octave = -1 + voices_append ("\\clef alto\n" ) + elif re.match('^bass',s ): + s = s[4:] + state.base_octave = -2 + voices_append ("\\clef bass\n" ) + return s def select_voice (name, rol): - if not voice_idx_dict.has_key (name): - state_list.append(Parser_state()) - voices.append ('') - slyrics.append ([]) - voice_idx_dict[name] = len (voices) -1 - __main__.current_voice_idx = voice_idx_dict[name] - __main__.state = state_list[current_voice_idx] - while rol != '': - m = re.match ('^([^ \t=]*)=(.*)$', rol) # find keywork - if m: - keyword = m.group(1) - rol = m.group (2) - a = re.match ('^("[^"]*"|[^ \t]*) *(.*)$', rol) - if a: - value = a.group (1) - rol = a.group ( 2) - if keyword == 'clef': - check_clef(value) - elif keyword == "name": - value = re.sub ('\\\\','\\\\\\\\', value) - ## < 2.2 - voices_append ("\\set Staff.instrument = %s\n" % value ) - - __main__.part_names = 1 - elif keyword == "sname" or keyword == "snm": - voices_append ("\\set Staff.instr = %s\n" % value ) - else: - break + if not voice_idx_dict.has_key (name): + state_list.append(Parser_state()) + voices.append ('') + slyrics.append ([]) + voice_idx_dict[name] = len (voices) -1 + __main__.current_voice_idx = voice_idx_dict[name] + __main__.state = state_list[current_voice_idx] + while rol != '': + m = re.match ('^([^ \t=]*)=(.*)$', rol) # find keywork + if m: + keyword = m.group(1) + rol = m.group (2) + a = re.match ('^("[^"]*"|[^ \t]*) *(.*)$', rol) + if a: + value = a.group (1) + rol = a.group ( 2) + if keyword == 'clef': + check_clef(value) + elif keyword == "name": + value = re.sub ('\\\\','\\\\\\\\', value) + ## < 2.2 + voices_append ("\\set Staff.instrument = %s\n" % value ) + + __main__.part_names = 1 + elif keyword == "sname" or keyword == "snm": + voices_append ("\\set Staff.instr = %s\n" % value ) + else: + break def dump_header (outf,hdr): - outf.write ('\\header {\n') - ks = hdr.keys () - ks.sort () - for k in ks: - hdr[k] = re.sub('"', '\\"', hdr[k]) - outf.write ('\t%s = "%s"\n'% (k,hdr[k])) - outf.write ('}') + outf.write ('\\header {\n') + ks = hdr.keys () + ks.sort () + for k in ks: + hdr[k] = re.sub('"', '\\"', hdr[k]) + outf.write ('\t%s = "%s"\n'% (k,hdr[k])) + outf.write ('}') def dump_lyrics (outf): - if (len(lyrics)): - outf.write("\n\\score\n{\n \\lyrics\n <<\n") - for i in range (len (lyrics)): - outf.write ( lyrics [i]) - outf.write ("\n") - outf.write(" >>\n \\layout{}\n}\n") + if (len(lyrics)): + outf.write("\n\\score\n{\n \\lyrics\n <<\n") + for i in range (len (lyrics)): + outf.write ( lyrics [i]) + outf.write ("\n") + outf.write(" >>\n \\layout{}\n}\n") def dump_default_bar (outf): - """ - Nowadays abc2ly outputs explicits barlines (?) - """ - ## < 2.2 - outf.write ("\n\\set Score.defaultBarType = \"empty\"\n") + """ + Nowadays abc2ly outputs explicits barlines (?) + """ + ## < 2.2 + outf.write ("\n\\set Score.defaultBarType = \"empty\"\n") def dump_slyrics (outf): - ks = voice_idx_dict.keys() - ks.sort () - for k in ks: - if re.match('[1-9]', k): - m = alphabet(string.atoi(k)) - else: - m = k - for i in range (len(slyrics[voice_idx_dict[k]])): - l= alphabet(i) - outf.write ("\nwords%sV%s = \lyricmode {" % (m, l)) - outf.write ("\n" + slyrics [voice_idx_dict[k]][i]) - outf.write ("\n}") + ks = voice_idx_dict.keys() + ks.sort () + for k in ks: + if re.match('[1-9]', k): + m = alphabet(string.atoi(k)) + else: + m = k + for i in range (len(slyrics[voice_idx_dict[k]])): + l= alphabet(i) + outf.write ("\nwords%sV%s = \lyricmode {" % (m, l)) + outf.write ("\n" + slyrics [voice_idx_dict[k]][i]) + outf.write ("\n}") def dump_voices (outf): - global doing_alternative, in_repeat - ks = voice_idx_dict.keys() - ks.sort () - for k in ks: - if re.match ('[1-9]', k): - m = alphabet(string.atoi(k)) - else: - m = k - outf.write ("\nvoice%s = {" % m) - dump_default_bar(outf) - if repeat_state[voice_idx_dict[k]]: - outf.write("\n\\repeat volta 2 {") - outf.write ("\n" + voices [voice_idx_dict[k]]) - if not using_old: - if doing_alternative[voice_idx_dict[k]]: - outf.write("}") - if in_repeat[voice_idx_dict[k]]: - outf.write("}") - outf.write ("\n}") + global doing_alternative, in_repeat + ks = voice_idx_dict.keys() + ks.sort () + for k in ks: + if re.match ('[1-9]', k): + m = alphabet(string.atoi(k)) + else: + m = k + outf.write ("\nvoice%s = {" % m) + dump_default_bar(outf) + if repeat_state[voice_idx_dict[k]]: + outf.write("\n\\repeat volta 2 {") + outf.write ("\n" + voices [voice_idx_dict[k]]) + if not using_old: + if doing_alternative[voice_idx_dict[k]]: + outf.write("}") + if in_repeat[voice_idx_dict[k]]: + outf.write("}") + outf.write ("\n}") def try_parse_q(a): - global midi_specs - #assume that Q takes the form "Q:1/4=120" - #There are other possibilities, but they are deprecated - if string.count(a, '/') == 1: - array=string.split(a,'/') - numerator=array[0] - if numerator != 1: - sys.stderr.write("abc2ly: Warning, unable to translate a Q specification with a numerator of %s: %s\n" % (numerator, a)) - array2=string.split(array[1],'=') - denominator=array2[0] - perminute=array2[1] - duration=str(string.atoi(denominator)/string.atoi(numerator)) - midi_specs=string.join(["\\tempo", duration, "=", perminute]) - else: - sys.stderr.write("abc2ly: Warning, unable to parse Q specification: %s\n" % a) - + global midi_specs + #assume that Q takes the form "Q:1/4=120" + #There are other possibilities, but they are deprecated + if string.count(a, '/') == 1: + array=string.split(a,'/') + numerator=array[0] + if numerator != 1: + sys.stderr.write("abc2ly: Warning, unable to translate a Q specification with a numerator of %s: %s\n" % (numerator, a)) + array2=string.split(array[1],'=') + denominator=array2[0] + perminute=array2[1] + duration=str(string.atoi(denominator)/string.atoi(numerator)) + midi_specs=string.join(["\\tempo", duration, "=", perminute]) + else: + sys.stderr.write("abc2ly: Warning, unable to parse Q specification: %s\n" % a) + def dump_score (outf): - outf.write (r""" + outf.write (r""" \score{ - << + << """) - ks = voice_idx_dict.keys (); - ks.sort () - for k in ks: - if re.match('[1-9]', k): - m = alphabet (string.atoi(k)) - else: - m = k - if k == 'default' and len (voice_idx_dict) > 1: - break - outf.write ("\n\t\\context Staff=\"%s\"\n\t{\n" %k ) - if k != 'default': - outf.write ("\t \\voicedefault\n") - outf.write ("\t \\voice%s " % m) - outf.write ("\n\t}\n") - - l = ord( 'A' ) - for lyrics in slyrics [voice_idx_dict[k]]: - outf.write ("\n\t\\addlyrics { \n") - if re.match('[1-9]',k): - m = alphabet (string.atoi(k)) - else: - m = k - - outf.write ( " \\words%sV%s } " % ( m, chr (l)) ) - l += 1 - - outf.write ("\n >>") - outf.write ("\n\t\\layout {\n") - outf.write ("\t}\n\t\\midi {%s}\n}\n" % midi_specs) + ks = voice_idx_dict.keys (); + ks.sort () + for k in ks: + if re.match('[1-9]', k): + m = alphabet (string.atoi(k)) + else: + m = k + if k == 'default' and len (voice_idx_dict) > 1: + break + outf.write ("\n\t\\context Staff=\"%s\"\n\t{\n" %k ) + if k != 'default': + outf.write ("\t \\voicedefault\n") + outf.write ("\t \\voice%s " % m) + outf.write ("\n\t}\n") + + l = ord( 'A' ) + for lyrics in slyrics [voice_idx_dict[k]]: + outf.write ("\n\t\\addlyrics { \n") + if re.match('[1-9]',k): + m = alphabet (string.atoi(k)) + else: + m = k + + outf.write ( " \\words%sV%s } " % ( m, chr (l)) ) + l += 1 + + outf.write ("\n >>") + outf.write ("\n\t\\layout {\n") + outf.write ("\t}\n\t\\midi {%s}\n}\n" % midi_specs) def set_default_length (s): - global length_specified - m = re.search ('1/([0-9]+)', s) - if m: - __main__.default_len = string.atoi ( m.group (1)) - length_specified = 1 + global length_specified + m = re.search ('1/([0-9]+)', s) + if m: + __main__.default_len = string.atoi ( m.group (1)) + length_specified = 1 def set_default_len_from_time_sig (s): - m = re.search ('([0-9]+)/([0-9]+)', s) - if m: - n = string.atoi (m.group (1)) - d = string.atoi (m.group (2)) - if (n * 1.0 )/(d * 1.0) < 0.75: - __main__.default_len = 16 - else: - __main__.default_len = 8 + m = re.search ('([0-9]+)/([0-9]+)', s) + if m: + n = string.atoi (m.group (1)) + d = string.atoi (m.group (2)) + if (n * 1.0 )/(d * 1.0) < 0.75: + __main__.default_len = 16 + else: + __main__.default_len = 8 def gulp_file(f): - try: - i = open(f) - i.seek (0, 2) - n = i.tell () - i.seek (0,0) - except: - sys.stderr.write ("can't open file: `%s'\n" % f) - return '' - s = i.read (n) - if len (s) <= 0: - sys.stderr.write ("gulped empty file: `%s'\n" % f) - i.close () - return s + try: + i = open(f) + i.seek (0, 2) + n = i.tell () + i.seek (0,0) + except: + sys.stderr.write ("can't open file: `%s'\n" % f) + return '' + s = i.read (n) + if len (s) <= 0: + sys.stderr.write ("gulped empty file: `%s'\n" % f) + i.close () + return s # pitch manipulation. Tuples are (name, alteration). # 0 is (central) C. Alteration -1 is a flat, Alteration +1 is a sharp # pitch in semitones. def semitone_pitch (tup): - p =0 - - t = tup[0] - p = p + 12 * (t / 7) - t = t % 7 - - if t > 2: - p = p- 1 - - p = p + t* 2 + tup[1] - return p + p =0 + + t = tup[0] + p = p + 12 * (t / 7) + t = t % 7 + + if t > 2: + p = p- 1 + + p = p + t* 2 + tup[1] + return p def fifth_above_pitch (tup): - (n, a) = (tup[0] + 4, tup[1]) + (n, a) = (tup[0] + 4, tup[1]) - difference = 7 - (semitone_pitch ((n,a)) - semitone_pitch (tup)) - a = a + difference - - return (n,a) + difference = 7 - (semitone_pitch ((n,a)) - semitone_pitch (tup)) + a = a + difference + + return (n,a) def sharp_keys (): - p = (0,0) - l = [] - k = 0 - while 1: - l.append (p) - (t,a) = fifth_above_pitch (p) - if semitone_pitch((t,a)) % 12 == 0: - break - - p = (t % 7, a) - return l + p = (0,0) + l = [] + k = 0 + while 1: + l.append (p) + (t,a) = fifth_above_pitch (p) + if semitone_pitch((t,a)) % 12 == 0: + break + + p = (t % 7, a) + return l def flat_keys (): - p = (0,0) - l = [] - k = 0 - while 1: - l.append (p) - (t,a) = quart_above_pitch (p) - if semitone_pitch((t,a)) % 12 == 0: - break - - p = (t % 7, a) - return l + p = (0,0) + l = [] + k = 0 + while 1: + l.append (p) + (t,a) = quart_above_pitch (p) + if semitone_pitch((t,a)) % 12 == 0: + break + + p = (t % 7, a) + return l def quart_above_pitch (tup): - (n, a) = (tup[0] + 3, tup[1]) - - difference = 5 - (semitone_pitch ((n,a)) - semitone_pitch (tup)) - a = a + difference - - return (n,a) - -key_lookup = { # abc to lilypond key mode names - 'm' : 'minor', - 'min' : 'minor', - 'maj' : 'major', - 'major' : 'major', - 'phr' : 'phrygian', - 'ion' : 'ionian', - 'loc' : 'locrian', - 'aeo' : 'aeolian', - 'mix' : 'mixolydian', - 'mixolydian' : 'mixolydian', - 'lyd' : 'lydian', - 'dor' : 'dorian', - 'dorian' : 'dorian' + (n, a) = (tup[0] + 3, tup[1]) + + difference = 5 - (semitone_pitch ((n,a)) - semitone_pitch (tup)) + a = a + difference + + return (n,a) + +key_lookup = { # abc to lilypond key mode names + 'm' : 'minor', + 'min' : 'minor', + 'maj' : 'major', + 'major' : 'major', + 'phr' : 'phrygian', + 'ion' : 'ionian', + 'loc' : 'locrian', + 'aeo' : 'aeolian', + 'mix' : 'mixolydian', + 'mixolydian' : 'mixolydian', + 'lyd' : 'lydian', + 'dor' : 'dorian', + 'dorian' : 'dorian' } def lily_key (k): - orig = "" + k - # UGR - k = string.lower (k) - key = k[0] - #UGH - k = k[1:] - if k and k[0] == '#': - key = key + 'is' - k = k[1:] - elif k and k[0] == 'b': - key = key + 'es' - k = k[1:] - if not k: - return '%s \\major' % key - - type = k[0:3] - if not key_lookup.has_key (type): - #ugh, use lilylib, say WARNING:FILE:LINE: - sys.stderr.write ("abc2ly:warning:") - sys.stderr.write ("ignoring unknown key: `%s'" % orig) - sys.stderr.write ('\n') - return 0 - return ("%s \\%s" % ( key, key_lookup[type])) + orig = "" + k + # UGR + k = string.lower (k) + key = k[0] + #UGH + k = k[1:] + if k and k[0] == '#': + key = key + 'is' + k = k[1:] + elif k and k[0] == 'b': + key = key + 'es' + k = k[1:] + if not k: + return '%s \\major' % key + + type = k[0:3] + if not key_lookup.has_key (type): + #ugh, use lilylib, say WARNING:FILE:LINE: + sys.stderr.write ("abc2ly:warning:") + sys.stderr.write ("ignoring unknown key: `%s'" % orig) + sys.stderr.write ('\n') + return 0 + return ("%s \\%s" % ( key, key_lookup[type])) def shift_key (note, acc, shift): - s = semitone_pitch((note, acc)) - s = (s + shift + 12) % 12 - if s <= 4: - n = s / 2 - a = s % 2 - else: - n = (s + 1) / 2 - a = (s + 1) % 2 - if a: - n = n + 1 - a = -1 - return (n,a) + s = semitone_pitch((note, acc)) + s = (s + shift + 12) % 12 + if s <= 4: + n = s / 2 + a = s % 2 + else: + n = (s + 1) / 2 + a = (s + 1) % 2 + if a: + n = n + 1 + a = -1 + return (n,a) key_shift = { # semitone shifts for key mode names - 'm' : 3, - 'min' : 3, - 'minor' : 3, - 'maj' : 0, - 'major' : 0, - 'phr' : -4, - 'phrygian' : -4, - 'ion' : 0, - 'ionian' : 0, - 'loc' : 1, - 'locrian' : 1, - 'aeo' : 3, - 'aeolian' : 3, - 'mix' : 5, - 'mixolydian' : 5, - 'lyd' : -5, - 'lydian' : -5, - 'dor' : -2, - 'dorian' : -2 + 'm' : 3, + 'min' : 3, + 'minor' : 3, + 'maj' : 0, + 'major' : 0, + 'phr' : -4, + 'phrygian' : -4, + 'ion' : 0, + 'ionian' : 0, + 'loc' : 1, + 'locrian' : 1, + 'aeo' : 3, + 'aeolian' : 3, + 'mix' : 5, + 'mixolydian' : 5, + 'lyd' : -5, + 'lydian' : -5, + 'dor' : -2, + 'dorian' : -2 } def compute_key (k): - k = string.lower (k) - intkey = (ord (k[0]) - ord('a') + 5) % 7 - intkeyacc =0 - k = k[1:] - - if k and k[0] == 'b': - intkeyacc = -1 - k = k[1:] - elif k and k[0] == '#': - intkeyacc = 1 - k = k[1:] - k = k[0:3] - if k and key_shift.has_key(k): - (intkey, intkeyacc) = shift_key(intkey, intkeyacc, key_shift[k]) - keytup = (intkey, intkeyacc) - - sharp_key_seq = sharp_keys () - flat_key_seq = flat_keys () - - accseq = None - accsign = 0 - if keytup in sharp_key_seq: - accsign = 1 - key_count = sharp_key_seq.index (keytup) - accseq = map (lambda x: (4*x -1 ) % 7, range (1, key_count + 1)) - - elif keytup in flat_key_seq: - accsign = -1 - key_count = flat_key_seq.index (keytup) - accseq = map (lambda x: (3*x + 3 ) % 7, range (1, key_count + 1)) - else: - error ("Huh?") - raise "Huh" - - key_table = [0] * 7 - for a in accseq: - key_table[a] = key_table[a] + accsign - - return key_table + k = string.lower (k) + intkey = (ord (k[0]) - ord('a') + 5) % 7 + intkeyacc =0 + k = k[1:] + + if k and k[0] == 'b': + intkeyacc = -1 + k = k[1:] + elif k and k[0] == '#': + intkeyacc = 1 + k = k[1:] + k = k[0:3] + if k and key_shift.has_key(k): + (intkey, intkeyacc) = shift_key(intkey, intkeyacc, key_shift[k]) + keytup = (intkey, intkeyacc) + + sharp_key_seq = sharp_keys () + flat_key_seq = flat_keys () + + accseq = None + accsign = 0 + if keytup in sharp_key_seq: + accsign = 1 + key_count = sharp_key_seq.index (keytup) + accseq = map (lambda x: (4*x -1 ) % 7, range (1, key_count + 1)) + + elif keytup in flat_key_seq: + accsign = -1 + key_count = flat_key_seq.index (keytup) + accseq = map (lambda x: (3*x + 3 ) % 7, range (1, key_count + 1)) + else: + error ("Huh?") + raise "Huh" + + key_table = [0] * 7 + for a in accseq: + key_table[a] = key_table[a] + accsign + + return key_table tup_lookup = { - '2' : '3/2', - '3' : '2/3', - '4' : '4/3', - '5' : '4/5', - '6' : '4/6', - '7' : '6/7', - '9' : '8/9', - } + '2' : '3/2', + '3' : '2/3', + '4' : '4/3', + '5' : '4/5', + '6' : '4/6', + '7' : '6/7', + '9' : '8/9', + } def try_parse_tuplet_begin (str, state): - if re.match ('\([2-9]', str): - dig = str[1] - str = str[2:] - prev_tuplet_state = state.parsing_tuplet - state.parsing_tuplet = string.atoi (dig[0]) - if prev_tuplet_state: - voices_append ("}") - voices_append ("\\times %s {" % tup_lookup[dig]) - return str + if re.match ('\([2-9]', str): + dig = str[1] + str = str[2:] + prev_tuplet_state = state.parsing_tuplet + state.parsing_tuplet = string.atoi (dig[0]) + if prev_tuplet_state: + voices_append ("}") + voices_append ("\\times %s {" % tup_lookup[dig]) + return str def try_parse_group_end (str, state): - if str and str[0] in HSPACE: - str = str[1:] - close_beam_state(state) - return str - + if str and str[0] in HSPACE: + str = str[1:] + close_beam_state(state) + return str + def header_append (key, a): - s = '' - if header.has_key (key): - s = header[key] + "\n" - header [key] = s + a + s = '' + if header.has_key (key): + s = header[key] + "\n" + header [key] = s + a def wordwrap(a, v): - linelen = len (v) - string.rfind(v, '\n') - if linelen + len (a) > 80: - v = v + '\n' - return v + a + ' ' + linelen = len (v) - string.rfind(v, '\n') + if linelen + len (a) > 80: + v = v + '\n' + return v + a + ' ' def stuff_append (stuff, idx, a): - if not stuff: - stuff.append (a) - else: - stuff [idx] = wordwrap(a, stuff[idx]) + if not stuff: + stuff.append (a) + else: + stuff [idx] = wordwrap(a, stuff[idx]) # ignore wordwrap since we are adding to the previous word def stuff_append_back(stuff, idx, a): - if not stuff: - stuff.append (a) - else: - point = len(stuff[idx])-1 - while stuff[idx][point] is ' ': - point = point - 1 - point = point +1 - stuff[idx] = stuff[idx][:point] + a + stuff[idx][point:] + if not stuff: + stuff.append (a) + else: + point = len(stuff[idx])-1 + while stuff[idx][point] is ' ': + point = point - 1 + point = point +1 + stuff[idx] = stuff[idx][:point] + a + stuff[idx][point:] def voices_append(a): - if current_voice_idx < 0: - select_voice ('default', '') - stuff_append (voices, current_voice_idx, a) + if current_voice_idx < 0: + select_voice ('default', '') + stuff_append (voices, current_voice_idx, a) # word wrap really makes it hard to bind beams to the end of notes since it # pushes out whitespace on every call. The _back functions do an append # prior to the last space, effectively tagging whatever they are given # onto the last note def voices_append_back(a): - if current_voice_idx < 0: - select_voice ('default', '') - stuff_append_back(voices, current_voice_idx, a) + if current_voice_idx < 0: + select_voice ('default', '') + stuff_append_back(voices, current_voice_idx, a) def repeat_prepend(): - global repeat_state - if current_voice_idx < 0: - select_voice ('default', '') - if not using_old: - repeat_state[current_voice_idx] = 't' + global repeat_state + if current_voice_idx < 0: + select_voice ('default', '') + if not using_old: + repeat_state[current_voice_idx] = 't' - + def lyrics_append(a): - a = re.sub ('#', '\\#', a) # latex does not like naked #'s - a = re.sub ('"', '\\"', a) # latex does not like naked "'s - a = '\t{ "' + a + '" }\n' - stuff_append (lyrics, current_lyric_idx, a) + a = re.sub ('#', '\\#', a) # latex does not like naked #'s + a = re.sub ('"', '\\"', a) # latex does not like naked "'s + a = '\t{ "' + a + '" }\n' + stuff_append (lyrics, current_lyric_idx, a) # break lyrics to words and put "'s around words containing numbers and '"'s def fix_lyric(str): - ret = '' - while str != '': - m = re.match('[ \t]*([^ \t]*)[ \t]*(.*$)', str) - if m: - word = m.group(1) - str = m.group(2) - word = re.sub('"', '\\"', word) # escape " - if re.match('.*[0-9"\(]', word): - word = re.sub('_', ' ', word) # _ causes probs inside "" - ret = ret + '\"' + word + '\" ' - else: - ret = ret + word + ' ' - else: - return (ret) - return (ret) + ret = '' + while str != '': + m = re.match('[ \t]*([^ \t]*)[ \t]*(.*$)', str) + if m: + word = m.group(1) + str = m.group(2) + word = re.sub('"', '\\"', word) # escape " + if re.match('.*[0-9"\(]', word): + word = re.sub('_', ' ', word) # _ causes probs inside "" + ret = ret + '\"' + word + '\" ' + else: + ret = ret + word + ' ' + else: + return (ret) + return (ret) def slyrics_append(a): - a = re.sub ( '_', ' _ ', a) # _ to ' _ ' - a = re.sub ( '-', '- ', a) # split words with - - a = re.sub ( '\\\\- ', '-', a) # unless \- - a = re.sub ( '~', '_', a) # ~ to space('_') - a = re.sub ( '\*', '_ ', a) # * to to space - a = re.sub ( '#', '\\#', a) # latex does not like naked #'s - if re.match('.*[0-9"\(]', a): # put numbers and " and ( into quoted string - a = fix_lyric(a) - a = re.sub ( '$', ' ', a) # insure space between lines - __main__.lyric_idx = lyric_idx + 1 - if len(slyrics[current_voice_idx]) <= lyric_idx: - slyrics[current_voice_idx].append(a) - else: - v = slyrics[current_voice_idx][lyric_idx] - slyrics[current_voice_idx][lyric_idx] = wordwrap(a, slyrics[current_voice_idx][lyric_idx]) + a = re.sub ( '_', ' _ ', a) # _ to ' _ ' + a = re.sub ( '-', '- ', a) # split words with - + a = re.sub ( '\\\\- ', '-', a) # unless \- + a = re.sub ( '~', '_', a) # ~ to space('_') + a = re.sub ( '\*', '_ ', a) # * to to space + a = re.sub ( '#', '\\#', a) # latex does not like naked #'s + if re.match('.*[0-9"\(]', a): # put numbers and " and ( into quoted string + a = fix_lyric(a) + a = re.sub ( '$', ' ', a) # insure space between lines + __main__.lyric_idx = lyric_idx + 1 + if len(slyrics[current_voice_idx]) <= lyric_idx: + slyrics[current_voice_idx].append(a) + else: + v = slyrics[current_voice_idx][lyric_idx] + slyrics[current_voice_idx][lyric_idx] = wordwrap(a, slyrics[current_voice_idx][lyric_idx]) def try_parse_header_line (ln, state): - global length_specified - m = re.match ('^([A-Za-z]): *(.*)$', ln) - - if m: - g =m.group (1) - a = m.group (2) - if g == 'T': #title - a = re.sub('[ \t]*$','', a) #strip trailing blanks - if header.has_key('title'): - if a: - if len(header['title']): - # the non-ascii character - # in the string below is a - # punctuation dash. (TeX ---) - header['title'] = header['title'] + ' — ' + a - else: - header['subtitle'] = a - else: - header['title'] = a - if g == 'M': # Meter - if a == 'C': - if not state.common_time: - state.common_time = 1 - voices_append (" \\override Staff.TimeSignature #\'style = #'C\n") - a = '4/4' - if a == 'C|': - if not state.common_time: - state.common_time = 1 - voices_append ("\\override Staff.TimeSignature #\'style = #'C\n") - a = '2/2' - if not length_specified: - set_default_len_from_time_sig (a) - else: - length_specified = 0 - if not a == 'none': - voices_append ('\\time %s' % a) - state.next_bar = '' - if g == 'K': # KEY - a = check_clef(a) - if a: - m = re.match ('^([^ \t]*) *(.*)$', a) # seperate clef info - if m: - # there may or may not be a space - # between the key letter and the mode - if key_lookup.has_key(m.group(2)[0:3]): - key_info = m.group(1) + m.group(2)[0:3] - clef_info = m.group(2)[4:] - else: - key_info = m.group(1) - clef_info = m.group(2) - __main__.global_key = compute_key (key_info) - k = lily_key (key_info) - if k: - voices_append ('\\key %s' % k) - check_clef(clef_info) - else: - __main__.global_key = compute_key (a) - k = lily_key (a) - if k: - voices_append ('\\key %s \\major' % k) - if g == 'N': # Notes - header ['footnotes'] = header['footnotes'] + '\\\\\\\\' + a - if g == 'O': # Origin - header ['origin'] = a - if g == 'X': # Reference Number - header ['crossRefNumber'] = a - if g == 'A': # Area - header ['area'] = a - if g == 'H': # History - header_append ('history', a) - if g == 'B': # Book - header ['book'] = a - if g == 'C': # Composer - if header.has_key('composer'): - if a: - header['composer'] = header['composer'] + '\\\\\\\\' + a - else: - header['composer'] = a - if g == 'S': - header ['subtitle'] = a - if g == 'L': # Default note length - set_default_length (ln) - if g == 'V': # Voice - voice = re.sub (' .*$', '', a) - rest = re.sub ('^[^ \t]* *', '', a) - if state.next_bar: - voices_append(state.next_bar) - state.next_bar = '' - select_voice (voice, rest) - if g == 'W': # Words - lyrics_append(a) - if g == 'w': # vocals - slyrics_append (a) - if g == 'Q': #tempo - try_parse_q (a) - return '' - return ln + global length_specified + m = re.match ('^([A-Za-z]): *(.*)$', ln) + + if m: + g =m.group (1) + a = m.group (2) + if g == 'T': #title + a = re.sub('[ \t]*$','', a) #strip trailing blanks + if header.has_key('title'): + if a: + if len(header['title']): + # the non-ascii character + # in the string below is a + # punctuation dash. (TeX ---) + header['title'] = header['title'] + ' — ' + a + else: + header['subtitle'] = a + else: + header['title'] = a + if g == 'M': # Meter + if a == 'C': + if not state.common_time: + state.common_time = 1 + voices_append (" \\override Staff.TimeSignature #\'style = #'C\n") + a = '4/4' + if a == 'C|': + if not state.common_time: + state.common_time = 1 + voices_append ("\\override Staff.TimeSignature #\'style = #'C\n") + a = '2/2' + if not length_specified: + set_default_len_from_time_sig (a) + else: + length_specified = 0 + if not a == 'none': + voices_append ('\\time %s' % a) + state.next_bar = '' + if g == 'K': # KEY + a = check_clef(a) + if a: + m = re.match ('^([^ \t]*) *(.*)$', a) # seperate clef info + if m: + # there may or may not be a space + # between the key letter and the mode + if key_lookup.has_key(m.group(2)[0:3]): + key_info = m.group(1) + m.group(2)[0:3] + clef_info = m.group(2)[4:] + else: + key_info = m.group(1) + clef_info = m.group(2) + __main__.global_key = compute_key (key_info) + k = lily_key (key_info) + if k: + voices_append ('\\key %s' % k) + check_clef(clef_info) + else: + __main__.global_key = compute_key (a) + k = lily_key (a) + if k: + voices_append ('\\key %s \\major' % k) + if g == 'N': # Notes + header ['footnotes'] = header['footnotes'] + '\\\\\\\\' + a + if g == 'O': # Origin + header ['origin'] = a + if g == 'X': # Reference Number + header ['crossRefNumber'] = a + if g == 'A': # Area + header ['area'] = a + if g == 'H': # History + header_append ('history', a) + if g == 'B': # Book + header ['book'] = a + if g == 'C': # Composer + if header.has_key('composer'): + if a: + header['composer'] = header['composer'] + '\\\\\\\\' + a + else: + header['composer'] = a + if g == 'S': + header ['subtitle'] = a + if g == 'L': # Default note length + set_default_length (ln) + if g == 'V': # Voice + voice = re.sub (' .*$', '', a) + rest = re.sub ('^[^ \t]* *', '', a) + if state.next_bar: + voices_append(state.next_bar) + state.next_bar = '' + select_voice (voice, rest) + if g == 'W': # Words + lyrics_append(a) + if g == 'w': # vocals + slyrics_append (a) + if g == 'Q': #tempo + try_parse_q (a) + return '' + return ln # we use in this order specified accidental, active accidental for bar, # active accidental for key def pitch_to_lilypond_name (name, acc, bar_acc, key): - s = '' - if acc == UNDEF: - if not nobarlines: - acc = bar_acc - if acc == UNDEF: - acc = key - if acc == -1: - s = 'es' - elif acc == 1: - s = 'is' - - if name > 4: - name = name -7 - return(chr (name + ord('c')) + s) + s = '' + if acc == UNDEF: + if not nobarlines: + acc = bar_acc + if acc == UNDEF: + acc = key + if acc == -1: + s = 'es' + elif acc == 1: + s = 'is' + + if name > 4: + name = name -7 + return(chr (name + ord('c')) + s) def octave_to_lilypond_quotes (o): - o = o + 2 - s ='' - if o < 0: - o = -o - s=',' - else: - s ='\'' + o = o + 2 + s ='' + if o < 0: + o = -o + s=',' + else: + s ='\'' - return s * o + return s * o def parse_num (str): - durstr = '' - while str and str[0] in DIGITS: - durstr = durstr + str[0] - str = str[1:] + durstr = '' + while str and str[0] in DIGITS: + durstr = durstr + str[0] + str = str[1:] - n = None - if durstr: - n =string.atoi (durstr) - return (str,n) + n = None + if durstr: + n =string.atoi (durstr) + return (str,n) def duration_to_lilypond_duration (multiply_tup, defaultlen, dots): - base = 1 - # (num / den) / defaultlen < 1/base - while base * multiply_tup[0] < multiply_tup[1]: - base = base * 2 - if base == 1: - if (multiply_tup[0] / multiply_tup[1]) == 2: - base = '\\breve' - if (multiply_tup[0] / multiply_tup[1]) == 3: - base = '\\breve' - dots = 1 - if (multiply_tup[0] / multiply_tup[1]) == 4: - base = '\longa' - return '%s%s' % ( base, '.'* dots) + base = 1 + # (num / den) / defaultlen < 1/base + while base * multiply_tup[0] < multiply_tup[1]: + base = base * 2 + if base == 1: + if (multiply_tup[0] / multiply_tup[1]) == 2: + base = '\\breve' + if (multiply_tup[0] / multiply_tup[1]) == 3: + base = '\\breve' + dots = 1 + if (multiply_tup[0] / multiply_tup[1]) == 4: + base = '\longa' + return '%s%s' % ( base, '.'* dots) class Parser_state: - def __init__ (self): - self.in_acc = {} - self.next_articulation = '' - self.next_bar = '' - self.next_dots = 0 - self.next_den = 1 - self.parsing_tuplet = 0 - self.plus_chord = 0 - self.base_octave = 0 - self.common_time = 0 - self.parsing_beam = 0 + def __init__ (self): + self.in_acc = {} + self.next_articulation = '' + self.next_bar = '' + self.next_dots = 0 + self.next_den = 1 + self.parsing_tuplet = 0 + self.plus_chord = 0 + self.base_octave = 0 + self.common_time = 0 + self.parsing_beam = 0 # return (str, num,den,dots) def parse_duration (str, parser_state): - num = 0 - den = parser_state.next_den - parser_state.next_den = 1 - - (str, num) = parse_num (str) - if not num: - num = 1 - if len(str): - if str[0] == '/': - if len(str[0]): - while str[:1] == '/': - str= str[1:] - d = 2 - if str[0] in DIGITS: - (str, d) =parse_num (str) - - den = den * d - - den = den * default_len - - current_dots = parser_state.next_dots - parser_state.next_dots = 0 - if re.match ('[ \t]*[<>]', str): - while str[0] in HSPACE: - str = str[1:] - while str[0] == '>': - str = str [1:] - current_dots = current_dots + 1 - parser_state.next_den = parser_state.next_den * 2 - - while str[0] == '<': - str = str [1:] - den = den * 2 - parser_state.next_dots = parser_state.next_dots + 1 - - - - try_dots = [3, 2, 1] - for d in try_dots: - f = 1 << d - multiplier = (2*f-1) - if num % multiplier == 0 and den % f == 0: - num = num / multiplier - den = den / f - current_dots = current_dots + d - - return (str, num,den,current_dots) + num = 0 + den = parser_state.next_den + parser_state.next_den = 1 + + (str, num) = parse_num (str) + if not num: + num = 1 + if len(str): + if str[0] == '/': + if len(str[0]): + while str[:1] == '/': + str= str[1:] + d = 2 + if str[0] in DIGITS: + (str, d) =parse_num (str) + + den = den * d + + den = den * default_len + + current_dots = parser_state.next_dots + parser_state.next_dots = 0 + if re.match ('[ \t]*[<>]', str): + while str[0] in HSPACE: + str = str[1:] + while str[0] == '>': + str = str [1:] + current_dots = current_dots + 1 + parser_state.next_den = parser_state.next_den * 2 + + while str[0] == '<': + str = str [1:] + den = den * 2 + parser_state.next_dots = parser_state.next_dots + 1 + + + + try_dots = [3, 2, 1] + for d in try_dots: + f = 1 << d + multiplier = (2*f-1) + if num % multiplier == 0 and den % f == 0: + num = num / multiplier + den = den / f + current_dots = current_dots + d + + return (str, num,den,current_dots) def try_parse_rest (str, parser_state): - if not str or str[0] <> 'z' and str[0] <> 'x': - return str + if not str or str[0] <> 'z' and str[0] <> 'x': + return str - __main__.lyric_idx = -1 + __main__.lyric_idx = -1 - if parser_state.next_bar: - voices_append(parser_state.next_bar) - parser_state.next_bar = '' + if parser_state.next_bar: + voices_append(parser_state.next_bar) + parser_state.next_bar = '' - if str[0] == 'z': - rest = 'r' - else: - rest = 's' - str = str[1:] + if str[0] == 'z': + rest = 'r' + else: + rest = 's' + str = str[1:] - (str, num,den,d) = parse_duration (str, parser_state) - voices_append ('%s%s' % (rest, duration_to_lilypond_duration ((num,den), default_len, d))) - if parser_state.next_articulation: - voices_append (parser_state.next_articulation) - parser_state.next_articulation = '' + (str, num,den,d) = parse_duration (str, parser_state) + voices_append ('%s%s' % (rest, duration_to_lilypond_duration ((num,den), default_len, d))) + if parser_state.next_articulation: + voices_append (parser_state.next_articulation) + parser_state.next_articulation = '' - return str + return str artic_tbl = { - '.' : '-.', - 'T' : '^\\trill', - 'H' : '^\\fermata', - 'u' : '^\\upbow', - 'K' : '^\\ltoe', - 'k' : '^\\accent', - 'M' : '^\\tenuto', - '~' : '^"~" ', - 'J' : '', # ignore slide - 'R' : '', # ignore roll - 'v' : '^\\downbow' + '.' : '-.', + 'T' : '^\\trill', + 'H' : '^\\fermata', + 'u' : '^\\upbow', + 'K' : '^\\ltoe', + 'k' : '^\\accent', + 'M' : '^\\tenuto', + '~' : '^"~" ', + 'J' : '', # ignore slide + 'R' : '', # ignore roll + 'v' : '^\\downbow' } - + def try_parse_articulation (str, state): - while str and artic_tbl.has_key(str[:1]): - state.next_articulation = state.next_articulation + artic_tbl[str[:1]] - if not artic_tbl[str[:1]]: - sys.stderr.write("Warning: ignoring `%s'\n" % str[:1] ) - - str = str[1:] - - - - # s7m2 input doesnt care about spaces - if re.match('[ \t]*\(', str): - str = string.lstrip (str) - - slur_begin =0 - while str[:1] =='(' and str[1] not in DIGITS: - slur_begin = slur_begin + 1 - state.next_articulation = state.next_articulation + '(' - str = str[1:] - - return str - + while str and artic_tbl.has_key(str[:1]): + state.next_articulation = state.next_articulation + artic_tbl[str[:1]] + if not artic_tbl[str[:1]]: + sys.stderr.write("Warning: ignoring `%s'\n" % str[:1] ) + + str = str[1:] + + + + # s7m2 input doesnt care about spaces + if re.match('[ \t]*\(', str): + str = string.lstrip (str) + + slur_begin =0 + while str[:1] =='(' and str[1] not in DIGITS: + slur_begin = slur_begin + 1 + state.next_articulation = state.next_articulation + '(' + str = str[1:] + + return str + # # remember accidental for rest of bar # def set_bar_acc(note, octave, acc, state): - if acc == UNDEF: - return - n_oct = note + octave * 7 - state.in_acc[n_oct] = acc + if acc == UNDEF: + return + n_oct = note + octave * 7 + state.in_acc[n_oct] = acc # get accidental set in this bar or UNDEF if not set def get_bar_acc(note, octave, state): - n_oct = note + octave * 7 - if state.in_acc.has_key(n_oct): - return(state.in_acc[n_oct]) - else: - return(UNDEF) + n_oct = note + octave * 7 + if state.in_acc.has_key(n_oct): + return(state.in_acc[n_oct]) + else: + return(UNDEF) def clear_bar_acc(state): - for k in state.in_acc.keys(): - del state.in_acc[k] - + for k in state.in_acc.keys(): + del state.in_acc[k] + # if we are parsing a beam, close it off def close_beam_state(state): - if state.parsing_beam and global_options.beams: - state.parsing_beam = 0 - voices_append_back( ']' ) + if state.parsing_beam and global_options.beams: + state.parsing_beam = 0 + voices_append_back( ']' ) - + # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP ! def try_parse_note (str, parser_state): - mud = '' - - slur_begin =0 - if not str: - return str - - articulation ='' - acc = UNDEF - if str[0] in '^=_': - c = str[0] - str = str[1:] - if c == '^': - acc = 1 - if c == '=': - acc = 0 - if c == '_': - acc = -1 - - octave = parser_state.base_octave - if str[0] in "ABCDEFG": - str = string.lower (str[0]) + str[1:] - octave = octave - 1 - - - notename = 0 - if str[0] in "abcdefg": - notename = (ord(str[0]) - ord('a') + 5)%7 - str = str[1:] - else: - return str # failed; not a note! - - - __main__.lyric_idx = -1 - - if parser_state.next_bar: - voices_append(parser_state.next_bar) - parser_state.next_bar = '' - - while str[0] == ',': - octave = octave - 1 - str = str[1:] - while str[0] == '\'': - octave = octave + 1 - str = str[1:] - - (str, num,den,current_dots) = parse_duration (str, parser_state) - - if re.match('[ \t]*\)', str): - str = string.lstrip (str) - - slur_end =0 - while str[:1] ==')': - slur_end = slur_end + 1 - str = str[1:] - - - bar_acc = get_bar_acc(notename, octave, parser_state) - pit = pitch_to_lilypond_name(notename, acc, bar_acc, global_key[notename]) - oct = octave_to_lilypond_quotes (octave) - if acc != UNDEF and (acc == global_key[notename] or acc == bar_acc): - mod='!' - else: - mod = '' - voices_append ("%s%s%s%s" % - (pit, oct, mod, - duration_to_lilypond_duration ((num,den), default_len, current_dots))) - - set_bar_acc(notename, octave, acc, parser_state) - if parser_state.next_articulation: - articulation = articulation + parser_state.next_articulation - parser_state.next_articulation = '' - - voices_append (articulation) - - if parser_state.parsing_tuplet: - parser_state.parsing_tuplet = parser_state.parsing_tuplet - 1 - if not parser_state.parsing_tuplet: - voices_append ("}") - if slur_begin: - voices_append ('-(' * slur_begin ) - if slur_end: - voices_append ('-)' *slur_end ) - - if global_options.beams and \ - str[0] in '^=_ABCDEFGabcdefg' and \ - not parser_state.parsing_beam and \ - not parser_state.parsing_tuplet: - parser_state.parsing_beam = 1 - voices_append_back( '[' ) - - return str + mud = '' + + slur_begin =0 + if not str: + return str + + articulation ='' + acc = UNDEF + if str[0] in '^=_': + c = str[0] + str = str[1:] + if c == '^': + acc = 1 + if c == '=': + acc = 0 + if c == '_': + acc = -1 + + octave = parser_state.base_octave + if str[0] in "ABCDEFG": + str = string.lower (str[0]) + str[1:] + octave = octave - 1 + + + notename = 0 + if str[0] in "abcdefg": + notename = (ord(str[0]) - ord('a') + 5)%7 + str = str[1:] + else: + return str # failed; not a note! + + + __main__.lyric_idx = -1 + + if parser_state.next_bar: + voices_append(parser_state.next_bar) + parser_state.next_bar = '' + + while str[0] == ',': + octave = octave - 1 + str = str[1:] + while str[0] == '\'': + octave = octave + 1 + str = str[1:] + + (str, num,den,current_dots) = parse_duration (str, parser_state) + + if re.match('[ \t]*\)', str): + str = string.lstrip (str) + + slur_end =0 + while str[:1] ==')': + slur_end = slur_end + 1 + str = str[1:] + + + bar_acc = get_bar_acc(notename, octave, parser_state) + pit = pitch_to_lilypond_name(notename, acc, bar_acc, global_key[notename]) + oct = octave_to_lilypond_quotes (octave) + if acc != UNDEF and (acc == global_key[notename] or acc == bar_acc): + mod='!' + else: + mod = '' + voices_append ("%s%s%s%s" % + (pit, oct, mod, + duration_to_lilypond_duration ((num,den), default_len, current_dots))) + + set_bar_acc(notename, octave, acc, parser_state) + if parser_state.next_articulation: + articulation = articulation + parser_state.next_articulation + parser_state.next_articulation = '' + + voices_append (articulation) + + if parser_state.parsing_tuplet: + parser_state.parsing_tuplet = parser_state.parsing_tuplet - 1 + if not parser_state.parsing_tuplet: + voices_append ("}") + if slur_begin: + voices_append ('-(' * slur_begin ) + if slur_end: + voices_append ('-)' *slur_end ) + + if global_options.beams and \ + str[0] in '^=_ABCDEFGabcdefg' and \ + not parser_state.parsing_beam and \ + not parser_state.parsing_tuplet: + parser_state.parsing_beam = 1 + voices_append_back( '[' ) + + return str def junk_space (str,state): - while str and str[0] in '\t\n\r ': - str = str[1:] - close_beam_state(state) + while str and str[0] in '\t\n\r ': + str = str[1:] + close_beam_state(state) - return str + return str def try_parse_guitar_chord (str, state): - if str[:1] =='"': - str = str[1:] - gc = '' - if str[0] == '_' or (str[0] == '^'): - position = str[0] - str = str[1:] - else: - position = '^' - while str and str[0] != '"': - gc = gc + str[0] - str = str[1:] - - if str: - str = str[1:] - gc = re.sub('#', '\\#', gc) # escape '#'s - state.next_articulation = ("%c\"%s\"" % (position, gc)) \ - + state.next_articulation - return str + if str[:1] =='"': + str = str[1:] + gc = '' + if str[0] == '_' or (str[0] == '^'): + position = str[0] + str = str[1:] + else: + position = '^' + while str and str[0] != '"': + gc = gc + str[0] + str = str[1:] + + if str: + str = str[1:] + gc = re.sub('#', '\\#', gc) # escape '#'s + state.next_articulation = ("%c\"%s\"" % (position, gc)) \ + + state.next_articulation + return str def try_parse_escape (str): - if not str or str [0] != '\\': - return str - - str = str[1:] - if str[:1] =='K': - key_table = compute_key () - return str + if not str or str [0] != '\\': + return str + + str = str[1:] + if str[:1] =='K': + key_table = compute_key () + return str # # |] thin-thick double bar line @@ -1105,17 +1105,17 @@ old_bar_dict = { '|' : '|' } bar_dict = { - '|]' : '\\bar "|."', - '||' : '\\bar "||"', - '[|' : '\\bar "||"', - ':|' : '}', - '|:' : '\\repeat volta 2 {', - '::' : '} \\repeat volta 2 {', - '|1' : '} \\alternative{{', - '|2' : '} {', - ':|2' : '} {', - '|' : '\\bar "|"' - } +'|]' : '\\bar "|."', +'||' : '\\bar "||"', +'[|' : '\\bar "||"', +':|' : '}', +'|:' : '\\repeat volta 2 {', +'::' : '} \\repeat volta 2 {', +'|1' : '} \\alternative{{', +'|2' : '} {', +':|2' : '} {', +'|' : '\\bar "|"' + } warn_about = ['|:', '::', ':|', '|1', ':|2', '|2'] @@ -1127,137 +1127,137 @@ doing_alternative = [''] * 8 using_old = '' def try_parse_bar (str,state): - global in_repeat, doing_alternative, using_old - do_curly = '' - bs = None - if current_voice_idx < 0: - select_voice ('default', '') - # first try the longer one - for trylen in [3,2,1]: - if str[:trylen] and bar_dict.has_key (str[:trylen]): - s = str[:trylen] - if using_old: - bs = "\\bar \"%s\"" % old_bar_dict[s] - else: - bs = "%s" % bar_dict[s] - str = str[trylen:] - if s in alternative_opener: - if not in_repeat[current_voice_idx]: - using_old = 't' - bs = "\\bar \"%s\"" % old_bar_dict[s] - else: - doing_alternative[current_voice_idx] = 't' - - if s in repeat_ender: - if not in_repeat[current_voice_idx]: - sys.stderr.write("Warning: inserting repeat to beginning of notes.\n") - repeat_prepend() - in_repeat[current_voice_idx] = '' - else: - if doing_alternative[current_voice_idx]: - do_curly = 't' - if using_old: - bs = "\\bar \"%s\"" % old_bar_dict[s] - else: - bs = bar_dict[s] - doing_alternative[current_voice_idx] = '' - in_repeat[current_voice_idx] = '' - if s in repeat_opener: - in_repeat[current_voice_idx] = 't' - if using_old: - bs = "\\bar \"%s\"" % old_bar_dict[s] - else: - bs = bar_dict[s] - break - if str[:1] == '|': - state.next_bar = '|\n' - str = str[1:] - clear_bar_acc(state) - close_beam_state(state) - - if bs <> None or state.next_bar != '': - if state.parsing_tuplet: - state.parsing_tuplet =0 - voices_append ('} ') - - if bs <> None: - clear_bar_acc(state) - close_beam_state(state) - voices_append (bs) - if do_curly != '': - voices_append("} }") - do_curly = '' - return str + global in_repeat, doing_alternative, using_old + do_curly = '' + bs = None + if current_voice_idx < 0: + select_voice ('default', '') + # first try the longer one + for trylen in [3,2,1]: + if str[:trylen] and bar_dict.has_key (str[:trylen]): + s = str[:trylen] + if using_old: + bs = "\\bar \"%s\"" % old_bar_dict[s] + else: + bs = "%s" % bar_dict[s] + str = str[trylen:] + if s in alternative_opener: + if not in_repeat[current_voice_idx]: + using_old = 't' + bs = "\\bar \"%s\"" % old_bar_dict[s] + else: + doing_alternative[current_voice_idx] = 't' + + if s in repeat_ender: + if not in_repeat[current_voice_idx]: + sys.stderr.write("Warning: inserting repeat to beginning of notes.\n") + repeat_prepend() + in_repeat[current_voice_idx] = '' + else: + if doing_alternative[current_voice_idx]: + do_curly = 't' + if using_old: + bs = "\\bar \"%s\"" % old_bar_dict[s] + else: + bs = bar_dict[s] + doing_alternative[current_voice_idx] = '' + in_repeat[current_voice_idx] = '' + if s in repeat_opener: + in_repeat[current_voice_idx] = 't' + if using_old: + bs = "\\bar \"%s\"" % old_bar_dict[s] + else: + bs = bar_dict[s] + break + if str[:1] == '|': + state.next_bar = '|\n' + str = str[1:] + clear_bar_acc(state) + close_beam_state(state) + + if bs <> None or state.next_bar != '': + if state.parsing_tuplet: + state.parsing_tuplet =0 + voices_append ('} ') + + if bs <> None: + clear_bar_acc(state) + close_beam_state(state) + voices_append (bs) + if do_curly != '': + voices_append("} }") + do_curly = '' + return str def try_parse_tie (str): - if str[:1] =='-': - str = str[1:] - voices_append (' ~ ') - return str + if str[:1] =='-': + str = str[1:] + voices_append (' ~ ') + return str def bracket_escape (str, state): - m = re.match ( '^([^\]]*)] *(.*)$', str) - if m: - cmd = m.group (1) - str = m.group (2) - try_parse_header_line (cmd, state) - return str + m = re.match ( '^([^\]]*)] *(.*)$', str) + if m: + cmd = m.group (1) + str = m.group (2) + try_parse_header_line (cmd, state) + return str def try_parse_chord_delims (str, state): - if str[:1] =='[': - str = str[1:] - if re.match('[A-Z]:', str): # bracket escape - return bracket_escape(str, state) - if state.next_bar: - voices_append(state.next_bar) - state.next_bar = '' - voices_append ('<<') - - if str[:1] == '+': - str = str[1:] - if state.plus_chord: - voices_append ('>>') - state.plus_chord = 0 - else: - if state.next_bar: - voices_append(state.next_bar) - state.next_bar = '' - voices_append ('<<') - state.plus_chord = 1 - - ch = '' - if str[:1] ==']': - str = str[1:] - ch = '>>' - - end = 0 - while str[:1] ==')': - end = end + 1 - str = str[1:] - - - voices_append ("\\spanrequest \\stop \"slur\"" * end) - voices_append (ch) - return str + if str[:1] =='[': + str = str[1:] + if re.match('[A-Z]:', str): # bracket escape + return bracket_escape(str, state) + if state.next_bar: + voices_append(state.next_bar) + state.next_bar = '' + voices_append ('<<') + + if str[:1] == '+': + str = str[1:] + if state.plus_chord: + voices_append ('>>') + state.plus_chord = 0 + else: + if state.next_bar: + voices_append(state.next_bar) + state.next_bar = '' + voices_append ('<<') + state.plus_chord = 1 + + ch = '' + if str[:1] ==']': + str = str[1:] + ch = '>>' + + end = 0 + while str[:1] ==')': + end = end + 1 + str = str[1:] + + + voices_append ("\\spanrequest \\stop \"slur\"" * end) + voices_append (ch) + return str def try_parse_grace_delims (str, state): - if str[:1] =='{': - if state.next_bar: - voices_append(state.next_bar) - state.next_bar = '' - str = str[1:] - voices_append ('\\grace { ') + if str[:1] =='{': + if state.next_bar: + voices_append(state.next_bar) + state.next_bar = '' + str = str[1:] + voices_append ('\\grace { ') - if str[:1] =='}': - str = str[1:] - voices_append ('}') + if str[:1] =='}': + str = str[1:] + voices_append ('}') - return str + return str def try_parse_comment (str): - global nobarlines - if (str[0] == '%'): - if str[0:5] == '%MIDI': + global nobarlines + if (str[0] == '%'): + if str[0:5] == '%MIDI': #the nobarlines option is necessary for an abc to lilypond translator for #exactly the same reason abc2midi needs it: abc requires the user to enter #the note that will be printed, and MIDI and lilypond expect entry of the @@ -1271,77 +1271,77 @@ def try_parse_comment (str): #convention, such as most music written before 1700, or ethnic music in #non-western scales, it is necessary to be able to tell a translator that #the barlines should not affect its interpretation of the pitch. - if (string.find(str,'nobarlines') > 0): - nobarlines = 1 - elif str[0:3] == '%LY': - p = string.find(str, 'voices') - if (p > -1): - voices_append(str[p+7:]) - voices_append("\n") - p = string.find(str, 'slyrics') - if (p > -1): - slyrics_append(str[p+8:]) - -#write other kinds of appending if we ever need them. - return str + if (string.find(str,'nobarlines') > 0): + nobarlines = 1 + elif str[0:3] == '%LY': + p = string.find(str, 'voices') + if (p > -1): + voices_append(str[p+7:]) + voices_append("\n") + p = string.find(str, 'slyrics') + if (p > -1): + slyrics_append(str[p+8:]) + +#write other kinds of appending if we ever need them. + return str lineno = 0 happy_count = 100 def parse_file (fn): - f = open (fn) - ls = f.readlines () - ls = map (lambda x: re.sub ("\r$", '', x), ls) - - select_voice('default', '') - global lineno - lineno = 0 - sys.stderr.write ("Line ... ") - sys.stderr.flush () - __main__.state = state_list[current_voice_idx] - - for ln in ls: - lineno = lineno + 1 - - if not (lineno % happy_count): - sys.stderr.write ('[%d]'% lineno) - sys.stderr.flush () - m = re.match ('^([^%]*)%(.*)$',ln) # add comments to current voice - if m: - if m.group(2): - try_parse_comment(m.group(2)) - voices_append ('%% %s\n' % m.group(2)) - ln = m.group (1) - - orig_ln = ln - - ln = try_parse_header_line (ln, state) - - # Try nibbling characters off until the line doesn't change. - prev_ln = '' - while ln != prev_ln: - prev_ln = ln - ln = try_parse_chord_delims (ln, state) - ln = try_parse_rest (ln, state) - ln = try_parse_articulation (ln,state) - ln = try_parse_note (ln, state) - ln = try_parse_bar (ln, state) - ln = try_parse_tie (ln) - ln = try_parse_escape (ln) - ln = try_parse_guitar_chord (ln, state) - ln = try_parse_tuplet_begin (ln, state) - ln = try_parse_group_end (ln, state) - ln = try_parse_grace_delims (ln, state) - ln = junk_space (ln, state) - - if ln: - error ("%s: %d: Huh? Don't understand\n" % (fn, lineno)) - left = orig_ln[0:-len (ln)] - sys.stderr.write (left + '\n') - sys.stderr.write (' ' * len (left) + ln + '\n') + f = open (fn) + ls = f.readlines () + ls = map (lambda x: re.sub ("\r$", '', x), ls) + + select_voice('default', '') + global lineno + lineno = 0 + sys.stderr.write ("Line ... ") + sys.stderr.flush () + __main__.state = state_list[current_voice_idx] + + for ln in ls: + lineno = lineno + 1 + + if not (lineno % happy_count): + sys.stderr.write ('[%d]'% lineno) + sys.stderr.flush () + m = re.match ('^([^%]*)%(.*)$',ln) # add comments to current voice + if m: + if m.group(2): + try_parse_comment(m.group(2)) + voices_append ('%% %s\n' % m.group(2)) + ln = m.group (1) + + orig_ln = ln + + ln = try_parse_header_line (ln, state) + + # Try nibbling characters off until the line doesn't change. + prev_ln = '' + while ln != prev_ln: + prev_ln = ln + ln = try_parse_chord_delims (ln, state) + ln = try_parse_rest (ln, state) + ln = try_parse_articulation (ln,state) + ln = try_parse_note (ln, state) + ln = try_parse_bar (ln, state) + ln = try_parse_tie (ln) + ln = try_parse_escape (ln) + ln = try_parse_guitar_chord (ln, state) + ln = try_parse_tuplet_begin (ln, state) + ln = try_parse_group_end (ln, state) + ln = try_parse_grace_delims (ln, state) + ln = junk_space (ln, state) + + if ln: + error ("%s: %d: Huh? Don't understand\n" % (fn, lineno)) + left = orig_ln[0:-len (ln)] + sys.stderr.write (left + '\n') + sys.stderr.write (' ' * len (left) + ln + '\n') def identify(): - sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version)) + sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version)) authors = """ Written by Han-Wen Nienhuys , Laura Conrad @@ -1349,24 +1349,24 @@ Written by Han-Wen Nienhuys , Laura Conrad """ def print_version (): - print r"""abc2ly (GNU lilypond) %s""" % version + print r"""abc2ly (GNU lilypond) %s""" % version def get_option_parser (): - p = ly.get_option_parser (usage='abc2ly [OPTIONS] FILE', - version="abc2ly (LilyPond) @TOPLEVEL_VERSION@", - description=_('''This program converts ABC music files (see + p = ly.get_option_parser (usage='abc2ly [OPTIONS] FILE', + version="abc2ly (LilyPond) @TOPLEVEL_VERSION@", + description=_('''This program converts ABC music files (see http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt) to LilyPond input.''')) - p.add_option ('-o', '--output', metavar='FILE',help=_("set output filename to FILE"), - action='store') - p.add_option ('-s', '--strict', help=_("be strict about succes"), - action='store_true') - p.add_option ('-b', '--beams', help=_("preserve ABC's notion of beams")) - p.add_option_group ('bugs', - description='''Report bugs via http://post.gmane.org/post.php''' - '''?group=gmane.comp.gnu.lilypond.bugs\n''') - - return p + p.add_option ('-o', '--output', metavar='FILE',help=_("set output filename to FILE"), + action='store') + p.add_option ('-s', '--strict', help=_("be strict about succes"), + action='store_true') + p.add_option ('-b', '--beams', help=_("preserve ABC's notion of beams")) + p.add_option_group ('bugs', + description='''Report bugs via http://post.gmane.org/post.php''' + '''?group=gmane.comp.gnu.lilypond.bugs\n''') + + return p option_parser = get_option_parser() @@ -1377,26 +1377,26 @@ identify() header['tagline'] = 'Lily was here %s -- automatically converted from ABC' % version for f in files: - if f == '-': - f = '' + if f == '-': + f = '' - sys.stderr.write ('Parsing `%s\'...\n' % f) - parse_file (f) + sys.stderr.write ('Parsing `%s\'...\n' % f) + parse_file (f) - if not global_options.output: - global_options.output = os.path.basename (os.path.splitext (f)[0]) + ".ly" - sys.stderr.write ('lilypond output to: `%s\'...' % global_options.output) - outf = open (global_options.output, 'w') + if not global_options.output: + global_options.output = os.path.basename (os.path.splitext (f)[0]) + ".ly" + sys.stderr.write ('lilypond output to: `%s\'...' % global_options.output) + outf = open (global_options.output, 'w') # don't substitute @VERSION@. We want this to reflect # the last version that was verified to work. - outf.write ('\\version "2.7.40"\n') - -# dump_global (outf) - dump_header (outf, header) - dump_slyrics (outf) - dump_voices (outf) - dump_score (outf) - dump_lyrics (outf) - sys.stderr.write ('\n') - + outf.write ('\\version "2.7.40"\n') + +# dump_global (outf) + dump_header (outf, header) + dump_slyrics (outf) + dump_voices (outf) + dump_score (outf) + dump_lyrics (outf) + sys.stderr.write ('\n') + diff --git a/scripts/etf2ly.py b/scripts/etf2ly.py index 18a33a4324..5fb09c7333 100644 --- a/scripts/etf2ly.py +++ b/scripts/etf2ly.py @@ -37,7 +37,7 @@ program_name = sys.argv[0] version = '@TOPLEVEL_VERSION@' if version == '@' + 'TOPLEVEL_VERSION' + '@': - version = '(unknown version)' # uGUHGUHGHGUGH + version = '(unknown version)' # uGUHGUHGHGUGH ################################################################ @@ -45,1189 +45,1189 @@ if version == '@' + 'TOPLEVEL_VERSION' + '@': # libdir = '@local_lilypond_libdir@' if not os.path.isdir (libdir): - libdir = '@lilypond_libdir@' + libdir = '@lilypond_libdir@' # ugh datadir = '@local_lilypond_datadir@' if os.environ.has_key ('LILYPONDPREFIX'): - datadir = os.environ['LILYPONDPREFIX'] - while datadir[-1] == os.sep: - datadir= datadir[:-1] - libdir = datadir.replace ('/share/', '/lib/') + datadir = os.environ['LILYPONDPREFIX'] + while datadir[-1] == os.sep: + datadir= datadir[:-1] + libdir = datadir.replace ('/share/', '/lib/') if os.path.exists (os.path.join (datadir, 'lib/lilypond/@TOPLEVEL_VERSION@/')): - libdir = os.path.join (libdir, 'lib/lilypond/@TOPLEVEL_VERSION@/') - + libdir = os.path.join (libdir, 'lib/lilypond/@TOPLEVEL_VERSION@/') + if os.path.exists (os.path.join (datadir, 'lib/lilypond/current/')): - libdir = os.path.join (libdir, 'lib/lilypond/current/') - + libdir = os.path.join (libdir, 'lib/lilypond/current/') + sys.path.insert (0, os.path.join (libdir, 'python')) # dynamic relocation, for GUB binaries. bindir = os.path.split (sys.argv[0])[0] for p in ['share', 'lib']: - datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % p) - sys.path.insert (0, datadir) + datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % p) + sys.path.insert (0, datadir) ################################################################ import lilylib as ly _ = ly._ - + finale_clefs= ['treble', 'alto', 'tenor', 'bass', 'percussion', 'treble_8', 'bass_8', 'baritone'] def lily_clef (fin): - try: - return finale_clefs[fin] - except IndexError: - sys.stderr.write ( '\nHuh? Found clef number %d\n' % fin) + try: + return finale_clefs[fin] + except IndexError: + sys.stderr.write ( '\nHuh? Found clef number %d\n' % fin) - return 'treble' - - + return 'treble' + + def gulp_file(f): - return open (f).read () + return open (f).read () # notename 0 == central C distances = [0, 2, 4, 5, 7, 9, 11, 12] def semitones (name, acc): - return (name / 7 ) * 12 + distances[name % 7] + acc + return (name / 7 ) * 12 + distances[name % 7] + acc # represent pitches as (notename, alteration), relative to C-major scale def transpose(orig, delta): - (oname, oacc) = orig - (dname, dacc) = delta - - old_pitch =semitones (oname, oacc) - delta_pitch = semitones (dname, dacc) - nname = (oname + dname) - nacc = oacc - new_pitch = semitones (nname, nacc) + (oname, oacc) = orig + (dname, dacc) = delta + + old_pitch =semitones (oname, oacc) + delta_pitch = semitones (dname, dacc) + nname = (oname + dname) + nacc = oacc + new_pitch = semitones (nname, nacc) - nacc = nacc - (new_pitch - old_pitch - delta_pitch) + nacc = nacc - (new_pitch - old_pitch - delta_pitch) - return (nname, nacc) + return (nname, nacc) def interpret_finale_key_sig (finale_id): - """ + """ find the transposition of C-major scale that belongs here. we are not going to insert the correct major/minor, we only want to have the correct number of accidentals """ - p = (0,0) + p = (0,0) - - bank_number = finale_id >> 8 - accidental_bits = finale_id & 0xff + + bank_number = finale_id >> 8 + accidental_bits = finale_id & 0xff - if 0 <= accidental_bits < 7: - while accidental_bits > 0: - p = transpose (p, (4,0)) # a fifth up - accidental_bits = accidental_bits - 1 - elif 248 < accidental_bits <= 255: - while accidental_bits < 256: - p = transpose (p, (3,0)) - accidental_bits = accidental_bits + 1 + if 0 <= accidental_bits < 7: + while accidental_bits > 0: + p = transpose (p, (4,0)) # a fifth up + accidental_bits = accidental_bits - 1 + elif 248 < accidental_bits <= 255: + while accidental_bits < 256: + p = transpose (p, (3,0)) + accidental_bits = accidental_bits + 1 - if bank_number == 1: - # minor scale - p = transpose (p, (5, 0)) - p = (p[0] % 7, p[1]) + if bank_number == 1: + # minor scale + p = transpose (p, (5, 0)) + p = (p[0] % 7, p[1]) - return KeySignature (p, bank_number) + return KeySignature (p, bank_number) # should cache this. def find_scale (keysig): - cscale = map (lambda x: (x,0), range (0,7)) -# print "cscale: ", cscale - ascale = map (lambda x: (x,0), range (-2,5)) -# print "ascale: ", ascale - transposition = keysig.pitch - if keysig.sig_type == 1: - transposition = transpose(transposition, (2, -1)) - transposition = (transposition[0] % 7, transposition[1]) - trscale = map(lambda x, k=transposition: transpose(x, k), ascale) - else: - trscale = map(lambda x, k=transposition: transpose(x, k), cscale) -# print "trscale: ", trscale - return trscale + cscale = map (lambda x: (x,0), range (0,7)) +# print "cscale: ", cscale + ascale = map (lambda x: (x,0), range (-2,5)) +# print "ascale: ", ascale + transposition = keysig.pitch + if keysig.sig_type == 1: + transposition = transpose(transposition, (2, -1)) + transposition = (transposition[0] % 7, transposition[1]) + trscale = map(lambda x, k=transposition: transpose(x, k), ascale) + else: + trscale = map(lambda x, k=transposition: transpose(x, k), cscale) +# print "trscale: ", trscale + return trscale def EDU_to_duration (edu): - log = 1 - d = 4096 - while d > edu: - d = d >> 1 - log = log << 1 - - edu = edu - d - dots = 0 - if edu == d /2: - dots = 1 - elif edu == d*3/4: - dots = 2 - return (log, dots) + log = 1 + d = 4096 + while d > edu: + d = d >> 1 + log = log << 1 + + edu = edu - d + dots = 0 + if edu == d /2: + dots = 1 + elif edu == d*3/4: + dots = 2 + return (log, dots) def rational_to_lily_skip (rat): - (n,d) = rat + (n,d) = rat - basedur = 1 - while d and d % 2 == 0: - basedur = basedur << 1 - d = d >> 1 + basedur = 1 + while d and d % 2 == 0: + basedur = basedur << 1 + d = d >> 1 - str = 's%d' % basedur - if n <> 1: - str = str + '*%d' % n - if d <> 1: - str = str + '/%d' % d + str = 's%d' % basedur + if n <> 1: + str = str + '*%d' % n + if d <> 1: + str = str + '/%d' % d - return str + return str def gcd (a,b): - if b == 0: - return a - c = a - while c: - c = a % b - a = b - b = c - return a - + if b == 0: + return a + c = a + while c: + c = a % b + a = b + b = c + return a + def rat_simplify (r): - (n,d) = r - if d < 0: - d = -d - n = -n - if n == 0: - return (0,1) - else: - g = gcd (n, d) - return (n/g, d/g) - + (n,d) = r + if d < 0: + d = -d + n = -n + if n == 0: + return (0,1) + else: + g = gcd (n, d) + return (n/g, d/g) + def rat_multiply (a,b): - (x,y) = a - (p,q) = b + (x,y) = a + (p,q) = b - return rat_simplify ((x*p, y*q)) + return rat_simplify ((x*p, y*q)) def rat_add (a,b): - (x,y) = a - (p,q) = b + (x,y) = a + (p,q) = b - return rat_simplify ((x*q + p*y, y*q)) + return rat_simplify ((x*q + p*y, y*q)) def rat_neg (a): - (p,q) = a - return (-p,q) + (p,q) = a + return (-p,q) def rat_subtract (a,b ): - return rat_add (a, rat_neg (b)) + return rat_add (a, rat_neg (b)) def lily_notename (tuple2): - (n, a) = tuple2 - nn = chr ((n+ 2)%7 + ord ('a')) + (n, a) = tuple2 + nn = chr ((n+ 2)%7 + ord ('a')) - return nn + {-2:'eses', -1:'es', 0:'', 1:'is', 2:'isis'}[a] + return nn + {-2:'eses', -1:'es', 0:'', 1:'is', 2:'isis'}[a] class Tuplet: - def __init__ (self, number): - self.start_note = number - self.finale = [] - - def append_finale (self, fin): - self.finale.append (fin) - - def factor (self): - n = self.finale[0][2]*self.finale[0][3] - d = self.finale[0][0]*self.finale[0][1] - return rat_simplify( (n, d)) - - def dump_start (self): - return '\\times %d/%d { ' % self.factor () - - def dump_end (self): - return ' }' - - def calculate (self, chords): - edu_left = self.finale[0][0] * self.finale[0][1] - - startch = chords[self.start_note] - c = startch - while c and edu_left: - c.tuplet = self - if c == startch: - c.chord_prefix = self.dump_start () + c.chord_prefix - - if not c.grace: - edu_left = edu_left - c.EDU_duration () - if edu_left == 0: - c.chord_suffix = c.chord_suffix+ self.dump_end () - c = c.next - - if edu_left: - sys.stderr.write ("\nHuh? Tuplet starting at entry %d was too short." % self.start_note) - + def __init__ (self, number): + self.start_note = number + self.finale = [] + + def append_finale (self, fin): + self.finale.append (fin) + + def factor (self): + n = self.finale[0][2]*self.finale[0][3] + d = self.finale[0][0]*self.finale[0][1] + return rat_simplify( (n, d)) + + def dump_start (self): + return '\\times %d/%d { ' % self.factor () + + def dump_end (self): + return ' }' + + def calculate (self, chords): + edu_left = self.finale[0][0] * self.finale[0][1] + + startch = chords[self.start_note] + c = startch + while c and edu_left: + c.tuplet = self + if c == startch: + c.chord_prefix = self.dump_start () + c.chord_prefix + + if not c.grace: + edu_left = edu_left - c.EDU_duration () + if edu_left == 0: + c.chord_suffix = c.chord_suffix+ self.dump_end () + c = c.next + + if edu_left: + sys.stderr.write ("\nHuh? Tuplet starting at entry %d was too short." % self.start_note) + class Slur: - def __init__ (self, number, params): - self.number = number - self.finale = params - - def append_entry (self, finale_e): - self.finale.append (finale_e) - - def calculate (self, chords): - startnote = self.finale[5] - endnote = self.finale[3*6 + 2] - try: - cs = chords[startnote] - ce = chords[endnote] - - if not cs or not ce: - raise IndexError - - cs.note_suffix = '-(' + cs.note_suffix - ce.note_suffix = ce.note_suffix + '-)' - - except IndexError: - sys.stderr.write ("""\nHuh? Slur no %d between (%d,%d), with %d notes""" % (self.number, startnote, endnote, len (chords))) - - + def __init__ (self, number, params): + self.number = number + self.finale = params + + def append_entry (self, finale_e): + self.finale.append (finale_e) + + def calculate (self, chords): + startnote = self.finale[5] + endnote = self.finale[3*6 + 2] + try: + cs = chords[startnote] + ce = chords[endnote] + + if not cs or not ce: + raise IndexError + + cs.note_suffix = '-(' + cs.note_suffix + ce.note_suffix = ce.note_suffix + '-)' + + except IndexError: + sys.stderr.write ("""\nHuh? Slur no %d between (%d,%d), with %d notes""" % (self.number, startnote, endnote, len (chords))) + + class Global_measure: - def __init__ (self, number): - self.timesig = '' - self.number = number - self.key_signature = None - self.scale = None - self.force_break = 0 - - self.repeats = [] - self.finale = [] - - def __str__ (self): - return `self.finale ` - - def set_timesig (self, finale): - (beats, fdur) = finale - (log, dots) = EDU_to_duration (fdur) - - if dots == 1: - beats = beats * 3 - log = log * 2 - dots = 0 - - if dots <> 0: - sys.stderr.write ("\nHuh? Beat duration has dots? (EDU Duration = %d)" % fdur) - self.timesig = (beats, log) - - def length (self): - return self.timesig - - def set_key_sig (self, finale): - k = interpret_finale_key_sig (finale) - self.key_signature = k - self.scale = find_scale (k) - - def set_flags (self,flag1, flag2): - - # flag1 isn't all that interesting. - if flag2 & 0x8000: - self.force_break = 1 - - if flag2 & 0x0008: - self.repeats.append ('start') - if flag2 & 0x0004: - self.repeats.append ('stop') - - if flag2 & 0x0002: - if flag2 & 0x0004: - self.repeats.append ('bracket') + def __init__ (self, number): + self.timesig = '' + self.number = number + self.key_signature = None + self.scale = None + self.force_break = 0 + + self.repeats = [] + self.finale = [] + + def __str__ (self): + return `self.finale ` + + def set_timesig (self, finale): + (beats, fdur) = finale + (log, dots) = EDU_to_duration (fdur) + + if dots == 1: + beats = beats * 3 + log = log * 2 + dots = 0 + + if dots <> 0: + sys.stderr.write ("\nHuh? Beat duration has dots? (EDU Duration = %d)" % fdur) + self.timesig = (beats, log) + + def length (self): + return self.timesig + + def set_key_sig (self, finale): + k = interpret_finale_key_sig (finale) + self.key_signature = k + self.scale = find_scale (k) + + def set_flags (self,flag1, flag2): + + # flag1 isn't all that interesting. + if flag2 & 0x8000: + self.force_break = 1 + + if flag2 & 0x0008: + self.repeats.append ('start') + if flag2 & 0x0004: + self.repeats.append ('stop') + + if flag2 & 0x0002: + if flag2 & 0x0004: + self.repeats.append ('bracket') articulation_dict ={ - 94: '^', - 109: '\\prall', - 84: '\\turn', - 62: '\\mordent', - 85: '\\fermata', - 46: '.', -# 3: '>', -# 18: '\arpeggio' , + 94: '^', + 109: '\\prall', + 84: '\\turn', + 62: '\\mordent', + 85: '\\fermata', + 46: '.', +# 3: '>', +# 18: '\arpeggio' , } class Articulation_def: - def __init__ (self, n, a, b): - self.finale_glyph = a & 0xff - self.number = n - - def dump (self): - try: - return articulation_dict[self.finale_glyph] - except KeyError: - sys.stderr.write ("\nUnknown articulation no. %d" % self.finale_glyph) - sys.stderr.write ("\nPlease add an entry to articulation_dict in the Python source") - return None - + def __init__ (self, n, a, b): + self.finale_glyph = a & 0xff + self.number = n + + def dump (self): + try: + return articulation_dict[self.finale_glyph] + except KeyError: + sys.stderr.write ("\nUnknown articulation no. %d" % self.finale_glyph) + sys.stderr.write ("\nPlease add an entry to articulation_dict in the Python source") + return None + class Articulation: - def __init__ (self, a,b, finale): - self.definition = finale[0] - self.notenumber = b - - def calculate (self, chords, defs): - c = chords[self.notenumber] + def __init__ (self, a,b, finale): + self.definition = finale[0] + self.notenumber = b + + def calculate (self, chords, defs): + c = chords[self.notenumber] - adef = defs[self.definition] - lystr =adef.dump() - if lystr == None: - lystr = '"art"' - sys.stderr.write ("\nThis happened on note %d" % self.notenumber) + adef = defs[self.definition] + lystr =adef.dump() + if lystr == None: + lystr = '"art"' + sys.stderr.write ("\nThis happened on note %d" % self.notenumber) - c.note_suffix = '-' + lystr + c.note_suffix = '-' + lystr class Syllable: - def __init__ (self, a,b , finale): - self.chordnum = b - self.syllable = finale[1] - self.verse = finale[0] - def calculate (self, chords, lyrics): - self.chord = chords[self.chordnum] + def __init__ (self, a,b , finale): + self.chordnum = b + self.syllable = finale[1] + self.verse = finale[0] + def calculate (self, chords, lyrics): + self.chord = chords[self.chordnum] class Verse: - def __init__ (self, number, body): - self.body = body - self.number = number - self.split_syllables () - def split_syllables (self): - ss = re.split ('(-| +)', self.body) - - sep = 0 - syls = [None] - for s in ss: - if sep: - septor = re.sub (" +", "", s) - septor = re.sub ("-", " -- ", septor) - syls[-1] = syls[-1] + septor - else: - syls.append (s) - - sep = not sep - - self.syllables = syls - - def dump (self): - str = '' - line = '' - for s in self.syllables[1:]: - line = line + ' ' + s - if len (line) > 72: - str = str + ' ' * 4 + line + '\n' - line = '' - - str = """\nverse%s = \\lyricmode {\n %s }\n""" % (encodeint (self.number - 1) ,str) - return str + def __init__ (self, number, body): + self.body = body + self.number = number + self.split_syllables () + def split_syllables (self): + ss = re.split ('(-| +)', self.body) + + sep = 0 + syls = [None] + for s in ss: + if sep: + septor = re.sub (" +", "", s) + septor = re.sub ("-", " -- ", septor) + syls[-1] = syls[-1] + septor + else: + syls.append (s) + + sep = not sep + + self.syllables = syls + + def dump (self): + str = '' + line = '' + for s in self.syllables[1:]: + line = line + ' ' + s + if len (line) > 72: + str = str + ' ' * 4 + line + '\n' + line = '' + + str = """\nverse%s = \\lyricmode {\n %s }\n""" % (encodeint (self.number - 1) ,str) + return str class KeySignature: - def __init__(self, pitch, sig_type = 0): - self.pitch = pitch - self.sig_type = sig_type - - def signature_type (self): - if self.sig_type == 1: - return "\\minor" - else: - # really only for 0, but we only know about 0 and 1 - return "\\major" - - def equal (self, other): - if other and other.pitch == self.pitch and other.sig_type == self.sig_type: - return 1 - else: - return 0 - + def __init__(self, pitch, sig_type = 0): + self.pitch = pitch + self.sig_type = sig_type + + def signature_type (self): + if self.sig_type == 1: + return "\\minor" + else: + # really only for 0, but we only know about 0 and 1 + return "\\major" + + def equal (self, other): + if other and other.pitch == self.pitch and other.sig_type == self.sig_type: + return 1 + else: + return 0 + class Measure: - def __init__(self, no): - self.number = no - self.frames = [0] * 4 - self.flags = 0 - self.clef = 0 - self.finale = [] - self.global_measure = None - self.staff = None - self.valid = 1 - - - def valid (self): - return self.valid - def calculate (self): - fs = [] - - if len (self.finale) < 2: - fs = self.finale[0] - - self.clef = fs[1] - self.frames = [fs[0]] - else: - fs = self.finale - self.clef = fs[0] - self.flags = fs[1] - self.frames = fs[2:] + def __init__(self, no): + self.number = no + self.frames = [0] * 4 + self.flags = 0 + self.clef = 0 + self.finale = [] + self.global_measure = None + self.staff = None + self.valid = 1 + + + def valid (self): + return self.valid + def calculate (self): + fs = [] + + if len (self.finale) < 2: + fs = self.finale[0] + + self.clef = fs[1] + self.frames = [fs[0]] + else: + fs = self.finale + self.clef = fs[0] + self.flags = fs[1] + self.frames = fs[2:] class Frame: - def __init__ (self, finale): - self.measure = None - self.finale = finale - (number, start, end ) = finale - self.number = number - self.start = start - self.end = end - self.chords = [] - - def set_measure (self, m): - self.measure = m - - def calculate (self): - - # do grace notes. - lastch = None - in_grace = 0 - for c in self.chords: - if c.grace and (lastch == None or (not lastch.grace)): - c.chord_prefix = r'\grace {' + c.chord_prefix - in_grace = 1 - elif not c.grace and lastch and lastch.grace: - lastch.chord_suffix = lastch.chord_suffix + ' } ' - in_grace = 0 - - lastch = c - - if lastch and in_grace: - lastch.chord_suffix += '}' - - - def dump (self): - str = '%% FR(%d)\n' % self.number - left = self.measure.global_measure.length () - - - ln = '' - for c in self.chords: - add = c.ly_string () + ' ' - if len (ln) + len(add) > 72: - str = str + ln + '\n' - ln = '' - ln = ln + add - left = rat_subtract (left, c.length ()) - - str = str + ln - - if left[0] < 0: - sys.stderr.write ("""\nHuh? Going backwards in frame no %d, start/end (%d,%d)""" % (self.number, self.start, self.end)) - left = (0,1) - if left[0]: - str = str + rational_to_lily_skip (left) - - str = str + ' | \n' - return str - + def __init__ (self, finale): + self.measure = None + self.finale = finale + (number, start, end ) = finale + self.number = number + self.start = start + self.end = end + self.chords = [] + + def set_measure (self, m): + self.measure = m + + def calculate (self): + + # do grace notes. + lastch = None + in_grace = 0 + for c in self.chords: + if c.grace and (lastch == None or (not lastch.grace)): + c.chord_prefix = r'\grace {' + c.chord_prefix + in_grace = 1 + elif not c.grace and lastch and lastch.grace: + lastch.chord_suffix = lastch.chord_suffix + ' } ' + in_grace = 0 + + lastch = c + + if lastch and in_grace: + lastch.chord_suffix += '}' + + + def dump (self): + str = '%% FR(%d)\n' % self.number + left = self.measure.global_measure.length () + + + ln = '' + for c in self.chords: + add = c.ly_string () + ' ' + if len (ln) + len(add) > 72: + str = str + ln + '\n' + ln = '' + ln = ln + add + left = rat_subtract (left, c.length ()) + + str = str + ln + + if left[0] < 0: + sys.stderr.write ("""\nHuh? Going backwards in frame no %d, start/end (%d,%d)""" % (self.number, self.start, self.end)) + left = (0,1) + if left[0]: + str = str + rational_to_lily_skip (left) + + str = str + ' | \n' + return str + def encodeint (i): - return chr ( i + ord ('A')) + return chr ( i + ord ('A')) class Staff: - def __init__ (self, number): - self.number = number - self.measures = [] - - def get_measure (self, no): - fill_list_to (self.measures, no) - - if self.measures[no] == None: - m = Measure (no) - self.measures [no] =m - m.staff = self - - return self.measures[no] - def staffid (self): - return 'staff' + encodeint (self.number - 1) - def layerid (self, l): - return self.staffid() + 'layer%s' % chr (l -1 + ord ('A')) - - def dump_time_key_sigs (self): - k = '' - last_key = None - last_time = None - last_clef = None - gap = (0,1) - for m in self.measures[1:]: - if not m or not m.valid: - continue # ugh. - - g = m.global_measure - e = '' - - if g: - if g.key_signature and not g.key_signature.equal(last_key): - pitch= g.key_signature.pitch - e = e + "\\key %s %s " % (lily_notename (pitch), - g.key_signature.signature_type()) - - last_key = g.key_signature - if last_time <> g.timesig : - e = e + "\\time %d/%d " % g.timesig - last_time = g.timesig - - if 'start' in g.repeats: - e = e + ' \\bar "|:" ' - - - # we don't attempt voltas since they fail easily. - if 0 : # and g.repeat_bar == '|:' or g.repeat_bar == ':|:' or g.bracket: - strs = [] - if g.repeat_bar == '|:' or g.repeat_bar == ':|:' or g.bracket == 'end': - strs.append ('#f') - - - if g.bracket == 'start': - strs.append ('"0."') - - str = string.join (map (lambda x: '(volta %s)' % x, strs)) - - e = e + ' \\set Score.repeatCommands = #\'(%s) ' % str - - if g.force_break: - e = e + ' \\break ' - - if last_clef <> m.clef : - e = e + '\\clef "%s"' % lily_clef (m.clef) - last_clef = m.clef - if e: - if gap <> (0,1): - k = k +' ' + rational_to_lily_skip (gap) + '\n' - gap = (0,1) - k = k + e - - if g: - gap = rat_add (gap, g.length ()) - if 'stop' in g.repeats: - k = k + ' \\bar ":|" ' - - k = '%sglobal = { %s }\n\n ' % (self.staffid (), k) - return k - - def dump (self): - str = '' - - - layerids = [] - for x in range (1,5): # 4 layers. - laystr = '' - last_frame = None - first_frame = None - gap = (0,1) - for m in self.measures[1:]: - if not m or not m.valid: - sys.stderr.write ("Skipping non-existant or invalid measure\n") - continue - - fr = None - try: - fr = m.frames[x] - except IndexError: - sys.stderr.write ("Skipping nonexistent frame %d\n" % x) - laystr = laystr + "%% non existent frame %d (skipped) \n" % x - if fr: - first_frame = fr - if gap <> (0,1): - laystr = laystr +'} %s {\n ' % rational_to_lily_skip (gap) - gap = (0,1) - laystr = laystr + fr.dump () - else: - if m.global_measure : - gap = rat_add (gap, m.global_measure.length ()) - else: - sys.stderr.write ( \ - "No global measure for staff %d measure %d\n" - % (self.number, m.number)) - if first_frame: - l = self.layerid (x) - laystr = '%s = { { %s } }\n\n' % (l, laystr) - str = str + laystr - layerids.append (l) - - str = str + self.dump_time_key_sigs () - stafdef = '\\%sglobal' % self.staffid () - for i in layerids: - stafdef = stafdef + ' \\' + i - - - str = str + '%s = \\context Staff = %s <<\n %s\n >>\n' % \ - (self.staffid (), self.staffid (), stafdef) - return str - - + def __init__ (self, number): + self.number = number + self.measures = [] + + def get_measure (self, no): + fill_list_to (self.measures, no) + + if self.measures[no] == None: + m = Measure (no) + self.measures [no] =m + m.staff = self + + return self.measures[no] + def staffid (self): + return 'staff' + encodeint (self.number - 1) + def layerid (self, l): + return self.staffid() + 'layer%s' % chr (l -1 + ord ('A')) + + def dump_time_key_sigs (self): + k = '' + last_key = None + last_time = None + last_clef = None + gap = (0,1) + for m in self.measures[1:]: + if not m or not m.valid: + continue # ugh. + + g = m.global_measure + e = '' + + if g: + if g.key_signature and not g.key_signature.equal(last_key): + pitch= g.key_signature.pitch + e = e + "\\key %s %s " % (lily_notename (pitch), + g.key_signature.signature_type()) + + last_key = g.key_signature + if last_time <> g.timesig : + e = e + "\\time %d/%d " % g.timesig + last_time = g.timesig + + if 'start' in g.repeats: + e = e + ' \\bar "|:" ' + + + # we don't attempt voltas since they fail easily. + if 0 : # and g.repeat_bar == '|:' or g.repeat_bar == ':|:' or g.bracket: + strs = [] + if g.repeat_bar == '|:' or g.repeat_bar == ':|:' or g.bracket == 'end': + strs.append ('#f') + + + if g.bracket == 'start': + strs.append ('"0."') + + str = string.join (map (lambda x: '(volta %s)' % x, strs)) + + e = e + ' \\set Score.repeatCommands = #\'(%s) ' % str + + if g.force_break: + e = e + ' \\break ' + + if last_clef <> m.clef : + e = e + '\\clef "%s"' % lily_clef (m.clef) + last_clef = m.clef + if e: + if gap <> (0,1): + k = k +' ' + rational_to_lily_skip (gap) + '\n' + gap = (0,1) + k = k + e + + if g: + gap = rat_add (gap, g.length ()) + if 'stop' in g.repeats: + k = k + ' \\bar ":|" ' + + k = '%sglobal = { %s }\n\n ' % (self.staffid (), k) + return k + + def dump (self): + str = '' + + + layerids = [] + for x in range (1,5): # 4 layers. + laystr = '' + last_frame = None + first_frame = None + gap = (0,1) + for m in self.measures[1:]: + if not m or not m.valid: + sys.stderr.write ("Skipping non-existant or invalid measure\n") + continue + + fr = None + try: + fr = m.frames[x] + except IndexError: + sys.stderr.write ("Skipping nonexistent frame %d\n" % x) + laystr = laystr + "%% non existent frame %d (skipped) \n" % x + if fr: + first_frame = fr + if gap <> (0,1): + laystr = laystr +'} %s {\n ' % rational_to_lily_skip (gap) + gap = (0,1) + laystr = laystr + fr.dump () + else: + if m.global_measure : + gap = rat_add (gap, m.global_measure.length ()) + else: + sys.stderr.write ( \ + "No global measure for staff %d measure %d\n" + % (self.number, m.number)) + if first_frame: + l = self.layerid (x) + laystr = '%s = { { %s } }\n\n' % (l, laystr) + str = str + laystr + layerids.append (l) + + str = str + self.dump_time_key_sigs () + stafdef = '\\%sglobal' % self.staffid () + for i in layerids: + stafdef = stafdef + ' \\' + i + + + str = str + '%s = \\context Staff = %s <<\n %s\n >>\n' % \ + (self.staffid (), self.staffid (), stafdef) + return str + + def ziplist (l): - if len (l) < 2: - return [] - else: - return [(l[0], l[1])] + ziplist (l[2:]) + if len (l) < 2: + return [] + else: + return [(l[0], l[1])] + ziplist (l[2:]) class Chord: - def __init__ (self, number, contents): - self.pitches = [] - self.frame = None - self.finale = contents[:7] - - self.notelist = ziplist (contents[7:]) - self.duration = None - self.next = None - self.prev = None - self.number = number - self.note_prefix= '' - self.note_suffix = '' - self.chord_suffix = '' - self.chord_prefix = '' - self.tuplet = None - self.grace = 0 - - def measure (self): - if not self.frame: - return None - return self.frame.measure - - def length (self): - if self.grace: - return (0,1) - - l = (1, self.duration[0]) - - d = 1 << self.duration[1] - - dotfact = rat_subtract ((2,1), (1,d)) - mylen = rat_multiply (dotfact, l) - - if self.tuplet: - mylen = rat_multiply (mylen, self.tuplet.factor()) - return mylen - - - def EDU_duration (self): - return self.finale[2] - def set_duration (self): - self.duration = EDU_to_duration(self.EDU_duration ()) - - def calculate (self): - self.find_realpitch () - self.set_duration () - - flag = self.finale[4] - if Chord.GRACE_MASK & flag: - self.grace = 1 - - - def find_realpitch (self): - - meas = self.measure () - tiestart = 0 - if not meas or not meas.global_measure : - sys.stderr.write ('note %d not in measure\n' % self.number) - elif not meas.global_measure.scale: - sys.stderr.write ('note %d: no scale in this measure.' % self.number) - else: - - for p in self.notelist: - (pitch, flag) = p - - - nib1 = pitch & 0x0f - - if nib1 > 8: - nib1 = -(nib1 - 8) - rest = pitch / 16 - - scale = meas.global_measure.scale - (sn, sa) =scale[rest % 7] - sn = sn + (rest - (rest%7)) + 7 - acc = sa + nib1 - self.pitches.append ((sn, acc)) - tiestart = tiestart or (flag & Chord.TIE_START_MASK) - if tiestart : - self.chord_suffix = self.chord_suffix + ' ~ ' - - REST_MASK = 0x40000000L - TIE_START_MASK = 0x40000000L - GRACE_MASK = 0x00800000L - - def ly_string (self): - s = '' - - rest = '' - - - if not (self.finale[4] & Chord.REST_MASK): - rest = 'r' - - for p in self.pitches: - (n,a) = p - o = n/ 7 - n = n % 7 - - nn = lily_notename ((n,a)) - - if o < 0: - nn = nn + (',' * -o) - elif o > 0: - nn = nn + ('\'' * o) - - if s: - s = s + ' ' - - if rest: - nn = rest - - s = s + nn - - if not self.pitches: - s = 'r' - if len (self.pitches) > 1: - s = '<%s>' % s - - s = s + '%d%s' % (self.duration[0], '.'* self.duration[1]) - s = self.note_prefix + s + self.note_suffix - - s = self.chord_prefix + s + self.chord_suffix - - return s + def __init__ (self, number, contents): + self.pitches = [] + self.frame = None + self.finale = contents[:7] + + self.notelist = ziplist (contents[7:]) + self.duration = None + self.next = None + self.prev = None + self.number = number + self.note_prefix= '' + self.note_suffix = '' + self.chord_suffix = '' + self.chord_prefix = '' + self.tuplet = None + self.grace = 0 + + def measure (self): + if not self.frame: + return None + return self.frame.measure + + def length (self): + if self.grace: + return (0,1) + + l = (1, self.duration[0]) + + d = 1 << self.duration[1] + + dotfact = rat_subtract ((2,1), (1,d)) + mylen = rat_multiply (dotfact, l) + + if self.tuplet: + mylen = rat_multiply (mylen, self.tuplet.factor()) + return mylen + + + def EDU_duration (self): + return self.finale[2] + def set_duration (self): + self.duration = EDU_to_duration(self.EDU_duration ()) + + def calculate (self): + self.find_realpitch () + self.set_duration () + + flag = self.finale[4] + if Chord.GRACE_MASK & flag: + self.grace = 1 + + + def find_realpitch (self): + + meas = self.measure () + tiestart = 0 + if not meas or not meas.global_measure : + sys.stderr.write ('note %d not in measure\n' % self.number) + elif not meas.global_measure.scale: + sys.stderr.write ('note %d: no scale in this measure.' % self.number) + else: + + for p in self.notelist: + (pitch, flag) = p + + + nib1 = pitch & 0x0f + + if nib1 > 8: + nib1 = -(nib1 - 8) + rest = pitch / 16 + + scale = meas.global_measure.scale + (sn, sa) =scale[rest % 7] + sn = sn + (rest - (rest%7)) + 7 + acc = sa + nib1 + self.pitches.append ((sn, acc)) + tiestart = tiestart or (flag & Chord.TIE_START_MASK) + if tiestart : + self.chord_suffix = self.chord_suffix + ' ~ ' + + REST_MASK = 0x40000000L + TIE_START_MASK = 0x40000000L + GRACE_MASK = 0x00800000L + + def ly_string (self): + s = '' + + rest = '' + + + if not (self.finale[4] & Chord.REST_MASK): + rest = 'r' + + for p in self.pitches: + (n,a) = p + o = n/ 7 + n = n % 7 + + nn = lily_notename ((n,a)) + + if o < 0: + nn = nn + (',' * -o) + elif o > 0: + nn = nn + ('\'' * o) + + if s: + s = s + ' ' + + if rest: + nn = rest + + s = s + nn + + if not self.pitches: + s = 'r' + if len (self.pitches) > 1: + s = '<%s>' % s + + s = s + '%d%s' % (self.duration[0], '.'* self.duration[1]) + s = self.note_prefix + s + self.note_suffix + + s = self.chord_prefix + s + self.chord_suffix + + return s def fill_list_to (list, no): - """ + """ Add None to LIST until it contains entry number NO. - """ - while len (list) <= no: - list.extend ([None] * (no - len(list) + 1)) - return list + """ + while len (list) <= no: + list.extend ([None] * (no - len(list) + 1)) + return list def read_finale_value (str): - """ + """ Pry off one value from STR. The value may be $hex, decimal, or "string". Return: (value, rest-of-STR) - """ - while str and str[0] in ' \t\n': - str = str[1:] - - if not str: - return (None,str) - - if str[0] == '$': - str = str [1:] - - hex = '' - while str and str[0] in '0123456789ABCDEF': - hex = hex + str[0] - str = str[1:] - - - return (string.atol (hex, 16), str) - elif str[0] == '"': - str = str[1:] - s = '' - while str and str[0] <> '"': - s = s + str[0] - str = str[1:] - - return (s,str) - elif str[0] in '-0123456789': - dec = '' - while str and str[0] in '-0123456789': - dec = dec + str[0] - str = str[1:] - - return (string.atoi (dec), str) - else: - sys.stderr.write ("can't convert `%s'\n" % str) - return (None, str) - - - - + """ + while str and str[0] in ' \t\n': + str = str[1:] + + if not str: + return (None,str) + + if str[0] == '$': + str = str [1:] + + hex = '' + while str and str[0] in '0123456789ABCDEF': + hex = hex + str[0] + str = str[1:] + + + return (string.atol (hex, 16), str) + elif str[0] == '"': + str = str[1:] + s = '' + while str and str[0] <> '"': + s = s + str[0] + str = str[1:] + + return (s,str) + elif str[0] in '-0123456789': + dec = '' + while str and str[0] in '-0123456789': + dec = dec + str[0] + str = str[1:] + + return (string.atoi (dec), str) + else: + sys.stderr.write ("can't convert `%s'\n" % str) + return (None, str) + + + + def parse_etf_file (fn, tag_dict): - """ Read FN, putting ETF info into - a giant dictionary. The keys of TAG_DICT indicate which tags - to put into the dict. - """ - - sys.stderr.write ('parsing ... ' ) - f = open (fn) - - gulp = re.sub ('[\n\r]+', '\n', f.read ()) - ls = string.split (gulp, '\n^') + """ Read FN, putting ETF info into + a giant dictionary. The keys of TAG_DICT indicate which tags + to put into the dict. + """ + + sys.stderr.write ('parsing ... ' ) + f = open (fn) + + gulp = re.sub ('[\n\r]+', '\n', f.read ()) + ls = string.split (gulp, '\n^') - etf_file_dict = {} - for k in tag_dict.keys (): - etf_file_dict[k] = {} + etf_file_dict = {} + for k in tag_dict.keys (): + etf_file_dict[k] = {} - last_tag = None - last_numbers = None + last_tag = None + last_numbers = None - for l in ls: - m = re.match ('^([a-zA-Z0-9&]+)\(([^)]+)\)', l) - if m and tag_dict.has_key (m.group (1)): - tag = m.group (1) + for l in ls: + m = re.match ('^([a-zA-Z0-9&]+)\(([^)]+)\)', l) + if m and tag_dict.has_key (m.group (1)): + tag = m.group (1) - indices = tuple (map (string.atoi, string.split (m.group (2), ','))) - content = l[m.end (2)+1:] + indices = tuple (map (string.atoi, string.split (m.group (2), ','))) + content = l[m.end (2)+1:] - tdict = etf_file_dict[tag] - if not tdict.has_key (indices): - tdict[indices] = [] + tdict = etf_file_dict[tag] + if not tdict.has_key (indices): + tdict[indices] = [] - parsed = [] + parsed = [] - if tag == 'verse' or tag == 'block': - m2 = re.match ('(.*)\^end', content) - if m2: - parsed = [m2.group (1)] - else: - while content: - (v, content) = read_finale_value (content) - if v <> None: - parsed.append (v) + if tag == 'verse' or tag == 'block': + m2 = re.match ('(.*)\^end', content) + if m2: + parsed = [m2.group (1)] + else: + while content: + (v, content) = read_finale_value (content) + if v <> None: + parsed.append (v) - tdict [indices].extend (parsed) + tdict [indices].extend (parsed) - last_indices = indices - last_tag = tag + last_indices = indices + last_tag = tag - continue + continue # let's not do this: this really confuses when eE happens to be before a ^text. -# if last_tag and last_indices: -# etf_file_dict[last_tag][last_indices].append (l) - - sys.stderr.write ('\n') - return etf_file_dict +# if last_tag and last_indices: +# etf_file_dict[last_tag][last_indices].append (l) + + sys.stderr.write ('\n') + return etf_file_dict - + class Etf_file: - def __init__ (self, name): - self.measures = [None] - self.chords = [None] - self.frames = [None] - self.tuplets = [None] - self.staffs = [None] - self.slurs = [None] - self.articulations = [None] - self.syllables = [None] - self.verses = [None] - self.articulation_defs = [None] - - ## do it - self.parse (name) - - def get_global_measure (self, no): - fill_list_to (self.measures, no) - if self.measures[no] == None: - self.measures [no] = Global_measure (no) - - return self.measures[no] - - - def get_staff(self,staffno): - fill_list_to (self.staffs, staffno) - if self.staffs[staffno] == None: - self.staffs[staffno] = Staff (staffno) - - return self.staffs[staffno] - - # staff-spec - def try_IS (self, indices, contents): - pass - - def try_BC (self, indices, contents): - bn = indices[0] - where = contents[0] / 1024.0 - def try_TP(self, indices, contents): - (nil, num) = indices - - if self.tuplets[-1] == None or num <> self.tuplets[-1].start_note: - self.tuplets.append (Tuplet (num)) - - self.tuplets[-1].append_finale (contents) - - def try_IM (self, indices, contents): - (a,b) = indices - fin = contents - self.articulations.append (Articulation (a,b,fin)) - def try_verse (self, indices, contents): - a = indices[0] - body = contents[0] - - body = re.sub (r"""\^[a-z]+\([^)]+\)""", "", body) - body = re.sub ("\^[a-z]+", "", body) - self.verses.append (Verse (a, body)) - def try_ve (self,indices, contents): - (a,b) = indices - self.syllables.append (Syllable (a,b,contents)) - - def try_eE (self,indices, contents): - no = indices[0] - (prev, next, dur, pos, entryflag, extended, follow) = contents[:7] - - fill_list_to (self.chords, no) - self.chords[no] =Chord (no, contents) - - def try_Sx(self,indices, contents): - slurno = indices[0] - fill_list_to (self.slurs, slurno) - self.slurs[slurno] = Slur(slurno, contents) - - def try_IX (self, indices, contents): - n = indices[0] - a = contents[0] - b = contents[1] - - ix= None - try: - ix = self.articulation_defs[n] - except IndexError: - ix = Articulation_def (n,a,b) - self.articulation_defs.append (Articulation_def (n, a, b)) - - def try_GF(self, indices, contents): - (staffno,measno) = indices - - st = self.get_staff (staffno) - meas = st.get_measure (measno) - meas.finale = contents - - def try_FR(self, indices, contents): - frameno = indices [0] - - startnote = contents[0] - endnote = contents[1] - - fill_list_to (self.frames, frameno) - - self.frames[frameno] = Frame ((frameno, startnote, endnote)) - - def try_MS (self, indices, contents): - measno = indices[0] - keynum = contents[1] - meas =self. get_global_measure (measno) - - meas.set_key_sig (keynum) - - beats = contents[2] - beatlen = contents[3] - meas.set_timesig ((beats, beatlen)) - - meas_flag1 = contents[4] - meas_flag2 = contents[5] - - meas.set_flags (meas_flag1, meas_flag2); - - - routine_dict = { - 'MS': try_MS, - 'FR': try_FR, - 'GF': try_GF, - 'IX': try_IX, - 'Sx' : try_Sx, - 'eE' : try_eE, - 'verse' : try_verse, - 've' : try_ve, - 'IM' : try_IM, - 'TP' : try_TP, - 'BC' : try_BC, - 'IS' : try_IS, - } - - def parse (self, etf_dict): - sys.stderr.write ('reconstructing ...') - sys.stderr.flush () - - for (tag,routine) in Etf_file.routine_dict.items (): - ks = etf_dict[tag].keys () - ks.sort () - for k in ks: - routine (self, k, etf_dict[tag][k]) - - sys.stderr.write ('processing ...') - sys.stderr.flush () - - self.unthread_entries () - - for st in self.staffs[1:]: - if not st: - continue - mno = 1 - for m in st.measures[1:]: - if not m: - continue - - m.calculate() - try: - m.global_measure = self.measures[mno] - except IndexError: - sys.stderr.write ("Non-existent global measure %d" % mno) - continue - - frame_obj_list = [None] - for frno in m.frames: - try: - fr = self.frames[frno] - frame_obj_list.append (fr) - except IndexError: - sys.stderr.write ("\nNon-existent frame %d" % frno) - - m.frames = frame_obj_list - for fr in frame_obj_list[1:]: - if not fr: - continue - - fr.set_measure (m) - - fr.chords = self.get_thread (fr.start, fr.end) - for c in fr.chords: - c.frame = fr - mno = mno + 1 - - for c in self.chords[1:]: - if c: - c.calculate() - - for f in self.frames[1:]: - if f: - f.calculate () - - for t in self.tuplets[1:]: - t.calculate (self.chords) - - for s in self.slurs[1:]: - if s: - s.calculate (self.chords) - - for s in self.articulations[1:]: - s.calculate (self.chords, self.articulation_defs) - - def get_thread (self, startno, endno): - - thread = [] - - c = None - try: - c = self.chords[startno] - except IndexError: - sys.stderr.write ("Huh? Frame has invalid bounds (%d,%d)\n" % (startno, endno)) - return [] - - - while c and c.number <> endno: - thread.append (c) - c = c.next - - if c: - thread.append (c) - - return thread - - def dump (self): - str = '' - staffs = [] - for s in self.staffs[1:]: - if s: - str = str + '\n\n' + s.dump () - staffs.append ('\\' + s.staffid ()) - - - # should use \addlyrics ? - - for v in self.verses[1:]: - str = str + v.dump() - - if len (self.verses) > 1: - sys.stderr.write ("\nLyrics found; edit to use \\addlyrics to couple to a staff\n") - - if staffs: - str += '\\version "2.3.25"\n' - str = str + '<<\n %s\n>> } ' % string.join (staffs) - - return str - - - def __str__ (self): - return 'ETF FILE %s %s' % (self.measures, self.entries) - - def unthread_entries (self): - for e in self.chords[1:]: - if not e: - continue - - e.prev = self.chords[e.finale[0]] - e.next = self.chords[e.finale[1]] + def __init__ (self, name): + self.measures = [None] + self.chords = [None] + self.frames = [None] + self.tuplets = [None] + self.staffs = [None] + self.slurs = [None] + self.articulations = [None] + self.syllables = [None] + self.verses = [None] + self.articulation_defs = [None] + + ## do it + self.parse (name) + + def get_global_measure (self, no): + fill_list_to (self.measures, no) + if self.measures[no] == None: + self.measures [no] = Global_measure (no) + + return self.measures[no] + + + def get_staff(self,staffno): + fill_list_to (self.staffs, staffno) + if self.staffs[staffno] == None: + self.staffs[staffno] = Staff (staffno) + + return self.staffs[staffno] + + # staff-spec + def try_IS (self, indices, contents): + pass + + def try_BC (self, indices, contents): + bn = indices[0] + where = contents[0] / 1024.0 + def try_TP(self, indices, contents): + (nil, num) = indices + + if self.tuplets[-1] == None or num <> self.tuplets[-1].start_note: + self.tuplets.append (Tuplet (num)) + + self.tuplets[-1].append_finale (contents) + + def try_IM (self, indices, contents): + (a,b) = indices + fin = contents + self.articulations.append (Articulation (a,b,fin)) + def try_verse (self, indices, contents): + a = indices[0] + body = contents[0] + + body = re.sub (r"""\^[a-z]+\([^)]+\)""", "", body) + body = re.sub ("\^[a-z]+", "", body) + self.verses.append (Verse (a, body)) + def try_ve (self,indices, contents): + (a,b) = indices + self.syllables.append (Syllable (a,b,contents)) + + def try_eE (self,indices, contents): + no = indices[0] + (prev, next, dur, pos, entryflag, extended, follow) = contents[:7] + + fill_list_to (self.chords, no) + self.chords[no] =Chord (no, contents) + + def try_Sx(self,indices, contents): + slurno = indices[0] + fill_list_to (self.slurs, slurno) + self.slurs[slurno] = Slur(slurno, contents) + + def try_IX (self, indices, contents): + n = indices[0] + a = contents[0] + b = contents[1] + + ix= None + try: + ix = self.articulation_defs[n] + except IndexError: + ix = Articulation_def (n,a,b) + self.articulation_defs.append (Articulation_def (n, a, b)) + + def try_GF(self, indices, contents): + (staffno,measno) = indices + + st = self.get_staff (staffno) + meas = st.get_measure (measno) + meas.finale = contents + + def try_FR(self, indices, contents): + frameno = indices [0] + + startnote = contents[0] + endnote = contents[1] + + fill_list_to (self.frames, frameno) + + self.frames[frameno] = Frame ((frameno, startnote, endnote)) + + def try_MS (self, indices, contents): + measno = indices[0] + keynum = contents[1] + meas =self. get_global_measure (measno) + + meas.set_key_sig (keynum) + + beats = contents[2] + beatlen = contents[3] + meas.set_timesig ((beats, beatlen)) + + meas_flag1 = contents[4] + meas_flag2 = contents[5] + + meas.set_flags (meas_flag1, meas_flag2); + + + routine_dict = { + 'MS': try_MS, + 'FR': try_FR, + 'GF': try_GF, + 'IX': try_IX, + 'Sx' : try_Sx, + 'eE' : try_eE, + 'verse' : try_verse, + 've' : try_ve, + 'IM' : try_IM, + 'TP' : try_TP, + 'BC' : try_BC, + 'IS' : try_IS, + } + + def parse (self, etf_dict): + sys.stderr.write ('reconstructing ...') + sys.stderr.flush () + + for (tag,routine) in Etf_file.routine_dict.items (): + ks = etf_dict[tag].keys () + ks.sort () + for k in ks: + routine (self, k, etf_dict[tag][k]) + + sys.stderr.write ('processing ...') + sys.stderr.flush () + + self.unthread_entries () + + for st in self.staffs[1:]: + if not st: + continue + mno = 1 + for m in st.measures[1:]: + if not m: + continue + + m.calculate() + try: + m.global_measure = self.measures[mno] + except IndexError: + sys.stderr.write ("Non-existent global measure %d" % mno) + continue + + frame_obj_list = [None] + for frno in m.frames: + try: + fr = self.frames[frno] + frame_obj_list.append (fr) + except IndexError: + sys.stderr.write ("\nNon-existent frame %d" % frno) + + m.frames = frame_obj_list + for fr in frame_obj_list[1:]: + if not fr: + continue + + fr.set_measure (m) + + fr.chords = self.get_thread (fr.start, fr.end) + for c in fr.chords: + c.frame = fr + mno = mno + 1 + + for c in self.chords[1:]: + if c: + c.calculate() + + for f in self.frames[1:]: + if f: + f.calculate () + + for t in self.tuplets[1:]: + t.calculate (self.chords) + + for s in self.slurs[1:]: + if s: + s.calculate (self.chords) + + for s in self.articulations[1:]: + s.calculate (self.chords, self.articulation_defs) + + def get_thread (self, startno, endno): + + thread = [] + + c = None + try: + c = self.chords[startno] + except IndexError: + sys.stderr.write ("Huh? Frame has invalid bounds (%d,%d)\n" % (startno, endno)) + return [] + + + while c and c.number <> endno: + thread.append (c) + c = c.next + + if c: + thread.append (c) + + return thread + + def dump (self): + str = '' + staffs = [] + for s in self.staffs[1:]: + if s: + str = str + '\n\n' + s.dump () + staffs.append ('\\' + s.staffid ()) + + + # should use \addlyrics ? + + for v in self.verses[1:]: + str = str + v.dump() + + if len (self.verses) > 1: + sys.stderr.write ("\nLyrics found; edit to use \\addlyrics to couple to a staff\n") + + if staffs: + str += '\\version "2.3.25"\n' + str = str + '<<\n %s\n>> } ' % string.join (staffs) + + return str + + + def __str__ (self): + return 'ETF FILE %s %s' % (self.measures, self.entries) + + def unthread_entries (self): + for e in self.chords[1:]: + if not e: + continue + + e.prev = self.chords[e.finale[0]] + e.next = self.chords[e.finale[1]] def identify(): - sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version)) + sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version)) def warranty (): - identify () - sys.stdout.write (''' + identify () + sys.stdout.write (''' Copyright (c) %s by - Han-Wen Nienhuys - Jan Nieuwenhuizen + Han-Wen Nienhuys + Jan Nieuwenhuizen %s %s ''' % ( '2001--2006', - _('Distributed under terms of the GNU General Public License.'), - _('It comes with NO WARRANTY.'))) + _('Distributed under terms of the GNU General Public License.'), + _('It comes with NO WARRANTY.'))) def get_option_parser (): - p = ly.get_option_parser (usage='etf2ly [OPTIONS]... ETF-FILE', - version="etf2ly (LilyPond) @TOPLEVEL_VERSION@", - description=_("""Enigma Transport Format is a format used by Coda Music Technology's + p = ly.get_option_parser (usage='etf2ly [OPTIONS]... ETF-FILE', + version="etf2ly (LilyPond) @TOPLEVEL_VERSION@", + description=_("""Enigma Transport Format is a format used by Coda Music Technology's Finale product. This program will convert a subset of ETF to a ready-to-use lilypond file.""")) - p.add_option ('-o', '--output', help=_("write output to FILE"), - metavar=_("FILE"), - action='store') - p.add_option ('-w', '--warranty', help=_ ("show warranty"), - action='store_true', - ), - - p.add_option_group ('bugs', - description='''Report bugs via http://post.gmane.org/post.php''' - '''?group=gmane.comp.gnu.lilypond.bugs\n''') - return p + p.add_option ('-o', '--output', help=_("write output to FILE"), + metavar=_("FILE"), + action='store') + p.add_option ('-w', '--warranty', help=_ ("show warranty"), + action='store_true', + ), + + p.add_option_group ('bugs', + description='''Report bugs via http://post.gmane.org/post.php''' + '''?group=gmane.comp.gnu.lilypond.bugs\n''') + return p def do_options (): - opt_parser = get_option_parser() - (options,args) = opt_parser.parse_args () - if options.warranty: - warranty () - sys.exit (0) + opt_parser = get_option_parser() + (options,args) = opt_parser.parse_args () + if options.warranty: + warranty () + sys.exit (0) - return (options,args) + return (options,args) (options, files) = do_options() identify() @@ -1236,26 +1236,26 @@ out_filename = options.output e = None for f in files: - if f == '-': - f = '' - - sys.stderr.write ('Processing `%s\'\n' % f) - - dict = parse_etf_file (f, Etf_file.routine_dict) - e = Etf_file(dict) - if not out_filename: - out_filename = os.path.basename (re.sub ('(?i).etf$', '.ly', f)) - - if out_filename == f: - out_filename = os.path.basename (f + '.ly') - - sys.stderr.write ('Writing `%s\'' % out_filename) - ly = e.dump() - - - - fo = open (out_filename, 'w') - fo.write ('%% lily was here -- automatically converted by etf2ly from %s\n' % f) - fo.write(ly) - fo.close () - + if f == '-': + f = '' + + sys.stderr.write ('Processing `%s\'\n' % f) + + dict = parse_etf_file (f, Etf_file.routine_dict) + e = Etf_file(dict) + if not out_filename: + out_filename = os.path.basename (re.sub ('(?i).etf$', '.ly', f)) + + if out_filename == f: + out_filename = os.path.basename (f + '.ly') + + sys.stderr.write ('Writing `%s\'' % out_filename) + ly = e.dump() + + + + fo = open (out_filename, 'w') + fo.write ('%% lily was here -- automatically converted by etf2ly from %s\n' % f) + fo.write(ly) + fo.close () + diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py index 32829bdb47..2faaa9c3bf 100644 --- a/scripts/lilypond-book.py +++ b/scripts/lilypond-book.py @@ -4,27 +4,27 @@ Example usage: test: - lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK + lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK convert-ly on book: - lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK + lilypond-book --filter="convert-ly --no-version --from=1.6.11 -" BOOK classic lilypond-book: - lilypond-book --process="lilypond" BOOK.tely + lilypond-book --process="lilypond" BOOK.tely TODO: - * this script is too complex. Modularize. - - * ly-options: intertext? - * --line-width? - * eps in latex / eps by lilypond -b ps? - * check latex parameters, twocolumn, multicolumn? - * use --png --ps --pdf for making images? + * this script is too complex. Modularize. + + * ly-options: intertext? + * --line-width? + * eps in latex / eps by lilypond -b ps? + * check latex parameters, twocolumn, multicolumn? + * use --png --ps --pdf for making images? - * Converting from lilypond-book source, substitute: - @mbinclude foo.itely -> @include foo.itely - \mbinput -> \input + * Converting from lilypond-book source, substitute: + @mbinclude foo.itely -> @include foo.itely + \mbinput -> \input ''' @@ -51,16 +51,16 @@ import re datadir = '@local_lilypond_datadir@' if not os.path.isdir (datadir): - datadir = '@lilypond_datadir@' + datadir = '@lilypond_datadir@' sys.path.insert (0, os.path.join (datadir, 'python')) if os.environ.has_key ('LILYPONDPREFIX'): - datadir = os.environ['LILYPONDPREFIX'] - while datadir[-1] == os.sep: - datadir= datadir[:-1] - - datadir = os.path.join (datadir, "share/lilypond/current/") + datadir = os.environ['LILYPONDPREFIX'] + while datadir[-1] == os.sep: + datadir= datadir[:-1] + + datadir = os.path.join (datadir, "share/lilypond/current/") sys.path.insert (0, os.path.join (datadir, 'python')) # dynamic relocation, for GUB binaries. @@ -68,8 +68,8 @@ bindir = os.path.split (sys.argv[0])[0] for prefix_component in ['share', 'lib']: - datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % prefix_component) - sys.path.insert (0, datadir) + datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % prefix_component) + sys.path.insert (0, datadir) import lilylib as ly @@ -89,44 +89,44 @@ help_summary = _ ( Example usage: - lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK - lilypond-book --filter="convert-ly --no-version --from=2.0.0 -" BOOK - lilypond-book --process='lilypond -I include' BOOK + lilypond-book --filter="tr '[a-z]' '[A-Z]'" BOOK + lilypond-book --filter="convert-ly --no-version --from=2.0.0 -" BOOK + lilypond-book --process='lilypond -I include' BOOK ''') authors = ('Jan Nieuwenhuizen ', - 'Han-Wen Nienhuys ') + 'Han-Wen Nienhuys ') - + ################################################################ def exit (i): - if global_options.verbose: - raise _ ('Exiting (%d)...') % i - else: - sys.exit (i) + if global_options.verbose: + raise _ ('Exiting (%d)...') % i + else: + sys.exit (i) def identify (): - sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) + sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) def progress (s): - sys.stderr.write (s) + sys.stderr.write (s) def warning (s): - sys.stderr.write (program_name + ": " + _ ("warning: %s") % s + '\n') + sys.stderr.write (program_name + ": " + _ ("warning: %s") % s + '\n') def error (s): - sys.stderr.write (program_name + ": " + _ ("error: %s") % s + '\n') + sys.stderr.write (program_name + ": " + _ ("error: %s") % s + '\n') def ps_page_count (ps_name): - header = open (ps_name).read (1024) - m = re.search ('\n%%Pages: ([0-9]+)', header) - if m: - return string.atoi (m.group (1)) - return 0 + header = open (ps_name).read (1024) + m = re.search ('\n%%Pages: ([0-9]+)', header) + if m: + return string.atoi (m.group (1)) + return 0 def warranty (): - identify () - sys.stdout.write (''' + identify () + sys.stdout.write (''' %s %s @@ -134,62 +134,62 @@ def warranty (): %s %s ''' % ( _('Copyright (c) %s by') % '2001--2006', - ' '.join (authors), - _('Distributed under terms of the GNU General Public License.'), - _('It comes with NO WARRANTY.'))) + ' '.join (authors), + _('Distributed under terms of the GNU General Public License.'), + _('It comes with NO WARRANTY.'))) def get_option_parser (): - p = ly.get_option_parser (usage='lilypond-book [OPTIONS] FILE', - version="@TOPLEVEL_VERSION@", - description=help_summary) - - p.add_option ('-F', '--filter', metavar=_ ("FILTER"), - action="store", - dest="filter_cmd", - help=_ ("pipe snippets through FILTER [convert-ly -n -]"), - default=None) - p.add_option ('-f', '--format', help=_('''use output format FORMAT (texi [default], texi-html, latex, html)'''), - action='store') - p.add_option ("-I", '--include', help=_('add DIR to include path'), - metavar="DIR", - action='append', dest='include_path', - default=[os.path.abspath (os.getcwd ())]) - - p.add_option ("-o", '--output', help=_('write output to DIR'), - metavar="DIR", - action='store', dest='output_name', - default='') - p.add_option ('-P', '--process', metavar=_("COMMAND"), - help = _ ("process ly_files using COMMAND FILE..."), - action='store', - dest='process_cmd', default='lilypond -b eps') - - p.add_option ('', '--psfonts', action="store_true", dest="psfonts", - help=_ ('''extract all PostScript fonts into INPUT.psfonts for LaTeX''' - '''must use this with dvips -h INPUT.psfonts'''), - default=None) - p.add_option ('-V', '--verbose', help=_("be verbose"), - action="store_true", - default=False, - dest="verbose") - - p.add_option ('-w', '--warranty', - help=_("show warranty and copyright"), - action='store_true') - - - p.add_option_group ('bugs', - description='''Report bugs via http://post.gmane.org/post.php''' - '''?group=gmane.comp.gnu.lilypond.bugs\n''') - - return p + p = ly.get_option_parser (usage='lilypond-book [OPTIONS] FILE', + version="@TOPLEVEL_VERSION@", + description=help_summary) + + p.add_option ('-F', '--filter', metavar=_ ("FILTER"), + action="store", + dest="filter_cmd", + help=_ ("pipe snippets through FILTER [convert-ly -n -]"), + default=None) + p.add_option ('-f', '--format', help=_('''use output format FORMAT (texi [default], texi-html, latex, html)'''), + action='store') + p.add_option ("-I", '--include', help=_('add DIR to include path'), + metavar="DIR", + action='append', dest='include_path', + default=[os.path.abspath (os.getcwd ())]) + + p.add_option ("-o", '--output', help=_('write output to DIR'), + metavar="DIR", + action='store', dest='output_name', + default='') + p.add_option ('-P', '--process', metavar=_("COMMAND"), + help = _ ("process ly_files using COMMAND FILE..."), + action='store', + dest='process_cmd', default='lilypond -b eps') + + p.add_option ('', '--psfonts', action="store_true", dest="psfonts", + help=_ ('''extract all PostScript fonts into INPUT.psfonts for LaTeX''' + '''must use this with dvips -h INPUT.psfonts'''), + default=None) + p.add_option ('-V', '--verbose', help=_("be verbose"), + action="store_true", + default=False, + dest="verbose") + + p.add_option ('-w', '--warranty', + help=_("show warranty and copyright"), + action='store_true') + + + p.add_option_group ('bugs', + description='''Report bugs via http://post.gmane.org/post.php''' + '''?group=gmane.comp.gnu.lilypond.bugs\n''') + + return p lilypond_binary = os.path.join ('@bindir@', 'lilypond') # Only use installed binary when we are installed too. if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary): - lilypond_binary = 'lilypond' + lilypond_binary = 'lilypond' global_options = None @@ -235,8 +235,8 @@ ALT = 'alt' # NOTIME has no opposite so it isn't part of this dictionary. # NOQUOTE is used internally only. no_options = { - NOFRAGMENT: FRAGMENT, - NOINDENT: INDENT, + NOFRAGMENT: FRAGMENT, + NOINDENT: INDENT, } @@ -249,361 +249,361 @@ no_options = { # (?x) -- Ignore whitespace in patterns. no_match = 'a\ba' snippet_res = { - ## - HTML: { - 'include': - no_match, - - 'lilypond': - r'''(?mx) - (?P - .*?)\s*:)?\s* - (?P.*?) - />)''', - - 'lilypond_block': - r'''(?msx) - (?P - .*?)\s* - > - (?P.*?) - )''', - - 'lilypond_file': - r'''(?mx) - (?P - .*?)\s* - > - \s*(?P.*?)\s* - )''', - - 'multiline_comment': - r'''(?smx) - (?P - \s*(?!@c\s+) - (?P) - \s)''', - - 'singleline_comment': - no_match, - - 'verb': - r'''(?x) - (?P - (?P
.*?
))''', - - 'verbatim': - r'''(?x) - (?s) - (?P - (?P
\s.*?
\s))''', - }, - - ## - LATEX: { - 'include': - r'''(?smx) - ^[^%\n]*? - (?P - \\input\s*{ - (?P\S+?) - })''', - - 'lilypond': - r'''(?smx) - ^[^%\n]*? - (?P - \\lilypond\s*( - \[ - \s*(?P.*?)\s* - \])?\s*{ - (?P.*?) - })''', - - 'lilypond_block': - r'''(?smx) - ^[^%\n]*? - (?P - \\begin\s*( - \[ - \s*(?P.*?)\s* - \])?\s*{lilypond} - (?P.*?) - ^[^%\n]*? - \\end\s*{lilypond})''', - - 'lilypond_file': - r'''(?smx) - ^[^%\n]*? - (?P - \\lilypondfile\s*( - \[ - \s*(?P.*?)\s* - \])?\s*\{ - (?P\S+?) - })''', - - 'multiline_comment': - no_match, - - 'singleline_comment': - r'''(?mx) - ^.*? - (?P - (?P - %.*$\n+))''', - - 'verb': - r'''(?mx) - ^[^%\n]*? - (?P - (?P - \\verb(?P.) - .*? - (?P=del)))''', - - 'verbatim': - r'''(?msx) - ^[^%\n]*? - (?P - (?P - \\begin\s*{verbatim} - .*? - \\end\s*{verbatim}))''', - }, - - ## - TEXINFO: { - 'include': - r'''(?mx) - ^(?P - @include\s+ - (?P\S+))''', - - 'lilypond': - r'''(?smx) - ^[^\n]*?(?!@c\s+)[^\n]*? - (?P - @lilypond\s*( - \[ - \s*(?P.*?)\s* - \])?\s*{ - (?P.*?) - })''', - - 'lilypond_block': - r'''(?msx) - ^(?P - @lilypond\s*( - \[ - \s*(?P.*?)\s* - \])?\s+? - ^(?P.*?) - ^@end\s+lilypond)\s''', - - 'lilypond_file': - r'''(?mx) - ^(?P - @lilypondfile\s*( - \[ - \s*(?P.*?)\s* - \])?\s*{ - (?P\S+) - })''', - - 'multiline_comment': - r'''(?smx) - ^(?P - (?P - @ignore\s - .*? - @end\s+ignore))\s''', - - 'singleline_comment': - r'''(?mx) - ^.* - (?P - (?P - @c([ \t][^\n]*|)\n))''', - - # Don't do this: It interferes with @code{@{}. - # 'verb': r'''(?P@code{.*?})''', - - 'verbatim': - r'''(?sx) - (?P - (?P - @example - \s.*? - @end\s+example\s))''', - }, + ## + HTML: { + 'include': + no_match, + + 'lilypond': + r'''(?mx) + (?P + .*?)\s*:)?\s* + (?P.*?) + />)''', + + 'lilypond_block': + r'''(?msx) + (?P + .*?)\s* + > + (?P.*?) + )''', + + 'lilypond_file': + r'''(?mx) + (?P + .*?)\s* + > + \s*(?P.*?)\s* + )''', + + 'multiline_comment': + r'''(?smx) + (?P + \s*(?!@c\s+) + (?P) + \s)''', + + 'singleline_comment': + no_match, + + 'verb': + r'''(?x) + (?P + (?P
.*?
))''', + + 'verbatim': + r'''(?x) + (?s) + (?P + (?P
\s.*?
\s))''', + }, + + ## + LATEX: { + 'include': + r'''(?smx) + ^[^%\n]*? + (?P + \\input\s*{ + (?P\S+?) + })''', + + 'lilypond': + r'''(?smx) + ^[^%\n]*? + (?P + \\lilypond\s*( + \[ + \s*(?P.*?)\s* + \])?\s*{ + (?P.*?) + })''', + + 'lilypond_block': + r'''(?smx) + ^[^%\n]*? + (?P + \\begin\s*( + \[ + \s*(?P.*?)\s* + \])?\s*{lilypond} + (?P.*?) + ^[^%\n]*? + \\end\s*{lilypond})''', + + 'lilypond_file': + r'''(?smx) + ^[^%\n]*? + (?P + \\lilypondfile\s*( + \[ + \s*(?P.*?)\s* + \])?\s*\{ + (?P\S+?) + })''', + + 'multiline_comment': + no_match, + + 'singleline_comment': + r'''(?mx) + ^.*? + (?P + (?P + %.*$\n+))''', + + 'verb': + r'''(?mx) + ^[^%\n]*? + (?P + (?P + \\verb(?P.) + .*? + (?P=del)))''', + + 'verbatim': + r'''(?msx) + ^[^%\n]*? + (?P + (?P + \\begin\s*{verbatim} + .*? + \\end\s*{verbatim}))''', + }, + + ## + TEXINFO: { + 'include': + r'''(?mx) + ^(?P + @include\s+ + (?P\S+))''', + + 'lilypond': + r'''(?smx) + ^[^\n]*?(?!@c\s+)[^\n]*? + (?P + @lilypond\s*( + \[ + \s*(?P.*?)\s* + \])?\s*{ + (?P.*?) + })''', + + 'lilypond_block': + r'''(?msx) + ^(?P + @lilypond\s*( + \[ + \s*(?P.*?)\s* + \])?\s+? + ^(?P.*?) + ^@end\s+lilypond)\s''', + + 'lilypond_file': + r'''(?mx) + ^(?P + @lilypondfile\s*( + \[ + \s*(?P.*?)\s* + \])?\s*{ + (?P\S+) + })''', + + 'multiline_comment': + r'''(?smx) + ^(?P + (?P + @ignore\s + .*? + @end\s+ignore))\s''', + + 'singleline_comment': + r'''(?mx) + ^.* + (?P + (?P + @c([ \t][^\n]*|)\n))''', + + # Don't do this: It interferes with @code{@{}. + # 'verb': r'''(?P@code{.*?})''', + + 'verbatim': + r'''(?sx) + (?P + (?P + @example + \s.*? + @end\s+example\s))''', + }, } format_res = { - HTML: { - 'intertext': r',?\s*intertext=\".*?\"', - 'option_sep': '\s*', - }, - - LATEX: { - 'intertext': r',?\s*intertext=\".*?\"', - 'option_sep': '\s*,\s*', - }, - - TEXINFO: { - 'intertext': r',?\s*intertext=\".*?\"', - 'option_sep': '\s*,\s*', - }, + HTML: { + 'intertext': r',?\s*intertext=\".*?\"', + 'option_sep': '\s*', + }, + + LATEX: { + 'intertext': r',?\s*intertext=\".*?\"', + 'option_sep': '\s*,\s*', + }, + + TEXINFO: { + 'intertext': r',?\s*intertext=\".*?\"', + 'option_sep': '\s*,\s*', + }, } # Options without a pattern in ly_options. simple_options = [ - EXAMPLEINDENT, - FRAGMENT, - NOFRAGMENT, - NOINDENT, - PRINTFILENAME, - TEXIDOC, - VERBATIM, - FONTLOAD, - FILENAME, - ALT + EXAMPLEINDENT, + FRAGMENT, + NOFRAGMENT, + NOINDENT, + PRINTFILENAME, + TEXIDOC, + VERBATIM, + FONTLOAD, + FILENAME, + ALT ] ly_options = { - ## - NOTES: { - RELATIVE: r'''\relative c%(relative_quotes)s''', - }, - - ## - PAPER: { - INDENT: r'''indent = %(indent)s''', - - LINE_WIDTH: r'''line-width = %(line-width)s''', - - QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', - - RAGGED_RIGHT: r'''ragged-right = ##t''', - - PACKED: r'''packed = ##t''', - }, - - ## - LAYOUT: { - NOTIME: r''' - \context { - \Score - timing = ##f - } - \context { - \Staff - \remove Time_signature_engraver - }''', - }, - - ## - PREAMBLE: { - STAFFSIZE: r'''#(set-global-staff-size %(staffsize)s)''', - }, + ## + NOTES: { + RELATIVE: r'''\relative c%(relative_quotes)s''', + }, + + ## + PAPER: { + INDENT: r'''indent = %(indent)s''', + + LINE_WIDTH: r'''line-width = %(line-width)s''', + + QUOTE: r'''line-width = %(line-width)s - 2.0 * %(exampleindent)s''', + + RAGGED_RIGHT: r'''ragged-right = ##t''', + + PACKED: r'''packed = ##t''', + }, + + ## + LAYOUT: { + NOTIME: r''' + \context { + \Score + timing = ##f + } + \context { + \Staff + \remove Time_signature_engraver + }''', + }, + + ## + PREAMBLE: { + STAFFSIZE: r'''#(set-global-staff-size %(staffsize)s)''', + }, } output = { - ## - HTML: { - FILTER: r''' + ## + HTML: { + FILTER: r''' %(code)s ''', - AFTER: r''' - + AFTER: r''' +

''', - BEFORE: r'''

- ''', + BEFORE: r'''

+ ''', - OUTPUT: r''' - %(alt)s''', + OUTPUT: r''' + %(alt)s''', - PRINTFILENAME: '

%(filename)s

', + PRINTFILENAME: '

%(filename)s

', - QUOTE: r'''
+ QUOTE: r'''
%(str)s
''', - VERBATIM: r'''
+        VERBATIM: r'''
 %(verb)s
''', - }, + }, - ## - LATEX: { - OUTPUT: r'''{%% + ## + LATEX: { + OUTPUT: r'''{%% \parindent 0pt%% \catcode`\@=12%% \ifx\preLilyPondExample \undefined%% - \relax%% + \relax%% \else%% - \preLilyPondExample%% + \preLilyPondExample%% \fi%% \def\lilypondbook{}%% \input %(base)s-systems.tex%% \ifx\postLilyPondExample \undefined%% - \relax%% + \relax%% \else%% - \postLilyPondExample%% + \postLilyPondExample%% \fi%% }''', - PRINTFILENAME: '''\\texttt{%(filename)s} - ''', + PRINTFILENAME: '''\\texttt{%(filename)s} + ''', - QUOTE: r'''\begin{quotation}%(str)s + QUOTE: r'''\begin{quotation}%(str)s \end{quotation}''', - VERBATIM: r'''\noindent + VERBATIM: r'''\noindent \begin{verbatim}%(verb)s\end{verbatim}''', - FILTER: r'''\begin{lilypond}[%(options)s] + FILTER: r'''\begin{lilypond}[%(options)s] %(code)s \end{lilypond}''', - }, + }, - ## - TEXINFO: { - FILTER: r'''@lilypond[%(options)s] + ## + TEXINFO: { + FILTER: r'''@lilypond[%(options)s] %(code)s @lilypond''', - OUTPUT: r''' + OUTPUT: r''' @iftex @include %(base)s-systems.texi @end iftex ''', - OUTPUTIMAGE: r'''@noindent + OUTPUTIMAGE: r'''@noindent @ifinfo @image{%(base)s,,,%(alt)s,%(ext)s} @end ifinfo @html

- - %(alt)s - + + %(alt)s +

@end html ''', - PRINTFILENAME: ''' + PRINTFILENAME: ''' @html @end html @@ -611,21 +611,21 @@ output = { @html @end html - ''', + ''', - QUOTE: r'''@quotation + QUOTE: r'''@quotation %(str)s@end quotation ''', - NOQUOTE: r'''@format + NOQUOTE: r'''@format %(str)s@end format ''', - VERBATIM: r'''@exampleindent 0 + VERBATIM: r'''@exampleindent 0 @verbatim %(verb)s@end verbatim ''', - }, + }, } # @@ -634,9 +634,9 @@ output = { ## TODO if 0: - for f in [HTML, LATEX]: - for s in (QUOTE, VERBATIM): - output[f][s] = output[f][s].replace("\n"," ") + for f in [HTML, LATEX]: + for s in (QUOTE, VERBATIM): + output[f][s] = output[f][s].replace("\n"," ") PREAMBLE_LY = '''%%%% Generated by %(program_name)s @@ -644,10 +644,10 @@ PREAMBLE_LY = '''%%%% Generated by %(program_name)s #(set! toplevel-score-handler print-score-with-defaults) #(set! toplevel-music-handler - (lambda (p m) - (if (not (eq? (ly:music-property m \'void) #t)) - (print-score-with-defaults - p (scorify-music m p))))) + (lambda (p m) + (if (not (eq? (ly:music-property m \'void) #t)) + (print-score-with-defaults + p (scorify-music m p))))) #(ly:set-option (quote no-point-and-click)) #(define inside-lilypond-book #t) @@ -664,13 +664,13 @@ PREAMBLE_LY = '''%%%% Generated by %(program_name)s %% **************************************************************** \paper { - #(define dump-extents #t) - %(font_dump_setting)s - %(paper_string)s + #(define dump-extents #t) + %(font_dump_setting)s + %(paper_string)s } \layout { - %(layout_string)s + %(layout_string)s } ''' @@ -706,696 +706,696 @@ FULL_LY = ''' ''' texinfo_line_widths = { - '@afourpaper': '160\\mm', - '@afourwide': '6.5\\in', - '@afourlatex': '150\\mm', - '@smallbook': '5\\in', - '@letterpaper': '6\\in', + '@afourpaper': '160\\mm', + '@afourwide': '6.5\\in', + '@afourlatex': '150\\mm', + '@smallbook': '5\\in', + '@letterpaper': '6\\in', } def classic_lilypond_book_compatibility (key, value): - if key == 'singleline' and value == None: - return (RAGGED_RIGHT, None) + if key == 'singleline' and value == None: + return (RAGGED_RIGHT, None) - m = re.search ('relative\s*([-0-9])', key) - if m: - return ('relative', m.group (1)) + m = re.search ('relative\s*([-0-9])', key) + if m: + return ('relative', m.group (1)) - m = re.match ('([0-9]+)pt', key) - if m: - return ('staffsize', m.group (1)) + m = re.match ('([0-9]+)pt', key) + if m: + return ('staffsize', m.group (1)) - if key == 'indent' or key == 'line-width': - m = re.match ('([-.0-9]+)(cm|in|mm|pt|staffspace)', value) - if m: - f = float (m.group (1)) - return (key, '%f\\%s' % (f, m.group (2))) + if key == 'indent' or key == 'line-width': + m = re.match ('([-.0-9]+)(cm|in|mm|pt|staffspace)', value) + if m: + f = float (m.group (1)) + return (key, '%f\\%s' % (f, m.group (2))) - return (None, None) + return (None, None) def find_file (name): - for i in global_options.include_path: - full = os.path.join (i, name) - if os.path.exists (full): - return full - - error (_ ("file not found: %s") % name + '\n') - exit (1) - return '' + for i in global_options.include_path: + full = os.path.join (i, name) + if os.path.exists (full): + return full + + error (_ ("file not found: %s") % name + '\n') + exit (1) + return '' def verbatim_html (s): - return re.sub ('>', '>', - re.sub ('<', '<', - re.sub ('&', '&', s))) + return re.sub ('>', '>', + re.sub ('<', '<', + re.sub ('&', '&', s))) def split_options (option_string): - if option_string: - if global_options.format == HTML: - options = re.findall('[\w\.-:]+(?:\s*=\s*(?:"[^"]*"|\'[^\']*\'|\S+))?',option_string) - for i in range(len(options)): - options[i] = re.sub('^([^=]+=\s*)(?P["\'])(.*)(?P=q)','\g<1>\g<3>',options[i]) - return options - else: - return re.split (format_res[global_options.format]['option_sep'], - option_string) - return [] + if option_string: + if global_options.format == HTML: + options = re.findall('[\w\.-:]+(?:\s*=\s*(?:"[^"]*"|\'[^\']*\'|\S+))?',option_string) + for i in range(len(options)): + options[i] = re.sub('^([^=]+=\s*)(?P["\'])(.*)(?P=q)','\g<1>\g<3>',options[i]) + return options + else: + return re.split (format_res[global_options.format]['option_sep'], + option_string) + return [] def set_default_options (source): - global default_ly_options - if not default_ly_options.has_key (LINE_WIDTH): - if global_options.format == LATEX: - textwidth = get_latex_textwidth (source) - default_ly_options[LINE_WIDTH] = \ - '''%.0f\\pt''' % textwidth - elif global_options.format == TEXINFO: - for (k, v) in texinfo_line_widths.items (): - # FIXME: @layout is usually not in - # chunk #0: - # - # \input texinfo @c -*-texinfo-*- - # - # Bluntly search first K items of - # source. - # s = chunks[0].replacement_text () - if re.search (k, source[:1024]): - default_ly_options[LINE_WIDTH] = v - break + global default_ly_options + if not default_ly_options.has_key (LINE_WIDTH): + if global_options.format == LATEX: + textwidth = get_latex_textwidth (source) + default_ly_options[LINE_WIDTH] = \ + '''%.0f\\pt''' % textwidth + elif global_options.format == TEXINFO: + for (k, v) in texinfo_line_widths.items (): + # FIXME: @layout is usually not in + # chunk #0: + # + # \input texinfo @c -*-texinfo-*- + # + # Bluntly search first K items of + # source. + # s = chunks[0].replacement_text () + if re.search (k, source[:1024]): + default_ly_options[LINE_WIDTH] = v + break class Chunk: - def replacement_text (self): - return '' + def replacement_text (self): + return '' - def filter_text (self): - return self.replacement_text () + def filter_text (self): + return self.replacement_text () - def ly_is_outdated (self): - return 0 + def ly_is_outdated (self): + return 0 - def png_is_outdated (self): - return 0 + def png_is_outdated (self): + return 0 - def is_plain (self): - return False - + def is_plain (self): + return False + class Substring (Chunk): - def __init__ (self, source, start, end, line_number): - self.source = source - self.start = start - self.end = end - self.line_number = line_number - self.override_text = None - - def is_plain (self): - return True - - def replacement_text (self): - if self.override_text: - return self.override_text - else: - return self.source[self.start:self.end] + def __init__ (self, source, start, end, line_number): + self.source = source + self.start = start + self.end = end + self.line_number = line_number + self.override_text = None + + def is_plain (self): + return True + + def replacement_text (self): + if self.override_text: + return self.override_text + else: + return self.source[self.start:self.end] class Snippet (Chunk): - def __init__ (self, type, match, format, line_number): - self.type = type - self.match = match - self.hash = 0 - self.option_dict = {} - self.format = format - self.line_number = line_number + def __init__ (self, type, match, format, line_number): + self.type = type + self.match = match + self.hash = 0 + self.option_dict = {} + self.format = format + self.line_number = line_number - def replacement_text (self): - return self.match.group ('match') + def replacement_text (self): + return self.match.group ('match') - def substring (self, s): - return self.match.group (s) + def substring (self, s): + return self.match.group (s) - def __repr__ (self): - return `self.__class__` + ' type = ' + self.type + def __repr__ (self): + return `self.__class__` + ' type = ' + self.type class Include_snippet (Snippet): - def processed_filename (self): - f = self.substring ('filename') - return os.path.splitext (f)[0] + format2ext[global_options.format] + def processed_filename (self): + f = self.substring ('filename') + return os.path.splitext (f)[0] + format2ext[global_options.format] - def replacement_text (self): - s = self.match.group ('match') - f = self.substring ('filename') + def replacement_text (self): + s = self.match.group ('match') + f = self.substring ('filename') - return re.sub (f, self.processed_filename (), s) + return re.sub (f, self.processed_filename (), s) class Lilypond_snippet (Snippet): - def __init__ (self, type, match, format, line_number): - Snippet.__init__ (self, type, match, format, line_number) - os = match.group ('options') - self.do_options (os, self.type) - - def ly (self): - return self.substring ('code') - - def full_ly (self): - s = self.ly () - if s: - return self.compose_ly (s) - return '' - - def do_options (self, option_string, type): - self.option_dict = {} - - options = split_options (option_string) - - for i in options: - if string.find (i, '=') > 0: - (key, value) = re.split ('\s*=\s*', i) - self.option_dict[key] = value - else: - if i in no_options.keys (): - if no_options[i] in self.option_dict.keys (): - del self.option_dict[no_options[i]] - else: - self.option_dict[i] = None - - has_line_width = self.option_dict.has_key (LINE_WIDTH) - no_line_width_value = 0 - - # If LINE_WIDTH is used without parameter, set it to default. - if has_line_width and self.option_dict[LINE_WIDTH] == None: - no_line_width_value = 1 - del self.option_dict[LINE_WIDTH] - - for i in default_ly_options.keys (): - if i not in self.option_dict.keys (): - self.option_dict[i] = default_ly_options[i] - - if not has_line_width: - if type == 'lilypond' or FRAGMENT in self.option_dict.keys (): - self.option_dict[RAGGED_RIGHT] = None - - if type == 'lilypond': - if LINE_WIDTH in self.option_dict.keys (): - del self.option_dict[LINE_WIDTH] - else: - if RAGGED_RIGHT in self.option_dict.keys (): - if LINE_WIDTH in self.option_dict.keys (): - del self.option_dict[LINE_WIDTH] - - if QUOTE in self.option_dict.keys () or type == 'lilypond': - if LINE_WIDTH in self.option_dict.keys (): - del self.option_dict[LINE_WIDTH] - - if not INDENT in self.option_dict.keys (): - self.option_dict[INDENT] = '0\\mm' - - # The QUOTE pattern from ly_options only emits the `line-width' - # keyword. - if has_line_width and QUOTE in self.option_dict.keys (): - if no_line_width_value: - del self.option_dict[LINE_WIDTH] - else: - del self.option_dict[QUOTE] - - def compose_ly (self, code): - if FRAGMENT in self.option_dict.keys (): - body = FRAGMENT_LY - else: - body = FULL_LY - - # 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 DVI 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. - override[EXAMPLEINDENT] = r'0.4\in' - override[LINE_WIDTH] = texinfo_line_widths['@smallbook'] - override.update (default_ly_options) - - option_list = [] - for (key, value) in self.option_dict.items (): - if value == None: - option_list.append (key) - else: - option_list.append (key + '=' + value) - option_string = string.join (option_list, ',') - - compose_dict = {} - compose_types = [NOTES, PREAMBLE, LAYOUT, PAPER] - for a in compose_types: - compose_dict[a] = [] - - for (key, value) in self.option_dict.items (): - (c_key, c_value) = \ - classic_lilypond_book_compatibility (key, value) - if c_key: - if c_value: - warning \ - (_ ("deprecated ly-option used: %s=%s" \ - % (key, value))) - warning \ - (_ ("compatibility mode translation: %s=%s" \ - % (c_key, c_value))) - else: - warning \ - (_ ("deprecated ly-option used: %s" \ - % key)) - warning \ - (_ ("compatibility mode translation: %s" \ - % c_key)) - - (key, value) = (c_key, c_value) - - if value: - override[key] = value - else: - if not override.has_key (key): - override[key] = None - - found = 0 - for type in compose_types: - if ly_options[type].has_key (key): - compose_dict[type].append (ly_options[type][key]) - found = 1 - break - - if not found and key not in simple_options: - warning (_ ("ignoring unknown ly option: %s") % key) - - # URGS - if RELATIVE in override.keys () and override[RELATIVE]: - relative = int (override[RELATIVE]) - - relative_quotes = '' - - # 1 = central C - if relative < 0: - relative_quotes += ',' * (- relative) - elif relative > 0: - relative_quotes += "'" * relative - - paper_string = string.join (compose_dict[PAPER], - '\n ') % override - layout_string = string.join (compose_dict[LAYOUT], - '\n ') % override - notes_string = string.join (compose_dict[NOTES], - '\n ') % vars () - preamble_string = string.join (compose_dict[PREAMBLE], - '\n ') % override - - font_dump_setting = '' - if FONTLOAD in self.option_dict: - font_dump_setting = '#(define-public force-eps-font-include #t)\n' - - d = globals().copy() - d.update (locals()) - return (PREAMBLE_LY + body) % d - - # TODO: Use md5? - def get_hash (self): - if not self.hash: - self.hash = abs (hash (self.full_ly ())) - return self.hash - - def basename (self): - if FILENAME in self.option_dict: - return self.option_dict[FILENAME] - if global_options.use_hash: - return 'lily-%d' % self.get_hash () - raise 'to be done' - - def write_ly (self): - outf = open (self.basename () + '.ly', 'w') - outf.write (self.full_ly ()) - - open (self.basename () + '.txt', 'w').write ('image of music') - - def ly_is_outdated (self): - base = self.basename () - - tex_file = '%s.tex' % base - eps_file = '%s.eps' % base - system_file = '%s-systems.tex' % base - ly_file = '%s.ly' % base - ok = os.path.exists (ly_file) \ - and os.path.exists (system_file)\ - and os.stat (system_file)[stat.ST_SIZE] \ - and re.match ('% eof', open (system_file).readlines ()[-1]) - if ok and (not global_options.use_hash or FILENAME in self.option_dict): - ok = (self.full_ly () == open (ly_file).read ()) - if ok: - # TODO: Do something smart with target formats - # (ps, png) and m/ctimes. - return None - return self - - def png_is_outdated (self): - base = self.basename () - ok = self.ly_is_outdated () - if global_options.format in (HTML, TEXINFO): - ok = ok and os.path.exists (base + '.eps') - - page_count = 0 - if ok: - page_count = ps_page_count (base + '.eps') - - if page_count == 1: - ok = ok and os.path.exists (base + '.png') - elif page_count > 1: - for a in range (1, page_count + 1): - ok = ok and os.path.exists (base + '-page%d.png' % a) - - return not ok - - def texstr_is_outdated (self): - if backend == 'ps': - return 0 - - base = self.basename () - ok = self.ly_is_outdated () - ok = ok and (os.path.exists (base + '.texstr')) - return not ok - - def filter_text (self): - code = self.substring ('code') - s = run_filter (code) - d = { - 'code': s, - 'options': self.match.group ('options') - } - # TODO - return output[self.format][FILTER] % d - - def replacement_text (self): - func = Lilypond_snippet.__dict__['output_' + self.format] - return func (self) - - def get_images (self): - base = self.basename () - # URGUGHUGHUGUGH - single = '%(base)s.png' % vars () - multiple = '%(base)s-page1.png' % vars () - images = (single,) - if os.path.exists (multiple) \ - and (not os.path.exists (single) \ - or (os.stat (multiple)[stat.ST_MTIME] \ - > os.stat (single)[stat.ST_MTIME])): - count = ps_page_count ('%(base)s.eps' % vars ()) - images = ['%s-page%d.png' % (base, a) for a in range (1, count+1)] - images = tuple (images) - return images - - def output_html (self): - str = '' - base = self.basename () - if global_options.format == HTML: - str += self.output_print_filename (HTML) - if VERBATIM in self.option_dict: - verb = verbatim_html (self.substring ('code')) - str += output[HTML][VERBATIM] % vars () - if QUOTE in self.option_dict: - str = output[HTML][QUOTE] % vars () - - str += output[HTML][BEFORE] % vars () - for image in self.get_images (): - (base, ext) = os.path.splitext (image) - alt = self.option_dict[ALT] - str += output[HTML][OUTPUT] % vars () - str += output[HTML][AFTER] % vars () - return str - - def output_info (self): - str = '' - for image in self.get_images (): - (base, ext) = os.path.splitext (image) - - # URG, makeinfo implicitly prepends dot to extension. - # Specifying no extension is most robust. - ext = '' - alt = self.option_dict[ALT] - str += output[TEXINFO][OUTPUTIMAGE] % vars () - - base = self.basename () - str += output[global_options.format][OUTPUT] % vars () - return str - - def output_latex (self): - str = '' - base = self.basename () - if global_options.format == LATEX: - str += self.output_print_filename (LATEX) - if VERBATIM in self.option_dict: - verb = self.substring ('code') - str += (output[LATEX][VERBATIM] % vars ()) - - str += (output[LATEX][OUTPUT] % vars ()) - - ## todo: maintain breaks - if 0: - breaks = self.ly ().count ("\n") - str += "".ljust (breaks, "\n").replace ("\n","%\n") - - if QUOTE in self.option_dict: - str = output[LATEX][QUOTE] % vars () - return str - - def output_print_filename (self, format): - str = '' - if PRINTFILENAME in self.option_dict: - base = self.basename () - filename = self.substring ('filename') - str = output[global_options.format][PRINTFILENAME] % vars () - - return str - - def output_texinfo (self): - str = '' - if self.output_print_filename (TEXINFO): - str += ('@html\n' - + self.output_print_filename (HTML) - + '\n@end html\n') - str += ('@tex\n' - + self.output_print_filename (LATEX) - + '\n@end tex\n') - base = self.basename () - if TEXIDOC in self.option_dict: - texidoc = base + '.texidoc' - if os.path.exists (texidoc): - str += '@include %(texidoc)s\n\n' % vars () - - if VERBATIM in self.option_dict: - verb = self.substring ('code') - str += (output[TEXINFO][VERBATIM] % vars ()) - if not QUOTE in self.option_dict: - str = output[TEXINFO][NOQUOTE] % vars () - - str += self.output_info () - -# str += ('@ifinfo\n' + self.output_info () + '\n@end ifinfo\n') -# str += ('@tex\n' + self.output_latex () + '\n@end tex\n') -# str += ('@html\n' + self.output_html () + '\n@end html\n') - - if QUOTE in self.option_dict: - str = output[TEXINFO][QUOTE] % vars () - - # need par after image - str += '\n' - - return str + def __init__ (self, type, match, format, line_number): + Snippet.__init__ (self, type, match, format, line_number) + os = match.group ('options') + self.do_options (os, self.type) + + def ly (self): + return self.substring ('code') + + def full_ly (self): + s = self.ly () + if s: + return self.compose_ly (s) + return '' + + def do_options (self, option_string, type): + self.option_dict = {} + + options = split_options (option_string) + + for i in options: + if string.find (i, '=') > 0: + (key, value) = re.split ('\s*=\s*', i) + self.option_dict[key] = value + else: + if i in no_options.keys (): + if no_options[i] in self.option_dict.keys (): + del self.option_dict[no_options[i]] + else: + self.option_dict[i] = None + + has_line_width = self.option_dict.has_key (LINE_WIDTH) + no_line_width_value = 0 + + # If LINE_WIDTH is used without parameter, set it to default. + if has_line_width and self.option_dict[LINE_WIDTH] == None: + no_line_width_value = 1 + del self.option_dict[LINE_WIDTH] + + for i in default_ly_options.keys (): + if i not in self.option_dict.keys (): + self.option_dict[i] = default_ly_options[i] + + if not has_line_width: + if type == 'lilypond' or FRAGMENT in self.option_dict.keys (): + self.option_dict[RAGGED_RIGHT] = None + + if type == 'lilypond': + if LINE_WIDTH in self.option_dict.keys (): + del self.option_dict[LINE_WIDTH] + else: + if RAGGED_RIGHT in self.option_dict.keys (): + if LINE_WIDTH in self.option_dict.keys (): + del self.option_dict[LINE_WIDTH] + + if QUOTE in self.option_dict.keys () or type == 'lilypond': + if LINE_WIDTH in self.option_dict.keys (): + del self.option_dict[LINE_WIDTH] + + if not INDENT in self.option_dict.keys (): + self.option_dict[INDENT] = '0\\mm' + + # The QUOTE pattern from ly_options only emits the `line-width' + # keyword. + if has_line_width and QUOTE in self.option_dict.keys (): + if no_line_width_value: + del self.option_dict[LINE_WIDTH] + else: + del self.option_dict[QUOTE] + + def compose_ly (self, code): + if FRAGMENT in self.option_dict.keys (): + body = FRAGMENT_LY + else: + body = FULL_LY + + # 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 DVI 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. + override[EXAMPLEINDENT] = r'0.4\in' + override[LINE_WIDTH] = texinfo_line_widths['@smallbook'] + override.update (default_ly_options) + + option_list = [] + for (key, value) in self.option_dict.items (): + if value == None: + option_list.append (key) + else: + option_list.append (key + '=' + value) + option_string = string.join (option_list, ',') + + compose_dict = {} + compose_types = [NOTES, PREAMBLE, LAYOUT, PAPER] + for a in compose_types: + compose_dict[a] = [] + + for (key, value) in self.option_dict.items (): + (c_key, c_value) = \ + classic_lilypond_book_compatibility (key, value) + if c_key: + if c_value: + warning \ + (_ ("deprecated ly-option used: %s=%s" \ + % (key, value))) + warning \ + (_ ("compatibility mode translation: %s=%s" \ + % (c_key, c_value))) + else: + warning \ + (_ ("deprecated ly-option used: %s" \ + % key)) + warning \ + (_ ("compatibility mode translation: %s" \ + % c_key)) + + (key, value) = (c_key, c_value) + + if value: + override[key] = value + else: + if not override.has_key (key): + override[key] = None + + found = 0 + for type in compose_types: + if ly_options[type].has_key (key): + compose_dict[type].append (ly_options[type][key]) + found = 1 + break + + if not found and key not in simple_options: + warning (_ ("ignoring unknown ly option: %s") % key) + + # URGS + if RELATIVE in override.keys () and override[RELATIVE]: + relative = int (override[RELATIVE]) + + relative_quotes = '' + + # 1 = central C + if relative < 0: + relative_quotes += ',' * (- relative) + elif relative > 0: + relative_quotes += "'" * relative + + paper_string = string.join (compose_dict[PAPER], + '\n ') % override + layout_string = string.join (compose_dict[LAYOUT], + '\n ') % override + notes_string = string.join (compose_dict[NOTES], + '\n ') % vars () + preamble_string = string.join (compose_dict[PREAMBLE], + '\n ') % override + + font_dump_setting = '' + if FONTLOAD in self.option_dict: + font_dump_setting = '#(define-public force-eps-font-include #t)\n' + + d = globals().copy() + d.update (locals()) + return (PREAMBLE_LY + body) % d + + # TODO: Use md5? + def get_hash (self): + if not self.hash: + self.hash = abs (hash (self.full_ly ())) + return self.hash + + def basename (self): + if FILENAME in self.option_dict: + return self.option_dict[FILENAME] + if global_options.use_hash: + return 'lily-%d' % self.get_hash () + raise 'to be done' + + def write_ly (self): + outf = open (self.basename () + '.ly', 'w') + outf.write (self.full_ly ()) + + open (self.basename () + '.txt', 'w').write ('image of music') + + def ly_is_outdated (self): + base = self.basename () + + tex_file = '%s.tex' % base + eps_file = '%s.eps' % base + system_file = '%s-systems.tex' % base + ly_file = '%s.ly' % base + ok = os.path.exists (ly_file) \ + and os.path.exists (system_file)\ + and os.stat (system_file)[stat.ST_SIZE] \ + and re.match ('% eof', open (system_file).readlines ()[-1]) + if ok and (not global_options.use_hash or FILENAME in self.option_dict): + ok = (self.full_ly () == open (ly_file).read ()) + if ok: + # TODO: Do something smart with target formats + # (ps, png) and m/ctimes. + return None + return self + + def png_is_outdated (self): + base = self.basename () + ok = self.ly_is_outdated () + if global_options.format in (HTML, TEXINFO): + ok = ok and os.path.exists (base + '.eps') + + page_count = 0 + if ok: + page_count = ps_page_count (base + '.eps') + + if page_count == 1: + ok = ok and os.path.exists (base + '.png') + elif page_count > 1: + for a in range (1, page_count + 1): + ok = ok and os.path.exists (base + '-page%d.png' % a) + + return not ok + + def texstr_is_outdated (self): + if backend == 'ps': + return 0 + + base = self.basename () + ok = self.ly_is_outdated () + ok = ok and (os.path.exists (base + '.texstr')) + return not ok + + def filter_text (self): + code = self.substring ('code') + s = run_filter (code) + d = { + 'code': s, + 'options': self.match.group ('options') + } + # TODO + return output[self.format][FILTER] % d + + def replacement_text (self): + func = Lilypond_snippet.__dict__['output_' + self.format] + return func (self) + + def get_images (self): + base = self.basename () + # URGUGHUGHUGUGH + single = '%(base)s.png' % vars () + multiple = '%(base)s-page1.png' % vars () + images = (single,) + if os.path.exists (multiple) \ + and (not os.path.exists (single) \ + or (os.stat (multiple)[stat.ST_MTIME] \ + > os.stat (single)[stat.ST_MTIME])): + count = ps_page_count ('%(base)s.eps' % vars ()) + images = ['%s-page%d.png' % (base, a) for a in range (1, count+1)] + images = tuple (images) + return images + + def output_html (self): + str = '' + base = self.basename () + if global_options.format == HTML: + str += self.output_print_filename (HTML) + if VERBATIM in self.option_dict: + verb = verbatim_html (self.substring ('code')) + str += output[HTML][VERBATIM] % vars () + if QUOTE in self.option_dict: + str = output[HTML][QUOTE] % vars () + + str += output[HTML][BEFORE] % vars () + for image in self.get_images (): + (base, ext) = os.path.splitext (image) + alt = self.option_dict[ALT] + str += output[HTML][OUTPUT] % vars () + str += output[HTML][AFTER] % vars () + return str + + def output_info (self): + str = '' + for image in self.get_images (): + (base, ext) = os.path.splitext (image) + + # URG, makeinfo implicitly prepends dot to extension. + # Specifying no extension is most robust. + ext = '' + alt = self.option_dict[ALT] + str += output[TEXINFO][OUTPUTIMAGE] % vars () + + base = self.basename () + str += output[global_options.format][OUTPUT] % vars () + return str + + def output_latex (self): + str = '' + base = self.basename () + if global_options.format == LATEX: + str += self.output_print_filename (LATEX) + if VERBATIM in self.option_dict: + verb = self.substring ('code') + str += (output[LATEX][VERBATIM] % vars ()) + + str += (output[LATEX][OUTPUT] % vars ()) + + ## todo: maintain breaks + if 0: + breaks = self.ly ().count ("\n") + str += "".ljust (breaks, "\n").replace ("\n","%\n") + + if QUOTE in self.option_dict: + str = output[LATEX][QUOTE] % vars () + return str + + def output_print_filename (self, format): + str = '' + if PRINTFILENAME in self.option_dict: + base = self.basename () + filename = self.substring ('filename') + str = output[global_options.format][PRINTFILENAME] % vars () + + return str + + def output_texinfo (self): + str = '' + if self.output_print_filename (TEXINFO): + str += ('@html\n' + + self.output_print_filename (HTML) + + '\n@end html\n') + str += ('@tex\n' + + self.output_print_filename (LATEX) + + '\n@end tex\n') + base = self.basename () + if TEXIDOC in self.option_dict: + texidoc = base + '.texidoc' + if os.path.exists (texidoc): + str += '@include %(texidoc)s\n\n' % vars () + + if VERBATIM in self.option_dict: + verb = self.substring ('code') + str += (output[TEXINFO][VERBATIM] % vars ()) + if not QUOTE in self.option_dict: + str = output[TEXINFO][NOQUOTE] % vars () + + str += self.output_info () + +# str += ('@ifinfo\n' + self.output_info () + '\n@end ifinfo\n') +# str += ('@tex\n' + self.output_latex () + '\n@end tex\n') +# str += ('@html\n' + self.output_html () + '\n@end html\n') + + if QUOTE in self.option_dict: + str = output[TEXINFO][QUOTE] % vars () + + # need par after image + str += '\n' + + return str class Lilypond_file_snippet (Lilypond_snippet): - def ly (self): - name = self.substring ('filename') - return '\\sourcefilename \"%s\"\n%s' \ - % (name, open (find_file (name)).read ()) + def ly (self): + name = self.substring ('filename') + return '\\sourcefilename \"%s\"\n%s' \ + % (name, open (find_file (name)).read ()) snippet_type_to_class = { - 'lilypond_file': Lilypond_file_snippet, - 'lilypond_block': Lilypond_snippet, - 'lilypond': Lilypond_snippet, - 'include': Include_snippet, + 'lilypond_file': Lilypond_file_snippet, + 'lilypond_block': Lilypond_snippet, + 'lilypond': Lilypond_snippet, + 'include': Include_snippet, } def find_linestarts (s): - nls = [0] - start = 0 - end = len (s) - while 1: - i = s.find ('\n', start) - if i < 0: - break + nls = [0] + start = 0 + end = len (s) + while 1: + i = s.find ('\n', start) + if i < 0: + break - i = i + 1 - nls.append (i) - start = i + i = i + 1 + nls.append (i) + start = i - nls.append (len (s)) - return nls + nls.append (len (s)) + return nls def find_toplevel_snippets (s, types): - res = {} - for i in types: - res[i] = ly.re.compile (snippet_res[global_options.format][i]) - - snippets = [] - index = 0 - ## found = dict (map (lambda x: (x, None), - ## types)) - ## urg python2.1 - found = {} - map (lambda x, f = found: f.setdefault (x, None), - types) - - line_starts = find_linestarts (s) - line_start_idx = 0 - # We want to search for multiple regexes, without searching - # the string multiple times for one regex. - # Hence, we use earlier results to limit the string portion - # where we search. - # Since every part of the string is traversed at most once for - # every type of snippet, this is linear. - - while 1: - first = None - endex = 1 << 30 - for type in types: - if not found[type] or found[type][0] < index: - found[type] = None - - m = res[type].search (s[index:endex]) - if not m: - continue - - cl = Snippet - if snippet_type_to_class.has_key (type): - cl = snippet_type_to_class[type] - - - start = index + m.start ('match') - line_number = line_start_idx - while (line_starts[line_number] < start): - line_number += 1 - - line_number += 1 - snip = cl (type, m, global_options.format, line_number) - - found[type] = (start, snip) - - if found[type] \ - and (not first \ - or found[type][0] < found[first][0]): - first = type - - # FIXME. - - # Limiting the search space is a cute - # idea, but this *requires* to search - # for possible containing blocks - # first, at least as long as we do not - # search for the start of blocks, but - # always/directly for the entire - # @block ... @end block. - - endex = found[first][0] - - if not first: - snippets.append (Substring (s, index, len (s), line_start_idx)) - break - - while (start > line_starts[line_start_idx+1]): - line_start_idx += 1 - - (start, snip) = found[first] - snippets.append (Substring (s, index, start, line_start_idx + 1)) - snippets.append (snip) - found[first] = None - index = start + len (snip.match.group ('match')) - - return snippets + res = {} + for i in types: + res[i] = ly.re.compile (snippet_res[global_options.format][i]) + + snippets = [] + index = 0 + ## found = dict (map (lambda x: (x, None), + ## types)) + ## urg python2.1 + found = {} + map (lambda x, f = found: f.setdefault (x, None), + types) + + line_starts = find_linestarts (s) + line_start_idx = 0 + # We want to search for multiple regexes, without searching + # the string multiple times for one regex. + # Hence, we use earlier results to limit the string portion + # where we search. + # Since every part of the string is traversed at most once for + # every type of snippet, this is linear. + + while 1: + first = None + endex = 1 << 30 + for type in types: + if not found[type] or found[type][0] < index: + found[type] = None + + m = res[type].search (s[index:endex]) + if not m: + continue + + cl = Snippet + if snippet_type_to_class.has_key (type): + cl = snippet_type_to_class[type] + + + start = index + m.start ('match') + line_number = line_start_idx + while (line_starts[line_number] < start): + line_number += 1 + + line_number += 1 + snip = cl (type, m, global_options.format, line_number) + + found[type] = (start, snip) + + if found[type] \ + and (not first \ + or found[type][0] < found[first][0]): + first = type + + # FIXME. + + # Limiting the search space is a cute + # idea, but this *requires* to search + # for possible containing blocks + # first, at least as long as we do not + # search for the start of blocks, but + # always/directly for the entire + # @block ... @end block. + + endex = found[first][0] + + if not first: + snippets.append (Substring (s, index, len (s), line_start_idx)) + break + + while (start > line_starts[line_start_idx+1]): + line_start_idx += 1 + + (start, snip) = found[first] + snippets.append (Substring (s, index, start, line_start_idx + 1)) + snippets.append (snip) + found[first] = None + index = start + len (snip.match.group ('match')) + + return snippets def filter_pipe (input, cmd): - if global_options.verbose: - progress (_ ("Opening filter `%s'") % cmd) - - (stdin, stdout, stderr) = os.popen3 (cmd) - stdin.write (input) - status = stdin.close () - - if not status: - status = 0 - output = stdout.read () - status = stdout.close () - error = stderr.read () - - if not status: - status = 0 - signal = 0x0f & status - if status or (not output and error): - exit_status = status >> 8 - error (_ ("`%s' failed (%d)") % (cmd, exit_status)) - error (_ ("The error log is as follows:")) - sys.stderr.write (error) - sys.stderr.write (stderr.read ()) - exit (status) - - if global_options.verbose: - progress ('\n') - - return output + if global_options.verbose: + progress (_ ("Opening filter `%s'") % cmd) + + (stdin, stdout, stderr) = os.popen3 (cmd) + stdin.write (input) + status = stdin.close () + + if not status: + status = 0 + output = stdout.read () + status = stdout.close () + error = stderr.read () + + if not status: + status = 0 + signal = 0x0f & status + if status or (not output and error): + exit_status = status >> 8 + error (_ ("`%s' failed (%d)") % (cmd, exit_status)) + error (_ ("The error log is as follows:")) + sys.stderr.write (error) + sys.stderr.write (stderr.read ()) + exit (status) + + if global_options.verbose: + progress ('\n') + + return output def run_filter (s): - return filter_pipe (s, global_options.filter_cmd) + return filter_pipe (s, global_options.filter_cmd) def is_derived_class (cl, baseclass): - if cl == baseclass: - return 1 - for b in cl.__bases__: - if is_derived_class (b, baseclass): - return 1 - return 0 + if cl == baseclass: + return 1 + for b in cl.__bases__: + if is_derived_class (b, baseclass): + return 1 + return 0 def process_snippets (cmd, ly_snippets, texstr_snippets, png_snippets): - ly_names = filter (lambda x: x, - map (Lilypond_snippet.basename, ly_snippets)) - texstr_names = filter (lambda x: x, - map (Lilypond_snippet.basename, texstr_snippets)) - png_names = filter (lambda x: x, - map (Lilypond_snippet.basename, png_snippets)) - - status = 0 - def my_system (cmd): - status = ly.system (cmd, - be_verbose=global_options.verbose, - progress_p= 1) - - # UGH - # the --process=CMD switch is a bad idea - # it is too generic for lilypond-book. - if texstr_names: - my_system (string.join ([cmd, '--backend texstr', - 'snippet-map.ly'] + texstr_names)) - for l in texstr_names: - my_system ('latex %s.texstr' % l) - - if ly_names: - my_system (string.join ([cmd, 'snippet-map.ly'] + ly_names)) + ly_names = filter (lambda x: x, + map (Lilypond_snippet.basename, ly_snippets)) + texstr_names = filter (lambda x: x, + map (Lilypond_snippet.basename, texstr_snippets)) + png_names = filter (lambda x: x, + map (Lilypond_snippet.basename, png_snippets)) + + status = 0 + def my_system (cmd): + status = ly.system (cmd, + be_verbose=global_options.verbose, + progress_p= 1) + + # UGH + # the --process=CMD switch is a bad idea + # it is too generic for lilypond-book. + if texstr_names: + my_system (string.join ([cmd, '--backend texstr', + 'snippet-map.ly'] + texstr_names)) + for l in texstr_names: + my_system ('latex %s.texstr' % l) + + if ly_names: + my_system (string.join ([cmd, 'snippet-map.ly'] + ly_names)) LATEX_INSPECTION_DOCUMENT = r''' \nonstopmode @@ -1409,368 +1409,368 @@ LATEX_INSPECTION_DOCUMENT = r''' # Do we need anything else besides `textwidth'? def get_latex_textwidth (source): - m = re.search (r'''(?P\\begin\s*{document})''', source) - if m == None: - warning (_ ("Can't find \\begin{document} in LaTeX document")) - - ## what's a sensible default? - return 550.0 - - preamble = source[:m.start (0)] - latex_document = LATEX_INSPECTION_DOCUMENT % vars () - - (handle, tmpfile) = tempfile.mkstemp('.tex') - logfile = os.path.splitext (tmpfile)[0] + '.log' - logfile = os.path.split (logfile)[1] - - tmp_handle = os.fdopen (handle,'w') - tmp_handle.write (latex_document) - tmp_handle.close () - - ly.system ('latex %s' % tmpfile, be_verbose=global_options.verbose) - parameter_string = open (logfile).read() - - os.unlink (tmpfile) - 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)) - - textwidth = 0 - m = re.search ('textwidth=([0-9.]*)pt', parameter_string) - if m: - textwidth = float (m.group (1)) - if columns: - textwidth = (textwidth - columnsep) / columns - - return textwidth + m = re.search (r'''(?P\\begin\s*{document})''', source) + if m == None: + warning (_ ("Can't find \\begin{document} in LaTeX document")) + + ## what's a sensible default? + return 550.0 + + preamble = source[:m.start (0)] + latex_document = LATEX_INSPECTION_DOCUMENT % vars () + + (handle, tmpfile) = tempfile.mkstemp('.tex') + logfile = os.path.splitext (tmpfile)[0] + '.log' + logfile = os.path.split (logfile)[1] + + tmp_handle = os.fdopen (handle,'w') + tmp_handle.write (latex_document) + tmp_handle.close () + + ly.system ('latex %s' % tmpfile, be_verbose=global_options.verbose) + parameter_string = open (logfile).read() + + os.unlink (tmpfile) + 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)) + + textwidth = 0 + m = re.search ('textwidth=([0-9.]*)pt', parameter_string) + if m: + textwidth = float (m.group (1)) + if columns: + textwidth = (textwidth - columnsep) / columns + + return textwidth def modify_preamble (chunk): - str = chunk.replacement_text () - if (re.search (r"\\begin *{document}", str) - and not re.search ("{graphic[sx]", str)): - str = re.sub (r"\\begin{document}", - r"\\usepackage{graphics}" + '\n' - + r"\\begin{document}", - str) - chunk.override_text = str - - + str = chunk.replacement_text () + if (re.search (r"\\begin *{document}", str) + and not re.search ("{graphic[sx]", str)): + str = re.sub (r"\\begin{document}", + r"\\usepackage{graphics}" + '\n' + + r"\\begin{document}", + str) + chunk.override_text = str + + ext2format = { - '.html': HTML, - '.itely': TEXINFO, - '.latex': LATEX, - '.lytex': LATEX, - '.tely': TEXINFO, - '.tex': LATEX, - '.texi': TEXINFO, - '.texinfo': TEXINFO, - '.xml': HTML, + '.html': HTML, + '.itely': TEXINFO, + '.latex': LATEX, + '.lytex': LATEX, + '.tely': TEXINFO, + '.tex': LATEX, + '.texi': TEXINFO, + '.texinfo': TEXINFO, + '.xml': HTML, } format2ext = { - HTML: '.html', - # TEXINFO: '.texinfo', - TEXINFO: '.texi', - LATEX: '.tex', + HTML: '.html', + # TEXINFO: '.texinfo', + TEXINFO: '.texi', + LATEX: '.tex', } class Compile_error: - pass + pass def write_file_map (lys, name): - snippet_map = open ('snippet-map.ly', 'w') - snippet_map.write (""" + snippet_map = open ('snippet-map.ly', 'w') + snippet_map.write (""" #(define version-seen? #t) #(ly:add-file-name-alist '( """) - for ly in lys: - snippet_map.write ('("%s.ly" . "%s:%d (%s.ly)")\n' - % (ly.basename (), - name, - ly.line_number, - ly.basename ())) + for ly in lys: + snippet_map.write ('("%s.ly" . "%s:%d (%s.ly)")\n' + % (ly.basename (), + name, + ly.line_number, + ly.basename ())) - snippet_map.write ('))\n') + snippet_map.write ('))\n') def do_process_cmd (chunks, input_name): - all_lys = filter (lambda x: is_derived_class (x.__class__, - Lilypond_snippet), - chunks) - - write_file_map (all_lys, input_name) - ly_outdated = \ - filter (lambda x: is_derived_class (x.__class__, - Lilypond_snippet) - and x.ly_is_outdated (), - chunks) - texstr_outdated = \ - filter (lambda x: is_derived_class (x.__class__, - Lilypond_snippet) - and x.texstr_is_outdated (), - chunks) - png_outdated = \ - filter (lambda x: is_derived_class (x.__class__, - Lilypond_snippet) - and x.png_is_outdated (), - chunks) - - progress (_ ("Writing snippets...")) - map (Lilypond_snippet.write_ly, ly_outdated) - progress ('\n') - - if ly_outdated: - progress (_ ("Processing...")) - progress ('\n') - process_snippets (global_options.process_cmd, ly_outdated, texstr_outdated, png_outdated) - else: - progress (_ ("All snippets are up to date...")) - progress ('\n') + all_lys = filter (lambda x: is_derived_class (x.__class__, + Lilypond_snippet), + chunks) + + write_file_map (all_lys, input_name) + ly_outdated = \ + filter (lambda x: is_derived_class (x.__class__, + Lilypond_snippet) + and x.ly_is_outdated (), + chunks) + texstr_outdated = \ + filter (lambda x: is_derived_class (x.__class__, + Lilypond_snippet) + and x.texstr_is_outdated (), + chunks) + png_outdated = \ + filter (lambda x: is_derived_class (x.__class__, + Lilypond_snippet) + and x.png_is_outdated (), + chunks) + + progress (_ ("Writing snippets...")) + map (Lilypond_snippet.write_ly, ly_outdated) + progress ('\n') + + if ly_outdated: + progress (_ ("Processing...")) + progress ('\n') + process_snippets (global_options.process_cmd, ly_outdated, texstr_outdated, png_outdated) + else: + progress (_ ("All snippets are up to date...")) + progress ('\n') def guess_format (input_filename): - format = None - e = os.path.splitext (input_filename)[1] - if e in ext2format.keys (): - # FIXME - format = ext2format[e] - else: - error (_ ("can't determine format for: %s" \ - % input_filename)) - exit (1) - return format + format = None + e = os.path.splitext (input_filename)[1] + if e in ext2format.keys (): + # FIXME + format = ext2format[e] + else: + error (_ ("can't determine format for: %s" \ + % input_filename)) + exit (1) + return format def write_if_updated (file_name, lines): - try: - f = open (file_name) - oldstr = f.read () - new_str = string.join (lines, '') - if oldstr == new_str: - progress (_ ("%s is up to date.") % file_name) - progress ('\n') - return - except: - pass - - progress (_ ("Writing `%s'...") % file_name) - open (file_name, 'w').writelines (lines) - progress ('\n') + try: + f = open (file_name) + oldstr = f.read () + new_str = string.join (lines, '') + if oldstr == new_str: + progress (_ ("%s is up to date.") % file_name) + progress ('\n') + return + except: + pass + + progress (_ ("Writing `%s'...") % file_name) + open (file_name, 'w').writelines (lines) + progress ('\n') def note_input_file (name, inputs=[]): - ## hack: inputs is mutable! - inputs.append (name) - return inputs + ## hack: inputs is mutable! + inputs.append (name) + return inputs def samefile (f1, f2): - try: - return os.path.samefile (f1, f2) - except AttributeError: # Windoze - f1 = re.sub ("//*", "/", f1) - f2 = re.sub ("//*", "/", f2) - return f1 == f2 + try: + return os.path.samefile (f1, f2) + except AttributeError: # Windoze + f1 = re.sub ("//*", "/", f1) + f2 = re.sub ("//*", "/", f2) + return f1 == f2 def do_file (input_filename): - # Ugh. - if not input_filename or input_filename == '-': - in_handle = sys.stdin - input_fullname = '' - else: - if os.path.exists (input_filename): - input_fullname = input_filename - elif global_options.format == LATEX and ly.search_exe_path ('kpsewhich'): - input_fullname = os.popen ('kpsewhich ' + input_filename).read()[:-1] - else: - input_fullname = find_file (input_filename) - - note_input_file (input_fullname) - in_handle = open (input_fullname) - - if input_filename == '-': - input_base = 'stdin' - else: - input_base = os.path.basename \ - (os.path.splitext (input_filename)[0]) - - # Only default to stdout when filtering. - if global_options.output_name == '-' or (not global_options.output_name and global_options.filter_cmd): - output_filename = '-' - output_file = sys.stdout - else: - # don't complain when global_options.output_name is existing - output_filename = input_base + format2ext[global_options.format] - if global_options.output_name: - if not os.path.isdir (global_options.output_name): - os.mkdir (global_options.output_name, 0777) - os.chdir (global_options.output_name) - else: - if os.path.exists (input_filename) \ - and os.path.exists (output_filename) \ - and samefile (output_filename, input_fullname): - error ( - _ ("Output would overwrite input file; use --output.")) - exit (2) - - try: - progress (_ ("Reading %s...") % input_fullname) - source = in_handle.read () - progress ('\n') - - set_default_options (source) - - - # FIXME: Containing blocks must be first, see - # find_toplevel_snippets. - snippet_types = ( - 'multiline_comment', - 'verbatim', - 'lilypond_block', - # 'verb', - 'singleline_comment', - 'lilypond_file', - 'include', - 'lilypond', - ) - progress (_ ("Dissecting...")) - chunks = find_toplevel_snippets (source, snippet_types) - - if global_options.format == LATEX: - for c in chunks: - if (c.is_plain () and - re.search (r"\\begin *{document}", c.replacement_text())): - modify_preamble (c) - break - progress ('\n') - - if global_options.filter_cmd: - write_if_updated (output_filename, - [c.filter_text () for c in chunks]) - elif global_options.process_cmd: - do_process_cmd (chunks, input_fullname) - progress (_ ("Compiling %s...") % output_filename) - progress ('\n') - write_if_updated (output_filename, - [s.replacement_text () - for s in chunks]) - - def process_include (snippet): - os.chdir (original_dir) - name = snippet.substring ('filename') - progress (_ ("Processing include: %s") % name) - progress ('\n') - return do_file (name) - - include_chunks = map (process_include, - filter (lambda x: is_derived_class (x.__class__, - Include_snippet), - chunks)) - - - return chunks + reduce (lambda x,y: x + y, include_chunks, []) - - except Compile_error: - os.chdir (original_dir) - progress (_ ("Removing `%s'") % output_filename) - progress ('\n') - raise Compile_error + # Ugh. + if not input_filename or input_filename == '-': + in_handle = sys.stdin + input_fullname = '' + else: + if os.path.exists (input_filename): + input_fullname = input_filename + elif global_options.format == LATEX and ly.search_exe_path ('kpsewhich'): + input_fullname = os.popen ('kpsewhich ' + input_filename).read()[:-1] + else: + input_fullname = find_file (input_filename) + + note_input_file (input_fullname) + in_handle = open (input_fullname) + + if input_filename == '-': + input_base = 'stdin' + else: + input_base = os.path.basename \ + (os.path.splitext (input_filename)[0]) + + # Only default to stdout when filtering. + if global_options.output_name == '-' or (not global_options.output_name and global_options.filter_cmd): + output_filename = '-' + output_file = sys.stdout + else: + # don't complain when global_options.output_name is existing + output_filename = input_base + format2ext[global_options.format] + if global_options.output_name: + if not os.path.isdir (global_options.output_name): + os.mkdir (global_options.output_name, 0777) + os.chdir (global_options.output_name) + else: + if os.path.exists (input_filename) \ + and os.path.exists (output_filename) \ + and samefile (output_filename, input_fullname): + error ( + _ ("Output would overwrite input file; use --output.")) + exit (2) + + try: + progress (_ ("Reading %s...") % input_fullname) + source = in_handle.read () + progress ('\n') + + set_default_options (source) + + + # FIXME: Containing blocks must be first, see + # find_toplevel_snippets. + snippet_types = ( + 'multiline_comment', + 'verbatim', + 'lilypond_block', + # 'verb', + 'singleline_comment', + 'lilypond_file', + 'include', + 'lilypond', + ) + progress (_ ("Dissecting...")) + chunks = find_toplevel_snippets (source, snippet_types) + + if global_options.format == LATEX: + for c in chunks: + if (c.is_plain () and + re.search (r"\\begin *{document}", c.replacement_text())): + modify_preamble (c) + break + progress ('\n') + + if global_options.filter_cmd: + write_if_updated (output_filename, + [c.filter_text () for c in chunks]) + elif global_options.process_cmd: + do_process_cmd (chunks, input_fullname) + progress (_ ("Compiling %s...") % output_filename) + progress ('\n') + write_if_updated (output_filename, + [s.replacement_text () + for s in chunks]) + + def process_include (snippet): + os.chdir (original_dir) + name = snippet.substring ('filename') + progress (_ ("Processing include: %s") % name) + progress ('\n') + return do_file (name) + + include_chunks = map (process_include, + filter (lambda x: is_derived_class (x.__class__, + Include_snippet), + chunks)) + + + return chunks + reduce (lambda x,y: x + y, include_chunks, []) + + except Compile_error: + os.chdir (original_dir) + progress (_ ("Removing `%s'") % output_filename) + progress ('\n') + raise Compile_error def do_options (): - global global_options + global global_options - opt_parser = get_option_parser() - (global_options, args) = opt_parser.parse_args () + opt_parser = get_option_parser() + (global_options, args) = opt_parser.parse_args () - if global_options.format in ('texi-html', 'texi'): - global_options.format = TEXINFO - global_options.use_hash = True + if global_options.format in ('texi-html', 'texi'): + global_options.format = TEXINFO + global_options.use_hash = True - global_options.include_path = map (os.path.abspath, global_options.include_path) - - if global_options.warranty: - warranty () - exit (0) - if not args or len (args) > 1: - opt_parser.print_help () - exit (2) - - return args + global_options.include_path = map (os.path.abspath, global_options.include_path) + + if global_options.warranty: + warranty () + exit (0) + if not args or len (args) > 1: + opt_parser.print_help () + exit (2) + + return args def main (): - files = do_options () - - file = files[0] - - basename = os.path.splitext (file)[0] - basename = os.path.split (basename)[1] - - if not global_options.format: - global_options.format = guess_format (files[0]) - - formats = 'ps' - if global_options.format in (TEXINFO, HTML): - formats += ',png' - if global_options.process_cmd == '': - global_options.process_cmd = lilypond_binary \ - + ' --formats=%s --backend eps ' % formats - - if global_options.process_cmd: - global_options.process_cmd += string.join ([(' -I %s' % commands.mkarg (p)) - for p in global_options.include_path]) - - identify () - - try: - chunks = do_file (file) - if global_options.psfonts: - fontextract.verbose = global_options.verbose - snippet_chunks = filter (lambda x: is_derived_class (x.__class__, - Lilypond_snippet), - chunks) - - psfonts_file = basename + '.psfonts' - if not global_options.verbose: - progress (_ ("Writing fonts to %s...") % psfonts_file) - fontextract.extract_fonts (psfonts_file, - [x.basename() + '.eps' - for x in snippet_chunks]) - if not global_options.verbose: - progress ('\n') - - except Compile_error: - exit (1) - - if global_options.format in (TEXINFO, LATEX): - if not global_options.psfonts: - warning (_ ("option --psfonts not used")) - warning (_ ("processing with dvips will have no fonts")) - - psfonts_file = os.path.join (global_options.output_name, basename + '.psfonts') - output = os.path.join (global_options.output_name, basename + '.dvi' ) - - progress ('\n') - progress (_ ("DVIPS usage:")) - progress ('\n') - progress (" dvips -h %(psfonts_file)s %(output)s" % vars ()) - progress ('\n') - - inputs = note_input_file ('') - inputs.pop () - - base_file_name = os.path.splitext (os.path.basename (file))[0] - dep_file = os.path.join (global_options.output_name, base_file_name + '.dep') - final_output_file = os.path.join (global_options.output_name, - base_file_name - + '.%s' % global_options.format) - - os.chdir (original_dir) - open (dep_file, 'w').write ('%s: %s' % (final_output_file, ' '.join (inputs))) + files = do_options () + + file = files[0] + + basename = os.path.splitext (file)[0] + basename = os.path.split (basename)[1] + + if not global_options.format: + global_options.format = guess_format (files[0]) + + formats = 'ps' + if global_options.format in (TEXINFO, HTML): + formats += ',png' + if global_options.process_cmd == '': + global_options.process_cmd = lilypond_binary \ + + ' --formats=%s --backend eps ' % formats + + if global_options.process_cmd: + global_options.process_cmd += string.join ([(' -I %s' % commands.mkarg (p)) + for p in global_options.include_path]) + + identify () + + try: + chunks = do_file (file) + if global_options.psfonts: + fontextract.verbose = global_options.verbose + snippet_chunks = filter (lambda x: is_derived_class (x.__class__, + Lilypond_snippet), + chunks) + + psfonts_file = basename + '.psfonts' + if not global_options.verbose: + progress (_ ("Writing fonts to %s...") % psfonts_file) + fontextract.extract_fonts (psfonts_file, + [x.basename() + '.eps' + for x in snippet_chunks]) + if not global_options.verbose: + progress ('\n') + + except Compile_error: + exit (1) + + if global_options.format in (TEXINFO, LATEX): + if not global_options.psfonts: + warning (_ ("option --psfonts not used")) + warning (_ ("processing with dvips will have no fonts")) + + psfonts_file = os.path.join (global_options.output_name, basename + '.psfonts') + output = os.path.join (global_options.output_name, basename + '.dvi' ) + + progress ('\n') + progress (_ ("DVIPS usage:")) + progress ('\n') + progress (" dvips -h %(psfonts_file)s %(output)s" % vars ()) + progress ('\n') + + inputs = note_input_file ('') + inputs.pop () + + base_file_name = os.path.splitext (os.path.basename (file))[0] + dep_file = os.path.join (global_options.output_name, base_file_name + '.dep') + final_output_file = os.path.join (global_options.output_name, + base_file_name + + '.%s' % global_options.format) + + os.chdir (original_dir) + open (dep_file, 'w').write ('%s: %s' % (final_output_file, ' '.join (inputs))) if __name__ == '__main__': - main () + main () diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py index c61cce84ed..a3b53d8fa2 100644 --- a/scripts/midi2ly.py +++ b/scripts/midi2ly.py @@ -10,15 +10,15 @@ ''' TODO: - * test on weird and unquantised midi input (lily-devel) - * update doc and manpage - - * simply insert clef changes whenever too many ledger lines - [to avoid tex capacity exceeded] - * do not ever quant skips - * better lyrics handling - * [see if it is feasible to] move ly-classes to library for use in - other converters, while leaving midi specific stuff here + * test on weird and unquantised midi input (lily-devel) + * update doc and manpage + + * simply insert clef changes whenever too many ledger lines + [to avoid tex capacity exceeded] + * do not ever quant skips + * better lyrics handling + * [see if it is feasible to] move ly-classes to library for use in + other converters, while leaving midi specific stuff here ''' import os @@ -31,21 +31,21 @@ import sys # libdir = '@local_lilypond_libdir@' if not os.path.isdir (libdir): - libdir = '@lilypond_libdir@' + libdir = '@lilypond_libdir@' # ugh datadir = '@local_lilypond_datadir@' if os.environ.has_key ('LILYPONDPREFIX'): - datadir = os.environ['LILYPONDPREFIX'] - while datadir[-1] == os.sep: - datadir= datadir[:-1] - libdir = datadir.replace ('/share/', '/lib/') + datadir = os.environ['LILYPONDPREFIX'] + while datadir[-1] == os.sep: + datadir= datadir[:-1] + libdir = datadir.replace ('/share/', '/lib/') if os.path.exists (os.path.join (datadir, 'lib/lilypond/@TOPLEVEL_VERSION@/')): - libdir = os.path.join (libdir, 'lib/lilypond/@TOPLEVEL_VERSION@/') + libdir = os.path.join (libdir, 'lib/lilypond/@TOPLEVEL_VERSION@/') if os.path.exists (os.path.join (datadir, 'lib/lilypond/current/')): - libdir = os.path.join (libdir, 'lib/lilypond/current/') + libdir = os.path.join (libdir, 'lib/lilypond/current/') sys.path.insert (0, os.path.join (libdir, 'python')) @@ -53,8 +53,8 @@ sys.path.insert (0, os.path.join (libdir, 'python')) bindir = os.path.split (sys.argv[0])[0] for prefix_component in ['share', 'lib']: - datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % prefix_component) - sys.path.insert (0, datadir) + datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % prefix_component) + sys.path.insert (0, datadir) import midi import lilylib as ly @@ -84,13 +84,13 @@ allowed_tuplet_clocks = [] localedir = '@localedir@' try: - import gettext - gettext.bindtextdomain ('lilypond', localedir) - gettext.textdomain ('lilypond') - _ = gettext.gettext + import gettext + gettext.bindtextdomain ('lilypond', localedir) + gettext.textdomain ('lilypond') + _ = gettext.gettext except: - def _ (s): - return s + def _ (s): + return s program_name = sys.argv[0] program_version = '@TOPLEVEL_VERSION@' @@ -98,907 +98,907 @@ program_version = '@TOPLEVEL_VERSION@' errorport = sys.stderr def identify (): - sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) + sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) def warranty (): - identify () - sys.stdout.write (''' + identify () + sys.stdout.write (''' Copyright (c) %s by - Han-Wen Nienhuys - Jan Nieuwenhuizen + Han-Wen Nienhuys + Jan Nieuwenhuizen %s %s ''' ( '2001--2006', - _('Distributed under terms of the GNU General Public License.'), - _('It comes with NO WARRANTY.'))) + _('Distributed under terms of the GNU General Public License.'), + _('It comes with NO WARRANTY.'))) def progress (s): - errorport.write (s + '\n') + errorport.write (s + '\n') def warning (s): - progress (_ ("warning: ") + s) - + progress (_ ("warning: ") + s) + def error (s): - progress (_ ("error: ") + s) - raise _ ("Exiting ... ") + progress (_ ("error: ") + s) + raise _ ("Exiting ... ") def system (cmd, ignore_error = 0): - return ly.system (cmd, ignore_error=ignore_error) + return ly.system (cmd, ignore_error=ignore_error) def strip_extension (f, ext): - (p, e) = os.path.splitext (f) - if e == ext: - e = '' - return p + e + (p, e) = os.path.splitext (f) + if e == ext: + e = '' + return p + e class Duration: - allowed_durs = (1, 2, 4, 8, 16, 32, 64, 128) - def __init__ (self, clocks): - self.clocks = clocks - if clocks <= 0: - self.clocks = duration_quant_clocks - (self.dur, self.num, self.den) = self.dur_num_den (clocks) - - def dur_num_den (self, clocks): - for i in range (len (allowed_tuplet_clocks)): - if clocks == allowed_tuplet_clocks[i]: - return global_options.allowed_tuplets[i] - - dur = 0; num = 1; den = 1; - g = gcd (clocks, clocks_per_1) - if g: - (dur, num) = (clocks_per_1 / g, clocks / g) - if not dur in self.allowed_durs: - dur = 4; num = clocks; den = clocks_per_4 - return (dur, num, den) - - def dump (self): - if self.den == 1: - if self.num == 1: - s = '%d' % self.dur - elif self.num == 3 and self.dur != 1: - s = '%d.' % (self.dur / 2) - else: - s = '%d*%d' % (self.dur, self.num) - else: - s = '%d*%d/%d' % (self.dur, self.num, self.den) - - global reference_note - reference_note.duration = self - - return s - - def compare (self, other): - return self.clocks - other.clocks + allowed_durs = (1, 2, 4, 8, 16, 32, 64, 128) + def __init__ (self, clocks): + self.clocks = clocks + if clocks <= 0: + self.clocks = duration_quant_clocks + (self.dur, self.num, self.den) = self.dur_num_den (clocks) + + def dur_num_den (self, clocks): + for i in range (len (allowed_tuplet_clocks)): + if clocks == allowed_tuplet_clocks[i]: + return global_options.allowed_tuplets[i] + + dur = 0; num = 1; den = 1; + g = gcd (clocks, clocks_per_1) + if g: + (dur, num) = (clocks_per_1 / g, clocks / g) + if not dur in self.allowed_durs: + dur = 4; num = clocks; den = clocks_per_4 + return (dur, num, den) + + def dump (self): + if self.den == 1: + if self.num == 1: + s = '%d' % self.dur + elif self.num == 3 and self.dur != 1: + s = '%d.' % (self.dur / 2) + else: + s = '%d*%d' % (self.dur, self.num) + else: + s = '%d*%d/%d' % (self.dur, self.num, self.den) + + global reference_note + reference_note.duration = self + + return s + + def compare (self, other): + return self.clocks - other.clocks def sign (x): - if x >= 0: - return 1 - else: - return -1 + if x >= 0: + return 1 + else: + return -1 class Note: - names = (0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6) - alterations = (0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0) - alteration_names = ('eses', 'es', '', 'is' , 'isis') - def __init__ (self, clocks, pitch, velocity): - self.pitch = pitch - self.velocity = velocity - # hmm - self.clocks = clocks - self.duration = Duration (clocks) - (self.octave, self.notename, self.alteration) = self.o_n_a () - - def o_n_a (self): - # major scale: do-do - # minor scale: la-la (= + 5) ''' - - n = self.names[(self.pitch) % 12] - a = self.alterations[(self.pitch) % 12] - - if a and global_options.key.flats: - a = - self.alterations[(self.pitch) % 12] - n = (n - a) % 7 - - # By tradition, all scales now consist of a sequence - # of 7 notes each with a distinct name, from amongst - # a b c d e f g. But, minor scales have a wide - # second interval at the top - the 'leading note' is - # sharped. (Why? it just works that way! Anything - # else doesn't sound as good and isn't as flexible at - # saying things. In medieval times, scales only had 6 - # notes to avoid this problem - the hexachords.) - - # So, the d minor scale is d e f g a b-flat c-sharp d - # - using d-flat for the leading note would skip the - # name c and duplicate the name d. Why isn't c-sharp - # put in the key signature? Tradition. (It's also - # supposedly based on the Pythagorean theory of the - # cycle of fifths, but that really only applies to - # major scales...) Anyway, g minor is g a b-flat c d - # e-flat f-sharp g, and all the other flat minor keys - # end up with a natural leading note. And there you - # have it. - - # John Sankey - # - # Let's also do a-minor: a b c d e f gis a - # - # --jcn - - o = self.pitch / 12 - 4 - - key = global_options.key - if key.minor: - # as -> gis - if key.sharps == 0 and key.flats == 0 \ - and n == 5 and a == -1: - n = 4; a = 1 - # des -> cis - elif key.flats == 1 and n == 1 and a == -1: - n = 0; a = 1 - # ges -> fis - elif key.flats == 2 and n == 4 and a == -1: - n = 3; a = 1 - # g -> fisis - elif key.sharps == 5 and n == 4 and a == 0: - n = 3; a = 2 - # d -> cisis - elif key.sharps == 6 and n == 1 and a == 0: - n = 0; a = 2 - # a -> gisis - elif key.sharps == 7 and n == 5 and a == 0: - n = 4; a = 2 - - # b -> ces - if key.flats >= 6 and n == 6 and a == 0: - n = 0; a = -1; o = o + 1 - # e -> fes - if key.flats >= 7 and n == 2 and a == 0: - n = 3; a = -1 - - # f -> eis - if key.sharps >= 3 and n == 3 and a == 0: - n = 2; a = 1 - # c -> bis - if key.sharps >= 4 and n == 0 and a == 0: - n = 6; a = 1; o = o - 1 - - return (o, n, a) - - def __repr__ (self): - s = chr ((self.notename + 2) % 7 + ord ('a')) - return 'Note(%s %s)' % (s, self.duration.dump()) - - def dump (self, dump_dur = 1): - global reference_note - s = chr ((self.notename + 2) % 7 + ord ('a')) - s = s + self.alteration_names[self.alteration + 2] - if global_options.absolute_pitches: - commas = self.octave - else: - delta = self.pitch - reference_note.pitch - commas = sign (delta) * (abs (delta) / 12) - if ((sign (delta) \ - * (self.notename - reference_note.notename) + 7) \ - % 7 >= 4) \ - or ((self.notename == reference_note.notename) \ - and (abs (delta) > 4) and (abs (delta) < 12)): - commas = commas + sign (delta) - - if commas > 0: - s = s + "'" * commas - elif commas < 0: - s = s + "," * -commas - - ## FIXME: compile fix --jcn - if dump_dur and (global_options.explicit_durations \ - or self.duration.compare (reference_note.duration)): - s = s + self.duration.dump () - - reference_note = self - - # TODO: move space - return s + ' ' + names = (0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6) + alterations = (0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0) + alteration_names = ('eses', 'es', '', 'is' , 'isis') + def __init__ (self, clocks, pitch, velocity): + self.pitch = pitch + self.velocity = velocity + # hmm + self.clocks = clocks + self.duration = Duration (clocks) + (self.octave, self.notename, self.alteration) = self.o_n_a () + + def o_n_a (self): + # major scale: do-do + # minor scale: la-la (= + 5) ''' + + n = self.names[(self.pitch) % 12] + a = self.alterations[(self.pitch) % 12] + + if a and global_options.key.flats: + a = - self.alterations[(self.pitch) % 12] + n = (n - a) % 7 + + # By tradition, all scales now consist of a sequence + # of 7 notes each with a distinct name, from amongst + # a b c d e f g. But, minor scales have a wide + # second interval at the top - the 'leading note' is + # sharped. (Why? it just works that way! Anything + # else doesn't sound as good and isn't as flexible at + # saying things. In medieval times, scales only had 6 + # notes to avoid this problem - the hexachords.) + + # So, the d minor scale is d e f g a b-flat c-sharp d + # - using d-flat for the leading note would skip the + # name c and duplicate the name d. Why isn't c-sharp + # put in the key signature? Tradition. (It's also + # supposedly based on the Pythagorean theory of the + # cycle of fifths, but that really only applies to + # major scales...) Anyway, g minor is g a b-flat c d + # e-flat f-sharp g, and all the other flat minor keys + # end up with a natural leading note. And there you + # have it. + + # John Sankey + # + # Let's also do a-minor: a b c d e f gis a + # + # --jcn + + o = self.pitch / 12 - 4 + + key = global_options.key + if key.minor: + # as -> gis + if key.sharps == 0 and key.flats == 0 \ + and n == 5 and a == -1: + n = 4; a = 1 + # des -> cis + elif key.flats == 1 and n == 1 and a == -1: + n = 0; a = 1 + # ges -> fis + elif key.flats == 2 and n == 4 and a == -1: + n = 3; a = 1 + # g -> fisis + elif key.sharps == 5 and n == 4 and a == 0: + n = 3; a = 2 + # d -> cisis + elif key.sharps == 6 and n == 1 and a == 0: + n = 0; a = 2 + # a -> gisis + elif key.sharps == 7 and n == 5 and a == 0: + n = 4; a = 2 + + # b -> ces + if key.flats >= 6 and n == 6 and a == 0: + n = 0; a = -1; o = o + 1 + # e -> fes + if key.flats >= 7 and n == 2 and a == 0: + n = 3; a = -1 + + # f -> eis + if key.sharps >= 3 and n == 3 and a == 0: + n = 2; a = 1 + # c -> bis + if key.sharps >= 4 and n == 0 and a == 0: + n = 6; a = 1; o = o - 1 + + return (o, n, a) + + def __repr__ (self): + s = chr ((self.notename + 2) % 7 + ord ('a')) + return 'Note(%s %s)' % (s, self.duration.dump()) + + def dump (self, dump_dur = 1): + global reference_note + s = chr ((self.notename + 2) % 7 + ord ('a')) + s = s + self.alteration_names[self.alteration + 2] + if global_options.absolute_pitches: + commas = self.octave + else: + delta = self.pitch - reference_note.pitch + commas = sign (delta) * (abs (delta) / 12) + if ((sign (delta) \ + * (self.notename - reference_note.notename) + 7) \ + % 7 >= 4) \ + or ((self.notename == reference_note.notename) \ + and (abs (delta) > 4) and (abs (delta) < 12)): + commas = commas + sign (delta) + + if commas > 0: + s = s + "'" * commas + elif commas < 0: + s = s + "," * -commas + + ## FIXME: compile fix --jcn + if dump_dur and (global_options.explicit_durations \ + or self.duration.compare (reference_note.duration)): + s = s + self.duration.dump () + + reference_note = self + + # TODO: move space + return s + ' ' class Time: - def __init__ (self, num, den): - self.clocks = 0 - self.num = num - self.den = den - - def bar_clocks (self): - return clocks_per_1 * self.num / self.den - - def __repr__ (self): - return 'Time(%d/%d)' % (self.num, self.den) - - def dump (self): - global time - time = self - return '\n ' + '\\time %d/%d ' % (self.num, self.den) + '\n ' + def __init__ (self, num, den): + self.clocks = 0 + self.num = num + self.den = den + + def bar_clocks (self): + return clocks_per_1 * self.num / self.den + + def __repr__ (self): + return 'Time(%d/%d)' % (self.num, self.den) + + def dump (self): + global time + time = self + return '\n ' + '\\time %d/%d ' % (self.num, self.den) + '\n ' class Tempo: - def __init__ (self, seconds_per_1): - self.clocks = 0 - self.seconds_per_1 = seconds_per_1 - - def __repr__ (self): - return 'Tempo(%d)' % self.bpm () - - def bpm (self): - return 4 * 60 / self.seconds_per_1 - - def dump (self): - return '\n ' + '\\tempo 4 = %d ' % (self.bpm()) + '\n ' + def __init__ (self, seconds_per_1): + self.clocks = 0 + self.seconds_per_1 = seconds_per_1 + + def __repr__ (self): + return 'Tempo(%d)' % self.bpm () + + def bpm (self): + return 4 * 60 / self.seconds_per_1 + + def dump (self): + return '\n ' + '\\tempo 4 = %d ' % (self.bpm()) + '\n ' class Clef: - clefs = ('"bass_8"', 'bass', 'violin', '"violin^8"') - def __init__ (self, type): - self.type = type + clefs = ('"bass_8"', 'bass', 'violin', '"violin^8"') + def __init__ (self, type): + self.type = type - def __repr__ (self): - return 'Clef(%s)' % self.clefs[self.type] - - def dump (self): - return '\n \\clef %s\n ' % self.clefs[self.type] + def __repr__ (self): + return 'Clef(%s)' % self.clefs[self.type] + + def dump (self): + return '\n \\clef %s\n ' % self.clefs[self.type] class Key: - key_sharps = ('c', 'g', 'd', 'a', 'e', 'b', 'fis') - key_flats = ('BUG', 'f', 'bes', 'es', 'as', 'des', 'ges') - - def __init__ (self, sharps, flats, minor): - self.clocks = 0 - self.flats = flats - self.sharps = sharps - self.minor = minor - - def dump (self): - global_options.key = self - - s = '' - if self.sharps and self.flats: - pass - else: - if self.flats: - k = (ord ('cfbeadg'[self.flats % 7]) - ord ('a') - 2 -2 * self.minor + 7) % 7 - else: - k = (ord ('cgdaebf'[self.sharps % 7]) - ord ('a') - 2 -2 * self.minor + 7) % 7 - - if not self.minor: - name = chr ((k + 2) % 7 + ord ('a')) - else: - name = chr ((k + 2) % 7 + ord ('a')) - - # fis cis gis dis ais eis bis - sharps = (2, 4, 6, 1, 3, 5, 7) - # bes es as des ges ces fes - flats = (6, 4, 2, 7, 5, 3, 1) - a = 0 - if self.flats: - if flats[k] <= self.flats: - a = -1 - else: - if sharps[k] <= self.sharps: - a = 1 - - if a: - name = name + Note.alteration_names[a + 2] - - s = '\\key ' + name - if self.minor: - s = s + ' \\minor' - else: - s = s + ' \\major' - - return '\n\n ' + s + '\n ' + key_sharps = ('c', 'g', 'd', 'a', 'e', 'b', 'fis') + key_flats = ('BUG', 'f', 'bes', 'es', 'as', 'des', 'ges') + + def __init__ (self, sharps, flats, minor): + self.clocks = 0 + self.flats = flats + self.sharps = sharps + self.minor = minor + + def dump (self): + global_options.key = self + + s = '' + if self.sharps and self.flats: + pass + else: + if self.flats: + k = (ord ('cfbeadg'[self.flats % 7]) - ord ('a') - 2 -2 * self.minor + 7) % 7 + else: + k = (ord ('cgdaebf'[self.sharps % 7]) - ord ('a') - 2 -2 * self.minor + 7) % 7 + + if not self.minor: + name = chr ((k + 2) % 7 + ord ('a')) + else: + name = chr ((k + 2) % 7 + ord ('a')) + + # fis cis gis dis ais eis bis + sharps = (2, 4, 6, 1, 3, 5, 7) + # bes es as des ges ces fes + flats = (6, 4, 2, 7, 5, 3, 1) + a = 0 + if self.flats: + if flats[k] <= self.flats: + a = -1 + else: + if sharps[k] <= self.sharps: + a = 1 + + if a: + name = name + Note.alteration_names[a + 2] + + s = '\\key ' + name + if self.minor: + s = s + ' \\minor' + else: + s = s + ' \\major' + + return '\n\n ' + s + '\n ' class Text: - text_types = ( - 'SEQUENCE_NUMBER', - 'TEXT_EVENT', - 'COPYRIGHT_NOTICE', - 'SEQUENCE_TRACK_NAME', - 'INSTRUMENT_NAME', - 'LYRIC', - 'MARKER', - 'CUE_POINT',) - - def __init__ (self, type, text): - self.clocks = 0 - self.type = type - self.text = text - - def dump (self): - # urg, we should be sure that we're in a lyrics staff - if self.type == midi.LYRIC: - s = '"%s"' % self.text - d = Duration (self.clocks) - if global_options.explicit_durations \ - or d.compare (reference_note.duration): - s = s + Duration (self.clocks).dump () - s = s + ' ' - else: - s = '\n % [' + self.text_types[self.type] + '] ' + self.text + '\n ' - return s - - def __repr__ (self): - return 'Text(%d=%s)' % (self.type, self.text) + text_types = ( + 'SEQUENCE_NUMBER', + 'TEXT_EVENT', + 'COPYRIGHT_NOTICE', + 'SEQUENCE_TRACK_NAME', + 'INSTRUMENT_NAME', + 'LYRIC', + 'MARKER', + 'CUE_POINT',) + + def __init__ (self, type, text): + self.clocks = 0 + self.type = type + self.text = text + + def dump (self): + # urg, we should be sure that we're in a lyrics staff + if self.type == midi.LYRIC: + s = '"%s"' % self.text + d = Duration (self.clocks) + if global_options.explicit_durations \ + or d.compare (reference_note.duration): + s = s + Duration (self.clocks).dump () + s = s + ' ' + else: + s = '\n % [' + self.text_types[self.type] + '] ' + self.text + '\n ' + return s + + def __repr__ (self): + return 'Text(%d=%s)' % (self.type, self.text) def split_track (track): - chs = {} - for i in range(16): - chs[i] = [] - - for e in track: - data = list (e[1]) - if data[0] > 0x7f and data[0] < 0xf0: - c = data[0] & 0x0f - e = (e[0], tuple ([data[0] & 0xf0] + data[1:])) - chs[c].append (e) - else: - chs[0].append (e) - - for i in range (16): - if chs[i] == []: - del chs[i] - - threads = [] - for v in chs.values (): - events = events_on_channel (v) - thread = unthread_notes (events) - if len (thread): - threads.append (thread) - return threads + chs = {} + for i in range(16): + chs[i] = [] + + for e in track: + data = list (e[1]) + if data[0] > 0x7f and data[0] < 0xf0: + c = data[0] & 0x0f + e = (e[0], tuple ([data[0] & 0xf0] + data[1:])) + chs[c].append (e) + else: + chs[0].append (e) + + for i in range (16): + if chs[i] == []: + del chs[i] + + threads = [] + for v in chs.values (): + events = events_on_channel (v) + thread = unthread_notes (events) + if len (thread): + threads.append (thread) + return threads def quantise_clocks (clocks, quant): - q = int (clocks / quant) * quant - if q != clocks: - for tquant in allowed_tuplet_clocks: - if int (clocks / tquant) * tquant == clocks: - return clocks - if 2 * (clocks - q) > quant: - q = q + quant - return q + q = int (clocks / quant) * quant + if q != clocks: + for tquant in allowed_tuplet_clocks: + if int (clocks / tquant) * tquant == clocks: + return clocks + if 2 * (clocks - q) > quant: + q = q + quant + return q def end_note (pitches, notes, t, e): - try: - (lt, vel) = pitches[e] - del pitches[e] - - i = len (notes) - 1 - while i > 0: - if notes[i][0] > lt: - i = i -1 - else: - break - d = t - lt - if duration_quant_clocks: - d = quantise_clocks (d, duration_quant_clocks) - if not d: - d = duration_quant_clocks - - notes.insert (i + 1, - (lt, Note (d, e, vel))) - - except KeyError: - pass + try: + (lt, vel) = pitches[e] + del pitches[e] + + i = len (notes) - 1 + while i > 0: + if notes[i][0] > lt: + i = i -1 + else: + break + d = t - lt + if duration_quant_clocks: + d = quantise_clocks (d, duration_quant_clocks) + if not d: + d = duration_quant_clocks + + notes.insert (i + 1, + (lt, Note (d, e, vel))) + + except KeyError: + pass def events_on_channel (channel): - pitches = {} - - notes = [] - events = [] - last_lyric = 0 - last_time = 0 - for e in channel: - t = e[0] - - if start_quant_clocks: - t = quantise_clocks (t, start_quant_clocks) - - - if e[1][0] == midi.NOTE_OFF \ - or (e[1][0] == midi.NOTE_ON and e[1][2] == 0): - end_note (pitches, notes, t, e[1][1]) - - elif e[1][0] == midi.NOTE_ON: - if not pitches.has_key (e[1][1]): - pitches[e[1][1]] = (t, e[1][2]) - - # all include ALL_NOTES_OFF - elif e[1][0] >= midi.ALL_SOUND_OFF \ - and e[1][0] <= midi.POLY_MODE_ON: - for i in pitches.keys (): - end_note (pitches, notes, t, i) - - elif e[1][0] == midi.META_EVENT: - if e[1][1] == midi.END_OF_TRACK: - for i in pitches.keys (): - end_note (pitches, notes, t, i) - break - - elif e[1][1] == midi.SET_TEMPO: - (u0, u1, u2) = map (ord, e[1][2]) - us_per_4 = u2 + 256 * (u1 + 256 * u0) - seconds_per_1 = us_per_4 * 4 / 1e6 - events.append ((t, Tempo (seconds_per_1))) - elif e[1][1] == midi.TIME_SIGNATURE: - (num, dur, clocks4, count32) = map (ord, e[1][2]) - den = 2 ** dur - events.append ((t, Time (num, den))) - elif e[1][1] == midi.KEY_SIGNATURE: - (alterations, minor) = map (ord, e[1][2]) - sharps = 0 - flats = 0 - if alterations < 127: - sharps = alterations - else: - flats = 256 - alterations - - k = Key (sharps, flats, minor) - events.append ((t, k)) - - # ugh, must set key while parsing - # because Note init uses key - # Better do Note.calc () at dump time? - global_options.key = k - - elif e[1][1] == midi.LYRIC \ - or (global_options.text_lyrics and e[1][1] == midi.TEXT_EVENT): - if last_lyric: - last_lyric.clocks = t - last_time - events.append ((last_time, last_lyric)) - last_time = t - last_lyric = Text (midi.LYRIC, e[1][2]) - - elif e[1][1] >= midi.SEQUENCE_NUMBER \ - and e[1][1] <= midi.CUE_POINT: - events.append ((t, Text (e[1][1], e[1][2]))) - else: - if global_options.verbose: - sys.stderr.write ("SKIP: %s\n" % `e`) - pass - else: - if global_options.verbose: - sys.stderr.write ("SKIP: %s\n" % `e`) - pass - - if last_lyric: - # last_lyric.clocks = t - last_time - # hmm - last_lyric.clocks = clocks_per_4 - events.append ((last_time, last_lyric)) - last_lyric = 0 - - i = 0 - while len (notes): - if i < len (events) and notes[0][0] >= events[i][0]: - i = i + 1 - else: - events.insert (i, notes[0]) - del notes[0] - return events + pitches = {} + + notes = [] + events = [] + last_lyric = 0 + last_time = 0 + for e in channel: + t = e[0] + + if start_quant_clocks: + t = quantise_clocks (t, start_quant_clocks) + + + if e[1][0] == midi.NOTE_OFF \ + or (e[1][0] == midi.NOTE_ON and e[1][2] == 0): + end_note (pitches, notes, t, e[1][1]) + + elif e[1][0] == midi.NOTE_ON: + if not pitches.has_key (e[1][1]): + pitches[e[1][1]] = (t, e[1][2]) + + # all include ALL_NOTES_OFF + elif e[1][0] >= midi.ALL_SOUND_OFF \ + and e[1][0] <= midi.POLY_MODE_ON: + for i in pitches.keys (): + end_note (pitches, notes, t, i) + + elif e[1][0] == midi.META_EVENT: + if e[1][1] == midi.END_OF_TRACK: + for i in pitches.keys (): + end_note (pitches, notes, t, i) + break + + elif e[1][1] == midi.SET_TEMPO: + (u0, u1, u2) = map (ord, e[1][2]) + us_per_4 = u2 + 256 * (u1 + 256 * u0) + seconds_per_1 = us_per_4 * 4 / 1e6 + events.append ((t, Tempo (seconds_per_1))) + elif e[1][1] == midi.TIME_SIGNATURE: + (num, dur, clocks4, count32) = map (ord, e[1][2]) + den = 2 ** dur + events.append ((t, Time (num, den))) + elif e[1][1] == midi.KEY_SIGNATURE: + (alterations, minor) = map (ord, e[1][2]) + sharps = 0 + flats = 0 + if alterations < 127: + sharps = alterations + else: + flats = 256 - alterations + + k = Key (sharps, flats, minor) + events.append ((t, k)) + + # ugh, must set key while parsing + # because Note init uses key + # Better do Note.calc () at dump time? + global_options.key = k + + elif e[1][1] == midi.LYRIC \ + or (global_options.text_lyrics and e[1][1] == midi.TEXT_EVENT): + if last_lyric: + last_lyric.clocks = t - last_time + events.append ((last_time, last_lyric)) + last_time = t + last_lyric = Text (midi.LYRIC, e[1][2]) + + elif e[1][1] >= midi.SEQUENCE_NUMBER \ + and e[1][1] <= midi.CUE_POINT: + events.append ((t, Text (e[1][1], e[1][2]))) + else: + if global_options.verbose: + sys.stderr.write ("SKIP: %s\n" % `e`) + pass + else: + if global_options.verbose: + sys.stderr.write ("SKIP: %s\n" % `e`) + pass + + if last_lyric: + # last_lyric.clocks = t - last_time + # hmm + last_lyric.clocks = clocks_per_4 + events.append ((last_time, last_lyric)) + last_lyric = 0 + + i = 0 + while len (notes): + if i < len (events) and notes[0][0] >= events[i][0]: + i = i + 1 + else: + events.insert (i, notes[0]) + del notes[0] + return events def unthread_notes (channel): - threads = [] - while channel: - thread = [] - end_busy_t = 0 - start_busy_t = 0 - todo = [] - for e in channel: - t = e[0] - if e[1].__class__ == Note \ - and ((t == start_busy_t \ - and e[1].clocks + t == end_busy_t) \ - or t >= end_busy_t): - thread.append (e) - start_busy_t = t - end_busy_t = t + e[1].clocks - elif e[1].__class__ == Time \ - or e[1].__class__ == Key \ - or e[1].__class__ == Text \ - or e[1].__class__ == Tempo: - thread.append (e) - else: - todo.append (e) - threads.append (thread) - channel = todo - - return threads + threads = [] + while channel: + thread = [] + end_busy_t = 0 + start_busy_t = 0 + todo = [] + for e in channel: + t = e[0] + if e[1].__class__ == Note \ + and ((t == start_busy_t \ + and e[1].clocks + t == end_busy_t) \ + or t >= end_busy_t): + thread.append (e) + start_busy_t = t + end_busy_t = t + e[1].clocks + elif e[1].__class__ == Time \ + or e[1].__class__ == Key \ + or e[1].__class__ == Text \ + or e[1].__class__ == Tempo: + thread.append (e) + else: + todo.append (e) + threads.append (thread) + channel = todo + + return threads def gcd (a,b): - if b == 0: - return a - c = a - while c: - c = a % b - a = b - b = c - return a - + if b == 0: + return a + c = a + while c: + c = a % b + a = b + b = c + return a + def dump_skip (skip, clocks): - return skip + Duration (clocks).dump () + ' ' + return skip + Duration (clocks).dump () + ' ' def dump (d): - return d.dump () + return d.dump () def dump_chord (ch): - s = '' - notes = [] - for i in ch: - if i.__class__ == Note: - notes.append (i) - else: - s = s + i.dump () - if len (notes) == 1: - s = s + dump (notes[0]) - elif len (notes) > 1: - global reference_note - s = s + '<' - s = s + notes[0].dump (dump_dur = 0) - r = reference_note - for i in notes[1:]: - s = s + i.dump (dump_dur = 0 ) - s = s + '>' - - s = s + notes[0].duration.dump() + ' ' - reference_note = r - return s + s = '' + notes = [] + for i in ch: + if i.__class__ == Note: + notes.append (i) + else: + s = s + i.dump () + if len (notes) == 1: + s = s + dump (notes[0]) + elif len (notes) > 1: + global reference_note + s = s + '<' + s = s + notes[0].dump (dump_dur = 0) + r = reference_note + for i in notes[1:]: + s = s + i.dump (dump_dur = 0 ) + s = s + '>' + + s = s + notes[0].duration.dump() + ' ' + reference_note = r + return s def dump_bar_line (last_bar_t, t, bar_count): - s = '' - bar_t = time.bar_clocks () - if t - last_bar_t >= bar_t: - bar_count = bar_count + (t - last_bar_t) / bar_t - - if t - last_bar_t == bar_t: - s = '|\n %% %d\n ' % bar_count - last_bar_t = t - else: - # urg, this will barf at meter changes - last_bar_t = last_bar_t + (t - last_bar_t) / bar_t * bar_t - - return (s, last_bar_t, bar_count) - - + s = '' + bar_t = time.bar_clocks () + if t - last_bar_t >= bar_t: + bar_count = bar_count + (t - last_bar_t) / bar_t + + if t - last_bar_t == bar_t: + s = '|\n %% %d\n ' % bar_count + last_bar_t = t + else: + # urg, this will barf at meter changes + last_bar_t = last_bar_t + (t - last_bar_t) / bar_t * bar_t + + return (s, last_bar_t, bar_count) + + def dump_channel (thread, skip): - global reference_note, time - - global_options.key = Key (0, 0, 0) - time = Time (4, 4) - # urg LilyPond doesn't start at c4, but - # remembers from previous tracks! - # reference_note = Note (clocks_per_4, 4*12, 0) - reference_note = Note (0, 4*12, 0) - last_e = None - chs = [] - ch = [] - - for e in thread: - if last_e and last_e[0] == e[0]: - ch.append (e[1]) - else: - if ch: - chs.append ((last_e[0], ch)) - - ch = [e[1]] - - last_e = e - - if ch: - chs.append ((last_e[0], ch)) - t = 0 - last_t = 0 - last_bar_t = 0 - bar_count = 1 - - lines = [''] - for ch in chs: - t = ch[0] - - i = string.rfind (lines[-1], '\n') + 1 - if len (lines[-1][i:]) > LINE_BELL: - lines.append ('') - - if t - last_t > 0: - lines[-1] = lines[-1] + dump_skip (skip, t-last_t) - elif t - last_t < 0: - errorport.write ('BUG: time skew') - - (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t, - t, bar_count) - lines[-1] = lines[-1] + s - - lines[-1] = lines[-1] + dump_chord (ch[1]) - - clocks = 0 - for i in ch[1]: - if i.clocks > clocks: - clocks = i.clocks - - last_t = t + clocks - - (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t, - last_t, bar_count) - lines[-1] = lines[-1] + s - - return string.join (lines, '\n ') + '\n' + global reference_note, time + + global_options.key = Key (0, 0, 0) + time = Time (4, 4) + # urg LilyPond doesn't start at c4, but + # remembers from previous tracks! + # reference_note = Note (clocks_per_4, 4*12, 0) + reference_note = Note (0, 4*12, 0) + last_e = None + chs = [] + ch = [] + + for e in thread: + if last_e and last_e[0] == e[0]: + ch.append (e[1]) + else: + if ch: + chs.append ((last_e[0], ch)) + + ch = [e[1]] + + last_e = e + + if ch: + chs.append ((last_e[0], ch)) + t = 0 + last_t = 0 + last_bar_t = 0 + bar_count = 1 + + lines = [''] + for ch in chs: + t = ch[0] + + i = string.rfind (lines[-1], '\n') + 1 + if len (lines[-1][i:]) > LINE_BELL: + lines.append ('') + + if t - last_t > 0: + lines[-1] = lines[-1] + dump_skip (skip, t-last_t) + elif t - last_t < 0: + errorport.write ('BUG: time skew') + + (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t, + t, bar_count) + lines[-1] = lines[-1] + s + + lines[-1] = lines[-1] + dump_chord (ch[1]) + + clocks = 0 + for i in ch[1]: + if i.clocks > clocks: + clocks = i.clocks + + last_t = t + clocks + + (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t, + last_t, bar_count) + lines[-1] = lines[-1] + s + + return string.join (lines, '\n ') + '\n' def track_name (i): - return 'track%c' % (i + ord ('A')) + return 'track%c' % (i + ord ('A')) def channel_name (i): - return 'channel%c' % (i + ord ('A')) + return 'channel%c' % (i + ord ('A')) def dump_track (channels, n): - s = '\n' - track = track_name (n) - clef = guess_clef (channels) - - for i in range (len (channels)): - channel = channel_name (i) - item = thread_first_item (channels[i]) - - if item and item.__class__ == Note: - skip = 's' - s = s + '%s = ' % (track + channel) - if not global_options.absolute_pitches: - s = s + '\\relative c ' - elif item and item.__class__ == Text: - skip = '" "' - s = s + '%s = \\lyricmode ' % (track + channel) - else: - skip = '\\skip ' - s = s + '%s = ' % (track + channel) - s = s + '{\n' - s = s + ' ' + dump_channel (channels[i][0], skip) - s = s + '}\n\n' - - s = s + '%s = <<\n' % track - - if clef.type != 2: - s = s + clef.dump () + '\n' - - for i in range (len (channels)): - channel = channel_name (i) - item = thread_first_item (channels[i]) - if item and item.__class__ == Text: - s = s + ' \\context Lyrics = %s \\%s\n' % (channel, - track + channel) - else: - s = s + ' \\context Voice = %s \\%s\n' % (channel, - track + channel) - s = s + '>>\n\n' - return s + s = '\n' + track = track_name (n) + clef = guess_clef (channels) + + for i in range (len (channels)): + channel = channel_name (i) + item = thread_first_item (channels[i]) + + if item and item.__class__ == Note: + skip = 's' + s = s + '%s = ' % (track + channel) + if not global_options.absolute_pitches: + s = s + '\\relative c ' + elif item and item.__class__ == Text: + skip = '" "' + s = s + '%s = \\lyricmode ' % (track + channel) + else: + skip = '\\skip ' + s = s + '%s = ' % (track + channel) + s = s + '{\n' + s = s + ' ' + dump_channel (channels[i][0], skip) + s = s + '}\n\n' + + s = s + '%s = <<\n' % track + + if clef.type != 2: + s = s + clef.dump () + '\n' + + for i in range (len (channels)): + channel = channel_name (i) + item = thread_first_item (channels[i]) + if item and item.__class__ == Text: + s = s + ' \\context Lyrics = %s \\%s\n' % (channel, + track + channel) + else: + s = s + ' \\context Voice = %s \\%s\n' % (channel, + track + channel) + s = s + '>>\n\n' + return s def thread_first_item (thread): - for chord in thread: - for event in chord: - if (event[1].__class__ == Note - or (event[1].__class__ == Text - and event[1].type == midi.LYRIC)): - - return event[1] - return None + for chord in thread: + for event in chord: + if (event[1].__class__ == Note + or (event[1].__class__ == Text + and event[1].type == midi.LYRIC)): + + return event[1] + return None def track_first_item (track): - for thread in track: - first = thread_first_item (thread) - if first: - return first - return None + for thread in track: + first = thread_first_item (thread) + if first: + return first + return None def guess_clef (track): - i = 0 - p = 0 - for thread in track: - for chord in thread: - for event in chord: - if event[1].__class__ == Note: - i = i + 1 - p = p + event[1].pitch - if i and p / i <= 3*12: - return Clef (0) - elif i and p / i <= 5*12: - return Clef (1) - elif i and p / i >= 7*12: - return Clef (3) - else: - return Clef (2) - + i = 0 + p = 0 + for thread in track: + for chord in thread: + for event in chord: + if event[1].__class__ == Note: + i = i + 1 + p = p + event[1].pitch + if i and p / i <= 3*12: + return Clef (0) + elif i and p / i <= 5*12: + return Clef (1) + elif i and p / i >= 7*12: + return Clef (3) + else: + return Clef (2) + def convert_midi (in_file, out_file): - global clocks_per_1, clocks_per_4, key - global start_quant_clocks - global duration_quant_clocks - global allowed_tuplet_clocks - - str = open (in_file).read () - midi_dump = midi.parse (str) - - clocks_per_1 = midi_dump[0][1] - clocks_per_4 = clocks_per_1 / 4 - - if global_options.start_quant: - start_quant_clocks = clocks_per_1 / global_options.start_quant - - if global_options.duration_quant: - duration_quant_clocks = clocks_per_1 / global_options.duration_quant - - allowed_tuplet_clocks = [] - for (dur, num, den) in global_options.allowed_tuplets: - allowed_tuplet_clocks.append (clocks_per_1 / den) - - tracks = [] - for t in midi_dump[1]: - global_options.key = Key (0, 0, 0) - tracks.append (split_track (t)) - - tag = '%% Lily was here -- automatically converted by %s from %s' % ( program_name, in_file) - + global clocks_per_1, clocks_per_4, key + global start_quant_clocks + global duration_quant_clocks + global allowed_tuplet_clocks + + str = open (in_file).read () + midi_dump = midi.parse (str) + + clocks_per_1 = midi_dump[0][1] + clocks_per_4 = clocks_per_1 / 4 + + if global_options.start_quant: + start_quant_clocks = clocks_per_1 / global_options.start_quant + + if global_options.duration_quant: + duration_quant_clocks = clocks_per_1 / global_options.duration_quant + + allowed_tuplet_clocks = [] + for (dur, num, den) in global_options.allowed_tuplets: + allowed_tuplet_clocks.append (clocks_per_1 / den) + + tracks = [] + for t in midi_dump[1]: + global_options.key = Key (0, 0, 0) + tracks.append (split_track (t)) + + tag = '%% Lily was here -- automatically converted by %s from %s' % ( program_name, in_file) + + + s = '' + s = tag + '\n\\version "2.7.18"\n\n' + for i in range (len (tracks)): + s = s + dump_track (tracks[i], i) + + s = s + '\n\\score {\n <<\n' + + i = 0 + for t in tracks: + track = track_name (i) + item = track_first_item (t) - s = '' - s = tag + '\n\\version "2.7.18"\n\n' - for i in range (len (tracks)): - s = s + dump_track (tracks[i], i) - - s = s + '\n\\score {\n <<\n' - - i = 0 - for t in tracks: - track = track_name (i) - item = track_first_item (t) - - if item and item.__class__ == Note: - s = s + ' \\context Staff=%s \\%s\n' % (track, track) - elif item and item.__class__ == Text: - s = s + ' \\context Lyrics=%s \\%s\n' % (track, track) + if item and item.__class__ == Note: + s = s + ' \\context Staff=%s \\%s\n' % (track, track) + elif item and item.__class__ == Text: + s = s + ' \\context Lyrics=%s \\%s\n' % (track, track) - i += 1 - s = s + ' >>\n}\n' + i += 1 + s = s + ' >>\n}\n' - progress (_ ("%s output to `%s'...") % ('LY', out_file)) + progress (_ ("%s output to `%s'...") % ('LY', out_file)) - if out_file == '-': - handle = sys.stdout - else: - handle = open (out_file, 'w') + if out_file == '-': + handle = sys.stdout + else: + handle = open (out_file, 'w') - handle.write (s) - handle.close () + handle.write (s) + handle.close () def get_option_parser (): - p = ly.get_option_parser (usage='midi2ly [OPTIONS] FILE', - version="midi2ly (LilyPond) @TOPLEVEL_VERSION@", - description=_('''Convert MIDI to LilyPond source.''')) - - p.add_option ('-a', '--absolute-pitches', - action='store_true', - help=_ ("print absolute pitches")) - p.add_option ('-d', '--duration-quant', - metavar= _("DUR"), - help=_("quantise note durations on DUR")) - p.add_option ('-e', '--explicit-durations', - action='store_true', - help=_ ("print explicit durations")) - p.add_option('-k', '--key', help=_ ("set key: ALT=+sharps|-flats; MINOR=1"), - metavar=_ ("ALT[:MINOR]"), - default='0'), - p.add_option ('-o', '--output', help=_("write output to FILE"), - metavar=_("FILE"), - action='store') - p.add_option ('-s', '--start-quant',help= _ ("quantise note starts on DUR"), - metavar=_ ("DUR")) - p.add_option ('-t', '--allow-tuplet', - metavar=_ ("DUR*NUM/DEN"), - action = "append", - dest="allowed_tuplets", - help=_ ("allow tuplet durations DUR*NUM/DEN"), - default=[]) - p.add_option ('-V', '--verbose', help=_("be verbose"), - action='store_true' - ), - p.add_option ('-w', '--warranty', help=_("show warranty"), - action='store_true', - ), - p.add_option ('-x', '--text-lyrics', help=_("treat every text as a lyric"), - action='store_true') - - p.add_option_group (_ ("example"), - description = r''' - midi2ly --key=-2:1 --duration-quant=32 \ - --allow-tuplet=4*2/3 --allow-tuplet=2*4/3 foo.midi + p = ly.get_option_parser (usage='midi2ly [OPTIONS] FILE', + version="midi2ly (LilyPond) @TOPLEVEL_VERSION@", + description=_('''Convert MIDI to LilyPond source.''')) + + p.add_option ('-a', '--absolute-pitches', + action='store_true', + help=_ ("print absolute pitches")) + p.add_option ('-d', '--duration-quant', + metavar= _("DUR"), + help=_("quantise note durations on DUR")) + p.add_option ('-e', '--explicit-durations', + action='store_true', + help=_ ("print explicit durations")) + p.add_option('-k', '--key', help=_ ("set key: ALT=+sharps|-flats; MINOR=1"), + metavar=_ ("ALT[:MINOR]"), + default='0'), + p.add_option ('-o', '--output', help=_("write output to FILE"), + metavar=_("FILE"), + action='store') + p.add_option ('-s', '--start-quant',help= _ ("quantise note starts on DUR"), + metavar=_ ("DUR")) + p.add_option ('-t', '--allow-tuplet', + metavar=_ ("DUR*NUM/DEN"), + action = "append", + dest="allowed_tuplets", + help=_ ("allow tuplet durations DUR*NUM/DEN"), + default=[]) + p.add_option ('-V', '--verbose', help=_("be verbose"), + action='store_true' + ), + p.add_option ('-w', '--warranty', help=_("show warranty"), + action='store_true', + ), + p.add_option ('-x', '--text-lyrics', help=_("treat every text as a lyric"), + action='store_true') + + p.add_option_group (_ ("example"), + description = r''' + midi2ly --key=-2:1 --duration-quant=32 \ + --allow-tuplet=4*2/3 --allow-tuplet=2*4/3 foo.midi ''') - - p.add_option_group ('bugs', - description='''Report bugs via http://post.gmane.org/post.php''' - '''?group=gmane.comp.gnu.lilypond.bugs\n''') - - return p + + p.add_option_group ('bugs', + description='''Report bugs via http://post.gmane.org/post.php''' + '''?group=gmane.comp.gnu.lilypond.bugs\n''') + + return p def do_options (): - opt_parser = get_option_parser() - (options, args) = opt_parser.parse_args () - - if not args or args[0] == '-': - opt_parser.print_help () - sys.stderr.write ('\n%s: %s %s\n' % (program_name, _ ("error: "), - _ ("no files specified on command line."))) - sys.exit (2) - - if options.duration_quant: - options.duration_quant = int (options.duration_quant) - - if options.warranty: - warranty () - sys.exit (0) - if 1: - (alterations, minor) = map (int, string.split (options.key + ':0', ':'))[0:2] - sharps = 0 - flats = 0 - if alterations >= 0: - sharps = alterations - else: - flats = - alterations - - options.key = Key (sharps, flats, minor) - - - if options.start_quant: - options.start_quant = int (options.start_quant) - - options.allowed_tuplets = [map (int, a.replace ('/','*').split ('*')) - for a in options.allowed_tuplets] - - global global_options - global_options = options - - return args + opt_parser = get_option_parser() + (options, args) = opt_parser.parse_args () + + if not args or args[0] == '-': + opt_parser.print_help () + sys.stderr.write ('\n%s: %s %s\n' % (program_name, _ ("error: "), + _ ("no files specified on command line."))) + sys.exit (2) + + if options.duration_quant: + options.duration_quant = int (options.duration_quant) + + if options.warranty: + warranty () + sys.exit (0) + if 1: + (alterations, minor) = map (int, string.split (options.key + ':0', ':'))[0:2] + sharps = 0 + flats = 0 + if alterations >= 0: + sharps = alterations + else: + flats = - alterations + + options.key = Key (sharps, flats, minor) + + + if options.start_quant: + options.start_quant = int (options.start_quant) + + options.allowed_tuplets = [map (int, a.replace ('/','*').split ('*')) + for a in options.allowed_tuplets] + + global global_options + global_options = options + + return args def main(): - files = do_options() - - for f in files: - g = f - g = strip_extension (g, '.midi') - g = strip_extension (g, '.mid') - g = strip_extension (g, '.MID') - (outdir, outbase) = ('','') - - if not output_name: - outdir = '.' - outbase = os.path.basename (g) - o = os.path.join (outdir, outbase + '-midi.ly') - elif output_name[-1] == os.sep: - outdir = output_name - outbase = os.path.basename (g) - os.path.join (outdir, outbase + '-gen.ly') - else: - o = output_name - (outdir, outbase) = os.path.split (o) - - if outdir != '.' and outdir != '': - try: - os.mkdir (outdir, 0777) - except OSError: - pass - - convert_midi (f, o) + files = do_options() + + for f in files: + g = f + g = strip_extension (g, '.midi') + g = strip_extension (g, '.mid') + g = strip_extension (g, '.MID') + (outdir, outbase) = ('','') + + if not output_name: + outdir = '.' + outbase = os.path.basename (g) + o = os.path.join (outdir, outbase + '-midi.ly') + elif output_name[-1] == os.sep: + outdir = output_name + outbase = os.path.basename (g) + os.path.join (outdir, outbase + '-gen.ly') + else: + o = output_name + (outdir, outbase) = os.path.split (o) + + if outdir != '.' and outdir != '': + try: + os.mkdir (outdir, 0777) + except OSError: + pass + + convert_midi (f, o) if __name__ == '__main__': - main() + main() diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index 15bbb2ba65..71b41d9dc3 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -10,16 +10,16 @@ from gettext import gettext as _ datadir = '@local_lilypond_datadir@' if not os.path.isdir (datadir): - datadir = '@lilypond_datadir@' + datadir = '@lilypond_datadir@' if os.environ.has_key ('LILYPONDPREFIX'): - datadir = os.environ['LILYPONDPREFIX'] - while datadir[-1] == os.sep: - datadir = datadir[:-1] + datadir = os.environ['LILYPONDPREFIX'] + while datadir[-1] == os.sep: + datadir = datadir[:-1] if os.path.exists (os.path.join (datadir, 'share/lilypond/@TOPLEVEL_VERSION@/')): - datadir = os.path.join (datadir, 'share/lilypond/@TOPLEVEL_VERSION@/') + datadir = os.path.join (datadir, 'share/lilypond/@TOPLEVEL_VERSION@/') elif os.path.exists (os.path.join (datadir, 'share/lilypond/current/')): - datadir = os.path.join (datadir, 'share/lilypond/current/') + datadir = os.path.join (datadir, 'share/lilypond/current/') sys.path.insert (0, os.path.join (datadir, 'python')) @@ -27,8 +27,8 @@ sys.path.insert (0, os.path.join (datadir, 'python')) bindir = os.path.split (sys.argv[0])[0] for prefix_component in ['share', 'lib']: - datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % prefix_component) - sys.path.insert (0, datadir) + datadir = os.path.abspath (bindir + '/../%s/lilypond/current/python/' % prefix_component) + sys.path.insert (0, datadir) @@ -40,349 +40,349 @@ from rational import Rational def progress (str): - sys.stderr.write (str + '\n') - sys.stderr.flush () - + sys.stderr.write (str + '\n') + sys.stderr.flush () + def musicxml_duration_to_lily (mxl_note): - d = musicexp.Duration () - if mxl_note.get_maybe_exist_typed_child (musicxml.Type): - d.duration_log = mxl_note.get_duration_log () - else: - d.duration_log = 0 + d = musicexp.Duration () + if mxl_note.get_maybe_exist_typed_child (musicxml.Type): + d.duration_log = mxl_note.get_duration_log () + else: + d.duration_log = 0 - d.dots = len (mxl_note.get_typed_children (musicxml.Dot)) - d.factor = mxl_note._duration / d.get_length () + d.dots = len (mxl_note.get_typed_children (musicxml.Dot)) + d.factor = mxl_note._duration / d.get_length () - return d + return d def group_tuplets (music_list, events): - """Collect Musics from - MUSIC_LIST demarcated by EVENTS_LIST in TimeScaledMusic objects. - """ + """Collect Musics from + MUSIC_LIST demarcated by EVENTS_LIST in TimeScaledMusic objects. + """ - - indices = [] + + indices = [] - j = 0 - for (ev_chord, tuplet_elt, fraction) in events: - while (j < len (music_list)): - if music_list[j]== ev_chord: - break - j += 1 - if tuplet_elt.type == 'start': - indices.append ((j, None, fraction)) - elif tuplet_elt.type == 'stop': - indices[-1] = (indices[-1][0], j, indices[-1][2]) + j = 0 + for (ev_chord, tuplet_elt, fraction) in events: + while (j < len (music_list)): + if music_list[j]== ev_chord: + break + j += 1 + if tuplet_elt.type == 'start': + indices.append ((j, None, fraction)) + elif tuplet_elt.type == 'stop': + indices[-1] = (indices[-1][0], j, indices[-1][2]) - new_list = [] - last = 0 - for (i1, i2, frac) in indices: - if i1 >= i2: - continue + new_list = [] + last = 0 + for (i1, i2, frac) in indices: + if i1 >= i2: + continue - new_list.extend (music_list[last:i1]) - seq = musicexp.SequentialMusic () - last = i2 + 1 - seq.elements = music_list[i1:last] + new_list.extend (music_list[last:i1]) + seq = musicexp.SequentialMusic () + last = i2 + 1 + seq.elements = music_list[i1:last] - tsm = musicexp.TimeScaledMusic () - tsm.element = seq + tsm = musicexp.TimeScaledMusic () + tsm.element = seq - tsm.numerator = frac[0] - tsm.denominator = frac[1] + tsm.numerator = frac[0] + tsm.denominator = frac[1] - new_list.append (tsm) + new_list.append (tsm) - new_list.extend (music_list[last:]) - return new_list + new_list.extend (music_list[last:]) + return new_list def musicxml_clef_to_lily (mxl): - sign = mxl.get_maybe_exist_named_child ('sign') - change = musicexp.ClefChange () - if sign: - change.type = sign.get_text () - return change + sign = mxl.get_maybe_exist_named_child ('sign') + change = musicexp.ClefChange () + if sign: + change.type = sign.get_text () + return change - + def musicxml_time_to_lily (mxl): - beats = mxl.get_maybe_exist_named_child ('beats') - type = mxl.get_maybe_exist_named_child ('beat-type') - change = musicexp.TimeSignatureChange() - change.fraction = (string.atoi(beats.get_text ()), - string.atoi(type.get_text ())) - - return change + beats = mxl.get_maybe_exist_named_child ('beats') + type = mxl.get_maybe_exist_named_child ('beat-type') + change = musicexp.TimeSignatureChange() + change.fraction = (string.atoi(beats.get_text ()), + string.atoi(type.get_text ())) + + return change def musicxml_key_to_lily (mxl): - start_pitch = musicexp.Pitch () - try: - mode = mxl.get_maybe_exist_named_child ('mode') - if mode: - mode = mode.get_text () - else: - mode = 'major' - - (n,a) = { 'major' : (0,0), - 'minor' : (6,0), - }[mode] - start_pitch.step = n - start_pitch.alteration = a - except KeyError: - print 'unknown mode', mode - - fifths = string.atoi (mxl.get_maybe_exist_named_child ('fifths').get_text ()) - - fifth = musicexp.Pitch() - fifth.step = 4 - if fifths < 0: - fifths *= -1 - fifth.step *= -1 - fifth.normalize () - - start_pitch = musicexp.Pitch() - for x in range (fifths): - start_pitch = start_pitch.transposed (fifth) - - start_pitch.octave = 0 - - change = musicexp.KeySignatureChange() - change.mode = mode - change.tonic = start_pitch - return change - + start_pitch = musicexp.Pitch () + try: + mode = mxl.get_maybe_exist_named_child ('mode') + if mode: + mode = mode.get_text () + else: + mode = 'major' + + (n,a) = { 'major' : (0,0), + 'minor' : (6,0), + }[mode] + start_pitch.step = n + start_pitch.alteration = a + except KeyError: + print 'unknown mode', mode + + fifths = string.atoi (mxl.get_maybe_exist_named_child ('fifths').get_text ()) + + fifth = musicexp.Pitch() + fifth.step = 4 + if fifths < 0: + fifths *= -1 + fifth.step *= -1 + fifth.normalize () + + start_pitch = musicexp.Pitch() + for x in range (fifths): + start_pitch = start_pitch.transposed (fifth) + + start_pitch.octave = 0 + + change = musicexp.KeySignatureChange() + change.mode = mode + change.tonic = start_pitch + return change + def musicxml_attributes_to_lily (attrs): - elts = [] - attr_dispatch = { - 'clef': musicxml_clef_to_lily, - 'time': musicxml_time_to_lily, - 'key': musicxml_key_to_lily - } - for (k, func) in attr_dispatch.items (): - childs = attrs.get_named_children (k) - - ## ugh: you get clefs spread over staves for piano - if childs: - elts.append (func (childs[0])) - - return elts + elts = [] + attr_dispatch = { + 'clef': musicxml_clef_to_lily, + 'time': musicxml_time_to_lily, + 'key': musicxml_key_to_lily + } + for (k, func) in attr_dispatch.items (): + childs = attrs.get_named_children (k) + + ## ugh: you get clefs spread over staves for piano + if childs: + elts.append (func (childs[0])) + + return elts def create_skip_music (duration): - skip = musicexp.SkipEvent() - skip.duration.duration_log = 0 - skip.duration.factor = duration + skip = musicexp.SkipEvent() + skip.duration.duration_log = 0 + skip.duration.factor = duration - evc = musicexp.EventChord () - evc.append (skip) - return evc + evc = musicexp.EventChord () + evc.append (skip) + return evc spanner_event_dict = { - 'slur' : musicexp.SlurEvent, - 'beam' : musicexp.BeamEvent, -} + 'slur' : musicexp.SlurEvent, + 'beam' : musicexp.BeamEvent, +} spanner_type_dict = { - 'start': -1, - 'begin': -1, - 'stop': 1, - 'end' : 1 + 'start': -1, + 'begin': -1, + 'stop': 1, + 'end' : 1 } def musicxml_spanner_to_lily_event (mxl_event): - ev = None - - name = mxl_event.get_name() - try: - func = spanner_event_dict[name] - ev = func() - except KeyError: - print 'unknown span event ', mxl_event - - try: - key = mxl_event.get_type () - ev.span_direction = spanner_type_dict[key] - except KeyError: - print 'unknown span type', key, 'for', name - - return ev + ev = None + + name = mxl_event.get_name() + try: + func = spanner_event_dict[name] + ev = func() + except KeyError: + print 'unknown span event ', mxl_event + + try: + key = mxl_event.get_type () + ev.span_direction = spanner_type_dict[key] + except KeyError: + print 'unknown span type', key, 'for', name + + return ev def musicxml_note_to_lily_main_event (n): - pitch = None - duration = None - - mxl_pitch = n.get_maybe_exist_typed_child (musicxml.Pitch) - event = None - if mxl_pitch: - pitch = musicxml_pitch_to_lily (mxl_pitch) - event = musicexp.NoteEvent() - event.pitch = pitch - - acc = n.get_maybe_exist_named_child ('accidental') - if acc: - # let's not force accs everywhere. - event.cautionary = acc.editorial - - elif n.get_maybe_exist_typed_child (musicxml.Rest): - event = musicexp.RestEvent() - - event.duration = musicxml_duration_to_lily (n) - return event + pitch = None + duration = None + + mxl_pitch = n.get_maybe_exist_typed_child (musicxml.Pitch) + event = None + if mxl_pitch: + pitch = musicxml_pitch_to_lily (mxl_pitch) + event = musicexp.NoteEvent() + event.pitch = pitch + + acc = n.get_maybe_exist_named_child ('accidental') + if acc: + # let's not force accs everywhere. + event.cautionary = acc.editorial + + elif n.get_maybe_exist_typed_child (musicxml.Rest): + event = musicexp.RestEvent() + + event.duration = musicxml_duration_to_lily (n) + return event def musicxml_voice_to_lily_voice (voice): - ly_voice = [] - ly_now = Rational (0) - pending_skip = Rational (0) - - tuplet_events = [] - - for n in voice._elements: - if n.get_name () == 'forward': - continue - - if isinstance (n, musicxml.Attributes): - ly_now += pending_skip - pending_skip = Rational (0) - - ly_voice.extend (musicxml_attributes_to_lily (n)) - continue - - if not n.__class__.__name__ == 'Note': - print 'not a Note or Attributes?', n - continue - - if n.is_first () and ly_voice: - ly_voice[-1].comment += '\n' - - - main_event = musicxml_note_to_lily_main_event (n) - - ev_chord = None - if None == n.get_maybe_exist_typed_child (musicxml.Chord): - ly_now += pending_skip - pending_skip = main_event.get_length () - - if ly_now <> n._when: - diff = n._when - ly_now - - if diff < Rational (0): - print 'huh: negative skip', n._when, ly_now, n._duration - diff = Rational (1,314159265) - - ly_voice.append (create_skip_music (diff)) - ly_now = n._when - - ly_voice.append (musicexp.EventChord()) - else: - pass - - ev_chord = ly_voice[-1] - ev_chord.append (main_event) - - notations = n.get_maybe_exist_typed_child (musicxml.Notations) - tuplet_event = None - span_events = [] - if notations: - if notations.get_tuplet(): - tuplet_event = notations.get_tuplet() - mod = n.get_maybe_exist_typed_child (musicxml.Time_modification) - frac = (1,1) - if mod: - frac = mod.get_fraction () - - tuplet_events.append ((ev_chord, tuplet_event, frac)) - - slurs = [s for s in notations.get_named_children ('slur') - if s.get_type () in ('start','stop')] - if slurs: - if len (slurs) > 1: - print 'more than 1 slur?' - - lily_ev = musicxml_spanner_to_lily_event (slurs[0]) - ev_chord.append (lily_ev) - - mxl_tie = notations.get_tie () - if mxl_tie and mxl_tie.type == 'start': - ev_chord.append (musicexp.TieEvent ()) - - mxl_beams = [b for b in n.get_named_children ('beam') - if b.get_type () in ('begin', 'end')] - if mxl_beams: - beam_ev = musicxml_spanner_to_lily_event (mxl_beams[0]) - if beam_ev: - ev_chord.append (beam_ev) - - if tuplet_event: - mod = n.get_maybe_exist_typed_child (musicxml.Time_modification) - frac = (1,1) - if mod: - frac = mod.get_fraction () - - tuplet_events.append ((ev_chord, tuplet_event, frac)) - - ly_voice = group_tuplets (ly_voice, tuplet_events) - - seq_music = musicexp.SequentialMusic() - - seq_music.elements = ly_voice - return seq_music + ly_voice = [] + ly_now = Rational (0) + pending_skip = Rational (0) + + tuplet_events = [] + + for n in voice._elements: + if n.get_name () == 'forward': + continue + + if isinstance (n, musicxml.Attributes): + ly_now += pending_skip + pending_skip = Rational (0) + + ly_voice.extend (musicxml_attributes_to_lily (n)) + continue + + if not n.__class__.__name__ == 'Note': + print 'not a Note or Attributes?', n + continue + + if n.is_first () and ly_voice: + ly_voice[-1].comment += '\n' + + + main_event = musicxml_note_to_lily_main_event (n) + + ev_chord = None + if None == n.get_maybe_exist_typed_child (musicxml.Chord): + ly_now += pending_skip + pending_skip = main_event.get_length () + + if ly_now <> n._when: + diff = n._when - ly_now + + if diff < Rational (0): + print 'huh: negative skip', n._when, ly_now, n._duration + diff = Rational (1,314159265) + + ly_voice.append (create_skip_music (diff)) + ly_now = n._when + + ly_voice.append (musicexp.EventChord()) + else: + pass + + ev_chord = ly_voice[-1] + ev_chord.append (main_event) + + notations = n.get_maybe_exist_typed_child (musicxml.Notations) + tuplet_event = None + span_events = [] + if notations: + if notations.get_tuplet(): + tuplet_event = notations.get_tuplet() + mod = n.get_maybe_exist_typed_child (musicxml.Time_modification) + frac = (1,1) + if mod: + frac = mod.get_fraction () + + tuplet_events.append ((ev_chord, tuplet_event, frac)) + + slurs = [s for s in notations.get_named_children ('slur') + if s.get_type () in ('start','stop')] + if slurs: + if len (slurs) > 1: + print 'more than 1 slur?' + + lily_ev = musicxml_spanner_to_lily_event (slurs[0]) + ev_chord.append (lily_ev) + + mxl_tie = notations.get_tie () + if mxl_tie and mxl_tie.type == 'start': + ev_chord.append (musicexp.TieEvent ()) + + mxl_beams = [b for b in n.get_named_children ('beam') + if b.get_type () in ('begin', 'end')] + if mxl_beams: + beam_ev = musicxml_spanner_to_lily_event (mxl_beams[0]) + if beam_ev: + ev_chord.append (beam_ev) + + if tuplet_event: + mod = n.get_maybe_exist_typed_child (musicxml.Time_modification) + frac = (1,1) + if mod: + frac = mod.get_fraction () + + tuplet_events.append ((ev_chord, tuplet_event, frac)) + + ly_voice = group_tuplets (ly_voice, tuplet_events) + + seq_music = musicexp.SequentialMusic() + + seq_music.elements = ly_voice + return seq_music def musicxml_id_to_lily (id): - digits = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', - 'nine', 'ten'] - - for dig in digits: - d = digits.index (dig) + 1 - dig = dig[0].upper() + dig[1:] - id = re.sub ('%d' % d, dig, id) + digits = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', + 'nine', 'ten'] + + for dig in digits: + d = digits.index (dig) + 1 + dig = dig[0].upper() + dig[1:] + id = re.sub ('%d' % d, dig, id) - id = re.sub ('[^a-zA-Z]', 'X', id) - return id + id = re.sub ('[^a-zA-Z]', 'X', id) + return id def musicxml_pitch_to_lily (mxl_pitch): - p = musicexp.Pitch() - p.alteration = mxl_pitch.get_alteration () - p.step = (ord (mxl_pitch.get_step ()) - ord ('A') + 7 - 2) % 7 - p.octave = mxl_pitch.get_octave () - 4 - return p + p = musicexp.Pitch() + p.alteration = mxl_pitch.get_alteration () + p.step = (ord (mxl_pitch.get_step ()) - ord ('A') + 7 - 2) % 7 + p.octave = mxl_pitch.get_octave () - 4 + return p def voices_in_part (part): - """Return a Name -> Voice dictionary for PART""" - part.interpret () - part.extract_voices () - voice_dict = part.get_voices () + """Return a Name -> Voice dictionary for PART""" + part.interpret () + part.extract_voices () + voice_dict = part.get_voices () - return voice_dict + return voice_dict def voices_in_part_in_parts (parts): - """return a Part -> Name -> Voice dictionary""" - return dict([(p, voices_in_part (p)) for p in parts]) + """return a Part -> Name -> Voice dictionary""" + return dict([(p, voices_in_part (p)) for p in parts]) def get_all_voices (parts): - all_voices = voices_in_part_in_parts (parts) + all_voices = voices_in_part_in_parts (parts) - all_ly_voices = {} - for p, name_voice in all_voices.items (): + all_ly_voices = {} + for p, name_voice in all_voices.items (): - part_ly_voices = {} - for n, v in name_voice.items (): - progress ("Converting to LilyPond expressions...") - part_ly_voices[n] = (musicxml_voice_to_lily_voice (v), v) + part_ly_voices = {} + for n, v in name_voice.items (): + progress ("Converting to LilyPond expressions...") + part_ly_voices[n] = (musicxml_voice_to_lily_voice (v), v) - all_ly_voices[p] = part_ly_voices - - return all_ly_voices + all_ly_voices[p] = part_ly_voices + + return all_ly_voices def option_parser (): - p = ly.get_option_parser(usage='musicxml2ly FILE.xml', - version = """%prog (LilyPond) @TOPLEVEL_VERSION@ + p = ly.get_option_parser(usage='musicxml2ly FILE.xml', + version = """%prog (LilyPond) @TOPLEVEL_VERSION@ This program is free software. It is covered by the GNU General Public License and you are welcome to change it and/or distribute copies of it @@ -390,145 +390,145 @@ under certain conditions. Invoke as `lilypond --warranty' for more information. Copyright (c) 2005--2006 by - Han-Wen Nienhuys and - Jan Nieuwenhuizen + Han-Wen Nienhuys and + Jan Nieuwenhuizen """, - description = - """Convert MusicXML file to LilyPond input. + description = + """Convert MusicXML file to LilyPond input. """ - ) - p.add_option ('-v', '--verbose', - action = "store_true", - dest = 'verbose', - help = 'be verbose') - p.add_option ('-o', '--output', - metavar = 'FILE', - action = "store", - default = None, - type = 'string', - dest = 'output', - help = 'set output file') - - p.add_option_group ('', description = '''Report bugs via http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs + ) + p.add_option ('-v', '--verbose', + action = "store_true", + dest = 'verbose', + help = 'be verbose') + p.add_option ('-o', '--output', + metavar = 'FILE', + action = "store", + default = None, + type = 'string', + dest = 'output', + help = 'set output file') + + p.add_option_group ('', description = '''Report bugs via http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs ''') - return p + return p def music_xml_voice_name_to_lily_name (part, name): - str = "Part%sVoice%s" % (part.id, name) - return musicxml_id_to_lily (str) + str = "Part%sVoice%s" % (part.id, name) + return musicxml_id_to_lily (str) def print_voice_definitions (printer, voices): - for (part, nv_dict) in voices.items(): - for (name, (voice, mxlvoice)) in nv_dict.items (): - k = music_xml_voice_name_to_lily_name (part, name) - printer.dump ('%s = ' % k) - voice.print_ly (printer) - printer.newline() + for (part, nv_dict) in voices.items(): + for (name, (voice, mxlvoice)) in nv_dict.items (): + k = music_xml_voice_name_to_lily_name (part, name) + printer.dump ('%s = ' % k) + voice.print_ly (printer) + printer.newline() def uniq_list (l): - return dict ([(elt,1) for elt in l]).keys () - + return dict ([(elt,1) for elt in l]).keys () + def print_score_setup (printer, part_list, voices): - part_dict = dict ([(p.id, p) for p in voices.keys ()]) - - printer ('<<') - printer.newline () - for part_definition in part_list: - part_name = part_definition.id - try: - part = part_dict[part_name] - except KeyError: - print 'unknown part in part-list:', part_name - continue - - nv_dict = voices[part] - staves = reduce (lambda x,y: x+ y, - [mxlvoice._staves.keys () - for (v, mxlvoice) in nv_dict.values ()], - []) - - if len (staves) > 1: - staves = uniq_list (staves) - staves.sort () - printer ('\\context PianoStaff << ') - printer.newline () - - for s in staves: - staff_voices = [music_xml_voice_name_to_lily_name (part, voice_name) - for (voice_name, (v, mxlvoice)) in nv_dict.items () - if mxlvoice._start_staff == s] - - printer ('\\context Staff = "%s" << ' % s) - printer.newline () - for v in staff_voices: - printer ('\\context Voice = "%s" \\%s' % (v,v)) - printer.newline () - printer ('>>') - printer.newline () - - printer ('>>') - printer.newline () - - else: - printer ('\\new Staff <<') - printer.newline () - for (n,v) in nv_dict.items (): - - n = music_xml_voice_name_to_lily_name (part, n) - printer ('\\context Voice = "%s" \\%s' % (n,n)) - printer ('>>') - printer.newline () - - - printer ('>>') - printer.newline () - - + part_dict = dict ([(p.id, p) for p in voices.keys ()]) + + printer ('<<') + printer.newline () + for part_definition in part_list: + part_name = part_definition.id + try: + part = part_dict[part_name] + except KeyError: + print 'unknown part in part-list:', part_name + continue + + nv_dict = voices[part] + staves = reduce (lambda x,y: x+ y, + [mxlvoice._staves.keys () + for (v, mxlvoice) in nv_dict.values ()], + []) + + if len (staves) > 1: + staves = uniq_list (staves) + staves.sort () + printer ('\\context PianoStaff << ') + printer.newline () + + for s in staves: + staff_voices = [music_xml_voice_name_to_lily_name (part, voice_name) + for (voice_name, (v, mxlvoice)) in nv_dict.items () + if mxlvoice._start_staff == s] + + printer ('\\context Staff = "%s" << ' % s) + printer.newline () + for v in staff_voices: + printer ('\\context Voice = "%s" \\%s' % (v,v)) + printer.newline () + printer ('>>') + printer.newline () + + printer ('>>') + printer.newline () + + else: + printer ('\\new Staff <<') + printer.newline () + for (n,v) in nv_dict.items (): + + n = music_xml_voice_name_to_lily_name (part, n) + printer ('\\context Voice = "%s" \\%s' % (n,n)) + printer ('>>') + printer.newline () + + + printer ('>>') + printer.newline () + + def print_ly_preamble (printer, filename): - printer.dump_version () - printer.print_verbatim ('%% converted from %s\n' % filename) + printer.dump_version () + printer.print_verbatim ('%% converted from %s\n' % filename) def convert (filename, output_name): - printer = musicexp.Output_printer() - progress ("Reading MusicXML...") - - tree = musicxml.read_musicxml (filename) - parts = tree.get_typed_children (musicxml.Part) - voices = get_all_voices (parts) - - part_list = [] - if tree.get_maybe_exist_typed_child (musicxml.Part_list): - pl = tree.get_maybe_exist_typed_child (musicxml.Part_list) - part_list = pl.get_named_children ("score-part") - - if not output_name: - output_name = os.path.basename (filename) - output_name = os.path.splitext (output_name)[0] + '.ly' - - - if output_name: - progress ("Output to `%s'" % output_name) - printer.set_file (open (output_name, 'w')) - - progress ("Printing as .ly...") - - print_ly_preamble (printer, filename) - print_voice_definitions (printer, voices) - print_score_setup (printer, part_list, voices) - printer.newline () - return voices + printer = musicexp.Output_printer() + progress ("Reading MusicXML...") + + tree = musicxml.read_musicxml (filename) + parts = tree.get_typed_children (musicxml.Part) + voices = get_all_voices (parts) + + part_list = [] + if tree.get_maybe_exist_typed_child (musicxml.Part_list): + pl = tree.get_maybe_exist_typed_child (musicxml.Part_list) + part_list = pl.get_named_children ("score-part") + + if not output_name: + output_name = os.path.basename (filename) + output_name = os.path.splitext (output_name)[0] + '.ly' + + + if output_name: + progress ("Output to `%s'" % output_name) + printer.set_file (open (output_name, 'w')) + + progress ("Printing as .ly...") + + print_ly_preamble (printer, filename) + print_voice_definitions (printer, voices) + print_score_setup (printer, part_list, voices) + printer.newline () + return voices def main (): - opt_parser = option_parser() + opt_parser = option_parser() - (options, args) = opt_parser.parse_args () - if not args: - opt_parser.print_usage() - sys.exit (2) + (options, args) = opt_parser.parse_args () + if not args: + opt_parser.print_usage() + sys.exit (2) - voices = convert (args[0], options.output) + voices = convert (args[0], options.output) if __name__ == '__main__': - main() + main() -- 2.39.2