Standard MIDI file: C++98/STL parsing library

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.

File extension

["mid", "midi", "smf"]

KS implementation details

License: CC0-1.0

References

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.

Usage

Runtime library

All parsing code for C++98/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.mid", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    standard_midi_file_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.hdr() // => get hdr

C++98/STL source code to parse Standard MIDI file

standard_midi_file.h

#ifndef STANDARD_MIDI_FILE_H_
#define STANDARD_MIDI_FILE_H_

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include "vlq_base128_be.h"
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class vlq_base128_be_t;

/**
 * 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.
 */

class standard_midi_file_t : public kaitai::kstruct {

public:
    class track_events_t;
    class track_event_t;
    class pitch_bend_event_t;
    class program_change_event_t;
    class note_on_event_t;
    class polyphonic_pressure_event_t;
    class track_t;
    class meta_event_body_t;
    class controller_event_t;
    class header_t;
    class sysex_event_body_t;
    class note_off_event_t;
    class channel_pressure_event_t;

    standard_midi_file_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, standard_midi_file_t* p__root = 0);

private:
    void _read();
    void _clean_up();

public:
    ~standard_midi_file_t();

    class track_events_t : public kaitai::kstruct {

    public:

        track_events_t(kaitai::kstream* p__io, standard_midi_file_t::track_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~track_events_t();

    private:
        std::vector<track_event_t*>* m_event;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_t* m__parent;

    public:
        std::vector<track_event_t*>* event() const { return m_event; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_t* _parent() const { return m__parent; }
    };

    class track_event_t : public kaitai::kstruct {

    public:

        track_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_events_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~track_event_t();

    private:
        bool f_event_type;
        int32_t m_event_type;

    public:
        int32_t event_type();

    private:
        bool f_channel;
        int32_t m_channel;
        bool n_channel;

    public:
        bool _is_null_channel() { channel(); return n_channel; };

    private:

    public:
        int32_t channel();

    private:
        vlq_base128_be_t* m_v_time;
        uint8_t m_event_header;
        meta_event_body_t* m_meta_event_body;
        bool n_meta_event_body;

    public:
        bool _is_null_meta_event_body() { meta_event_body(); return n_meta_event_body; };

    private:
        sysex_event_body_t* m_sysex_body;
        bool n_sysex_body;

    public:
        bool _is_null_sysex_body() { sysex_body(); return n_sysex_body; };

    private:
        kaitai::kstruct* m_event_body;
        bool n_event_body;

    public:
        bool _is_null_event_body() { event_body(); return n_event_body; };

    private:
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_events_t* m__parent;

    public:
        vlq_base128_be_t* v_time() const { return m_v_time; }
        uint8_t event_header() const { return m_event_header; }
        meta_event_body_t* meta_event_body() const { return m_meta_event_body; }
        sysex_event_body_t* sysex_body() const { return m_sysex_body; }
        kaitai::kstruct* event_body() const { return m_event_body; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_events_t* _parent() const { return m__parent; }
    };

    class pitch_bend_event_t : public kaitai::kstruct {

    public:

        pitch_bend_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~pitch_bend_event_t();

    private:
        bool f_bend_value;
        int32_t m_bend_value;

    public:
        int32_t bend_value();

    private:
        bool f_adj_bend_value;
        int32_t m_adj_bend_value;

    public:
        int32_t adj_bend_value();

    private:
        uint8_t m_b1;
        uint8_t m_b2;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t b1() const { return m_b1; }
        uint8_t b2() const { return m_b2; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class program_change_event_t : public kaitai::kstruct {

    public:

        program_change_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~program_change_event_t();

    private:
        uint8_t m_program;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t program() const { return m_program; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class note_on_event_t : public kaitai::kstruct {

    public:

        note_on_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~note_on_event_t();

    private:
        uint8_t m_note;
        uint8_t m_velocity;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t note() const { return m_note; }
        uint8_t velocity() const { return m_velocity; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class polyphonic_pressure_event_t : public kaitai::kstruct {

    public:

        polyphonic_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~polyphonic_pressure_event_t();

    private:
        uint8_t m_note;
        uint8_t m_pressure;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t note() const { return m_note; }
        uint8_t pressure() const { return m_pressure; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class track_t : public kaitai::kstruct {

    public:

        track_t(kaitai::kstream* p__io, standard_midi_file_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~track_t();

    private:
        std::string m_magic;
        uint32_t m_len_events;
        track_events_t* m_events;
        standard_midi_file_t* m__root;
        standard_midi_file_t* m__parent;
        std::string m__raw_events;
        kaitai::kstream* m__io__raw_events;

    public:
        std::string magic() const { return m_magic; }
        uint32_t len_events() const { return m_len_events; }
        track_events_t* events() const { return m_events; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t* _parent() const { return m__parent; }
        std::string _raw_events() const { return m__raw_events; }
        kaitai::kstream* _io__raw_events() const { return m__io__raw_events; }
    };

    class meta_event_body_t : public kaitai::kstruct {

    public:

        enum meta_type_enum_t {
            META_TYPE_ENUM_SEQUENCE_NUMBER = 0,
            META_TYPE_ENUM_TEXT_EVENT = 1,
            META_TYPE_ENUM_COPYRIGHT = 2,
            META_TYPE_ENUM_SEQUENCE_TRACK_NAME = 3,
            META_TYPE_ENUM_INSTRUMENT_NAME = 4,
            META_TYPE_ENUM_LYRIC_TEXT = 5,
            META_TYPE_ENUM_MARKER_TEXT = 6,
            META_TYPE_ENUM_CUE_POINT = 7,
            META_TYPE_ENUM_MIDI_CHANNEL_PREFIX_ASSIGNMENT = 32,
            META_TYPE_ENUM_END_OF_TRACK = 47,
            META_TYPE_ENUM_TEMPO = 81,
            META_TYPE_ENUM_SMPTE_OFFSET = 84,
            META_TYPE_ENUM_TIME_SIGNATURE = 88,
            META_TYPE_ENUM_KEY_SIGNATURE = 89,
            META_TYPE_ENUM_SEQUENCER_SPECIFIC_EVENT = 127
        };

        meta_event_body_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~meta_event_body_t();

    private:
        meta_type_enum_t m_meta_type;
        vlq_base128_be_t* m_len;
        std::string m_body;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        meta_type_enum_t meta_type() const { return m_meta_type; }
        vlq_base128_be_t* len() const { return m_len; }
        std::string body() const { return m_body; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class controller_event_t : public kaitai::kstruct {

    public:

        controller_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~controller_event_t();

    private:
        uint8_t m_controller;
        uint8_t m_value;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t controller() const { return m_controller; }
        uint8_t value() const { return m_value; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class header_t : public kaitai::kstruct {

    public:

        header_t(kaitai::kstream* p__io, standard_midi_file_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~header_t();

    private:
        std::string m_magic;
        uint32_t m_len_header;
        uint16_t m_format;
        uint16_t m_num_tracks;
        int16_t m_division;
        standard_midi_file_t* m__root;
        standard_midi_file_t* m__parent;

    public:
        std::string magic() const { return m_magic; }
        uint32_t len_header() const { return m_len_header; }
        uint16_t format() const { return m_format; }
        uint16_t num_tracks() const { return m_num_tracks; }
        int16_t division() const { return m_division; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t* _parent() const { return m__parent; }
    };

    class sysex_event_body_t : public kaitai::kstruct {

    public:

        sysex_event_body_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~sysex_event_body_t();

    private:
        vlq_base128_be_t* m_len;
        std::string m_data;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        vlq_base128_be_t* len() const { return m_len; }
        std::string data() const { return m_data; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class note_off_event_t : public kaitai::kstruct {

    public:

        note_off_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~note_off_event_t();

    private:
        uint8_t m_note;
        uint8_t m_velocity;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t note() const { return m_note; }
        uint8_t velocity() const { return m_velocity; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

    class channel_pressure_event_t : public kaitai::kstruct {

    public:

        channel_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent = 0, standard_midi_file_t* p__root = 0);

    private:
        void _read();
        void _clean_up();

    public:
        ~channel_pressure_event_t();

    private:
        uint8_t m_pressure;
        standard_midi_file_t* m__root;
        standard_midi_file_t::track_event_t* m__parent;

    public:
        uint8_t pressure() const { return m_pressure; }
        standard_midi_file_t* _root() const { return m__root; }
        standard_midi_file_t::track_event_t* _parent() const { return m__parent; }
    };

private:
    header_t* m_hdr;
    std::vector<track_t*>* m_tracks;
    standard_midi_file_t* m__root;
    kaitai::kstruct* m__parent;

public:
    header_t* hdr() const { return m_hdr; }
    std::vector<track_t*>* tracks() const { return m_tracks; }
    standard_midi_file_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // STANDARD_MIDI_FILE_H_

standard_midi_file.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "standard_midi_file.h"
#include "kaitai/exceptions.h"

standard_midi_file_t::standard_midi_file_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_hdr = 0;
    m_tracks = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::_read() {
    m_hdr = new header_t(m__io, this, m__root);
    m_tracks = new std::vector<track_t*>();
    const int l_tracks = hdr()->num_tracks();
    for (int i = 0; i < l_tracks; i++) {
        m_tracks->push_back(new track_t(m__io, this, m__root));
    }
}

standard_midi_file_t::~standard_midi_file_t() {
    _clean_up();
}

void standard_midi_file_t::_clean_up() {
    if (m_hdr) {
        delete m_hdr; m_hdr = 0;
    }
    if (m_tracks) {
        for (std::vector<track_t*>::iterator it = m_tracks->begin(); it != m_tracks->end(); ++it) {
            delete *it;
        }
        delete m_tracks; m_tracks = 0;
    }
}

standard_midi_file_t::track_events_t::track_events_t(kaitai::kstream* p__io, standard_midi_file_t::track_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_event = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::track_events_t::_read() {
    m_event = new std::vector<track_event_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_event->push_back(new track_event_t(m__io, this, m__root));
            i++;
        }
    }
}

standard_midi_file_t::track_events_t::~track_events_t() {
    _clean_up();
}

void standard_midi_file_t::track_events_t::_clean_up() {
    if (m_event) {
        for (std::vector<track_event_t*>::iterator it = m_event->begin(); it != m_event->end(); ++it) {
            delete *it;
        }
        delete m_event; m_event = 0;
    }
}

standard_midi_file_t::track_event_t::track_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_events_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_v_time = 0;
    m_meta_event_body = 0;
    m_sysex_body = 0;
    f_event_type = false;
    f_channel = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::track_event_t::_read() {
    m_v_time = new vlq_base128_be_t(m__io);
    m_event_header = m__io->read_u1();
    n_meta_event_body = true;
    if (event_header() == 255) {
        n_meta_event_body = false;
        m_meta_event_body = new meta_event_body_t(m__io, this, m__root);
    }
    n_sysex_body = true;
    if (event_header() == 240) {
        n_sysex_body = false;
        m_sysex_body = new sysex_event_body_t(m__io, this, m__root);
    }
    n_event_body = true;
    switch (event_type()) {
    case 224: {
        n_event_body = false;
        m_event_body = new pitch_bend_event_t(m__io, this, m__root);
        break;
    }
    case 144: {
        n_event_body = false;
        m_event_body = new note_on_event_t(m__io, this, m__root);
        break;
    }
    case 208: {
        n_event_body = false;
        m_event_body = new channel_pressure_event_t(m__io, this, m__root);
        break;
    }
    case 192: {
        n_event_body = false;
        m_event_body = new program_change_event_t(m__io, this, m__root);
        break;
    }
    case 160: {
        n_event_body = false;
        m_event_body = new polyphonic_pressure_event_t(m__io, this, m__root);
        break;
    }
    case 176: {
        n_event_body = false;
        m_event_body = new controller_event_t(m__io, this, m__root);
        break;
    }
    case 128: {
        n_event_body = false;
        m_event_body = new note_off_event_t(m__io, this, m__root);
        break;
    }
    }
}

standard_midi_file_t::track_event_t::~track_event_t() {
    _clean_up();
}

void standard_midi_file_t::track_event_t::_clean_up() {
    if (m_v_time) {
        delete m_v_time; m_v_time = 0;
    }
    if (!n_meta_event_body) {
        if (m_meta_event_body) {
            delete m_meta_event_body; m_meta_event_body = 0;
        }
    }
    if (!n_sysex_body) {
        if (m_sysex_body) {
            delete m_sysex_body; m_sysex_body = 0;
        }
    }
    if (!n_event_body) {
        if (m_event_body) {
            delete m_event_body; m_event_body = 0;
        }
    }
}

int32_t standard_midi_file_t::track_event_t::event_type() {
    if (f_event_type)
        return m_event_type;
    m_event_type = (event_header() & 240);
    f_event_type = true;
    return m_event_type;
}

int32_t standard_midi_file_t::track_event_t::channel() {
    if (f_channel)
        return m_channel;
    n_channel = true;
    if (event_type() != 240) {
        n_channel = false;
        m_channel = (event_header() & 15);
    }
    f_channel = true;
    return m_channel;
}

standard_midi_file_t::pitch_bend_event_t::pitch_bend_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_bend_value = false;
    f_adj_bend_value = false;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::pitch_bend_event_t::_read() {
    m_b1 = m__io->read_u1();
    m_b2 = m__io->read_u1();
}

standard_midi_file_t::pitch_bend_event_t::~pitch_bend_event_t() {
    _clean_up();
}

void standard_midi_file_t::pitch_bend_event_t::_clean_up() {
}

int32_t standard_midi_file_t::pitch_bend_event_t::bend_value() {
    if (f_bend_value)
        return m_bend_value;
    m_bend_value = (((b2() << 7) + b1()) - 16384);
    f_bend_value = true;
    return m_bend_value;
}

int32_t standard_midi_file_t::pitch_bend_event_t::adj_bend_value() {
    if (f_adj_bend_value)
        return m_adj_bend_value;
    m_adj_bend_value = (bend_value() - 16384);
    f_adj_bend_value = true;
    return m_adj_bend_value;
}

standard_midi_file_t::program_change_event_t::program_change_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::program_change_event_t::_read() {
    m_program = m__io->read_u1();
}

standard_midi_file_t::program_change_event_t::~program_change_event_t() {
    _clean_up();
}

void standard_midi_file_t::program_change_event_t::_clean_up() {
}

standard_midi_file_t::note_on_event_t::note_on_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::note_on_event_t::_read() {
    m_note = m__io->read_u1();
    m_velocity = m__io->read_u1();
}

standard_midi_file_t::note_on_event_t::~note_on_event_t() {
    _clean_up();
}

void standard_midi_file_t::note_on_event_t::_clean_up() {
}

standard_midi_file_t::polyphonic_pressure_event_t::polyphonic_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::polyphonic_pressure_event_t::_read() {
    m_note = m__io->read_u1();
    m_pressure = m__io->read_u1();
}

standard_midi_file_t::polyphonic_pressure_event_t::~polyphonic_pressure_event_t() {
    _clean_up();
}

void standard_midi_file_t::polyphonic_pressure_event_t::_clean_up() {
}

standard_midi_file_t::track_t::track_t(kaitai::kstream* p__io, standard_midi_file_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_events = 0;
    m__io__raw_events = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::track_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x4D\x54\x72\x6B", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x4D\x54\x72\x6B", 4), magic(), _io(), std::string("/types/track/seq/0"));
    }
    m_len_events = m__io->read_u4be();
    m__raw_events = m__io->read_bytes(len_events());
    m__io__raw_events = new kaitai::kstream(m__raw_events);
    m_events = new track_events_t(m__io__raw_events, this, m__root);
}

standard_midi_file_t::track_t::~track_t() {
    _clean_up();
}

void standard_midi_file_t::track_t::_clean_up() {
    if (m__io__raw_events) {
        delete m__io__raw_events; m__io__raw_events = 0;
    }
    if (m_events) {
        delete m_events; m_events = 0;
    }
}

standard_midi_file_t::meta_event_body_t::meta_event_body_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_len = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::meta_event_body_t::_read() {
    m_meta_type = static_cast<standard_midi_file_t::meta_event_body_t::meta_type_enum_t>(m__io->read_u1());
    m_len = new vlq_base128_be_t(m__io);
    m_body = m__io->read_bytes(len()->value());
}

standard_midi_file_t::meta_event_body_t::~meta_event_body_t() {
    _clean_up();
}

void standard_midi_file_t::meta_event_body_t::_clean_up() {
    if (m_len) {
        delete m_len; m_len = 0;
    }
}

standard_midi_file_t::controller_event_t::controller_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::controller_event_t::_read() {
    m_controller = m__io->read_u1();
    m_value = m__io->read_u1();
}

standard_midi_file_t::controller_event_t::~controller_event_t() {
    _clean_up();
}

void standard_midi_file_t::controller_event_t::_clean_up() {
}

standard_midi_file_t::header_t::header_t(kaitai::kstream* p__io, standard_midi_file_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::header_t::_read() {
    m_magic = m__io->read_bytes(4);
    if (!(magic() == std::string("\x4D\x54\x68\x64", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x4D\x54\x68\x64", 4), magic(), _io(), std::string("/types/header/seq/0"));
    }
    m_len_header = m__io->read_u4be();
    m_format = m__io->read_u2be();
    m_num_tracks = m__io->read_u2be();
    m_division = m__io->read_s2be();
}

standard_midi_file_t::header_t::~header_t() {
    _clean_up();
}

void standard_midi_file_t::header_t::_clean_up() {
}

standard_midi_file_t::sysex_event_body_t::sysex_event_body_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_len = 0;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::sysex_event_body_t::_read() {
    m_len = new vlq_base128_be_t(m__io);
    m_data = m__io->read_bytes(len()->value());
}

standard_midi_file_t::sysex_event_body_t::~sysex_event_body_t() {
    _clean_up();
}

void standard_midi_file_t::sysex_event_body_t::_clean_up() {
    if (m_len) {
        delete m_len; m_len = 0;
    }
}

standard_midi_file_t::note_off_event_t::note_off_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::note_off_event_t::_read() {
    m_note = m__io->read_u1();
    m_velocity = m__io->read_u1();
}

standard_midi_file_t::note_off_event_t::~note_off_event_t() {
    _clean_up();
}

void standard_midi_file_t::note_off_event_t::_clean_up() {
}

standard_midi_file_t::channel_pressure_event_t::channel_pressure_event_t(kaitai::kstream* p__io, standard_midi_file_t::track_event_t* p__parent, standard_midi_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;

    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}

void standard_midi_file_t::channel_pressure_event_t::_read() {
    m_pressure = m__io->read_u1();
}

standard_midi_file_t::channel_pressure_event_t::~channel_pressure_event_t() {
    _clean_up();
}

void standard_midi_file_t::channel_pressure_event_t::_clean_up() {
}