]> git.donarmstrong.com Git - lilypond.git/blob - scripts/abc2ly.py
Merge branch 'translation' into staging
[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     orig = "" + k
437     # UGR
438     k = k.lower ()
439     key = k[0]
440     #UGH
441     k = k[1:]
442     if k and k[0] == '#':
443         key = key + 'is'
444         k = k[1:]
445     elif k and k[0] == 'b':
446         key = key + 'es'
447         k = k[1:]
448     if not k:
449         return '%s \\major' % key
450
451     type = k[0:3]
452     if not key_lookup.has_key (type):
453         #ugh, use lilylib, say WARNING:FILE:LINE:
454         sys.stderr.write ("abc2ly:warning:")
455         sys.stderr.write ("ignoring unknown key: `%s'" % orig)
456         sys.stderr.write ('\n')
457         return 0
458     return ("%s \\%s" % ( key, key_lookup[type]))
459
460 def shift_key (note, acc, shift):
461     s = semitone_pitch((note, acc))
462     s = (s + shift + 12) % 12
463     if s <= 4:
464         n = s / 2
465         a = s % 2
466     else:
467         n = (s + 1) / 2
468         a = (s + 1) % 2
469     if a:
470         n = n + 1
471         a = -1
472     return (n,a)
473
474 key_shift = { # semitone shifts for key mode names
475     'm'   : 3,
476     'min' : 3,
477     'minor' : 3,
478     'maj' : 0,
479     'major' : 0,
480     'phr' : -4,
481     'phrygian' : -4,
482     'ion' : 0,
483     'ionian' : 0,
484     'loc' : 1,
485     'locrian' : 1,
486     'aeo' : 3,
487     'aeolian' : 3,
488     'mix' : 5,
489     'mixolydian' : 5,
490     'lyd' : -5,
491     'lydian' : -5,
492     'dor' :        -2,
493     'dorian' :        -2
494 }
495 def compute_key (k):
496     k = k.lower ()
497     intkey = (ord (k[0]) - ord('a') + 5) % 7
498     intkeyacc =0
499     k = k[1:]
500
501     if k and k[0] == 'b':
502         intkeyacc = -1
503         k = k[1:]
504     elif  k and k[0] == '#':
505         intkeyacc = 1
506         k = k[1:]
507     k = k[0:3]
508     if k and key_shift.has_key(k):
509         (intkey, intkeyacc) = shift_key(intkey, intkeyacc, key_shift[k])
510     keytup = (intkey, intkeyacc)
511
512     sharp_key_seq = sharp_keys ()
513     flat_key_seq = flat_keys ()
514
515     accseq = None
516     accsign = 0
517     if keytup in sharp_key_seq:
518         accsign = 1
519         key_count = sharp_key_seq.index (keytup)
520         accseq = map (lambda x: (4*x -1 ) % 7, range (1, key_count + 1))
521
522     elif keytup in flat_key_seq:
523         accsign = -1
524         key_count = flat_key_seq.index (keytup)
525         accseq = map (lambda x: (3*x + 3 ) % 7, range (1, key_count + 1))
526     else:
527         error ("Huh?")
528         raise Exception ("Huh")
529
530     key_table = [0] * 7
531     for a in accseq:
532         key_table[a] = key_table[a] + accsign
533
534     return key_table
535
536 tup_lookup = {
537     '2' : '3/2',
538     '3' : '2/3',
539     '4' : '4/3',
540     '5' : '4/5',
541     '6' : '4/6',
542     '7' : '6/7',
543     '9' : '8/9',
544     }
545
546
547 def try_parse_tuplet_begin (str, state):
548     if re.match ('\([2-9]', str):
549         dig = str[1]
550         str = str[2:]
551         prev_tuplet_state = state.parsing_tuplet
552         state.parsing_tuplet = int (dig[0])
553         if prev_tuplet_state:
554             voices_append ("}")
555         voices_append ("\\times %s {" % tup_lookup[dig])
556     return str
557
558 def  try_parse_group_end (str, state):
559     if str and str[0] in HSPACE:
560         str = str[1:]
561         close_beam_state(state)
562     return str
563
564 def header_append (key, a):
565     s = ''
566     if header.has_key (key):
567         s = header[key] + "\n"
568         header [key] = s + a
569
570 def wordwrap(a, v):
571     linelen = len (v) - v.rfind ('\n')
572     if linelen + len (a) > 80:
573         v = v + '\n'
574     return v + a + ' '
575
576 def stuff_append (stuff, idx, a):
577     if not stuff:
578         stuff.append (a)
579     else:
580         stuff [idx] = wordwrap(a, stuff[idx])
581
582 # ignore wordwrap since we are adding to the previous word
583 def stuff_append_back(stuff, idx, a):
584     if not stuff:
585         stuff.append (a)
586     else:
587         point = len(stuff[idx])-1
588         while stuff[idx][point] is ' ':
589             point = point - 1
590         point = point +1
591         stuff[idx] = stuff[idx][:point] + a + stuff[idx][point:]
592
593 def voices_append(a):
594     if current_voice_idx < 0:
595         select_voice ('default', '')
596     stuff_append (voices, current_voice_idx, a)
597
598 # word wrap really makes it hard to bind beams to the end of notes since it
599 # pushes out whitespace on every call. The _back functions do an append
600 # prior to the last space, effectively tagging whatever they are given
601 # onto the last note
602 def voices_append_back(a):
603     if current_voice_idx < 0:
604         select_voice ('default', '')
605     stuff_append_back(voices, current_voice_idx, a)
606
607 def repeat_prepend():
608     global repeat_state
609     if current_voice_idx < 0:
610         select_voice ('default', '')
611     if not using_old:
612         repeat_state[current_voice_idx] = 't'
613
614
615 def lyrics_append(a):
616     a = re.sub ('#', '\\#', a)        # latex does not like naked #'s
617     a = re.sub ('"', '\\"', a)        # latex does not like naked "'s
618     a = '\t{  "' + a + '" }\n'
619     stuff_append (lyrics, current_lyric_idx, a)
620
621 # break lyrics to words and put "'s around words containing numbers and '"'s
622 def fix_lyric(str):
623     ret = ''
624     while str != '':
625         m = re.match('[ \t]*([^ \t]*)[ \t]*(.*$)', str)
626         if m:
627             word = m.group(1)
628             str = m.group(2)
629             word = re.sub('"', '\\"', word) # escape "
630             if re.match('.*[0-9"\(]', word):
631                 word = re.sub('_', ' ', word) # _ causes probs inside ""
632                 ret = ret + '\"' + word + '\" '
633             else:
634                 ret = ret + word + ' '
635         else:
636             return (ret)
637     return (ret)
638
639 def slyrics_append(a):
640     a = re.sub ( '_', ' _ ', a)        # _ to ' _ '
641     a = re.sub ( '([^-])-([^-])', '\\1- \\2', a)        # split words with "-" unless was originally "--"
642     a = re.sub ( '\\\\- ', '-', a)         # unless \-
643     a = re.sub ( '~', '_', a)        # ~ to space('_')
644     a = re.sub ( '\*', '_ ', a)        # * to to space
645     a = re.sub ( '#', '\\#', a)        # latex does not like naked #'s
646     if re.match('.*[0-9"\(]', a):        # put numbers and " and ( into quoted string
647         a = fix_lyric(a)
648     a = re.sub ( '$', ' ', a)        # insure space between lines
649     __main__.lyric_idx = lyric_idx + 1
650     if len(slyrics[current_voice_idx]) <= lyric_idx:
651         slyrics[current_voice_idx].append(a)
652     else:
653         v = slyrics[current_voice_idx][lyric_idx]
654         slyrics[current_voice_idx][lyric_idx] = wordwrap(a, slyrics[current_voice_idx][lyric_idx])
655
656
657 def try_parse_header_line (ln, state):
658     global length_specified
659     m = re.match ('^([A-Za-z]): *(.*)$', ln)
660
661     if m:
662         g =m.group (1)
663         a = m.group (2)
664         if g == 'T':        #title
665             a = re.sub('[ \t]*$','', a)        #strip trailing blanks
666             if header.has_key('title'):
667                 if a:
668                     if len(header['title']):
669                         # the non-ascii character
670                         # in the string below is a
671                         # punctuation dash. (TeX ---)
672                         header['title'] = header['title'] + ' â€” ' + a
673                     else:
674                         header['subtitle'] = a
675             else:
676                 header['title'] =  a
677         if g == 'M':        # Meter
678             if a == 'C':
679                 if not state.common_time:
680                     state.common_time = 1
681                     voices_append (" \\override Staff.TimeSignature #'style = #'C\n")
682                 a = '4/4'
683             if a == 'C|':
684                 if not state.common_time:
685                     state.common_time = 1
686                     voices_append ("\\override Staff.TimeSignature #'style = #'C\n")
687                 a = '2/2'
688             if not length_specified:
689                 set_default_len_from_time_sig (a)
690             else:
691                 length_specified = 0
692             if not a == 'none':
693                 voices_append ('\\time %s' % a)
694             state.next_bar = ''
695         if g == 'K': # KEY
696             a = check_clef(a)
697             if a:
698                 m = re.match ('^([^ \t]*) *([^ ]*)( *)(.*)$', a) # separate clef info
699                 if m:
700                     # there may or may not be a space
701                     # between the key letter and the mode
702                     # convert the mode to lower-case before comparing
703                     mode = m.group(2)[0:3].lower();
704                     if key_lookup.has_key(mode):
705                         # use the full mode, not only the first three letters
706                         key_info = m.group(1) + m.group(2).lower()
707                         clef_info = a[m.start(4):]
708                     else:
709                         key_info = m.group(1)
710                         clef_info = a[m.start(2):]
711                     __main__.global_key  = compute_key (key_info)
712                     k = lily_key (key_info)
713                     if k:
714                         voices_append ('\\key %s' % k)
715                     check_clef(clef_info)
716                 else:
717                     __main__.global_key  = compute_key (a)
718                     k = lily_key (a)
719                     if k:
720                         voices_append ('\\key %s \\major' % k)
721         if g == 'N': # Notes
722             header ['footnotes'] = header['footnotes'] +  '\\\\\\\\' + a
723         if g == 'O': # Origin
724             header ['origin'] = a
725         if g == 'X': # Reference Number
726             header ['crossRefNumber'] = a
727         if g == 'A': #        Area
728             header ['area'] = a
729         if g == 'H':        # History
730             header_append ('history', a)
731         if g == 'B':        # Book
732             header ['book'] = a
733         if g == 'C':        # Composer
734             if header.has_key('composer'):
735                 if a:
736                     header['composer'] = header['composer'] + '\\\\\\\\' + a
737             else:
738                 header['composer'] =  a
739         if g == 'S':
740             header ['subtitle'] = a
741         if g == 'L':        # Default note length
742             set_default_length (ln)
743         if g == 'V':        # Voice
744             voice = re.sub (' .*$', '', a)
745             rest = re.sub ('^[^ \t]*  *', '', a)
746             if state.next_bar:
747                 voices_append(state.next_bar)
748                 state.next_bar = ''
749             select_voice (voice, rest)
750         if g == 'W':        # Words
751             lyrics_append(a)
752         if g == 'w':        # vocals
753             slyrics_append (a)
754         if g == 'Q':    #tempo
755             try_parse_q (a)
756         return ''
757     return ln
758
759 # we use in this order specified accidental, active accidental for bar,
760 # active accidental for key
761 def pitch_to_lilypond_name (name, acc, bar_acc, key):
762     s = ''
763     if acc == UNDEF:
764         if not nobarlines:
765             acc = bar_acc
766     if acc == UNDEF:
767         acc = key
768     if acc == -1:
769         s = 'es'
770     elif acc == 1:
771         s =  'is'
772
773     if name > 4:
774         name = name -7
775     return(chr (name  + ord('c')) + s)
776
777
778 def octave_to_lilypond_quotes (o):
779     o = o + 2
780     s =''
781     if o < 0:
782         o = -o
783         s=','
784     else:
785         s ='\''
786
787     return s * o
788
789 def parse_num (str):
790     durstr = ''
791     while str and str[0] in DIGITS:
792         durstr = durstr + str[0]
793         str = str[1:]
794
795     n = None
796     if durstr:
797         n = int (durstr)
798     return (str,n)
799
800
801 def duration_to_lilypond_duration  (multiply_tup, defaultlen, dots):
802     base = 1
803     # (num /  den)  / defaultlen < 1/base
804     while base * multiply_tup[0] < multiply_tup[1]:
805         base = base * 2
806     if base == 1:
807         if (multiply_tup[0] / multiply_tup[1])  == 2:
808             base = '\\breve'
809         if (multiply_tup[0] / multiply_tup[1]) == 3:
810             base = '\\breve'
811             dots = 1
812         if (multiply_tup[0] / multiply_tup[1]) == 4:
813             base = '\\longa'
814     return '%s%s' % ( base, '.'* dots)
815
816 class Parser_state:
817     def __init__ (self):
818         self.in_acc = {}
819         self.next_articulation = ''
820         self.next_bar = ''
821         self.next_dots = 0
822         self.next_den = 1
823         self.parsing_tuplet = 0
824         self.plus_chord = 0
825         self.base_octave = 0
826         self.common_time = 0
827         self.parsing_beam = 0
828
829
830
831 # return (str, num,den,dots)
832 def parse_duration (str, parser_state):
833     num = 0
834     den = parser_state.next_den
835     parser_state.next_den = 1
836
837     (str, num) = parse_num (str)
838     if not num:
839         num = 1
840     if len(str):
841         if str[0] == '/':
842             if len(str[0]):
843                 while str[:1] == '/':
844                     str= str[1:]
845                     d = 2
846                     if str[0] in DIGITS:
847                         (str, d) =parse_num (str)
848
849                     den = den * d
850
851     den = den * default_len
852
853     current_dots = parser_state.next_dots
854     parser_state.next_dots = 0
855     if re.match ('[ \t]*[<>]', str):
856         while str[0] in HSPACE:
857             str = str[1:]
858         while str[0] == '>':
859             str = str [1:]
860             current_dots = current_dots + 1
861             parser_state.next_den = parser_state.next_den * 2
862
863         while str[0] == '<':
864             str = str [1:]
865             den = den * 2
866             parser_state.next_dots = parser_state.next_dots + 1
867
868
869
870     try_dots = [3, 2, 1]
871     for d in try_dots:
872         f = 1 << d
873         multiplier = (2*f-1)
874         if num % multiplier == 0 and den % f == 0:
875             num = num / multiplier
876             den = den / f
877             current_dots = current_dots + d
878
879     return (str, num,den,current_dots)
880
881
882 def try_parse_rest (str, parser_state):
883     if not str or str[0] <> 'z' and str[0] <> 'x':
884         return str
885
886     __main__.lyric_idx = -1
887
888     if parser_state.next_bar:
889         voices_append(parser_state.next_bar)
890         parser_state.next_bar = ''
891
892     if str[0] == 'z':
893         rest = 'r'
894     else:
895         rest = 's'
896     str = str[1:]
897
898     (str, num,den,d) = parse_duration (str, parser_state)
899     voices_append ('%s%s' % (rest, duration_to_lilypond_duration ((num,den), default_len, d)))
900     if parser_state.next_articulation:
901         voices_append (parser_state.next_articulation)
902         parser_state.next_articulation = ''
903
904     return str
905
906 artic_tbl = {
907     '.'  : '-.',
908     'T' : '^\\trill',
909     'H' : '^\\fermata',
910     'u' : '^\\upbow',
911     'K' : '^\\ltoe',
912     'k' : '^\\accent',
913     'M' : '^\\tenuto',
914     '~' : '^"~" ',
915     'J' : '',                # ignore slide
916     'R' : '',                # ignore roll
917     'S' : '^\\segno',
918     'O' : '^\\coda',
919     'v' : '^\\downbow'
920 }
921
922 def try_parse_articulation (str, state):
923     while str and  artic_tbl.has_key(str[:1]):
924         state.next_articulation = state.next_articulation + artic_tbl[str[:1]]
925         if not artic_tbl[str[:1]]:
926             sys.stderr.write("Warning: ignoring `%s'\n" % str[:1] )
927
928         str = str[1:]
929
930
931
932     # s7m2 input doesn't care about spaces
933     if re.match('[ \t]*\(', str):
934         str = str.lstrip ()
935
936     slur_begin =0
937     while str[:1] =='(' and str[1] not in DIGITS:
938         slur_begin = slur_begin + 1
939         state.next_articulation = state.next_articulation + '('
940         str = str[1:]
941
942     return str
943
944 #
945 # remember accidental for rest of bar
946 #
947 def set_bar_acc(note, octave, acc, state):
948     if acc == UNDEF:
949         return
950     n_oct = note + octave * 7
951     state.in_acc[n_oct] = acc
952
953 # get accidental set in this bar or UNDEF if not set
954 def get_bar_acc(note, octave, state):
955     n_oct = note + octave * 7
956     if state.in_acc.has_key(n_oct):
957         return(state.in_acc[n_oct])
958     else:
959         return(UNDEF)
960
961 def clear_bar_acc(state):
962     state.in_acc = {}
963
964
965 # if we are parsing a beam, close it off
966 def close_beam_state(state):
967     if state.parsing_beam and global_options.beams:
968         state.parsing_beam = 0
969         voices_append_back( ']' )
970
971
972 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP  !
973 def try_parse_note (str, parser_state):
974     mud = ''
975
976     slur_begin =0
977     if not str:
978         return str
979
980     articulation =''
981     acc = UNDEF
982     if str[0] in '^=_':
983         c = str[0]
984         str = str[1:]
985         if c == '^':
986             acc = 1
987         if c == '=':
988             acc = 0
989         if c == '_':
990             acc = -1
991
992     octave = parser_state.base_octave
993     if str[0] in "ABCDEFG":
994         str = str[0].lower () + str[1:]
995         octave = octave - 1
996
997
998     notename = 0
999     if str[0] in "abcdefg":
1000         notename = (ord(str[0]) - ord('a') + 5)%7
1001         str = str[1:]
1002     else:
1003         return str                # failed; not a note!
1004
1005
1006     __main__.lyric_idx = -1
1007
1008     if parser_state.next_bar:
1009         voices_append(parser_state.next_bar)
1010         parser_state.next_bar = ''
1011
1012     while str[0] == ',':
1013         octave = octave - 1
1014         str = str[1:]
1015     while str[0] == '\'':
1016         octave = octave + 1
1017         str = str[1:]
1018
1019     (str, num,den,current_dots) = parse_duration (str, parser_state)
1020
1021     if re.match('[ \t]*\)', str):
1022         str = str.lstrip ()
1023
1024     slur_end =0
1025     while str[:1] ==')':
1026         slur_end = slur_end + 1
1027         str = str[1:]
1028
1029
1030     bar_acc = get_bar_acc(notename, octave, parser_state)
1031     pit = pitch_to_lilypond_name(notename, acc, bar_acc, global_key[notename])
1032     oct = octave_to_lilypond_quotes (octave)
1033     if acc != UNDEF and (acc == global_key[notename] or acc == bar_acc):
1034         mod='!'
1035     else:
1036         mod = ''
1037     voices_append ("%s%s%s%s" %
1038         (pit, oct, mod,
1039          duration_to_lilypond_duration ((num,den), default_len, current_dots)))
1040
1041     set_bar_acc(notename, octave, acc, parser_state)
1042     if parser_state.next_articulation:
1043         articulation = articulation + parser_state.next_articulation
1044         parser_state.next_articulation = ''
1045
1046     voices_append (articulation)
1047
1048     if slur_begin:
1049         voices_append ('-(' * slur_begin )
1050     if slur_end:
1051         voices_append ('-)' *slur_end )
1052
1053     if parser_state.parsing_tuplet:
1054         parser_state.parsing_tuplet = parser_state.parsing_tuplet - 1
1055         if not parser_state.parsing_tuplet:
1056             voices_append ("}")
1057
1058     if global_options.beams and \
1059      str[0] in '^=_ABCDEFGabcdefg' and \
1060      not parser_state.parsing_beam and \
1061      not parser_state.parsing_tuplet:
1062         parser_state.parsing_beam = 1
1063         voices_append_back( '[' )
1064
1065     return str
1066
1067 def junk_space (str,state):
1068     while str and str[0] in '\t\n\r ':
1069         str = str[1:]
1070         close_beam_state(state)
1071
1072     return str
1073
1074
1075 def try_parse_guitar_chord (str, state):
1076     if str[:1] =='"':
1077         str = str[1:]
1078         gc = ''
1079         if str[0] == '_' or (str[0] == '^'):
1080             position = str[0]
1081             str = str[1:]
1082         else:
1083             position = '^'
1084         while str and str[0] != '"':
1085             gc = gc + str[0]
1086             str = str[1:]
1087
1088         if str:
1089             str = str[1:]
1090         gc = re.sub('#', '\\#', gc)        # escape '#'s
1091         state.next_articulation = ("%c\"%s\"" % (position, gc)) \
1092                      + state.next_articulation
1093     return str
1094
1095 def try_parse_escape (str):
1096     if not str or str [0] != '\\':
1097         return str
1098
1099     str = str[1:]
1100     if str[:1] =='K':
1101         key_table = compute_key ()
1102     return str
1103
1104 #
1105 # |] thin-thick double bar line
1106 # || thin-thin double bar line
1107 # [| thick-thin double bar line
1108 # :| left repeat
1109 # |: right repeat
1110 # :: left-right repeat
1111 # |1 volta 1
1112 # |2 volta 2
1113 old_bar_dict = {
1114 '|]' : '|.',
1115 '||' : '||',
1116 '[|' : '||',
1117 ':|' : ':|',
1118 '|:' : '|:',
1119 '::' : ':|:',
1120 '|1' : '|',
1121 '|2' : '|',
1122 ':|2' : ':|',
1123 '|' :  '|'
1124 }
1125 bar_dict = {
1126 '|]' : '\\bar "|."',
1127 '||' : '\\bar "||"',
1128 '[|' : '\\bar "||"',
1129 ':|' : '}',
1130 '|:' : '\\repeat volta 2 {',
1131 '::' : '} \\repeat volta 2 {',
1132 '|1' : '} \\alternative{{',
1133 '|2' : '} {',
1134 ':|2' : '} {',
1135 '|' :  '\\bar "|"'
1136  }
1137
1138
1139 warn_about = ['|:', '::', ':|', '|1', ':|2', '|2']
1140 alternative_opener = ['|1', '|2', ':|2']
1141 repeat_ender = ['::', ':|']
1142 repeat_opener = ['::', '|:']
1143 in_repeat = [''] * 8
1144 doing_alternative = [''] * 8
1145 using_old = ''
1146
1147 def try_parse_bar (str,state):
1148     global in_repeat, doing_alternative, using_old
1149     do_curly = ''
1150     bs = None
1151     if current_voice_idx < 0:
1152         select_voice ('default', '')
1153     # first try the longer one
1154     for trylen in [3,2,1]:
1155         if str[:trylen] and bar_dict.has_key (str[:trylen]):
1156             s = str[:trylen]
1157             if using_old:
1158                 bs = "\\bar \"%s\"" % old_bar_dict[s]
1159             else:
1160                 bs = "%s" % bar_dict[s]
1161             str = str[trylen:]
1162             if s in alternative_opener:
1163                 if not in_repeat[current_voice_idx]:
1164                     using_old = 't'
1165                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1166                 else:
1167                     doing_alternative[current_voice_idx] = 't'
1168
1169             if s in repeat_ender:
1170                 if not in_repeat[current_voice_idx]:
1171                     sys.stderr.write("Warning: inserting repeat to beginning of notes.\n")
1172                     repeat_prepend()
1173                     in_repeat[current_voice_idx] = ''
1174                 else:
1175                     if doing_alternative[current_voice_idx]:
1176                         do_curly = 't'
1177                 if using_old:
1178                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1179                 else:
1180                     bs =  bar_dict[s]
1181                 doing_alternative[current_voice_idx] = ''
1182                 in_repeat[current_voice_idx] = ''
1183             if s in repeat_opener:
1184                 in_repeat[current_voice_idx] = 't'
1185                 if using_old:
1186                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1187                 else:
1188                     bs =  bar_dict[s]
1189             break
1190     if str[:1] == '|':
1191         state.next_bar = '|\n'
1192         str = str[1:]
1193         clear_bar_acc(state)
1194         close_beam_state(state)
1195
1196     if bs <> None or state.next_bar != '':
1197         if state.parsing_tuplet:
1198             state.parsing_tuplet =0
1199             voices_append ('} ')
1200
1201     if bs <> None:
1202         clear_bar_acc(state)
1203         close_beam_state(state)
1204         voices_append (bs)
1205         if do_curly != '':
1206             voices_append("} ")
1207             do_curly = ''
1208     return str
1209
1210 def try_parse_tie (str):
1211     if str[:1] =='-':
1212         str = str[1:]
1213         voices_append (' ~ ')
1214     return str
1215
1216 def bracket_escape (str, state):
1217     m = re.match ( '^([^\]]*)] *(.*)$', str)
1218     if m:
1219         cmd = m.group (1)
1220         str = m.group (2)
1221         try_parse_header_line (cmd, state)
1222     return str
1223
1224 def try_parse_chord_delims (str, state):
1225     if str[:1] =='[':
1226         str = str[1:]
1227         if re.match('[A-Z]:', str):        # bracket escape
1228             return bracket_escape(str, state)
1229         if state.next_bar:
1230             voices_append(state.next_bar)
1231             state.next_bar = ''
1232         voices_append ('<<')
1233
1234     if str[:1] == '+':
1235         str = str[1:]
1236         if state.plus_chord:
1237             voices_append ('>>')
1238             state.plus_chord = 0
1239         else:
1240             if state.next_bar:
1241                 voices_append(state.next_bar)
1242                 state.next_bar = ''
1243             voices_append ('<<')
1244             state.plus_chord = 1
1245
1246     ch = ''
1247     if str[:1] ==']':
1248         str = str[1:]
1249         ch = '>>'
1250
1251     end = 0
1252     while str[:1] ==')':
1253         end = end + 1
1254         str = str[1:]
1255
1256
1257     voices_append ("\\spanrequest \\stop \"slur\"" * end)
1258     voices_append (ch)
1259     return str
1260
1261 def try_parse_grace_delims (str, state):
1262     if str[:1] =='{':
1263         if state.next_bar:
1264             voices_append(state.next_bar)
1265             state.next_bar = ''
1266         str = str[1:]
1267         voices_append ('\\grace { ')
1268
1269     if str[:1] =='}':
1270         str = str[1:]
1271         voices_append ('}')
1272
1273     return str
1274
1275 def try_parse_comment (str):
1276     global nobarlines
1277     if (str[0] == '%'):
1278         if str[0:5] == '%MIDI':
1279 #the nobarlines option is necessary for an abc to lilypond translator for
1280 #exactly the same reason abc2midi needs it: abc requires the user to enter
1281 #the note that will be printed, and MIDI and lilypond expect entry of the
1282 #pitch that will be played.
1283 #
1284 #In standard 19th century musical notation, the algorithm for translating
1285 #between printed note and pitch involves using the barlines to determine
1286 #the scope of the accidentals.
1287 #
1288 #Since ABC is frequently used for music in styles that do not use this
1289 #convention, such as most music written before 1700, or ethnic music in
1290 #non-western scales, it is necessary to be able to tell a translator that
1291 #the barlines should not affect its interpretation of the pitch.
1292             if 'nobarlines' in str:
1293                 nobarlines = 1
1294         elif str[0:3] == '%LY':
1295             p = str.find ('voices')
1296             if (p > -1):
1297                 voices_append(str[p+7:])
1298                 voices_append("\n")
1299             p = str.find ('slyrics')
1300             if (p > -1):
1301                 slyrics_append(str[p+8:])
1302
1303 #write other kinds of appending  if we ever need them.
1304     return str
1305
1306 lineno = 0
1307 happy_count = 100
1308 def parse_file (fn):
1309     f = open (fn)
1310     ls = f.readlines ()
1311     ls = map (lambda x: re.sub ("\r$", '', x), ls)
1312
1313     select_voice('default', '')
1314     global lineno
1315     lineno = 0
1316     if not global_options.quiet:
1317         sys.stderr.write ("Line ... ")
1318         sys.stderr.flush ()
1319     __main__.state = state_list[current_voice_idx]
1320
1321     for ln in ls:
1322         lineno = lineno + 1
1323
1324         if not (lineno % happy_count):
1325             sys.stderr.write ('[%d]'% lineno)
1326             sys.stderr.flush ()
1327         m = re.match  ('^([^%]*)%(.*)$',ln)  # add comments to current voice
1328         if m:
1329             if m.group(2):
1330                 try_parse_comment(m.group(2))
1331                 voices_append ('%% %s\n' % m.group(2))
1332             ln = m.group (1)
1333
1334         orig_ln = ln
1335
1336         ln = junk_space (ln, state)
1337         ln = try_parse_header_line (ln, state)
1338
1339         # Try nibbling characters off until the line doesn't change.
1340         prev_ln = ''
1341         while ln != prev_ln:
1342             prev_ln = ln
1343             ln = try_parse_chord_delims (ln, state)
1344             ln = try_parse_rest (ln, state)
1345             ln = try_parse_articulation (ln,state)
1346             ln = try_parse_note  (ln, state)
1347             ln = try_parse_bar (ln, state)
1348             ln = try_parse_tie (ln)
1349             ln = try_parse_escape (ln)
1350             ln = try_parse_guitar_chord (ln, state)
1351             ln = try_parse_tuplet_begin (ln, state)
1352             ln = try_parse_group_end (ln, state)
1353             ln = try_parse_grace_delims (ln, state)
1354             ln = junk_space (ln, state)
1355
1356         if ln:
1357             error ("%s: %d: Huh?  Don't understand\n" % (fn, lineno))
1358             left = orig_ln[0:-len (ln)]
1359             sys.stderr.write (left + '\n')
1360             sys.stderr.write (' ' *  len (left) + ln + '\n')
1361
1362
1363 def identify():
1364     if not global_options.quiet:
1365         sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
1366
1367 authors = """
1368 Written by Han-Wen Nienhuys <hanwen@xs4all.nl>, Laura Conrad
1369 <lconrad@laymusic.org>, Roy Rankin <Roy.Rankin@@alcatel.com.au>.
1370 """
1371
1372 def print_version ():
1373     print r"""abc2ly (GNU lilypond) %s""" % version
1374
1375 def get_option_parser ():
1376     p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'abc2ly',
1377                  description=_ ('''abc2ly converts ABC music files (see
1378 %s) to LilyPond input.
1379 ''') % 'http://abcnotation.com/abc2mtex/abc.txt',
1380                  add_help_option=False)
1381
1382     p.version = "abc2ly (LilyPond) @TOPLEVEL_VERSION@"
1383     p.add_option("--version",
1384                  action="version",
1385                  help=_ ("show version number and exit"))
1386     p.add_option("-h", "--help",
1387                  action="help",
1388                  help=_ ("show this help and exit"))
1389     p.add_option ("-o", "--output", metavar='FILE',
1390                   action="store",
1391                   help=_ ("write output to FILE"))
1392     p.add_option ("-s", "--strict",
1393                   action="store_true",
1394                   help=_ ("be strict about success"))
1395     p.add_option ('-b', '--beams',
1396                   action="store_true",
1397                   help=_ ("preserve ABC's notion of beams"))
1398     p.add_option ('-q', '--quiet',
1399                   action="store_true",
1400                   help=_ ("suppress progress messages"))
1401     p.add_option_group ('',
1402                         description=(
1403             _ ('Report bugs via %s')
1404             % 'http://post.gmane.org/post.php'
1405             '?group=gmane.comp.gnu.lilypond.bugs') + '\n')
1406     return p
1407
1408
1409 option_parser = get_option_parser ()
1410 (global_options, files) = option_parser.parse_args ()
1411
1412
1413 identify ()
1414
1415 header['tagline'] = 'Lily was here %s -- automatically converted from ABC' % version
1416 for f in files:
1417     if f == '-':
1418         f = ''
1419
1420     if not global_options.quiet:
1421         sys.stderr.write ('Parsing `%s\'...\n' % f)
1422     parse_file (f)
1423
1424     if not global_options.output:
1425         global_options.output = os.path.basename (os.path.splitext (f)[0]) + ".ly"
1426     if not global_options.quiet:
1427         sys.stderr.write ('lilypond output to: `%s\'...' % global_options.output)
1428     outf = open (global_options.output, 'w')
1429
1430 # don't substitute @VERSION@. We want this to reflect
1431 # the last version that was verified to work.
1432     outf.write ('\\version "2.7.40"\n')
1433
1434 #        dump_global (outf)
1435     dump_header (outf, header)
1436     dump_slyrics (outf)
1437     dump_voices (outf)
1438     dump_score (outf)
1439     dump_lyrics (outf)
1440     if not global_options.quiet:
1441         sys.stderr.write ('\n')