3 # Copyright (C) 2006--2012 Brailcom, o.p.s.
5 # Author: Milan Zamazal <pdm@brailcom.org>
7 # This file is part of LilyPond, the GNU music typesetter.
9 # LilyPond is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # LilyPond is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
30 def process_options (args):
31 parser = optparse.OptionParser (version="@TOPLEVEL_VERSION@")
32 parser.add_option ('', '--filter-tracks', metavar='REGEXP', action='store', type='string', dest='regexp',
33 help="display only tracks numbers, of those track names matching REGEXP")
34 parser.add_option ('', '--prefix-tracks', metavar='PREFIX', action='store', type='string', dest='prefix',
35 help="prefix filtered track numbers with PREFIX")
36 parser.add_option ('', '--dump', action='store_true', dest='dump',
37 help="just dump parsed contents of the MIDI file")
38 parser.add_option ('', '--pretty', action='store_true', dest='pretty',
39 help="dump parsed contents of the MIDI file in human-readable form (implies --dump)")
40 parser.usage = parser.usage + " FILE"
41 options, args = parser.parse_args (args)
49 return midi.parse (open (file).read ())
51 def track_info (data):
53 def track_name (track):
55 for time, event in track:
58 if event[0] == 255 and event[1] == 3:
63 for i in range (len (tracks)):
64 track_info.append ((i, track_name (tracks[i])))
69 def __init__ (self, txt = ""):
71 def format_vals (self, val1, val2 = ""):
72 return str (val1) + str(val2)
73 def format (self, val1, val2 = ""):
74 return self.text + self.format_vals (val1, val2)
75 class none_formatter (formatter):
76 def format_vals (self, val1, val2 = ""):
78 class meta_formatter (formatter):
79 def format_vals (self, val1, val2):
81 class tempo_formatter (formatter):
82 def format_vals (self, val1, val2):
83 return str (ord (val2[0])*65536 + ord (val2[1])*256 + ord (val2[2])) \
86 class time_signature_formatter (formatter):
87 def format_vals (self, val1, val2 = ""):
88 from fractions import Fraction
89 # if there are more notated 32nd notes per midi quarter than 8,
90 # we display a fraction smaller than 1 as scale factor.
91 r = Fraction(8, ord (val2[3]))
95 ratio = " *" + str (r)
96 return str (ord (val2[0])) + "/" + str(1 << ord (val2[1])) + ratio \
97 + ", metronome " + str (Fraction (ord (val2[2]), 96))
98 class key_signature_formatter (formatter):
99 def format_vals (self, val1, val2):
100 key_names = ['F', 'C', 'G', 'D', 'A', 'E', 'B']
101 key = (((ord(val2[0])+128)%256)-128) + ord(val2[1])*3 + 1;
102 return (key_names[key%7] + (key/7) * "is" + (-(key/7)) * "es"
103 + " " + ['major','minor'][ord(val2[1])])
104 class channel_formatter (formatter):
105 def __init__ (self, txt, ch):
106 formatter.__init__ (self, txt)
108 def format (self, val1, val2 = ""):
109 return self.text + "Channel " + str (self.channel) + ", " + \
110 self.format_vals (val1, val2)
111 class control_mode_formatter (formatter):
112 def __init__ (self, txt, ch):
113 formatter.__init__ (self, txt)
115 def format (self, val1, val2 = ""):
116 return self.text + str (self.mode) + ", " + \
117 self.format_vals (val1, val2)
118 class note_formatter (channel_formatter):
119 def pitch (self, val):
120 pitch_names = ['C', 'Cis', 'D', 'Dis', 'E', 'F', 'Fis', 'G', 'Gis', 'A', 'Ais', 'B'];
123 return pitch_names[p] + str(oct) + "(" + str(val) + ")"
124 def velocity (self, val):
125 #01 #10 #20 #30 #40 #50 #60 #70 #7F
127 def format_vals (self, val1, val2):
128 return self.pitch (val1)
131 meta_dict = {0x00: meta_formatter ("Seq.Nr.: "),
132 0x01: meta_formatter ("Text: "),
133 0x02: meta_formatter ("Copyright: "),
134 0x03: meta_formatter ("Track name: "),
135 0x04: meta_formatter ("Instrument: "),
136 0x05: meta_formatter ("Lyric: "),
137 0x06: meta_formatter ("Marker: "),
138 0x07: meta_formatter ("Cue point: "),
139 0x2F: none_formatter ("End of Track"),
140 0x51: tempo_formatter ("Tempo: "),
141 0x54: meta_formatter ("SMPTE Offs.:"),
142 0x58: time_signature_formatter ("Time signature: "),
143 0x59: key_signature_formatter ("Key signature: ")
146 def dump_event (ev, time, padding):
151 f = meta_dict.get (ev[1], formatter ())
153 f = note_formatter ("Note off: ", ch)
159 f = note_formatter (desc, ch)
161 f = note_formatter ("Polyphonic aftertouch: ", ch, "Aftertouch pressure: ")
163 f = control_mode_formatter ("Control mode change: ", ch)
165 f = channel_formatter ("Program Change: ", ch)
167 f = channel_formatter ("Channel aftertouch: ", ch)
168 elif (ev[0] in [0xF0, 0xF7]):
169 f = meta_formatter ("System-exclusive event: ")
173 print padding + f.format (ev[1], ev[2])
175 print padding + f.format (ev[1])
177 print padding + f.format ()
179 print padding + "Unrecognized MIDI event: " + str (ev);
181 def dump_midi (data, midi_file, options):
182 if not options.pretty:
185 # First, dump general info, #tracks, etc.
186 print "Filename: " + midi_file;
188 m_formats = {0: 'single multi-channel track',
189 1: "one or more simultaneous tracks",
190 2: "one or more sequentially independent single-track patterns"}
191 print "MIDI format: " + str (i[0]) + " (" + m_formats.get (i[0], "") + ")";
192 print "Divisions: " + str (i[1]) + " per whole note";
193 print "#Tracks: " + str ( len (data[1]))
199 print "Track " + str(n) + ":"
204 print " Time " + str(time) + ": "
205 dump_event (ev[1], time, " ");
210 options, args = process_options (sys.argv[1:])
212 midi_data = read_midi (midi_file)
213 info = track_info (midi_data)
214 if (options.dump or options.pretty):
215 dump_midi (midi_data, midi_file, options);
218 regexp = re.compile (options.regexp)
219 numbers = [str(n+1) for n, name in info if regexp.search (name)]
222 sys.stdout.write ('%s ' % (options.prefix,))
224 sys.stdout.write (string.join (numbers, ','))
225 sys.stdout.write ('\n')
228 sys.stdout.write ('%d %s\n' % (n+1, name,))
230 if __name__ == '__main__':