3 # once upon a rainy monday afternoon.
8 # ABC standard v1.6: http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt
11 program_name
= 'abc-to-ly'
12 version
= '@TOPLEVEL_VERSION@'
21 sys
.stderr
.write ("This script needs Python 1.5.1\n")
28 global_voice_stuff
= []
30 global_key
= [0] * 7 # UGH
31 names
= ["One", "Two", "Three"]
41 def __init__ (self
, n
, d
= 1):
46 g
= gcd (self
.num
, self
.den
)
47 self
.num
= self
.num
/ g
48 self
.den
= self
.den
/g
53 def __sub__ (self
, other
):
58 print ("global = \\notes{")
59 for i
in global_voice_stuff
:
64 def dump_header (hdr
):
67 print '%s = "%s";\n'% (k
,hdr
[k
])
71 for i
in range (len (lyrics
)):
72 print ("verse%s = \\lyrics {" % names
[i
])
77 for i
in range (len (voices
)):
78 print ("voice%s = \\notes {" % names
[i
])
86 for i
in range (len (voices
)):
87 print (" \\context Staff=%s \\voice%s" %
88 (names
[i
], names
[i
]))
89 for i
in range (len (lyrics
)):
93 print (" \\context Lyrics=%s \\rhythm \\voice%s \\verse%s" %
94 (names
[i
], names
[j
], names
[i
]))
97 #print "%%%s" % global_voice_stuff, 1
100 def set_default_length (s
):
101 m
= re
.search ('1/([0-9]+)', s
)
103 __main__
.default_len
= string
.atoi ( m
.group (1))
112 sys
.stderr
.write ("can't open file: %s\n" % f
)
116 sys
.stderr
.write ("gulped emty file: %s\n" % f
)
121 # pitch manipulation. Tuples are (name, alteration).
122 # 0 is (central) C. Alteration -1 is a flat, Alteration +1 is a sharp
123 # pitch in semitones.
124 def semitone_pitch (tup
):
134 p
= p
+ t
* 2 + tup
[1]
137 def fifth_above_pitch (tup
):
138 (n
, a
) = (tup
[0] + 4, tup
[1])
140 difference
= 7 - (semitone_pitch ((n
,a
)) - semitone_pitch (tup
))
151 (t
,a
) = fifth_above_pitch (p
)
152 if semitone_pitch((t
,a
)) % 12 == 0:
164 (t
,a
) = quart_above_pitch (p
)
165 if semitone_pitch((t
,a
)) % 12 == 0:
171 def quart_above_pitch (tup
):
172 (n
, a
) = (tup
[0] + 3, tup
[1])
174 difference
= 5 - (semitone_pitch ((n
,a
)) - semitone_pitch (tup
))
182 intkey
= (ord (k
[0]) - ord('a') + 5) % 7
186 if k
and k
[0] == 'b':
189 elif k
and k
[0] == '#':
193 keytup
= (intkey
, intkeyacc
)
195 sharp_key_seq
= sharp_keys ()
196 flat_key_seq
= flat_keys ()
200 if keytup
in sharp_key_seq
:
202 key_count
= sharp_key_seq
.index (keytup
)
203 accseq
= map (lambda x
: (4*x
-1 ) % 7, range (1, key_count
+ 1))
205 elif keytup
in flat_key_seq
:
207 key_count
= flat_key_seq
.index (keytup
)
208 accseq
= map (lambda x
: (3*x
+ 3 ) % 7, range (1, key_count
+ 1))
214 key_table
[a
] = key_table
[a
] + accsign
227 def try_parse_tuplet_begin (str, state
):
228 if str and str[0] in DIGITS
:
231 state
.parsing_tuplet
= 1
233 voices_append ("\\times %s {" % tup_lookup
[dig
])
236 def try_parse_group_end (str, state
):
237 if str and str[0] in HSPACE
:
239 if state
.parsing_tuplet
:
240 state
.parsing_tuplet
= 0
244 def header_append (key
, a
):
246 if header
.has_key (key
):
247 s
= header
[key
] + "\n"
250 def lyrics_append (a
):
254 if len (lyrics
) <= i
:
256 lyrics
[i
] = lyrics
[i
] + a
+ "\n"
258 def voices_append (a
):
262 if len (voices
) <= i
:
264 voices
[i
] = voices
[i
] + a
+ "\n"
266 def try_parse_header_line (ln
):
267 m
= re
.match ('^(.): *(.*)$', ln
)
272 a
= re
.sub ('"', '\\"', a
)
278 global_voice_stuff
.append ('\\time %s;' % a
)
280 __main__
.global_key
=compute_key (a
)# ugh.
282 global_voice_stuff
.append ('\\key %s;' % a
)
284 header
['origin'] = a
286 header
['crossRefNumber'] = a
290 header_append ('history', a
)
294 header
['subtitle'] = a
296 set_default_length (ln
)
304 def pitch_to_mudela_name (name
, acc
):
314 return chr (name
+ ord('c')) + s
* acc
316 def octave_to_mudela_quotes (o
):
329 while str and str[0] in DIGITS
:
330 durstr
= durstr
+ str[0]
335 n
=string
.atoi (durstr
)
339 def duration_to_mudela_duration (multiply_tup
, defaultlen
, dots
):
342 # (num / den) / defaultlen < 1/base
343 while base
* multiply_tup
[0] < defaultlen
* multiply_tup
[1]:
347 return '%d%s' % ( base
, '.'* dots
)
353 self
.parsing_tuplet
= 0
356 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP !
357 def try_parse_note (str, parser_state
):
380 if str[0] in "ABCDEFG":
381 str = string
.lower (str[0]) + str[1:]
386 if str[0] in "abcdefg":
387 notename
= (ord(str[0]) - ord('a') + 5)%7
390 return str # failed; not a note!
395 while str[0] == '\'':
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
430 voices_append ("%s%s%s" %
431 (pitch_to_mudela_name (notename
, acc
+ global_key
[notename
]),
432 octave_to_mudela_quotes (octave
),
433 duration_to_mudela_duration ((num
,den
), default_len
, current_dots
)))
442 def junk_space (str):
443 while str and str[0] in '\t\n ':
449 def try_parse_guitar_chord (str):
450 if str and str[0] == '"':
453 while str and str[0] != '"':
460 sys
.stderr
.write ("warning: ignoring guitar chord: %s\n" % gc
)
464 def try_parse_escape (str):
465 if not str or str [0] != '\\':
469 if str and str[0] == 'K':
470 key_table
= compute_key ()
475 # |] thin-thick double bar line
476 # || thin-thin double bar line
477 # [| thick-thin double bar line
480 # :: left-right repeat
483 def try_parse_bar (str):
484 if str and str[0] == '|':
493 sys
.stderr
.write ("warning: repeat kludge\n")
496 voices_append ('\\bar "%s";' % bs
)
499 if str and str[:2] == '[|':
500 sys
.stderr
.write ("warning: thick-thin bar kludge\n")
501 voices_append ('\\bar "||";')
504 if str and str[:2] == ':|':
505 sys
.stderr
.write ("warning: repeat kludge\n")
506 voices_append ('\\bar ":|:";')
509 if str and str[:2] == '::':
510 sys
.stderr
.write ("warning: repeat kludge\n")
511 voices_append ('\\bar ":|:";')
517 def try_parse_chord_delims (str):
518 if str and str[0] == '[':
522 if str and str[0] == ']':
528 # urg, hairy to compute grace note hack using \times{}
529 def try_parse_grace_delims (str):
530 if str and str[0] == '{':
532 voices_append ('\\grace { ')
534 if str and str[0] == '}':
540 # Try nibbling characters off until the line doesn't change.
541 def try_parse_body_line (ln
, state
):
545 ln
= try_parse_chord_delims (ln
)
546 ln
= try_parse_note (ln
, state
)
547 ln
= try_parse_bar (ln
)
548 ln
= try_parse_escape (ln
)
549 ln
= try_parse_guitar_chord (ln
)
550 ln
= try_parse_tuplet_begin (ln
, state
)
551 ln
= try_parse_group_end (ln
, state
)
552 ln
= try_parse_grace_delims (ln
)
556 sys
.stderr
.write ("Huh? Don't understand `%s'\n" % ln
)
565 state
= Parser_state ()
567 if re
.match ('^[\t ]*(%.*)?$', l
):
571 m
= try_parse_header_line (l
)
576 m
= try_parse_body_line (l
,state
)
580 sys
.stderr
.write ("%s from LilyPond %s\n" % (program_name
, version
))
584 This is a disfunctional ABC to mudela convertor. It only gulps input, and
585 says huh when confused. Go ahead and fix me.
587 Usage: abc-2-ly INPUTFILE
589 -h, --help this help.
595 (options
, files
) = getopt
.getopt (sys
.argv
[1:], 'h', ['help'])
600 if o
== '--help' or o
== '-h':