cog/Frameworks/midi_processing/midi_processing/midi_container.h

269 lines
7.6 KiB
C++

#ifndef _MIDI_CONTAINER_H_
#define _MIDI_CONTAINER_H_
#include <stdint.h>
#include <string>
#include <vector>
#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<uint8_t> 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<midi_event> 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<tempo_entry> 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<uint8_t> m_data;
std::vector<system_exclusive_entry> 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<midi_meta_data_item> m_data;
std::vector<uint8_t> 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<uint8_t> & p_out );
void assign_bitmap( std::vector<uint8_t>::const_iterator const& begin, std::vector<uint8_t>::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<uint64_t> m_channel_mask;
std::vector<tempo_map> m_tempo_map;
std::vector<midi_track> m_tracks;
std::vector<uint8_t> m_port_numbers;
std::vector< std::vector< std::string > > m_device_names;
midi_meta_data m_extra_meta_data;
std::vector<unsigned long> m_timestamp_end;
std::vector<unsigned long> m_timestamp_loop_start;
std::vector<unsigned long> m_timestamp_loop_end;
unsigned long timestamp_to_ms( unsigned long p_timestamp, unsigned long p_subsong ) const;
/*
* Normalize port numbers properly
*/
template <typename T> 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 <typename T> 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<midi_stream_event> & 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<uint8_t> & 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<uint8_t> & p_out, unsigned long delta );
};
#endif