From: fred Date: Wed, 27 Mar 2002 00:58:54 +0000 (+0000) Subject: lilypond-1.3.142 X-Git-Tag: release/1.5.59~829 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=5ad2a67690e01b435bffe7f381adf2bf1c85383b;p=lilypond.git lilypond-1.3.142 --- diff --git a/scripts/ly2dvi.py b/scripts/ly2dvi.py index 9a4d5a05c0..bb9d97188c 100644 --- a/scripts/ly2dvi.py +++ b/scripts/ly2dvi.py @@ -21,6 +21,8 @@ TODO: * dvi from lilypond .tex output? This is hairy, because we create dvi from lilypond .tex *and* header output. + * windows compatibility: rm -rf, cp file... dir + ''' @@ -61,61 +63,55 @@ extra_init = { extra_fields = extra_init.keys () fields = layout_fields + extra_fields -original_dir = os.getcwd () +program_name = 'ly2dvi' +help_summary = _("Generate .dvi with LaTeX for LilyPond") + include_path = ['.'] -temp_dir = '' -keep_temp_dir = 0 no_lily = 0 outdir = '.' track_dependencies_p = 0 - dependency_files = [] - -program_version = '@TOPLEVEL_VERSION@' -if program_version == '@' + 'TOPLEVEL_VERSION' + '@': - program_version = '1.3.134' - # generate ps ? postscript_p = 0 # be verbose? verbose_p = 0 -option_definitions = [ - ('', 'h', 'help', _ ("this help")), - ('KEY=VAL', 's', 'set', _ ("change global setting KEY to VAL")), - ('', 'P', 'postscript', _ ("generate PostScript output")), - ('', 'k', 'keep', _ ("keep all output, and name the directory ly2dvi.dir")), - ('', '', 'no-lily', _ ("don't run LilyPond")), - ('', 'V', 'verbose', _ ("verbose")), - ('', 'v', 'version', _ ("print version number")), - ('', 'w', 'warranty', _ ("show warranty and copyright")), - ('DIR', '', 'outdir', _ ("dump all final output into DIR")), - ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")), - ] + +# lily_py.py -- options and stuff +# +# source file of the GNU LilyPond music typesetter + +# BEGIN Library for these? +# cut-n-paste from ly2dvi + +program_version = '@TOPLEVEL_VERSION@' +if program_version == '@' + 'TOPLEVEL_VERSION' + '@': + program_version = '1.3.142' + + +original_dir = os.getcwd () +temp_dir = '%s.dir' % program_name +keep_temp_dir_p = 0 +verbose_p = 0 def identify (): - sys.stdout.write ('ly2dvi (GNU LilyPond) %s\n' % program_version) + sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) def warranty (): identify () sys.stdout.write ('\n') - sys.stdout.write (_ ('Copyright (c) %s by' % ' 1998-2001')) + sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001')) sys.stdout.write ('\n') sys.stdout.write (' Han-Wen Nienhuys') + sys.stdout.write (' Jan Nieuwenhuizen') sys.stdout.write ('\n') sys.stdout.write (_ (r''' Distributed under terms of the GNU General Public License. It comes with NO WARRANTY.''')) sys.stdout.write ('\n') - - -def star_progress (s): - '''Progress messages that stand out between lilypond stuff''' - progress ('*** ' + s) - def progress (s): sys.stderr.write (s + '\n') @@ -129,34 +125,6 @@ def error (s): sys.stderr.write ('\n') raise _ ("Exiting ... ") - -def find_file (name): - ''' - Search the include path for NAME. If found, return the (CONTENTS, PATH) of the file. - ''' - - f = None - nm = '' - for a in include_path: - try: - nm = os.path.join (a, name) - f = open (nm) - __main__.read_files.append (nm) - break - except IOError: - pass - if f: - sys.stderr.write (_ ("Reading %s...") % nm) - sys.stderr.write ('\n'); - return (f.read (), nm) - else: - error (_ ("can't open file: `%s'" % name)) - sys.stderr.write ('\n'); - return ('', '') - - - - def getopt_args (opts): '''Construct arguments (LONG, SHORT) for getopt from list of options.''' short = '' @@ -213,16 +181,14 @@ def options_help_str (opts): return str def help (): - sys.stdout.write (_ ("Usage: %s [OPTION]... FILE") % 'ly2dvi') + sys.stdout.write (_ ("Usage: %s [OPTION]... FILE") % program_name) sys.stdout.write ('\n\n') - sys.stdout.write (_ ("Generate .dvi with LaTeX for LilyPond")) + sys.stdout.write (help_summary) sys.stdout.write ('\n\n') sys.stdout.write (_ ("Options:")) sys.stdout.write ('\n') sys.stdout.write (options_help_str (option_definitions)) sys.stdout.write ('\n\n') - warning (_ ("all output is written in the CURRENT directory")) - sys.stdout.write ('\n') sys.stdout.write (_ ("Report bugs to %s") % 'bug-gnu-music@gnu.org') sys.stdout.write ('\n') sys.exit (0) @@ -230,31 +196,15 @@ def help (): def setup_temp (): global temp_dir - temp_dir = 'ly2dvi.dir' - if not keep_temp_dir: - temp_dir = tempfile.mktemp ('ly2dvi') - + if not keep_temp_dir_p: + temp_dir = tempfile.mktemp (program_name) try: os.mkdir (temp_dir, 0777) except OSError: pass - - - # try not to gen/search MF stuff in temp dir - fp = '' - try: - fp = ':' + os.environ['TFMFONTS'] - except KeyError: - fp = '://:' - - - os.environ['TFMFONTS'] = original_dir + fp - os.chdir (temp_dir) - if verbose_p: - progress (_ ('Temp directory is `%s\'\n') % temp_dir) - + def system (cmd, ignore_error = 0): if verbose_p: progress (_ ("Invoking `%s\'") % cmd) @@ -268,24 +218,12 @@ def system (cmd, ignore_error = 0): return st + def cleanup_temp (): - if not keep_temp_dir: + if not keep_temp_dir_p: if verbose_p: progress (_ ('Cleaning up `%s\'') % temp_dir) system ('rm -rf %s' % temp_dir) - - -def run_lilypond (files): - opts = '' - opts = opts + ' ' + string.join (map (lambda x : '-I ' + x, include_path)) - opts = opts + ' ' + string.join (map (lambda x : '-H ' + x, fields)) - - if track_dependencies_p: - opts = opts + " --dependencies " - - fs = string.join (files) - - system ('lilypond %s %s ' % (opts, fs)) def set_setting (dict, key, val): @@ -300,7 +238,34 @@ def set_setting (dict, key, val): except KeyError: warning (_ ("no such setting: %s") % `key`) dict[key] = [val] + +# END Library + +option_definitions = [ + ('', 'h', 'help', _ ("this help")), + ('KEY=VAL', 's', 'set', _ ("change global setting KEY to VAL")), + ('DIR', 'I', 'include', _ ("add DIR to LilyPond\'s search path")), + ('', 'P', 'postscript', _ ("generate PostScript output")), + ('', 'k', 'keep', _ ("keep all output, and name the directory ly2dvi.dir")), + ('', '', 'no-lily', _ ("don't run LilyPond")), + ('', 'V', 'verbose', _ ("verbose")), + ('', 'v', 'version', _ ("print version number")), + ('', 'w', 'warranty', _ ("show warranty and copyright")), + ('DIR', '', 'outdir', _ ("dump all final output into DIR")), + ('', 'd', 'dependencies', _ ("write Makefile dependencies for every input file")), + ] + +def run_lilypond (files): + opts = '' + opts = opts + ' ' + string.join (map (lambda x : '-I ' + x, include_path)) + opts = opts + ' ' + string.join (map (lambda x : '-H ' + x, fields)) + + if track_dependencies_p: + opts = opts + " --dependencies " + + fs = string.join (files) + system ('lilypond %s %s ' % (opts, fs)) def analyse_lilypond_output (filename, extra): '''Grep FILENAME for interesting stuff, and @@ -403,8 +368,10 @@ def global_latex_definition (tfiles, extra): s = s + '\\usepackage{%s}\n' \ % string.join (extra['latexpackages'], ',') - - s = s + string.join (extra['latexheaders'], ' ') + + if extra['latexheaders']: + s = s + '\\include{%s}\n' \ + % string.join (extra['latexheaders'], '}\n\\include{') textheight = '' if extra['textheight']: @@ -526,7 +493,7 @@ for opt in options: elif o == '--postscript' or o == '-P': postscript_p = 1 elif o == '--keep' or o == '-k': - keep_temp_dir = 1 + keep_temp_dir_p = 1 elif o == '--no-lily': no_lily = 1 elif o == '--outdir': @@ -544,11 +511,15 @@ for opt in options: elif o == '--warranty' or o == '-w': warranty () sys.exit (0) - - -include_path = map (os.path.abspath, include_path) -files = map (os.path.abspath, files) -outdir = os.path.abspath (outdir) + +# On most platforms, this is equivalent to +#`normpath(join(os.getcwd()), PATH)'. *Added in Python version 1.5.2* +def compat_abspath (path): + return os.path.normpath (os.path.join (os.getcwd (), path)) + +include_path = map (compat_abspath, include_path) +files = map (compat_abspath, files) +outdir = compat_abspath (outdir) def strip_ly_suffix (f): (p, e) =os.path.splitext (f) diff --git a/scripts/mup2ly.py b/scripts/mup2ly.py index 0ffa3a9bcf..2808dc1b65 100644 --- a/scripts/mup2ly.py +++ b/scripts/mup2ly.py @@ -1,164 +1,932 @@ #!@PYTHON@ - -# mup-to-ly.py -- +# mup2ly.py -- mup input converter # # source file of the GNU LilyPond music typesetter -# -# (c) 1998, 1999 Jan Nieuwenhuizen +# +# (c) 2001 -# TODO: regex -> re. +''' +TODO: -name = 'mup2ly' -version = '0.1' + WIP:lots of stuff + +''' import os +import fnmatch +import stat +import string +import re +import getopt import sys +import __main__ +import operator +import tempfile -import getopt -from string import * -import regex -import regsub -import time -def program_id (): - return name + ' version ' + version; +sys.path.append ('@datadir@/python') +import gettext +gettext.bindtextdomain ('lilypond', '@localedir@') +gettext.textdomain('lilypond') +_ = gettext.gettext + + +program_name = 'mup2ly' +help_summary = _("Convert mup to ly") +output = 0 + +# lily_py.py -- options and stuff +# +# source file of the GNU LilyPond music typesetter + +# BEGIN Library for these? +# cut-n-paste from ly2dvi + +program_version = '@TOPLEVEL_VERSION@' +if program_version == '@' + 'TOPLEVEL_VERSION' + '@': + program_version = '1.3.142' + + +original_dir = os.getcwd () +temp_dir = '%s.dir' % program_name +keep_temp_dir_p = 0 +verbose_p = 0 def identify (): - sys.stdout.write (program_id () + '\n') + sys.stdout.write ('%s (GNU LilyPond) %s\n' % (program_name, program_version)) + +def warranty (): + identify () + sys.stdout.write ('\n') + sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001')) + sys.stdout.write ('\n') + sys.stdout.write (' Han-Wen Nienhuys') + sys.stdout.write (' Jan Nieuwenhuizen') + sys.stdout.write ('\n') + sys.stdout.write (_ (r''' +Distributed under terms of the GNU General Public License. It comes with +NO WARRANTY.''')) + sys.stdout.write ('\n') + +def progress (s): + if s[-1] != '\n': + s = s + '\n' + sys.stderr.write (s) + +def warning (s): + sys.stderr.write (_ ("warning: ") + s) + sys.stderr.write ('\n') + + +def error (s): + sys.stderr.write (_ ("error: ") + s) + sys.stderr.write ('\n') + raise _ ("Exiting ... ") + +def getopt_args (opts): + '''Construct arguments (LONG, SHORT) for getopt from list of options.''' + short = '' + long = [] + for o in opts: + if o[1]: + short = short + o[1] + if o[0]: + short = short + ':' + if o[2]: + l = o[2] + if o[0]: + l = l + '=' + long.append (l) + return (short, long) + +def option_help_str (o): + '''Transform one option description (4-tuple ) into neatly formatted string''' + sh = ' ' + if o[1]: + sh = '-%s' % o[1] + + sep = ' ' + if o[1] and o[2]: + sep = ',' + + long = '' + if o[2]: + long= '--%s' % o[2] + + arg = '' + if o[0]: + if o[2]: + arg = '=' + arg = arg + o[0] + return ' ' + sh + sep + long + arg + + +def options_help_str (opts): + '''Convert a list of options into a neatly formatted string''' + w = 0 + strs =[] + helps = [] + + for o in opts: + s = option_help_str (o) + strs.append ((s, o[3])) + if len (s) > w: + w = len (s) + + str = '' + for s in strs: + str = str + '%s%s%s\n' % (s[0], ' ' * (w - len(s[0]) + 3), s[1]) + return str def help (): - sys.stdout.write ("Usage: %s [options] [files]\n" - "Convert mup to ly\n\n" - + "Options:\n" - + " -h, --help print this help\n" - % (program_name) - ) - sys.exit (0) - -identify () -(options, files) = getopt.getopt ( - sys.argv[1:], 'hp:', ['help', 'package']) -for opt in options: - o = opt[0] - a = opt[1] - if o== '--help' or o == '-h': - help () - elif o == '-p' or o == '--package': - topdir = a - else: - print o - raise getopt.error - -def gulp_file (f): - sys.stderr.write ('[%s' % f) + sys.stdout.write (_ ("Usage: %s [OPTION]... FILE") % program_name) + sys.stdout.write ('\n\n') + sys.stdout.write (help_summary) + sys.stdout.write ('\n\n') + sys.stdout.write (_ ("Options:")) + sys.stdout.write ('\n') + sys.stdout.write (options_help_str (option_definitions)) + sys.stdout.write ('\n\n') + sys.stdout.write (_ ("Report bugs to %s") % 'bug-gnu-music@gnu.org') + sys.stdout.write ('\n') + sys.exit (0) + + +def setup_temp (): + global temp_dir + if not keep_temp_dir_p: + temp_dir = tempfile.mktemp (program_name) 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) - sys.stderr.write (']') - if len (s) <= 0: - sys.stderr.write ('gulped empty file: %s\n'% f) - return s - -def line_to_ly (s): - notes = "" - o = 0 - i = regex.search (";", s) - last_name = "c" - last_duration = "4" - while i >= 0: - note = s[o:o+i] - o = o + i - i = regex.search (";", s[o+1:]) - if i >= 0 : - o = o + 1 - name = regsub.gsub ("[0-9<>\.&]*", "", note) - duration = regsub.gsub ("[a-z+<>#+&\-]*", "", note) - duration = regsub.gsub (" ", "", duration) - if name: - last_name = name + os.mkdir (temp_dir, 0777) + except OSError: + pass + + +def system (cmd, ignore_error = 0): + if verbose_p: + progress (_ ("Invoking `%s\'") % cmd) + st = os.system (cmd) + if st: + msg = ( _ ("error: ") + _ ("command exited with value %d") % st) + if ignore_error: + sys.stderr.write (msg + ' ' + _ ("(ignored)") + ' ') else: - name = last_name - name = lstrip (name) - name = rstrip (name) - if name == "ms": - name = "s" - duration = 1 - if duration: - last_duration = duration + error (msg) + + return st + + +def cleanup_temp (): + if not keep_temp_dir_p: + if verbose_p: + progress (_ ('Cleaning up `%s\'') % temp_dir) + system ('rm -rf %s' % temp_dir) + + +def set_setting (dict, key, val): + try: + val = string.atof (val) + except ValueError: + #warning (_ ("invalid value: %s") % `val`) + pass + + try: + dict[key].append (val) + except KeyError: + warning (_ ("no such setting: %s") % `key`) + dict[key] = [val] + +# END Library + + +# +# PMX cut and paste +# + +def encodeint (i): + return chr (i + ord ('A')) + + +actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'} + +def pitch_to_lily_string (tup): + (o,n,a) = tup + + nm = chr((n + 2) % 7 + ord ('a')) + nm = nm + actab[a] + if o > 0: + nm = nm + "'" * o + elif o < 0: + nm = nm + "," * -o + return nm + +def gcd (a,b): + 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) + +def rat_multiply (a,b): + (x,y) = a + (p,q) = b + + return rat_simplify ((x*p, y*q)) + +def rat_divide (a,b): + (p,q) = b + return rat_multiply (a, (q,p)) + +tuplet_table = { + 2: 3, + 3: 2, + 5: 4 +} + + +def rat_add (a,b): + (x,y) = a + (p,q) = b + + return rat_simplify ((x*q + p*y, y*q)) + +def rat_neg (a): + (p,q) = a + return (-p,q) + + +def rat_larger (a,b): + return rat_subtract (a, b )[0] > 0 + +def rat_subtract (a,b ): + return rat_add (a, rat_neg (b)) + +def rat_to_duration (frac): + log = 1 + d = (1,1) + while rat_larger (d, frac): + d = rat_multiply (d, (1,2)) + log = log << 1 + + frac = rat_subtract (frac, d) + dots = 0 + if frac == rat_multiply (d, (1,2)): + dots = 1 + elif frac == rat_multiply (d, (3,4)): + dots = 2 + return (log, dots) + + +class Barcheck : + def __init__ (self): + pass + def dump (self): + return '|\n' + + +class Meter : + def __init__ (self,nums): + self.nums = nums + def dump (self): + return ' %{ FIXME: meter change %} ' + +class Beam: + def __init__ (self, ch): + self.char = ch + def dump (self): + return self.char + +class Slur: + def __init__ (self,id): + self.id = id + self.start_chord = None + self.end_chord = None + def calculate (self): + s =self.start_chord + e= self.end_chord + + if e and s: + s.note_suffix = s.note_suffix + '(' + e.note_prefix = ')' + e.note_prefix else: - duration = last_duration - name = regsub.sub ("#", "is", name) - name = regsub.sub ("+", "'", name) - name = regsub.sub ("-", ",", name) - #name = regsub.sub ("ms", "s1", name) - notes = notes + " %s%s" % (name, duration) - return notes - -def get_voice (staff, s, staffs): - voice = len (staffs[staff-1]) + 1 - tag = "^%d [0-9-]*%d[0-9-]*:" % (staff, voice) - notes = "" - o = 0 - i = regex.search (tag, s) - while i >= 0: - o = o + i - n = regex.search ("$", s[o:]) - line = s[o:o+n] - line = regsub.sub (tag, "", line) - line = line_to_ly (line) - notes = notes + line - i = regex.search (tag, s[o+n:]) - if i >= 0: - i = i + n - if notes != "": - sys.stderr.write ('%d ' % voice) - staffs[staff-1].append (notes) - return notes != "" - -def get_staff (s, staffs): - staff=len (staffs) - i=1 - sys.stderr.write ('Staff %d ( ' % staff) - while i: - i = get_voice (staff, s, staffs) - if not i: - sys.stderr.write (')\n') - staffs.append ([]) - staff = staff + 1 - sys.stderr.write ('Staff %d ( ' % staff) - i = get_voice (staff, s, staffs) - if not i: - del staffs[staff-1] - return 0 + sys.stderr.write ("\nOrphaned slur") + +class Voice: + def __init__ (self, n): + self.number = n + self.entries = [] + self.chords = [] + self.staff = None + self.current_slurs = [] + self.slurs = [] + + def toggle_slur (self, id): + + for s in self.current_slurs: + if s.id == id: + self.current_slurs.remove (s) + s.end_chord = self.chords[-1] + return + s = Slur (id) + s.start_chord = self.chords[-1] + self.current_slurs.append (s) + self.slurs.append (s) + + def last_chord (self): + if len (self.chords): + return self.chords[-1] + else: + ch = Chord () + ch.basic_duration = 4 + return ch + + def add_chord (self, ch): + self.chords.append (ch) + self.entries.append (ch) + + def add_nonchord (self, nch): + self.entries.append (nch) + + def idstring (self): + return 'staff%svoice%s ' % (encodeint (self.staff.number) , encodeint(self.number)) + + def dump (self): + str = '' + if not self.entries: + #return '\n' + #ugh ugh + return '\n%s = {}\n\n' % self.idstring () + ln = ' ' + one_two = ("One", "Two") + if self.staff.voices [1 - self.number].entries: + ln = ln + '\\voice%s\n ' % one_two[self.number] + for e in self.entries: + next = e.dump () + if next[-1] == '\n': + str = str + ln + next + ' ' + ln = ' ' + continue + + if len (ln) +len (next) > 72: + str = str+ ln + '\n' + ln = ' ' + ln = ln + next + ' ' + + + str = str + ln + id = self.idstring () + + str = '''%s = \\notes { +%s +} + +'''% (id, str) + return str + + def calculate_graces (self): + lastgr = 0 + lastc = None + for c in self.chords: + if c.grace and not lastgr: + c.chord_prefix = c.chord_prefix + '\\grace { ' + elif not c.grace and lastgr: + lastc.chord_suffix = lastc.chord_suffix + ' } ' + lastgr = c.grace + lastc = c + + def calculate (self): + self.calculate_graces () + for s in self.slurs: + s.calculate () + +class Clef: + def __init__ (self, cl): + self.type = cl + def dump(self): + return '\\clef %s;' % self.type + +clef_table = { + 'b':'bass' , + 'r':'baritone', + 'n':'tenor', + 'a':'alto', + 'm':'mezzosoprano', + 's':'soprano', + 't':'treble', + 'f':'frenchviolin', + } + +class Staff: + def __init__ (self, n): + # ugh + self.voices = (Voice (0), Voice (1)) + + # self.voice_idx = 0 + self.clef = None + self.instrument = 0 + self.number = n + + i = 0 + for v in self.voices: + v.staff = self + v.number = i + i = i+1 + + def set_clef (self, letter): + clstr = clef_table[letter] + self.voices[0].add_nonchord (Clef (clstr)) + + #def current_voice (self): + # return self.voices[self.voice_idx] + # + #def next_voice (self): + # self.voice_idx = (self.voice_idx + 1)%len (self.voices) + + def calculate (self): + for v in self.voices: + v.calculate () + + def idstring (self): + return 'staff%s' % encodeint (self.number) + + def dump (self): + str = '' + + refs = '' + for v in self.voices: + str = str + v.dump() + refs = refs + '\n \\' + v.idstring () + + str = str + ''' +%s = \context Staff = %s <%s +> + +''' % (self.idstring (), self.idstring (), refs) + return str + +class Tuplet: + def __init__ (self, number, base, dots): + self.chords = [] + self.number = number + self.replaces = tuplet_table[number] + self.base = base + self.dots = dots + + length = (1,base) + if dots == 1: + length = rat_multiply (length, (3,2)) + elif dots == 2: + length = rat_multiply (length, (7,4)) + + length = rat_multiply (length, (1,self.replaces)) + + (nb,nd) =rat_to_duration (length) + + self.note_base = nb + self.note_dots = nd + + def add_chord (self, ch): + ch.dots = self.note_dots + ch.basic_duration = self.note_base + self.chords.append (ch) + + if len (self.chords) == 1: + ch.chord_prefix = '\\times %d/%d { ' % (self.replaces, self.number) + elif len (self.chords) == self.number: + ch.chord_suffix = ' }' + +class Chord: + def __init__ (self): + self.pitches = [] + self.multimeasure = 0 + self.dots = 0 + self.basic_duration = 0 + self.scripts = [] + self.grace = 0 + self.chord_prefix = '' + self.chord_suffix = '' + self.note_prefix = '' + self.note_suffix = '' + + def dump (self): + str = '' + + sd = '' + if self.basic_duration == 0.5: + sd = '\\breve' + else: + sd = '%d' % self.basic_duration + sd = sd + '.' * self.dots + for p in self.pitches: + if str: + str = str + ' ' + str = str + pitch_to_lily_string (p) + sd + + for s in self.scripts: + str = str + '-' + s + + str = self.note_prefix +str + self.note_suffix + + if len (self.pitches) > 1: + str = '<%s>' % str + elif self.multimeasure: + str = 'R' + sd + elif len (self.pitches) == 0: + str = 'r' + sd + + str = self.chord_prefix + str + self.chord_suffix + + return str + +SPACE=' \t\n' +DIGITS ='0123456789' +basicdur_table = { + 9: 0.5, + 0: 0 , + 2: 2 , + 4: 4 , + 8: 8 , + 1: 16, + 3: 32, + 6: 64 + } + + +ornament_table = { + 't': '\\prall', + 'm': '\\mordent', + 'x': '"x"', + '+': '+', + 'u': '"pizz"', + 'p': '|', + '(': '"paren"', + ')': '"paren"', + 'g': '"segno"', + '.': '.', + 'fd': '\\fermata', + 'f': '\\fermata', + '_': '-', + 'T': '\\trill', + '>': '>', + '^': '^', + } + +# http://www.arkkra.com/doc/uguide/contexts.html + +contexts = [ + 'header', + 'footer', + 'header2', + 'footer2', + 'score', + 'staff', + 'voice', + 'grids', + 'music', + ] + +class Parser: + def __init__ (self, filename): + self.parse_function = self.parse_context_music + self.staffs = [] + self.current_voices = [] + self.forced_duration = None + self.last_name = 0 + self.last_oct = 0 + self.tuplets_expected = 0 + self.tuplets = [] + self.last_basic_duration = 4 + + self.parse (filename) + + #def set_staffs (self, number): + # self.staffs = map (lambda x: Staff (x), range (0, number)) + + #def current_staff (self): + # return self.staffs[self.staff_idx] + + #def current_voice (self): + # return self.current_staff ().current_voice () + + #def next_staff (self): + # self.staff_idx = (self.staff_idx + 1)% len (self.staffs) + + def parse_compound_location (self, line): + colon = string.index (line, ':') + s = line[:colon] + debug (s) + line = line[colon + 1:] + debug (line) + self.current_voices = [] + ##self.current_staffs = [] + map (self.parse_location, string.split (s, '&')) + return line + + def parse_location (self, line): + m = re.match ('^([-,0-9]+) *([-,0-9]*)', string.lstrip (line)) + + def range_list_to_idxs (s): + + # duh + def flatten (l): + f = [] + for i in l: + for j in i: + f.append (j) + return f + + def range_to_list (s): + if string.find (s, '-') >= 0: + debug ('s: ' + s) + l = map (string.lstrip, + string.split (s, '-')) + r = range (string.atoi (l[0]) - 1, + string.atoi (l[1])) + else: + r = (string.atoi (s) - 1,) + return r + + ranges = string.split (s, ',') + l = flatten (map (range_to_list, ranges)) + l.sort () + return l + + staff_idxs = range_list_to_idxs (m.group (1)) + if m.group (2): + voice_idxs = range_list_to_idxs (m.group (2)) + else: + voice_idxs = [0] + for s in staff_idxs: + while s > len (self.staffs) - 1: + self.staffs.append (Staff (s)) + for v in voice_idxs: + self.current_voices.append (self.staffs[s].voices[v]) + + def parse_note (self, line): + # FIXME: 1? + oct = 1 + name = (ord (line[0]) - ord ('a') + 5) % 7 + # FIXME: does key play any role in this? + alteration = 0 + line = string.lstrip (line[1:]) + while line: + if len (line) > 1 and line[:2] == '//': + line = 0 + break + elif line[0] == '#': + alteration = alteration + 1 + elif line[0] == '&': + alteration = alteration - 1 + elif line[0] == '+': + oct = oct + 1 + elif line[0] == '-': + oct = oct - 1 + else: + skipping (_ ("%s") % line[0]) + line = string.lstrip (line[1:]) + return (oct, name, alteration) + + def parse_chord (self, line): + line = string.lstrip (line) + ch = Chord () + if not line: + ch = self.current_voices[0].last_chord () + else: + m = re.match ('^([0-9]+)([.]*)', line) + if m: + ch.basic_duration = string.atoi (m.group (1)) + line = line[len (m.group (1)):] + if m.group (2): + ch.basic_duration = len (m.group (2)) + line = line[len (m.group (1)):] + else: + ch.basic_duration = self.current_voices[0].last_chord ().basic_duration + + line = string.lstrip (line) + if len (line) > 1 and line[:2] == '//': + line = 0 + #ugh + if not line: + duration = ch.basic_duration + ch = self.current_voices[0].last_chord () + ch.basic_duration = duration + + while line: + if len (line) > 1 and line[:2] == '//': + line = 0 + break + elif line[:1] == 'mr': + ch.multimeasure = 1 + line = line[1:] + elif line[:1] == 'ms': + ch.multimeasure = 1 + line = line[1:] + elif line[0] in 'rs': + pass + elif line[0] in 'abcdefg': + pitch = self.parse_note (line) + debug ('PITCH: ' + `pitch`) + ch.pitches.append (pitch) + line = 0 + break + else: + skipping (_ ("%s") % line[0]) + line = string.lstrip (line[1:]) + map (lambda x, ch=ch: x.add_chord (ch), self.current_voices) + + def parse_voice (self, line): + chords = string.split (line, ';') + map (self.parse_chord, chords) + + def init_context_header (self, line): + self.parse_function = self.parse_context_header + + def parse_context_header (self, line): + debug ('header: ' + line) + + def init_context_footer (self, line): + self.parse_function = self.parse_context_footer + + def parse_context_footer (self, line): + debug ('footer: ' + line) + + def init_context_header2 (self, line): + self.parse_function = self.parse_context_header2 + + def parse_context_header2 (self, line): + debug ('header2: ' + line) + + def init_context_footer2 (self, line): + self.parse_function = self.parse_context_footer2 + + def parse_context_footer2 (self, line): + debug ('footer2: ' + line) + + def init_context_score (self, line): + self.parse_function = self.parse_context_score + + def parse_context_score (self, line): + debug ('score: ' + line) + + def init_context_staff (self, line): + self.parse_function = self.parse_context_staff + + def parse_context_staff (self, line): + debug ('staff: ' + line) + + def init_context_voice (self, line): + self.parse_function = self.parse_context_voice + + def parse_context_voice (self, line): + debug ('voice: ' + line) + + def init_context_grids (self, line): + self.parse_function = self.parse_context_line + + def parse_context_grids (self, line): + debug ('grids: ' + line) + + def init_context_music (self, line): + self.parse_function = self.parse_context_music + + def parse_context_music (self, line): + debug ('music: ' + line) + line = string.lstrip (line) + if line and line[0] in '0123456789': + line = string.lstrip (self.parse_compound_location (line)) + self.parse_voice (line) + else: + skipping (_ ("%s") % line) + + def parse (self, file): + # shortcut: set to official mup maximum (duh) + # self.set_staffs (40) + lines = open (file).readlines () + for line in lines: + debug ('LINE: ' + line) + m = re.match ('^([a-z]+2?)', line) + + if m: + word = m.group (1) + if word in contexts: + eval ('self.init_context_%s (line)' % word) + continue + else: + warning (_ ("no such context: %s") % word) + skipping (line) + else: + debug ('FUNC: ' + `self.parse_function`) + self.parse_function (line) + + for c in self.staffs: + c.calculate () + + def dump (self): + str = '' + + refs = '' + for s in self.staffs: + str = str + s.dump () + refs = refs + '\n \\' + s.idstring () + + str = str + ''' + +\score { + <%s + > +} +''' % refs + return str + + +option_definitions = [ + ('', 'd', 'debug', _ ("debug")), + ('', 'h', 'help', _ ("this help")), + ('FILE', 'o', 'output', _ ("write output to FILE")), + ('', 'V', 'verbose', _ ("verbose")), + ('', 'v', 'version', _ ("print version number")), + ('', 'w', 'warranty', _ ("show warranty and copyright")), + ] + +debug_p = 0 +def debug (s): + if debug_p: + progress ('DEBUG: ' + s) +def skipping (s): + if debug_p: + progress ('SKIPPING: ' + s) + +(sh, long) = getopt_args (__main__.option_definitions) +try: + (options, files) = getopt.getopt (sys.argv[1:], sh, long) +except: + help () + sys.exit (2) + + +for opt in options: + o = opt[0] + a = opt[1] + if 0: + pass + elif o== '--debug' or o == '-d': + debug_p = 1 + elif o== '--help' or o == '-h': + help () + sys.exit (0) + elif o== '--verbose' or o == '-V': + verbose_p = 1 + elif o == '--version' or o == '-v': + identify () + sys.exit (0) + elif o == '--output' or o == '-o': + output = a + else: + print o + raise getopt.error + +# writes to stdout for help2man +# don't call +# identify () +# sys.stdout.flush () + +# handy emacs testing +if not files: + files = ['template.mup'] + +for f in files: + if f == '-': + f = '' + + progress ( _("Processing %s..." % f)) + e = Parser (f) + if not output: + output = os.path.basename (re.sub ('(?i).mup$', '.ly', f)) + + if output == f: + output = os.path.basename (f + '.ly') + + progress (_ ("Writing %s...") % output) + + tag = '%% Lily was here -- automatically converted by %s from %s' % ( program_name, f) + ly = tag + '\n' + e.dump () + + o = open (output, 'w') + o.write (ly) + o.close () + print ly -staffs=[[]] -mup=files[0] -ly = os.path.basename (os.path.splitext (mup)[0]) + ".ly" -s = gulp_file (mup) -sys.stderr.write ('\n') -i=1 -while i: - i=get_staff (s, staffs) -sys.stderr.write ('\n') -sys.stderr.write ('Ly output to: %s...' % ly) -lyfile = open (ly, "w") -for i in range (len (staffs)): - for v in range (len (staffs[i])): - lyfile.write ("$staff%d_voice_%d = \\notes {\n %s\n}\n\n" % (i+1, v+1, staffs[i][v])) -lyfile.write ("\\score{\n") -lyfile.write ("\\notes <\n") -for i in range (len (staffs)): - lyfile.write ("\\context Staff=staff%s <\n" % chr(ord('A')+i)) - for v in range (len (staffs[i])): - lyfile.write ("{ \\$staff%d_voice_%d } " % (i+1, v+1)) - lyfile.write ("\n>\n") -lyfile.write (">\n") -lyfile.write ("\n}") -lyfile.close () -sys.stderr.write ('\n') diff --git a/scripts/pmx2ly.py b/scripts/pmx2ly.py index b8d289b861..c260b06819 100644 --- a/scripts/pmx2ly.py +++ b/scripts/pmx2ly.py @@ -407,7 +407,9 @@ class Parser: str = str[1:] else: ch = Chord () - self.current_voice().add_chord (ch) + self.current_voice().add_chord (ch) + + # what about 's'? if str[0] <> 'r': name = (ord (str[0]) - ord('a') + 5) % 7