#ifndef _MIDI_CONTAINER_H_ #define _MIDI_CONTAINER_H_ #include #include #include #ifdef _MSC_VER #define strcasecmp _stricmp #define strncasecmp _strnicmp #define snprintf sprintf_s #endif struct midi_event { enum { max_static_data_count = 16 }; enum event_type { note_off = 0, note_on, polyphonic_aftertouch, control_change, program_change, channel_aftertouch, pitch_wheel, extended }; unsigned long m_timestamp; event_type m_type; unsigned m_channel; unsigned long m_data_count; uint8_t m_data[max_static_data_count]; std::vector m_ext_data; midi_event() : m_timestamp(0), m_type(note_off), m_channel(0), m_data_count(0) { } midi_event( const midi_event & p_in ); midi_event( unsigned long p_timestamp, event_type p_type, unsigned p_channel, const uint8_t * p_data, std::size_t p_data_count ); unsigned long get_data_count() const; void copy_data( uint8_t * p_out, unsigned long p_offset, unsigned long p_count ) const; }; class midi_track { std::vector m_events; public: midi_track() { } midi_track(const midi_track & p_in); void add_event( const midi_event & p_event ); std::size_t get_count() const; const midi_event & operator [] ( std::size_t p_index ) const; midi_event & operator [] ( std::size_t p_index ); void remove_event( unsigned long index ); }; struct tempo_entry { unsigned long m_timestamp; unsigned m_tempo; tempo_entry() : m_timestamp(0), m_tempo(0) { } tempo_entry(unsigned long p_timestamp, unsigned p_tempo); }; class tempo_map { std::vector m_entries; public: void add_tempo( unsigned p_tempo, unsigned long p_timestamp ); unsigned long timestamp_to_ms( unsigned long p_timestamp, unsigned p_dtx ) const; std::size_t get_count() const; const tempo_entry & operator [] ( std::size_t p_index ) const; tempo_entry & operator [] ( std::size_t p_index ); }; struct system_exclusive_entry { std::size_t m_port; std::size_t m_offset; std::size_t m_length; system_exclusive_entry() : m_port(0), m_offset(0), m_length(0) { } system_exclusive_entry(const system_exclusive_entry & p_in); system_exclusive_entry(std::size_t p_port, std::size_t p_offset, std::size_t p_length); }; class system_exclusive_table { std::vector m_data; std::vector m_entries; public: unsigned add_entry( const uint8_t * p_data, std::size_t p_size, std::size_t p_port ); void get_entry( unsigned p_index, const uint8_t * & p_data, std::size_t & p_size, std::size_t & p_port ); }; struct midi_stream_event { unsigned long m_timestamp; uint32_t m_event; midi_stream_event() : m_timestamp(0), m_event(0) { } midi_stream_event(unsigned long p_timestamp, uint32_t p_event); }; struct midi_meta_data_item { unsigned long m_timestamp; std::string m_name; std::string m_value; midi_meta_data_item() : m_timestamp(0) { } midi_meta_data_item(const midi_meta_data_item & p_in); midi_meta_data_item(unsigned long p_timestamp, const char * p_name, const char * p_value); }; class midi_meta_data { std::vector m_data; std::vector m_bitmap; public: midi_meta_data() { } void add_item( const midi_meta_data_item & p_item ); void append( const midi_meta_data & p_data ); bool get_item( const char * p_name, midi_meta_data_item & p_out ) const; bool get_bitmap( std::vector & p_out ); void assign_bitmap( std::vector::const_iterator const& begin, std::vector::const_iterator const& end ); std::size_t get_count() const; const midi_meta_data_item & operator [] ( std::size_t p_index ) const; }; class midi_container { public: enum { clean_flag_emidi = 1 << 0, clean_flag_instruments = 1 << 1, clean_flag_banks = 1 << 2, }; private: unsigned m_form; unsigned m_dtx; std::vector m_channel_mask; std::vector m_tempo_map; std::vector m_tracks; std::vector m_port_numbers; std::vector< std::vector< std::string > > m_device_names; midi_meta_data m_extra_meta_data; std::vector m_timestamp_end; std::vector m_timestamp_loop_start; std::vector m_timestamp_loop_end; unsigned long timestamp_to_ms( unsigned long p_timestamp, unsigned long p_subsong ) const; /* * Normalize port numbers properly */ template void limit_port_number(T & number) { for ( unsigned i = 0; i < m_port_numbers.size(); i++ ) { if ( m_port_numbers[ i ] == number ) { number = i; return; } } m_port_numbers.push_back( (const uint8_t) number ); number = m_port_numbers.size() - 1; } template void limit_port_number(T & number) const { for ( unsigned i = 0; i < m_port_numbers.size(); i++ ) { if ( m_port_numbers[ i ] == number ) { number = i; return; } } } public: midi_container() { m_device_names.resize( 16 ); } void initialize( unsigned p_form, unsigned p_dtx ); void add_track( const midi_track & p_track ); void add_track_event( std::size_t p_track_index, const midi_event & p_event ); /* * These functions are really only designed to merge and later remove System Exclusive message dumps */ void merge_tracks( const midi_container & p_source ); void set_track_count( unsigned count ); void set_extra_meta_data( const midi_meta_data & p_data ); /* * Blah. * Hack 0: Remove channel 16 * Hack 1: Remove channels 11-16 */ void apply_hackfix( unsigned hack ); void serialize_as_stream( unsigned long subsong, std::vector & p_stream, system_exclusive_table & p_system_exclusive, unsigned long & loop_start, unsigned long & loop_end, unsigned clean_flags ) const; void serialize_as_standard_midi_file( std::vector & p_midi_file ) const; void promote_to_type1(); void trim_start(); private: void trim_range_of_tracks(unsigned long start, unsigned long end); void trim_tempo_map(unsigned long p_index, unsigned long base_timestamp); public: typedef std::string(*split_callback)(uint8_t bank_msb, uint8_t bank_lsb, uint8_t instrument); void split_by_instrument_changes(split_callback cb = NULL); unsigned long get_subsong_count() const; unsigned long get_subsong( unsigned long p_index ) const; unsigned long get_timestamp_end(unsigned long subsong, bool ms = false) const; unsigned get_format() const; unsigned get_track_count() const; unsigned get_channel_count(unsigned long subsong) const; unsigned long get_timestamp_loop_start(unsigned long subsong, bool ms = false) const; unsigned long get_timestamp_loop_end(unsigned long subsong, bool ms = false) const; void get_meta_data( unsigned long subsong, midi_meta_data & p_out ); void scan_for_loops( bool p_xmi_loops, bool p_marker_loops, bool p_rpgmaker_loops, bool p_touhou_loops ); static void encode_delta( std::vector & p_out, unsigned long delta ); }; #endif