]> git.donarmstrong.com Git - lilypond.git/blob - scripts/abc2ly.py
Fixes bug in abc2ly and abc2ly regtest
[lilypond.git] / scripts / abc2ly.py
1 #!@TARGET_PYTHON@
2 # -*- coding: utf-8 -*-
3
4 # once upon a rainy monday afternoon.
5
6 #    This file is part of LilyPond, the GNU music typesetter.
7 #
8 #    LilyPond is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    LilyPond is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
20
21 #
22 #   ...
23 #
24 # (not finished.)
25 # ABC standard v1.6:  http://abcnotation.com/
26 #
27 # Enhancements  (Roy R. Rankin)
28 #
29 # Header section moved to top of lilypond file
30 # handle treble, treble-8, alto, and bass clef
31 # Handle voices (V: headers) with clef and part names, multiple voices
32 # Handle w: lyrics with multiple verses
33 # Handle key mode names for minor, major, phrygian, ionian, locrian, aeolian,
34 #     mixolydian, lydian, dorian
35 # Handle part names from V: header
36 # Tuplets handling fixed up
37 # Lines starting with |: not discarded as header lines
38 # Multiple T: and C: header entries handled
39 # Accidental maintained until next bar check
40 # Silent rests supported
41 # articulations fermata, upbow, downbow, ltoe, accent, tenuto supported
42 # Chord strings([-^]"string") can contain a '#'
43 # Header fields enclosed by [] in notes string processed
44 # W: words output after tune as abc2ps does it (they failed before)
45
46 # Enhancements (Laura Conrad)
47 #
48 # Barring now preserved between ABC and lilypond
49 # the default placement for text in abc is above the staff.
50 # %%LY now supported.
51 # \breve and \longa supported.
52 # M:none doesn't crash lily.
53 # lilypond '--' supported.
54
55 # Enhancements (Guy Gascoigne-Piggford)
56 #
57 # Add support for maintaining ABC's notion of beaming, this is selectable
58 # from the command line with a -b or --beam option.
59 # Fixd a problem where on cygwin empty lines weren't being correctly identifed
60 # and so were complaining, but still generating the correct output.
61
62 # Limitations
63 #
64 # Multiple tunes in single file not supported
65 # Blank T: header lines should write score and open a new score
66 # Not all header fields supported
67 # ABC line breaks are ignored
68 # Block comments generate error and are ignored
69 # Postscript commands are ignored
70 # lyrics not resynchronized by line breaks (lyrics must fully match notes)
71 # %%LY slyrics can't be directly before a w: line.
72 # ???
73
74
75
76 #TODO:
77 #
78 # * coding style
79 # * lilylib
80 # * GNU style messages:  warning:FILE:LINE:
81 # * l10n
82 #
83 # Convert to new chord styles.
84 #
85 # UNDEF -> None
86 #
87
88
89 import __main__
90 import getopt
91 import sys
92 import re
93 import os
94
95 program_name = sys.argv[0]
96
97
98 """
99 @relocate-preamble@
100 """
101
102 import lilylib as ly
103 global _;_=ly._
104
105 version = '@TOPLEVEL_VERSION@'
106 if version == '@' + 'TOPLEVEL_VERSION' + '@':
107     version = '(unknown version)'                # uGUHGUHGHGUGH
108
109 UNDEF = 255
110 state = UNDEF
111 voice_idx_dict = {}
112 header = {}
113 header['footnotes'] = ''
114 lyrics = []
115 slyrics = []
116 voices = []
117 state_list = []
118 repeat_state = [0] * 8
119 current_voice_idx = -1
120 current_lyric_idx = -1
121 lyric_idx = -1
122 part_names = 0
123 default_len = 8
124 length_specified = 0
125 nobarlines = 0
126 global_key = [0] * 7                        # UGH
127 names = ["One", "Two", "Three"]
128 DIGITS='0123456789'
129 HSPACE=' \t'
130 midi_specs = ''
131
132
133 def error (msg):
134     sys.stderr.write (msg)
135     if global_options.strict:
136         sys.exit (1)
137
138
139 def alphabet (i):
140     return chr (i + ord('A'))
141
142 def check_clef(s):
143     # the number gives the base_octave
144     clefs = [("treble", "treble", 0),
145              ("treble1", "french", 0),
146              ("bass3", "varbaritone", 0),
147              ("bass", "bass", 0),
148              ("alto4", "tenor", 0),
149              ("alto2", "mezzosoprano", 0),
150              ("alto1", "soprano", 0),
151              ("alto", "alto", 0),
152              ("perc", "percussion", 0)]
153     modifier = [("-8va", "_8", -1),
154                 ("-8", "_8", -1),
155                 ("\+8", "^8", +1),
156                 ("8", "_8", -1)]
157
158     if not s:
159         return ''
160     clef = None;
161     octave = 0;
162     for c in clefs:
163       m = re.match('^'+c[0], s)
164       if m:
165         (clef, octave) = (c[1], c[2])
166         s = s[m.end():]
167         break;
168     if not clef:
169       return s
170
171     mod = "";
172     for md in modifier:
173       m = re.match('^'+md[0], s)
174       if m:
175         mod = md[1];
176         octave += md[2];
177         s = s[m.end():]
178         break;
179
180     state.base_octave = octave
181     voices_append ("\\clef \""+clef+mod+"\"\n")
182     return s
183
184 def select_voice (name, rol):
185     if not voice_idx_dict.has_key (name):
186         state_list.append(Parser_state())
187         voices.append ('')
188         slyrics.append ([])
189         voice_idx_dict[name] = len (voices) -1
190     __main__.current_voice_idx =  voice_idx_dict[name]
191     __main__.state = state_list[current_voice_idx]
192     while rol != '':
193         m = re.match ('^([^ \t=]*)=(.*)$', rol) # find keywork
194         if m:
195             keyword = m.group(1)
196             rol = m.group (2)
197             a = re.match ('^("[^"]*"|[^ \t]*) *(.*)$', rol)
198             if a:
199                 value = a.group (1)
200                 rol = a.group ( 2)
201                 if keyword == 'clef':
202                     check_clef(value)
203                 elif keyword == "name":
204                     value = re.sub ('\\\\','\\\\\\\\', value)
205                     ## < 2.2
206                     voices_append ("\\set Staff.instrument = %s\n" % value )
207
208                     __main__.part_names = 1
209                 elif keyword == "sname" or keyword == "snm":
210                     voices_append ("\\set Staff.instr = %s\n" % value )
211         else:
212             break
213
214 def dump_header (outf,hdr):
215     outf.write ('\\header {\n')
216     ks = hdr.keys ()
217     ks.sort ()
218     for k in ks:
219         hdr[k] = re.sub('"', '\\"', hdr[k])
220         outf.write ('\t%s = "%s"\n'% (k,hdr[k]))
221     outf.write ('}')
222
223 def dump_lyrics (outf):
224     if (len(lyrics)):
225         outf.write("\n\\score\n{\n \\lyrics\n <<\n")
226         for i in range (len (lyrics)):
227             outf.write ( lyrics [i])
228             outf.write ("\n")
229         outf.write("    >>\n    \\layout{}\n}\n")
230
231 def dump_default_bar (outf):
232     """
233     Nowadays abc2ly outputs explicits barlines (?)
234     """
235     ## < 2.2
236     outf.write ("\n\\set Score.defaultBarType = \"empty\"\n")
237
238
239 def dump_slyrics (outf):
240     ks = voice_idx_dict.keys()
241     ks.sort ()
242     for k in ks:
243         if re.match('[1-9]', k):
244             m = alphabet (int (k))
245         else:
246             m = k
247         for i in range (len(slyrics[voice_idx_dict[k]])):
248             l= alphabet(i)
249             outf.write ("\nwords%sV%s = \\lyricmode {" % (m, l))
250             outf.write ("\n" + slyrics [voice_idx_dict[k]][i])
251             outf.write ("\n}")
252
253 def dump_voices (outf):
254     global doing_alternative, in_repeat
255     ks = voice_idx_dict.keys()
256     ks.sort ()
257     for k in ks:
258         if re.match ('[1-9]', k):
259             m = alphabet (int (k))
260         else:
261             m = k
262         outf.write ("\nvoice%s =  {" % m)
263         dump_default_bar(outf)
264         if repeat_state[voice_idx_dict[k]]:
265             outf.write("\n\\repeat volta 2 {")
266         outf.write ("\n" + voices [voice_idx_dict[k]])
267         if not using_old:
268             if doing_alternative[voice_idx_dict[k]]:
269                 outf.write("}")
270             if in_repeat[voice_idx_dict[k]]:
271                 outf.write("}")
272         outf.write ("\n}")
273
274 def try_parse_q(a):
275     #assume that Q takes the form "Q:'opt. description' 1/4=120"
276     #There are other possibilities, but they are deprecated
277     r = re.compile ('^(.*) *([0-9]+) */ *([0-9]+) *=* *([0-9]+)\s*')
278     m = r.match (a)
279     if m:
280         descr = m.group(1) # possibly empty
281         numerator = int(m.group (2))
282         denominator = int(m.group (3))
283         tempo = m.group (4)
284         dur = duration_to_lilypond_duration ((numerator,denominator), 1, 0)
285         voices_append ("\\tempo " + descr + " " + dur + "=" + tempo + "\n")
286     else:
287         sys.stderr.write("abc2ly: Warning, unable to parse Q specification: %s\n" % a)
288
289 def dump_score (outf):
290     outf.write (r"""
291
292 \score{
293     <<
294 """)
295
296     ks = voice_idx_dict.keys ();
297     ks.sort ()
298     for k in  ks:
299         if re.match('[1-9]', k):
300             m = alphabet (int (k))
301         else:
302             m = k
303         if k == 'default' and len (voice_idx_dict) > 1:
304             break
305         outf.write ("\n\t\\context Staff=\"%s\"\n\t{\n" %k )
306         if k != 'default':
307             outf.write ("\t    \\voicedefault\n")
308         outf.write ("\t    \\voice%s " % m)
309         outf.write ("\n\t}\n")
310
311         l = ord( 'A' )
312         for lyrics in slyrics [voice_idx_dict[k]]:
313             outf.write ("\n\t\\addlyrics {\n")
314             if re.match('[1-9]',k):
315                 m = alphabet (int (k))
316             else:
317                 m = k
318
319             outf.write ( " \\words%sV%s } " % ( m, chr (l)) )
320             l += 1
321
322     outf.write ("\n    >>")
323     outf.write ("\n\t\\layout {\n")
324     outf.write ("\t}\n\t\\midi {%s}\n}\n" % midi_specs)
325
326
327
328 def set_default_length (s):
329     global length_specified
330     m =  re.search ('1/([0-9]+)', s)
331     if m:
332         __main__.default_len = int ( m.group (1))
333         length_specified = 1
334
335 def set_default_len_from_time_sig (s):
336     m =  re.search ('([0-9]+)/([0-9]+)', s)
337     if m:
338         n = int (m.group (1))
339         d = int (m.group (2))
340         if (n * 1.0 )/(d * 1.0) <  0.75:
341             __main__.default_len =  16
342         else:
343             __main__.default_len = 8
344
345 def gulp_file(f):
346     try:
347         i = open(f)
348         i.seek (0, 2)
349         n = i.tell ()
350         i.seek (0,0)
351     except:
352         sys.stderr.write ("cannot open file: `%s'\n" % f)
353         return ''
354     s = i.read (n)
355     if len (s) <= 0:
356         sys.stderr.write ("gulped empty file: `%s'\n" % f)
357     i.close ()
358     return s
359
360
361 # pitch manipulation. Tuples are (name, alteration).
362 # 0 is (central) C. Alteration -1 is a flat, Alteration +1 is a sharp
363 # pitch in semitones.
364 def semitone_pitch  (tup):
365     p =0
366
367     t = tup[0]
368     p = p + 12 * (t / 7)
369     t = t % 7
370
371     if t > 2:
372         p = p- 1
373
374     p = p + t* 2 + tup[1]
375     return p
376
377 def fifth_above_pitch (tup):
378     (n, a)  = (tup[0] + 4, tup[1])
379
380     difference = 7 - (semitone_pitch ((n,a)) - semitone_pitch (tup))
381     a = a + difference
382
383     return (n,a)
384
385 def sharp_keys ():
386     p = (0,0)
387     l = []
388     k = 0
389     while 1:
390         l.append (p)
391         (t,a) = fifth_above_pitch (p)
392         if semitone_pitch((t,a)) % 12 == 0:
393             break
394
395         p = (t % 7, a)
396     return l
397
398 def flat_keys ():
399     p = (0,0)
400     l = []
401     k = 0
402     while 1:
403         l.append (p)
404         (t,a) = quart_above_pitch (p)
405         if semitone_pitch((t,a)) % 12 == 0:
406             break
407
408         p = (t % 7, a)
409     return l
410
411 def quart_above_pitch (tup):
412     (n, a)  = (tup[0] + 3, tup[1])
413
414     difference = 5 - (semitone_pitch ((n,a)) - semitone_pitch (tup))
415     a = a + difference
416
417     return (n,a)
418
419 key_lookup = {         # abc to lilypond key mode names
420     'm'   : 'minor',
421     'min' : 'minor',
422     'maj' : 'major',
423     'major' : 'major',
424     'phr' : 'phrygian',
425     'ion' : 'ionian',
426     'loc' : 'locrian',
427     'aeo' : 'aeolian',
428     'mix' : 'mixolydian',
429     'mixolydian' : 'mixolydian',
430     'lyd' : 'lydian',
431     'dor' : 'dorian',
432     'dorian' : 'dorian'
433 }
434
435 def lily_key (k):
436     if k == 'none':
437         return
438     orig = "" + k
439     # UGR
440     k = k.lower ()
441     key = k[0]
442     #UGH
443     k = k[1:]
444     if k and k[0] == '#':
445         key = key + 'is'
446         k = k[1:]
447     elif k and k[0] == 'b':
448         key = key + 'es'
449         k = k[1:]
450     if not k:
451         return '%s \\major' % key
452
453     type = k[0:3]
454     if not key_lookup.has_key (type):
455         #ugh, use lilylib, say WARNING:FILE:LINE:
456         sys.stderr.write ("abc2ly:warning:")
457         sys.stderr.write ("ignoring unknown key: `%s'" % orig)
458         sys.stderr.write ('\n')
459         return 0
460     return ("%s \\%s" % ( key, key_lookup[type]))
461
462 def shift_key (note, acc, shift):
463     s = semitone_pitch((note, acc))
464     s = (s + shift + 12) % 12
465     if s <= 4:
466         n = s / 2
467         a = s % 2
468     else:
469         n = (s + 1) / 2
470         a = (s + 1) % 2
471     if a:
472         n = n + 1
473         a = -1
474     return (n,a)
475
476 key_shift = { # semitone shifts for key mode names
477     'm'   : 3,
478     'min' : 3,
479     'minor' : 3,
480     'maj' : 0,
481     'major' : 0,
482     'phr' : -4,
483     'phrygian' : -4,
484     'ion' : 0,
485     'ionian' : 0,
486     'loc' : 1,
487     'locrian' : 1,
488     'aeo' : 3,
489     'aeolian' : 3,
490     'mix' : 5,
491     'mixolydian' : 5,
492     'lyd' : -5,
493     'lydian' : -5,
494     'dor' :        -2,
495     'dorian' :        -2
496 }
497 def compute_key (k):
498     k = k.lower ()
499     intkey = (ord (k[0]) - ord('a') + 5) % 7
500     intkeyacc =0
501     k = k[1:]
502
503     if k and k[0] == 'b':
504         intkeyacc = -1
505         k = k[1:]
506     elif  k and k[0] == '#':
507         intkeyacc = 1
508         k = k[1:]
509     k = k[0:3]
510     if k and key_shift.has_key(k):
511         (intkey, intkeyacc) = shift_key(intkey, intkeyacc, key_shift[k])
512     keytup = (intkey, intkeyacc)
513
514     sharp_key_seq = sharp_keys ()
515     flat_key_seq = flat_keys ()
516
517     accseq = None
518     accsign = 0
519     if keytup in sharp_key_seq:
520         accsign = 1
521         key_count = sharp_key_seq.index (keytup)
522         accseq = map (lambda x: (4*x -1 ) % 7, range (1, key_count + 1))
523
524     elif keytup in flat_key_seq:
525         accsign = -1
526         key_count = flat_key_seq.index (keytup)
527         accseq = map (lambda x: (3*x + 3 ) % 7, range (1, key_count + 1))
528     else:
529         error ("Huh?")
530         raise Exception ("Huh")
531
532     key_table = [0] * 7
533     for a in accseq:
534         key_table[a] = key_table[a] + accsign
535
536     return key_table
537
538 tup_lookup = {
539     '2' : '3/2',
540     '3' : '2/3',
541     '4' : '4/3',
542     '5' : '4/5',
543     '6' : '4/6',
544     '7' : '6/7',
545     '9' : '8/9',
546     }
547
548
549 def try_parse_tuplet_begin (str, state):
550     if re.match ('\([2-9]', str):
551         dig = str[1]
552         str = str[2:]
553         prev_tuplet_state = state.parsing_tuplet
554         state.parsing_tuplet = int (dig[0])
555         if prev_tuplet_state:
556             voices_append ("}")
557         voices_append ("\\times %s {" % tup_lookup[dig])
558     return str
559
560 def  try_parse_group_end (str, state):
561     if str and str[0] in HSPACE:
562         str = str[1:]
563         close_beam_state(state)
564     return str
565
566 def header_append (key, a):
567     s = ''
568     if header.has_key (key):
569         s = header[key] + "\n"
570         header [key] = s + a
571
572 def wordwrap(a, v):
573     linelen = len (v) - v.rfind ('\n')
574     if linelen + len (a) > 80:
575         v = v + '\n'
576     return v + a + ' '
577
578 def stuff_append (stuff, idx, a):
579     if not stuff:
580         stuff.append (a)
581     else:
582         stuff [idx] = wordwrap(a, stuff[idx])
583
584 # ignore wordwrap since we are adding to the previous word
585 def stuff_append_back(stuff, idx, a):
586     if not stuff:
587         stuff.append (a)
588     else:
589         point = len(stuff[idx])-1
590         while stuff[idx][point] is ' ':
591             point = point - 1
592         point = point +1
593         stuff[idx] = stuff[idx][:point] + a + stuff[idx][point:]
594
595 def voices_append(a):
596     if current_voice_idx < 0:
597         select_voice ('default', '')
598     stuff_append (voices, current_voice_idx, a)
599
600 # word wrap really makes it hard to bind beams to the end of notes since it
601 # pushes out whitespace on every call. The _back functions do an append
602 # prior to the last space, effectively tagging whatever they are given
603 # onto the last note
604 def voices_append_back(a):
605     if current_voice_idx < 0:
606         select_voice ('default', '')
607     stuff_append_back(voices, current_voice_idx, a)
608
609 def repeat_prepend():
610     global repeat_state
611     if current_voice_idx < 0:
612         select_voice ('default', '')
613     if not using_old:
614         repeat_state[current_voice_idx] = 't'
615
616
617 def lyrics_append(a):
618     a = re.sub ('#', '\\#', a)        # latex does not like naked #'s
619     a = re.sub ('"', '\\"', a)        # latex does not like naked "'s
620     a = '\t{  "' + a + '" }\n'
621     stuff_append (lyrics, current_lyric_idx, a)
622
623 # break lyrics to words and put "'s around words containing numbers and '"'s
624 def fix_lyric(str):
625     ret = ''
626     while str != '':
627         m = re.match('[ \t]*([^ \t]*)[ \t]*(.*$)', str)
628         if m:
629             word = m.group(1)
630             str = m.group(2)
631             word = re.sub('"', '\\"', word) # escape "
632             if re.match('.*[0-9"\(]', word):
633                 word = re.sub('_', ' ', word) # _ causes probs inside ""
634                 ret = ret + '\"' + word + '\" '
635             else:
636                 ret = ret + word + ' '
637         else:
638             return (ret)
639     return (ret)
640
641 def slyrics_append(a):
642     a = re.sub ( '_', ' _ ', a)        # _ to ' _ '
643     a = re.sub ( '([^-])-([^-])', '\\1- \\2', a)        # split words with "-" unless was originally "--"
644     a = re.sub ( '\\\\- ', '-', a)         # unless \-
645     a = re.sub ( '~', '_', a)        # ~ to space('_')
646     a = re.sub ( '\*', '_ ', a)        # * to to space
647     a = re.sub ( '#', '\\#', a)        # latex does not like naked #'s
648     if re.match('.*[0-9"\(]', a):        # put numbers and " and ( into quoted string
649         a = fix_lyric(a)
650     a = re.sub ( '$', ' ', a)        # insure space between lines
651     __main__.lyric_idx = lyric_idx + 1
652     if len(slyrics[current_voice_idx]) <= lyric_idx:
653         slyrics[current_voice_idx].append(a)
654     else:
655         v = slyrics[current_voice_idx][lyric_idx]
656         slyrics[current_voice_idx][lyric_idx] = wordwrap(a, slyrics[current_voice_idx][lyric_idx])
657
658
659 def try_parse_header_line (ln, state):
660     global length_specified
661     m = re.match ('^([A-Za-z]): *(.*)$', ln)
662
663     if m:
664         g =m.group (1)
665         a = m.group (2)
666         if g == 'T':        #title
667             a = re.sub('[ \t]*$','', a)        #strip trailing blanks
668             if header.has_key('title'):
669                 if a:
670                     if len(header['title']):
671                         # the non-ascii character
672                         # in the string below is a
673                         # punctuation dash. (TeX ---)
674                         header['title'] = header['title'] + ' â€” ' + a
675                     else:
676                         header['subtitle'] = a
677             else:
678                 header['title'] =  a
679         if g == 'M':        # Meter
680             if a == 'C':
681                 if not state.common_time:
682                     state.common_time = 1
683                     voices_append (" \\override Staff.TimeSignature #'style = #'C\n")
684                 a = '4/4'
685             if a == 'C|':
686                 if not state.common_time:
687                     state.common_time = 1
688                     voices_append ("\\override Staff.TimeSignature #'style = #'C\n")
689                 a = '2/2'
690             if not length_specified:
691                 set_default_len_from_time_sig (a)
692             else:
693                 length_specified = 0
694             if not a == 'none':
695                 voices_append ('\\time %s' % a)
696             state.next_bar = ''
697         if g == 'K': # KEY
698             a = check_clef(a)
699             if a:
700                 m = re.match ('^([^ \t]*) *([^ ]*)( *)(.*)$', a) # separate clef info
701                 if m:
702                     # there may or may not be a space
703                     # between the key letter and the mode
704                     # convert the mode to lower-case before comparing
705                     mode = m.group(2)[0:3].lower();
706                     if key_lookup.has_key(mode):
707                         # use the full mode, not only the first three letters
708                         key_info = m.group(1) + m.group(2).lower()
709                         clef_info = a[m.start(4):]
710                     else:
711                         key_info = m.group(1)
712                         clef_info = a[m.start(2):]
713                     __main__.global_key  = compute_key (key_info)
714                     k = lily_key (key_info)
715                     if k:
716                         voices_append ('\\key %s' % k)
717                     check_clef(clef_info)
718                 else:
719                     __main__.global_key  = compute_key (a)
720                     k = lily_key (a)
721                     if k:
722                         voices_append ('\\key %s \\major' % k)
723         if g == 'N': # Notes
724             header ['footnotes'] = header['footnotes'] +  '\\\\\\\\' + a
725         if g == 'O': # Origin
726             header ['origin'] = a
727         if g == 'X': # Reference Number
728             header ['crossRefNumber'] = a
729         if g == 'A': #        Area
730             header ['area'] = a
731         if g == 'H':        # History
732             header_append ('history', a)
733         if g == 'B':        # Book
734             header ['book'] = a
735         if g == 'C':        # Composer
736             if header.has_key('composer'):
737                 if a:
738                     header['composer'] = header['composer'] + '\\\\\\\\' + a
739             else:
740                 header['composer'] =  a
741         if g == 'S':
742             header ['subtitle'] = a
743         if g == 'L':        # Default note length
744             set_default_length (ln)
745         if g == 'V':        # Voice
746             voice = re.sub (' .*$', '', a)
747             rest = re.sub ('^[^ \t]*  *', '', a)
748             if state.next_bar:
749                 voices_append(state.next_bar)
750                 state.next_bar = ''
751             select_voice (voice, rest)
752         if g == 'W':        # Words
753             lyrics_append(a)
754         if g == 'w':        # vocals
755             slyrics_append (a)
756         if g == 'Q':    #tempo
757             try_parse_q (a)
758         return ''
759     return ln
760
761 # we use in this order specified accidental, active accidental for bar,
762 # active accidental for key
763 def pitch_to_lilypond_name (name, acc, bar_acc, key):
764     s = ''
765     if acc == UNDEF:
766         if not nobarlines:
767             acc = bar_acc
768     if acc == UNDEF:
769         acc = key
770     if acc == -1:
771         s = 'es'
772     elif acc == 1:
773         s =  'is'
774
775     if name > 4:
776         name = name -7
777     return(chr (name  + ord('c')) + s)
778
779
780 def octave_to_lilypond_quotes (o):
781     o = o + 2
782     s =''
783     if o < 0:
784         o = -o
785         s=','
786     else:
787         s ='\''
788
789     return s * o
790
791 def parse_num (str):
792     durstr = ''
793     while str and str[0] in DIGITS:
794         durstr = durstr + str[0]
795         str = str[1:]
796
797     n = None
798     if durstr:
799         n = int (durstr)
800     return (str,n)
801
802
803 def duration_to_lilypond_duration  (multiply_tup, defaultlen, dots):
804     base = 1
805     # (num /  den)  / defaultlen < 1/base
806     while base * multiply_tup[0] < multiply_tup[1]:
807         base = base * 2
808     if base == 1:
809         if (multiply_tup[0] / multiply_tup[1])  == 2:
810             base = '\\breve'
811         if (multiply_tup[0] / multiply_tup[1]) == 3:
812             base = '\\breve'
813             dots = 1
814         if (multiply_tup[0] / multiply_tup[1]) == 4:
815             base = '\\longa'
816     return '%s%s' % ( base, '.'* dots)
817
818 class Parser_state:
819     def __init__ (self):
820         self.in_acc = {}
821         self.next_articulation = ''
822         self.next_bar = ''
823         self.next_dots = 0
824         self.next_den = 1
825         self.parsing_tuplet = 0
826         self.plus_chord = 0
827         self.base_octave = 0
828         self.common_time = 0
829         self.parsing_beam = 0
830
831
832
833 # return (str, num,den,dots)
834 def parse_duration (str, parser_state):
835     num = 0
836     den = parser_state.next_den
837     parser_state.next_den = 1
838
839     (str, num) = parse_num (str)
840     if not num:
841         num = 1
842     if len(str):
843         if str[0] == '/':
844             if len(str[0]):
845                 while str[:1] == '/':
846                     str= str[1:]
847                     d = 2
848                     if str[0] in DIGITS:
849                         (str, d) =parse_num (str)
850
851                     den = den * d
852
853     den = den * default_len
854
855     current_dots = parser_state.next_dots
856     parser_state.next_dots = 0
857     if re.match ('[ \t]*[<>]', str):
858         while str[0] in HSPACE:
859             str = str[1:]
860         while str[0] == '>':
861             str = str [1:]
862             current_dots = current_dots + 1
863             parser_state.next_den = parser_state.next_den * 2
864
865         while str[0] == '<':
866             str = str [1:]
867             den = den * 2
868             parser_state.next_dots = parser_state.next_dots + 1
869
870
871
872     try_dots = [3, 2, 1]
873     for d in try_dots:
874         f = 1 << d
875         multiplier = (2*f-1)
876         if num % multiplier == 0 and den % f == 0:
877             num = num / multiplier
878             den = den / f
879             current_dots = current_dots + d
880
881     return (str, num,den,current_dots)
882
883
884 def try_parse_rest (str, parser_state):
885     if not str or str[0] <> 'z' and str[0] <> 'x':
886         return str
887
888     __main__.lyric_idx = -1
889
890     if parser_state.next_bar:
891         voices_append(parser_state.next_bar)
892         parser_state.next_bar = ''
893
894     if str[0] == 'z':
895         rest = 'r'
896     else:
897         rest = 's'
898     str = str[1:]
899
900     (str, num,den,d) = parse_duration (str, parser_state)
901     voices_append ('%s%s' % (rest, duration_to_lilypond_duration ((num,den), default_len, d)))
902     if parser_state.next_articulation:
903         voices_append (parser_state.next_articulation)
904         parser_state.next_articulation = ''
905
906     return str
907
908 artic_tbl = {
909     '.'  : '-.',
910     'T' : '^\\trill',
911     'H' : '^\\fermata',
912     'u' : '^\\upbow',
913     'K' : '^\\ltoe',
914     'k' : '^\\accent',
915     'M' : '^\\tenuto',
916     '~' : '^"~" ',
917     'J' : '',                # ignore slide
918     'R' : '',                # ignore roll
919     'S' : '^\\segno',
920     'O' : '^\\coda',
921     'v' : '^\\downbow'
922 }
923
924 def try_parse_articulation (str, state):
925     while str and  artic_tbl.has_key(str[:1]):
926         state.next_articulation = state.next_articulation + artic_tbl[str[:1]]
927         if not artic_tbl[str[:1]]:
928             sys.stderr.write("Warning: ignoring `%s'\n" % str[:1] )
929
930         str = str[1:]
931
932
933
934     # s7m2 input doesn't care about spaces
935     if re.match('[ \t]*\(', str):
936         str = str.lstrip ()
937
938     slur_begin =0
939     while str[:1] =='(' and str[1] not in DIGITS:
940         slur_begin = slur_begin + 1
941         state.next_articulation = state.next_articulation + '('
942         str = str[1:]
943
944     return str
945
946 #
947 # remember accidental for rest of bar
948 #
949 def set_bar_acc(note, octave, acc, state):
950     if acc == UNDEF:
951         return
952     n_oct = note + octave * 7
953     state.in_acc[n_oct] = acc
954
955 # get accidental set in this bar or UNDEF if not set
956 def get_bar_acc(note, octave, state):
957     n_oct = note + octave * 7
958     if state.in_acc.has_key(n_oct):
959         return(state.in_acc[n_oct])
960     else:
961         return(UNDEF)
962
963 def clear_bar_acc(state):
964     state.in_acc = {}
965
966
967 # if we are parsing a beam, close it off
968 def close_beam_state(state):
969     if state.parsing_beam and global_options.beams:
970         state.parsing_beam = 0
971         voices_append_back( ']' )
972
973
974 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP  !
975 def try_parse_note (str, parser_state):
976     mud = ''
977
978     slur_begin =0
979     if not str:
980         return str
981
982     articulation =''
983     acc = UNDEF
984     if str[0] in '^=_':
985         c = str[0]
986         str = str[1:]
987         if c == '^':
988             acc = 1
989         if c == '=':
990             acc = 0
991         if c == '_':
992             acc = -1
993
994     octave = parser_state.base_octave
995     if str[0] in "ABCDEFG":
996         str = str[0].lower () + str[1:]
997         octave = octave - 1
998
999
1000     notename = 0
1001     if str[0] in "abcdefg":
1002         notename = (ord(str[0]) - ord('a') + 5)%7
1003         str = str[1:]
1004     else:
1005         return str                # failed; not a note!
1006
1007
1008     __main__.lyric_idx = -1
1009
1010     if parser_state.next_bar:
1011         voices_append(parser_state.next_bar)
1012         parser_state.next_bar = ''
1013
1014     while str[0] == ',':
1015         octave = octave - 1
1016         str = str[1:]
1017     while str[0] == '\'':
1018         octave = octave + 1
1019         str = str[1:]
1020
1021     (str, num,den,current_dots) = parse_duration (str, parser_state)
1022
1023     if re.match('[ \t]*\)', str):
1024         str = str.lstrip ()
1025
1026     slur_end =0
1027     while str[:1] ==')':
1028         slur_end = slur_end + 1
1029         str = str[1:]
1030
1031
1032     bar_acc = get_bar_acc(notename, octave, parser_state)
1033     pit = pitch_to_lilypond_name(notename, acc, bar_acc, global_key[notename])
1034     oct = octave_to_lilypond_quotes (octave)
1035     if acc != UNDEF and (acc == global_key[notename] or acc == bar_acc):
1036         mod='!'
1037     else:
1038         mod = ''
1039     voices_append ("%s%s%s%s" %
1040         (pit, oct, mod,
1041          duration_to_lilypond_duration ((num,den), default_len, current_dots)))
1042
1043     set_bar_acc(notename, octave, acc, parser_state)
1044     if parser_state.next_articulation:
1045         articulation = articulation + parser_state.next_articulation
1046         parser_state.next_articulation = ''
1047
1048     voices_append (articulation)
1049
1050     if slur_begin:
1051         voices_append ('-(' * slur_begin )
1052     if slur_end:
1053         voices_append ('-)' *slur_end )
1054
1055     if parser_state.parsing_tuplet:
1056         parser_state.parsing_tuplet = parser_state.parsing_tuplet - 1
1057         if not parser_state.parsing_tuplet:
1058             voices_append ("}")
1059
1060     if global_options.beams and \
1061      str[0] in '^=_ABCDEFGabcdefg' and \
1062      not parser_state.parsing_beam and \
1063      not parser_state.parsing_tuplet:
1064         parser_state.parsing_beam = 1
1065         voices_append_back( '[' )
1066
1067     return str
1068
1069 def junk_space (str,state):
1070     while str and str[0] in '\t\n\r ':
1071         str = str[1:]
1072         close_beam_state(state)
1073
1074     return str
1075
1076
1077 def try_parse_guitar_chord (str, state):
1078     if str[:1] =='"':
1079         str = str[1:]
1080         gc = ''
1081         if str[0] == '_' or (str[0] == '^'):
1082             position = str[0]
1083             str = str[1:]
1084         else:
1085             position = '^'
1086         while str and str[0] != '"':
1087             gc = gc + str[0]
1088             str = str[1:]
1089
1090         if str:
1091             str = str[1:]
1092         gc = re.sub('#', '\\#', gc)        # escape '#'s
1093         state.next_articulation = ("%c\"%s\"" % (position, gc)) \
1094                      + state.next_articulation
1095     return str
1096
1097 def try_parse_escape (str):
1098     if not str or str [0] != '\\':
1099         return str
1100
1101     str = str[1:]
1102     if str[:1] =='K':
1103         key_table = compute_key ()
1104     return str
1105
1106 #
1107 # |] thin-thick double bar line
1108 # || thin-thin double bar line
1109 # [| thick-thin double bar line
1110 # :| left repeat
1111 # |: right repeat
1112 # :: left-right repeat
1113 # |1 volta 1
1114 # |2 volta 2
1115 old_bar_dict = {
1116 '|]' : '|.',
1117 '||' : '||',
1118 '[|' : '||',
1119 ':|' : ':|',
1120 '|:' : '|:',
1121 '::' : ':|:',
1122 '|1' : '|',
1123 '|2' : '|',
1124 ':|2' : ':|',
1125 '|' :  '|'
1126 }
1127 bar_dict = {
1128 '|]' : '\\bar "|."',
1129 '||' : '\\bar "||"',
1130 '[|' : '\\bar "||"',
1131 ':|' : '}',
1132 '|:' : '\\repeat volta 2 {',
1133 '::' : '} \\repeat volta 2 {',
1134 '|1' : '} \\alternative{{',
1135 '|2' : '} {',
1136 ':|2' : '} {',
1137 '|' :  '\\bar "|"'
1138  }
1139
1140
1141 warn_about = ['|:', '::', ':|', '|1', ':|2', '|2']
1142 alternative_opener = ['|1', '|2', ':|2']
1143 repeat_ender = ['::', ':|']
1144 repeat_opener = ['::', '|:']
1145 in_repeat = [''] * 8
1146 doing_alternative = [''] * 8
1147 using_old = ''
1148
1149 def try_parse_bar (str,state):
1150     global in_repeat, doing_alternative, using_old
1151     do_curly = ''
1152     bs = None
1153     if current_voice_idx < 0:
1154         select_voice ('default', '')
1155     # first try the longer one
1156     for trylen in [3,2,1]:
1157         if str[:trylen] and bar_dict.has_key (str[:trylen]):
1158             s = str[:trylen]
1159             if using_old:
1160                 bs = "\\bar \"%s\"" % old_bar_dict[s]
1161             else:
1162                 bs = "%s" % bar_dict[s]
1163             str = str[trylen:]
1164             if s in alternative_opener:
1165                 if not in_repeat[current_voice_idx]:
1166                     using_old = 't'
1167                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1168                 else:
1169                     doing_alternative[current_voice_idx] = 't'
1170
1171             if s in repeat_ender:
1172                 if not in_repeat[current_voice_idx]:
1173                     sys.stderr.write("Warning: inserting repeat to beginning of notes.\n")
1174                     repeat_prepend()
1175                     in_repeat[current_voice_idx] = ''
1176                 else:
1177                     if doing_alternative[current_voice_idx]:
1178                         do_curly = 't'
1179                 if using_old:
1180                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1181                 else:
1182                     bs =  bar_dict[s]
1183                 doing_alternative[current_voice_idx] = ''
1184                 in_repeat[current_voice_idx] = ''
1185             if s in repeat_opener:
1186                 in_repeat[current_voice_idx] = 't'
1187                 if using_old:
1188                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1189                 else:
1190                     bs =  bar_dict[s]
1191             break
1192     if str[:1] == '|':
1193         state.next_bar = '|\n'
1194         str = str[1:]
1195         clear_bar_acc(state)
1196         close_beam_state(state)
1197
1198     if bs <> None or state.next_bar != '':
1199         if state.parsing_tuplet:
1200             state.parsing_tuplet =0
1201             voices_append ('} ')
1202
1203     if bs <> None:
1204         clear_bar_acc(state)
1205         close_beam_state(state)
1206         voices_append (bs)
1207         if do_curly != '':
1208             voices_append("} ")
1209             do_curly = ''
1210     return str
1211
1212 def try_parse_tie (str):
1213     if str[:1] =='-':
1214         str = str[1:]
1215         voices_append (' ~ ')
1216     return str
1217
1218 def bracket_escape (str, state):
1219     m = re.match ( '^([^\]]*)] *(.*)$', str)
1220     if m:
1221         cmd = m.group (1)
1222         str = m.group (2)
1223         try_parse_header_line (cmd, state)
1224     return str
1225
1226 def try_parse_chord_delims (str, state):
1227     if str[:1] =='[':
1228         str = str[1:]
1229         if re.match('[A-Z]:', str):        # bracket escape
1230             return bracket_escape(str, state)
1231         if state.next_bar:
1232             voices_append(state.next_bar)
1233             state.next_bar = ''
1234         voices_append ('<<')
1235
1236     if str[:1] == '+':
1237         str = str[1:]
1238         if state.plus_chord:
1239             voices_append ('>>')
1240             state.plus_chord = 0
1241         else:
1242             if state.next_bar:
1243                 voices_append(state.next_bar)
1244                 state.next_bar = ''
1245             voices_append ('<<')
1246             state.plus_chord = 1
1247
1248     ch = ''
1249     if str[:1] ==']':
1250         str = str[1:]
1251         ch = '>>'
1252
1253     end = 0
1254     while str[:1] ==')':
1255         end = end + 1
1256         str = str[1:]
1257
1258
1259     voices_append ("\\spanrequest \\stop \"slur\"" * end)
1260     voices_append (ch)
1261     return str
1262
1263 def try_parse_grace_delims (str, state):
1264     if str[:1] =='{':
1265         if state.next_bar:
1266             voices_append(state.next_bar)
1267             state.next_bar = ''
1268         str = str[1:]
1269         voices_append ('\\grace { ')
1270
1271     if str[:1] =='}':
1272         str = str[1:]
1273         voices_append ('}')
1274
1275     return str
1276
1277 def try_parse_comment (str):
1278     global nobarlines
1279     if (str[0] == '%'):
1280         if str[0:5] == '%MIDI':
1281 #the nobarlines option is necessary for an abc to lilypond translator for
1282 #exactly the same reason abc2midi needs it: abc requires the user to enter
1283 #the note that will be printed, and MIDI and lilypond expect entry of the
1284 #pitch that will be played.
1285 #
1286 #In standard 19th century musical notation, the algorithm for translating
1287 #between printed note and pitch involves using the barlines to determine
1288 #the scope of the accidentals.
1289 #
1290 #Since ABC is frequently used for music in styles that do not use this
1291 #convention, such as most music written before 1700, or ethnic music in
1292 #non-western scales, it is necessary to be able to tell a translator that
1293 #the barlines should not affect its interpretation of the pitch.
1294             if 'nobarlines' in str:
1295                 nobarlines = 1
1296         elif str[0:3] == '%LY':
1297             p = str.find ('voices')
1298             if (p > -1):
1299                 voices_append(str[p+7:])
1300                 voices_append("\n")
1301             p = str.find ('slyrics')
1302             if (p > -1):
1303                 slyrics_append(str[p+8:])
1304
1305 #write other kinds of appending  if we ever need them.
1306     return str
1307
1308 lineno = 0
1309 happy_count = 100
1310 def parse_file (fn):
1311     f = open (fn)
1312     ls = f.readlines ()
1313     ls = map (lambda x: re.sub ("\r$", '', x), ls)
1314
1315     select_voice('default', '')
1316     global lineno
1317     lineno = 0
1318     if not global_options.quiet:
1319         sys.stderr.write ("Line ... ")
1320         sys.stderr.flush ()
1321     __main__.state = state_list[current_voice_idx]
1322
1323     for ln in ls:
1324         lineno = lineno + 1
1325
1326         if not (lineno % happy_count):
1327             sys.stderr.write ('[%d]'% lineno)
1328             sys.stderr.flush ()
1329         m = re.match  ('^([^%]*)%(.*)$',ln)  # add comments to current voice
1330         if m:
1331             if m.group(2):
1332                 try_parse_comment(m.group(2))
1333                 voices_append ('%% %s\n' % m.group(2))
1334             ln = m.group (1)
1335
1336         orig_ln = ln
1337
1338         ln = junk_space (ln, state)
1339         ln = try_parse_header_line (ln, state)
1340
1341         # Try nibbling characters off until the line doesn't change.
1342         prev_ln = ''
1343         while ln != prev_ln:
1344             prev_ln = ln
1345             ln = try_parse_chord_delims (ln, state)
1346             ln = try_parse_rest (ln, state)
1347             ln = try_parse_articulation (ln,state)
1348             ln = try_parse_note  (ln, state)
1349             ln = try_parse_bar (ln, state)
1350             ln = try_parse_tie (ln)
1351             ln = try_parse_escape (ln)
1352             ln = try_parse_guitar_chord (ln, state)
1353             ln = try_parse_tuplet_begin (ln, state)
1354             ln = try_parse_group_end (ln, state)
1355             ln = try_parse_grace_delims (ln, state)
1356             ln = junk_space (ln, state)
1357
1358         if ln:
1359             error ("%s: %d: Huh?  Don't understand\n" % (fn, lineno))
1360             left = orig_ln[0:-len (ln)]
1361             sys.stderr.write (left + '\n')
1362             sys.stderr.write (' ' *  len (left) + ln + '\n')
1363
1364
1365 def identify():
1366     if not global_options.quiet:
1367         sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
1368
1369 authors = """
1370 Written by Han-Wen Nienhuys <hanwen@xs4all.nl>, Laura Conrad
1371 <lconrad@laymusic.org>, Roy Rankin <Roy.Rankin@@alcatel.com.au>.
1372 """
1373
1374 def print_version ():
1375     print r"""abc2ly (GNU lilypond) %s""" % version
1376
1377 def get_option_parser ():
1378     p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'abc2ly',
1379                  description=_ ('''abc2ly converts ABC music files (see
1380 %s) to LilyPond input.
1381 ''') % 'http://abcnotation.com/abc2mtex/abc.txt',
1382                  add_help_option=False)
1383
1384     p.version = "abc2ly (LilyPond) @TOPLEVEL_VERSION@"
1385     p.add_option("--version",
1386                  action="version",
1387                  help=_ ("show version number and exit"))
1388     p.add_option("-h", "--help",
1389                  action="help",
1390                  help=_ ("show this help and exit"))
1391     p.add_option ("-o", "--output", metavar='FILE',
1392                   action="store",
1393                   help=_ ("write output to FILE"))
1394     p.add_option ("-s", "--strict",
1395                   action="store_true",
1396                   help=_ ("be strict about success"))
1397     p.add_option ('-b', '--beams',
1398                   action="store_true",
1399                   help=_ ("preserve ABC's notion of beams"))
1400     p.add_option ('-q', '--quiet',
1401                   action="store_true",
1402                   help=_ ("suppress progress messages"))
1403     p.add_option_group ('',
1404                         description=(
1405             _ ('Report bugs via %s')
1406             % 'http://post.gmane.org/post.php'
1407             '?group=gmane.comp.gnu.lilypond.bugs') + '\n')
1408     return p
1409
1410
1411 option_parser = get_option_parser ()
1412 (global_options, files) = option_parser.parse_args ()
1413
1414
1415 identify ()
1416
1417 header['tagline'] = 'Lily was here %s -- automatically converted from ABC' % version
1418 for f in files:
1419     if f == '-':
1420         f = ''
1421
1422     if not global_options.quiet:
1423         sys.stderr.write ('Parsing `%s\'...\n' % f)
1424     parse_file (f)
1425
1426     if not global_options.output:
1427         global_options.output = os.path.basename (os.path.splitext (f)[0]) + ".ly"
1428     if not global_options.quiet:
1429         sys.stderr.write ('lilypond output to: `%s\'...' % global_options.output)
1430     outf = open (global_options.output, 'w')
1431
1432 # don't substitute @VERSION@. We want this to reflect
1433 # the last version that was verified to work.
1434     outf.write ('\\version "2.7.40"\n')
1435
1436 #        dump_global (outf)
1437     dump_header (outf, header)
1438     dump_slyrics (outf)
1439     dump_voices (outf)
1440     dump_score (outf)
1441     dump_lyrics (outf)
1442     if not global_options.quiet:
1443         sys.stderr.write ('\n')