]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/etf2ly.py
* The grand 2005-2006 replace.
[lilypond.git] / scripts / etf2ly.py
index f80334bc14d7dac35c0f4953e79d63b7ca4c8d8d..225d23397b5ccd1c03ba62b5d5b0d2a63156cdfe 100644 (file)
@@ -1,7 +1,7 @@
 #!@PYTHON@
 
 # info mostly taken from looking at files. See also
-# http://www.cs.uu.nl/~hanwen/lily-devel/etf.html
+# http://lilypond.org/wiki/?EnigmaTransportFormat
 
 # This supports
 #
 #  * dynamics
 #  * empty measures (eg. twopt03.etf from freenote)
 #
-# 
 
-program_name = 'etf2ly'
-version = '@TOPLEVEL_VERSION@'
-if version == '@' + 'TOPLEVEL_VERSION' + '@':
-       version = '(unknown version)'      # uGUHGUHGHGUGH
-  
+
 import __main__
 import getopt
 import sys
@@ -38,6 +33,12 @@ import re
 import string
 import os
 
+program_name = sys.argv[0]
+
+version = '@TOPLEVEL_VERSION@'
+if version == '@' + 'TOPLEVEL_VERSION' + '@':
+       version = '(unknown version)'      # uGUHGUHGHGUGH
+  
 finale_clefs= ['treble', 'alto', 'tenor', 'bass', 'percussion', 'treble_8', 'bass_8', 'baritone']
 
 def lily_clef (fin):
@@ -75,27 +76,52 @@ def transpose(orig, delta):
 
 
 
-# find transposition of C-major scale that belongs here. 
 def interpret_finale_key_sig (finale_id):
+       """
+find the transposition of C-major scale that belongs here.
+
+we are not going to insert the correct major/minor, we only want to
+have the correct number of accidentals
+"""
+
        p = (0,0)
-       if 0 <= finale_id < 7:
-               while finale_id > 0:
+
+       
+       bank_number = finale_id >> 8
+       accidental_bits = finale_id & 0xff
+
+       if 0 <= accidental_bits < 7:
+               while accidental_bits > 0:
                        p = transpose (p, (4,0)) # a fifth up
-                       finale_id = finale_id - 1
-       elif 248 < finale_id <= 255:
-               while finale_id < 256:
+                       accidental_bits = accidental_bits - 1
+       elif 248 < accidental_bits <= 255:
+               while accidental_bits < 256:
                        p = transpose (p, (3,0))
-                       finale_id = finale_id + 1
+                       accidental_bits = accidental_bits + 1
 
+       if bank_number == 1:
+               # minor scale
+               p = transpose (p, (5, 0))
        p  = (p[0] % 7, p[1])
-       return p
+
+       return KeySignature (p, bank_number)
 
 # should cache this.
-def find_scale (transposition):
+def find_scale (keysig):
        cscale = map (lambda x: (x,0), range (0,7))
-       trscale = map(lambda x, k=transposition: transpose(x, k), cscale)
-
+#      print "cscale: ", cscale
+       ascale = map (lambda x: (x,0), range (-2,5))
+#      print "ascale: ", ascale
+       transposition = keysig.pitch
+       if keysig.sig_type == 1:
+               transposition = transpose(transposition, (2, -1))
+               transposition = (transposition[0] % 7, transposition[1])
+               trscale = map(lambda x, k=transposition: transpose(x, k), ascale)
+       else:
+               trscale = map(lambda x, k=transposition: transpose(x, k), cscale)
+#      print "trscale: ", trscale
        return trscale
+
 def EDU_to_duration (edu):
        log = 1
        d = 4096
@@ -111,7 +137,7 @@ def EDU_to_duration (edu):
                dots = 2
        return (log, dots)      
 
-def rat_to_lily_duration (rat):
+def rational_to_lily_skip (rat):
        (n,d) = rat
 
        basedur = 1
@@ -233,8 +259,9 @@ class Slur:
                        if not cs or not ce:
                                raise IndexError
                        
-                       cs.note_suffix = '(' + cs.note_suffix 
-                       ce.note_prefix = ce.note_prefix + ')'
+                       cs.note_suffix = '-(' + cs.note_suffix 
+                       ce.note_suffix = ce.note_suffix + '-)'
+                       
                except IndexError:
                        sys.stderr.write ("""\nHuh? Slur no %d between (%d,%d), with %d notes""" % (self.number,  startnote, endnote, len (chords)))
                                         
@@ -243,7 +270,7 @@ class Global_measure:
        def __init__ (self, number):
                self.timesig = ''
                self.number = number
-               self.keysignature = None
+               self.key_signature = None
                self.scale = None
                self.force_break = 0
                
@@ -256,16 +283,22 @@ class Global_measure:
        def set_timesig (self, finale):
                (beats, fdur) = finale
                (log, dots) = EDU_to_duration (fdur)
+
+               if dots == 1:
+                       beats = beats * 3
+                       log = log * 2
+                       dots = 0
+
                if dots <> 0:
-                       sys.stderr.write ("\nHuh? Beat duration has a dot? (EDU Duration = %d)" % fdur) 
+                       sys.stderr.write ("\nHuh? Beat duration has  dots? (EDU Duration = %d)" % fdur) 
                self.timesig = (beats, log)
 
        def length (self):
                return self.timesig
        
-       def set_keysig (self, finale):
+       def set_key_sig (self, finale):
                k = interpret_finale_key_sig (finale)
-               self.keysignature = k
+               self.key_signature = k
                self.scale = find_scale (k)
 
        def set_flags (self,flag1, flag2):
@@ -362,10 +395,28 @@ class Verse:
                                str = str + ' ' * 4 + line + '\n'
                                line = ''
                        
-               str = """\nverse%s = \\lyrics {\n %s}\n""" %  (encodeint (self.number - 1) ,str)
+               str = """\nverse%s = \\lyricmode {\n %s }\n""" %  (encodeint (self.number - 1) ,str)
                return str
 
+class KeySignature:
+       def __init__(self, pitch, sig_type = 0):
+               self.pitch = pitch
+               self.sig_type = sig_type
+       
+       def signature_type (self):
+               if self.sig_type == 1:
+                       return "\\minor"
+               else:
+                       # really only for 0, but we only know about 0 and 1
+                       return "\\major"
        
+       def equal (self, other):
+               if other and other.pitch == self.pitch and other.sig_type == self.sig_type:
+                       return 1
+               else:
+                       return 0
+       
+
 class Measure:
        def __init__(self, no):
                self.number = no
@@ -412,14 +463,19 @@ class Frame:
 
                # do grace notes.
                lastch = None
+               in_grace = 0
                for c in self.chords:
                        if c.grace and (lastch == None or (not lastch.grace)):
                                c.chord_prefix = r'\grace {' + c.chord_prefix
+                               in_grace = 1
                        elif not c.grace and lastch and lastch.grace:
                                lastch.chord_suffix = lastch.chord_suffix + ' } '
-
+                               in_grace = 0
+                               
                        lastch = c
-                       
+
+               if lastch and in_grace:
+                       lastch.chord_suffix += '}' 
 
                
        def dump (self):
@@ -442,7 +498,7 @@ class Frame:
                        sys.stderr.write ("""\nHuh? Going backwards in frame no %d, start/end (%d,%d)""" % (self.number, self.start, self.end))
                        left = (0,1)
                if left[0]:
-                       str = str + rat_to_lily_duration (left)
+                       str = str + rational_to_lily_skip (left)
 
                str = str + '  | \n'
                return str
@@ -483,9 +539,12 @@ class Staff:
                        e = ''
                        
                        if g:
-                               if last_key <> g.keysignature:
-                                       e = e + "\\key %s \\major " % lily_notename (g.keysignature)
-                                       last_key = g.keysignature
+                               if g.key_signature and not g.key_signature.equal(last_key):
+                                       pitch= g.key_signature.pitch
+                                       e = e + "\\key %s %s " % (lily_notename (pitch),
+                                                                 g.key_signature.signature_type())
+                                       
+                                       last_key = g.key_signature
                                if last_time <> g.timesig :
                                        e = e + "\\time %d/%d " % g.timesig
                                        last_time = g.timesig
@@ -506,7 +565,7 @@ class Staff:
 
                                        str = string.join (map (lambda x: '(volta %s)' % x, strs))
                                        
-                                       e = e + ' \\property Score.repeatCommands =  #\'(%s) ' % str
+                                       e = e + ' \\set Score.repeatCommands =  #\'(%s) ' % str
 
                                if g.force_break:
                                        e = e + ' \\break '  
@@ -516,7 +575,7 @@ class Staff:
                                last_clef = m.clef
                        if e:
                                if gap <> (0,1):
-                                       k = k +' ' + rat_to_lily_duration (gap) + '\n'
+                                       k = k +' ' + rational_to_lily_skip (gap) + '\n'
                                gap = (0,1)
                                k = k + e
                                
@@ -525,7 +584,7 @@ class Staff:
                                if 'stop' in g.repeats:
                                        k = k + ' \\bar ":|" '
                                
-               k = '%sglobal = \\notes  { %s }\n\n ' % (self.staffid (), k)
+               k = '%sglobal = { %s }\n\n ' % (self.staffid (), k)
                return k
        
        def dump (self):
@@ -552,7 +611,7 @@ class Staff:
                                if fr:
                                        first_frame = fr
                                        if gap <> (0,1):
-                                               laystr = laystr +'} %s {\n ' % rat_to_lily_duration (gap)
+                                               laystr = laystr +'} %s {\n ' % rational_to_lily_skip (gap)
                                                gap = (0,1)
                                        laystr = laystr + fr.dump ()
                                else:
@@ -564,7 +623,7 @@ class Staff:
                                                        % (self.number, m.number))
                        if first_frame:
                                l = self.layerid (x)
-                               laystr = '%s =  \\notes { { %s } }\n\n' % (l, laystr)
+                               laystr = '%s = { {  %s } }\n\n' % (l, laystr)
                                str = str  + laystr
                                layerids.append (l)
 
@@ -574,7 +633,7 @@ class Staff:
                        stafdef = stafdef + ' \\' + i
                        
 
-               str = str + '%s = \\context Staff = %s <\n %s\n >\n' % \
+               str = str + '%s = \\context Staff = %s <<\n %s\n >>\n' % \
                      (self.staffid (), self.staffid (), stafdef)
                return str
 
@@ -700,15 +759,18 @@ class Chord:
                        if rest:
                                nn = rest
                                
-                       s = s + '%s%d%s' % (nn, self.duration[0], '.'* self.duration[1])
+                       s = s + nn 
 
                if not self.pitches:
-                       s  = 'r%d%s' % (self.duration[0] , '.'* self.duration[1])
-               s = self.note_prefix + s + self.note_suffix
+                       s  = 'r'
                if len (self.pitches) > 1:
                        s = '<%s>' % s
+
+               s = s + '%d%s' % (self.duration[0], '.'* self.duration[1])
+               s = self.note_prefix + s + self.note_suffix
                
                s = self.chord_prefix + s + self.chord_suffix
+
                return s
 
 
@@ -757,7 +819,7 @@ Return: (value, rest-of-STR)
                        
                return (string.atoi (dec), str)
        else:
-               sys.stderr.write ("Can't convert `%s'\n" % str)
+               sys.stderr.write ("can't convert `%s'\n" % str)
                return (None, str)
 
 
@@ -934,7 +996,8 @@ class Etf_file:
                measno = indices[0]
                keynum = contents[1]
                meas =self. get_global_measure (measno)
-               meas.set_keysig (keynum)
+
+               meas.set_key_sig (keynum)
 
                beats = contents[2]
                beatlen = contents[3]
@@ -1068,7 +1131,8 @@ class Etf_file:
                        sys.stderr.write ("\nLyrics found; edit to use \\addlyrics to couple to a staff\n")
                        
                if staffs:
-                       str = str + '\\score { < %s > } ' % string.join (staffs)
+                       str += '\\version "2.3.25"\n'
+                       str = str + '<<\n  %s\n>> } ' % string.join (staffs)
                        
                return str
 
@@ -1088,22 +1152,25 @@ def identify():
        sys.stderr.write ("%s from LilyPond %s\n" % (program_name, version))
 
 def help ():
-       sys.stdout.write("""Usage: etf2ly [OPTION]... ETF-FILE
+       sys.stdout.write("""Usage: etf2ly [OPTIONS]... ETF-FILE
 
 Convert ETF to LilyPond.
 
 Options:
-  -h,--help          this help
-  -o,--output=FILE   set output filename to FILE
-  -v,--version       version information
+  -h, --help          print this help
+  -o, --output=FILE   set output filename to FILE
+  -v, --version       show version information
 
 Enigma Transport Format is a format used by Coda Music Technology's
 Finale product. This program will convert a subset of ETF to a
 ready-to-use lilypond file.
 
-Report bugs to bug-gnu-music@gnu.org
+Report bugs via
+
+  http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs
+
+Written by  Han-Wen Nienhuys <hanwen@cs.uu.nl>.
 
-Written by  Han-Wen Nienhuys <hanwen@cs.uu.nl>
 """)
 
 def print_version ():
@@ -1113,7 +1180,7 @@ This is free software.  It is covered by the GNU General Public License,
 and you are welcome to change it and/or distribute copies of it under
 certain conditions.  Invoke as `midi2ly --warranty' for more information.
 
-Copyright (c) 2000 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
+Copyright (c) 2000--2006 by Han-Wen Nienhuys <hanwen@cs.uu.nl>
 """ % version)