Standard MIDI file, typically known just as "MID", is a standard way to serialize series of MIDI events, which is a protocol used in many music synthesizers to transfer music data: notes being played, effects being applied, etc.
Internally, file consists of a header and series of tracks, every track listing MIDI events with certain header designating time these events are happening.
NOTE: Rarely, MIDI files employ certain stateful compression scheme to avoid storing certain elements of further elements, instead reusing them from events which happened earlier in the stream. Kaitai Struct (as of v0.9) is currently unable to parse these, but files employing this mechanism are relatively rare.
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.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
)
/**
* Standard MIDI file, typically known just as "MID", is a standard way
* to serialize series of MIDI events, which is a protocol used in many
* music synthesizers to transfer music data: notes being played,
* effects being applied, etc.
*
* Internally, file consists of a header and series of tracks, every
* track listing MIDI events with certain header designating time these
* events are happening.
*
* NOTE: Rarely, MIDI files employ certain stateful compression scheme
* to avoid storing certain elements of further elements, instead
* reusing them from events which happened earlier in the
* stream. Kaitai Struct (as of v0.9) is currently unable to parse
* these, but files employing this mechanism are relatively rare.
*/
type StandardMidiFile struct {
Hdr *StandardMidiFile_Header
Tracks []*StandardMidiFile_Track
_io *kaitai.Stream
_root *StandardMidiFile
_parent kaitai.Struct
}
func NewStandardMidiFile() *StandardMidiFile {
return &StandardMidiFile{
}
}
func (this StandardMidiFile) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile) Read(io *kaitai.Stream, parent kaitai.Struct, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1 := NewStandardMidiFile_Header()
err = tmp1.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Hdr = tmp1
for i := 0; i < int(this.Hdr.NumTracks); i++ {
_ = i
tmp2 := NewStandardMidiFile_Track()
err = tmp2.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Tracks = append(this.Tracks, tmp2)
}
return err
}
type StandardMidiFile_ChannelPressureEvent struct {
Pressure uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_ChannelPressureEvent() *StandardMidiFile_ChannelPressureEvent {
return &StandardMidiFile_ChannelPressureEvent{
}
}
func (this StandardMidiFile_ChannelPressureEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_ChannelPressureEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp3, err := this._io.ReadU1()
if err != nil {
return err
}
this.Pressure = tmp3
return err
}
type StandardMidiFile_ControllerEvent struct {
Controller uint8
Value uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_ControllerEvent() *StandardMidiFile_ControllerEvent {
return &StandardMidiFile_ControllerEvent{
}
}
func (this StandardMidiFile_ControllerEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_ControllerEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp4, err := this._io.ReadU1()
if err != nil {
return err
}
this.Controller = tmp4
tmp5, err := this._io.ReadU1()
if err != nil {
return err
}
this.Value = tmp5
return err
}
type StandardMidiFile_Header struct {
Magic []byte
LenHeader uint32
Format uint16
NumTracks uint16
Division int16
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile
}
func NewStandardMidiFile_Header() *StandardMidiFile_Header {
return &StandardMidiFile_Header{
}
}
func (this StandardMidiFile_Header) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_Header) Read(io *kaitai.Stream, parent *StandardMidiFile, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp6, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp6 = tmp6
this.Magic = tmp6
if !(bytes.Equal(this.Magic, []uint8{77, 84, 104, 100})) {
return kaitai.NewValidationNotEqualError([]uint8{77, 84, 104, 100}, this.Magic, this._io, "/types/header/seq/0")
}
tmp7, err := this._io.ReadU4be()
if err != nil {
return err
}
this.LenHeader = uint32(tmp7)
tmp8, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Format = uint16(tmp8)
tmp9, err := this._io.ReadU2be()
if err != nil {
return err
}
this.NumTracks = uint16(tmp9)
tmp10, err := this._io.ReadS2be()
if err != nil {
return err
}
this.Division = int16(tmp10)
return err
}
type StandardMidiFile_MetaEventBody_MetaTypeEnum int
const (
StandardMidiFile_MetaEventBody_MetaTypeEnum__SequenceNumber StandardMidiFile_MetaEventBody_MetaTypeEnum = 0
StandardMidiFile_MetaEventBody_MetaTypeEnum__TextEvent StandardMidiFile_MetaEventBody_MetaTypeEnum = 1
StandardMidiFile_MetaEventBody_MetaTypeEnum__Copyright StandardMidiFile_MetaEventBody_MetaTypeEnum = 2
StandardMidiFile_MetaEventBody_MetaTypeEnum__SequenceTrackName StandardMidiFile_MetaEventBody_MetaTypeEnum = 3
StandardMidiFile_MetaEventBody_MetaTypeEnum__InstrumentName StandardMidiFile_MetaEventBody_MetaTypeEnum = 4
StandardMidiFile_MetaEventBody_MetaTypeEnum__LyricText StandardMidiFile_MetaEventBody_MetaTypeEnum = 5
StandardMidiFile_MetaEventBody_MetaTypeEnum__MarkerText StandardMidiFile_MetaEventBody_MetaTypeEnum = 6
StandardMidiFile_MetaEventBody_MetaTypeEnum__CuePoint StandardMidiFile_MetaEventBody_MetaTypeEnum = 7
StandardMidiFile_MetaEventBody_MetaTypeEnum__MidiChannelPrefixAssignment StandardMidiFile_MetaEventBody_MetaTypeEnum = 32
StandardMidiFile_MetaEventBody_MetaTypeEnum__EndOfTrack StandardMidiFile_MetaEventBody_MetaTypeEnum = 47
StandardMidiFile_MetaEventBody_MetaTypeEnum__Tempo StandardMidiFile_MetaEventBody_MetaTypeEnum = 81
StandardMidiFile_MetaEventBody_MetaTypeEnum__SmpteOffset StandardMidiFile_MetaEventBody_MetaTypeEnum = 84
StandardMidiFile_MetaEventBody_MetaTypeEnum__TimeSignature StandardMidiFile_MetaEventBody_MetaTypeEnum = 88
StandardMidiFile_MetaEventBody_MetaTypeEnum__KeySignature StandardMidiFile_MetaEventBody_MetaTypeEnum = 89
StandardMidiFile_MetaEventBody_MetaTypeEnum__SequencerSpecificEvent StandardMidiFile_MetaEventBody_MetaTypeEnum = 127
)
var values_StandardMidiFile_MetaEventBody_MetaTypeEnum = map[StandardMidiFile_MetaEventBody_MetaTypeEnum]struct{}{0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 32: {}, 47: {}, 81: {}, 84: {}, 88: {}, 89: {}, 127: {}}
func (v StandardMidiFile_MetaEventBody_MetaTypeEnum) isDefined() bool {
_, ok := values_StandardMidiFile_MetaEventBody_MetaTypeEnum[v]
return ok
}
type StandardMidiFile_MetaEventBody struct {
MetaType StandardMidiFile_MetaEventBody_MetaTypeEnum
Len *VlqBase128Be
Body []byte
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_MetaEventBody() *StandardMidiFile_MetaEventBody {
return &StandardMidiFile_MetaEventBody{
}
}
func (this StandardMidiFile_MetaEventBody) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_MetaEventBody) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp11, err := this._io.ReadU1()
if err != nil {
return err
}
this.MetaType = StandardMidiFile_MetaEventBody_MetaTypeEnum(tmp11)
tmp12 := NewVlqBase128Be()
err = tmp12.Read(this._io, nil, nil)
if err != nil {
return err
}
this.Len = tmp12
tmp13, err := this.Len.Value()
if err != nil {
return err
}
tmp14, err := this._io.ReadBytes(int(tmp13))
if err != nil {
return err
}
tmp14 = tmp14
this.Body = tmp14
return err
}
type StandardMidiFile_NoteOffEvent struct {
Note uint8
Velocity uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_NoteOffEvent() *StandardMidiFile_NoteOffEvent {
return &StandardMidiFile_NoteOffEvent{
}
}
func (this StandardMidiFile_NoteOffEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_NoteOffEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp15, err := this._io.ReadU1()
if err != nil {
return err
}
this.Note = tmp15
tmp16, err := this._io.ReadU1()
if err != nil {
return err
}
this.Velocity = tmp16
return err
}
type StandardMidiFile_NoteOnEvent struct {
Note uint8
Velocity uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_NoteOnEvent() *StandardMidiFile_NoteOnEvent {
return &StandardMidiFile_NoteOnEvent{
}
}
func (this StandardMidiFile_NoteOnEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_NoteOnEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp17, err := this._io.ReadU1()
if err != nil {
return err
}
this.Note = tmp17
tmp18, err := this._io.ReadU1()
if err != nil {
return err
}
this.Velocity = tmp18
return err
}
type StandardMidiFile_PitchBendEvent struct {
B1 uint8
B2 uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
_f_adjBendValue bool
adjBendValue int
_f_bendValue bool
bendValue int
}
func NewStandardMidiFile_PitchBendEvent() *StandardMidiFile_PitchBendEvent {
return &StandardMidiFile_PitchBendEvent{
}
}
func (this StandardMidiFile_PitchBendEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_PitchBendEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp19, err := this._io.ReadU1()
if err != nil {
return err
}
this.B1 = tmp19
tmp20, err := this._io.ReadU1()
if err != nil {
return err
}
this.B2 = tmp20
return err
}
func (this *StandardMidiFile_PitchBendEvent) AdjBendValue() (v int, err error) {
if (this._f_adjBendValue) {
return this.adjBendValue, nil
}
this._f_adjBendValue = true
tmp21, err := this.BendValue()
if err != nil {
return 0, err
}
this.adjBendValue = int(tmp21 - 16384)
return this.adjBendValue, nil
}
func (this *StandardMidiFile_PitchBendEvent) BendValue() (v int, err error) {
if (this._f_bendValue) {
return this.bendValue, nil
}
this._f_bendValue = true
this.bendValue = int((this.B2 << 7 + this.B1) - 16384)
return this.bendValue, nil
}
type StandardMidiFile_PolyphonicPressureEvent struct {
Note uint8
Pressure uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_PolyphonicPressureEvent() *StandardMidiFile_PolyphonicPressureEvent {
return &StandardMidiFile_PolyphonicPressureEvent{
}
}
func (this StandardMidiFile_PolyphonicPressureEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_PolyphonicPressureEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp22, err := this._io.ReadU1()
if err != nil {
return err
}
this.Note = tmp22
tmp23, err := this._io.ReadU1()
if err != nil {
return err
}
this.Pressure = tmp23
return err
}
type StandardMidiFile_ProgramChangeEvent struct {
Program uint8
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_ProgramChangeEvent() *StandardMidiFile_ProgramChangeEvent {
return &StandardMidiFile_ProgramChangeEvent{
}
}
func (this StandardMidiFile_ProgramChangeEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_ProgramChangeEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp24, err := this._io.ReadU1()
if err != nil {
return err
}
this.Program = tmp24
return err
}
type StandardMidiFile_SysexEventBody struct {
Len *VlqBase128Be
Data []byte
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvent
}
func NewStandardMidiFile_SysexEventBody() *StandardMidiFile_SysexEventBody {
return &StandardMidiFile_SysexEventBody{
}
}
func (this StandardMidiFile_SysexEventBody) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_SysexEventBody) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvent, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp25 := NewVlqBase128Be()
err = tmp25.Read(this._io, nil, nil)
if err != nil {
return err
}
this.Len = tmp25
tmp26, err := this.Len.Value()
if err != nil {
return err
}
tmp27, err := this._io.ReadBytes(int(tmp26))
if err != nil {
return err
}
tmp27 = tmp27
this.Data = tmp27
return err
}
type StandardMidiFile_Track struct {
Magic []byte
LenEvents uint32
Events *StandardMidiFile_TrackEvents
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile
_raw_Events []byte
}
func NewStandardMidiFile_Track() *StandardMidiFile_Track {
return &StandardMidiFile_Track{
}
}
func (this StandardMidiFile_Track) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_Track) Read(io *kaitai.Stream, parent *StandardMidiFile, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp28, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp28 = tmp28
this.Magic = tmp28
if !(bytes.Equal(this.Magic, []uint8{77, 84, 114, 107})) {
return kaitai.NewValidationNotEqualError([]uint8{77, 84, 114, 107}, this.Magic, this._io, "/types/track/seq/0")
}
tmp29, err := this._io.ReadU4be()
if err != nil {
return err
}
this.LenEvents = uint32(tmp29)
tmp30, err := this._io.ReadBytes(int(this.LenEvents))
if err != nil {
return err
}
tmp30 = tmp30
this._raw_Events = tmp30
_io__raw_Events := kaitai.NewStream(bytes.NewReader(this._raw_Events))
tmp31 := NewStandardMidiFile_TrackEvents()
err = tmp31.Read(_io__raw_Events, this, this._root)
if err != nil {
return err
}
this.Events = tmp31
return err
}
type StandardMidiFile_TrackEvent struct {
VTime *VlqBase128Be
EventHeader uint8
MetaEventBody *StandardMidiFile_MetaEventBody
SysexBody *StandardMidiFile_SysexEventBody
EventBody kaitai.Struct
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_TrackEvents
_f_channel bool
channel int
_f_eventType bool
eventType int
}
func NewStandardMidiFile_TrackEvent() *StandardMidiFile_TrackEvent {
return &StandardMidiFile_TrackEvent{
}
}
func (this StandardMidiFile_TrackEvent) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_TrackEvent) Read(io *kaitai.Stream, parent *StandardMidiFile_TrackEvents, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp32 := NewVlqBase128Be()
err = tmp32.Read(this._io, nil, nil)
if err != nil {
return err
}
this.VTime = tmp32
tmp33, err := this._io.ReadU1()
if err != nil {
return err
}
this.EventHeader = tmp33
if (this.EventHeader == 255) {
tmp34 := NewStandardMidiFile_MetaEventBody()
err = tmp34.Read(this._io, this, this._root)
if err != nil {
return err
}
this.MetaEventBody = tmp34
}
if (this.EventHeader == 240) {
tmp35 := NewStandardMidiFile_SysexEventBody()
err = tmp35.Read(this._io, this, this._root)
if err != nil {
return err
}
this.SysexBody = tmp35
}
tmp36, err := this.EventType()
if err != nil {
return err
}
switch (tmp36) {
case 128:
tmp37 := NewStandardMidiFile_NoteOffEvent()
err = tmp37.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp37
case 144:
tmp38 := NewStandardMidiFile_NoteOnEvent()
err = tmp38.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp38
case 160:
tmp39 := NewStandardMidiFile_PolyphonicPressureEvent()
err = tmp39.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp39
case 176:
tmp40 := NewStandardMidiFile_ControllerEvent()
err = tmp40.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp40
case 192:
tmp41 := NewStandardMidiFile_ProgramChangeEvent()
err = tmp41.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp41
case 208:
tmp42 := NewStandardMidiFile_ChannelPressureEvent()
err = tmp42.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp42
case 224:
tmp43 := NewStandardMidiFile_PitchBendEvent()
err = tmp43.Read(this._io, this, this._root)
if err != nil {
return err
}
this.EventBody = tmp43
}
return err
}
func (this *StandardMidiFile_TrackEvent) Channel() (v int, err error) {
if (this._f_channel) {
return this.channel, nil
}
this._f_channel = true
tmp44, err := this.EventType()
if err != nil {
return 0, err
}
if (tmp44 != 240) {
this.channel = int(this.EventHeader & 15)
}
return this.channel, nil
}
func (this *StandardMidiFile_TrackEvent) EventType() (v int, err error) {
if (this._f_eventType) {
return this.eventType, nil
}
this._f_eventType = true
this.eventType = int(this.EventHeader & 240)
return this.eventType, nil
}
type StandardMidiFile_TrackEvents struct {
Event []*StandardMidiFile_TrackEvent
_io *kaitai.Stream
_root *StandardMidiFile
_parent *StandardMidiFile_Track
}
func NewStandardMidiFile_TrackEvents() *StandardMidiFile_TrackEvents {
return &StandardMidiFile_TrackEvents{
}
}
func (this StandardMidiFile_TrackEvents) IO_() *kaitai.Stream {
return this._io
}
func (this *StandardMidiFile_TrackEvents) Read(io *kaitai.Stream, parent *StandardMidiFile_Track, root *StandardMidiFile) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0;; i++ {
tmp45, err := this._io.EOF()
if err != nil {
return err
}
if tmp45 {
break
}
tmp46 := NewStandardMidiFile_TrackEvent()
err = tmp46.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Event = append(this.Event, tmp46)
}
return err
}