If you have an issue with any of our projects. feel free to register.

Commit f5c7c4d4 authored by Christopher Snowhill's avatar Christopher Snowhill

Update midi_processing to latest version, fixing some severe MIDI file...

Update midi_processing to latest version, fixing some severe MIDI file handling issues, including Standard MIDI file SysEx and SysEx continuation handling
parent 798cc4ce
......@@ -13,36 +13,36 @@
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;
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() : 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;
unsigned long get_data_count() const;
void copy_data( uint8_t * p_out, unsigned long p_offset, unsigned long p_count ) const;
};
......@@ -51,23 +51,24 @@ class midi_track
std::vector<midi_event> m_events;
public:
midi_track() { }
midi_track(const midi_track & p_in);
midi_track() { }
midi_track(const midi_track & p_in);
void add_event( const midi_event & p_event );
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;
unsigned long m_timestamp;
unsigned m_tempo;
tempo_entry() : m_timestamp(0), m_tempo(0) { }
tempo_entry(unsigned long p_timestamp, unsigned p_tempo);
tempo_entry() : m_timestamp(0), m_tempo(0) { }
tempo_entry(unsigned long p_timestamp, unsigned p_tempo);
};
class tempo_map
......@@ -75,11 +76,12 @@ class tempo_map
std::vector<tempo_entry> m_entries;
public:
void add_tempo( unsigned p_tempo, unsigned long p_timestamp );
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
......@@ -87,8 +89,8 @@ 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() : 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);
};
......@@ -104,42 +106,42 @@ public:
struct midi_stream_event
{
unsigned long m_timestamp;
uint32_t m_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);
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;
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);
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() { }
midi_meta_data() { }
void add_item( const midi_meta_data_item & p_item );
void add_item( const midi_meta_data_item & p_item );
void append( const midi_meta_data & p_data );
void append( const midi_meta_data & p_data );
bool get_item( const char * p_name, midi_meta_data_item & p_out ) const;
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;
......@@ -148,16 +150,16 @@ public:
class midi_container
{
public:
enum
{
clean_flag_emidi = 1 << 0,
clean_flag_instruments = 1 << 1,
clean_flag_banks = 1 << 2,
};
enum
{
clean_flag_emidi = 1 << 0,
clean_flag_instruments = 1 << 1,
clean_flag_banks = 1 << 2,
};
private:
unsigned m_form;
unsigned m_dtx;
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;
......@@ -166,7 +168,7 @@ private:
std::vector< std::vector< std::string > > m_device_names;
midi_meta_data m_extra_meta_data;
midi_meta_data m_extra_meta_data;
std::vector<unsigned long> m_timestamp_end;
......@@ -207,9 +209,9 @@ private:
public:
midi_container() { m_device_names.resize( 16 ); }
void initialize( unsigned p_form, unsigned p_dtx );
void initialize( unsigned p_form, unsigned p_dtx );
void add_track( const midi_track & p_track );
void add_track( const midi_track & p_track );
void add_track_event( std::size_t p_track_index, const midi_event & p_event );
......@@ -219,7 +221,7 @@ public:
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
......@@ -233,6 +235,17 @@ public:
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;
......@@ -245,9 +258,9 @@ public:
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 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 );
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 );
};
......
......@@ -51,14 +51,14 @@ class midi_processor
static bool process_lds( std::vector<uint8_t> const& p_file, midi_container & p_out );
static bool process_gmf( std::vector<uint8_t> const& p_file, midi_container & p_out );
static bool process_syx( std::vector<uint8_t> const& p_file, midi_container & p_out );
static bool process_standard_midi_count( std::vector<uint8_t> const& p_file, size_t & track_count );
static bool process_riff_midi_count( std::vector<uint8_t> const& p_file, size_t & track_count );
static bool process_xmi_count( std::vector<uint8_t> const& p_file, size_t & track_count );
public:
static bool process_track_count( std::vector<uint8_t> const& p_file, const char * p_extension, size_t & track_count );
static bool process_file( std::vector<uint8_t> const& p_file, const char * p_extension, midi_container & p_out );
static bool process_syx_file( std::vector<uint8_t> const& p_file, midi_container & p_out );
......
......@@ -4,47 +4,47 @@ bool midi_processor::is_gmf( std::vector<uint8_t> const& p_file )
{
if ( p_file.size() < 32 ) return false;
if ( p_file[ 0 ] != 'G' || p_file[ 1 ] != 'M' || p_file[ 2 ] != 'F' || p_file[ 3 ] != 1 ) return false;
return true;
return true;
}
bool midi_processor::process_gmf( std::vector<uint8_t> const& p_file, midi_container & p_out )
{
uint8_t buffer[10];
p_out.initialize( 0, 0xC0 );
p_out.initialize( 0, 0xC0 );
uint16_t tempo = ( p_file[ 4 ] << 8 ) | p_file[ 5 ];
uint32_t tempo_scaled = tempo * 100000;
midi_track track;
midi_track track;
buffer[0] = 0xFF;
buffer[1] = 0x51;
buffer[2] = tempo_scaled >> 16;
buffer[3] = tempo_scaled >> 8;
buffer[4] = tempo_scaled;
buffer[0] = 0xFF;
buffer[1] = 0x51;
buffer[2] = tempo_scaled >> 16;
buffer[3] = tempo_scaled >> 8;
buffer[4] = tempo_scaled;
track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 5 ) );
track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 5 ) );
buffer[0] = 0xF0;
buffer[1] = 0x41;
buffer[2] = 0x10;
buffer[3] = 0x16;
buffer[4] = 0x12;
buffer[5] = 0x7F;
buffer[6] = 0x00;
buffer[7] = 0x00;
buffer[8] = 0x01;
buffer[9] = 0xF7;
buffer[0] = 0xF0;
buffer[1] = 0x41;
buffer[2] = 0x10;
buffer[3] = 0x16;
buffer[4] = 0x12;
buffer[5] = 0x7F;
buffer[6] = 0x00;
buffer[7] = 0x00;
buffer[8] = 0x01;
buffer[9] = 0xF7;
track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 10 ) );
track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 10 ) );
buffer[0] = 0xFF;
buffer[1] = 0x2F;
buffer[0] = 0xFF;
buffer[1] = 0x2F;
track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 2 ) );
track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 2 ) );
p_out.add_track( track );
p_out.add_track( track );
std::vector<uint8_t>::const_iterator it = p_file.begin() + 7;
......
......@@ -6,54 +6,54 @@ const uint8_t midi_processor::loop_end[9] = {0xFF, 0x06, 'l', 'o', 'o', 'p',
int midi_processor::decode_delta( std::vector<uint8_t>::const_iterator & it, std::vector<uint8_t>::const_iterator end )
{
int delta = 0;
unsigned char byte;
do
{
if ( it == end ) return 0;
int delta = 0;
unsigned char byte;
do
{
if ( it == end ) return 0;
byte = *it++;
delta = ( delta << 7 ) + ( byte & 0x7F );
}
while ( byte & 0x80 );
return delta;
delta = ( delta << 7 ) + ( byte & 0x7F );
}
while ( byte & 0x80 );
return delta;
}
bool midi_processor::process_file( std::vector<uint8_t> const& p_file, const char * p_extension, midi_container & p_out )
{
if ( is_standard_midi( p_file ) )
{
{
return process_standard_midi( p_file, p_out );
}
}
else if ( is_riff_midi( p_file ) )
{
{
return process_riff_midi( p_file, p_out );
}
}
else if ( is_hmp( p_file ) )
{
{
return process_hmp( p_file, p_out );
}
else if ( is_hmi( p_file ) )
{
{
return process_hmi( p_file, p_out );
}
else if ( is_xmi( p_file ) )
{
{
return process_xmi( p_file, p_out );
}
else if ( is_mus( p_file ) )
{
{
return process_mus( p_file, p_out );
}
else if ( is_mids( p_file ) )
{
{
return process_mids( p_file, p_out );
}
else if ( is_lds( p_file, p_extension ) )
{
{
return process_lds( p_file, p_out );
}
else if ( is_gmf( p_file ) )
{
{
return process_gmf( p_file, p_out );
}
else return false;
......@@ -71,7 +71,7 @@ bool midi_processor::process_syx_file( std::vector<uint8_t> const& p_file, midi_
bool midi_processor::process_track_count( std::vector<uint8_t> const& p_file, const char * p_extension, size_t & track_count )
{
track_count = 0;
if ( is_standard_midi( p_file ) )
{
return process_standard_midi_count( p_file, track_count );
......
......@@ -13,18 +13,18 @@ bool midi_processor::is_hmp( std::vector<uint8_t> const& p_file )
unsigned midi_processor::decode_hmp_delta( std::vector<uint8_t>::const_iterator & it, std::vector<uint8_t>::const_iterator end )
{
unsigned delta = 0;
unsigned shift = 0;
unsigned char byte;
do
unsigned delta = 0;
unsigned shift = 0;
unsigned char byte;
do
{
if ( it == end ) return 0;
if ( it == end ) return 0;
byte = *it++;
delta = delta + ( ( byte & 0x7F ) << shift );
shift += 7;
}
while ( !( byte & 0x80 ) );
return delta;
delta = delta + ( ( byte & 0x7F ) << shift );
shift += 7;
}
while ( !( byte & 0x80 ) );
return delta;
}
bool midi_processor::process_hmp( std::vector<uint8_t> const& p_file, midi_container & p_out )
......@@ -34,87 +34,89 @@ bool midi_processor::process_hmp( std::vector<uint8_t> const& p_file, midi_conta
uint8_t track_count_8;
uint16_t dtx = 0xC0;
uint32_t offset = is_funky ? 0x1A : 0x30;
uint32_t offset = is_funky ? 0x1A : 0x30;
if ( offset >= p_file.size() )
return false;
if ( offset >= p_file.size() )
return false;
std::vector<uint8_t>::const_iterator it = p_file.begin() + offset;
std::vector<uint8_t>::const_iterator end = p_file.end();
std::vector<uint8_t>::const_iterator end = p_file.end();
track_count_8 = *it;
if ( is_funky )
if ( is_funky )
{
if ( p_file.size() <= 0x4D )
return false;
if ( p_file.size() <= 0x4D )
return false;
dtx = ( p_file[ 0x4C ] << 16 ) | p_file[ 0x4D ];
}
if ( !dtx ) // dtx == 0, will cause division by zero on tempo calculations
return false;
}
p_out.initialize( 1, dtx );
p_out.initialize( 1, dtx );
{
midi_track track;
track.add_event( midi_event( 0, midi_event::extended, 0, hmp_default_tempo, _countof( hmp_default_tempo ) ) );
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
p_out.add_track( track );
}
midi_track track;
track.add_event( midi_event( 0, midi_event::extended, 0, hmp_default_tempo, _countof( hmp_default_tempo ) ) );
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
p_out.add_track( track );
}
uint8_t buffer[ 4 ];
if ( it == end ) return false;
if ( it == end ) return false;
buffer[ 0 ] = *it++;
while ( it != end )
{
if ( buffer[ 0 ] != 0xFF )
{
{
if ( buffer[ 0 ] != 0xFF )
{
buffer[ 0 ] = *it++;
continue;
}
if ( it == end ) break;
continue;
}
if ( it == end ) break;
buffer[ 1 ] = *it++;
if ( buffer[ 1 ] != 0x2F )
{
buffer[ 0 ] = buffer[ 1 ];
continue;
}
break;
}
offset = is_funky ? 3 : 5;
if ( (unsigned long)(end - it) < offset ) return false;
if ( buffer[ 1 ] != 0x2F )
{
buffer[ 0 ] = buffer[ 1 ];
continue;
}
break;
}
offset = is_funky ? 3 : 5;
if ( (unsigned long)(end - it) < offset ) return false;
it += offset;
unsigned track_count = track_count_8;
unsigned track_count = track_count_8;
for ( unsigned i = 1; i < track_count; ++i )
{
for ( unsigned i = 1; i < track_count; ++i )
{
uint16_t track_size_16;
uint32_t track_size_32;
if ( is_funky )
{
if ( end - it < 4 ) break;
if ( is_funky )
{
if ( end - it < 4 ) break;
track_size_16 = it[ 0 ] | ( it[ 1 ] << 8 );
it += 2;
track_size_32 = track_size_16 - 4;
if ( (unsigned long)(end - it) < track_size_32 + 2 ) break;
it += 2;
}
else
{
if ( end - it < 8 ) break;
}
else
{
if ( end - it < 8 ) break;
track_size_32 = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
it += 4;
track_size_32 -= 12;
track_size_32 -= 12;
if ( (unsigned long)(end - it) < track_size_32 + 8 ) break;
it += 4;
}
}
midi_track track;
midi_track track;
unsigned current_timestamp = 0;
unsigned current_timestamp = 0;
std::vector<uint8_t> _buffer;
_buffer.resize( 3 );
......@@ -122,47 +124,47 @@ bool midi_processor::process_hmp( std::vector<uint8_t> const& p_file, midi_conta