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