]> git.donarmstrong.com Git - lilypond.git/blob - scripts/abc2ly.py
Add '-dcrop' option to ps and svg backends
[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         if g == 'R':        # Rhythm (e.g. jig, reel, hornpipe)
767             header['meter'] = a
768         if g == 'Z':        # Transcription (e.g. Steve Mansfield 1/2/2000)
769             header['transcription'] = a
770         return ''
771     return ln
772
773 # we use in this order specified accidental, active accidental for bar,
774 # active accidental for key
775 def pitch_to_lilypond_name (name, acc, bar_acc, key):
776     s = ''
777     if acc == UNDEF:
778         if not nobarlines:
779             acc = bar_acc
780     if acc == UNDEF:
781         acc = key
782     if acc == -1:
783         s = 'es'
784     elif acc == 1:
785         s =  'is'
786
787     if name > 4:
788         name = name -7
789     return(chr (name  + ord('c')) + s)
790
791
792 def octave_to_lilypond_quotes (o):
793     o = o + 2
794     s =''
795     if o < 0:
796         o = -o
797         s=','
798     else:
799         s ='\''
800
801     return s * o
802
803 def parse_num (str):
804     durstr = ''
805     while str and str[0] in DIGITS:
806         durstr = durstr + str[0]
807         str = str[1:]
808
809     n = None
810     if durstr:
811         n = int (durstr)
812     return (str,n)
813
814
815 def duration_to_lilypond_duration  (multiply_tup, defaultlen, dots):
816     base = 1
817     # (num /  den)  / defaultlen < 1/base
818     while base * multiply_tup[0] < multiply_tup[1]:
819         base = base * 2
820     if base == 1:
821         if (multiply_tup[0] / multiply_tup[1])  == 2:
822             base = '\\breve'
823         if (multiply_tup[0] / multiply_tup[1]) == 3:
824             base = '\\breve'
825             dots = 1
826         if (multiply_tup[0] / multiply_tup[1]) == 4:
827             base = '\\longa'
828     return '%s%s' % ( base, '.'* dots)
829
830 class Parser_state:
831     def __init__ (self):
832         self.in_acc = {}
833         self.next_articulation = ''
834         self.next_bar = ''
835         self.next_dots = 0
836         self.next_den = 1
837         self.parsing_tuplet = 0
838         self.plus_chord = 0
839         self.base_octave = 0
840         self.common_time = 0
841         self.parsing_beam = 0
842
843
844
845 # return (str, num,den,dots)
846 def parse_duration (str, parser_state):
847     num = 0
848     den = parser_state.next_den
849     parser_state.next_den = 1
850
851     (str, num) = parse_num (str)
852     if not num:
853         num = 1
854     if len(str):
855         if str[0] == '/':
856             if len(str[0]):
857                 while str[:1] == '/':
858                     str= str[1:]
859                     d = 2
860                     if str[0] in DIGITS:
861                         (str, d) =parse_num (str)
862
863                     den = den * d
864
865     den = den * default_len
866
867     current_dots = parser_state.next_dots
868     parser_state.next_dots = 0
869     if re.match ('[ \t]*[<>]', str):
870         while str[0] in HSPACE:
871             str = str[1:]
872         while str[0] == '>':
873             str = str [1:]
874             current_dots = current_dots + 1
875             parser_state.next_den = parser_state.next_den * 2
876
877         while str[0] == '<':
878             str = str [1:]
879             den = den * 2
880             parser_state.next_dots = parser_state.next_dots + 1
881
882
883
884     try_dots = [3, 2, 1]
885     for d in try_dots:
886         f = 1 << d
887         multiplier = (2*f-1)
888         if num % multiplier == 0 and den % f == 0:
889             num = num / multiplier
890             den = den / f
891             current_dots = current_dots + d
892
893     return (str, num,den,current_dots)
894
895
896 def try_parse_rest (str, parser_state):
897     if not str or str[0] <> 'z' and str[0] <> 'x':
898         return str
899
900     __main__.lyric_idx = -1
901
902     if parser_state.next_bar:
903         voices_append(parser_state.next_bar)
904         parser_state.next_bar = ''
905
906     if str[0] == 'z':
907         rest = 'r'
908     else:
909         rest = 's'
910     str = str[1:]
911
912     (str, num,den,d) = parse_duration (str, parser_state)
913     voices_append ('%s%s' % (rest, duration_to_lilypond_duration ((num,den), default_len, d)))
914     if parser_state.next_articulation:
915         voices_append (parser_state.next_articulation)
916         parser_state.next_articulation = ''
917
918     return str
919
920 artic_tbl = {
921     '.'  : '-.',
922     'T' : '^\\trill',
923     'H' : '^\\fermata',
924     'u' : '^\\upbow',
925     'K' : '^\\ltoe',
926     'k' : '^\\accent',
927     'M' : '^\\tenuto',
928     '~' : '^"~" ',
929     'J' : '',                # ignore slide
930     'R' : '',                # ignore roll
931     'S' : '^\\segno',
932     'O' : '^\\coda',
933     'v' : '^\\downbow'
934 }
935
936 def try_parse_articulation (str, state):
937     while str and  artic_tbl.has_key(str[:1]):
938         state.next_articulation = state.next_articulation + artic_tbl[str[:1]]
939         if not artic_tbl[str[:1]]:
940             sys.stderr.write("Warning: ignoring `%s'\n" % str[:1] )
941
942         str = str[1:]
943
944
945
946     # s7m2 input doesn't care about spaces
947     if re.match('[ \t]*\(', str):
948         str = str.lstrip ()
949
950     slur_begin =0
951     while str[:1] =='(' and str[1] not in DIGITS:
952         slur_begin = slur_begin + 1
953         state.next_articulation = state.next_articulation + '('
954         str = str[1:]
955
956     return str
957
958 #
959 # remember accidental for rest of bar
960 #
961 def set_bar_acc(note, octave, acc, state):
962     if acc == UNDEF:
963         return
964     n_oct = note + octave * 7
965     state.in_acc[n_oct] = acc
966
967 # get accidental set in this bar or UNDEF if not set
968 def get_bar_acc(note, octave, state):
969     n_oct = note + octave * 7
970     if state.in_acc.has_key(n_oct):
971         return(state.in_acc[n_oct])
972     else:
973         return(UNDEF)
974
975 def clear_bar_acc(state):
976     state.in_acc = {}
977
978
979 # if we are parsing a beam, close it off
980 def close_beam_state(state):
981     if state.parsing_beam and global_options.beams:
982         state.parsing_beam = 0
983         voices_append_back( ']' )
984
985
986 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP  !
987 def try_parse_note (str, parser_state):
988     mud = ''
989
990     slur_begin =0
991     if not str:
992         return str
993
994     articulation =''
995     acc = UNDEF
996     if str[0] in '^=_':
997         c = str[0]
998         str = str[1:]
999         if c == '^':
1000             acc = 1
1001         if c == '=':
1002             acc = 0
1003         if c == '_':
1004             acc = -1
1005
1006     octave = parser_state.base_octave
1007     if str[0] in "ABCDEFG":
1008         str = str[0].lower () + str[1:]
1009         octave = octave - 1
1010
1011
1012     notename = 0
1013     if str[0] in "abcdefg":
1014         notename = (ord(str[0]) - ord('a') + 5)%7
1015         str = str[1:]
1016     else:
1017         return str                # failed; not a note!
1018
1019
1020     __main__.lyric_idx = -1
1021
1022     if parser_state.next_bar:
1023         voices_append(parser_state.next_bar)
1024         parser_state.next_bar = ''
1025
1026     while str[0] == ',':
1027         octave = octave - 1
1028         str = str[1:]
1029     while str[0] == '\'':
1030         octave = octave + 1
1031         str = str[1:]
1032
1033     (str, num,den,current_dots) = parse_duration (str, parser_state)
1034
1035     if re.match('[ \t]*\)', str):
1036         str = str.lstrip ()
1037
1038     slur_end =0
1039     while str[:1] ==')':
1040         slur_end = slur_end + 1
1041         str = str[1:]
1042
1043
1044     bar_acc = get_bar_acc(notename, octave, parser_state)
1045     pit = pitch_to_lilypond_name(notename, acc, bar_acc, global_key[notename])
1046     oct = octave_to_lilypond_quotes (octave)
1047     if acc != UNDEF and (acc == global_key[notename] or acc == bar_acc):
1048         mod='!'
1049     else:
1050         mod = ''
1051     voices_append ("%s%s%s%s" %
1052         (pit, oct, mod,
1053          duration_to_lilypond_duration ((num,den), default_len, current_dots)))
1054
1055     set_bar_acc(notename, octave, acc, parser_state)
1056     if parser_state.next_articulation:
1057         articulation = articulation + parser_state.next_articulation
1058         parser_state.next_articulation = ''
1059
1060     voices_append (articulation)
1061
1062     if slur_begin:
1063         voices_append ('-(' * slur_begin )
1064     if slur_end:
1065         voices_append ('-)' *slur_end )
1066
1067     if parser_state.parsing_tuplet:
1068         parser_state.parsing_tuplet = parser_state.parsing_tuplet - 1
1069         if not parser_state.parsing_tuplet:
1070             voices_append ("}")
1071
1072     if global_options.beams and \
1073      str[0] in '^=_ABCDEFGabcdefg' and \
1074      not parser_state.parsing_beam and \
1075      not parser_state.parsing_tuplet:
1076         parser_state.parsing_beam = 1
1077         voices_append_back( '[' )
1078
1079     return str
1080
1081 def junk_space (str,state):
1082     while str and str[0] in '\t\n\r ':
1083         str = str[1:]
1084         close_beam_state(state)
1085
1086     return str
1087
1088
1089 def try_parse_guitar_chord (str, state):
1090     if str[:1] =='"':
1091         str = str[1:]
1092         gc = ''
1093         if str[0] == '_' or (str[0] == '^'):
1094             position = str[0]
1095             str = str[1:]
1096         else:
1097             position = '^'
1098         while str and str[0] != '"':
1099             gc = gc + str[0]
1100             str = str[1:]
1101
1102         if str:
1103             str = str[1:]
1104         gc = re.sub('#', '\\#', gc)        # escape '#'s
1105         state.next_articulation = ("%c\"%s\"" % (position, gc)) \
1106                      + state.next_articulation
1107     return str
1108
1109 def try_parse_escape (str):
1110     if not str or str [0] != '\\':
1111         return str
1112
1113     str = str[1:]
1114     if str[:1] =='K':
1115         key_table = compute_key ()
1116     return str
1117
1118 #
1119 # |] thin-thick double bar line
1120 # || thin-thin double bar line
1121 # [| thick-thin double bar line
1122 # :| left repeat
1123 # |: right repeat
1124 # :: left-right repeat
1125 # |1 volta 1
1126 # |2 volta 2
1127 old_bar_dict = {
1128 '|]' : '|.',
1129 '||' : '||',
1130 '[|' : '||',
1131 ':|' : ':|.',
1132 '|:' : '|:',
1133 '::' : ':|.|:',
1134 '|1' : '|',
1135 '|2' : '|',
1136 ':|2' : ':|.',
1137 '|' :  '|'
1138 }
1139 bar_dict = {
1140 '|]' : '\\bar "|."',
1141 '||' : '\\bar "||"',
1142 '[|' : '\\bar "||"',
1143 ':|' : '}',
1144 '|:' : '\\repeat volta 2 {',
1145 '::' : '} \\repeat volta 2 {',
1146 '|1' : '} \\alternative{{',
1147 '|2' : '} {',
1148 ':|2' : '} {',
1149 '|' :  '\\bar "|"'
1150  }
1151
1152
1153 warn_about = ['|:', '::', ':|', '|1', ':|2', '|2']
1154 alternative_opener = ['|1', '|2', ':|2']
1155 repeat_ender = ['::', ':|']
1156 repeat_opener = ['::', '|:']
1157 in_repeat = [''] * 8
1158 doing_alternative = [''] * 8
1159 using_old = ''
1160
1161 def try_parse_bar (str,state):
1162     global in_repeat, doing_alternative, using_old
1163     do_curly = ''
1164     bs = None
1165     if current_voice_idx < 0:
1166         select_voice ('default', '')
1167     # first try the longer one
1168     for trylen in [3,2,1]:
1169         if str[:trylen] and bar_dict.has_key (str[:trylen]):
1170             s = str[:trylen]
1171             if using_old:
1172                 bs = "\\bar \"%s\"" % old_bar_dict[s]
1173             else:
1174                 bs = "%s" % bar_dict[s]
1175             str = str[trylen:]
1176             if s in alternative_opener:
1177                 if not in_repeat[current_voice_idx]:
1178                     using_old = 't'
1179                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1180                 else:
1181                     doing_alternative[current_voice_idx] = 't'
1182
1183             if s in repeat_ender:
1184                 if not in_repeat[current_voice_idx]:
1185                     sys.stderr.write("Warning: inserting repeat to beginning of notes.\n")
1186                     repeat_prepend()
1187                     in_repeat[current_voice_idx] = ''
1188                 else:
1189                     if doing_alternative[current_voice_idx]:
1190                         do_curly = 't'
1191                 if using_old:
1192                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1193                 else:
1194                     bs =  bar_dict[s]
1195                 doing_alternative[current_voice_idx] = ''
1196                 in_repeat[current_voice_idx] = ''
1197             if s in repeat_opener:
1198                 in_repeat[current_voice_idx] = 't'
1199                 if using_old:
1200                     bs = "\\bar \"%s\"" % old_bar_dict[s]
1201                 else:
1202                     bs =  bar_dict[s]
1203             break
1204     if str[:1] == '|':
1205         state.next_bar = '|\n'
1206         str = str[1:]
1207         clear_bar_acc(state)
1208         close_beam_state(state)
1209
1210     if str[:1] == '}':
1211         close_beam_state(state)
1212
1213     if bs <> None or state.next_bar != '':
1214         if state.parsing_tuplet:
1215             state.parsing_tuplet =0
1216             voices_append ('} ')
1217
1218     if bs <> None:
1219         clear_bar_acc(state)
1220         close_beam_state(state)
1221         voices_append (bs)
1222         if do_curly != '':
1223             voices_append("} ")
1224             do_curly = ''
1225     return str
1226
1227 def try_parse_tie (str):
1228     if str[:1] =='-':
1229         str = str[1:]
1230         voices_append (' ~ ')
1231     return str
1232
1233 def bracket_escape (str, state):
1234     m = re.match ( '^([^\]]*)] *(.*)$', str)
1235     if m:
1236         cmd = m.group (1)
1237         str = m.group (2)
1238         try_parse_header_line (cmd, state)
1239     return str
1240
1241 def try_parse_chord_delims (str, state):
1242     if str[:1] =='[':
1243         str = str[1:]
1244         if re.match('[A-Z]:', str):        # bracket escape
1245             return bracket_escape(str, state)
1246         if state.next_bar:
1247             voices_append(state.next_bar)
1248             state.next_bar = ''
1249         voices_append ('<<')
1250
1251     if str[:1] == '+':
1252         str = str[1:]
1253         if state.plus_chord:
1254             voices_append ('>>')
1255             state.plus_chord = 0
1256         else:
1257             if state.next_bar:
1258                 voices_append(state.next_bar)
1259                 state.next_bar = ''
1260             voices_append ('<<')
1261             state.plus_chord = 1
1262
1263     ch = ''
1264     if str[:1] ==']':
1265         str = str[1:]
1266         ch = '>>'
1267
1268     end = 0
1269     while str[:1] ==')':
1270         end = end + 1
1271         str = str[1:]
1272
1273
1274     voices_append ("\\spanrequest \\stop \"slur\"" * end)
1275     voices_append (ch)
1276     return str
1277
1278 def try_parse_grace_delims (str, state):
1279     if str[:1] =='{':
1280         if state.next_bar:
1281             voices_append(state.next_bar)
1282             state.next_bar = ''
1283         str = str[1:]
1284         voices_append ('\\grace { ')
1285
1286     if str[:1] =='}':
1287         str = str[1:]
1288         voices_append ('}')
1289
1290     return str
1291
1292 def try_parse_comment (str):
1293     global nobarlines
1294     if (str[0] == '%'):
1295         if str[0:5] == '%MIDI':
1296 #the nobarlines option is necessary for an abc to lilypond translator for
1297 #exactly the same reason abc2midi needs it: abc requires the user to enter
1298 #the note that will be printed, and MIDI and lilypond expect entry of the
1299 #pitch that will be played.
1300 #
1301 #In standard 19th century musical notation, the algorithm for translating
1302 #between printed note and pitch involves using the barlines to determine
1303 #the scope of the accidentals.
1304 #
1305 #Since ABC is frequently used for music in styles that do not use this
1306 #convention, such as most music written before 1700, or ethnic music in
1307 #non-western scales, it is necessary to be able to tell a translator that
1308 #the barlines should not affect its interpretation of the pitch.
1309             if 'nobarlines' in str:
1310                 nobarlines = 1
1311         elif str[0:3] == '%LY':
1312             p = str.find ('voices')
1313             if (p > -1):
1314                 voices_append(str[p+7:])
1315                 voices_append("\n")
1316             p = str.find ('slyrics')
1317             if (p > -1):
1318                 slyrics_append(str[p+8:])
1319
1320 #write other kinds of appending  if we ever need them.
1321     return str
1322
1323 lineno = 0
1324 happy_count = 100
1325 def parse_file (fn):
1326     f = open (fn)
1327     ls = f.readlines ()
1328     ls = map (lambda x: re.sub ("\r$", '', x), ls)
1329
1330     select_voice('default', '')
1331     global lineno
1332     lineno = 0
1333     if not global_options.quiet:
1334         sys.stderr.write ("Line ... ")
1335         sys.stderr.flush ()
1336     __main__.state = state_list[current_voice_idx]
1337
1338     for ln in ls:
1339         lineno = lineno + 1
1340
1341         if not (lineno % happy_count):
1342             sys.stderr.write ('[%d]'% lineno)
1343             sys.stderr.flush ()
1344         m = re.match  ('^([^%]*)%(.*)$',ln)  # add comments to current voice
1345         if m:
1346             if m.group(2):
1347                 try_parse_comment(m.group(2))
1348                 voices_append ('%% %s\n' % m.group(2))
1349             ln = m.group (1)
1350
1351         orig_ln = ln
1352
1353         ln = junk_space (ln, state)
1354         ln = try_parse_header_line (ln, state)
1355
1356         # Try nibbling characters off until the line doesn't change.
1357         prev_ln = ''
1358         while ln != prev_ln:
1359             prev_ln = ln
1360             ln = try_parse_chord_delims (ln, state)
1361             ln = try_parse_rest (ln, state)
1362             ln = try_parse_articulation (ln,state)
1363             ln = try_parse_note  (ln, state)
1364             ln = try_parse_bar (ln, state)
1365             ln = try_parse_tie (ln)
1366             ln = try_parse_escape (ln)
1367             ln = try_parse_guitar_chord (ln, state)
1368             ln = try_parse_tuplet_begin (ln, state)
1369             ln = try_parse_group_end (ln, state)
1370             ln = try_parse_grace_delims (ln, state)
1371             ln = junk_space (ln, state)
1372
1373         if ln:
1374             error ("%s: %d: Huh?  Don't understand\n" % (fn, lineno))
1375             left = orig_ln[0:-len (ln)]
1376             sys.stderr.write (left + '\n')
1377             sys.stderr.write (' ' *  len (left) + ln + '\n')
1378
1379
1380 def identify():
1381     if not global_options.quiet:
1382         sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
1383
1384 authors = """
1385 Written by Han-Wen Nienhuys <hanwen@xs4all.nl>, Laura Conrad
1386 <lconrad@laymusic.org>, Roy Rankin <Roy.Rankin@@alcatel.com.au>.
1387 """
1388
1389 def print_version ():
1390     print r"""abc2ly (GNU lilypond) %s""" % version
1391
1392 def get_option_parser ():
1393     p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'abc2ly',
1394                  description=_ ('''abc2ly converts ABC music files (see
1395 %s) to LilyPond input.
1396 ''') % 'http://abcnotation.com/abc2mtex/abc.txt',
1397                  add_help_option=False)
1398
1399     p.version = "abc2ly (LilyPond) @TOPLEVEL_VERSION@"
1400     p.add_option("--version",
1401                  action="version",
1402                  help=_ ("show version number and exit"))
1403     p.add_option("-h", "--help",
1404                  action="help",
1405                  help=_ ("show this help and exit"))
1406     p.add_option ("-o", "--output", metavar='FILE',
1407                   action="store",
1408                   help=_ ("write output to FILE"))
1409     p.add_option ("-s", "--strict",
1410                   action="store_true",
1411                   help=_ ("be strict about success"))
1412     p.add_option ('-b', '--beams',
1413                   action="store_true",
1414                   help=_ ("preserve ABC's notion of beams"))
1415     p.add_option ('-q', '--quiet',
1416                   action="store_true",
1417                   help=_ ("suppress progress messages"))
1418     p.add_option_group ('',
1419                         description=(
1420             _ ('Report bugs via %s')
1421             % 'http://post.gmane.org/post.php'
1422             '?group=gmane.comp.gnu.lilypond.bugs') + '\n')
1423     return p
1424
1425
1426 option_parser = get_option_parser ()
1427 (global_options, files) = option_parser.parse_args ()
1428
1429
1430 identify ()
1431
1432 header['tagline'] = 'Lily was here %s -- automatically converted from ABC' % version
1433 for f in files:
1434     if f == '-':
1435         f = ''
1436
1437     if not global_options.quiet:
1438         sys.stderr.write ('Parsing `%s\'...\n' % f)
1439     parse_file (f)
1440
1441     if not global_options.output:
1442         global_options.output = os.path.basename (os.path.splitext (f)[0]) + ".ly"
1443     if not global_options.quiet:
1444         sys.stderr.write ('lilypond output to: `%s\'...' % global_options.output)
1445     outf = open (global_options.output, 'w')
1446
1447 # don't substitute @VERSION@. We want this to reflect
1448 # the last version that was verified to work.
1449     outf.write ('\\version "2.7.40"\n')
1450
1451 #        dump_global (outf)
1452     dump_header (outf, header)
1453     dump_slyrics (outf)
1454     dump_voices (outf)
1455     dump_score (outf)
1456     dump_lyrics (outf)
1457     if not global_options.quiet:
1458         sys.stderr.write ('\n')