]> git.donarmstrong.com Git - lilypond.git/commitdiff
Midi2ly: process all voices/threads of a channel. Fixes #1531.
authorJan Nieuwenhuizen <janneke@gnu.org>
Mon, 21 Feb 2011 13:37:32 +0000 (14:37 +0100)
committerJan Nieuwenhuizen <janneke@gnu.org>
Mon, 21 Feb 2011 13:37:32 +0000 (14:37 +0100)
scripts/midi2ly.py

index 9ce050b0a7e892621fe2c216903cd7b05249839d..e5cb88e826e9cd0b9c1b8b3d2da76d65539eb47e 100644 (file)
@@ -102,6 +102,10 @@ def error (s):
     progress (_ ("error: ") + s)
     raise Exception (_ ("Exiting... "))
 
+def debug (s):
+    if 0:
+        progress ("debug: " + s)
+
 def system (cmd, ignore_error = 0):
     return ly.system (cmd, ignore_error=ignore_error)
 
@@ -251,7 +255,7 @@ class Note:
         s = chr ((self.notename + 2)  % 7 + ord ('a'))
         return 'Note(%s %s)' % (s, self.duration.dump ())
 
-    def dump (self, dump_dur = 1):
+    def dump (self, dump_dur=True):
         global reference_note
         s = chr ((self.notename + 2)  % 7 + ord ('a'))
         s = s + self.alteration_names[self.alteration + 2]
@@ -272,9 +276,9 @@ class Note:
         elif commas < 0:
             s = s + "," * -commas
 
-        ## FIXME: compile fix --jcn
-        if (dump_dur and (global_options.explicit_durations
-                          or self.duration.compare (reference_note.duration))):
+        if ((dump_dur
+             and self.duration.compare (reference_note.duration))
+            or global_options.explicit_durations):
             s = s + self.duration.dump ()
 
         reference_note = self
@@ -431,12 +435,11 @@ def split_track (track):
     threads = []
     for v in chs.values ():
         events = events_on_channel (v)
-        thread = unthread_notes (events)
-        if len (thread):
-            threads.append (thread)
+        t = unthread_notes (events)
+        if len (t):
+            threads.append (t)
     return threads
 
-
 def quantise_clocks (clocks, quant):
     q = int (clocks / quant) * quant
     if q != clocks:
@@ -486,11 +489,17 @@ def events_on_channel (channel):
 
         if (e[1][0] == midi.NOTE_OFF
             or (e[1][0] == midi.NOTE_ON and e[1][2] == 0)):
+            debug ('%d: NOTE OFF: %s' % (t, e[1][1]))
+            if not e[1][2]:
+                debug ('   ...treated as OFF')
             end_note (pitches, notes, t, e[1][1])
 
         elif e[1][0] == midi.NOTE_ON:
             if not pitches.has_key (e[1][1]):
+                debug ('%d: NOTE ON: %s' % (t, e[1][1]))
                 pitches[e[1][1]] = (t, e[1][2])
+            else:
+                debug ('...ignored')
 
         # all include ALL_NOTES_OFF
         elif (e[1][0] >= midi.ALL_SOUND_OFF
@@ -623,10 +632,10 @@ def dump_chord (ch):
     elif len (notes) > 1:
         global reference_note
         s = s + '<'
-        s = s + notes[0].dump (dump_dur = 0)
+        s = s + notes[0].dump (dump_dur=False)
         r = reference_note
         for i in notes[1:]:
-            s = s + i.dump (dump_dur = 0 )
+            s = s + i.dump (dump_dur=False)
         s = s + '>'
 
         s = s + notes[0].duration.dump () + ' '
@@ -649,7 +658,7 @@ def dump_bar_line (last_bar_t, t, bar_count):
     return (s, last_bar_t, bar_count)
 
 
-def dump_channel (thread, skip):
+def dump_voice (thread, skip):
     global reference_note, time
 
     global_options.key = Key (0, 0, 0)
@@ -657,7 +666,8 @@ def dump_channel (thread, skip):
     # urg LilyPond doesn't start at c4, but
     # remembers from previous tracks!
     # reference_note = Note (clocks_per_4, 4*12, 0)
-    reference_note = Note (0, 4*12, 0)
+    if not reference_note:
+        reference_note = Note (0, 4*12, 0)
     last_e = None
     chs = []
     ch = []
@@ -727,66 +737,90 @@ def number2ascii (i):
         i = (i - m)/26
     return s
 
-def track_name (i):
+def get_track_name (i):
     return 'track' + number2ascii (i)
 
-def channel_name (i):
+def get_channel_name (i):
     return 'channel' + number2ascii (i)
 
-def dump_track (channels, n):
-    s = '\n'
-    track = track_name (n)
-    clef = guess_clef (channels)
+def get_voice_name (i):
+    if True: #i:
+        return 'voice' + number2ascii (i)
+    return ''
 
-    for i in range (len (channels)):
-        channel = channel_name (i)
-        item = thread_first_item (channels[i])
-
-        if item and item.__class__ == Note:
-            skip = 's'
-            s = s + '%s = ' % (track + channel)
-            if not global_options.absolute_pitches:
-                s = s + '\\relative c '
-        elif item and item.__class__ == Text:
-            skip = '" "'
-            s = s + '%s = \\lyricmode ' % (track + channel)
-        else:
-            skip = '\\skip '
-            s = s + '%s =  ' % (track + channel)
-        s = s + '{\n'
-        s = s + '  ' + dump_channel (channels[i][0], skip)
-        s = s + '}\n\n'
+def dump_track (track, n):
+    s = '\n'
+    track_name = get_track_name (n)
+    clef = guess_clef (track)
+
+    c = 0
+    for channel in track:
+        channel_name = get_channel_name (c)
+        c += 1
+        v = 0
+        for voice in channel:
+            voice_name = get_voice_name (v)
+            voice_id = track_name + channel_name + voice_name
+            item = voice_first_item (voice)
+
+            if item and item.__class__ == Note:
+                skip = 's'
+                s += '%(voice_id)s = ' % locals ()
+                if not global_options.absolute_pitches:
+                    s += '\\relative c '
+            elif item and item.__class__ == Text:
+                skip = '" "'
+                s += '%(voice_id)s = \\lyricmode ' % locals ()
+            else:
+                skip = '\\skip '
+                s += '%(voice_id)s = ' % locals ()
+            s += '{\n'
+            if len (channel) > 1 and v < 4:
+                s += '\\voice' + ['One', 'Two', 'Three', 'Four'][v]
+            s += '  ' + dump_voice (voice, skip)
+            s += '}\n\n'
+            v += 1
 
-    s = s + '%s = <<\n' % track
+    s += '%(track_name)s = <<\n' % locals ()
 
     if clef.type != 2:
-        s = s + clef.dump () + '\n'
-
-    for i in range (len (channels)):
-        channel = channel_name (i)
-        item = thread_first_item (channels[i])
-        if item and item.__class__ == Text:
-            s = s + '  \\context Lyrics = %s \\%s\n' % (channel,
-                                  track + channel)
-        else:
-            s = s + '  \\context Voice = %s \\%s\n' % (channel,
-                                 track + channel)
-    s = s + '>>\n\n'
+        s += clef.dump () + '\n'
+
+    c = 0
+    for channel in track:
+        channel_name = get_channel_name (c)
+        c += 1
+        v = 0
+        for voice in channel:
+            voice_name = get_voice_name (v)
+            v += 1
+            voice_id = track_name + channel_name + voice_name
+            item = voice_first_item (voice)
+            context = 'Voice'
+            if item and item.__class__ == Text:
+                context = 'Lyrics'
+            s += '  \\context %(context)s = %(voice_name)s \\%(voice_id)s\n' % locals ()
+    s += '>>\n\n'
     return s
 
-def thread_first_item (thread):
-    for chord in thread:
-        for event in chord:
-            if (event[1].__class__ == Note
-              or (event[1].__class__ == Text
+def voice_first_item (voice):
+    for event in voice:
+        if (event[1].__class__ == Note
+            or (event[1].__class__ == Text
                 and event[1].type == midi.LYRIC)):
+            return event[1]
+    return None
 
-              return event[1]
+def channel_first_item (channel):
+    for voice in channel:
+        first = voice_first_item (voice)
+        if first:
+            return first
     return None
 
 def track_first_item (track):
-    for thread in track:
-        first = thread_first_item (thread)
+    for channel in track:
+        first = channel_first_item (channel)
         if first:
             return first
     return None
@@ -794,9 +828,9 @@ def track_first_item (track):
 def guess_clef (track):
     i = 0
     p = 0
-    for thread in track:
-        for chord in thread:
-            for event in chord:
+    for voice in track:
+        for thread in voice:
+            for event in thread:
                 if event[1].__class__ == Note:
                     i = i + 1
                     p = p + event[1].pitch
@@ -853,13 +887,13 @@ def convert_midi (in_file, out_file):
 
     i = 0
     for t in tracks:
-        track = track_name (i)
+        track_name = get_track_name (i)
         item = track_first_item (t)
 
         if item and item.__class__ == Note:
-            s = s + '    \\context Staff=%s \\%s\n' % (track, track)
+            s += '    \\context Staff=%(track_name)s \\%(track_name)s\n' % locals ()
         elif item and item.__class__ == Text:
-            s = s + '    \\context Lyrics=%s \\%s\n' % (track, track)
+            s += '    \\context Lyrics=%(track_name)s \\%(track_name)s\n' % locals ()
 
         i += 1
     s = s + '  >>\n}\n'