]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/lilymidi.py
Add '-dcrop' option to ps and svg backends
[lilypond.git] / scripts / lilymidi.py
index dee735fa3b8ac3cacef079ae9ed3e8e92dcb0a1b..34308f07025e625ed0b0cae086ae6258cfde4edd 100644 (file)
@@ -1,6 +1,6 @@
 #!@TARGET_PYTHON@
 
-# Copyright (C) 2006--2009 Brailcom, o.p.s.
+# Copyright (C) 2006--2015 Brailcom, o.p.s.
 #
 # Author: Milan Zamazal <pdm@brailcom.org>
 #
@@ -35,6 +35,8 @@ def process_options (args):
                        help="prefix filtered track numbers with PREFIX")
     parser.add_option ('', '--dump', action='store_true', dest='dump',
                        help="just dump parsed contents of the MIDI file")
+    parser.add_option ('', '--pretty', action='store_true', dest='pretty',
+                       help="dump parsed contents of the MIDI file in human-readable form (implies --dump)")
     parser.usage = parser.usage + " FILE"
     options, args = parser.parse_args (args)
     if len (args) != 1:
@@ -62,13 +64,155 @@ def track_info (data):
         track_info.append ((i, track_name (tracks[i])))
     return track_info
 
+
+class formatter:
+   def __init__ (self, txt = ""):
+     self.text = txt
+   def format_vals (self, val1, val2 = ""):
+     return str (val1) + str(val2)
+   def format (self, val1, val2 = ""):
+     return self.text + self.format_vals (val1, val2)
+class none_formatter (formatter):
+   def format_vals (self, val1, val2 = ""):
+     return ''
+class meta_formatter (formatter):
+   def format_vals (self, val1, val2):
+     return str (val2);
+class tempo_formatter (formatter):
+   def format_vals (self, val1, val2):
+    return str (ord (val2[0])*65536 + ord (val2[1])*256 + ord (val2[2])) \
+        + " msec/quarter"
+
+class time_signature_formatter (formatter):
+   def format_vals (self, val1, val2 = ""):
+       from fractions import Fraction
+       # if there are more notated 32nd notes per midi quarter than 8,
+       # we display a fraction smaller than 1 as scale factor.
+       r = Fraction(8, ord (val2[3]))
+       if r == 1:
+           ratio =""
+       else:
+           ratio = " *" + str (r)
+       return str (ord (val2[0])) + "/" + str(1 << ord (val2[1])) + ratio \
+           + ", metronome "  + str (Fraction (ord (val2[2]), 96))
+class key_signature_formatter (formatter):
+   def format_vals (self, val1, val2):
+       key_names = ['F', 'C', 'G', 'D', 'A', 'E', 'B']
+       key = (((ord(val2[0])+128)%256)-128) + ord(val2[1])*3 + 1;
+       return (key_names[key%7] + (key/7) * "is" + (-(key/7)) * "es"
+               + " " + ['major','minor'][ord(val2[1])])
+class channel_formatter (formatter):
+   def __init__ (self, txt, ch):
+     formatter.__init__ (self, txt)
+     self.channel = ch
+   def format (self, val1, val2 = ""):
+     return self.text + "Channel " + str (self.channel) + ", " + \
+            self.format_vals (val1, val2)
+class control_mode_formatter (formatter):
+   def __init__ (self, txt, ch):
+     formatter.__init__ (self, txt)
+     self.mode = ch
+   def format (self, val1, val2 = ""):
+     return self.text + str (self.mode) + ", " + \
+            self.format_vals (val1, val2)
+class note_formatter (channel_formatter):
+   def pitch (self, val):
+     pitch_names = ['C', 'Cis', 'D', 'Dis', 'E', 'F', 'Fis', 'G', 'Gis', 'A', 'Ais', 'B'];
+     p = val % 12;
+     oct = val / 12 -1;
+     return pitch_names[p] + str(oct) + "(" + str(val) + ")"
+   def velocity (self, val):
+     #01   #10   #20   #30   #40   #50   #60   #70   #7F
+     pass;
+   def format_vals (self, val1, val2):
+     return self.pitch (val1)
+
+
+meta_dict = {0x00: meta_formatter ("Seq.Nr.:    "),
+             0x01: meta_formatter ("Text:       "),
+             0x02: meta_formatter ("Copyright:  "),
+             0x03: meta_formatter ("Track name: "),
+             0x04: meta_formatter ("Instrument: "),
+             0x05: meta_formatter ("Lyric:      "),
+             0x06: meta_formatter ("Marker:     "),
+             0x07: meta_formatter ("Cue point:  "),
+             0x2F: none_formatter ("End of Track"),
+             0x51: tempo_formatter ("Tempo:      "),
+             0x54: meta_formatter ("SMPTE Offs.:"),
+             0x58: time_signature_formatter ("Time signature: "),
+             0x59: key_signature_formatter ("Key signature: ")
+}
+
+def dump_event (ev, time, padding):
+    ch = ev[0] & 0x0F;
+    func = ev[0] & 0xF0;
+    f = None
+    if (ev[0] == 0xFF):
+        f = meta_dict.get (ev[1], formatter ())
+    if (func == 0x80):
+        f = note_formatter ("Note off: ", ch)
+    elif (func == 0x90):
+        if (ev[2] == 0):
+          desc = "Note off: "
+        else:
+          desc = "Note on: "
+        f = note_formatter (desc, ch)
+    elif (func == 0xA0):
+        f = note_formatter ("Polyphonic aftertouch: ", ch, "Aftertouch pressure: ")
+    elif (func == 0xB0):
+        f = control_mode_formatter ("Control mode change: ", ch)
+    elif (func == 0xC0):
+        f = channel_formatter ("Program Change: ", ch)
+    elif (func == 0xD0):
+        f = channel_formatter ("Channel aftertouch: ", ch)
+    elif (ev[0] in [0xF0, 0xF7]):
+        f = meta_formatter ("System-exclusive event: ")
+
+    if f:
+      if len (ev) > 2:
+        print padding + f.format (ev[1], ev[2])
+      elif len (ev) > 1:
+        print padding + f.format (ev[1])
+      else:
+        print padding + f.format ()
+    else:
+      print padding + "Unrecognized MIDI event: " + str (ev);
+
+def dump_midi (data, midi_file, options):
+    if not options.pretty:
+        print data
+        return
+    # First, dump general info, #tracks, etc.
+    print "Filename:     " + midi_file;
+    i = data[0];
+    m_formats = {0: 'single multi-channel track',
+                 1: "one or more simultaneous tracks",
+                 2: "one or more sequentially independent single-track patterns"}
+    print "MIDI format:  " + str (i[0]) + " (" + m_formats.get (i[0], "") + ")";
+    print "Divisions:    " + str (i[1]) + " per whole note";
+    print "#Tracks:      " + str ( len (data[1]))
+    n = 0;
+    for tr in data[1]:
+      time = 0;
+      n += 1;
+      print
+      print "Track " + str(n) + ":"
+      print "    Time 0:"
+      for ev in tr:
+        if ev[0]>time:
+           time = ev[0]
+           print "    Time " + str(time) + ": "
+        dump_event (ev[1], time, "        ");
+
+
+
 def go ():
     options, args = process_options (sys.argv[1:])
     midi_file = args[0]
     midi_data = read_midi (midi_file)
     info = track_info (midi_data)
-    if options.dump:
-        print midi_data
+    if (options.dump or options.pretty):
+        dump_midi (midi_data, midi_file, options);
     elif options.regexp:
         import re
         regexp = re.compile (options.regexp)