3 # once upon a rainy monday afternoon.
8 # ABC standard v1.6: http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt
12 program_name = 'abc2ly'
13 version = '@TOPLEVEL_VERSION@'
14 if version == '@' + 'TOPLEVEL_VERSION' + '@':
15 version = '1.2.6' # uGUHGUHGHGUGH
30 current_voice_idx = -1
31 current_lyric_idx = -1
33 def select_voice (name):
34 if not voice_idx_dict.has_key (name):
36 voice_idx_dict[name] = len (voices) -1
37 __main__.current_voice_idx = voice_idx_dict[name]
40 # current_voice_idx >= 0
43 global_key = [0] * 7 # UGH
44 names = ["One", "Two", "Three"]
54 def __init__ (self, n, d = 1):
59 g = gcd (self.num, self.den)
60 self.num = self.num / g
61 self.den = self.den /g
66 def __sub__ (self, other):
71 def dump_header (outf,hdr):
72 outf.write ('\\header {')
76 outf.write ('\n%s = "%s";\n'% (k,hdr[k]))
79 def dump_lyrics (outf):
80 for i in range (len (lyrics)):
81 outf.write ("\nverse%s = \\lyrics {" % names [i])
82 outf.write ("\n" + lyrics [i])
85 def dump_voices (outf):
86 ks = voice_idx_dict.keys()
89 outf.write ("\nvoice%s = \\notes {" % k)
90 outf.write ("\n" + voices [voice_idx_dict[k]])
93 def dump_score (outf):
94 outf.write (r"""\score{
98 ks = voice_idx_dict.keys ();
101 outf.write ("\n \\context Staff=\"%s\" \\$voice%s " % (k,k))# ugh
102 for i in range (len (lyrics)):
104 if j >= len (voices):
106 outf.write ("\n \\context Lyrics=\"%s\" \\addlyrics \\$voice%s \\$verse%s " %
107 (names [i], names [j], names [i]))
109 dump_header (outf ,header)
115 def set_default_length (s):
116 m = re.search ('1/([0-9]+)', s)
118 __main__.default_len = string.atoi ( m.group (1))
120 def set_default_len_from_time_sig (s):
121 m = re.search ('([0-9]+)/([0-9]+)', s)
123 n = string.atoi (m.group (1))
124 d = string.atoi (m.group (2))
125 if (n * 1.0 )/(d * 1.0) < 0.75:
137 sys.stderr.write ("can't open file: %s\n" % f)
141 sys.stderr.write ("gulped emty file: %s\n" % f)
146 # pitch manipulation. Tuples are (name, alteration).
147 # 0 is (central) C. Alteration -1 is a flat, Alteration +1 is a sharp
148 # pitch in semitones.
149 def semitone_pitch (tup):
159 p = p + t* 2 + tup[1]
162 def fifth_above_pitch (tup):
163 (n, a) = (tup[0] + 4, tup[1])
165 difference = 7 - (semitone_pitch ((n,a)) - semitone_pitch (tup))
176 (t,a) = fifth_above_pitch (p)
177 if semitone_pitch((t,a)) % 12 == 0:
189 (t,a) = quart_above_pitch (p)
190 if semitone_pitch((t,a)) % 12 == 0:
196 def quart_above_pitch (tup):
197 (n, a) = (tup[0] + 3, tup[1])
199 difference = 5 - (semitone_pitch ((n,a)) - semitone_pitch (tup))
207 intkey = (ord (k[0]) - ord('a') + 5) % 7
211 if k and k[0] == 'b':
214 elif k and k[0] == '#':
218 keytup = (intkey, intkeyacc)
220 sharp_key_seq = sharp_keys ()
221 flat_key_seq = flat_keys ()
225 if keytup in sharp_key_seq:
227 key_count = sharp_key_seq.index (keytup)
228 accseq = map (lambda x: (4*x -1 ) % 7, range (1, key_count + 1))
230 elif keytup in flat_key_seq:
232 key_count = flat_key_seq.index (keytup)
233 accseq = map (lambda x: (3*x + 3 ) % 7, range (1, key_count + 1))
239 key_table[a] = key_table[a] + accsign
255 def try_parse_tuplet_begin (str, state):
256 if re.match ('\([0-9]', str):
259 state.parsing_tuplet = 1
261 voices_append ("\\times %s {" % tup_lookup[dig])
264 def try_parse_group_end (str, state):
265 if str and str[0] in HSPACE:
267 if state.parsing_tuplet:
268 state.parsing_tuplet = 0
272 def header_append (key, a):
274 if header.has_key (key):
275 s = header[key] + "\n"
278 def stuff_append (stuff, idx, a):
285 linelen = len (v) - string.rfind(v, '\n')
286 if linelen + len (a) > 80:
293 def voices_append(a):
294 if current_voice_idx < 0:
295 select_voice ('default')
297 stuff_append (voices, current_voice_idx, a)
299 def lyrics_append(a):
300 stuff_append (lyrics, current_lyric_idx, a)
303 def try_parse_header_line (ln):
304 m = re.match ('^(.): *(.*)$', ln)
309 a = re.sub ('"', '\\"', a)
315 # global_voice_stuff.append ('\\time %s;' % a)
316 set_default_len_from_time_sig (a)
317 voices_append ('\\time %s;' % a)
319 __main__.global_key =compute_key (a)# ugh.
320 voices_append ('\\key %s;' % a)
323 header ['origin'] = a
325 header ['crossRefNumber'] = a
329 header_append ('history', a)
333 header ['composer'] = a
335 header ['subtitle'] = a
337 set_default_length (ln)
339 a = re.sub (' .*$', '', a)
350 def pitch_to_mudela_name (name, acc):
360 return chr (name + ord('c')) + s * acc
362 def octave_to_mudela_quotes (o):
375 while str and str[0] in DIGITS:
376 durstr = durstr + str[0]
381 n =string.atoi (durstr)
385 def duration_to_mudela_duration (multiply_tup, defaultlen, dots):
388 # (num / den) / defaultlen < 1/base
389 while base * multiply_tup[0] < multiply_tup[1]:
393 return '%d%s' % ( base, '.'* dots)
397 self.next_articulation = ''
400 self.parsing_tuplet = 0
404 # return (str, num,den,dots)
405 def parse_duration (str, parser_state):
407 den = parser_state.next_den
408 parser_state.next_den = 1
410 (str, num) = parse_num (str)
415 while str[:1] == '/':
419 (str, d) =parse_num (str)
423 den = den * default_len
425 current_dots = parser_state.next_dots
426 parser_state.next_dots = 0
433 current_dots = current_dots + 1;
434 parser_state.next_den = parser_state.next_den * 2
439 parser_state.next_dots = parser_state.next_dots + 1
447 if num % multiplier == 0 and den % f == 0:
448 num = num / multiplier
450 current_dots = current_dots + d
452 return (str, num,den,current_dots)
455 def try_parse_rest (str, parser_state):
456 if not str or str[0] <> 'z':
461 (str, num,den,d) = parse_duration (str, parser_state)
462 voices_append ('r%s' % duration_to_mudela_duration ((num,den), default_len, d))
466 def try_parse_articulation (str, state):
469 state.next_articulation = state.next_articulation + '-.'
473 state.next_articulation = state.next_articulation + '-\\trill'
477 state.next_articulation = state.next_articulation + '-\\fermata'
480 # s7m2 input doesnt care about spaces
481 if re.match('[ \t]*\(', str):
482 str = string.lstrip (str)
485 while str[:1] =='(' and str[1] not in DIGITS:
486 slur_begin = slur_begin + 1
487 state.next_articulation = state.next_articulation + '('
492 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP !
493 def try_parse_note (str, parser_state):
513 if str[0] in "ABCDEFG":
514 str = string.lower (str[0]) + str[1:]
519 if str[0] in "abcdefg":
520 notename = (ord(str[0]) - ord('a') + 5)%7
523 return str # failed; not a note!
528 while str[0] == '\'':
532 (str, num,den,current_dots) = parse_duration (str, parser_state)
535 if re.match('[ \t]*\)', str):
536 str = string.lstrip (str)
540 slur_end = slur_end + 1
545 voices_append ('%s' % ')' *slur_end )
546 voices_append ("%s%s%s" %
547 (pitch_to_mudela_name (notename, acc + global_key[notename]),
548 octave_to_mudela_quotes (octave),
549 duration_to_mudela_duration ((num,den), default_len, current_dots)))
550 if parser_state.next_articulation:
551 articulation = articulation + parser_state.next_articulation
552 parser_state.next_articulation = ''
554 voices_append (articulation)
556 voices_append ('%s' % '(' * slur_begin )
561 def junk_space (str):
562 while str and str[0] in '\t\n ':
568 def try_parse_guitar_chord (str, state):
572 while str and str[0] != '"':
579 state.next_articulation = "-\"%s\"" % gc
582 def try_parse_escape (str):
583 if not str or str [0] != '\\':
588 key_table = compute_key ()
593 # |] thin-thick double bar line
594 # || thin-thin double bar line
595 # [| thick-thin double bar line
598 # :: left-right repeat
614 warn_about = ['|:', '::', ':|', '|1', ':|2', '|2']
616 def try_parse_bar (str,state):
619 # first try the longer one
621 if str[:trylen] and bar_dict.has_key (str[:trylen]):
623 bs = "\\bar \"%s\";" % bar_dict[s]
625 sys.stderr.write('Warning kludging for barline `%s\'\n' % s)
634 if state.parsing_tuplet:
635 state.parsing_tuplet =0
642 def try_parse_tie (str):
645 voices_append (' ~ ')
648 def try_parse_chord_delims (str):
664 voices_append ("\\spanrequest \\stop \"slur\"" * end);
668 def try_parse_grace_delims (str):
671 voices_append ('\\grace { ')
685 state = Parser_state ()
687 sys.stderr.write ("Line ... ")
693 if not (lineno % happy_count):
694 sys.stderr.write ('[%d]'% lineno)
696 if re.match ('^[\t ]*(%.*)?$', ln):
698 m = re.match ('^(.*?)%(.*)$',ln)
700 voices_append ('%% %s\n' % m.group(2))
705 ln = try_parse_header_line (ln)
707 # Try nibbling characters off until the line doesn't change.
711 ln = try_parse_chord_delims (ln)
712 ln = try_parse_rest (ln, state)
713 ln = try_parse_articulation (ln,state)
714 ln = try_parse_note (ln, state)
715 ln = try_parse_bar (ln, state)
716 ln = try_parse_tie (ln)
717 ln = try_parse_escape (ln)
718 ln = try_parse_guitar_chord (ln, state)
719 ln = try_parse_tuplet_begin (ln, state)
720 ln = try_parse_group_end (ln, state)
721 ln = try_parse_grace_delims (ln)
725 msg = "%s: %d: Huh? Don't understand\n" % (fn, lineno)
726 sys.stderr.write (msg)
727 left = orig_ln[0:-len (ln)]
728 sys.stderr.write (left + '\n')
729 sys.stderr.write (' ' * len (left) + ln + '\n')
733 sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
737 Convert ABC to Mudela.
739 Usage: abc2ly [OPTION]... ABC-FILE
743 -o, --output=FILE set output filename to FILE
744 -v, --version version information
747 def print_version ():
748 print r"""abc2ly (GNU lilypond) %s""" % version
752 (options, files) = getopt.getopt (sys.argv[1:], 'vo:h', ['help','version', 'output='])
758 if o== '--help' or o == '-h':
761 if o == '--version' or o == '-v':
765 if o == '--output' or o == '-o':
773 header['tagline'] = 'Lily was here %s -- automatically converted from ABC' % version
778 sys.stderr.write ('Parsing... [%s]\n' % f)
782 out_filename = os.path.basename (os.path.splitext (f)[0]) + ".ly"
783 sys.stderr.write ('Ly output to: %s...' % out_filename)
784 outf = open (out_filename, 'w')
790 sys.stderr.write ('\n')