diff --git a/Frameworks/midi_processing/midi_processing/midi_container.cpp b/Frameworks/midi_processing/midi_processing/midi_container.cpp index d090b58da..3c0aabd96 100644 --- a/Frameworks/midi_processing/midi_processing/midi_container.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_container.cpp @@ -6,30 +6,30 @@ midi_event::midi_event( const midi_event & p_in ) { - m_timestamp = p_in.m_timestamp; - m_channel = p_in.m_channel; - m_type = p_in.m_type; - m_data_count = p_in.m_data_count; - memcpy( m_data, p_in.m_data, m_data_count ); - m_ext_data = p_in.m_ext_data; + m_timestamp = p_in.m_timestamp; + m_channel = p_in.m_channel; + m_type = p_in.m_type; + m_data_count = p_in.m_data_count; + memcpy( m_data, p_in.m_data, m_data_count ); + m_ext_data = p_in.m_ext_data; } midi_event::midi_event( unsigned long p_timestamp, event_type p_type, unsigned p_channel, const uint8_t * p_data, std::size_t p_data_count ) { - m_timestamp = p_timestamp; - m_type = p_type; - m_channel = p_channel; - if ( p_data_count <= max_static_data_count ) - { - m_data_count = p_data_count; - memcpy( m_data, p_data, p_data_count ); - } - else - { - m_data_count = max_static_data_count; - memcpy( m_data, p_data, max_static_data_count ); + m_timestamp = p_timestamp; + m_type = p_type; + m_channel = p_channel; + if ( p_data_count <= max_static_data_count ) + { + m_data_count = p_data_count; + memcpy( m_data, p_data, p_data_count ); + } + else + { + m_data_count = max_static_data_count; + memcpy( m_data, p_data, max_static_data_count ); m_ext_data.assign( p_data + max_static_data_count, p_data + p_data_count ); - } + } } unsigned long midi_event::get_data_count() const @@ -41,21 +41,21 @@ void midi_event::copy_data( uint8_t * p_out, unsigned long p_offset, unsigned lo { unsigned long max_count = m_data_count + m_ext_data.size() - p_offset; p_count = std::min( p_count, max_count ); - if ( p_offset < max_static_data_count ) - { - unsigned long _max_count = max_static_data_count - p_offset; + if ( p_offset < max_static_data_count ) + { + unsigned long _max_count = max_static_data_count - p_offset; unsigned long count = std::min( _max_count, p_count ); - memcpy( p_out, m_data + p_offset, count ); - p_offset -= count; - p_count -= count; - p_out += count; - } + memcpy( p_out, m_data + p_offset, count ); + p_offset -= count; + p_count -= count; + p_out += count; + } if ( p_count ) memcpy( p_out, &m_ext_data[0], p_count ); } midi_track::midi_track(const midi_track & p_in) { - m_events = p_in.m_events; + m_events = p_in.m_events; } void midi_track::add_event( const midi_event & p_event ) @@ -63,24 +63,24 @@ void midi_track::add_event( const midi_event & p_event ) auto it = m_events.end(); if ( m_events.size() ) - { + { midi_event & event = *(it - 1); - if ( event.m_type == midi_event::extended && event.get_data_count() >= 2 && - event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x2F ) - { + if ( event.m_type == midi_event::extended && event.get_data_count() >= 2 && + event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x2F ) + { --it; - if ( event.m_timestamp < p_event.m_timestamp ) - { - event.m_timestamp = p_event.m_timestamp; - } - } + if ( event.m_timestamp < p_event.m_timestamp ) + { + event.m_timestamp = p_event.m_timestamp; + } + } while ( it > m_events.begin() ) - { + { if ( (*( it - 1 )).m_timestamp <= p_event.m_timestamp ) break; --it; - } - } + } + } m_events.insert( it, p_event ); } @@ -92,7 +92,12 @@ std::size_t midi_track::get_count() const const midi_event & midi_track::operator [] ( std::size_t p_index ) const { - return m_events[ p_index ]; + return m_events[ p_index ]; +} + +midi_event & midi_track::operator [] ( std::size_t p_index ) +{ + return m_events[ p_index ]; } void midi_track::remove_event( unsigned long index ) @@ -102,8 +107,8 @@ void midi_track::remove_event( unsigned long index ) tempo_entry::tempo_entry(unsigned long p_timestamp, unsigned p_tempo) { - m_timestamp = p_timestamp; - m_tempo = p_tempo; + m_timestamp = p_timestamp; + m_tempo = p_tempo; } void tempo_map::add_tempo( unsigned p_tempo, unsigned long p_timestamp ) @@ -111,44 +116,44 @@ void tempo_map::add_tempo( unsigned p_tempo, unsigned long p_timestamp ) auto it = m_entries.end(); while ( it > m_entries.begin() ) - { + { if ( (*( it - 1 )).m_timestamp <= p_timestamp ) break; --it; - } + } if ( it > m_entries.begin() && (*( it - 1 )).m_timestamp == p_timestamp ) - { + { (*( it - 1 )).m_tempo = p_tempo; - } - else - { + } + else + { m_entries.insert( it, tempo_entry( p_timestamp, p_tempo ) ); - } + } } unsigned long tempo_map::timestamp_to_ms( unsigned long p_timestamp, unsigned p_dtx ) const { - unsigned long timestamp_ms = 0; - unsigned long timestamp = 0; + unsigned long timestamp_ms = 0; + unsigned long timestamp = 0; auto tempo_it = m_entries.begin(); - unsigned current_tempo = 500000; + unsigned current_tempo = 500000; unsigned half_dtx = p_dtx * 500; p_dtx = half_dtx * 2; while ( tempo_it < m_entries.end() && timestamp + p_timestamp >= (*tempo_it).m_timestamp ) - { + { unsigned long delta = (*tempo_it).m_timestamp - timestamp; timestamp_ms += ((uint64_t)current_tempo * (uint64_t)delta + half_dtx) / p_dtx; current_tempo = (*tempo_it).m_tempo; ++tempo_it; - timestamp += delta; - p_timestamp -= delta; - } + timestamp += delta; + p_timestamp -= delta; + } timestamp_ms += ((uint64_t)current_tempo * (uint64_t)p_timestamp + half_dtx) / p_dtx; - return timestamp_ms; + return timestamp_ms; } std::size_t tempo_map::get_count() const @@ -158,31 +163,36 @@ std::size_t tempo_map::get_count() const const tempo_entry & tempo_map::operator [] ( std::size_t p_index ) const { - return m_entries[ p_index ]; + return m_entries[ p_index ]; +} + +tempo_entry & tempo_map::operator [] ( std::size_t p_index ) +{ + return m_entries[ p_index ]; } system_exclusive_entry::system_exclusive_entry(const system_exclusive_entry & p_in) { - m_port = p_in.m_port; - m_offset = p_in.m_offset; - m_length = p_in.m_length; + m_port = p_in.m_port; + m_offset = p_in.m_offset; + m_length = p_in.m_length; } system_exclusive_entry::system_exclusive_entry(std::size_t p_port, std::size_t p_offset, std::size_t p_length) { - m_port = p_port; - m_offset = p_offset; - m_length = p_length; + m_port = p_port; + m_offset = p_offset; + m_length = p_length; } unsigned system_exclusive_table::add_entry( const uint8_t * p_data, std::size_t p_size, std::size_t p_port ) { for ( auto it = m_entries.begin(); it < m_entries.end(); ++it ) - { + { const system_exclusive_entry & entry = *it; if ( p_port == entry.m_port && p_size == entry.m_length && !memcmp( p_data, &m_data[ entry.m_offset ], p_size ) ) return ((unsigned)(it - m_entries.begin())); - } + } system_exclusive_entry entry( p_port, m_data.size(), p_size ); m_data.insert( m_data.end(), p_data, p_data + p_size ); m_entries.push_back( entry ); @@ -191,30 +201,30 @@ unsigned system_exclusive_table::add_entry( const uint8_t * p_data, std::size_t void system_exclusive_table::get_entry( unsigned p_index, const uint8_t * & p_data, std::size_t & p_size, std::size_t & p_port ) { - const system_exclusive_entry & entry = m_entries[ p_index ]; + const system_exclusive_entry & entry = m_entries[ p_index ]; p_data = &m_data[ entry.m_offset ]; - p_size = entry.m_length; - p_port = entry.m_port; + p_size = entry.m_length; + p_port = entry.m_port; } midi_stream_event::midi_stream_event(unsigned long p_timestamp, unsigned p_event) { - m_timestamp = p_timestamp; - m_event = p_event; + m_timestamp = p_timestamp; + m_event = p_event; } midi_meta_data_item::midi_meta_data_item(const midi_meta_data_item & p_in) { - m_timestamp = p_in.m_timestamp; - m_name = p_in.m_name; - m_value = p_in.m_value; + m_timestamp = p_in.m_timestamp; + m_name = p_in.m_name; + m_value = p_in.m_value; } midi_meta_data_item::midi_meta_data_item(unsigned long p_timestamp, const char * p_name, const char * p_value) { - m_timestamp = p_timestamp; - m_name = p_name; - m_value = p_value; + m_timestamp = p_timestamp; + m_name = p_name; + m_value = p_value; } void midi_meta_data::add_item( const midi_meta_data_item & p_item ) @@ -231,15 +241,15 @@ void midi_meta_data::append( const midi_meta_data & p_data ) bool midi_meta_data::get_item( const char * p_name, midi_meta_data_item & p_out ) const { for ( unsigned i = 0; i < m_data.size(); ++i ) - { - const midi_meta_data_item & item = m_data[ i ]; + { + const midi_meta_data_item & item = m_data[ i ]; if ( !strcasecmp( p_name, item.m_name.c_str() ) ) - { - p_out = item; - return true; - } - } - return false; + { + p_out = item; + return true; + } + } + return false; } bool midi_meta_data::get_bitmap( std::vector & p_out ) @@ -260,208 +270,206 @@ std::size_t midi_meta_data::get_count() const const midi_meta_data_item & midi_meta_data::operator [] ( std::size_t p_index ) const { - return m_data[ p_index ]; + return m_data[ p_index ]; } void midi_container::encode_delta( std::vector & p_out, unsigned long delta ) { - unsigned shift = 7 * 4; - while ( shift && !( delta >> shift ) ) - { - shift -= 7; - } - while (shift > 0) - { + unsigned shift = 7 * 4; + while ( shift && !( delta >> shift ) ) + { + shift -= 7; + } + while (shift > 0) + { p_out.push_back( (unsigned char)( ( ( delta >> shift ) & 0x7F ) | 0x80 ) ); - shift -= 7; - } + shift -= 7; + } p_out.push_back( (unsigned char)( delta & 0x7F ) ); } unsigned long midi_container::timestamp_to_ms( unsigned long p_timestamp, unsigned long p_subsong ) const { - unsigned long timestamp_ms = 0; - unsigned long timestamp = 0; + unsigned long timestamp_ms = 0; + unsigned long timestamp = 0; std::size_t tempo_index = 0; - unsigned current_tempo = 500000; + unsigned current_tempo = 500000; unsigned half_dtx = m_dtx * 500; unsigned p_dtx = half_dtx * 2; unsigned long subsong_count = m_tempo_map.size(); - if ( p_subsong && subsong_count ) - { + if ( p_subsong && subsong_count ) + { for ( unsigned long i = std::min( p_subsong, subsong_count ); --i; ) - { - unsigned long count = m_tempo_map[ i ].get_count(); - if ( count ) - { - current_tempo = m_tempo_map[ i ][ count - 1 ].m_tempo; - break; - } - } - } + { + unsigned long count = m_tempo_map[ i ].get_count(); + if ( count ) + { + current_tempo = m_tempo_map[ i ][ count - 1 ].m_tempo; + break; + } + } + } - if ( p_subsong < subsong_count ) - { - const tempo_map & m_entries = m_tempo_map[ p_subsong ]; + if ( p_subsong < subsong_count ) + { + const tempo_map & m_entries = m_tempo_map[ p_subsong ]; std::size_t tempo_count = m_entries.get_count(); - while ( tempo_index < tempo_count && timestamp + p_timestamp >= m_entries[ tempo_index ].m_timestamp ) - { - unsigned long delta = m_entries[ tempo_index ].m_timestamp - timestamp; + while ( tempo_index < tempo_count && timestamp + p_timestamp >= m_entries[ tempo_index ].m_timestamp ) + { + unsigned long delta = m_entries[ tempo_index ].m_timestamp - timestamp; timestamp_ms += ((uint64_t)current_tempo * (uint64_t)delta + half_dtx) / p_dtx; - current_tempo = m_entries[ tempo_index ].m_tempo; - ++tempo_index; - timestamp += delta; - p_timestamp -= delta; - } - } + current_tempo = m_entries[ tempo_index ].m_tempo; + ++tempo_index; + timestamp += delta; + p_timestamp -= delta; + } + } timestamp_ms += ((uint64_t)current_tempo * (uint64_t)p_timestamp + half_dtx) / p_dtx; - return timestamp_ms; + return timestamp_ms; } void midi_container::initialize( unsigned p_form, unsigned p_dtx ) { - m_form = p_form; - m_dtx = p_dtx; - if ( p_form != 2 ) - { + m_form = p_form; + m_dtx = p_dtx; + if ( p_form != 2 ) + { m_channel_mask.resize( 1 ); - m_channel_mask[ 0 ] = 0; + m_channel_mask[ 0 ] = 0; m_tempo_map.resize( 1 ); m_timestamp_end.resize( 1 ); - m_timestamp_end[ 0 ] = 0; + m_timestamp_end[ 0 ] = 0; m_timestamp_loop_start.resize( 1 ); m_timestamp_loop_end.resize( 1 ); - } - int port = 0; - limit_port_number(port); + } } void midi_container::add_track( const midi_track & p_track ) { - unsigned i; - unsigned long port_number = 0; + unsigned i; + unsigned long port_number = 0; std::vector data; std::string device_name; m_tracks.push_back( p_track ); - for ( i = 0; i < p_track.get_count(); ++i ) - { - const midi_event & event = p_track[ i ]; - if ( event.m_type == midi_event::extended && event.get_data_count() >= 5 && - event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x51 ) - { - unsigned tempo = ( event.m_data[ 2 ] << 16 ) + ( event.m_data[ 3 ] << 8 ) + event.m_data[ 4 ]; - if ( m_form != 2 ) m_tempo_map[ 0 ].add_tempo( tempo, event.m_timestamp ); - else - { + for ( i = 0; i < p_track.get_count(); ++i ) + { + const midi_event & event = p_track[ i ]; + if ( event.m_type == midi_event::extended && event.get_data_count() >= 5 && + event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x51 ) + { + unsigned tempo = ( event.m_data[ 2 ] << 16 ) + ( event.m_data[ 3 ] << 8 ) + event.m_data[ 4 ]; + if ( m_form != 2 ) m_tempo_map[ 0 ].add_tempo( tempo, event.m_timestamp ); + else + { m_tempo_map.resize( m_tracks.size() ); m_tempo_map[ m_tracks.size() - 1 ].add_tempo( tempo, event.m_timestamp ); - } - } - else if ( event.m_type == midi_event::extended && event.get_data_count() >= 3 && - event.m_data[ 0 ] == 0xFF ) - { + } + } + else if ( event.m_type == midi_event::extended && event.get_data_count() >= 3 && + event.m_data[ 0 ] == 0xFF ) + { if ( event.m_data[ 1 ] == 4 || event.m_data[1] == 9 ) - { - unsigned long data_count = event.get_data_count() - 2; + { + unsigned long data_count = event.get_data_count() - 2; data.resize( data_count ); event.copy_data( &data[0], 2, data_count ); device_name.assign( data.begin(), data.begin() + data_count ); std::transform( device_name.begin(), device_name.end(), device_name.begin(), ::tolower ); - } - else if ( event.m_data[ 1 ] == 0x21 ) - { - port_number = event.m_data[ 2 ]; + } + else if ( event.m_data[ 1 ] == 0x21 ) + { + port_number = event.m_data[ 2 ]; limit_port_number( port_number ); device_name.clear(); - } - } - else if ( event.m_type == midi_event::note_on || event.m_type == midi_event::note_off ) - { - unsigned channel = event.m_channel; - if ( device_name.length() ) - { - unsigned long j, k; + } + } + else if ( event.m_type == midi_event::note_on || event.m_type == midi_event::note_off ) + { + unsigned channel = event.m_channel; + if ( device_name.length() ) + { + unsigned long j, k; for ( j = 0, k = m_device_names[ channel ].size(); j < k; ++j ) - { + { if ( !strcmp( m_device_names[ channel ][ j ].c_str(), device_name.c_str() ) ) break; - } - if ( j < k ) port_number = j; - else - { + } + if ( j < k ) port_number = j; + else + { m_device_names[ channel ].push_back( device_name ); - port_number = k; - } + port_number = k; + } device_name.clear(); limit_port_number( port_number ); - } + } - channel += 16 * port_number; - channel %= 48; - if ( m_form != 2 ) m_channel_mask[ 0 ] |= 1ULL << channel; - else - { + channel += 16 * port_number; + channel %= 48; + if ( m_form != 2 ) m_channel_mask[ 0 ] |= 1ULL << channel; + else + { m_channel_mask.resize( m_tracks.size(), 0 ); m_channel_mask[ m_tracks.size() - 1 ] |= 1ULL << channel; - } - } - } + } + } + } - if ( i && m_form != 2 && p_track[ i - 1 ].m_timestamp > m_timestamp_end[ 0 ] ) - m_timestamp_end[ 0 ] = p_track[ i - 1 ].m_timestamp; - else if ( m_form == 2 ) - { - if ( i ) + if ( i && m_form != 2 && p_track[ i - 1 ].m_timestamp > m_timestamp_end[ 0 ] ) + m_timestamp_end[ 0 ] = p_track[ i - 1 ].m_timestamp; + else if ( m_form == 2 ) + { + if ( i ) m_timestamp_end.push_back( p_track[ i - 1 ].m_timestamp ); - else + else m_timestamp_end.push_back( (unsigned)0 ); - } + } } void midi_container::add_track_event( std::size_t p_track_index, const midi_event & p_event ) { - midi_track & track = m_tracks[ p_track_index ]; + midi_track & track = m_tracks[ p_track_index ]; - track.add_event( p_event ); + track.add_event( p_event ); - if ( p_event.m_type == midi_event::extended && p_event.get_data_count() >= 5 && - p_event.m_data[ 0 ] == 0xFF && p_event.m_data[ 1 ] == 0x51 ) - { - unsigned tempo = ( p_event.m_data[ 2 ] << 16 ) + ( p_event.m_data[ 3 ] << 8 ) + p_event.m_data[ 4 ]; - if ( m_form != 2 ) m_tempo_map[ 0 ].add_tempo( tempo, p_event.m_timestamp ); - else - { + if ( p_event.m_type == midi_event::extended && p_event.get_data_count() >= 5 && + p_event.m_data[ 0 ] == 0xFF && p_event.m_data[ 1 ] == 0x51 ) + { + unsigned tempo = ( p_event.m_data[ 2 ] << 16 ) + ( p_event.m_data[ 3 ] << 8 ) + p_event.m_data[ 4 ]; + if ( m_form != 2 ) m_tempo_map[ 0 ].add_tempo( tempo, p_event.m_timestamp ); + else + { m_tempo_map.resize( m_tracks.size() ); - m_tempo_map[ p_track_index ].add_tempo( tempo, p_event.m_timestamp ); - } - } - else if ( p_event.m_type == midi_event::note_on || p_event.m_type == midi_event::note_off ) - { - if ( m_form != 2 ) m_channel_mask[ 0 ] |= 1ULL << p_event.m_channel; - else - { + m_tempo_map[ p_track_index ].add_tempo( tempo, p_event.m_timestamp ); + } + } + else if ( p_event.m_type == midi_event::note_on || p_event.m_type == midi_event::note_off ) + { + if ( m_form != 2 ) m_channel_mask[ 0 ] |= 1ULL << p_event.m_channel; + else + { m_channel_mask.resize( m_tracks.size(), 0 ); - m_channel_mask[ p_track_index ] |= 1ULL << p_event.m_channel; - } - } + m_channel_mask[ p_track_index ] |= 1ULL << p_event.m_channel; + } + } - if ( m_form != 2 && p_event.m_timestamp > m_timestamp_end[ 0 ] ) - { - m_timestamp_end[ 0 ] = p_event.m_timestamp; - } - else if ( m_form == 2 && p_event.m_timestamp > m_timestamp_end[ p_track_index ] ) - { - m_timestamp_end[ p_track_index ] = p_event.m_timestamp; - } + if ( m_form != 2 && p_event.m_timestamp > m_timestamp_end[ 0 ] ) + { + m_timestamp_end[ 0 ] = p_event.m_timestamp; + } + else if ( m_form == 2 && p_event.m_timestamp > m_timestamp_end[ p_track_index ] ) + { + m_timestamp_end[ p_track_index ] = p_event.m_timestamp; + } } void midi_container::merge_tracks( const midi_container & p_source ) @@ -479,7 +487,7 @@ void midi_container::set_track_count( unsigned count ) void midi_container::set_extra_meta_data( const midi_meta_data & p_data ) { - m_extra_meta_data = p_data; + m_extra_meta_data = p_data; } void midi_container::apply_hackfix( unsigned hack ) @@ -504,7 +512,7 @@ void midi_container::apply_hackfix( unsigned hack ) } } break; - + case 1: for (unsigned i = 0; i < m_tracks.size(); ++i) { @@ -526,14 +534,19 @@ void midi_container::apply_hackfix( unsigned hack ) } } -void midi_container::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 midi_container::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 { std::vector data; std::vector track_positions; std::vector port_numbers; std::vector device_names; std::size_t track_count = m_tracks.size(); - + unsigned long tick_loop_start = get_timestamp_loop_start(subsong); unsigned long tick_loop_end = get_timestamp_loop_end(subsong); unsigned long local_loop_start = ~0UL; @@ -543,169 +556,169 @@ void midi_container::serialize_as_stream( unsigned long subsong, std::vector= m_tracks[ i ].get_count() ) continue; - if ( m_tracks[ i ][ track_positions[ i ] ].m_timestamp < next_timestamp ) - { - next_timestamp = m_tracks[ i ][ track_positions[ i ] ].m_timestamp; - next_track = i; - } - } + for ( unsigned i = 0; i < track_count; ++i ) + { + if ( track_positions[ i ] >= m_tracks[ i ].get_count() ) continue; + if ( m_tracks[ i ][ track_positions[ i ] ].m_timestamp < next_timestamp ) + { + next_timestamp = m_tracks[ i ][ track_positions[ i ] ].m_timestamp; + next_track = i; + } + } if ( next_timestamp == ~0UL ) break; - bool filtered = false; + bool filtered = false; - if ( clean_instruments || clean_banks ) - { - const midi_event & event = m_tracks[ next_track ][ track_positions[ next_track ] ]; - if ( clean_instruments && event.m_type == midi_event::program_change ) filtered = true; - else if ( clean_banks && event.m_type == midi_event::control_change && - ( event.m_data[ 0 ] == 0x00 || event.m_data[ 0 ] == 0x20 ) ) filtered = true; - } + if ( clean_instruments || clean_banks ) + { + const midi_event & event = m_tracks[ next_track ][ track_positions[ next_track ] ]; + if ( clean_instruments && event.m_type == midi_event::program_change ) filtered = true; + else if ( clean_banks && event.m_type == midi_event::control_change && + ( event.m_data[ 0 ] == 0x00 || event.m_data[ 0 ] == 0x20 ) ) filtered = true; + } - if ( !filtered ) - { - unsigned long tempo_track = 0; - if ( m_form == 2 && subsong ) tempo_track = subsong; + if ( !filtered ) + { + unsigned long tempo_track = 0; + if ( m_form == 2 && subsong ) tempo_track = subsong; - const midi_event & event = m_tracks[ next_track ][ track_positions[ next_track ] ]; + const midi_event & event = m_tracks[ next_track ][ track_positions[ next_track ] ]; if ( local_loop_start == ~0UL && event.m_timestamp >= tick_loop_start ) local_loop_start = p_stream.size(); if ( local_loop_end == ~0UL && event.m_timestamp > tick_loop_end ) local_loop_end = p_stream.size(); - - unsigned long timestamp_ms = timestamp_to_ms( event.m_timestamp, tempo_track ); - if ( event.m_type != midi_event::extended ) - { - if ( device_names[ next_track ].length() ) - { - unsigned long i, j; + + unsigned long timestamp_ms = timestamp_to_ms( event.m_timestamp, tempo_track ); + if ( event.m_type != midi_event::extended ) + { + if ( device_names[ next_track ].length() ) + { + unsigned long i, j; for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) - { + { if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; - } - port_numbers[ next_track ] = (uint8_t) i; + } + port_numbers[ next_track ] = (uint8_t) i; device_names[ next_track ].clear(); limit_port_number( port_numbers[ next_track ] ); - } + } - uint32_t event_code = ( ( event.m_type + 8 ) << 4 ) + event.m_channel; - if ( event.m_data_count >= 1 ) event_code += event.m_data[ 0 ] << 8; - if ( event.m_data_count >= 2 ) event_code += event.m_data[ 1 ] << 16; - event_code += port_numbers[ next_track ] << 24; + uint32_t event_code = ( ( event.m_type + 8 ) << 4 ) + event.m_channel; + if ( event.m_data_count >= 1 ) event_code += event.m_data[ 0 ] << 8; + if ( event.m_data_count >= 2 ) event_code += event.m_data[ 1 ] << 16; + event_code += port_numbers[ next_track ] << 24; p_stream.push_back( midi_stream_event( timestamp_ms, event_code ) ); - } - else - { + } + else + { std::size_t data_count = event.get_data_count(); - if ( data_count >= 3 && event.m_data[ 0 ] == 0xF0 ) - { - if ( device_names[ next_track ].length() ) - { - unsigned long i, j; + if ( data_count >= 3 && event.m_data[ 0 ] == 0xF0 ) + { + if ( device_names[ next_track ].length() ) + { + unsigned long i, j; for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) - { + { if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; - } - port_numbers[ next_track ] = (uint8_t) i; + } + port_numbers[ next_track ] = (uint8_t) i; device_names[ next_track ].clear(); limit_port_number( port_numbers[ next_track ] ); - } + } data.resize( data_count ); event.copy_data( &data[0], 0, data_count ); - if ( data[ data_count - 1 ] == 0xF7 ) - { + if ( data[ data_count - 1 ] == 0xF7 ) + { uint32_t system_exclusive_index = p_system_exclusive.add_entry( &data[0], data_count, port_numbers[ next_track ] ); p_stream.push_back( midi_stream_event( timestamp_ms, system_exclusive_index | 0x80000000 ) ); - } - } - else if ( data_count >= 3 && event.m_data[ 0 ] == 0xFF ) - { + } + } + else if ( data_count >= 3 && event.m_data[ 0 ] == 0xFF ) + { if ( event.m_data[ 1 ] == 4 || event.m_data[ 1 ] == 9 ) - { - unsigned long _data_count = event.get_data_count() - 2; + { + unsigned long _data_count = event.get_data_count() - 2; data.resize( _data_count ); event.copy_data( &data[0], 2, _data_count ); device_names[ next_track ].clear(); device_names[ next_track ].assign( data.begin(), data.begin() + _data_count ); std::transform( device_names[ next_track ].begin(), device_names[ next_track ].end(), device_names[ next_track ].begin(), ::tolower ); - } - else if ( event.m_data[ 1 ] == 0x21 ) - { - port_numbers[ next_track ] = event.m_data[ 2 ]; + } + else if ( event.m_data[ 1 ] == 0x21 ) + { + port_numbers[ next_track ] = event.m_data[ 2 ]; device_names[ next_track ].clear(); limit_port_number( port_numbers[ next_track ] ); - } - } - else if ( data_count == 1 && event.m_data[ 0 ] >= 0xF8 ) - { - if ( device_names[ next_track ].length() ) - { - unsigned long i, j; - for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) - { - if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; - } - port_numbers[ next_track ] = (uint8_t) i; - device_names[ next_track ].clear(); - limit_port_number( port_numbers[ next_track ] ); - } + } + } + else if ( data_count == 1 && event.m_data[ 0 ] >= 0xF8 ) + { + if ( device_names[ next_track ].length() ) + { + unsigned long i, j; + for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) + { + if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; + } + port_numbers[ next_track ] = (uint8_t) i; + device_names[ next_track ].clear(); + limit_port_number( port_numbers[ next_track ] ); + } - uint32_t event_code = port_numbers[ next_track ] << 24; - event_code += event.m_data[ 0 ]; - p_stream.push_back( midi_stream_event( timestamp_ms, event_code ) ); - } - } - } + uint32_t event_code = port_numbers[ next_track ] << 24; + event_code += event.m_data[ 0 ]; + p_stream.push_back( midi_stream_event( timestamp_ms, event_code ) ); + } + } + } + + track_positions[ next_track ]++; + } - track_positions[ next_track ]++; - } - loop_start = local_loop_start; loop_end = local_loop_end; } @@ -730,10 +743,10 @@ void midi_container::serialize_as_standard_midi_file( std::vector & p_m p_midi_file.push_back( m_dtx ); for ( unsigned i = 0; i < m_tracks.size(); ++i ) - { - const midi_track & track = m_tracks[ i ]; - unsigned long last_timestamp = 0; - unsigned char last_event_code = 0xFF; + { + const midi_track & track = m_tracks[ i ]; + unsigned long last_timestamp = 0; + unsigned char last_event_code = 0xFF; std::size_t length_offset; const char _signature[] = "MTrk"; @@ -745,159 +758,159 @@ void midi_container::serialize_as_standard_midi_file( std::vector & p_m p_midi_file.push_back( 0 ); p_midi_file.push_back( 0 ); - for ( unsigned j = 0; j < track.get_count(); ++j ) - { - const midi_event & event = track[ j ]; - encode_delta( p_midi_file, event.m_timestamp - last_timestamp ); - last_timestamp = event.m_timestamp; - if ( event.m_type != midi_event::extended ) - { - const unsigned char event_code = ( ( event.m_type + 8 ) << 4 ) + event.m_channel; - if ( event_code != last_event_code ) - { + for ( unsigned j = 0; j < track.get_count(); ++j ) + { + const midi_event & event = track[ j ]; + encode_delta( p_midi_file, event.m_timestamp - last_timestamp ); + last_timestamp = event.m_timestamp; + if ( event.m_type != midi_event::extended ) + { + const unsigned char event_code = ( ( event.m_type + 8 ) << 4 ) + event.m_channel; + if ( event_code != last_event_code ) + { p_midi_file.push_back( event_code ); - last_event_code = event_code; - } + last_event_code = event_code; + } p_midi_file.insert( p_midi_file.end(), event.m_data, event.m_data + event.m_data_count ); - } - else - { + } + else + { std::size_t data_count = event.get_data_count(); - if ( data_count >= 1 ) - { - if ( event.m_data[ 0 ] == 0xF0 ) - { - --data_count; + if ( data_count >= 1 ) + { + if ( event.m_data[ 0 ] == 0xF0 ) + { + --data_count; p_midi_file.push_back( 0xF0 ); - encode_delta( p_midi_file, data_count ); - if ( data_count ) - { - data.resize( data_count ); - event.copy_data( &data[0], 1, data_count ); - p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); - } - } - else if ( event.m_data[ 0 ] == 0xFF && data_count >= 2 ) - { - data_count -= 2; + encode_delta( p_midi_file, data_count ); + if ( data_count ) + { + data.resize( data_count ); + event.copy_data( &data[0], 1, data_count ); + p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); + } + } + else if ( event.m_data[ 0 ] == 0xFF && data_count >= 2 ) + { + data_count -= 2; p_midi_file.push_back( 0xFF ); p_midi_file.push_back( event.m_data[ 1 ] ); - encode_delta( p_midi_file, data_count ); - if ( data_count ) - { - data.resize( data_count ); - event.copy_data( &data[0], 2, data_count ); - p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); - } - } - else - { - data.resize( data_count ); - event.copy_data( &data[0], 1, data_count ); - p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); - } - } - } - } + encode_delta( p_midi_file, data_count ); + if ( data_count ) + { + data.resize( data_count ); + event.copy_data( &data[0], 2, data_count ); + p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); + } + } + else + { + data.resize( data_count ); + event.copy_data( &data[0], 1, data_count ); + p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); + } + } + } + } std::size_t track_length = p_midi_file.size() - length_offset - 4; - p_midi_file[ length_offset + 0 ] = (unsigned char)( track_length >> 24 ); - p_midi_file[ length_offset + 1 ] = (unsigned char)( track_length >> 16 ); - p_midi_file[ length_offset + 2 ] = (unsigned char)( track_length >> 8 ); - p_midi_file[ length_offset + 3 ] = (unsigned char)track_length; - } + p_midi_file[ length_offset + 0 ] = (unsigned char)( track_length >> 24 ); + p_midi_file[ length_offset + 1 ] = (unsigned char)( track_length >> 16 ); + p_midi_file[ length_offset + 2 ] = (unsigned char)( track_length >> 8 ); + p_midi_file[ length_offset + 3 ] = (unsigned char)track_length; + } } void midi_container::promote_to_type1() { - if ( m_form == 0 && m_tracks.size() <= 2 ) - { - bool meter_track_present = false; - midi_track new_tracks[17]; - midi_track original_data_track = m_tracks[ m_tracks.size() - 1 ]; - if ( m_tracks.size() > 1 ) - { - new_tracks[0] = m_tracks[0]; - meter_track_present = true; - } + if ( m_form == 0 && m_tracks.size() <= 2 ) + { + bool meter_track_present = false; + midi_track new_tracks[17]; + midi_track original_data_track = m_tracks[ m_tracks.size() - 1 ]; + if ( m_tracks.size() > 1 ) + { + new_tracks[0] = m_tracks[0]; + meter_track_present = true; + } - m_tracks.resize( 0 ); + m_tracks.resize( 0 ); - for ( std::size_t i = 0; i < original_data_track.get_count(); ++i ) - { - const midi_event & event = original_data_track[ i ]; + for ( std::size_t i = 0; i < original_data_track.get_count(); ++i ) + { + const midi_event & event = original_data_track[ i ]; - if ( event.m_type != midi_event::extended ) - { - new_tracks[ 1 + event.m_channel ].add_event( event ); - } - else - { - if ( event.m_data[0] != 0xFF || event.get_data_count() < 2 || event.m_data[1] != 0x2F ) - { - new_tracks[ 0 ].add_event( event ); - } - else - { - if ( !meter_track_present ) - new_tracks[ 0 ].add_event( event ); - for ( std::size_t j = 1; j < 17; ++j ) - { - new_tracks[ j ].add_event( event ); - } - } - } - } + if ( event.m_type != midi_event::extended ) + { + new_tracks[ 1 + event.m_channel ].add_event( event ); + } + else + { + if ( event.m_data[0] != 0xFF || event.get_data_count() < 2 || event.m_data[1] != 0x2F ) + { + new_tracks[ 0 ].add_event( event ); + } + else + { + if ( !meter_track_present ) + new_tracks[ 0 ].add_event( event ); + for ( std::size_t j = 1; j < 17; ++j ) + { + new_tracks[ j ].add_event( event ); + } + } + } + } - for ( std::size_t i = 0; i < 17; ++i ) - { - if ( new_tracks[ i ].get_count() > 1 ) - add_track( new_tracks[ i ] ); - } + for ( std::size_t i = 0; i < 17; ++i ) + { + if ( new_tracks[ i ].get_count() > 1 ) + add_track( new_tracks[ i ] ); + } - m_form = 1; - } + m_form = 1; + } } unsigned long midi_container::get_subsong_count() const { - unsigned long subsong_count = 0; + unsigned long subsong_count = 0; for ( unsigned i = 0; i < m_channel_mask.size(); ++i ) - { - if ( m_channel_mask[ i ] ) ++subsong_count; - } - return subsong_count; + { + if ( m_channel_mask[ i ] ) ++subsong_count; + } + return subsong_count; } unsigned long midi_container::get_subsong( unsigned long p_index ) const { for ( unsigned i = 0; i < m_channel_mask.size(); ++i ) - { - if ( m_channel_mask[ i ] ) - { - if ( p_index ) --p_index; - else return i; - } - } - return 0; + { + if ( m_channel_mask[ i ] ) + { + if ( p_index ) --p_index; + else return i; + } + } + return 0; } unsigned long midi_container::get_timestamp_end(unsigned long subsong, bool ms /* = false */) const { - unsigned long tempo_track = 0; - unsigned long timestamp = m_timestamp_end[ 0 ]; - if ( m_form == 2 && subsong ) - { - tempo_track = subsong; - timestamp = m_timestamp_end[ subsong ]; - } - if ( !ms ) return timestamp; - else return timestamp_to_ms( timestamp, tempo_track ); + unsigned long tempo_track = 0; + unsigned long timestamp = m_timestamp_end[ 0 ]; + if ( m_form == 2 && subsong ) + { + tempo_track = subsong; + timestamp = m_timestamp_end[ subsong ]; + } + if ( !ms ) return timestamp; + else return timestamp_to_ms( timestamp, tempo_track ); } unsigned midi_container::get_format() const { - return m_form; + return m_form; } unsigned midi_container::get_track_count() const @@ -907,39 +920,39 @@ unsigned midi_container::get_track_count() const unsigned midi_container::get_channel_count( unsigned long subsong ) const { - unsigned count = 0; + unsigned count = 0; uint64_t j = 1; - for (unsigned i = 0; i < 48; ++i, j <<= 1) - { - if ( m_channel_mask[ subsong ] & j ) ++count; - } - return count; + for (unsigned i = 0; i < 48; ++i, j <<= 1) + { + if ( m_channel_mask[ subsong ] & j ) ++count; + } + return count; } unsigned long midi_container::get_timestamp_loop_start( unsigned long subsong, bool ms /* = false */ ) const { - unsigned long tempo_track = 0; - unsigned long timestamp = m_timestamp_loop_start[ 0 ]; - if ( m_form == 2 && subsong ) - { - tempo_track = subsong; - timestamp = m_timestamp_loop_start[ subsong ]; - } - if ( !ms ) return timestamp; + unsigned long tempo_track = 0; + unsigned long timestamp = m_timestamp_loop_start[ 0 ]; + if ( m_form == 2 && subsong ) + { + tempo_track = subsong; + timestamp = m_timestamp_loop_start[ subsong ]; + } + if ( !ms ) return timestamp; else if ( timestamp != ~0UL ) return timestamp_to_ms( timestamp, tempo_track ); else return ~0UL; } unsigned long midi_container::get_timestamp_loop_end( unsigned long subsong, bool ms /* = false */ ) const { - unsigned long tempo_track = 0; - unsigned long timestamp = m_timestamp_loop_end[ 0 ]; - if ( m_form == 2 && subsong ) - { - tempo_track = subsong; - timestamp = m_timestamp_loop_end[ subsong ]; - } - if ( !ms ) return timestamp; + unsigned long tempo_track = 0; + unsigned long timestamp = m_timestamp_loop_end[ 0 ]; + if ( m_form == 2 && subsong ) + { + tempo_track = subsong; + timestamp = m_timestamp_loop_end[ subsong ]; + } + if ( !ms ) return timestamp; else if ( timestamp != ~0UL ) return timestamp_to_ms( timestamp, tempo_track ); else return ~0UL; } @@ -957,106 +970,285 @@ void midi_container::get_meta_data( unsigned long subsong, midi_meta_data & p_ou std::vector data; - bool type_found = false; - bool type_non_gm_found = false; + bool type_found = false; + bool type_non_gm_found = false; for ( unsigned long i = 0; i < m_tracks.size(); ++i ) - { - if ( m_form == 2 && i != subsong ) continue; + { + if ( m_form == 2 && i != subsong ) continue; - unsigned long tempo_track = 0; - if ( m_form == 2 ) tempo_track = i; + unsigned long tempo_track = 0; + if ( m_form == 2 ) tempo_track = i; - const midi_track & track = m_tracks[ i ]; - for ( unsigned j = 0; j < track.get_count(); ++j ) - { - const midi_event & event = track[ j ]; - if ( event.m_type == midi_event::extended ) - { + const midi_track & track = m_tracks[ i ]; + for ( unsigned j = 0; j < track.get_count(); ++j ) + { + const midi_event & event = track[ j ]; + if ( event.m_type == midi_event::extended ) + { std::size_t data_count = event.get_data_count(); if ( !type_non_gm_found && data_count >= 1 && event.m_data[ 0 ] == 0xF0 ) - { - unsigned char test = 0; - unsigned char test2 = 0; - if ( data_count > 1 ) test = event.m_data[ 1 ]; - if ( data_count > 3 ) test2 = event.m_data[ 3 ]; + { + unsigned char test = 0; + unsigned char test2 = 0; + if ( data_count > 1 ) test = event.m_data[ 1 ]; + if ( data_count > 3 ) test2 = event.m_data[ 3 ]; - const char * type = NULL; + const char * type = NULL; - switch( test ) - { - case 0x7E: - type_found = true; - break; - case 0x43: - type = "XG"; - break; - case 0x42: - type = "X5"; - break; - case 0x41: - if ( test2 == 0x42 ) type = "GS"; - else if ( test2 == 0x16 ) type = "MT-32"; - else if ( test2 == 0x14 ) type = "D-50"; - } + switch( test ) + { + case 0x7E: + type_found = true; + break; + case 0x43: + type = "XG"; + break; + case 0x42: + type = "X5"; + break; + case 0x41: + if ( test2 == 0x42 ) type = "GS"; + else if ( test2 == 0x16 ) type = "MT-32"; + else if ( test2 == 0x14 ) type = "D-50"; + } - if ( type ) - { - type_found = true; - type_non_gm_found = true; - p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "type", type ) ); - } - } - else if ( data_count >= 2 && event.m_data[ 0 ] == 0xFF ) - { - data_count -= 2; - switch ( event.m_data[ 1 ] ) - { - case 6: + if ( type ) + { + type_found = true; + type_non_gm_found = true; + p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "type", type ) ); + } + } + else if ( data_count >= 2 && event.m_data[ 0 ] == 0xFF ) + { + data_count -= 2; + switch ( event.m_data[ 1 ] ) + { + case 6: data.resize( data_count ); event.copy_data( &data[0], 2, data_count ); convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "track_marker", convert.c_str() ) ); - break; + break; - case 2: + case 2: data.resize( data_count ); event.copy_data( &data[0], 2, data_count ); convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "copyright", convert.c_str() ) ); - break; + break; - case 1: + case 1: data.resize( data_count ); event.copy_data( &data[0], 2, data_count ); convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); snprintf(temp, 31, "track_text_%02lu", i); p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), temp, convert.c_str() ) ); - break; + break; - case 3: - case 4: + case 3: + case 4: data.resize( data_count ); event.copy_data( &data[0], 2, data_count ); convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); snprintf(temp, 31, "track_name_%02lu", i); p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), temp, convert.c_str() ) ); - break; - } - } - } - } - } + break; + } + } + } + } + } - if ( type_found && !type_non_gm_found ) - { - p_out.add_item( midi_meta_data_item( 0, "type", "GM" ) ); - } + if ( type_found && !type_non_gm_found ) + { + p_out.add_item( midi_meta_data_item( 0, "type", "GM" ) ); + } - p_out.append( m_extra_meta_data ); + p_out.append( m_extra_meta_data ); } -void midi_container::scan_for_loops( bool p_xmi_loops, bool p_marker_loops, bool p_rpgmaker_loops ) +void midi_container::trim_tempo_map( unsigned long p_index, unsigned long base_timestamp ) +{ + if ( p_index < m_tempo_map.size() ) + { + tempo_map & map = m_tempo_map[ p_index ]; + + for ( unsigned long i = 0, j = map.get_count(); i < j; ++i ) + { + tempo_entry & entry = map[ i ]; + if ( entry.m_timestamp >= base_timestamp ) + entry.m_timestamp -= base_timestamp; + else + entry.m_timestamp = 0; + } + } +} + +void midi_container::trim_range_of_tracks(unsigned long start, unsigned long end) +{ + unsigned long timestamp_first_note = ~0UL; + + for (unsigned long i = start; i <= end; ++i) + { + unsigned long j, k; + + const midi_track & track = m_tracks[ i ]; + + for (j = 0, k = track.get_count(); j < k; ++j) + { + const midi_event & event = track[ j ]; + + if ( event.m_type == midi_event::note_on && event.m_data[ 0 ] ) + break; + } + + if ( j < k ) + { + if ( track[ j ].m_timestamp < timestamp_first_note ) + timestamp_first_note = track[ j ].m_timestamp; + } + } + + if ( timestamp_first_note < ~0UL && timestamp_first_note > 0 ) + { + for (unsigned long i = start; i <= end; ++i) + { + midi_track & track = m_tracks[ i ]; + + for (unsigned long j = 0, k = track.get_count(); j < k; ++j) + { + midi_event & event = track[ j ]; + if ( event.m_timestamp >= timestamp_first_note ) + event.m_timestamp -= timestamp_first_note; + else + event.m_timestamp = 0; + } + } + + if ( start == end ) + { + trim_tempo_map( start, timestamp_first_note ); + + m_timestamp_end[ start ] -= timestamp_first_note; + + if ( m_timestamp_loop_end[ start ] != ~0UL ) + m_timestamp_loop_end[ start ] -= timestamp_first_note; + if ( m_timestamp_loop_start[ start ] != ~0UL ) + { + if ( m_timestamp_loop_start[ start ] > timestamp_first_note ) + m_timestamp_loop_start[ start ] -= timestamp_first_note; + else + m_timestamp_loop_start[ start ] = 0; + } + } + else + { + trim_tempo_map( 0, timestamp_first_note ); + + m_timestamp_end[ 0 ] -= timestamp_first_note; + + if ( m_timestamp_loop_end[ 0 ] != ~0UL ) + m_timestamp_loop_end[ 0 ] -= timestamp_first_note; + if ( m_timestamp_loop_start[ 0 ] != ~0UL ) + { + if ( m_timestamp_loop_start[ 0 ] > timestamp_first_note ) + m_timestamp_loop_start[ 0 ] -= timestamp_first_note; + else + m_timestamp_loop_start[ 0 ] = 0; + } + } + } +} + +void midi_container::trim_start() +{ + if (m_form == 2) + { + for (unsigned long i = 0, j = m_tracks.size(); i < j; ++i) + { + trim_range_of_tracks(i, i); + } + } + else + { + trim_range_of_tracks(0, m_tracks.size() - 1); + } +} + +void midi_container::split_by_instrument_changes(split_callback cb) +{ + if (m_form != 1) /* This would literally die on anything else */ + return; + + for (unsigned long i = 0, j = m_tracks.size(); i < j; ++i) + { + midi_track source_track = m_tracks[0]; + + m_tracks.erase(m_tracks.begin()); + + midi_track output_track; + midi_track program_change; + + for (unsigned long k = 0, l = source_track.get_count(); k < l; ++k) + { + const midi_event & event = source_track[ k ]; + if ( event.m_type == midi_event::program_change || + ( event.m_type == midi_event::control_change && + (event.m_data[0] == 0 || event.m_data[0] == 0x20))) + { + program_change.add_event( event ); + } + else + { + if (program_change.get_count()) + { + if (output_track.get_count()) + m_tracks.push_back( output_track ); + output_track = program_change; + if (cb) + { + unsigned long timestamp = 0; + uint8_t bank_msb = 0, bank_lsb = 0, instrument = 0; + for (int i = 0, j = program_change.get_count(); i < j; ++i) + { + const midi_event & ev = program_change[i]; + if (ev.m_type == midi_event::program_change) + instrument = ev.m_data[0]; + else if (ev.m_data[0] == 0) + bank_msb = ev.m_data[1]; + else + bank_lsb = ev.m_data[1]; + if (ev.m_timestamp > timestamp) + timestamp = ev.m_timestamp; + } + + std::string name = cb(bank_msb, bank_lsb, instrument); + + std::vector data; + + data.resize(name.length() + 2); + + data[0] = 0xFF; + data[1] = 0x03; + + std::copy(name.begin(), name.end(), data.begin() + 2); + + output_track.add_event(midi_event(timestamp, midi_event::extended, 0, &data[0], data.size())); + } + program_change = midi_track(); + } + output_track.add_event( event ); + } + } + + if (output_track.get_count()) + m_tracks.push_back(output_track); + } +} + +void midi_container::scan_for_loops( bool p_xmi_loops, bool p_marker_loops, bool p_rpgmaker_loops, bool p_touhou_loops ) { std::vector data; @@ -1065,144 +1257,189 @@ void midi_container::scan_for_loops( bool p_xmi_loops, bool p_marker_loops, bool m_timestamp_loop_start.resize( subsong_count ); m_timestamp_loop_end.resize( subsong_count ); - for ( unsigned long i = 0; i < subsong_count; ++i ) - { + for ( unsigned long i = 0; i < subsong_count; ++i ) + { m_timestamp_loop_start[ i ] = ~0UL; m_timestamp_loop_end[ i ] = ~0UL; - } + } - if ( p_rpgmaker_loops ) - { + if ( p_touhou_loops && m_form == 0 ) + { + bool loop_start_found = false; + bool loop_end_found = false; + bool errored = false; + + for ( unsigned long i = 0; !errored && i < m_tracks.size(); ++i ) + { + const midi_track & track = m_tracks[ i ]; + for ( unsigned long j = 0; !errored && j < track.get_count(); ++j ) + { + const midi_event & event = track[ j ]; + if ( event.m_type == midi_event::control_change ) + { + if ( event.m_data[ 0 ] == 2 ) + { + if ( event.m_data[ 1 ] != 0 ) + { + errored = true; + break; + } + m_timestamp_loop_start[ 0 ] = event.m_timestamp; + loop_start_found = true; + } + if ( event.m_data[ 0 ] == 4 ) + { + if ( event.m_data[ 1 ] != 0 ) + { + errored = true; + break; + } + m_timestamp_loop_end[ 0 ] = event.m_timestamp; + loop_end_found = true; + } + } + } + } + + if ( errored ) + { + m_timestamp_loop_start[ 0 ] = ~0UL; + m_timestamp_loop_end[ 0 ] = ~0UL; + } + } + + if ( p_rpgmaker_loops ) + { bool emidi_commands_found = false; - + for ( unsigned long i = 0; i < m_tracks.size(); ++i ) - { - unsigned long subsong = 0; - if ( m_form == 2 ) subsong = i; - - const midi_track & track = m_tracks[ i ]; - for ( unsigned long j = 0; j < track.get_count(); ++j ) - { - const midi_event & event = track[ j ]; - if ( event.m_type == midi_event::control_change && - ( event.m_data[ 0 ] == 110 || event.m_data[ 0 ] == 111 ) ) - { + { + unsigned long subsong = 0; + if ( m_form == 2 ) subsong = i; + + const midi_track & track = m_tracks[ i ]; + for ( unsigned long j = 0; j < track.get_count(); ++j ) + { + const midi_event & event = track[ j ]; + if ( event.m_type == midi_event::control_change && + ( event.m_data[ 0 ] == 110 || event.m_data[ 0 ] == 111 ) ) + { if ( event.m_data[ 0 ] == 110 ) { emidi_commands_found = true; break; } - { + { if ( m_timestamp_loop_start[ subsong ] == ~0UL || m_timestamp_loop_start[ subsong ] > event.m_timestamp ) - { - m_timestamp_loop_start[ subsong ] = event.m_timestamp; - } - } - } - } - + { + m_timestamp_loop_start[ subsong ] = event.m_timestamp; + } + } + } + } + if ( emidi_commands_found ) { m_timestamp_loop_start[ subsong ] = ~0UL; m_timestamp_loop_end[ subsong ] = ~0UL; break; } - } - } - - if ( p_xmi_loops ) - { - for ( unsigned long i = 0; i < m_tracks.size(); ++i ) - { - unsigned long subsong = 0; - if ( m_form == 2 ) subsong = i; + } + } - const midi_track & track = m_tracks[ i ]; - for ( unsigned long j = 0; j < track.get_count(); ++j ) - { - const midi_event & event = track[ j ]; - if ( event.m_type == midi_event::control_change && - ( event.m_data[ 0 ] >= 0x74 && event.m_data[ 0 ] <= 0x77 ) ) - { - if ( event.m_data[ 0 ] == 0x74 || event.m_data[ 0 ] == 0x76 ) - { + if ( p_xmi_loops ) + { + for ( unsigned long i = 0; i < m_tracks.size(); ++i ) + { + unsigned long subsong = 0; + if ( m_form == 2 ) subsong = i; + + const midi_track & track = m_tracks[ i ]; + for ( unsigned long j = 0; j < track.get_count(); ++j ) + { + const midi_event & event = track[ j ]; + if ( event.m_type == midi_event::control_change && + ( event.m_data[ 0 ] >= 0x74 && event.m_data[ 0 ] <= 0x77 ) ) + { + if ( event.m_data[ 0 ] == 0x74 || event.m_data[ 0 ] == 0x76 ) + { if ( m_timestamp_loop_start[ subsong ] == ~0UL || m_timestamp_loop_start[ subsong ] > event.m_timestamp ) - { - m_timestamp_loop_start[ subsong ] = event.m_timestamp; - } - } - else - { + { + m_timestamp_loop_start[ subsong ] = event.m_timestamp; + } + } + else + { if ( m_timestamp_loop_end[ subsong ] == ~0UL || m_timestamp_loop_end[ subsong ] < event.m_timestamp ) - { - m_timestamp_loop_end[ subsong ] = event.m_timestamp; - } - } - } - } - } - } + { + m_timestamp_loop_end[ subsong ] = event.m_timestamp; + } + } + } + } + } + } - if ( p_marker_loops ) - { + if ( p_marker_loops ) + { for ( unsigned long i = 0; i < m_tracks.size(); ++i ) - { - unsigned long subsong = 0; - if ( m_form == 2 ) subsong = i; + { + unsigned long subsong = 0; + if ( m_form == 2 ) subsong = i; - const midi_track & track = m_tracks[ i ]; - for ( unsigned long j = 0; j < track.get_count(); ++j ) - { - const midi_event & event = track[ j ]; - if ( event.m_type == midi_event::extended && - event.get_data_count() >= 9 && - event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x06 ) - { - unsigned long data_count = event.get_data_count() - 2; + const midi_track & track = m_tracks[ i ]; + for ( unsigned long j = 0; j < track.get_count(); ++j ) + { + const midi_event & event = track[ j ]; + if ( event.m_type == midi_event::extended && + event.get_data_count() >= 9 && + event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x06 ) + { + unsigned long data_count = event.get_data_count() - 2; data.resize( data_count ); event.copy_data( &data[0], 2, data_count ); if ( data_count == 9 && !strncasecmp( (const char *) &data[0], "loopStart", 9 ) ) - { + { if ( m_timestamp_loop_start[ subsong ] == ~0UL || m_timestamp_loop_start[ subsong ] > event.m_timestamp ) - { - m_timestamp_loop_start[ subsong ] = event.m_timestamp; - } - } + { + m_timestamp_loop_start[ subsong ] = event.m_timestamp; + } + } else if ( data_count == 7 && !strncasecmp( (const char *) &data[0], "loopEnd", 7 ) ) - { + { if ( m_timestamp_loop_end[ subsong ] == ~0UL || m_timestamp_loop_end[ subsong ] < event.m_timestamp ) - { - m_timestamp_loop_end[ subsong ] = event.m_timestamp; - } - } - } - } - } - } + { + m_timestamp_loop_end[ subsong ] = event.m_timestamp; + } + } + } + } + } + } - // Sanity + // Sanity - for ( unsigned long i = 0; i < subsong_count; ++i ) - { - unsigned long timestamp_song_end; - if ( m_form == 2 ) - timestamp_song_end = m_tracks[i][m_tracks[i].get_count()-1].m_timestamp; - else - { - timestamp_song_end = 0; - for (unsigned long j = 0; j < m_tracks.size(); ++j) - { - const midi_track & track = m_tracks[j]; - unsigned long timestamp = track[track.get_count()-1].m_timestamp; - if (timestamp > timestamp_song_end) - timestamp_song_end = timestamp; - } - } + for ( unsigned long i = 0; i < subsong_count; ++i ) + { + unsigned long timestamp_song_end; + if ( m_form == 2 ) + timestamp_song_end = m_tracks[i][m_tracks[i].get_count()-1].m_timestamp; + else + { + timestamp_song_end = 0; + for (unsigned long j = 0; j < m_tracks.size(); ++j) + { + const midi_track & track = m_tracks[j]; + unsigned long timestamp = track[track.get_count()-1].m_timestamp; + if (timestamp > timestamp_song_end) + timestamp_song_end = timestamp; + } + } if ( m_timestamp_loop_start[ i ] != ~0UL && ( ( m_timestamp_loop_start[ i ] == m_timestamp_loop_end[ i ] ) || ( m_timestamp_loop_start[ i ] == timestamp_song_end ) ) ) - { + { m_timestamp_loop_start[ i ] = ~0UL; m_timestamp_loop_end[ i ] = ~0UL; - } - } + } + } } diff --git a/Frameworks/midi_processing/midi_processing/midi_container.h b/Frameworks/midi_processing/midi_processing/midi_container.h index ba0e9c73a..e512c1a42 100644 --- a/Frameworks/midi_processing/midi_processing/midi_container.h +++ b/Frameworks/midi_processing/midi_processing/midi_container.h @@ -13,36 +13,36 @@ struct midi_event { - enum - { - max_static_data_count = 16 - }; + 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 - }; + enum event_type + { + note_off = 0, + note_on, + polyphonic_aftertouch, + control_change, + program_change, + channel_aftertouch, + pitch_wheel, + extended + }; - unsigned long m_timestamp; + unsigned long m_timestamp; - event_type m_type; - unsigned m_channel; - unsigned long m_data_count; + 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() : 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 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 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 m_data; std::vector 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 ); - - bool get_item( const char * p_name, midi_meta_data_item & p_out ) const; + 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; @@ -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 m_channel_mask; std::vector m_tempo_map; std::vector 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 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 & p_out, unsigned long delta ); }; diff --git a/Frameworks/midi_processing/midi_processing/midi_processor.h b/Frameworks/midi_processing/midi_processing/midi_processor.h index 23cace4b0..bf29247c9 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor.h +++ b/Frameworks/midi_processing/midi_processing/midi_processor.h @@ -51,14 +51,14 @@ class midi_processor static bool process_lds( std::vector const& p_file, midi_container & p_out ); static bool process_gmf( std::vector const& p_file, midi_container & p_out ); static bool process_syx( std::vector const& p_file, midi_container & p_out ); - + static bool process_standard_midi_count( std::vector const& p_file, size_t & track_count ); static bool process_riff_midi_count( std::vector const& p_file, size_t & track_count ); static bool process_xmi_count( std::vector const& p_file, size_t & track_count ); public: static bool process_track_count( std::vector const& p_file, const char * p_extension, size_t & track_count ); - + static bool process_file( std::vector const& p_file, const char * p_extension, midi_container & p_out ); static bool process_syx_file( std::vector const& p_file, midi_container & p_out ); diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_gmf.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_gmf.cpp index b8fdc8899..f10b3137b 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_gmf.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_gmf.cpp @@ -4,47 +4,47 @@ bool midi_processor::is_gmf( std::vector 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 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::const_iterator it = p_file.begin() + 7; diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp index 96ebaf4cf..db922f658 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp @@ -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::const_iterator & it, std::vector::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 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 const& p_file, midi_ bool midi_processor::process_track_count( std::vector 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 ); diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_hmi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_hmi.cpp index 56e70bfce..af0e1956c 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_hmi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_hmi.cpp @@ -18,43 +18,43 @@ bool midi_processor::process_hmi( std::vector const& p_file, midi_conta uint32_t track_count = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); uint32_t track_table_offset = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); - if ( track_table_offset >= p_file.size() || track_table_offset + track_count * 4 > p_file.size() ) - return false; + if ( track_table_offset >= p_file.size() || track_table_offset + track_count * 4 > p_file.size() ) + return false; it = p_file.begin() + track_table_offset; std::vector track_offsets; track_offsets.resize( track_count ); - for ( unsigned i = 0; i < track_count; ++i ) - { + for ( unsigned i = 0; i < track_count; ++i ) + { track_offsets[ i ] = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; - } + } - p_out.initialize( 1, 0xC0 ); + p_out.initialize( 1, 0xC0 ); - { - 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 ); + } - for ( unsigned i = 0; i < track_count; ++i ) - { - unsigned track_offset = track_offsets[ i ]; - unsigned long track_length; - if ( i + 1 < track_count ) - { - track_length = track_offsets[ i + 1 ] - track_offset; - } - else - { + for ( unsigned i = 0; i < track_count; ++i ) + { + unsigned track_offset = track_offsets[ i ]; + unsigned long track_length; + if ( i + 1 < track_count ) + { + track_length = track_offsets[ i + 1 ] - track_offset; + } + else + { track_length = p_file.size() - track_offset; - } - if ( track_offset >= p_file.size() || track_offset + track_length > p_file.size() ) - return false; + } + if ( track_offset >= p_file.size() || track_offset + track_length > p_file.size() ) + return false; std::vector::const_iterator track_body = p_file.begin() + track_offset; std::vector::const_iterator track_end = track_body + track_length; @@ -65,31 +65,31 @@ bool midi_processor::process_hmi( std::vector const& p_file, midi_conta track_body[ 8 ] != 'T' || track_body[ 9 ] != 'R' || track_body[ 10 ] != 'A' || track_body[ 11 ] != 'C' || track_body[ 12 ] != 'K' ) return false; - midi_track track; - unsigned current_timestamp = 0; - unsigned char last_event_code = 0xFF; + midi_track track; + unsigned current_timestamp = 0; + unsigned char last_event_code = 0xFF; - unsigned last_event_timestamp = 0; + unsigned last_event_timestamp = 0; if ( track_length < 0x4B + 4 ) return false; uint32_t meta_offset = track_body[ 0x4B ] | ( track_body[ 0x4C ] << 8 ) | ( track_body[ 0x4D ] << 16 ) | ( track_body[ 0x4E ] << 24 ); if ( meta_offset && meta_offset + 1 < track_length ) - { + { buffer.resize( 2 ); std::copy( track_body + meta_offset, track_body + meta_offset + 2, buffer.begin() ); - unsigned meta_size = buffer[ 1 ]; + unsigned meta_size = buffer[ 1 ]; if ( meta_offset + 2 + meta_size > track_length ) return false; buffer.resize( meta_size + 2 ); std::copy( track_body + meta_offset + 2, track_body + meta_offset + 2 + meta_size, buffer.begin() + 2 ); - while ( meta_size > 0 && buffer[ meta_size + 1 ] == ' ' ) --meta_size; + while ( meta_size > 0 && buffer[ meta_size + 1 ] == ' ' ) --meta_size; if ( meta_size > 0 ) { buffer[ 0 ] = 0xFF; buffer[ 1 ] = 0x01; track.add_event( midi_event( 0, midi_event::extended, 0, &buffer[0], meta_size + 2 ) ); } - } + } if ( track_length < 0x57 + 4 ) return false; @@ -100,129 +100,129 @@ bool midi_processor::process_hmi( std::vector const& p_file, midi_conta buffer.resize( 3 ); while ( it != track_end ) - { + { int delta = decode_delta( it, track_end ); - if ( delta > 0xFFFF || delta < 0 ) - { - current_timestamp = last_event_timestamp; + if ( delta > 0xFFFF || delta < 0 ) + { + current_timestamp = last_event_timestamp; /*console::formatter() << "[foo_midi] Large HMI delta detected, shunting.";*/ - } - else - { - current_timestamp += delta; - if ( current_timestamp > last_event_timestamp ) - { - last_event_timestamp = current_timestamp; - } - } + } + else + { + current_timestamp += delta; + if ( current_timestamp > last_event_timestamp ) + { + last_event_timestamp = current_timestamp; + } + } - if ( it == track_end ) return false; + if ( it == track_end ) return false; buffer[ 0 ] = *it++; - if ( buffer[ 0 ] == 0xFF ) - { - last_event_code = 0xFF; - if ( it == track_end ) return false; + if ( buffer[ 0 ] == 0xFF ) + { + last_event_code = 0xFF; + if ( it == track_end ) return false; buffer[ 1 ] = *it++; int meta_count = decode_delta( it, track_end ); if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid HMI meta message" );*/ - if ( track_end - it < meta_count ) return false; + if ( track_end - it < meta_count ) return false; buffer.resize( meta_count + 2 ); std::copy( it, it + meta_count, buffer.begin() + 2 ); it += meta_count; - if ( buffer[ 1 ] == 0x2F && last_event_timestamp > current_timestamp ) - { - current_timestamp = last_event_timestamp; - } + if ( buffer[ 1 ] == 0x2F && last_event_timestamp > current_timestamp ) + { + current_timestamp = last_event_timestamp; + } track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], meta_count + 2 ) ); - if ( buffer[ 1 ] == 0x2F ) break; - } - else if ( buffer[ 0 ] == 0xF0 ) - { - last_event_code = 0xFF; + if ( buffer[ 1 ] == 0x2F ) break; + } + else if ( buffer[ 0 ] == 0xF0 ) + { + last_event_code = 0xFF; int system_exclusive_count = decode_delta( it, track_end ); if ( system_exclusive_count < 0 ) return false; /*throw exception_io_data( "Invalid HMI System Exclusive message" );*/ - if ( track_end - it < system_exclusive_count ) return false; + if ( track_end - it < system_exclusive_count ) return false; buffer.resize( system_exclusive_count + 1 ); std::copy( it, it + system_exclusive_count, buffer.begin() + 1 ); it += system_exclusive_count; track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], system_exclusive_count + 1 ) ); - } - else if ( buffer[ 0 ] == 0xFE ) - { - last_event_code = 0xFF; - if ( it == track_end ) return false; + } + else if ( buffer[ 0 ] == 0xFE ) + { + last_event_code = 0xFF; + if ( it == track_end ) return false; buffer[ 1 ] = *it++; - if ( buffer[ 1 ] == 0x10 ) - { - if ( track_end - it < 3 ) return false; + if ( buffer[ 1 ] == 0x10 ) + { + if ( track_end - it < 3 ) return false; it += 2; buffer[ 2 ] = *it++; - if ( track_end - it < buffer[ 2 ] + 4 ) return false; + if ( track_end - it < buffer[ 2 ] + 4 ) return false; it += buffer[ 2 ] + 4; - } - else if ( buffer[ 1 ] == 0x12 ) - { - if ( track_end - it < 2 ) return false; + } + else if ( buffer[ 1 ] == 0x12 ) + { + if ( track_end - it < 2 ) return false; it += 2; - } - else if ( buffer[ 1 ] == 0x13 ) - { - if ( track_end - it < 10 ) return false; + } + else if ( buffer[ 1 ] == 0x13 ) + { + if ( track_end - it < 10 ) return false; it += 10; - } - else if ( buffer[ 1 ] == 0x14 ) - { - if ( track_end - it < 2 ) return false; + } + else if ( buffer[ 1 ] == 0x14 ) + { + if ( track_end - it < 2 ) return false; it += 2; - p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); - } - else if ( buffer[ 1 ] == 0x15 ) - { - if ( track_end - it < 6 ) return false; + p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); + } + else if ( buffer[ 1 ] == 0x15 ) + { + if ( track_end - it < 6 ) return false; it += 6; - p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); - } + p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); + } else return false; /*throw exception_io_data( "Unexpected HMI meta event" );*/ - } - else if ( buffer[ 0 ] <= 0xEF ) - { - unsigned bytes_read = 1; - if ( buffer[ 0 ] >= 0x80 ) - { - if ( it == track_end ) return false; + } + else if ( buffer[ 0 ] <= 0xEF ) + { + unsigned bytes_read = 1; + if ( buffer[ 0 ] >= 0x80 ) + { + if ( it == track_end ) return false; buffer[ 1 ] = *it++; - last_event_code = buffer[ 0 ]; - } - else - { + last_event_code = buffer[ 0 ]; + } + else + { if ( last_event_code == 0xFF ) return false; /*throw exception_io_data( "HMI used shortened event after Meta or SysEx message" );*/ - buffer[ 1 ] = buffer[ 0 ]; - buffer[ 0 ] = last_event_code; - } - midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); - unsigned channel = buffer[ 0 ] & 0x0F; - if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) - { - if ( it == track_end ) return false; + buffer[ 1 ] = buffer[ 0 ]; + buffer[ 0 ] = last_event_code; + } + midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); + unsigned channel = buffer[ 0 ] & 0x0F; + if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) + { + if ( it == track_end ) return false; buffer[ 2 ] = *it++; - bytes_read = 2; - } + bytes_read = 2; + } track.add_event( midi_event( current_timestamp, type, channel, &buffer[ 1 ], bytes_read ) ); - if ( type == midi_event::note_on ) - { - buffer[ 2 ] = 0x00; + if ( type == midi_event::note_on ) + { + buffer[ 2 ] = 0x00; int note_length = decode_delta( it, track_end ); if ( note_length < 0 ) return false; /*throw exception_io_data( "Invalid HMI note message" );*/ - unsigned note_end_timestamp = current_timestamp + note_length; - if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; + unsigned note_end_timestamp = current_timestamp + note_length; + if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; track.add_event( midi_event( note_end_timestamp, midi_event::note_on, channel, &buffer[1], bytes_read ) ); - } - } + } + } else return false; /*throw exception_io_data( "Unexpected HMI status code" );*/ - } + } - p_out.add_track( track ); - } + p_out.add_track( track ); + } return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_hmp.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_hmp.cpp index 4503fbaa9..b755d4e60 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_hmp.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_hmp.cpp @@ -13,18 +13,18 @@ bool midi_processor::is_hmp( std::vector const& p_file ) unsigned midi_processor::decode_hmp_delta( std::vector::const_iterator & it, std::vector::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 const& p_file, midi_container & p_out ) @@ -34,87 +34,89 @@ bool midi_processor::process_hmp( std::vector 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::const_iterator it = p_file.begin() + offset; - std::vector::const_iterator end = p_file.end(); + std::vector::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; - } + if ( buffer[ 1 ] != 0x2F ) + { + buffer[ 0 ] = buffer[ 1 ]; + continue; + } + break; + } - offset = is_funky ? 3 : 5; - if ( (unsigned long)(end - it) < offset ) return false; + 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 _buffer; _buffer.resize( 3 ); @@ -122,47 +124,47 @@ bool midi_processor::process_hmp( std::vector const& p_file, midi_conta std::vector::const_iterator track_end = it + track_size_32; while ( it != track_end ) - { + { unsigned delta = decode_hmp_delta( it, track_end ); - current_timestamp += delta; - if ( it == track_end ) return false; + current_timestamp += delta; + if ( it == track_end ) return false; _buffer[ 0 ] = *it++; - if ( _buffer[ 0 ] == 0xFF ) - { - if ( it == track_end ) return false; + if ( _buffer[ 0 ] == 0xFF ) + { + if ( it == track_end ) return false; _buffer[ 1 ] = *it++; int meta_count = decode_delta( it, track_end ); if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid HMP meta message" );*/ - if ( track_end - it < meta_count ) return false; + if ( track_end - it < meta_count ) return false; _buffer.resize( meta_count + 2 ); std::copy( it, it + meta_count, _buffer.begin() + 2 ); it += meta_count; track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &_buffer[0], meta_count + 2 ) ); - if ( _buffer[ 1 ] == 0x2F ) break; - } - else if ( _buffer[ 0 ] >= 0x80 && _buffer[ 0 ] <= 0xEF ) - { - unsigned bytes_read = 2; - switch ( _buffer[ 0 ] & 0xF0 ) - { - case 0xC0: - case 0xD0: - bytes_read = 1; + if ( _buffer[ 1 ] == 0x2F ) break; + } + else if ( _buffer[ 0 ] >= 0x80 && _buffer[ 0 ] <= 0xEF ) + { + unsigned bytes_read = 2; + switch ( _buffer[ 0 ] & 0xF0 ) + { + case 0xC0: + case 0xD0: + bytes_read = 1; } - if ( (unsigned long)(track_end - it) < bytes_read ) return false; + if ( (unsigned long)(track_end - it) < bytes_read ) return false; std::copy( it, it + bytes_read, _buffer.begin() + 1 ); it += bytes_read; track.add_event( midi_event( current_timestamp, (midi_event::event_type)( ( _buffer[ 0 ] >> 4 ) - 8 ), _buffer[ 0 ] & 0x0F, &_buffer[1], bytes_read ) ); - } + } else return false; /*throw exception_io_data( "Unexpected status code in HMP track" );*/ - } + } - offset = is_funky ? 0 : 4; - if ( end - it < (signed long)offset ) return false; + offset = is_funky ? 0 : 4; + if ( end - it < (signed long)offset ) return false; it = track_end + offset; - p_out.add_track( track ); - } + p_out.add_track( track ); + } return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_lds.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_lds.cpp index 98a711a9d..8b2958684 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_lds.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_lds.cpp @@ -53,13 +53,13 @@ bool midi_processor::is_lds( std::vector const& p_file, const char * p_ struct sound_patch { - // skip 11 bytes worth of Adlib crap + // skip 11 bytes worth of Adlib crap uint8_t keyoff; #ifdef ENABLE_WHEEL uint8_t portamento; int8_t glide; #endif - // skip 1 byte + // skip 1 byte #ifdef ENABLE_VIB uint8_t vibrato; uint8_t vibrato_delay; @@ -73,13 +73,13 @@ struct sound_patch uint8_t arpeggio; int8_t arpeggio_table[12]; #endif - // skip 4 bytes worth of digital instrument crap - // skip 3 more bytes worth of Adlib crap that isn't even used + // skip 4 bytes worth of digital instrument crap + // skip 3 more bytes worth of Adlib crap that isn't even used uint8_t midi_instrument; uint8_t midi_velocity; uint8_t midi_key; int8_t midi_transpose; - // skip 2 bytes worth of MIDI dummy fields or whatever + // skip 2 bytes worth of MIDI dummy fields or whatever }; struct channel_state { @@ -92,23 +92,23 @@ struct channel_state { uint8_t glideto, portspeed; #endif uint8_t nextvol, volmod, volcar, - keycount, packwait; + keycount, packwait; #ifdef ENABLE_VIB uint8_t vibwait, vibspeed, vibrate, vibcount; #endif #ifdef ENABLE_TREM uint8_t trmstay, trmwait, trmspeed, trmrate, trmcount, - trcwait, trcspeed, trcrate, trccount; + trcwait, trcspeed, trcrate, trccount; #endif #ifdef ENABLE_ARP uint8_t arp_count, arp_size, arp_speed, arp_pos; int8_t arp_tab[12]; #endif - struct { + struct { uint8_t chandelay, sound; uint16_t high; - } chancheat; + } chancheat; }; void playsound( uint8_t current_instrument[], std::vector const& patches, uint8_t last_note[], uint8_t last_channel[], uint8_t last_instrument[], uint8_t last_volume[], uint8_t last_sent_volume[], @@ -118,207 +118,207 @@ void playsound( uint8_t current_instrument[], std::vector const& pa channel_state * c, uint8_t allvolume, unsigned current_timestamp, unsigned sound, unsigned chan, unsigned high, midi_track & track ) { uint8_t buffer[ 2 ]; - current_instrument[ chan ] = sound; + current_instrument[ chan ] = sound; if ( sound >= patches.size() ) return; - const sound_patch & patch = patches[ current_instrument[ chan ] ]; - unsigned channel = ( patch.midi_instrument >= 0x80 ) ? 9 : ( chan == 9 ) ? 10 : chan; - unsigned saved_last_note = last_note[ chan ]; - unsigned note; - - if ( channel != 9 ) - { - // set fine tune - high += c->finetune; + const sound_patch & patch = patches[ current_instrument[ chan ] ]; + unsigned channel = ( patch.midi_instrument >= 0x80 ) ? 9 : ( chan == 9 ) ? 10 : chan; + unsigned saved_last_note = last_note[ chan ]; + unsigned note; - // arpeggio handling + if ( channel != 9 ) + { + // set fine tune + high += c->finetune; + + // arpeggio handling #ifdef ENABLE_ARP - if(patch.arpeggio) - { - short arpcalc = patch.arpeggio_table[0] << 4; + if(patch.arpeggio) + { + short arpcalc = patch.arpeggio_table[0] << 4; - high += arpcalc; - } + high += arpcalc; + } #endif - // and MIDI transpose - high = (int)high + ( patch.midi_transpose << 4 ); + // and MIDI transpose + high = (int)high + ( patch.midi_transpose << 4 ); - note = high + note = high #ifdef ENABLE_WHEEL - - c->lasttune + - c->lasttune #endif - ; + ; - // glide handling + // glide handling #ifdef ENABLE_WHEEL - if(c->glideto != 0) - { - c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune; - c->portspeed = c->glideto; - c->glideto = c->finetune = 0; - return; - } -#endif - - if ( patch.midi_instrument != last_instrument[ chan ] ) - { - buffer[ 0 ] = patch.midi_instrument; - track.add_event( midi_event( current_timestamp, midi_event::program_change, channel, buffer, 1 ) ); - last_instrument[ chan ] = patch.midi_instrument; - } - } - else - { - note = ( patch.midi_instrument & 0x7F ) << 4; - } - - unsigned volume = 127; - - if ( c->nextvol ) - { - volume = ( c->nextvol & 0x3F ) * 127 / 63; - last_volume[ chan ] = volume; - } - - if ( allvolume ) - { - volume = volume * allvolume / 255; - } - - if ( volume != last_sent_volume[ channel ] ) - { - buffer[ 0 ] = 7; - buffer[ 1 ] = volume; - track.add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) ); - last_sent_volume[ channel ] = volume; - } - - if ( saved_last_note != 0xFF ) - { - buffer[ 0 ] = saved_last_note; - buffer[ 1 ] = 127; - track.add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) ); - last_note[ chan ] = 0xFF; -#ifdef ENABLE_WHEEL - if ( channel != 9 ) - { - note += c->lasttune; - c->lasttune = 0; - if ( last_pitch_wheel[ channel ] != 0 ) - { - buffer[ 0 ] = 0; - buffer[ 1 ] = 64; - track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); - last_pitch_wheel[ channel ] = 0; - } - } -#endif - } -#ifdef ENABLE_WHEEL - if ( c->lasttune != last_pitch_wheel[ channel ] ) - { - buffer[ 0 ] = WHEEL_SCALE_LOW( c->lasttune ); - buffer[ 1 ] = WHEEL_SCALE_HIGH( c->lasttune ); - track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, channel, buffer, 2 ) ); - last_pitch_wheel[ channel ] = c->lasttune; - } - if( !patch.glide || last_note[ chan ] == 0xFF ) -#endif - { -#ifdef ENABLE_WHEEL - if( !patch.portamento || last_note[ chan ] == 0xFF ) -#endif - { - buffer[ 0 ] = note >> 4; - buffer[ 1 ] = patch.midi_velocity; - track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); - last_note[ chan ] = note >> 4; - last_channel[ chan ] = channel; -#ifdef ENABLE_WHEEL - c->gototune = c->lasttune; -#endif - } -#ifdef ENABLE_WHEEL - else - { + if(c->glideto != 0) + { c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune; - c->portspeed = patch.portamento; - buffer[ 0 ] = last_note[ chan ] = saved_last_note; - buffer[ 1 ] = patch.midi_velocity; - track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); - } + c->portspeed = c->glideto; + c->glideto = c->finetune = 0; + return; + } #endif - } + + if ( patch.midi_instrument != last_instrument[ chan ] ) + { + buffer[ 0 ] = patch.midi_instrument; + track.add_event( midi_event( current_timestamp, midi_event::program_change, channel, buffer, 1 ) ); + last_instrument[ chan ] = patch.midi_instrument; + } + } + else + { + note = ( patch.midi_instrument & 0x7F ) << 4; + } + + unsigned volume = 127; + + if ( c->nextvol ) + { + volume = ( c->nextvol & 0x3F ) * 127 / 63; + last_volume[ chan ] = volume; + } + + if ( allvolume ) + { + volume = volume * allvolume / 255; + } + + if ( volume != last_sent_volume[ channel ] ) + { + buffer[ 0 ] = 7; + buffer[ 1 ] = volume; + track.add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) ); + last_sent_volume[ channel ] = volume; + } + + if ( saved_last_note != 0xFF ) + { + buffer[ 0 ] = saved_last_note; + buffer[ 1 ] = 127; + track.add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) ); + last_note[ chan ] = 0xFF; #ifdef ENABLE_WHEEL - else - { - buffer[ 0 ] = note >> 4; - buffer[ 1 ] = patch.midi_velocity; - track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); - last_note[ chan ] = note >> 4; - last_channel[ chan ] = channel; - c->gototune = patch.glide; - c->portspeed = patch.portamento; - } + if ( channel != 9 ) + { + note += c->lasttune; + c->lasttune = 0; + if ( last_pitch_wheel[ channel ] != 0 ) + { + buffer[ 0 ] = 0; + buffer[ 1 ] = 64; + track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); + last_pitch_wheel[ channel ] = 0; + } + } +#endif + } +#ifdef ENABLE_WHEEL + if ( c->lasttune != last_pitch_wheel[ channel ] ) + { + buffer[ 0 ] = WHEEL_SCALE_LOW( c->lasttune ); + buffer[ 1 ] = WHEEL_SCALE_HIGH( c->lasttune ); + track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, channel, buffer, 2 ) ); + last_pitch_wheel[ channel ] = c->lasttune; + } + if( !patch.glide || last_note[ chan ] == 0xFF ) +#endif + { +#ifdef ENABLE_WHEEL + if( !patch.portamento || last_note[ chan ] == 0xFF ) +#endif + { + buffer[ 0 ] = note >> 4; + buffer[ 1 ] = patch.midi_velocity; + track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); + last_note[ chan ] = note >> 4; + last_channel[ chan ] = channel; +#ifdef ENABLE_WHEEL + c->gototune = c->lasttune; +#endif + } +#ifdef ENABLE_WHEEL + else + { + c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune; + c->portspeed = patch.portamento; + buffer[ 0 ] = last_note[ chan ] = saved_last_note; + buffer[ 1 ] = patch.midi_velocity; + track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); + } +#endif + } +#ifdef ENABLE_WHEEL + else + { + buffer[ 0 ] = note >> 4; + buffer[ 1 ] = patch.midi_velocity; + track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); + last_note[ chan ] = note >> 4; + last_channel[ chan ] = channel; + c->gototune = patch.glide; + c->portspeed = patch.portamento; + } #endif #ifdef ENABLE_VIB - if(!patch.vibrato) - { - c->vibwait = c->vibspeed = c->vibrate = 0; - } - else - { - c->vibwait = patch.vibrato_delay; - // PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; - c->vibspeed = (patch.vibrato >> 4) + 2; - c->vibrate = (patch.vibrato & 15) + 1; - } + if(!patch.vibrato) + { + c->vibwait = c->vibspeed = c->vibrate = 0; + } + else + { + c->vibwait = patch.vibrato_delay; + // PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; + c->vibspeed = (patch.vibrato >> 4) + 2; + c->vibrate = (patch.vibrato & 15) + 1; + } #endif #ifdef ENABLE_TREM - if(!(c->trmstay & 0xf0)) - { - c->trmwait = (patch.tremolo_delay & 0xf0) >> 3; - // PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; - c->trmspeed = patch.modulator_tremolo >> 4; - c->trmrate = patch.modulator_tremolo & 15; - c->trmcount = 0; - } + if(!(c->trmstay & 0xf0)) + { + c->trmwait = (patch.tremolo_delay & 0xf0) >> 3; + // PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; + c->trmspeed = patch.modulator_tremolo >> 4; + c->trmrate = patch.modulator_tremolo & 15; + c->trmcount = 0; + } - if(!(c->trmstay & 0x0f)) - { - c->trcwait = (patch.tremolo_delay & 15) << 1; - // PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; - c->trcspeed = patch.carrier_tremolo >> 4; - c->trcrate = patch.carrier_tremolo & 15; - c->trccount = 0; - } + if(!(c->trmstay & 0x0f)) + { + c->trcwait = (patch.tremolo_delay & 15) << 1; + // PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; + c->trcspeed = patch.carrier_tremolo >> 4; + c->trcrate = patch.carrier_tremolo & 15; + c->trccount = 0; + } #endif #ifdef ENABLE_ARP - c->arp_size = patch.arpeggio & 15; - c->arp_speed = patch.arpeggio >> 4; - memcpy(c->arp_tab, patch.arpeggio_table, 12); - c->arp_pos = c->arp_count = 0; + c->arp_size = patch.arpeggio & 15; + c->arp_speed = patch.arpeggio >> 4; + memcpy(c->arp_tab, patch.arpeggio_table, 12); + c->arp_pos = c->arp_count = 0; #endif #ifdef ENABLE_VIB - c->vibcount = 0; + c->vibcount = 0; #endif #ifdef ENABLE_WHEEL - c->glideto = 0; + c->glideto = 0; #endif - c->keycount = patch.keyoff; - c->nextvol = c->finetune = 0; + c->keycount = patch.keyoff; + c->nextvol = c->finetune = 0; } bool midi_processor::process_lds( std::vector const& p_file, midi_container & p_out ) { - struct position_data - { + struct position_data + { uint16_t pattern_number; uint8_t transpose; - }; + }; uint8_t mode; /*uint16_t speed;*/ @@ -334,30 +334,30 @@ bool midi_processor::process_lds( std::vector const& p_file, midi_conta std::vector patterns; std::vector::const_iterator it = p_file.begin(); - std::vector::const_iterator end = p_file.end(); + std::vector::const_iterator end = p_file.end(); - if ( end == it ) return false; + if ( end == it ) return false; mode = *it++; if ( mode > 2 ) return false; /*throw exception_io_data( "Invalid LDS mode" );*/ /*speed = it[ 0 ] | ( it[ 1 ] << 8 );*/ - if ( end - it < 4 ) return false; + if ( end - it < 4 ) return false; tempo = it[ 2 ]; pattern_length = it[ 3 ]; it += 4; - if ( end - it < 9 ) return false; - for ( unsigned i = 0; i < 9; ++i ) + if ( end - it < 9 ) return false; + for ( unsigned i = 0; i < 9; ++i ) channel_delay[ i ] = *it++; /*register_bd = *it++;*/ it++; - if ( end - it < 2 ) return false; + if ( end - it < 2 ) return false; patch_count = it[ 0 ] | ( it[ 1 ] << 8 ); - if ( !patch_count ) return false; + if ( !patch_count ) return false; it += 2; patches.resize( patch_count ); - if ( end - it < 46 * patch_count ) return false; - for ( unsigned i = 0; i < patch_count; ++i ) - { - sound_patch & patch = patches[ i ]; + if ( end - it < 46 * patch_count ) return false; + for ( unsigned i = 0; i < patch_count; ++i ) + { + sound_patch & patch = patches[ i ]; it += 11; patch.keyoff = *it++; #ifdef ENABLE_WHEEL @@ -382,7 +382,7 @@ bool midi_processor::process_lds( std::vector const& p_file, midi_conta #endif #ifdef ENABLE_ARP patch.arpeggio = *it++; - for ( unsigned j = 0; j < 12; ++j ) + for ( unsigned j = 0; j < 12; ++j ) patch.arpeggio_table[ j ] = *it++; it += 7; #else @@ -395,43 +395,43 @@ bool midi_processor::process_lds( std::vector const& p_file, midi_conta it += 2; #ifdef ENABLE_WHEEL - // hax - if ( patch.midi_instrument >= 0x80 ) - { - patch.glide = 0; - } + // hax + if ( patch.midi_instrument >= 0x80 ) + { + patch.glide = 0; + } #endif - } + } - if ( end - it < 2 ) return false; + if ( end - it < 2 ) return false; position_count = it[ 0 ] | ( it[ 1 ] << 8 ); - if ( !position_count ) return false; + if ( !position_count ) return false; it += 2; positions.resize( 9 * position_count ); - if ( end - it < 3 * position_count ) return false; - for ( unsigned i = 0; i < position_count; ++i ) - { - for ( unsigned j = 0; j < 9; ++j ) - { - position_data & position = positions[ i * 9 + j ]; + if ( end - it < 3 * position_count ) return false; + for ( unsigned i = 0; i < position_count; ++i ) + { + for ( unsigned j = 0; j < 9; ++j ) + { + position_data & position = positions[ i * 9 + j ]; position.pattern_number = it[ 0 ] | ( it[ 1 ] << 8 ); if ( position.pattern_number & 1 ) return false; /*throw exception_io_data( "Odd LDS pattern number" );*/ - position.pattern_number >>= 1; + position.pattern_number >>= 1; position.transpose = it[ 2 ]; it += 3; - } - } + } + } - if ( end - it < 2 ) return false; + if ( end - it < 2 ) return false; it += 2; pattern_count = ( end - it ) / 2; patterns.resize( pattern_count ); - for ( unsigned i = 0; i < pattern_count; ++i ) - { + for ( unsigned i = 0; i < pattern_count; ++i ) + { patterns[ i ] = it[ 0 ] | ( it[ 1 ] << 8 ); it += 2; - } + } uint8_t /*jumping,*/ fadeonoff, allvolume, hardfade, tempo_now, pattplay; uint16_t posplay, jumppos; @@ -453,76 +453,76 @@ bool midi_processor::process_lds( std::vector const& p_file, midi_conta #endif uint8_t ticks_without_notes[11]; - memset( last_channel, 0, sizeof( last_channel ) ); - memset( last_instrument, 0xFF, sizeof( last_instrument ) ); - memset( last_note, 0xFF, sizeof( last_note ) ); - memset( last_volume, 127, sizeof( last_volume ) ); - memset( last_sent_volume, 127, sizeof( last_sent_volume ) ); + memset( last_channel, 0, sizeof( last_channel ) ); + memset( last_instrument, 0xFF, sizeof( last_instrument ) ); + memset( last_note, 0xFF, sizeof( last_note ) ); + memset( last_volume, 127, sizeof( last_volume ) ); + memset( last_sent_volume, 127, sizeof( last_sent_volume ) ); #ifdef ENABLE_WHEEL - memset( last_pitch_wheel, 0, sizeof( last_pitch_wheel ) ); + memset( last_pitch_wheel, 0, sizeof( last_pitch_wheel ) ); #endif - memset( ticks_without_notes, 0, sizeof( ticks_without_notes ) ); + memset( ticks_without_notes, 0, sizeof( ticks_without_notes ) ); - unsigned current_timestamp = 0; + unsigned current_timestamp = 0; uint8_t buffer[ 2 ]; - p_out.initialize( 1, 35 ); + p_out.initialize( 1, 35 ); - { - midi_track track; - track.add_event( midi_event( 0, midi_event::extended, 0, lds_default_tempo, _countof( lds_default_tempo ) ) ); - for ( unsigned i = 0; i < 11; ++i ) - { - buffer[ 0 ] = 120; - buffer[ 1 ] = 0; - track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); - buffer[ 0 ] = 121; - track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); + { + midi_track track; + track.add_event( midi_event( 0, midi_event::extended, 0, lds_default_tempo, _countof( lds_default_tempo ) ) ); + for ( unsigned i = 0; i < 11; ++i ) + { + buffer[ 0 ] = 120; + buffer[ 1 ] = 0; + track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); + buffer[ 0 ] = 121; + track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); #ifdef ENABLE_WHEEL - buffer[ 0 ] = 0x65; - track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); - buffer[ 0 ] = 0x64; - track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); - buffer[ 0 ] = 0x06; - buffer[ 1 ] = WHEEL_RANGE_HIGH; - track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); - buffer[ 0 ] = 0x26; - buffer[ 1 ] = WHEEL_RANGE_LOW; - track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); - buffer[ 0 ] = 0; - buffer[ 1 ] = 64; - track.add_event( midi_event( 0, midi_event::pitch_wheel, i, buffer, 2 ) ); + buffer[ 0 ] = 0x65; + track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); + buffer[ 0 ] = 0x64; + track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); + buffer[ 0 ] = 0x06; + buffer[ 1 ] = WHEEL_RANGE_HIGH; + track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); + buffer[ 0 ] = 0x26; + buffer[ 1 ] = WHEEL_RANGE_LOW; + track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); + buffer[ 0 ] = 0; + buffer[ 1 ] = 64; + track.add_event( midi_event( 0, midi_event::pitch_wheel, i, buffer, 2 ) ); #endif - } - track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); - p_out.add_track( track ); - } + } + track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); + p_out.add_track( track ); + } std::vector tracks; - { - midi_track track; - track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); + { + midi_track track; + track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); tracks.resize( 10, track ); - } + } - tempo_now = 3; + tempo_now = 3; /*jumping = 0;*/ - fadeonoff = 0; - allvolume = 0; - hardfade = 0; - pattplay = 0; - posplay = 0; - jumppos = 0; - mainvolume = 0; + fadeonoff = 0; + allvolume = 0; + hardfade = 0; + pattplay = 0; + posplay = 0; + jumppos = 0; + mainvolume = 0; memset( &channel[0], 0, sizeof( channel_state ) * 9 ); const uint16_t maxsound = 0x3F; const uint16_t maxpos = 0xFF; - bool playing = true; - while ( playing ) - { + bool playing = true; + while ( playing ) + { uint16_t chan; #ifdef ENABLE_VIB uint16_t wibc; @@ -536,514 +536,514 @@ bool midi_processor::process_lds( std::vector const& p_file, midi_conta #ifdef ENABLE_TREM uint16_t tremc; #endif - bool vbreak; - unsigned i; - channel_state * c; + bool vbreak; + unsigned i; + channel_state * c; - if(fadeonoff) - { - if(fadeonoff <= 128) - { - if(allvolume > fadeonoff || allvolume == 0) - { - allvolume -= fadeonoff; - } - else - { - allvolume = 1; - fadeonoff = 0; - if(hardfade != 0) - { - playing = false; - hardfade = 0; - for(i = 0; i < 9; i++) - channel[i].keycount = 1; - } - } - } - else if((unsigned)((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) - { - allvolume += 0x100 - fadeonoff; - } - else - { - allvolume = mainvolume; - fadeonoff = 0; - } - } + if(fadeonoff) + { + if(fadeonoff <= 128) + { + if(allvolume > fadeonoff || allvolume == 0) + { + allvolume -= fadeonoff; + } + else + { + allvolume = 1; + fadeonoff = 0; + if(hardfade != 0) + { + playing = false; + hardfade = 0; + for(i = 0; i < 9; i++) + channel[i].keycount = 1; + } + } + } + else if((unsigned)((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) + { + allvolume += 0x100 - fadeonoff; + } + else + { + allvolume = mainvolume; + fadeonoff = 0; + } + } - // handle channel delay - for(chan = 0; chan < 9; ++chan) - { - channel_state * _c = &channel[chan]; - if(_c->chancheat.chandelay) - { - if(!(--_c->chancheat.chandelay)) - { - playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume, + // handle channel delay + for(chan = 0; chan < 9; ++chan) + { + channel_state * _c = &channel[chan]; + if(_c->chancheat.chandelay) + { + if(!(--_c->chancheat.chandelay)) + { + playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume, #ifdef ENABLE_WHEEL - last_pitch_wheel, + last_pitch_wheel, #endif - _c, allvolume, current_timestamp, _c->chancheat.sound, chan, _c->chancheat.high, tracks[ chan ] ); - ticks_without_notes[ last_channel[ chan ] ] = 0; - } - } - } + _c, allvolume, current_timestamp, _c->chancheat.sound, chan, _c->chancheat.high, tracks[ chan ] ); + ticks_without_notes[ last_channel[ chan ] ] = 0; + } + } + } - // handle notes - if(!tempo_now) - { + // handle notes + if(!tempo_now) + { if ( pattplay == 0 && position_timestamps[ posplay ] == ~0u ) - { - position_timestamps[ posplay ] = current_timestamp; - } + { + position_timestamps[ posplay ] = current_timestamp; + } - vbreak = false; - for(unsigned _chan = 0; _chan < 9; _chan++) - { - channel_state * _c = &channel[_chan]; - if(!_c->packwait) - { - unsigned short patnum = positions[posplay * 9 + _chan].pattern_number; - unsigned char transpose = positions[posplay * 9 + _chan].transpose; + vbreak = false; + for(unsigned _chan = 0; _chan < 9; _chan++) + { + channel_state * _c = &channel[_chan]; + if(!_c->packwait) + { + unsigned short patnum = positions[posplay * 9 + _chan].pattern_number; + unsigned char transpose = positions[posplay * 9 + _chan].transpose; if ( (unsigned long)(patnum + _c->packpos) >= patterns.size() ) return false; /*throw exception_io_data( "Invalid LDS pattern number" );*/ - unsigned comword = patterns[patnum + _c->packpos]; - unsigned comhi = comword >> 8; - unsigned comlo = comword & 0xff; - if(comword) - { - if(comhi == 0x80) - { - _c->packwait = comlo; - } - else if(comhi >= 0x80) - { - switch(comhi) { - case 0xff: - { - unsigned volume = ( comlo & 0x3F ) * 127 / 63; - last_volume[ _chan ] = volume; - if ( volume != last_sent_volume[ last_channel[ _chan ] ] ) - { - buffer[ 0 ] = 7; - buffer[ 1 ] = volume; - tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) ); - last_sent_volume[ last_channel [ _chan ] ] = volume; - } - } - break; - case 0xfe: - tempo = comword & 0x3f; - break; - case 0xfd: - _c->nextvol = comlo; - break; - case 0xfc: - playing = false; - // in real player there's also full keyoff here, but we don't need it - break; - case 0xfb: - _c->keycount = 1; - break; - case 0xfa: - vbreak = true; - jumppos = (posplay + 1) & maxpos; - break; - case 0xf9: - vbreak = true; - jumppos = comlo & maxpos; + unsigned comword = patterns[patnum + _c->packpos]; + unsigned comhi = comword >> 8; + unsigned comlo = comword & 0xff; + if(comword) + { + if(comhi == 0x80) + { + _c->packwait = comlo; + } + else if(comhi >= 0x80) + { + switch(comhi) { + case 0xff: + { + unsigned volume = ( comlo & 0x3F ) * 127 / 63; + last_volume[ _chan ] = volume; + if ( volume != last_sent_volume[ last_channel[ _chan ] ] ) + { + buffer[ 0 ] = 7; + buffer[ 1 ] = volume; + tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) ); + last_sent_volume[ last_channel [ _chan ] ] = volume; + } + } + break; + case 0xfe: + tempo = comword & 0x3f; + break; + case 0xfd: + _c->nextvol = comlo; + break; + case 0xfc: + playing = false; + // in real player there's also full keyoff here, but we don't need it + break; + case 0xfb: + _c->keycount = 1; + break; + case 0xfa: + vbreak = true; + jumppos = (posplay + 1) & maxpos; + break; + case 0xf9: + vbreak = true; + jumppos = comlo & maxpos; /*jumping = 1;*/ - if(jumppos <= posplay) - { - p_out.add_track_event( 0, midi_event( position_timestamps[ jumppos ], midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); - p_out.add_track_event( 0, midi_event( current_timestamp + tempo - 1, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); - playing = false; - } - break; - case 0xf8: + if(jumppos <= posplay) + { + p_out.add_track_event( 0, midi_event( position_timestamps[ jumppos ], midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); + p_out.add_track_event( 0, midi_event( current_timestamp + tempo - 1, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); + playing = false; + } + break; + case 0xf8: #ifdef ENABLE_WHEEL - _c->lasttune = 0; + _c->lasttune = 0; #endif - break; - case 0xf7: + break; + case 0xf7: #ifdef ENABLE_VIB - _c->vibwait = 0; - // PASCAL: _c->vibspeed = ((comlo >> 4) & 15) + 2; - _c->vibspeed = (comlo >> 4) + 2; - _c->vibrate = (comlo & 15) + 1; + _c->vibwait = 0; + // PASCAL: _c->vibspeed = ((comlo >> 4) & 15) + 2; + _c->vibspeed = (comlo >> 4) + 2; + _c->vibrate = (comlo & 15) + 1; #endif - break; - case 0xf6: + break; + case 0xf6: #ifdef ENABLE_WHEEL - _c->glideto = comlo; + _c->glideto = comlo; #endif - break; - case 0xf5: - _c->finetune = comlo; - break; - case 0xf4: - if(!hardfade) { - allvolume = mainvolume = comlo; - fadeonoff = 0; - } - break; - case 0xf3: - if(!hardfade) fadeonoff = comlo; - break; - case 0xf2: + break; + case 0xf5: + _c->finetune = comlo; + break; + case 0xf4: + if(!hardfade) { + allvolume = mainvolume = comlo; + fadeonoff = 0; + } + break; + case 0xf3: + if(!hardfade) fadeonoff = comlo; + break; + case 0xf2: #ifdef ENABLE_TREM - _c->trmstay = comlo; + _c->trmstay = comlo; #endif - break; - case 0xf1: - buffer[ 0 ] = 10; - buffer[ 1 ] = ( comlo & 0x3F ) * 127 / 63; - tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) ); - break; - case 0xf0: - buffer[ 0 ] = comlo & 0x7F; - tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::program_change, last_channel[ _chan ], buffer, 1 ) ); - break; - default: + break; + case 0xf1: + buffer[ 0 ] = 10; + buffer[ 1 ] = ( comlo & 0x3F ) * 127 / 63; + tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) ); + break; + case 0xf0: + buffer[ 0 ] = comlo & 0x7F; + tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::program_change, last_channel[ _chan ], buffer, 1 ) ); + break; + default: #ifdef ENABLE_WHEEL - if(comhi < 0xa0) - _c->glideto = comhi & 0x1f; + if(comhi < 0xa0) + _c->glideto = comhi & 0x1f; #endif - break; - } - } - else - { - unsigned char sound; - unsigned short high; - signed char transp = transpose << 1; - transp >>= 1; + break; + } + } + else + { + unsigned char sound; + unsigned short high; + signed char transp = transpose << 1; + transp >>= 1; - if(transpose & 128) { - sound = (comlo + transp) & maxsound; - high = comhi << 4; - } else { - sound = comlo & maxsound; - high = (comhi + transp) << 4; - } + if(transpose & 128) { + sound = (comlo + transp) & maxsound; + high = comhi << 4; + } else { + sound = comlo & maxsound; + high = (comhi + transp) << 4; + } - /* - PASCAL: - sound = comlo & maxsound; - high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; - */ + /* + PASCAL: + sound = comlo & maxsound; + high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; + */ - if( !channel_delay[ _chan ] ) - { - playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume, + if( !channel_delay[ _chan ] ) + { + playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume, #ifdef ENABLE_WHEEL - last_pitch_wheel, + last_pitch_wheel, #endif - _c, allvolume, current_timestamp, sound, _chan, high, tracks[ _chan ] ); - ticks_without_notes[ last_channel[ _chan ] ] = 0; - } - else - { - _c->chancheat.chandelay = channel_delay[_chan]; - _c->chancheat.sound = sound; - _c->chancheat.high = high; - } - } - } - _c->packpos++; - } - else - { - _c->packwait--; - } - } + _c, allvolume, current_timestamp, sound, _chan, high, tracks[ _chan ] ); + ticks_without_notes[ last_channel[ _chan ] ] = 0; + } + else + { + _c->chancheat.chandelay = channel_delay[_chan]; + _c->chancheat.sound = sound; + _c->chancheat.high = high; + } + } + } + _c->packpos++; + } + else + { + _c->packwait--; + } + } - tempo_now = tempo; - /* - The continue table is updated here, but this is only used in the - original player, which can be paused in the middle of a song and then - unpaused. Since AdPlug does all this for us automatically, we don't - have a continue table here. The continue table update code is noted - here for reference only. + tempo_now = tempo; + /* + The continue table is updated here, but this is only used in the + original player, which can be paused in the middle of a song and then + unpaused. Since AdPlug does all this for us automatically, we don't + have a continue table here. The continue table update code is noted + here for reference only. - if(!pattplay) { - conttab[speed & maxcont].position = posplay & 0xff; - conttab[speed & maxcont].tempo = tempo; - } - */ - pattplay++; - if(vbreak) - { - pattplay = 0; - for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; - posplay = jumppos; + if(!pattplay) { + conttab[speed & maxcont].position = posplay & 0xff; + conttab[speed & maxcont].tempo = tempo; + } + */ + pattplay++; + if(vbreak) + { + pattplay = 0; + for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; + posplay = jumppos; if ( posplay >= position_count ) return false; /*throw exception_io_data( "Invalid LDS position jump" );*/ - } - else if(pattplay >= pattern_length) - { - pattplay = 0; - for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; - posplay = (posplay + 1) & maxpos; - if ( posplay >= position_count ) playing = false; //throw exception_io_data( "LDS reached the end without a loop or end command" ); - } - } - else - { - tempo_now--; - } + } + else if(pattplay >= pattern_length) + { + pattplay = 0; + for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; + posplay = (posplay + 1) & maxpos; + if ( posplay >= position_count ) playing = false; //throw exception_io_data( "LDS reached the end without a loop or end command" ); + } + } + else + { + tempo_now--; + } - // make effects - for(chan = 0; chan < 9; ++chan) - { - c = &channel[chan]; - if(c->keycount > 0) - { - if( c->keycount == 1 && last_note[ chan ] != 0xFF ) - { - buffer[ 0 ] = last_note[ chan ]; - buffer[ 1 ] = 127; - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) ); - last_note[ chan ] = 0xFF; + // make effects + for(chan = 0; chan < 9; ++chan) + { + c = &channel[chan]; + if(c->keycount > 0) + { + if( c->keycount == 1 && last_note[ chan ] != 0xFF ) + { + buffer[ 0 ] = last_note[ chan ]; + buffer[ 1 ] = 127; + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) ); + last_note[ chan ] = 0xFF; #ifdef ENABLE_WHEEL - if ( 0 != last_pitch_wheel[ last_channel[ chan ] ] ) - { - buffer[ 0 ] = 0; - buffer[ 1 ] = 64; - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); - last_pitch_wheel[ last_channel[ chan ] ] = 0; - c->lasttune = 0; - c->gototune = 0; - } + if ( 0 != last_pitch_wheel[ last_channel[ chan ] ] ) + { + buffer[ 0 ] = 0; + buffer[ 1 ] = 64; + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); + last_pitch_wheel[ last_channel[ chan ] ] = 0; + c->lasttune = 0; + c->gototune = 0; + } #endif - } - c->keycount--; - } + } + c->keycount--; + } #ifdef ENABLE_ARP - // arpeggio - if(c->arp_size == 0) - { - arpreg = 0; - } - else - { - arpreg = c->arp_tab[c->arp_pos] << 4; - if(arpreg == -0x800) - { - if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; - c->arp_size = 1; c->arp_pos = 0; - arpreg = c->arp_tab[0] << 4; - } + // arpeggio + if(c->arp_size == 0) + { + arpreg = 0; + } + else + { + arpreg = c->arp_tab[c->arp_pos] << 4; + if(arpreg == -0x800) + { + if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; + c->arp_size = 1; c->arp_pos = 0; + arpreg = c->arp_tab[0] << 4; + } - if(c->arp_count == c->arp_speed) { - c->arp_pos++; - if(c->arp_pos >= c->arp_size) c->arp_pos = 0; - c->arp_count = 0; - } - else - { - c->arp_count++; - } - } + if(c->arp_count == c->arp_speed) { + c->arp_pos++; + if(c->arp_pos >= c->arp_size) c->arp_pos = 0; + c->arp_count = 0; + } + else + { + c->arp_count++; + } + } #endif #ifdef ENABLE_WHEEL - // glide & portamento - if(c->lasttune != c->gototune) - { - if(c->lasttune > c->gototune) - { - if(c->lasttune - c->gototune < c->portspeed) - { - c->lasttune = c->gototune; - } - else - { - c->lasttune -= c->portspeed; - } - } - else - { - if(c->gototune - c->lasttune < c->portspeed) - { - c->lasttune = c->gototune; - } - else - { - c->lasttune += c->portspeed; - } - } + // glide & portamento + if(c->lasttune != c->gototune) + { + if(c->lasttune > c->gototune) + { + if(c->lasttune - c->gototune < c->portspeed) + { + c->lasttune = c->gototune; + } + else + { + c->lasttune -= c->portspeed; + } + } + else + { + if(c->gototune - c->lasttune < c->portspeed) + { + c->lasttune = c->gototune; + } + else + { + c->lasttune += c->portspeed; + } + } #ifdef ENABLE_ARP - arpreg += + arpreg += #else int16_t arpreg = #endif - c->lasttune; + c->lasttune; - if ( arpreg != last_pitch_wheel[ last_channel[ chan ] ] ) - { - buffer[ 0 ] = WHEEL_SCALE_LOW( arpreg ); - buffer[ 1 ] = WHEEL_SCALE_HIGH( arpreg ); - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); - last_pitch_wheel[ last_channel[ chan ] ] = arpreg; - } - } else - { + if ( arpreg != last_pitch_wheel[ last_channel[ chan ] ] ) + { + buffer[ 0 ] = WHEEL_SCALE_LOW( arpreg ); + buffer[ 1 ] = WHEEL_SCALE_HIGH( arpreg ); + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); + last_pitch_wheel[ last_channel[ chan ] ] = arpreg; + } + } else + { #ifdef ENABLE_VIB - // vibrato - if(!c->vibwait) - { - if(c->vibrate) - { - wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; + // vibrato + if(!c->vibwait) + { + if(c->vibrate) + { + wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; - if((c->vibcount & 0x40) == 0) - tune = c->lasttune + (wibc >> 8); - else - tune = c->lasttune - (wibc >> 8); + if((c->vibcount & 0x40) == 0) + tune = c->lasttune + (wibc >> 8); + else + tune = c->lasttune - (wibc >> 8); #ifdef ENABLE_ARP - tune += arpreg; + tune += arpreg; #endif - if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) - { - buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); - buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); - last_pitch_wheel[ last_channel[ chan ] ] = tune; - } + if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) + { + buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); + buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); + last_pitch_wheel[ last_channel[ chan ] ] = tune; + } - c->vibcount += c->vibspeed; - } + c->vibcount += c->vibspeed; + } #ifdef ENABLE_ARP - else if(c->arp_size != 0) - { // no vibrato, just arpeggio - tune = c->lasttune + arpreg; + else if(c->arp_size != 0) + { // no vibrato, just arpeggio + tune = c->lasttune + arpreg; - if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) - { - buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); - buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); - last_pitch_wheel[ last_channel[ chan ] ] = tune; - } - } + if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) + { + buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); + buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); + last_pitch_wheel[ last_channel[ chan ] ] = tune; + } + } #endif - } + } #ifdef ENABLE_ARP - else + else #endif #endif #ifdef ENABLE_ARP - { // no vibrato, just arpeggio + { // no vibrato, just arpeggio #ifdef ENABLE_VIB - c->vibwait--; + c->vibwait--; #endif - if(c->arp_size != 0) - { - tune = c->lasttune + arpreg; + if(c->arp_size != 0) + { + tune = c->lasttune + arpreg; - if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) - { - buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); - buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); - last_pitch_wheel[ last_channel[ chan ] ] = tune; - } - } - } + if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) + { + buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); + buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); + last_pitch_wheel[ last_channel[ chan ] ] = tune; + } + } + } #endif - } + } #endif #ifdef ENABLE_TREM - unsigned volume = last_volume[ chan ]; + unsigned volume = last_volume[ chan ]; - // tremolo (modulator) - if(!c->trmwait) - { - if(c->trmrate) - { - tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; - if((tremc >> 7) <= volume) - volume = volume - (tremc >> 7); - else - volume = 0; + // tremolo (modulator) + if(!c->trmwait) + { + if(c->trmrate) + { + tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; + if((tremc >> 7) <= volume) + volume = volume - (tremc >> 7); + else + volume = 0; - c->trmcount += c->trmspeed; - } - } - else - { - c->trmwait--; - } + c->trmcount += c->trmspeed; + } + } + else + { + c->trmwait--; + } - // tremolo (carrier) - if(!c->trcwait) - { - if(c->trcrate) - { - tremc = tremtab[c->trccount & 0x7f] * c->trcrate; - if((tremc >> 7) <= volume) - volume = volume - (tremc >> 8); - else - volume = 0; - } - } - else - { - c->trcwait--; - } + // tremolo (carrier) + if(!c->trcwait) + { + if(c->trcrate) + { + tremc = tremtab[c->trccount & 0x7f] * c->trcrate; + if((tremc >> 7) <= volume) + volume = volume - (tremc >> 8); + else + volume = 0; + } + } + else + { + c->trcwait--; + } - if ( allvolume ) - { - volume = volume * allvolume / 255; - } + if ( allvolume ) + { + volume = volume * allvolume / 255; + } - if ( volume != last_sent_volume[ last_channel[ chan ] ] ) - { - buffer[ 0 ] = 7; - buffer[ 1 ] = volume; - tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) ); - last_sent_volume[ last_channel[ chan ] ] = volume; - } + if ( volume != last_sent_volume[ last_channel[ chan ] ] ) + { + buffer[ 0 ] = 7; + buffer[ 1 ] = volume; + tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) ); + last_sent_volume[ last_channel[ chan ] ] = volume; + } #endif - } + } - ++current_timestamp; - } + ++current_timestamp; + } - --current_timestamp; + --current_timestamp; - for ( unsigned i = 0; i < 9; ++i ) - { - midi_track & track = tracks[ i ]; - unsigned long count = track.get_count(); - if ( count > 1 ) - { - if ( last_note[ i ] != 0xFF ) - { - buffer[ 0 ] = last_note[ i ]; - buffer[ 1 ] = 127; - track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::note_off, last_channel[ i ], buffer, 2 ) ); + for ( unsigned i = 0; i < 9; ++i ) + { + midi_track & track = tracks[ i ]; + unsigned long count = track.get_count(); + if ( count > 1 ) + { + if ( last_note[ i ] != 0xFF ) + { + buffer[ 0 ] = last_note[ i ]; + buffer[ 1 ] = 127; + track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::note_off, last_channel[ i ], buffer, 2 ) ); #ifdef ENABLE_WHEEL - if ( last_pitch_wheel[ last_channel[ i ] ] != 0 ) - { - buffer[ 0 ] = 0; - buffer[ 1 ] = 0x40; - track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::pitch_wheel, last_channel[ i ], buffer, 2 ) ); - } + if ( last_pitch_wheel[ last_channel[ i ] ] != 0 ) + { + buffer[ 0 ] = 0; + buffer[ 1 ] = 0x40; + track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::pitch_wheel, last_channel[ i ], buffer, 2 ) ); + } #endif - } - p_out.add_track( track ); - } - } + } + p_out.add_track( track ); + } + } return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_mids.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_mids.cpp index 88ed83d13..da0f62f28 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_mids.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_mids.cpp @@ -13,122 +13,124 @@ bool midi_processor::is_mids( std::vector const& p_file ) bool midi_processor::process_mids( std::vector const& p_file, midi_container & p_out ) { - if ( p_file.size() < 20 ) return false; + if ( p_file.size() < 20 ) return false; std::vector::const_iterator it = p_file.begin() + 16; - std::vector::const_iterator end = p_file.end(); + std::vector::const_iterator end = p_file.end(); uint32_t fmt_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; - if ( (unsigned long)(end - it) < fmt_size ) return false; + if ( (unsigned long)(end - it) < fmt_size ) return false; uint32_t time_format = 1; /*uint32_t max_buffer = 0;*/ uint32_t flags = 0; - if ( fmt_size >= 4 ) - { + if ( fmt_size >= 4 ) + { time_format = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; fmt_size -= 4; - } - if ( fmt_size >= 4 ) - { + if ( !time_format ) // dtx == 0, will cause division by zero on tempo calculations + return false; + } + if ( fmt_size >= 4 ) + { /*max_buffer = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );*/ it += 4; - fmt_size -= 4; - } - if ( fmt_size >= 4 ) - { + fmt_size -= 4; + } + if ( fmt_size >= 4 ) + { flags = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; - fmt_size -= 4; - } + fmt_size -= 4; + } it += fmt_size; - if ( it == end ) return false; + if ( it == end ) return false; if ( fmt_size & 1 ) ++it; - p_out.initialize( 0, time_format ); + p_out.initialize( 0, time_format ); - if ( end - it < 4 ) return false; + if ( end - it < 4 ) return false; if ( it[ 0 ] != 'd' || it[ 1 ] != 'a' || it[ 2 ] != 't' || it[ 3 ] != 'a' ) return false; /*throw exception_io_data( "MIDS missing RIFF data chunk" );*/ it += 4; - { - midi_track track; - 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, end_of_track, _countof( end_of_track ) ) ); + p_out.add_track( track ); + } - if ( end - it < 4 ) return false; + if ( end - it < 4 ) return false; uint32_t data_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; std::vector::const_iterator body_end = it + data_size; - if ( body_end - it < 4 ) return false; + if ( body_end - it < 4 ) return false; uint32_t segment_count = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; - bool is_eight_byte = !!(flags & 1); + bool is_eight_byte = !!(flags & 1); - midi_track track; + midi_track track; - unsigned current_timestamp = 0; + unsigned current_timestamp = 0; - for ( unsigned i = 0; i < segment_count; ++i ) - { - if ( end - it < 12 ) return false; + for ( unsigned i = 0; i < segment_count; ++i ) + { + if ( end - it < 12 ) return false; it += 4; uint32_t segment_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; std::vector::const_iterator segment_end = it + segment_size; while ( it != segment_end && it != body_end ) - { - if ( segment_end - it < 4 ) return false; + { + if ( segment_end - it < 4 ) return false; uint32_t delta = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; uint32_t event; - current_timestamp += delta; + current_timestamp += delta; if ( !is_eight_byte ) - { - if ( segment_end - it < 4 ) return false; - it += 4; - } - if ( segment_end - it < 4 ) return false; + { + if ( segment_end - it < 4 ) return false; + it += 4; + } + if ( segment_end - it < 4 ) return false; event = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); it += 4; - if ( event >> 24 == 0x01 ) - { + if ( event >> 24 == 0x01 ) + { uint8_t buffer[ 5 ] = { 0xFF, 0x51 }; buffer[ 2 ] = (uint8_t)( event >> 16 ); buffer[ 3 ] = (uint8_t)( event >> 8 ); buffer[ 4 ] = (uint8_t)event; - p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, buffer, sizeof( buffer ) ) ); - } - else if ( !( event >> 24 ) ) - { - unsigned event_code = ( event & 0xF0 ) >> 4; - if ( event_code >= 0x8 && event_code <= 0xE ) - { - unsigned bytes_to_write = 1; + p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, buffer, sizeof( buffer ) ) ); + } + else if ( !( event >> 24 ) ) + { + unsigned event_code = ( event & 0xF0 ) >> 4; + if ( event_code >= 0x8 && event_code <= 0xE ) + { + unsigned bytes_to_write = 1; uint8_t buffer[2]; buffer[ 0 ] = (uint8_t)( event >> 8 ); - if ( event_code != 0xC && event_code != 0xD ) - { + if ( event_code != 0xC && event_code != 0xD ) + { buffer[ 1 ] = (uint8_t)( event >> 16 ); - bytes_to_write = 2; - } - track.add_event( midi_event( current_timestamp, (midi_event::event_type)( event_code - 8 ), event & 0x0F, buffer, bytes_to_write ) ); - } - } - } - } + bytes_to_write = 2; + } + track.add_event( midi_event( current_timestamp, (midi_event::event_type)( event_code - 8 ), event & 0x0F, buffer, bytes_to_write ) ); + } + } + } + } - track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); + track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); - p_out.add_track( track ); + p_out.add_track( track ); return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_mus.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_mus.cpp index 24b4b8090..2e0f6085c 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_mus.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_mus.cpp @@ -20,132 +20,132 @@ bool midi_processor::process_mus( std::vector const& p_file, midi_conta uint16_t length = p_file[ 4 ] | ( p_file[ 5 ] << 8 ); uint16_t offset = p_file[ 6 ] | ( p_file[ 7 ] << 8 ); - p_out.initialize( 0, 0x59 ); + p_out.initialize( 0, 0x59 ); - { - midi_track track; - track.add_event( midi_event( 0, midi_event::extended, 0, mus_default_tempo, _countof( mus_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, mus_default_tempo, _countof( mus_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; + midi_track track; - unsigned current_timestamp = 0; + unsigned current_timestamp = 0; uint8_t velocity_levels[ 16 ] = { 0 }; - if ( (size_t)offset >= p_file.size() || (size_t)(offset + length) > p_file.size() ) - return false; + if ( (size_t)offset >= p_file.size() || (size_t)(offset + length) > p_file.size() ) + return false; std::vector::const_iterator it = p_file.begin() + offset, end = p_file.begin() + offset + length; uint8_t buffer[ 4 ]; while ( it != end ) - { + { buffer[ 0 ] = *it++; - if ( buffer[ 0 ] == 0x60 ) break; + if ( buffer[ 0 ] == 0x60 ) break; - midi_event::event_type type; + midi_event::event_type type; - unsigned bytes_to_write; + unsigned bytes_to_write; - unsigned channel = buffer[ 0 ] & 0x0F; - if ( channel == 0x0F ) channel = 9; - else if ( channel >= 9 ) ++channel; + unsigned channel = buffer[ 0 ] & 0x0F; + if ( channel == 0x0F ) channel = 9; + else if ( channel >= 9 ) ++channel; - switch ( buffer[ 0 ] & 0x70 ) - { - case 0x00: - type = midi_event::note_on; - if ( it == end ) return false; + switch ( buffer[ 0 ] & 0x70 ) + { + case 0x00: + type = midi_event::note_on; + if ( it == end ) return false; buffer[ 1 ] = *it++; - buffer[ 2 ] = 0; - bytes_to_write = 2; - break; + buffer[ 2 ] = 0; + bytes_to_write = 2; + break; - case 0x10: - type = midi_event::note_on; - if ( it == end ) return false; + case 0x10: + type = midi_event::note_on; + if ( it == end ) return false; buffer[ 1 ] = *it++; - if ( buffer[ 1 ] & 0x80 ) - { - if ( it == end ) return false; + if ( buffer[ 1 ] & 0x80 ) + { + if ( it == end ) return false; buffer[ 2 ] = *it++; - velocity_levels[ channel ] = buffer[ 2 ]; - buffer[ 1 ] &= 0x7F; - } - else - { - buffer[ 2 ] = velocity_levels[ channel ]; - } - bytes_to_write = 2; - break; + velocity_levels[ channel ] = buffer[ 2 ]; + buffer[ 1 ] &= 0x7F; + } + else + { + buffer[ 2 ] = velocity_levels[ channel ]; + } + bytes_to_write = 2; + break; - case 0x20: - type = midi_event::pitch_wheel; - if ( it == end ) return false; + case 0x20: + type = midi_event::pitch_wheel; + if ( it == end ) return false; buffer[ 1 ] = *it++; - buffer[ 2 ] = buffer[ 1 ] >> 1; - buffer[ 1 ] <<= 7; - bytes_to_write = 2; - break; + buffer[ 2 ] = buffer[ 1 ] >> 1; + buffer[ 1 ] <<= 7; + bytes_to_write = 2; + break; - case 0x30: - type = midi_event::control_change; - if ( it == end ) return false; + case 0x30: + type = midi_event::control_change; + if ( it == end ) return false; buffer[ 1 ] = *it++; - if ( buffer[ 1 ] >= 10 && buffer[ 1 ] <= 14 ) - { - buffer[ 1 ] = mus_controllers[ buffer[ 1 ] ]; - buffer[ 2 ] = 1; - bytes_to_write = 2; - } + if ( buffer[ 1 ] >= 10 && buffer[ 1 ] <= 14 ) + { + buffer[ 1 ] = mus_controllers[ buffer[ 1 ] ]; + buffer[ 2 ] = 1; + bytes_to_write = 2; + } else return false; /*throw exception_io_data( "Unhandled MUS system event" );*/ - break; + break; - case 0x40: - if ( it == end ) return false; + case 0x40: + if ( it == end ) return false; buffer[ 1 ] = *it++; - if ( buffer[ 1 ] ) - { - if ( buffer[ 1 ] < 10 ) - { - type = midi_event::control_change; - buffer[ 1 ] = mus_controllers[ buffer[ 1 ] ]; - if ( it == end ) return false; + if ( buffer[ 1 ] ) + { + if ( buffer[ 1 ] < 10 ) + { + type = midi_event::control_change; + buffer[ 1 ] = mus_controllers[ buffer[ 1 ] ]; + if ( it == end ) return false; buffer[ 2 ] = *it++; - bytes_to_write = 2; - } + bytes_to_write = 2; + } else return false; /*throw exception_io_data( "Invalid MUS controller change event" );*/ - } - else - { - type = midi_event::program_change; - if ( it == end ) return false; + } + else + { + type = midi_event::program_change; + if ( it == end ) return false; buffer[ 1 ] = *it++; - bytes_to_write = 1; - } - break; + bytes_to_write = 1; + } + break; - default: + default: return false; /*throw exception_io_data( "Invalid MUS status code" );*/ - } + } - track.add_event( midi_event( current_timestamp, type, channel, buffer + 1, bytes_to_write ) ); + track.add_event( midi_event( current_timestamp, type, channel, buffer + 1, bytes_to_write ) ); - if ( buffer[ 0 ] & 0x80 ) + if ( buffer[ 0 ] & 0x80 ) { int delta = decode_delta( it, end ); if ( delta < 0 ) return false; /*throw exception_io_data( "Invalid MUS delta" );*/ - current_timestamp += delta; - } - } + current_timestamp += delta; + } + } - track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); + track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); - p_out.add_track( track ); + p_out.add_track( track ); return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp index bd32906b2..34773b04f 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp @@ -2,15 +2,42 @@ #include +static inline bool it_equal( std::vector::const_iterator it1, const char *it2, size_t length ) +{ + for ( size_t i = 0; i < length; i++ ) + { + if ( it1[ i ] != it2[ i ] ) + return false; + } + return true; +} + +static inline uint32_t toInt32LE( const uint8_t *in ) +{ + return static_cast( in[ 0 ] ) | + static_cast( in[ 1 ] << 8 ) | + static_cast( in[ 2 ] << 16 ) | + static_cast( in[ 3 ] << 24 ); +} + +static inline uint32_t toInt32LE( std::vector::const_iterator in ) +{ + return static_cast( in[ 0 ] ) | + static_cast( in[ 1 ] << 8 ) | + static_cast( in[ 2 ] << 16 ) | + static_cast( in[ 3 ] << 24 ); +} + + bool midi_processor::is_riff_midi( std::vector const& p_file ) { if ( p_file.size() < 20 ) return false; - if ( p_file[ 0 ] != 'R' || p_file[ 1 ] != 'I' || p_file[ 2 ] != 'F' || p_file[ 3 ] != 'F' ) return false; + if ( memcmp( &p_file[ 0 ], "RIFF", 4 ) != 0 ) return false; uint32_t riff_size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); if ( riff_size < 12 || ( p_file.size() < riff_size + 8 ) ) return false; - if ( p_file[ 8 ] != 'R' || p_file[ 9 ] != 'M' || p_file[ 10 ] != 'I' || p_file[ 11 ] != 'D' || - p_file[ 12 ] != 'd' || p_file[ 13 ] != 'a' || p_file[ 14 ] != 't' || p_file[ 15 ] != 'a' ) return false; - uint32_t data_size = p_file[ 16 ] | ( p_file[ 17 ] << 8 ) | ( p_file[ 18 ] << 16 ) | ( p_file[ 19 ] << 24 ); + if ( memcmp( &p_file[ 8 ], "RMID", 4 ) != 0 || + memcmp( &p_file[ 12 ], "data", 4 ) != 0 ) return false; + uint32_t data_size = toInt32LE(&p_file[ 16 ]); if ( data_size < 18 || p_file.size() < data_size + 20 || riff_size < data_size + 12 ) return false; std::vector test; test.assign( p_file.begin() + 20, p_file.begin() + 20 + 18 ); @@ -20,21 +47,21 @@ bool midi_processor::is_riff_midi( std::vector const& p_file ) bool midi_processor::process_riff_midi_count( std::vector const& p_file, size_t & track_count ) { track_count = 0; - + uint32_t file_size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); - + std::vector::const_iterator it = p_file.begin() + 12; - + std::vector::const_iterator body_end = p_file.begin() + 8 + file_size; - + std::vector extra_buffer; - + while ( it != body_end ) { if ( body_end - it < 8 ) return false; uint32_t chunk_size = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); if ( (unsigned long)(body_end - it) < chunk_size ) return false; - if ( it[ 0 ] == 'd' && it[ 1 ] == 'a' && it[ 2 ] == 't' && it[ 3 ] == 'a' ) + if ( it_equal(it, "data", 4) ) { std::vector midi_file; midi_file.assign( it + 8, it + 8 + chunk_size ); @@ -46,32 +73,32 @@ bool midi_processor::process_riff_midi_count( std::vector const& p_file if ( chunk_size & 1 && it != body_end ) ++it; } } - + return false; } -static const char * riff_tag_mappings[][2] = +static const char * riff_tag_mappings[][2] = { { "IALB", "album" }, { "IARL", "archival_location" }, - { "IART", "artist" }, - { "ITRK", "tracknumber" }, - { "ICMS", "commissioned" }, - { "ICMP", "composer" }, - { "ICMT", "comment" }, - { "ICOP", "copyright" }, - { "ICRD", "creation_date" }, - { "IENG", "engineer" }, - { "IGNR", "genre" }, - { "IKEY", "keywords" }, - { "IMED", "medium" }, - { "INAM", "title" }, - { "IPRD", "product" }, - { "ISBJ", "subject" }, - { "ISFT", "software" }, - { "ISRC", "source" }, - { "ISRF", "source_form" }, - { "ITCH", "technician" } + { "IART", "artist" }, + { "ITRK", "tracknumber" }, + { "ICMS", "commissioned" }, + { "ICMP", "composer" }, + { "ICMT", "comment" }, + { "ICOP", "copyright" }, + { "ICRD", "creation_date" }, + { "IENG", "engineer" }, + { "IGNR", "genre" }, + { "IKEY", "keywords" }, + { "IMED", "medium" }, + { "INAM", "title" }, + { "IPRD", "product" }, + { "ISBJ", "subject" }, + { "ISFT", "software" }, + { "ISRC", "source" }, + { "ISRF", "source_form" }, + { "ITCH", "technician" } }; bool midi_processor::process_riff_midi( std::vector const& p_file, midi_container & p_out ) @@ -82,77 +109,79 @@ bool midi_processor::process_riff_midi( std::vector const& p_file, midi std::vector::const_iterator body_end = p_file.begin() + 8 + file_size; - bool found_data = false; - bool found_info = false; + bool found_data = false; + bool found_info = false; - midi_meta_data meta_data; + midi_meta_data meta_data; std::vector extra_buffer; while ( it != body_end ) - { - if ( body_end - it < 8 ) return false; - uint32_t chunk_size = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); - if ( (unsigned long)(body_end - it) < chunk_size ) return false; - if ( it[ 0 ] == 'd' && it[ 1 ] == 'a' && it[ 2 ] == 't' && it[ 3 ] == 'a' ) - { - if ( !found_data ) - { + { + if ( body_end - it < 8 ) return false; + uint32_t chunk_size = toInt32LE( it + 4 ); + if ( (unsigned long)(body_end - it) < chunk_size ) return false; + if ( it_equal( it, "data", 4 ) ) + { + if ( !found_data ) + { std::vector midi_file; midi_file.assign( it + 8, it + 8 + chunk_size ); if ( !process_standard_midi( midi_file, p_out ) ) return false; - found_data = true; + found_data = true; } else return false; /*throw exception_io_data( "Multiple RIFF data chunks found" );*/ it += 8 + chunk_size; if ( chunk_size & 1 && it != body_end ) ++it; - } - else if ( it[ 0 ] == 'D' && it[ 1 ] == 'I' && it[ 2 ] == 'S' && it[ 3 ] == 'P' ) - { - uint32_t type = it[ 8 ] | ( it[ 9 ] << 8 ) | ( it[ 10 ] << 16 ) | ( it[ 11 ] << 24 ); - if ( type == 1 ) - { - extra_buffer.resize( chunk_size - 4 ); + } + else if ( it_equal( it, "DISP", 4 ) ) + { + uint32_t type = toInt32LE( it + 8 ); + if ( type == 1 ) + { + extra_buffer.resize( chunk_size - 4 + 1 ); std::copy( it + 12, it + 8 + chunk_size, extra_buffer.begin() ); + extra_buffer[ chunk_size - 4 ] = '\0'; meta_data.add_item( midi_meta_data_item( 0, "display_name", (const char *) &extra_buffer[0] ) ); - } + } it += 8 + chunk_size; if ( chunk_size & 1 && it != body_end ) ++it; - } - else if ( it[ 0 ] == 'L' && it[ 1 ] == 'I' && it[ 2 ] == 'S' && it[ 3 ] == 'T' ) - { + } + else if ( it_equal( it, "LIST", 4 ) ) + { std::vector::const_iterator chunk_end = it + 8 + chunk_size; - if ( it[ 8 ] == 'I' && it[ 9 ] == 'N' && it[ 10 ] == 'F' && it[ 11 ] == 'O' ) - { - if ( !found_info ) - { - if ( chunk_end - it < 12 ) return false; + if ( it_equal( it + 8, "INFO", 4 ) ) + { + if ( !found_info ) + { + if ( chunk_end - it < 12 ) return false; it += 12; while ( it != chunk_end ) - { - if ( chunk_end - it < 4 ) return false; - uint32_t field_size = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); - if ( (unsigned long)(chunk_end - it) < 8 + field_size ) return false; + { + if ( chunk_end - it < 4 ) return false; + uint32_t field_size = toInt32LE( it + 4 ); + if ( (unsigned long)(chunk_end - it) < 8 + field_size ) return false; std::string field; field.assign( it, it + 4 ); - for ( unsigned i = 0; i < _countof(riff_tag_mappings); ++i ) - { + for ( unsigned i = 0; i < _countof(riff_tag_mappings); ++i ) + { if ( !memcmp( &it[0], riff_tag_mappings[ i ][ 0 ], 4 ) ) - { - field = riff_tag_mappings[ i ][ 1 ]; - break; - } - } - extra_buffer.resize( field_size ); + { + field = riff_tag_mappings[ i ][ 1 ]; + break; + } + } + extra_buffer.resize( field_size + 1 ); std::copy( it + 8, it + 8 + field_size, extra_buffer.begin() ); + extra_buffer[ field_size ] = '\0'; it += 8 + field_size; meta_data.add_item( midi_meta_data_item( 0, field.c_str(), ( const char * ) &extra_buffer[0] ) ); if ( field_size & 1 && it != chunk_end ) ++it; - } - found_info = true; - } + } + found_info = true; + } else return false; /*throw exception_io_data( "Multiple RIFF LIST INFO chunks found" );*/ - } + } else return false; /* unknown LIST chunk */ it = chunk_end; if ( chunk_size & 1 && it != body_end ) ++it; @@ -163,10 +192,10 @@ bool midi_processor::process_riff_midi( std::vector const& p_file, midi if ( chunk_size & 1 && it != body_end ) ++it; } - if ( found_data && found_info ) break; - } + if ( found_data && found_info ) break; + } - p_out.set_extra_meta_data( meta_data ); + p_out.set_extra_meta_data( meta_data ); return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp index 6ab7405db..5bbc2268c 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp @@ -5,6 +5,8 @@ bool midi_processor::is_standard_midi( std::vector const& p_file ) if ( p_file.size() < 18 ) return false; if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'T' || p_file[ 2 ] != 'h' || p_file[ 3 ] != 'd') return false; if ( p_file[ 4 ] != 0 || p_file[ 5 ] != 0 || p_file[ 6 ] != 0 || p_file[ 7 ] != 6 ) return false; + if ( p_file[ 10 ] == 0 && p_file[ 11 ] == 0 ) return false; // no tracks + if ( p_file[ 12 ] == 0 && p_file[ 13 ] == 0 ) return false; // dtx == 0, will cause division by zero on tempo calculations if ( p_file[ 14 ] != 'M' || p_file[ 15 ] != 'T' || p_file[ 16 ] != 'r' || p_file[ 17 ] != 'k' ) return false; return true; } @@ -12,29 +14,29 @@ bool midi_processor::is_standard_midi( std::vector const& p_file ) bool midi_processor::process_standard_midi_count( std::vector const& p_file, size_t & track_count ) { track_count = 0; - + if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'T' || p_file[ 2 ] != 'h' || p_file[ 3 ] != 'd' ) return false; if ( p_file[ 4 ] != 0 || p_file[ 5 ] != 0 || p_file[ 6 ] != 0 || p_file[ 7 ] != 6 ) return false; /*throw exception_io_data("Bad MIDI header size");*/ std::vector::const_iterator it = p_file.begin() + 8; - + uint16_t form = ( it[0] << 8 ) | it[1]; if ( form > 2 ) return false; - + uint16_t track_count_16 = ( it[2] << 8 ) | it[3]; - + if ( form == 2 ) track_count = track_count_16; else track_count = 1; - + return true; } bool midi_processor::process_standard_midi_track( std::vector::const_iterator & it, std::vector::const_iterator end, midi_container & p_out, bool needs_end_marker ) { - midi_track track; - unsigned current_timestamp = 0; - unsigned char last_event_code = 0xFF; - + midi_track track; + unsigned current_timestamp = 0; + unsigned char last_event_code = 0xFF; + unsigned last_sysex_length = 0; unsigned last_sysex_timestamp = 0; @@ -67,15 +69,15 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it { if ( last_sysex_length ) { - track.add_event( midi_event( last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length + 1 ) ); + track.add_event( midi_event( last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length ) ); last_sysex_length = 0; } - + last_event_code = event_code; if ( !needs_end_marker && ( event_code & 0xF0 ) == 0xE0 ) continue; if ( data_bytes_read < 1 ) { - if ( it == end ) return false; + if ( it == end ) return false; buffer[ 0 ] = *it++; ++data_bytes_read; } @@ -85,7 +87,7 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it case 0xD0: break; default: - if ( it == end ) return false; + if ( it == end ) return false; buffer[ data_bytes_read ] = *it++; ++data_bytes_read; } @@ -95,13 +97,13 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it { if ( last_sysex_length ) { - track.add_event( midi_event( last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length + 1 ) ); + track.add_event( midi_event( last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length ) ); last_sysex_length = 0; } - + int data_count = decode_delta( it, end ); if ( data_count < 0 ) return false; /*throw exception_io_data( "Invalid System Exclusive message" );*/ - if ( end - it < data_count ) return false; + if ( end - it < data_count ) return false; buffer.resize( data_count + 1 ); buffer[ 0 ] = 0xF0; std::copy( it, it + data_count, buffer.begin() + 1 ); @@ -115,7 +117,7 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it int data_count = decode_delta( it, end ); if ( data_count < 0 ) return false; if ( end - it < data_count ) return false; - buffer.resize( last_sysex_length + data_count + 1 ); + buffer.resize( last_sysex_length + data_count ); std::copy( it, it + data_count, buffer.begin() + last_sysex_length ); it += data_count; last_sysex_length += data_count; @@ -124,7 +126,7 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it { if ( last_sysex_length ) { - track.add_event( midi_event( last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length + 1 ) ); + track.add_event( midi_event( last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length ) ); last_sysex_length = 0; } @@ -132,7 +134,7 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it unsigned char meta_type = *it++; int data_count = decode_delta( it, end ); if ( data_count < 0 ) return false; /*throw exception_io_data( "Invalid meta message" );*/ - if ( end - it < data_count ) return false; + if ( end - it < data_count ) return false; buffer.resize( data_count + 2 ); buffer[ 0 ] = 0xFF; buffer[ 1 ] = meta_type; @@ -148,21 +150,21 @@ bool midi_processor::process_standard_midi_track( std::vector::const_it } else if ( event_code >= 0xF8 && event_code <= 0xFE ) { - /* Sequencer specific events, single byte */ - buffer[ 0 ] = event_code; - track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], 1 ) ); + /* Sequencer specific events, single byte */ + buffer[ 0 ] = event_code; + track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], 1 ) ); } else return false; /*throw exception_io_data("Unhandled MIDI status code");*/ } if ( !needs_end_marker ) - { - buffer[ 0 ] = 0xFF; - buffer[ 1 ] = 0x2F; + { + buffer[ 0 ] = 0xFF; + buffer[ 1 ] = 0x2F; track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], 2 ) ); - } + } - p_out.add_track( track ); + p_out.add_track( track ); return true; } @@ -173,7 +175,7 @@ bool midi_processor::process_standard_midi( std::vector const& p_file, if ( p_file[ 4 ] != 0 || p_file[ 5 ] != 0 || p_file[ 6 ] != 0 || p_file[ 7 ] != 6 ) return false; /*throw exception_io_data("Bad MIDI header size");*/ std::vector::const_iterator it = p_file.begin() + 8; - std::vector::const_iterator end = p_file.end(); + std::vector::const_iterator end = p_file.end(); uint16_t form = ( it[0] << 8 ) | it[1]; if ( form > 2 ) return false; @@ -181,19 +183,22 @@ bool midi_processor::process_standard_midi( std::vector const& p_file, uint16_t track_count_16 = ( it[2] << 8 ) | it[3]; uint16_t dtx = ( it[4] << 8 ) | it[5]; + if ( !track_count_16 || !dtx ) + return false; + it += 6; std::size_t track_count = track_count_16; - p_out.initialize( form, dtx ); + p_out.initialize( form, dtx ); for ( std::size_t i = 0; i < track_count; ++i ) - { - if ( end - it < 8 ) return false; + { + if ( end - it < 8 ) return false; if ( it[0] != 'M' || it[1] != 'T' || it[2] != 'r' || it[3] != 'k' ) return false; uint32_t track_size = ( it[4] << 24 ) | ( it[5] << 16 ) | ( it[6] << 8 ) | it[7]; - if ( (unsigned long)(end - it) < track_size ) return false; + if ( (unsigned long)(end - it) < track_size ) return false; it += 8; @@ -201,12 +206,12 @@ bool midi_processor::process_standard_midi( std::vector const& p_file, if ( !process_standard_midi_track( it, it + track_size, p_out, true ) ) return false; - track_data_offset += track_size; + track_data_offset += track_size; if ( it - p_file.begin() != track_data_offset ) - { + { it = p_file.begin() + track_data_offset; - } - } + } + } return true; } diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_syx.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_syx.cpp index 5e99bf626..54293a0cd 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_syx.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_syx.cpp @@ -1,35 +1,35 @@ -#include "midi_processor.h" - -bool midi_processor::is_syx( std::vector const& p_file ) -{ - if ( p_file.size() < 2 ) return false; - if ( p_file[ 0 ] != 0xF0 || p_file[ p_file.size() - 1 ] != 0xF7 ) return false; - return true; -} - -bool midi_processor::process_syx( std::vector const& p_file, midi_container & p_out ) -{ - const size_t size = p_file.size(); - size_t ptr = 0; - - p_out.initialize( 0, 1 ); - - midi_track track; - - while ( ptr < size ) - { - size_t msg_length = 1; - - if ( p_file[ptr] != 0xF0 ) return false; - - while ( p_file[ptr + msg_length++] != 0xF7 ); - - track.add_event( midi_event( 0, midi_event::extended, 0, &p_file[ptr], msg_length ) ); - - ptr += msg_length; - } - - p_out.add_track( track ); - - return true; -} +#include "midi_processor.h" + +bool midi_processor::is_syx( std::vector const& p_file ) +{ + if ( p_file.size() < 2 ) return false; + if ( p_file[ 0 ] != 0xF0 || p_file[ p_file.size() - 1 ] != 0xF7 ) return false; + return true; +} + +bool midi_processor::process_syx( std::vector const& p_file, midi_container & p_out ) +{ + const size_t size = p_file.size(); + size_t ptr = 0; + + p_out.initialize( 0, 1 ); + + midi_track track; + + while ( ptr < size ) + { + size_t msg_length = 1; + + if ( p_file[ptr] != 0xF0 ) return false; + + while ( p_file[ptr + msg_length++] != 0xF7 ); + + track.add_event( midi_event( 0, midi_event::extended, 0, &p_file[ptr], msg_length ) ); + + ptr += msg_length; + } + + p_out.add_track( track ); + + return true; +} diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp index 71a3b969f..3c9069211 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp @@ -15,21 +15,21 @@ const uint8_t midi_processor::xmi_default_tempo[5] = {0xFF, 0x51, 0x07, 0xA1, 0x unsigned midi_processor::decode_xmi_delta( std::vector::const_iterator & it, std::vector::const_iterator end ) { - unsigned delta = 0; - if ( it == end ) return 0; + unsigned delta = 0; + if ( it == end ) return 0; uint8_t byte = *it++; - if ( !( byte & 0x80 ) ) - { - do - { - delta += byte; - if ( it == end ) break; + if ( !( byte & 0x80 ) ) + { + do + { + delta += byte; + if ( it == end ) break; byte = *it++; - } + } while ( !( byte & 0x80 ) && it != end ); - } + } --it; - return delta; + return delta; } struct iff_chunk @@ -39,46 +39,46 @@ struct iff_chunk std::vector m_data; std::vector m_sub_chunks; - iff_chunk() - { - memset( m_id, 0, sizeof( m_id ) ); - memset( m_type, 0, sizeof( m_type ) ); - } + iff_chunk() + { + memset( m_id, 0, sizeof( m_id ) ); + memset( m_type, 0, sizeof( m_type ) ); + } - iff_chunk( const iff_chunk & p_in ) - { - memcpy( m_id, p_in.m_id, sizeof( m_id ) ); - memcpy( m_type, p_in.m_type, sizeof( m_type ) ); - m_data = p_in.m_data; - m_sub_chunks = p_in.m_sub_chunks; - } + iff_chunk( const iff_chunk & p_in ) + { + memcpy( m_id, p_in.m_id, sizeof( m_id ) ); + memcpy( m_type, p_in.m_type, sizeof( m_type ) ); + m_data = p_in.m_data; + m_sub_chunks = p_in.m_sub_chunks; + } - const iff_chunk & find_sub_chunk( const char * p_id, unsigned index = 0 ) const - { - for ( std::size_t i = 0; i < m_sub_chunks.size(); ++i ) - { - if ( !memcmp( p_id, m_sub_chunks[ i ].m_id, 4 ) ) - { - if ( index ) --index; - if ( !index ) return m_sub_chunks[ i ]; - } - } - /*throw exception_io_data( pfc::string_formatter() << "Missing IFF chunk: " << p_id );*/ - return *this; - } - - unsigned get_chunk_count( const char * p_id ) const - { - unsigned chunk_count = 0; + const iff_chunk & find_sub_chunk( const char * p_id, unsigned index = 0 ) const + { for ( std::size_t i = 0; i < m_sub_chunks.size(); ++i ) { - if ( !memcmp( p_id, m_sub_chunks[ i ].m_id, 4 ) ) - { - ++chunk_count; - } - } - return chunk_count; - } + if ( !memcmp( p_id, m_sub_chunks[ i ].m_id, 4 ) ) + { + if ( index ) --index; + if ( !index ) return m_sub_chunks[ i ]; + } + } + /*throw exception_io_data( pfc::string_formatter() << "Missing IFF chunk: " << p_id );*/ + return *this; + } + + unsigned get_chunk_count( const char * p_id ) const + { + unsigned chunk_count = 0; + for ( std::size_t i = 0; i < m_sub_chunks.size(); ++i ) + { + if ( !memcmp( p_id, m_sub_chunks[ i ].m_id, 4 ) ) + { + ++chunk_count; + } + } + return chunk_count; + } }; struct iff_stream @@ -87,69 +87,69 @@ struct iff_stream iff_chunk fail; - const iff_chunk & find_chunk( const char * p_id ) const - { + const iff_chunk & find_chunk( const char * p_id ) const + { for ( std::size_t i = 0; i < m_chunks.size(); ++i ) - { - if ( !memcmp( p_id, m_chunks[ i ].m_id, 4 ) ) - { - return m_chunks[ i ]; - } - } + { + if ( !memcmp( p_id, m_chunks[ i ].m_id, 4 ) ) + { + return m_chunks[ i ]; + } + } /*throw exception_io_data( pfc::string_formatter() << "Missing IFF chunk: " << p_id );*/ return fail; - } + } }; static bool read_iff_chunk( std::vector::const_iterator & it, std::vector::const_iterator end, iff_chunk & p_out, bool first_chunk ) { - if ( end - it < 8 ) return false; + if ( end - it < 8 ) return false; std::copy( it, it + 4, p_out.m_id ); it += 4; uint32_t chunk_size = ( it[ 0 ] << 24 ) | ( it[ 1 ] << 16 ) | ( it[ 2 ] << 8 ) | it[ 3 ]; - if ( (unsigned long)(end - it) < chunk_size ) return false; + if ( (unsigned long)(end - it) < chunk_size ) return false; it += 4; - bool is_cat_chunk = !memcmp( p_out.m_id, "CAT ", 4 ); - bool is_form_chunk = !memcmp( p_out.m_id, "FORM", 4 ); + bool is_cat_chunk = !memcmp( p_out.m_id, "CAT ", 4 ); + bool is_form_chunk = !memcmp( p_out.m_id, "FORM", 4 ); std::size_t chunk_size_limit = end - it; - if ( chunk_size > chunk_size_limit ) chunk_size = (uint32_t) chunk_size_limit; - if ( ( first_chunk && is_form_chunk ) || ( !first_chunk && is_cat_chunk ) ) - { - if ( end - it < 4 ) return false; + if ( chunk_size > chunk_size_limit ) chunk_size = (uint32_t) chunk_size_limit; + if ( ( first_chunk && is_form_chunk ) || ( !first_chunk && is_cat_chunk ) ) + { + if ( end - it < 4 ) return false; std::vector::const_iterator chunk_end = it + chunk_size; std::copy( it, it + 4, p_out.m_type ); it += 4; while ( it < chunk_end ) - { - iff_chunk chunk; + { + iff_chunk chunk; if ( !read_iff_chunk( it, chunk_end, chunk, is_cat_chunk ) ) return false; p_out.m_sub_chunks.push_back( chunk ); - } + } it = chunk_end; if ( chunk_size & 1 && it != end ) ++it; - } - else if ( !is_form_chunk && !is_cat_chunk ) - { + } + else if ( !is_form_chunk && !is_cat_chunk ) + { p_out.m_data.assign( it, it + chunk_size ); it += chunk_size; if ( chunk_size & 1 && it != end ) ++it; - } - else - { + } + else + { /*if ( first_chunk ) throw exception_io_data( pfc::string_formatter() << "Found " << pfc::string8( (const char *)p_out.m_id, 4 ) << " chunk instead of FORM" ); else throw exception_io_data( "Found multiple FORM chunks" );*/ return false; - } + } return true; } static bool read_iff_stream( std::vector const& p_file, iff_stream & p_out ) { std::vector::const_iterator it = p_file.begin(), end = p_file.end(); - bool first_chunk = true; + bool first_chunk = true; while ( it != end ) - { - iff_chunk chunk; + { + iff_chunk chunk; if ( read_iff_chunk( it, end, chunk, first_chunk ) ) { p_out.m_chunks.push_back( chunk ); @@ -159,27 +159,27 @@ static bool read_iff_stream( std::vector const& p_file, iff_stream & p_ return false; else break; - } + } return true; } bool midi_processor::process_xmi_count( std::vector const& p_file, size_t & track_count ) { track_count = 0; - + iff_stream xmi_file; if ( !read_iff_stream( p_file, xmi_file ) ) return false; - + const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); if ( memcmp( form_chunk.m_type, "XDIR", 4 ) ) return false; /*throw exception_io_data( "XMI IFF not XDIR type" );*/ - + const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); if ( memcmp( cat_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI CAT chunk not XMID type" );*/ - + unsigned _track_count = cat_chunk.get_chunk_count( "FORM" ); - + track_count = _track_count; - + return true; } @@ -188,32 +188,32 @@ bool midi_processor::process_xmi( std::vector const& p_file, midi_conta iff_stream xmi_file; if ( !read_iff_stream( p_file, xmi_file ) ) return false; - const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); + const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); if ( memcmp( form_chunk.m_type, "XDIR", 4 ) ) return false; /*throw exception_io_data( "XMI IFF not XDIR type" );*/ - const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); + const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); if ( memcmp( cat_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI CAT chunk not XMID type" );*/ - unsigned track_count = cat_chunk.get_chunk_count( "FORM" ); + unsigned track_count = cat_chunk.get_chunk_count( "FORM" ); - p_out.initialize( track_count > 1 ? 2 : 0, 60 ); + p_out.initialize( track_count > 1 ? 2 : 0, 60 ); - for ( unsigned i = 0; i < track_count; ++i ) - { - const iff_chunk & xmid_form_chunk = cat_chunk.find_sub_chunk( "FORM", i ); + for ( unsigned i = 0; i < track_count; ++i ) + { + const iff_chunk & xmid_form_chunk = cat_chunk.find_sub_chunk( "FORM", i ); if ( memcmp( xmid_form_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI nested FORM chunk not XMID type" );*/ - const iff_chunk & event_chunk = xmid_form_chunk.find_sub_chunk( "EVNT" ); + const iff_chunk & event_chunk = xmid_form_chunk.find_sub_chunk( "EVNT" ); if ( memcmp( event_chunk.m_id, "EVNT", 4 ) ) return false; /* EVNT chunk not found */ std::vector const& event_body = event_chunk.m_data; - midi_track track; + midi_track track; - bool initial_tempo = false; + bool initial_tempo = false; - unsigned current_timestamp = 0; + unsigned current_timestamp = 0; - unsigned last_event_timestamp = 0; + unsigned last_event_timestamp = 0; std::vector buffer; buffer.resize( 3 ); @@ -221,94 +221,94 @@ bool midi_processor::process_xmi( std::vector const& p_file, midi_conta std::vector::const_iterator it = event_body.begin(), end = event_body.end(); while ( it != end ) - { + { unsigned delta = decode_xmi_delta( it, end ); - current_timestamp += delta; + current_timestamp += delta; - if ( current_timestamp > last_event_timestamp ) - { - last_event_timestamp = current_timestamp; - } + if ( current_timestamp > last_event_timestamp ) + { + last_event_timestamp = current_timestamp; + } - if ( it == end ) return false; + if ( it == end ) return false; buffer[ 0 ] = *it++; - if ( buffer[ 0 ] == 0xFF ) - { - if ( it == end ) return false; + if ( buffer[ 0 ] == 0xFF ) + { + if ( it == end ) return false; buffer[ 1 ] = *it++; - long meta_count; - if ( buffer[ 1 ] == 0x2F ) - { - meta_count = 0; - } - else - { + long meta_count; + if ( buffer[ 1 ] == 0x2F ) + { + meta_count = 0; + } + else + { meta_count = decode_delta( it, end ); if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid XMI meta message" );*/ - if ( end - it < meta_count ) return false; + if ( end - it < meta_count ) return false; buffer.resize( meta_count + 2 ); std::copy( it, it + meta_count, buffer.begin() + 2 ); it += meta_count; - } - if ( buffer[ 1 ] == 0x2F && current_timestamp < last_event_timestamp ) - { - current_timestamp = last_event_timestamp; - } - if ( buffer[ 1 ] == 0x51 && meta_count == 3 ) - { - unsigned tempo = buffer[ 2 ] * 0x10000 + buffer[ 3 ] * 0x100 + buffer[ 4 ]; - unsigned ppqn = ( tempo * 3 ) / 25000; - tempo = tempo * 60 / ppqn; - buffer[ 2 ] = tempo / 0x10000; - buffer[ 3 ] = tempo / 0x100; - buffer[ 4 ] = tempo; - if ( current_timestamp == 0 ) initial_tempo = true; - } + } + if ( buffer[ 1 ] == 0x2F && current_timestamp < last_event_timestamp ) + { + current_timestamp = last_event_timestamp; + } + if ( buffer[ 1 ] == 0x51 && meta_count == 3 ) + { + unsigned tempo = buffer[ 2 ] * 0x10000 + buffer[ 3 ] * 0x100 + buffer[ 4 ]; + unsigned ppqn = ( tempo * 3 ) / 25000; + tempo = tempo * 60 / ppqn; + buffer[ 2 ] = tempo / 0x10000; + buffer[ 3 ] = tempo / 0x100; + buffer[ 4 ] = tempo; + if ( current_timestamp == 0 ) initial_tempo = true; + } track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], meta_count + 2 ) ); - if ( buffer[ 1 ] == 0x2F ) break; - } - else if ( buffer[ 0 ] == 0xF0 ) - { + if ( buffer[ 1 ] == 0x2F ) break; + } + else if ( buffer[ 0 ] == 0xF0 ) + { long system_exclusive_count = decode_delta( it, end ); if ( system_exclusive_count < 0 ) return false; /*throw exception_io_data( "Invalid XMI System Exclusive message" );*/ - if ( end - it < system_exclusive_count ) return false; + if ( end - it < system_exclusive_count ) return false; buffer.resize( system_exclusive_count + 1 ); std::copy( it, it + system_exclusive_count, buffer.begin() + 1 ); it += system_exclusive_count; track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], system_exclusive_count + 1 ) ); - } - else if ( buffer[ 0 ] >= 0x80 && buffer[ 0 ] <= 0xEF ) - { - unsigned bytes_read = 1; - if ( it == end ) return false; + } + else if ( buffer[ 0 ] >= 0x80 && buffer[ 0 ] <= 0xEF ) + { + unsigned bytes_read = 1; + if ( it == end ) return false; buffer[ 1 ] = *it++; - midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); - unsigned channel = buffer[ 0 ] & 0x0F; - if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) - { - if ( it == end ) return false; + midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); + unsigned channel = buffer[ 0 ] & 0x0F; + if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) + { + if ( it == end ) return false; buffer[ 2 ] = *it++; - bytes_read = 2; - } + bytes_read = 2; + } track.add_event( midi_event( current_timestamp, type, channel, &buffer[1], bytes_read ) ); - if ( type == midi_event::note_on ) - { - buffer[ 2 ] = 0x00; + if ( type == midi_event::note_on ) + { + buffer[ 2 ] = 0x00; int note_length = decode_delta( it, end ); if ( note_length < 0 ) return false; /*throw exception_io_data( "Invalid XMI note message" );*/ - unsigned note_end_timestamp = current_timestamp + note_length; - if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; + unsigned note_end_timestamp = current_timestamp + note_length; + if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; track.add_event( midi_event( note_end_timestamp, type, channel, &buffer[1], bytes_read ) ); - } - } + } + } else return false; /*throw exception_io_data( "Unexpected XMI status code" );*/ - } + } - if ( !initial_tempo ) - track.add_event( midi_event( 0, midi_event::extended, 0, xmi_default_tempo, _countof( xmi_default_tempo ) ) ); + if ( !initial_tempo ) + track.add_event( midi_event( 0, midi_event::extended, 0, xmi_default_tempo, _countof( xmi_default_tempo ) ) ); - p_out.add_track( track ); - } + p_out.add_track( track ); + } return true; } diff --git a/Plugins/MIDI/MIDI/MIDIDecoder.mm b/Plugins/MIDI/MIDI/MIDIDecoder.mm index 8ace1d098..7afb46298 100755 --- a/Plugins/MIDI/MIDI/MIDIDecoder.mm +++ b/Plugins/MIDI/MIDI/MIDIDecoder.mm @@ -62,7 +62,7 @@ static OSType getOSType(const char * in_) track_num = [[[s url] fragment] intValue]; //What if theres no fragment? Assuming we get 0. - midi_file.scan_for_loops( true, true, true ); + midi_file.scan_for_loops( true, true, true, true ); framesLength = midi_file.get_timestamp_end( track_num, true );