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@'
22 sys.stderr.write ("This script needs Python 1.5.1\n")
32 current_voice_idx = -1
33 current_lyric_idx = -1
35 def select_voice (name):
36 if not voice_idx_dict.has_key (name):
38 voice_idx_dict[name] = len (voices) -1
39 __main__.current_voice_idx = voice_idx_dict[name]
42 # current_voice_idx >= 0
44 global_voice_stuff = []
46 global_key = [0] * 7 # UGH
47 names = ["One", "Two", "Three"]
57 def __init__ (self, n, d = 1):
62 g = gcd (self.num, self.den)
63 self.num = self.num / g
64 self.den = self.den /g
69 def __sub__ (self, other):
73 def dump_global (outf):
74 outf.write ("\nglobal = \\notes{")
75 for i in global_voice_stuff:
80 def dump_header (outf,hdr):
81 outf.write ('\\header {')
85 outf.write ('\n%s = "%s";\n'% (k,hdr[k]))
88 def dump_lyrics (outf):
89 for i in range (len (lyrics)):
90 outf.write ("\nverse%s = \\lyrics {" % names [i])
91 outf.write ("\n" + lyrics [i])
94 def dump_voices (outf):
95 ks = voice_idx_dict.keys()
98 outf.write ("\nvoice%s = \\notes {" % k)
99 outf.write ("\n" + voices [voice_idx_dict[k]])
102 def dump_score (outf):
103 outf.write (r"""\score{
107 ks = voice_idx_dict.keys ();
110 outf.write ("\n \\context Staff=\"%s\" \\$voice%s " % (k,k))# ugh
111 for i in range (len (lyrics)):
113 if j >= len (voices):
115 outf.write ("\n \\context Lyrics=\"%s\" \\addlyrics \\$voice%s \\$verse%s " %
116 (names [i], names [j], names [i]))
118 dump_header (outf ,header)
124 def set_default_length (s):
125 m = re.search ('1/([0-9]+)', s)
127 __main__.default_len = string.atoi ( m.group (1))
136 sys.stderr.write ("can't open file: %s\n" % f)
140 sys.stderr.write ("gulped emty file: %s\n" % f)
145 # pitch manipulation. Tuples are (name, alteration).
146 # 0 is (central) C. Alteration -1 is a flat, Alteration +1 is a sharp
147 # pitch in semitones.
148 def semitone_pitch (tup):
158 p = p + t* 2 + tup[1]
161 def fifth_above_pitch (tup):
162 (n, a) = (tup[0] + 4, tup[1])
164 difference = 7 - (semitone_pitch ((n,a)) - semitone_pitch (tup))
175 (t,a) = fifth_above_pitch (p)
176 if semitone_pitch((t,a)) % 12 == 0:
188 (t,a) = quart_above_pitch (p)
189 if semitone_pitch((t,a)) % 12 == 0:
195 def quart_above_pitch (tup):
196 (n, a) = (tup[0] + 3, tup[1])
198 difference = 5 - (semitone_pitch ((n,a)) - semitone_pitch (tup))
206 intkey = (ord (k[0]) - ord('a') + 5) % 7
210 if k and k[0] == 'b':
213 elif k and k[0] == '#':
217 keytup = (intkey, intkeyacc)
219 sharp_key_seq = sharp_keys ()
220 flat_key_seq = flat_keys ()
224 if keytup in sharp_key_seq:
226 key_count = sharp_key_seq.index (keytup)
227 accseq = map (lambda x: (4*x -1 ) % 7, range (1, key_count + 1))
229 elif keytup in flat_key_seq:
231 key_count = flat_key_seq.index (keytup)
232 accseq = map (lambda x: (3*x + 3 ) % 7, range (1, key_count + 1))
238 key_table[a] = key_table[a] + accsign
254 def try_parse_tuplet_begin (str, state):
255 if re.match ('\([0-9]', str):
258 state.parsing_tuplet = 1
260 voices_append ("\\times %s {" % tup_lookup[dig])
263 def try_parse_group_end (str, state):
264 if str and str[0] in HSPACE:
266 if state.parsing_tuplet:
267 state.parsing_tuplet = 0
271 def header_append (key, a):
273 if header.has_key (key):
274 s = header[key] + "\n"
277 def stuff_append (stuff, idx, a):
284 linelen = len (v) - string.rfind(v, '\n')
285 if linelen + len (a) > 80:
292 def voices_append(a):
293 if current_voice_idx < 0:
294 select_voice ('default')
296 stuff_append (voices, current_voice_idx, a)
298 def lyrics_append(a):
299 stuff_append (lyrics, current_lyric_idx, a)
302 def try_parse_header_line (ln):
303 m = re.match ('^(.): *(.*)$', ln)
308 a = re.sub ('"', '\\"', a)
314 global_voice_stuff.append ('\\time %s;' % a)
316 __main__.global_key =compute_key (a)# ugh.
318 global_voice_stuff.append ('\\key %s;' % a)
320 header ['origin'] = a
322 header ['crossRefNumber'] = a
326 header_append ('history', a)
330 header ['subtitle'] = a
332 set_default_length (ln)
334 a = re.sub (' .*$', '', a)
345 def pitch_to_mudela_name (name, acc):
355 return chr (name + ord('c')) + s * acc
357 def octave_to_mudela_quotes (o):
370 while str and str[0] in DIGITS:
371 durstr = durstr + str[0]
376 n =string.atoi (durstr)
380 def duration_to_mudela_duration (multiply_tup, defaultlen, dots):
383 # (num / den) / defaultlen < 1/base
384 while base * multiply_tup[0] < defaultlen * multiply_tup[1]:
388 return '%d%s' % ( base, '.'* dots)
392 self.next_articulation = ''
395 self.parsing_tuplet = 0
397 # return (num,den,dots)
398 def parse_duration (str, parser_state):
400 den = parser_state.next_den
401 parser_state.next_den = 1
403 (str, num) = parse_num (str)
412 (str, d) =parse_num (str)
416 current_dots = parser_state.next_dots
417 parser_state.next_dots = 0
420 current_dots = current_dots + 1;
421 parser_state.next_den = parser_state.next_den * 2
426 parser_state.next_dots = parser_state.next_dots + 1
429 return (str, num,den,current_dots)
432 def try_parse_rest (str, parser_state):
433 if not str or str[0] <> 'z':
438 (str, num,den,d) = parse_duration (str, parser_state)
439 voices_append ('r%s' % duration_to_mudela_duration ((num,den), default_len, d))
443 def try_parse_articulation (str, state):
445 if str and str[0] == '.':
446 state.next_articulation = state.next_articulation + '-.'
449 # s7m2 input doesnt care about spaces
450 if re.match('[ \t]*\(', str):
451 str = string.lstrip (str)
454 while str and str[0] == '(' and str[1] not in DIGITS:
455 slur_begin = slur_begin + 1
456 state.next_articulation = state.next_articulation + '('
461 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP !
462 def try_parse_note (str, parser_state):
482 if str[0] in "ABCDEFG":
483 str = string.lower (str[0]) + str[1:]
488 if str[0] in "abcdefg":
489 notename = (ord(str[0]) - ord('a') + 5)%7
492 return str # failed; not a note!
497 while str[0] == '\'':
501 (str, num,den,current_dots) = parse_duration (str, parser_state)
504 if re.match('[ \t]*\)', str):
505 str = string.lstrip (str)
508 while str and str[0] == ')':
509 slur_end = slur_end + 1
514 voices_append ('%s' % ')' *slur_end )
515 voices_append ("%s%s%s" %
516 (pitch_to_mudela_name (notename, acc + global_key[notename]),
517 octave_to_mudela_quotes (octave),
518 duration_to_mudela_duration ((num,den), default_len, current_dots)))
519 if parser_state.next_articulation:
520 articulation = articulation + parser_state.next_articulation
521 parser_state.next_articulation = ''
523 voices_append (articulation)
525 voices_append ('%s' % '(' * slur_begin )
530 def junk_space (str):
531 while str and str[0] in '\t\n ':
537 def try_parse_guitar_chord (str, state):
538 if str and str[0] == '"':
541 while str and str[0] != '"':
548 state.next_articulation = "-\"%s\"" % gc
551 def try_parse_escape (str):
552 if not str or str [0] != '\\':
556 if str and str[0] == 'K':
557 key_table = compute_key ()
562 # |] thin-thick double bar line
563 # || thin-thin double bar line
564 # [| thick-thin double bar line
567 # :: left-right repeat
570 def try_parse_bar (str,state):
571 if str and str[0] == '|':
573 if state.parsing_tuplet:
574 state.parsing_tuplet =0
585 sys.stderr.write ("warning: repeat kludge\n")
588 voices_append ('\\bar "%s";' % bs)
591 if str and str[:2] == '[|':
592 if state.parsing_tuplet:
593 state.parsing_tuplet =0
595 sys.stderr.write ("warning: thick-thin bar kludge\n")
596 voices_append ('\\bar "||";')
599 if str and str[:2] == ':|':
600 if state.parsing_tuplet:
601 state.parsing_tuplet =0
604 sys.stderr.write ("warning: repeat kludge\n")
605 voices_append ('\\bar ":|:";')
608 if str and str[:2] == '::':
609 if state.parsing_tuplet:
610 state.parsing_tuplet =0
613 sys.stderr.write ("warning: repeat kludge\n")
614 voices_append ('\\bar ":|:";')
619 def try_parse_tie (str):
620 if str and str[0] == '-':
622 voices_append (' ~ ')
625 def try_parse_chord_delims (str):
626 if str and str[0] == '[':
631 if str and str[0] == ']':
636 while str and str[0] == ')':
641 voices_append ("\\spanrequest \\stop \"slur\"" * end);
645 def try_parse_grace_delims (str):
646 if str and str[0] == '{':
648 voices_append ('\\grace { ')
650 if str and str[0] == '}':
662 state = Parser_state ()
664 sys.stderr.write ("Parsing line ... ")
670 if not (lineno % happy_count):
671 sys.stderr.write ('[%d]'% lineno)
673 if re.match ('^[\t ]*(%.*)?$', ln):
675 m = re.match ('^(.*?)%(.*)$',ln)
677 voices_append ('%% %s\n' % m.group(2))
682 ln = try_parse_header_line (ln)
684 # Try nibbling characters off until the line doesn't change.
688 ln = try_parse_chord_delims (ln)
689 ln = try_parse_rest (ln, state)
690 ln = try_parse_articulation (ln,state)
691 ln = try_parse_note (ln, state)
692 ln = try_parse_bar (ln, state)
693 ln = try_parse_tie (ln)
694 ln = try_parse_escape (ln)
695 ln = try_parse_guitar_chord (ln, state)
696 ln = try_parse_tuplet_begin (ln, state)
697 ln = try_parse_group_end (ln, state)
698 ln = try_parse_grace_delims (ln)
702 msg = "%s: %d: Huh? Don't understand\n" % (fn, lineno)
703 sys.stderr.write (msg)
704 left = orig_ln[0:-len (ln)]
705 sys.stderr.write (left + '\n')
706 sys.stderr.write (' ' * len (left) + ln + '\n')
710 sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
714 This is an ABC to mudela convertor.
716 Usage: abc2ly INPUTFILE
718 -h, --help this help.
719 -o, --output set output filename
725 (options, files) = getopt.getopt (sys.argv[1:], 'o:h', ['help', 'output='])
731 if o== '--help' or o == '-h':
733 if o == '--output' or o == '-o':
748 outf = open (out_filename, 'w')