Standard MIDI file: GraphViz block diagram (.dot) source

File extension

["mid", "smf"]

KS implementation details

License: CC0-1.0

This page hosts a formal specification of Standard MIDI file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

GraphViz block diagram source

standard_midi_file.dot

digraph {
	rankdir=LR;
	node [shape=plaintext];
	subgraph cluster__standard_midi_file {
		label="StandardMidiFile";
		graph[style=dotted];

		standard_midi_file__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
			<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
			<TR><TD PORT="hdr_pos">0</TD><TD PORT="hdr_size">14</TD><TD>Header</TD><TD PORT="hdr_type">hdr</TD></TR>
			<TR><TD PORT="tracks_pos">14</TD><TD PORT="tracks_size">...</TD><TD>Track</TD><TD PORT="tracks_type">tracks</TD></TR>
			<TR><TD COLSPAN="4" PORT="tracks__repeat">repeat hdr.qty_tracks times</TD></TR>
		</TABLE>>];
		subgraph cluster__track_events {
			label="StandardMidiFile::TrackEvents";
			graph[style=dotted];

			track_events__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="event_pos">0</TD><TD PORT="event_size">...</TD><TD>TrackEvent</TD><TD PORT="event_type">event</TD></TR>
				<TR><TD COLSPAN="4" PORT="event__repeat">repeat to end of stream</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__track_event {
			label="StandardMidiFile::TrackEvent";
			graph[style=dotted];

			track_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="v_time_pos">0</TD><TD PORT="v_time_size">...</TD><TD>VlqBase128Be</TD><TD PORT="v_time_type">v_time</TD></TR>
				<TR><TD PORT="event_header_pos">...</TD><TD PORT="event_header_size">1</TD><TD>u1</TD><TD PORT="event_header_type">event_header</TD></TR>
				<TR><TD PORT="meta_event_body_pos">...</TD><TD PORT="meta_event_body_size">...</TD><TD>MetaEventBody</TD><TD PORT="meta_event_body_type">meta_event_body</TD></TR>
				<TR><TD PORT="sysex_body_pos">...</TD><TD PORT="sysex_body_size">...</TD><TD>SysexEventBody</TD><TD PORT="sysex_body_type">sysex_body</TD></TR>
				<TR><TD PORT="event_body_pos">...</TD><TD PORT="event_body_size">...</TD><TD>switch (event_type)</TD><TD PORT="event_body_type">event_body</TD></TR>
			</TABLE>>];
			track_event__inst__event_type [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>event_type</TD><TD>(event_header &amp; 240)</TD></TR>
			</TABLE>>];
			track_event__inst__channel [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>channel</TD><TD>(event_header &amp; 15)</TD></TR>
			</TABLE>>];
track_event__seq_event_body_switch [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
	<TR><TD BGCOLOR="#F0F2E4">case</TD><TD BGCOLOR="#F0F2E4">type</TD></TR>
	<TR><TD>224</TD><TD PORT="case0">PitchBendEvent</TD></TR>
	<TR><TD>144</TD><TD PORT="case1">NoteOnEvent</TD></TR>
	<TR><TD>208</TD><TD PORT="case2">ChannelPressureEvent</TD></TR>
	<TR><TD>192</TD><TD PORT="case3">ProgramChangeEvent</TD></TR>
	<TR><TD>160</TD><TD PORT="case4">PolyphonicPressureEvent</TD></TR>
	<TR><TD>176</TD><TD PORT="case5">ControllerEvent</TD></TR>
	<TR><TD>128</TD><TD PORT="case6">NoteOffEvent</TD></TR>
</TABLE>>];
		}
		subgraph cluster__pitch_bend_event {
			label="StandardMidiFile::PitchBendEvent";
			graph[style=dotted];

			pitch_bend_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="b1_pos">0</TD><TD PORT="b1_size">1</TD><TD>u1</TD><TD PORT="b1_type">b1</TD></TR>
				<TR><TD PORT="b2_pos">1</TD><TD PORT="b2_size">1</TD><TD>u1</TD><TD PORT="b2_type">b2</TD></TR>
			</TABLE>>];
			pitch_bend_event__inst__bend_value [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>bend_value</TD><TD>(((b2 &lt;&lt; 7) + b1) - 16384)</TD></TR>
			</TABLE>>];
			pitch_bend_event__inst__adj_bend_value [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
				<TR><TD>adj_bend_value</TD><TD>(bend_value - 16384)</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__program_change_event {
			label="StandardMidiFile::ProgramChangeEvent";
			graph[style=dotted];

			program_change_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="program_pos">0</TD><TD PORT="program_size">1</TD><TD>u1</TD><TD PORT="program_type">program</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__note_on_event {
			label="StandardMidiFile::NoteOnEvent";
			graph[style=dotted];

			note_on_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="note_pos">0</TD><TD PORT="note_size">1</TD><TD>u1</TD><TD PORT="note_type">note</TD></TR>
				<TR><TD PORT="velocity_pos">1</TD><TD PORT="velocity_size">1</TD><TD>u1</TD><TD PORT="velocity_type">velocity</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__polyphonic_pressure_event {
			label="StandardMidiFile::PolyphonicPressureEvent";
			graph[style=dotted];

			polyphonic_pressure_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="note_pos">0</TD><TD PORT="note_size">1</TD><TD>u1</TD><TD PORT="note_type">note</TD></TR>
				<TR><TD PORT="pressure_pos">1</TD><TD PORT="pressure_size">1</TD><TD>u1</TD><TD PORT="pressure_type">pressure</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__track {
			label="StandardMidiFile::Track";
			graph[style=dotted];

			track__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="magic_pos">0</TD><TD PORT="magic_size">4</TD><TD>4D 54 72 6B</TD><TD PORT="magic_type">magic</TD></TR>
				<TR><TD PORT="track_length_pos">4</TD><TD PORT="track_length_size">4</TD><TD>u4be</TD><TD PORT="track_length_type">track_length</TD></TR>
				<TR><TD PORT="events_pos">8</TD><TD PORT="events_size">track_length</TD><TD>TrackEvents</TD><TD PORT="events_type">events</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__meta_event_body {
			label="StandardMidiFile::MetaEventBody";
			graph[style=dotted];

			meta_event_body__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="meta_type_pos">0</TD><TD PORT="meta_type_size">1</TD><TD>u1?MetaTypeEnum</TD><TD PORT="meta_type_type">meta_type</TD></TR>
				<TR><TD PORT="len_pos">1</TD><TD PORT="len_size">...</TD><TD>VlqBase128Be</TD><TD PORT="len_type">len</TD></TR>
				<TR><TD PORT="body_pos">...</TD><TD PORT="body_size">len.value</TD><TD></TD><TD PORT="body_type">body</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__controller_event {
			label="StandardMidiFile::ControllerEvent";
			graph[style=dotted];

			controller_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="controller_pos">0</TD><TD PORT="controller_size">1</TD><TD>u1</TD><TD PORT="controller_type">controller</TD></TR>
				<TR><TD PORT="value_pos">1</TD><TD PORT="value_size">1</TD><TD>u1</TD><TD PORT="value_type">value</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__header {
			label="StandardMidiFile::Header";
			graph[style=dotted];

			header__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="magic_pos">0</TD><TD PORT="magic_size">4</TD><TD>4D 54 68 64</TD><TD PORT="magic_type">magic</TD></TR>
				<TR><TD PORT="header_length_pos">4</TD><TD PORT="header_length_size">4</TD><TD>u4be</TD><TD PORT="header_length_type">header_length</TD></TR>
				<TR><TD PORT="format_pos">8</TD><TD PORT="format_size">2</TD><TD>u2be</TD><TD PORT="format_type">format</TD></TR>
				<TR><TD PORT="qty_tracks_pos">10</TD><TD PORT="qty_tracks_size">2</TD><TD>u2be</TD><TD PORT="qty_tracks_type">qty_tracks</TD></TR>
				<TR><TD PORT="division_pos">12</TD><TD PORT="division_size">2</TD><TD>s2be</TD><TD PORT="division_type">division</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__sysex_event_body {
			label="StandardMidiFile::SysexEventBody";
			graph[style=dotted];

			sysex_event_body__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="len_pos">0</TD><TD PORT="len_size">...</TD><TD>VlqBase128Be</TD><TD PORT="len_type">len</TD></TR>
				<TR><TD PORT="data_pos">...</TD><TD PORT="data_size">len.value</TD><TD></TD><TD PORT="data_type">data</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__note_off_event {
			label="StandardMidiFile::NoteOffEvent";
			graph[style=dotted];

			note_off_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="note_pos">0</TD><TD PORT="note_size">1</TD><TD>u1</TD><TD PORT="note_type">note</TD></TR>
				<TR><TD PORT="velocity_pos">1</TD><TD PORT="velocity_size">1</TD><TD>u1</TD><TD PORT="velocity_type">velocity</TD></TR>
			</TABLE>>];
		}
		subgraph cluster__channel_pressure_event {
			label="StandardMidiFile::ChannelPressureEvent";
			graph[style=dotted];

			channel_pressure_event__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
				<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
				<TR><TD PORT="pressure_pos">0</TD><TD PORT="pressure_size">1</TD><TD>u1</TD><TD PORT="pressure_type">pressure</TD></TR>
			</TABLE>>];
		}
	}
	standard_midi_file__seq:hdr_type -> header__seq [style=bold];
	standard_midi_file__seq:tracks_type -> track__seq [style=bold];
	header__seq:qty_tracks_type -> standard_midi_file__seq:tracks__repeat [color="#404040"];
	track_events__seq:event_type -> track_event__seq [style=bold];
	track_event__seq:v_time_type -> vlq_base128_be__seq [style=bold];
	track_event__seq:meta_event_body_type -> meta_event_body__seq [style=bold];
	track_event__seq:sysex_body_type -> sysex_event_body__seq [style=bold];
	track_event__seq:event_body_type -> track_event__seq_event_body_switch [style=bold];
	track_event__seq_event_body_switch:case0 -> pitch_bend_event__seq [style=bold];
	track_event__seq_event_body_switch:case1 -> note_on_event__seq [style=bold];
	track_event__seq_event_body_switch:case2 -> channel_pressure_event__seq [style=bold];
	track_event__seq_event_body_switch:case3 -> program_change_event__seq [style=bold];
	track_event__seq_event_body_switch:case4 -> polyphonic_pressure_event__seq [style=bold];
	track_event__seq_event_body_switch:case5 -> controller_event__seq [style=bold];
	track_event__seq_event_body_switch:case6 -> note_off_event__seq [style=bold];
	track_event__inst__event_type:event_type_type -> track_event__seq:event_body_type [color="#404040"];
	track_event__seq:event_header_type -> track_event__inst__event_type [color="#404040"];
	track_event__seq:event_header_type -> track_event__inst__channel [color="#404040"];
	pitch_bend_event__seq:b2_type -> pitch_bend_event__inst__bend_value [color="#404040"];
	pitch_bend_event__seq:b1_type -> pitch_bend_event__inst__bend_value [color="#404040"];
	pitch_bend_event__inst__bend_value:bend_value_type -> pitch_bend_event__inst__adj_bend_value [color="#404040"];
	track__seq:track_length_type -> track__seq:events_size [color="#404040"];
	track__seq:events_type -> track_events__seq [style=bold];
	meta_event_body__seq:len_type -> vlq_base128_be__seq [style=bold];
	vlq_base128_be__inst__value:value_type -> meta_event_body__seq:body_size [color="#404040"];
	sysex_event_body__seq:len_type -> vlq_base128_be__seq [style=bold];
	vlq_base128_be__inst__value:value_type -> sysex_event_body__seq:data_size [color="#404040"];
}