#
# (not finished.)
# ABC standard v1.6: http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt
-#
+#
# Enhancements (Roy R. Rankin)
#
# Header section moved to top of lilypond file
# Chord strings([-^]"string") can contain a '#'
# Header fields enclosed by [] in notes string processed
# W: words output after tune as abc2ps does it (they failed before)
+
+# Enhancements (Laura Conrad)
#
+# Barring now preserved between ABC and lilypond
+# the default placement for text in abc is above the staff.
+# %%LY now supported.
+
# Limitations
#
# Multiple tunes in single file not supported
# Blank T: header lines should write score and open a new score
# Not all header fields supported
-# Beaming not preserved between ABC and lilypond
# ABC line breaks are ignored
# Block comments generate error and are ignored
# Postscript commands are ignored
lyric_idx = -1
part_names = 0
default_len = 8
+length_specified = 0
+nobarlines = 0
global_key = [0] * 7 # UGH
names = ["One", "Two", "Three"]
DIGITS='0123456789'
else:
state.base_octave = 0
voices_append("\\clef treble;\n")
+ elif re.match('^-8va', s):
+ s = s[4:]
+ state.base_octave = -1
+ voices_append("\\clef \"G_8\";\n")
elif re.match('^alto', s):
s = s[4:]
state.base_octave = -1
outf.write ("\n")
outf.write(" >\n \\paper{}\n}\n")
+def dump_default_bar (outf):
+ outf.write ("\n\\property Score.defaultBarType=\"empty\"\n")
+
+
def dump_slyrics (outf):
ks = voice_idx_dict.keys()
ks.sort ()
ks.sort ()
for k in ks:
outf.write ("\nvoice%s = \\notes {" % k)
+ dump_default_bar(outf)
outf.write ("\n" + voices [voice_idx_dict[k]])
outf.write ("\n}")
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
def set_default_len_from_time_sig (s):
m = re.search ('([0-9]+)/([0-9]+)', s)
return ''
s = i.read (n)
if len (s) <= 0:
- sys.stderr.write ("gulped emty file: %s\n" % f)
+ sys.stderr.write ("gulped empty file: %s\n" % f)
i.close ()
return s
key = key + 'es'
k = k[1:]
if not k:
- return(key)
+ return '%s \\major' % key
type = k[0:3]
if key_lookup.has_key(type):
if str and str[0] in HSPACE:
str = str[1:]
return str
-
+
def header_append (key, a):
s = ''
if header.has_key (key):
def try_parse_header_line (ln, state):
+ global length_specified
m = re.match ('^([A-Za-z]): *(.*)$', ln)
if m:
if a == 'C':
if not state.common_time:
state.common_time = 1
- voices_append ("\\property Staff.timeSignatureStyle=\"C\"\n")
+ voices_append ("\\property Staff.TimeSignature \push #\'style = #\"C\"\n")
a = '4/4'
if a == 'C|':
if not state.common_time:
state.common_time = 1
- voices_append ("\\property Staff.timeSignatureStyle=\"C\"\n")
+ voices_append ("\\property Staff.TimeSignature \push #\'style = #\"C\"\n")
a = '2/2'
-# global_voice_stuff.append ('\\time %s;' % a)
- set_default_len_from_time_sig (a)
+ if not length_specified:
+ set_default_len_from_time_sig (a)
+ else:
+ length_specified = 0
voices_append ('\\time %s;' % a)
state.next_bar = ''
if g == 'K': # KEY
if a:
m = re.match ('^([^ \t]*) *(.*)$', a) # seperate clef info
if m:
- __main__.global_key =compute_key (m.group(1))# ugh.
- voices_append ('\\key %s \\major;' % lily_key(m.group(1)))
- check_clef(m.group(2))
+ # 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)# ugh.
+ voices_append ('\\key %s;' % lily_key(key_info))
+ check_clef(clef_info)
else:
- __main__.global_key =compute_key (a)# ugh.
+ __main__.global_key = compute_key (a)# ugh.
voices_append ('\\key %s \\major;' % lily_key(a))
if g == 'O': # Origin
header ['origin'] = a
# we use in this order specified accidental, active accidental for bar,
# active accidental for key
-def pitch_to_mudela_name (name, acc, bar_acc, key):
+def pitch_to_lilypond_name (name, acc, bar_acc, key):
s = ''
if acc == UNDEF:
- acc = bar_acc
+ if not nobarlines:
+ acc = bar_acc
if acc == UNDEF:
acc = key
if acc == -1:
return(chr (name + ord('c')) + s)
-def octave_to_mudela_quotes (o):
+def octave_to_lilypond_quotes (o):
o = o + 2
s =''
if o < 0:
return (str,n)
-def duration_to_mudela_duration (multiply_tup, defaultlen, dots):
+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
-
-
return '%d%s' % ( base, '.'* dots)
class Parser_state:
str = str[1:]
(str, num,den,d) = parse_duration (str, parser_state)
- voices_append ('%s%s' % (rest, duration_to_mudela_duration ((num,den), default_len, d)))
+ 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 = ''
voices_append ('%s' % ')' *slur_end )
bar_acc = get_bar_acc(notename, octave, parser_state)
- pit = pitch_to_mudela_name(notename, acc, bar_acc, global_key[notename])
- oct = octave_to_mudela_quotes (octave)
+ 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_mudela_duration ((num,den), default_len, current_dots)))
+ duration_to_lilypond_duration ((num,den), default_len, current_dots)))
set_bar_acc(notename, octave, acc, parser_state)
if parser_state.next_articulation:
if str:
str = str[1:]
gc = re.sub('#', '\\#', gc) # escape '#'s
- state.next_articulation = ("-\"%s\"" % gc) + state.next_articulation
+ state.next_articulation = ("^\"%s\"" % gc) + state.next_articulation
return str
def try_parse_escape (str):
'[|' : '||',
':|' : ':|',
'|:' : '|:',
-'::' : '::',
+'::' : ':|:',
'|1' : '|',
'|2' : '|',
-':|2' : ':|'
+':|2' : ':|',
+'|' : '|'
}
bs = None
# first try the longer one
- for trylen in [3,2]:
+ for trylen in [3,2,1]:
if str[:trylen] and bar_dict.has_key (str[:trylen]):
s = str[:trylen]
bs = "\\bar \"%s\";" % bar_dict[s]
return str
+def try_parse_comment (str):
+ 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
+#pitch that will be played.
+#
+#In standard 19th century musical notation, the algorithm for translating
+#between printed note and pitch involves using the barlines to determine
+#the scope of the accidentals.
+#
+#Since ABC is frequently used for music in styles that do not use this
+#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):
+ #debugging
+ nobarlines = 1
+ elif str[0:3] == '%LY':
+ p = string.find(str, 'voices')
+ if (p > -1):
+ voices_append(str[p+7:])
+ voices_append("\n")
+#write other kinds of appending if we ever need them.
+ return str
happy_count = 100
def parse_file (fn):
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)
def help ():
print r"""
-Convert ABC to Mudela.
+Convert ABC to Lilypond.
-Usage: abc2ly [OPTION]... ABC-FILE
+Usage: abc2ly [OPTIONS]... ABC-FILE
Options:
-h, --help this help
-o, --output=FILE set output filename to FILE
-v, --version version information
+
+This program converts ABC music files (see
+http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt) To LilyPond input.
"""
def print_version ():