#!@PYTHON@
-# (urg! wat een pokkeformaat (pokkenformaat?))
+# PMX is a Musixtex preprocessor written by Don Simons, see
+# http://www.gmd.de/Misc/Music/musixtex/software/pmx/
+
+# TODO:
+# * block openings aren't parsed.
+
import os
import string
import sys
def encodeint (i):
return chr ( i + ord ('A'))
-def stripcomment (l):
- return re.sub ('[ \t]*%.*$\n', '', l)
-
-def stripwhite (l):
- return re.sub ('[ \n\t]+', ' ', l)
-
-def stripeols (l):
- return re.sub ('^ ', '', re.sub (' $', '', l))
actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
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
e= self.end_chord
if e and s:
- s.note_suffix = s.note_suffix + '('
- e.note_prefix = ')' + e.note_prefix
+ s.note_suffix = s.note_suffix + '-('
+ e.note_prefix = e.note_suffix + '-)'
else:
sys.stderr.write ("\nOrphaned slur")
-
+
+
class Voice:
def __init__ (self):
self.entries = []
def last_chord (self):
return self.chords[-1]
+
def add_chord (self, ch):
self.chords.append (ch)
self.entries.append (ch)
def __init__ (self, cl):
self.type = cl
def dump(self):
- return '\\clef %s;' % self.type
+ return '\\clef %s' % self.type
+
+class Key:
+ def __init__ (self, key):
+ self.type = key
+ def dump(self):
+ return '\\key %s' % self.type
clef_table = {
'b':'bass' ,
's':'soprano',
't':'treble',
'f':'frenchviolin',
- }
+ }
+key_table = {
+ '+0':'c \major',
+ '+1':'g \major',
+ '+2':'d \major',
+ '+3':'a \major',
+ '+4':'e \major',
+ '+5':'b \major',
+ '+6':'fis \major',
+ '-1':'f \major',
+ '-2':'bes \major',
+ '-3':'ees \major',
+ '-4':'aes \major',
+ '-5':'des \major',
+ '-6':'ges \major'
+ }
class Staff:
def __init__ (self):
self.voices = (Voice (), Voice())
self.instrument = 0
self.voice_idx = 0
self.number = None
+ self.key = 0
i = 0
for v in self.voices:
v.number = i
i = i+1
def set_clef (self, letter):
-
- clstr = clef_table[letter]
- self.voices[0].add_nonchord (Clef (clstr))
-
+ if clef_table.has_key (letter):
+ clstr = clef_table[letter]
+ self.voices[0].add_nonchord (Clef (clstr))
+ else:
+ sys.stderr.write ("Clef type `%c' unknown\n" % letter)
+
def current_voice (self):
return self.voices[self.voice_idx]
def next_voice (self):
for p in self.pitches:
if str:
str = str + ' '
- str = str + pitch_to_lily_string (p) + sd
+ str = str + pitch_to_lily_string (p)
- for s in self.scripts:
- str = str + '-' + s
-
- str = self.note_prefix +str + self.note_suffix
-
if len (self.pitches) > 1:
- str = '<%s>' % str
+ str = '<<%s>>' % str
elif len (self.pitches) == 0:
- str = 'r' + sd
+ str = 'r'
+ str = str + sd
+ for s in self.scripts:
+ str = str + '-' + s
+
+ str = self.note_prefix + str + self.note_suffix
str = self.chord_prefix + str + self.chord_suffix
return str
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
str = str[1:]
return str
-
- def clean (self, ls):
- ls = map (stripcomment, ls)
- ls = map (stripwhite, ls)
- ls = map (stripeols, ls)
+ def parse_key (self, str):
+ key = ""
+ #The key is changed by a string of the form K[+-]<num>[+-]<num>
+ #where the first number is the transposition and the second number is the
+ #new key signature. For now, we won't bother with the transposition.
+ if str[2] != '0':
+ sys.stderr.write("Transposition not implemented yet: ")
+ while str[0] in '+-0123456789':
+ str = str[1:]
+ else:
+ str=str[3:]
+ key = ''
+ while str[0] in '+-0123456789':
+ key=key + str[0]
+ str=str[1:]
+ keystr = key_table[key]
+ self.current_voice().add_nonchord (Key(keystr))
+ return(str)
- ls = filter (lambda x: x <> '', ls)
- return ls
def parse_header (self, ls):
+ def atonum(a):
+ if re.search('\\.', a):
+ return string.atof (a)
+ else:
+ return string.atoi (a)
- opening = ls[0]
- ls = ls[1:]
+ number_count = 12
+ numbers = []
+ while len (numbers) < number_count:
+ opening = ls[0]
+ ls = ls[1:]
- opening = map (string.atoi, re.split ('[\t ]+', opening))
+ opening = re.sub ('[ \t\n]+', ' ', opening)
+ opening = re.sub ('^ ', '', opening)
+ opening = re.sub (' $', '', opening)
+ if opening == '':
+ continue
+ opening = string.split (opening, ' ')
- (no_staffs, no_instruments, timesig_num,timesig_den, ptimesig_num,
- ptimesig_den, pickup_beats,keysig_number) = tuple (opening)
+ numbers = numbers + map (atonum, opening)
- opening = ls[0]
- ls = ls[1:]
+ (no_staffs, no_instruments, timesig_num, timesig_den, ptimesig_num,
+ esig_den, pickup_beats,keysig_number) = tuple (numbers[0:8])
+ (no_pages,no_systems, musicsize, fracindent) = tuple (numbers[8:])
# ignore this.
# opening = map (string.atoi, re.split ('[\t ]+', opening))
- # (no_pages,no_systems, musicsize, fracindent) = tuple (opening)
-
+
instruments = []
while len (instruments) < no_instruments:
instruments.append (ls[0])
ls = ls[1:]
-
l = ls[0]
ls = ls[1:]
-
self.set_staffs (no_staffs)
+
for s in self.staffs:
s.set_clef(l[0])
l = l[1:]
ls = ls[1:]
# dump more ?
- ls = ls[2:]
-
return ls
def parse_ornament (self, left):
return left
def parse_body (self, left):
- left = re.sub ('[ \t\n]+', ' ', left)
-
+ preamble = 1
+
while left:
c = left[0]
- if c in 'Gzabcdefgr':
+ if c == '%':
+ f = string.find (left, '\n')
+ if f < 0:
+ left = ''
+ left = left[f+1:]
+ elif c == 'm':
+ left = left[1:]
+ m = re.match ('([o0-9]/[o0-9]/[o0-9]/[o0-9])', left)
+ if m:
+ nums = m.group (1)
+ left = left[len (nums):]
+ nums = map (string.atoi , nums)
+ self.current_voice ().add_nonchord (Meter (nums))
+ continue
+
+ m= re.match ('([0-9o]+)', left)
+ if m:
+ nums = m.group (1)
+ self.current_voice ().add_nonchord (Meter (map (string.atoi (nums))))
+ continue
+
+ elif left[0] in 'lh':
+ f = string.find (left, '\n')
+ if f <0 :
+ left = ''
+ else:
+ left = left[f+1:]
+
+ f = string.find (left, '\n')
+ title = left[:f]
+ left=left[f+1:]
+ elif c in 'Gzabcdefgr':
left = self.parse_note (left)
elif c in DIGITS + 'n#-':
left = self.parse_basso_continuo (left)
left = self.parse_ornament (left)
elif c == 'x':
left = self.parsex (left)
+ elif c == 'C':
+ self.current_staff().set_clef(str(left[1]))
+ left = left[2:]
+ elif c == 'K':
+ left = self.parse_key (left)
elif c in "[]":
left = self.parse_beams (left)
elif left[:2] == "//":
left = left[1:]
elif c == '\\':
left = self.parse_mumbo_jumbo(left)
+ elif c == '\r':
+ left = left[1:]
else:
sys.stderr.write ("""
Huh? Unknown directive `%s', before `%s'""" % (c, left[:20] ))
left = left[1:]
- for c in self.staffs:
- c.calculate ()
-
def dump (self):
str = ''
def parse (self,fn):
ls = open (fn).readlines ()
- ls = self.clean (ls)
+ def subst(s):
+ return re.sub ('%.*$', '', s)
+
+ ls = map (subst, ls)
+ ls = filter (lambda x: x <> '\n', ls)
ls = self.parse_header (ls)
left = string.join (ls, ' ')
+
+# print left
self.parse_body (left)
+ for c in self.staffs:
+ c.calculate ()
+
Convert PMX to LilyPond.
Options:
- -h, --help this help
+ -h, --help print this help
-o, --output=FILE set output filename to FILE
- -v, --version version information
+ -v, --version shown version information
PMX is a Musixtex preprocessor written by Don Simons, see
http://www.gmd.de/Misc/Music/musixtex/software/pmx/
-Report bugs to bug-gnu-music@gnu.org.
+Report bugs to bug-lilypond@gnu.org.
Written by Han-Wen Nienhuys <hanwen@cs.uu.nl>
""")
and you are welcome to change it and/or distribute copies of it under
certain conditions. Invoke as `midi2ly --warranty' for more information.
-Copyright (c) 2000 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+Copyright (c) 2000--2003 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
""" % version)
def identify():
sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))