]> git.donarmstrong.com Git - lilypond.git/commitdiff
ABC beams preserve support (courtesy Guy
authorJan Nieuwenhuizen <janneke@gnu.org>
Mon, 19 Apr 2004 18:15:27 +0000 (18:15 +0000)
committerJan Nieuwenhuizen <janneke@gnu.org>
Mon, 19 Apr 2004 18:15:27 +0000 (18:15 +0000)
Gascoigne-Piggford).  Also: TAB and whitespace fixes.

ChangeLog
THANKS
input/GNUmakefile
input/template/jazz-combo.ly
lily/relative-octave-music.cc
scripts/abc2ly.py

index c1221d5802ebcfd4d944af71e435814d2f045250..734a6fb249cf39e4aaaf30e03d247ed686978334 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2004-04-19  Jan Nieuwenhuizen  <janneke@gnu.org>
 
+       * scripts/abc2ly.py: ABC beams preserve support (courtesy Guy
+       Gascoigne-Piggford).  Also: TAB and whitespace fixes.
+
        * lily/lexer.ll: Allow \encoding in NOTES mode.
 
        * buildscripts/mf-to-table.py (write_fontlist): Use \lyrics
diff --git a/THANKS b/THANKS
index 3332625295de25d3ae8153e6ee705b92ec77a9f2..8d60bd459276e07dfd1ee1b55da59ee9ee718991 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -13,6 +13,7 @@ CONTRIBUTORS
 Michael Welsh Duggan
 Pedro Kroger
 Erik Sandberg
+Guy Gascoigne-Piggford
 
 BUG HUNTERS/SUGGESTIONS
 
index f928659815b36f278060c5156585aad1e4ef268d..60b44ff8b73a950d4df0260602fd480f28d62af7 100644 (file)
@@ -1,8 +1,8 @@
 depth = ..
 
-SUBDIRS=test regression tutorial no-notation template mutopia 
+SUBDIRS = test regression tutorial no-notation template mutopia 
 
-examples= les-nereides puer-fragment wilhelmus
+examples = simple simple-song les-nereides puer-fragment wilhelmus paddy
 
 LOCALSTEPMAKE_TEMPLATES=ly mutopia
 EXTRA_DIST_FILES=paddy.abc
index 836562f1e5c40b6b5240ae1ec3c37d050059f66b..7d0d9eb6c7689391ca445efea18caa75836fc3a7 100644 (file)
@@ -45,7 +45,7 @@ trpt = \notes \transpose c d \relative c'' {
     c1 c c
 }
 
-trpharmony = \chords \transpose c' d { \jzchords }
+trpharmony = \transpose c' d { \jzchords }
 trumpet = {
     \global 
     \set Staff.instrument = #"Trumpet"
@@ -56,12 +56,12 @@ trumpet = {
 }
 
 % ------ Alto Saxophone ------
-alto = \notes \transpose c a \relative c' {
+alto = \transpose c a \relative c' {
        \Key
         c1 c c
 }
 
-altoharmony = \chords \transpose c' a { \jzchords }
+altoharmony = \transpose c' a { \jzchords }
 altosax = {
         \global
         \set Staff.instrument = #"Alto Sax"
@@ -72,12 +72,12 @@ altosax = {
 }
 
 % ------ Baritone Saxophone ------
-bari = \notes \transpose c a' \relative c {
+bari = \transpose c a' \relative c {
        \Key
         c1 c \sl d4^"Solo" d d d \nsl
 }
 
-bariharmony = \chords \transpose c' a { \jzchords s1 s d2:maj e:m7 }
+bariharmony = \transpose c' a \chords { \jzchords s1 s d2:maj e:m7 }
 barisax = {
         \global
         \set Staff.instrument = #"Bari Sax"
@@ -249,4 +249,3 @@ drumContents = {
         }
         \midi { \tempo 4 = 75 }
 }
-
index ad9f617e2969491320002c955a855ab305499f24..f6f20454d60fdef40449b5350dbf0a558e0e7d62 100644 (file)
@@ -17,16 +17,16 @@ Relative_octave_music::to_relative_octave (Pitch p)
   if (lily_1_8_relative)
     {
       lily_1_8_compatibility_used = true;
-      /*
-       ugh: last-pitch should  be junked.
+      /* ugh: last-pitch should  be junked.
 
-       Change this for lilypond 2.0. When you do,
-       then B should start where A left off.
+         Change this for lilypond 2.0.
 
-       \relative { A \relative { ...} B }
+        FIXME: change WHAT?  We're at 2.3 already -- jcn
 
-      */
-      return * unsmob_pitch (get_property ("last-pitch"));
+        When you do, B should start where A left off.
+
+       \relative { A \relative { ...} B }  */
+      return *unsmob_pitch (get_property ("last-pitch"));
     }
   else
     return p;
index 881935f44307e2665342038a05eb8858c2d03f80..943cc94b3b821e64192db3c27a9fb34395f961c4 100644 (file)
 # \breve and \longa supported.
 # M:none doesn't crash lily.
 
+# Enhancements (Guy Gascoigne-Piggford)
+#
+# Add support for maintaining ABC's notion of beaming, this is selectable
+# from the command line with a -b or --beam option.
+# Fixd a problem where on cygwin empty lines weren't being correctly identifed
+# and so were complaining, but still generating the correct output.
+
 # Limitations
 #
 # Multiple tunes in single file not supported
@@ -76,6 +83,7 @@ import os
 UNDEF = 255
 state = UNDEF
 strict = 0
+preserve_beams = 0
 voice_idx_dict = {}
 header = {}
 header['footnotes'] = ''
@@ -106,65 +114,61 @@ def error (msg):
        
        
 def check_clef(s):
-      if not s:
-              return ''
-      if re.match('-8va', s) or re.match('treble8', s):
-             # treble8 is used by abctab2ps; -8va is used by barfly,
-             # and by my patch to abc2ps. If there's ever a standard
-             # about this we'll support that.
-             s = s[4:]
-             state.base_octave = -1
-             voices_append("\\clef \"G_8\"\n")
-      elif re.match('^treble', s):
-              s = s[6:]
-              if re.match ('^-8', s):
-                      s = s[2:]
-                      state.base_octave = -2
-                      voices_append("\\clef \"G_8\"\n")
-              else:
-                      state.base_octave = 0
-                      voices_append("\\clef treble\n")
-      elif re.match('^alto', s):
-              s = s[4:]
-              state.base_octave = -1
-              voices_append ("\\clef alto\n" )
-      elif re.match('^bass',s ):
-              s = s[4:]
-              state.base_octave = -2
-              voices_append ("\\clef bass\n" )
-      return s
+       if not s:
+               return ''
+       if re.match('-8va', s) or re.match('treble8', s):
+               # treble8 is used by abctab2ps; -8va is used by barfly,
+               # and by my patch to abc2ps. If there's ever a standard
+               # about this we'll support that.
+               s = s[4:]
+               state.base_octave = -1
+               voices_append("\\clef \"G_8\"\n")
+       elif re.match('^treble', s):
+               s = s[6:]
+               if re.match ('^-8', s):
+                       s = s[2:]
+                       state.base_octave = -2
+                       voices_append("\\clef \"G_8\"\n")
+               else:
+                       state.base_octave = 0
+                       voices_append("\\clef treble\n")
+       elif re.match('^alto', s):
+               s = s[4:]
+               state.base_octave = -1
+               voices_append ("\\clef alto\n" )
+       elif re.match('^bass',s ):
+               s = s[4:]
+               state.base_octave = -2
+               voices_append ("\\clef bass\n" )
+               return s
 
 def select_voice (name, rol):
        if not voice_idx_dict.has_key (name):
-             state_list.append(Parser_state())
-             voices.append ('')
-             slyrics.append ([])
-             voice_idx_dict[name] = len (voices) -1
+               state_list.append(Parser_state())
+               voices.append ('')
+               slyrics.append ([])
+               voice_idx_dict[name] = len (voices) -1
        __main__.current_voice_idx =  voice_idx_dict[name]
        __main__.state = state_list[current_voice_idx]
        while rol != '':
-             m = re.match ('^([^ \t=]*)=(.*)$', rol) # find keywork
-             if m:
-                     keyword = m.group(1)
-                     rol = m.group (2)
-                     a = re.match ('^("[^"]*"|[^ \t]*) *(.*)$', rol)
-                     if a:
-                             value = a.group (1)
-                             rol = a.group ( 2)
-                             if keyword == 'clef':
-                                     check_clef(value)
-                             elif keyword == "name":
-                                     value = re.sub ('\\\\','\\\\\\\\', value)
-                                     voices_append ("\\set Staff.instrument = %s\n" % value )
-                                     __main__.part_names = 1
-                             elif keyword == "sname" or keyword == "snm":
-                                     voices_append ("\\set Staff.instr = %s\n" % value )
-
-             else:
-                     break
-
-       return
-
+               m = re.match ('^([^ \t=]*)=(.*)$', rol) # find keywork
+               if m:
+                       keyword = m.group(1)
+                       rol = m.group (2)
+                       a = re.match ('^("[^"]*"|[^ \t]*) *(.*)$', rol)
+                       if a:
+                               value = a.group (1)
+                               rol = a.group ( 2)
+                               if keyword == 'clef':
+                                       check_clef(value)
+                               elif keyword == "name":
+                                       value = re.sub ('\\\\','\\\\\\\\', value)
+                                       voices_append ("\\property Staff.instrument = %s\n" % value )
+                                       __main__.part_names = 1
+                               elif keyword == "sname" or keyword == "snm":
+                                       voices_append ("\\property Staff.instr = %s\n" % value )
+               else:
+                       break
 
 def dump_header (outf,hdr):
        outf.write ('\\header {\n')
@@ -187,7 +191,7 @@ def dump_default_bar (outf):
        """
        Nowadays abc2ly outputs explicits barlines (?)
        """
-       outf.write ("\n\\set Score.defaultBarType=\"empty\"\n")
+       outf.write ("\n\\property Score.defaultBarType=\"empty\"\n")
 
 
 def dump_slyrics (outf):
@@ -247,7 +251,7 @@ def dump_score (outf):
         \notes <<
 """)
 
-       ks  = voice_idx_dict.keys ();
+       ks = voice_idx_dict.keys ();
        ks.sort ()
        for k in  ks:
                if re.match('[1-9]', k):
@@ -416,19 +420,19 @@ def lily_key (k):
                return 0
        return ("%s \\%s" % ( key, key_lookup[type]))
 
-def shift_key (note, acc , shift):
-        s = semitone_pitch((note, acc))
-        s = (s + shift + 12) % 12
-        if s <= 4:
-                n = s / 2
-                a = s % 2
-        else:
-                n = (s + 1) / 2
-                a = (s + 1) % 2
-        if a:
-                n = n + 1
-                a = -1
-        return (n,a)
+def shift_key (note, acc, shift):
+       s = semitone_pitch((note, acc))
+       s = (s + shift + 12) % 12
+       if s <= 4:
+               n = s / 2
+               a = s % 2
+       else:
+               n = (s + 1) / 2
+               a = (s + 1) % 2
+       if a:
+               n = n + 1
+               a = -1
+       return (n,a)
 
 key_shift = { # semitone shifts for key mode names
        'm'   : 3,
@@ -517,6 +521,7 @@ def try_parse_tuplet_begin (str, state):
 def  try_parse_group_end (str, state):
        if str and str[0] in HSPACE:
                str = str[1:]
+               close_beam_state(state)
        return str
        
 def header_append (key, a):
@@ -537,13 +542,31 @@ def stuff_append (stuff, idx, a):
        else:
                stuff [idx] = wordwrap(a, stuff[idx])
 
-
+# ignore wordwrap since we are adding to the previous word
+def stuff_append_back(stuff, idx, a):
+       if not stuff:
+               stuff.append (a)
+       else:
+               point = len(stuff[idx])-1
+               while stuff[idx][point] is ' ':
+                       point = point - 1
+               point = point +1
+               stuff[idx] = stuff[idx][:point] + a + stuff[idx][point:]
 
 def voices_append(a):
        if current_voice_idx < 0:
                select_voice ('default', '')
        stuff_append (voices, current_voice_idx, a)
 
+# word wrap really makes it hard to bind beams to the end of notes since it
+# pushes out whitespace on every call. The _back functions do an append
+# prior to the last space, effectively tagging whatever they are given
+# onto the last note
+def voices_append_back(a):
+       if current_voice_idx < 0:
+               select_voice ('default', '')
+       stuff_append_back(voices, current_voice_idx, a)
+
 def repeat_prepend():
        global repeat_state
        if current_voice_idx < 0:
@@ -615,12 +638,12 @@ def try_parse_header_line (ln, state):
                        if a == 'C':
                                if not state.common_time:
                                        state.common_time = 1
-                                       voices_append ("\\override Staff.TimeSignature #\'style = #'C\n")
+                                       voices_append ("\\property Staff.TimeSignature \\override #\'style = #'C\n")
                                a = '4/4'
                        if a == 'C|':
                                if not state.common_time:
                                        state.common_time = 1
-                                       voices_append ("\\override Staff.TimeSignature #\'style = #'C\n")
+                                       voices_append ("\\property Staff.TimeSignature \\override #\'style = #'C\n")
                                a = '2/2'
                        if not length_specified:
                                set_default_len_from_time_sig (a)
@@ -758,6 +781,7 @@ class Parser_state:
                self.plus_chord = 0
                self.base_octave = 0
                self.common_time = 0
+               self.parsing_beam = 0
 
 
 
@@ -894,6 +918,12 @@ def clear_bar_acc(state):
                del state.in_acc[k]
        
 
+# if we are parsing a beam, close it off
+def close_beam_state(state):
+       if state.parsing_beam and preserve_beams:
+               state.parsing_beam = 0
+               voices_append_back( ']' )
+
                
 # WAT IS ABC EEN ONTZETTENDE PROGRAMMEERPOEP  !
 def try_parse_note (str, parser_state):
@@ -915,7 +945,7 @@ def try_parse_note (str, parser_state):
                if c == '_':
                        acc = -1
 
-        octave = parser_state.base_octave
+       octave = parser_state.base_octave
        if str[0] in "ABCDEFG":
                str = string.lower (str[0]) + str[1:]
                octave = octave - 1
@@ -980,13 +1010,19 @@ def try_parse_note (str, parser_state):
        if slur_end:
                voices_append ('-)' *slur_end )
 
-
-
+       if preserve_beams and \
+          str[0] in '^=_ABCDEFGabcdefg' and \
+          not parser_state.parsing_beam and \
+          not parser_state.parsing_tuplet:
+               parser_state.parsing_beam = 1
+               voices_append_back( '[' )
+               
        return str
 
-def junk_space (str):
-       while str and str[0] in '\t\n ':
+def junk_space (str,state):
+       while str and str[0] in '\t\n\r ':
                str = str[1:]
+               close_beam_state(state)
 
        return str
 
@@ -1007,7 +1043,8 @@ def try_parse_guitar_chord (str, state):
                if str:
                        str = str[1:]
                gc = re.sub('#', '\\#', gc)     # escape '#'s
-               state.next_articulation = ("%c\"%s\"" % (position ,gc)) + state.next_articulation
+               state.next_articulation = ("%c\"%s\"" % (position, gc)) \
+                                         + state.next_articulation
        return str
 
 def try_parse_escape (str):
@@ -1109,6 +1146,7 @@ def try_parse_bar (str,state):
                state.next_bar = '|\n'
                str = str[1:]
                clear_bar_acc(state)
+               close_beam_state(state)
        
        if bs <> None or state.next_bar != '':
                if state.parsing_tuplet:
@@ -1117,6 +1155,7 @@ def try_parse_bar (str,state):
                
        if bs <> None:
                clear_bar_acc(state)
+               close_beam_state(state)
                voices_append (bs)
                if do_curly != '':
                        voices_append("} }")
@@ -1265,7 +1304,7 @@ def parse_file (fn):
                        ln = try_parse_tuplet_begin (ln, state)
                        ln = try_parse_group_end (ln, state)
                        ln = try_parse_grace_delims (ln, state)
-                       ln = junk_space (ln)
+                       ln = junk_space (ln, state)
 
                if ln:
                        error ("%s: %d: Huh?  Don't understand\n" % (fn, lineno))
@@ -1288,6 +1327,7 @@ Options:
   -o, --output=FILE   set output filename to FILE
   -v, --version       show version information
   -s, --strict        be strict about succes
+  -b, --beams         preserve ABC's notion of beams
   
 This program converts ABC music files (see
 http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt) to LilyPond input.
@@ -1304,7 +1344,7 @@ def print_version ():
 
 
 
-(options, files) = getopt.getopt (sys.argv[1:], 'vo:hs', ['help','version', 'output=', 'strict'])
+(options, files) = getopt.getopt (sys.argv[1:], 'vo:hsb', ['help','version', 'output=', 'strict', 'beams'])
 out_filename = ''
 
 for opt in options:
@@ -1320,6 +1360,8 @@ for opt in options:
                strict = 1
        elif o == '--output' or o == '-o':
                out_filename = a
+       elif o == '--beams' or o == '-b':
+               preserve_beams = 1
        else:
                print o
                raise getopt.error
@@ -1340,7 +1382,7 @@ for f in files:
        outf = open (out_filename, 'w')
 
 #      dump_global (outf)
-       dump_header (outf ,header)
+       dump_header (outfheader)
        dump_slyrics (outf)
        dump_voices (outf)
        dump_score (outf)