├── .gitignore ├── CMakeLists.txt ├── midi_container.cpp ├── midi_container.h ├── midi_processing.pro ├── midi_processing.vcxproj ├── midi_processing.vcxproj.filters ├── midi_processor.h ├── midi_processor_gmf.cpp ├── midi_processor_helpers.cpp ├── midi_processor_hmi.cpp ├── midi_processor_hmp.cpp ├── midi_processor_lds.cpp ├── midi_processor_mids.cpp ├── midi_processor_mus.cpp ├── midi_processor_riff_midi.cpp ├── midi_processor_standard_midi.cpp ├── midi_processor_syx.cpp └── midi_processor_xmi.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.o 3 | *.a 4 | Debug 5 | Release 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project( 4 | midi_processing 5 | VERSION 0.1.0 6 | DESCRIPTION "MIDI file parser and converter library" 7 | HOMEPAGE_URL "https://github.com/kode54/midi_processing" 8 | LANGUAGES CXX 9 | ) 10 | set(target midi_processing) 11 | add_library(${target} STATIC ${sources}) 12 | 13 | target_include_directories(${target} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") 14 | 15 | target_sources(${target} 16 | PRIVATE 17 | midi_container.h 18 | midi_processor.h 19 | midi_container.cpp 20 | midi_processor_gmf.cpp 21 | midi_processor_helpers.cpp 22 | midi_processor_hmi.cpp 23 | midi_processor_hmp.cpp 24 | midi_processor_lds.cpp 25 | midi_processor_mids.cpp 26 | midi_processor_mus.cpp 27 | midi_processor_riff_midi.cpp 28 | midi_processor_standard_midi.cpp 29 | midi_processor_syx.cpp 30 | midi_processor_xmi.cpp 31 | ) -------------------------------------------------------------------------------- /midi_container.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_container.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | midi_event::midi_event( const midi_event & p_in ) 8 | { 9 | m_timestamp = p_in.m_timestamp; 10 | m_channel = p_in.m_channel; 11 | m_type = p_in.m_type; 12 | m_data_count = p_in.m_data_count; 13 | memcpy( m_data, p_in.m_data, m_data_count ); 14 | m_ext_data = p_in.m_ext_data; 15 | } 16 | 17 | 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 ) 18 | { 19 | m_timestamp = p_timestamp; 20 | m_type = p_type; 21 | m_channel = p_channel; 22 | if ( p_data_count <= max_static_data_count ) 23 | { 24 | m_data_count = p_data_count; 25 | memcpy( m_data, p_data, p_data_count ); 26 | } 27 | else 28 | { 29 | m_data_count = max_static_data_count; 30 | memcpy( m_data, p_data, max_static_data_count ); 31 | m_ext_data.assign( p_data + max_static_data_count, p_data + p_data_count ); 32 | } 33 | } 34 | 35 | unsigned long midi_event::get_data_count() const 36 | { 37 | return m_data_count + m_ext_data.size(); 38 | } 39 | 40 | void midi_event::copy_data( uint8_t * p_out, unsigned long p_offset, unsigned long p_count ) const 41 | { 42 | unsigned long max_count = m_data_count + m_ext_data.size() - p_offset; 43 | p_count = std::min( p_count, max_count ); 44 | if ( p_offset < max_static_data_count ) 45 | { 46 | unsigned long _max_count = max_static_data_count - p_offset; 47 | unsigned long count = std::min( _max_count, p_count ); 48 | memcpy( p_out, m_data + p_offset, count ); 49 | p_offset -= count; 50 | p_count -= count; 51 | p_out += count; 52 | } 53 | if ( p_count ) memcpy( p_out, &m_ext_data[0], p_count ); 54 | } 55 | 56 | midi_track::midi_track(const midi_track & p_in) 57 | { 58 | m_events = p_in.m_events; 59 | } 60 | 61 | void midi_track::add_event( const midi_event & p_event ) 62 | { 63 | auto it = m_events.end(); 64 | 65 | if ( m_events.size() ) 66 | { 67 | midi_event & event = *(it - 1); 68 | if ( event.m_type == midi_event::extended && event.get_data_count() >= 2 && 69 | event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x2F ) 70 | { 71 | --it; 72 | if ( event.m_timestamp < p_event.m_timestamp ) 73 | { 74 | event.m_timestamp = p_event.m_timestamp; 75 | } 76 | } 77 | 78 | while ( it > m_events.begin() ) 79 | { 80 | if ( (*( it - 1 )).m_timestamp <= p_event.m_timestamp ) break; 81 | --it; 82 | } 83 | } 84 | 85 | m_events.insert( it, p_event ); 86 | } 87 | 88 | std::size_t midi_track::get_count() const 89 | { 90 | return m_events.size(); 91 | } 92 | 93 | const midi_event & midi_track::operator [] ( std::size_t p_index ) const 94 | { 95 | return m_events[ p_index ]; 96 | } 97 | 98 | midi_event & midi_track::operator [] ( std::size_t p_index ) 99 | { 100 | return m_events[ p_index ]; 101 | } 102 | 103 | void midi_track::remove_event( unsigned long index ) 104 | { 105 | m_events.erase( m_events.begin() + index ); 106 | } 107 | 108 | tempo_entry::tempo_entry(unsigned long p_timestamp, unsigned p_tempo) 109 | { 110 | m_timestamp = p_timestamp; 111 | m_tempo = p_tempo; 112 | } 113 | 114 | void tempo_map::add_tempo( unsigned p_tempo, unsigned long p_timestamp ) 115 | { 116 | auto it = m_entries.end(); 117 | 118 | while ( it > m_entries.begin() ) 119 | { 120 | if ( (*( it - 1 )).m_timestamp <= p_timestamp ) break; 121 | --it; 122 | } 123 | 124 | if ( it > m_entries.begin() && (*( it - 1 )).m_timestamp == p_timestamp ) 125 | { 126 | (*( it - 1 )).m_tempo = p_tempo; 127 | } 128 | else 129 | { 130 | m_entries.insert( it, tempo_entry( p_timestamp, p_tempo ) ); 131 | } 132 | } 133 | 134 | unsigned long tempo_map::timestamp_to_ms( unsigned long p_timestamp, unsigned p_dtx ) const 135 | { 136 | unsigned long timestamp_ms = 0; 137 | unsigned long timestamp = 0; 138 | auto tempo_it = m_entries.begin(); 139 | unsigned current_tempo = 500000; 140 | 141 | unsigned half_dtx = p_dtx * 500; 142 | p_dtx = half_dtx * 2; 143 | 144 | while ( tempo_it < m_entries.end() && timestamp + p_timestamp >= (*tempo_it).m_timestamp ) 145 | { 146 | unsigned long delta = (*tempo_it).m_timestamp - timestamp; 147 | timestamp_ms += ((uint64_t)current_tempo * (uint64_t)delta + half_dtx) / p_dtx; 148 | current_tempo = (*tempo_it).m_tempo; 149 | ++tempo_it; 150 | timestamp += delta; 151 | p_timestamp -= delta; 152 | } 153 | 154 | timestamp_ms += ((uint64_t)current_tempo * (uint64_t)p_timestamp + half_dtx) / p_dtx; 155 | 156 | return timestamp_ms; 157 | } 158 | 159 | std::size_t tempo_map::get_count() const 160 | { 161 | return m_entries.size(); 162 | } 163 | 164 | const tempo_entry & tempo_map::operator [] ( std::size_t p_index ) const 165 | { 166 | return m_entries[ p_index ]; 167 | } 168 | 169 | tempo_entry & tempo_map::operator [] ( std::size_t p_index ) 170 | { 171 | return m_entries[ p_index ]; 172 | } 173 | 174 | system_exclusive_entry::system_exclusive_entry(const system_exclusive_entry & p_in) 175 | { 176 | m_port = p_in.m_port; 177 | m_offset = p_in.m_offset; 178 | m_length = p_in.m_length; 179 | } 180 | 181 | system_exclusive_entry::system_exclusive_entry(std::size_t p_port, std::size_t p_offset, std::size_t p_length) 182 | { 183 | m_port = p_port; 184 | m_offset = p_offset; 185 | m_length = p_length; 186 | } 187 | 188 | unsigned system_exclusive_table::add_entry( const uint8_t * p_data, std::size_t p_size, std::size_t p_port ) 189 | { 190 | for ( auto it = m_entries.begin(); it < m_entries.end(); ++it ) 191 | { 192 | const system_exclusive_entry & entry = *it; 193 | if ( p_port == entry.m_port && p_size == entry.m_length && !memcmp( p_data, &m_data[ entry.m_offset ], p_size ) ) 194 | return ((unsigned)(it - m_entries.begin())); 195 | } 196 | system_exclusive_entry entry( p_port, m_data.size(), p_size ); 197 | m_data.insert( m_data.end(), p_data, p_data + p_size ); 198 | m_entries.push_back( entry ); 199 | return ((unsigned)(m_entries.size() - 1)); 200 | } 201 | 202 | void system_exclusive_table::get_entry( unsigned p_index, const uint8_t * & p_data, std::size_t & p_size, std::size_t & p_port ) 203 | { 204 | const system_exclusive_entry & entry = m_entries[ p_index ]; 205 | p_data = &m_data[ entry.m_offset ]; 206 | p_size = entry.m_length; 207 | p_port = entry.m_port; 208 | } 209 | 210 | midi_stream_event::midi_stream_event(unsigned long p_timestamp, unsigned p_event) 211 | { 212 | m_timestamp = p_timestamp; 213 | m_event = p_event; 214 | } 215 | 216 | midi_meta_data_item::midi_meta_data_item(const midi_meta_data_item & p_in) 217 | { 218 | m_timestamp = p_in.m_timestamp; 219 | m_name = p_in.m_name; 220 | m_value = p_in.m_value; 221 | } 222 | 223 | midi_meta_data_item::midi_meta_data_item(unsigned long p_timestamp, const char * p_name, const char * p_value) 224 | { 225 | m_timestamp = p_timestamp; 226 | m_name = p_name; 227 | m_value = p_value; 228 | } 229 | 230 | void midi_meta_data::add_item( const midi_meta_data_item & p_item ) 231 | { 232 | m_data.push_back( p_item ); 233 | } 234 | 235 | void midi_meta_data::append( const midi_meta_data & p_data ) 236 | { 237 | m_data.insert( m_data.end(), p_data.m_data.begin(), p_data.m_data.end() ); 238 | m_bitmap = p_data.m_bitmap; 239 | } 240 | 241 | bool midi_meta_data::get_item( const char * p_name, midi_meta_data_item & p_out ) const 242 | { 243 | for ( unsigned i = 0; i < m_data.size(); ++i ) 244 | { 245 | const midi_meta_data_item & item = m_data[ i ]; 246 | if ( !strcasecmp( p_name, item.m_name.c_str() ) ) 247 | { 248 | p_out = item; 249 | return true; 250 | } 251 | } 252 | return false; 253 | } 254 | 255 | bool midi_meta_data::get_bitmap( std::vector & p_out ) 256 | { 257 | p_out = m_bitmap; 258 | return p_out.size() != 0; 259 | } 260 | 261 | void midi_meta_data::assign_bitmap( std::vector::const_iterator const& begin, std::vector::const_iterator const& end ) 262 | { 263 | m_bitmap.assign( begin, end ); 264 | } 265 | 266 | std::size_t midi_meta_data::get_count() const 267 | { 268 | return m_data.size(); 269 | } 270 | 271 | const midi_meta_data_item & midi_meta_data::operator [] ( std::size_t p_index ) const 272 | { 273 | return m_data[ p_index ]; 274 | } 275 | 276 | void midi_container::encode_delta( std::vector & p_out, unsigned long delta ) 277 | { 278 | unsigned shift = 7 * 4; 279 | while ( shift && !( delta >> shift ) ) 280 | { 281 | shift -= 7; 282 | } 283 | while (shift > 0) 284 | { 285 | p_out.push_back( (unsigned char)( ( ( delta >> shift ) & 0x7F ) | 0x80 ) ); 286 | shift -= 7; 287 | } 288 | p_out.push_back( (unsigned char)( delta & 0x7F ) ); 289 | } 290 | 291 | unsigned long midi_container::timestamp_to_ms( unsigned long p_timestamp, unsigned long p_subsong ) const 292 | { 293 | unsigned long timestamp_ms = 0; 294 | unsigned long timestamp = 0; 295 | std::size_t tempo_index = 0; 296 | unsigned current_tempo = 500000; 297 | 298 | unsigned half_dtx = m_dtx * 500; 299 | unsigned p_dtx = half_dtx * 2; 300 | 301 | unsigned long subsong_count = m_tempo_map.size(); 302 | 303 | if ( p_subsong && subsong_count ) 304 | { 305 | for ( unsigned long i = std::min( p_subsong, subsong_count ); --i; ) 306 | { 307 | unsigned long count = m_tempo_map[ i ].get_count(); 308 | if ( count ) 309 | { 310 | current_tempo = m_tempo_map[ i ][ count - 1 ].m_tempo; 311 | break; 312 | } 313 | } 314 | } 315 | 316 | if ( p_subsong < subsong_count ) 317 | { 318 | const tempo_map & m_entries = m_tempo_map[ p_subsong ]; 319 | 320 | std::size_t tempo_count = m_entries.get_count(); 321 | 322 | while ( tempo_index < tempo_count && timestamp + p_timestamp >= m_entries[ tempo_index ].m_timestamp ) 323 | { 324 | unsigned long delta = m_entries[ tempo_index ].m_timestamp - timestamp; 325 | timestamp_ms += ((uint64_t)current_tempo * (uint64_t)delta + half_dtx) / p_dtx; 326 | current_tempo = m_entries[ tempo_index ].m_tempo; 327 | ++tempo_index; 328 | timestamp += delta; 329 | p_timestamp -= delta; 330 | } 331 | } 332 | 333 | timestamp_ms += ((uint64_t)current_tempo * (uint64_t)p_timestamp + half_dtx) / p_dtx; 334 | 335 | return timestamp_ms; 336 | } 337 | 338 | void midi_container::initialize( unsigned p_form, unsigned p_dtx ) 339 | { 340 | m_form = p_form; 341 | m_dtx = p_dtx; 342 | if ( p_form != 2 ) 343 | { 344 | m_channel_mask.resize( 1 ); 345 | m_channel_mask[ 0 ] = 0; 346 | m_tempo_map.resize( 1 ); 347 | m_timestamp_end.resize( 1 ); 348 | m_timestamp_end[ 0 ] = 0; 349 | m_timestamp_loop_start.resize( 1 ); 350 | m_timestamp_loop_end.resize( 1 ); 351 | } 352 | } 353 | 354 | void midi_container::add_track( const midi_track & p_track ) 355 | { 356 | unsigned i; 357 | unsigned long port_number = 0; 358 | 359 | std::vector data; 360 | std::string device_name; 361 | 362 | m_tracks.push_back( p_track ); 363 | 364 | for ( i = 0; i < p_track.get_count(); ++i ) 365 | { 366 | const midi_event & event = p_track[ i ]; 367 | if ( event.m_type == midi_event::extended && event.get_data_count() >= 5 && 368 | event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x51 ) 369 | { 370 | unsigned tempo = ( event.m_data[ 2 ] << 16 ) + ( event.m_data[ 3 ] << 8 ) + event.m_data[ 4 ]; 371 | if ( m_form != 2 ) m_tempo_map[ 0 ].add_tempo( tempo, event.m_timestamp ); 372 | else 373 | { 374 | m_tempo_map.resize( m_tracks.size() ); 375 | m_tempo_map[ m_tracks.size() - 1 ].add_tempo( tempo, event.m_timestamp ); 376 | } 377 | } 378 | else if ( event.m_type == midi_event::extended && event.get_data_count() >= 3 && 379 | event.m_data[ 0 ] == 0xFF ) 380 | { 381 | if ( event.m_data[ 1 ] == 4 || event.m_data[1] == 9 ) 382 | { 383 | unsigned long data_count = event.get_data_count() - 2; 384 | data.resize( data_count ); 385 | event.copy_data( &data[0], 2, data_count ); 386 | device_name.assign( data.begin(), data.begin() + data_count ); 387 | std::transform( device_name.begin(), device_name.end(), device_name.begin(), ::tolower ); 388 | } 389 | else if ( event.m_data[ 1 ] == 0x21 ) 390 | { 391 | port_number = event.m_data[ 2 ]; 392 | limit_port_number( port_number ); 393 | device_name.clear(); 394 | } 395 | } 396 | else if ( event.m_type == midi_event::note_on || event.m_type == midi_event::note_off ) 397 | { 398 | unsigned channel = event.m_channel; 399 | if ( device_name.length() ) 400 | { 401 | unsigned long j, k; 402 | for ( j = 0, k = m_device_names[ channel ].size(); j < k; ++j ) 403 | { 404 | if ( !strcmp( m_device_names[ channel ][ j ].c_str(), device_name.c_str() ) ) break; 405 | } 406 | if ( j < k ) port_number = j; 407 | else 408 | { 409 | m_device_names[ channel ].push_back( device_name ); 410 | port_number = k; 411 | } 412 | device_name.clear(); 413 | limit_port_number( port_number ); 414 | } 415 | 416 | channel += 16 * port_number; 417 | channel %= 48; 418 | if ( m_form != 2 ) m_channel_mask[ 0 ] |= 1ULL << channel; 419 | else 420 | { 421 | m_channel_mask.resize( m_tracks.size(), 0 ); 422 | m_channel_mask[ m_tracks.size() - 1 ] |= 1ULL << channel; 423 | } 424 | } 425 | } 426 | 427 | if ( i && m_form != 2 && p_track[ i - 1 ].m_timestamp > m_timestamp_end[ 0 ] ) 428 | m_timestamp_end[ 0 ] = p_track[ i - 1 ].m_timestamp; 429 | else if ( m_form == 2 ) 430 | { 431 | if ( i ) 432 | m_timestamp_end.push_back( p_track[ i - 1 ].m_timestamp ); 433 | else 434 | m_timestamp_end.push_back( (unsigned)0 ); 435 | } 436 | } 437 | 438 | void midi_container::add_track_event( std::size_t p_track_index, const midi_event & p_event ) 439 | { 440 | midi_track & track = m_tracks[ p_track_index ]; 441 | 442 | track.add_event( p_event ); 443 | 444 | if ( p_event.m_type == midi_event::extended && p_event.get_data_count() >= 5 && 445 | p_event.m_data[ 0 ] == 0xFF && p_event.m_data[ 1 ] == 0x51 ) 446 | { 447 | unsigned tempo = ( p_event.m_data[ 2 ] << 16 ) + ( p_event.m_data[ 3 ] << 8 ) + p_event.m_data[ 4 ]; 448 | if ( m_form != 2 ) m_tempo_map[ 0 ].add_tempo( tempo, p_event.m_timestamp ); 449 | else 450 | { 451 | m_tempo_map.resize( m_tracks.size() ); 452 | m_tempo_map[ p_track_index ].add_tempo( tempo, p_event.m_timestamp ); 453 | } 454 | } 455 | else if ( p_event.m_type == midi_event::note_on || p_event.m_type == midi_event::note_off ) 456 | { 457 | if ( m_form != 2 ) m_channel_mask[ 0 ] |= 1ULL << p_event.m_channel; 458 | else 459 | { 460 | m_channel_mask.resize( m_tracks.size(), 0 ); 461 | m_channel_mask[ p_track_index ] |= 1ULL << p_event.m_channel; 462 | } 463 | } 464 | 465 | if ( m_form != 2 && p_event.m_timestamp > m_timestamp_end[ 0 ] ) 466 | { 467 | m_timestamp_end[ 0 ] = p_event.m_timestamp; 468 | } 469 | else if ( m_form == 2 && p_event.m_timestamp > m_timestamp_end[ p_track_index ] ) 470 | { 471 | m_timestamp_end[ p_track_index ] = p_event.m_timestamp; 472 | } 473 | } 474 | 475 | void midi_container::merge_tracks( const midi_container & p_source ) 476 | { 477 | for ( unsigned i = 0; i < p_source.m_tracks.size(); i++ ) 478 | { 479 | add_track( p_source.m_tracks[ i ] ); 480 | } 481 | } 482 | 483 | void midi_container::set_track_count( unsigned count ) 484 | { 485 | m_tracks.resize( count ); 486 | } 487 | 488 | void midi_container::set_extra_meta_data( const midi_meta_data & p_data ) 489 | { 490 | m_extra_meta_data = p_data; 491 | } 492 | 493 | void midi_container::apply_hackfix( unsigned hack ) 494 | { 495 | switch (hack) 496 | { 497 | case 0: 498 | for (unsigned i = 0; i < m_tracks.size(); ++i) 499 | { 500 | midi_track & t = m_tracks[ i ]; 501 | for ( unsigned j = 0; j < t.get_count(); ) 502 | { 503 | if ( t[ j ].m_type != midi_event::extended && 504 | t[ j ].m_channel == 16 ) 505 | { 506 | t.remove_event( j ); 507 | } 508 | else 509 | { 510 | ++j; 511 | } 512 | } 513 | } 514 | break; 515 | 516 | case 1: 517 | for (unsigned i = 0; i < m_tracks.size(); ++i) 518 | { 519 | midi_track & t = m_tracks[ i ]; 520 | for ( unsigned j = 0; j < t.get_count(); ) 521 | { 522 | if ( t[ j ].m_type != midi_event::extended && 523 | ( t[ j ].m_channel - 10 < 6 ) ) 524 | { 525 | t.remove_event( j ); 526 | } 527 | else 528 | { 529 | ++j; 530 | } 531 | } 532 | } 533 | break; 534 | } 535 | } 536 | 537 | void midi_container::serialize_as_stream( unsigned long subsong, 538 | std::vector & p_stream, 539 | system_exclusive_table & p_system_exclusive, 540 | unsigned long & loop_start, 541 | unsigned long & loop_end, 542 | unsigned clean_flags ) const 543 | { 544 | std::vector data; 545 | std::vector track_positions; 546 | std::vector port_numbers; 547 | std::vector device_names; 548 | std::size_t track_count = m_tracks.size(); 549 | 550 | unsigned long tick_loop_start = get_timestamp_loop_start(subsong); 551 | unsigned long tick_loop_end = get_timestamp_loop_end(subsong); 552 | unsigned long local_loop_start = ~0UL; 553 | unsigned long local_loop_end = ~0UL; 554 | 555 | track_positions.resize( track_count, 0 ); 556 | port_numbers.resize( track_count, 0 ); 557 | device_names.resize( track_count ); 558 | 559 | bool clean_emidi = !!( clean_flags & clean_flag_emidi ); 560 | bool clean_instruments = !!( clean_flags & clean_flag_instruments ); 561 | bool clean_banks = !!( clean_flags & clean_flag_banks ); 562 | 563 | if ( clean_emidi ) 564 | { 565 | for ( unsigned i = 0; i < track_count; ++i ) 566 | { 567 | bool skip_track = false; 568 | const midi_track & track = m_tracks[ i ]; 569 | for ( unsigned j = 0; j < track.get_count(); ++j ) 570 | { 571 | const midi_event & event = track[ j ]; 572 | if ( event.m_type == midi_event::control_change && 573 | event.m_data[ 0 ] == 110 ) 574 | { 575 | if ( event.m_data[ 1 ] != 0 && event.m_data[ 1 ] != 1 && event.m_data[ 1 ] != 127 ) 576 | { 577 | skip_track = true; 578 | break; 579 | } 580 | } 581 | } 582 | if ( skip_track ) 583 | { 584 | track_positions[ i ] = track.get_count(); 585 | } 586 | } 587 | } 588 | 589 | if ( m_form == 2 ) 590 | { 591 | for ( unsigned long i = 0; i < track_count; ++i ) 592 | { 593 | if ( i != subsong ) track_positions[ i ] = m_tracks[ i ].get_count(); 594 | } 595 | } 596 | 597 | for (;;) 598 | { 599 | unsigned long next_timestamp = ~0UL; 600 | std::size_t next_track = 0; 601 | for ( unsigned i = 0; i < track_count; ++i ) 602 | { 603 | if ( track_positions[ i ] >= m_tracks[ i ].get_count() ) continue; 604 | if ( m_tracks[ i ][ track_positions[ i ] ].m_timestamp < next_timestamp ) 605 | { 606 | next_timestamp = m_tracks[ i ][ track_positions[ i ] ].m_timestamp; 607 | next_track = i; 608 | } 609 | } 610 | if ( next_timestamp == ~0UL ) break; 611 | 612 | bool filtered = false; 613 | 614 | if ( clean_instruments || clean_banks ) 615 | { 616 | const midi_event & event = m_tracks[ next_track ][ track_positions[ next_track ] ]; 617 | if ( clean_instruments && event.m_type == midi_event::program_change ) filtered = true; 618 | else if ( clean_banks && event.m_type == midi_event::control_change && 619 | ( event.m_data[ 0 ] == 0x00 || event.m_data[ 0 ] == 0x20 ) ) filtered = true; 620 | } 621 | 622 | if ( !filtered ) 623 | { 624 | unsigned long tempo_track = 0; 625 | if ( m_form == 2 && subsong ) tempo_track = subsong; 626 | 627 | const midi_event & event = m_tracks[ next_track ][ track_positions[ next_track ] ]; 628 | 629 | if ( local_loop_start == ~0UL && event.m_timestamp >= tick_loop_start ) 630 | local_loop_start = p_stream.size(); 631 | if ( local_loop_end == ~0UL && event.m_timestamp > tick_loop_end ) 632 | local_loop_end = p_stream.size(); 633 | 634 | unsigned long timestamp_ms = timestamp_to_ms( event.m_timestamp, tempo_track ); 635 | if ( event.m_type != midi_event::extended ) 636 | { 637 | if ( device_names[ next_track ].length() ) 638 | { 639 | unsigned long i, j; 640 | for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) 641 | { 642 | if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; 643 | } 644 | port_numbers[ next_track ] = (uint8_t) i; 645 | device_names[ next_track ].clear(); 646 | limit_port_number( port_numbers[ next_track ] ); 647 | } 648 | 649 | uint32_t event_code = ( ( event.m_type + 8 ) << 4 ) + event.m_channel; 650 | if ( event.m_data_count >= 1 ) event_code += event.m_data[ 0 ] << 8; 651 | if ( event.m_data_count >= 2 ) event_code += event.m_data[ 1 ] << 16; 652 | event_code += port_numbers[ next_track ] << 24; 653 | p_stream.push_back( midi_stream_event( timestamp_ms, event_code ) ); 654 | } 655 | else 656 | { 657 | std::size_t data_count = event.get_data_count(); 658 | if ( data_count >= 3 && event.m_data[ 0 ] == 0xF0 ) 659 | { 660 | if ( device_names[ next_track ].length() ) 661 | { 662 | unsigned long i, j; 663 | for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) 664 | { 665 | if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; 666 | } 667 | port_numbers[ next_track ] = (uint8_t) i; 668 | device_names[ next_track ].clear(); 669 | limit_port_number( port_numbers[ next_track ] ); 670 | } 671 | 672 | data.resize( data_count ); 673 | event.copy_data( &data[0], 0, data_count ); 674 | if ( data[ data_count - 1 ] == 0xF7 ) 675 | { 676 | uint32_t system_exclusive_index = p_system_exclusive.add_entry( &data[0], data_count, port_numbers[ next_track ] ); 677 | p_stream.push_back( midi_stream_event( timestamp_ms, system_exclusive_index | 0x80000000 ) ); 678 | } 679 | } 680 | else if ( data_count >= 3 && event.m_data[ 0 ] == 0xFF ) 681 | { 682 | if ( event.m_data[ 1 ] == 4 || event.m_data[ 1 ] == 9 ) 683 | { 684 | unsigned long _data_count = event.get_data_count() - 2; 685 | data.resize( _data_count ); 686 | event.copy_data( &data[0], 2, _data_count ); 687 | device_names[ next_track ].clear(); 688 | device_names[ next_track ].assign( data.begin(), data.begin() + _data_count ); 689 | std::transform( device_names[ next_track ].begin(), device_names[ next_track ].end(), device_names[ next_track ].begin(), ::tolower ); 690 | } 691 | else if ( event.m_data[ 1 ] == 0x21 ) 692 | { 693 | port_numbers[ next_track ] = event.m_data[ 2 ]; 694 | device_names[ next_track ].clear(); 695 | limit_port_number( port_numbers[ next_track ] ); 696 | } 697 | } 698 | else if ( data_count == 1 && event.m_data[ 0 ] >= 0xF8 ) 699 | { 700 | if ( device_names[ next_track ].length() ) 701 | { 702 | unsigned long i, j; 703 | for ( i = 0, j = m_device_names[ event.m_channel ].size(); i < j; ++i ) 704 | { 705 | if ( !strcmp( m_device_names[ event.m_channel ][ i ].c_str(), device_names[ next_track ].c_str() ) ) break; 706 | } 707 | port_numbers[ next_track ] = (uint8_t) i; 708 | device_names[ next_track ].clear(); 709 | limit_port_number( port_numbers[ next_track ] ); 710 | } 711 | 712 | uint32_t event_code = port_numbers[ next_track ] << 24; 713 | event_code += event.m_data[ 0 ]; 714 | p_stream.push_back( midi_stream_event( timestamp_ms, event_code ) ); 715 | } 716 | } 717 | } 718 | 719 | track_positions[ next_track ]++; 720 | } 721 | 722 | loop_start = local_loop_start; 723 | loop_end = local_loop_end; 724 | } 725 | 726 | midi_track midi_container::demote_to_form_0() const 727 | { 728 | if ( m_tracks.size() < 1 ) return midi_track(); 729 | 730 | midi_track ttrack = m_tracks[ 0 ]; 731 | 732 | for ( unsigned i = 1; i < m_tracks.size(); ++i ) 733 | { 734 | const midi_track & track = m_tracks[ i ]; 735 | 736 | for ( unsigned j = 0; j < track.get_count(); ++j ) 737 | { 738 | ttrack.add_event( track[ j ] ); 739 | } 740 | } 741 | 742 | return ttrack; 743 | } 744 | 745 | void midi_container::serialize_as_standard_midi_file( std::vector & p_midi_file ) const 746 | { 747 | if ( !m_tracks.size() ) return; 748 | 749 | std::vector tracks; 750 | 751 | if ( m_form > 0 ) 752 | tracks = m_tracks; 753 | else 754 | tracks.push_back( demote_to_form_0() ); 755 | 756 | std::vector data; 757 | 758 | const char signature[] = "MThd"; 759 | p_midi_file.insert( p_midi_file.end(), signature, signature + 4 ); 760 | p_midi_file.push_back( 0 ); 761 | p_midi_file.push_back( 0 ); 762 | p_midi_file.push_back( 0 ); 763 | p_midi_file.push_back( 6 ); 764 | p_midi_file.push_back( 0 ); 765 | p_midi_file.push_back( m_form ); 766 | p_midi_file.push_back( (uint8_t) (tracks.size() >> 8) ); 767 | p_midi_file.push_back( (uint8_t) tracks.size() ); 768 | p_midi_file.push_back( (m_dtx >> 8) ); 769 | p_midi_file.push_back( m_dtx ); 770 | 771 | for ( unsigned i = 0; i < tracks.size(); ++i ) 772 | { 773 | const midi_track & track = tracks[ i ]; 774 | unsigned long last_timestamp = 0; 775 | unsigned char last_event_code = 0xFF; 776 | std::size_t length_offset; 777 | 778 | const char _signature[] = "MTrk"; 779 | p_midi_file.insert( p_midi_file.end(), _signature, _signature + 4 ); 780 | 781 | length_offset = p_midi_file.size(); 782 | p_midi_file.push_back( 0 ); 783 | p_midi_file.push_back( 0 ); 784 | p_midi_file.push_back( 0 ); 785 | p_midi_file.push_back( 0 ); 786 | 787 | for ( unsigned j = 0; j < track.get_count(); ++j ) 788 | { 789 | const midi_event & event = track[ j ]; 790 | encode_delta( p_midi_file, event.m_timestamp - last_timestamp ); 791 | last_timestamp = event.m_timestamp; 792 | if ( event.m_type != midi_event::extended ) 793 | { 794 | const unsigned char event_code = ( ( event.m_type + 8 ) << 4 ) + event.m_channel; 795 | if ( event_code != last_event_code ) 796 | { 797 | p_midi_file.push_back( event_code ); 798 | last_event_code = event_code; 799 | } 800 | p_midi_file.insert( p_midi_file.end(), event.m_data, event.m_data + event.m_data_count ); 801 | } 802 | else 803 | { 804 | std::size_t data_count = event.get_data_count(); 805 | if ( data_count >= 1 ) 806 | { 807 | if ( event.m_data[ 0 ] == 0xF0 ) 808 | { 809 | --data_count; 810 | p_midi_file.push_back( 0xF0 ); 811 | encode_delta( p_midi_file, data_count ); 812 | if ( data_count ) 813 | { 814 | data.resize( data_count ); 815 | event.copy_data( &data[0], 1, data_count ); 816 | p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); 817 | } 818 | } 819 | else if ( event.m_data[ 0 ] == 0xFF && data_count >= 2 ) 820 | { 821 | data_count -= 2; 822 | p_midi_file.push_back( 0xFF ); 823 | p_midi_file.push_back( event.m_data[ 1 ] ); 824 | encode_delta( p_midi_file, data_count ); 825 | if ( data_count ) 826 | { 827 | data.resize( data_count ); 828 | event.copy_data( &data[0], 2, data_count ); 829 | p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); 830 | } 831 | } 832 | else 833 | { 834 | data.resize( data_count ); 835 | event.copy_data( &data[0], 1, data_count ); 836 | p_midi_file.insert( p_midi_file.end(), data.begin(), data.begin() + data_count ); 837 | } 838 | } 839 | } 840 | } 841 | 842 | std::size_t track_length = p_midi_file.size() - length_offset - 4; 843 | p_midi_file[ length_offset + 0 ] = (unsigned char)( track_length >> 24 ); 844 | p_midi_file[ length_offset + 1 ] = (unsigned char)( track_length >> 16 ); 845 | p_midi_file[ length_offset + 2 ] = (unsigned char)( track_length >> 8 ); 846 | p_midi_file[ length_offset + 3 ] = (unsigned char)track_length; 847 | } 848 | } 849 | 850 | void midi_container::promote_to_form_1() 851 | { 852 | if ( m_form == 0 && m_tracks.size() <= 2 ) 853 | { 854 | bool meter_track_present = false; 855 | midi_track new_tracks[17]; 856 | midi_track original_data_track = m_tracks[ m_tracks.size() - 1 ]; 857 | if ( m_tracks.size() > 1 ) 858 | { 859 | new_tracks[0] = m_tracks[0]; 860 | meter_track_present = true; 861 | } 862 | 863 | m_tracks.resize( 0 ); 864 | 865 | for ( std::size_t i = 0; i < original_data_track.get_count(); ++i ) 866 | { 867 | const midi_event & event = original_data_track[ i ]; 868 | 869 | if ( event.m_type != midi_event::extended ) 870 | { 871 | new_tracks[ 1 + event.m_channel ].add_event( event ); 872 | } 873 | else 874 | { 875 | if ( event.m_data[0] != 0xFF || event.get_data_count() < 2 || event.m_data[1] != 0x2F ) 876 | { 877 | new_tracks[ 0 ].add_event( event ); 878 | } 879 | else 880 | { 881 | if ( !meter_track_present ) 882 | new_tracks[ 0 ].add_event( event ); 883 | for ( std::size_t j = 1; j < 17; ++j ) 884 | { 885 | new_tracks[ j ].add_event( event ); 886 | } 887 | } 888 | } 889 | } 890 | 891 | for ( std::size_t i = 0; i < 17; ++i ) 892 | { 893 | if ( new_tracks[ i ].get_count() > 1 ) 894 | add_track( new_tracks[ i ] ); 895 | } 896 | 897 | m_form = 1; 898 | } 899 | } 900 | 901 | unsigned long midi_container::get_subsong_count() const 902 | { 903 | unsigned long subsong_count = 0; 904 | for ( unsigned i = 0; i < m_channel_mask.size(); ++i ) 905 | { 906 | if ( m_channel_mask[ i ] ) ++subsong_count; 907 | } 908 | return subsong_count; 909 | } 910 | 911 | unsigned long midi_container::get_subsong( unsigned long p_index ) const 912 | { 913 | for ( unsigned i = 0; i < m_channel_mask.size(); ++i ) 914 | { 915 | if ( m_channel_mask[ i ] ) 916 | { 917 | if ( p_index ) --p_index; 918 | else return i; 919 | } 920 | } 921 | return 0; 922 | } 923 | 924 | unsigned long midi_container::get_timestamp_end(unsigned long subsong, bool ms /* = false */) const 925 | { 926 | unsigned long tempo_track = 0; 927 | unsigned long timestamp = m_timestamp_end[ 0 ]; 928 | if ( m_form == 2 && subsong ) 929 | { 930 | tempo_track = subsong; 931 | timestamp = m_timestamp_end[ subsong ]; 932 | } 933 | if ( !ms ) return timestamp; 934 | else return timestamp_to_ms( timestamp, tempo_track ); 935 | } 936 | 937 | unsigned midi_container::get_format() const 938 | { 939 | return m_form; 940 | } 941 | 942 | unsigned midi_container::get_track_count() const 943 | { 944 | return (unsigned) m_tracks.size(); 945 | } 946 | 947 | unsigned midi_container::get_channel_count( unsigned long subsong ) const 948 | { 949 | unsigned count = 0; 950 | uint64_t j = 1; 951 | for (unsigned i = 0; i < 48; ++i, j <<= 1) 952 | { 953 | if ( m_channel_mask[ subsong ] & j ) ++count; 954 | } 955 | return count; 956 | } 957 | 958 | unsigned long midi_container::get_timestamp_loop_start( unsigned long subsong, bool ms /* = false */ ) const 959 | { 960 | unsigned long tempo_track = 0; 961 | unsigned long timestamp = m_timestamp_loop_start[ 0 ]; 962 | if ( m_form == 2 && subsong ) 963 | { 964 | tempo_track = subsong; 965 | timestamp = m_timestamp_loop_start[ subsong ]; 966 | } 967 | if ( !ms ) return timestamp; 968 | else if ( timestamp != ~0UL ) return timestamp_to_ms( timestamp, tempo_track ); 969 | else return ~0UL; 970 | } 971 | 972 | unsigned long midi_container::get_timestamp_loop_end( unsigned long subsong, bool ms /* = false */ ) const 973 | { 974 | unsigned long tempo_track = 0; 975 | unsigned long timestamp = m_timestamp_loop_end[ 0 ]; 976 | if ( m_form == 2 && subsong ) 977 | { 978 | tempo_track = subsong; 979 | timestamp = m_timestamp_loop_end[ subsong ]; 980 | } 981 | if ( !ms ) return timestamp; 982 | else if ( timestamp != ~0UL ) return timestamp_to_ms( timestamp, tempo_track ); 983 | else return ~0UL; 984 | } 985 | 986 | /* TODO: Use iconv or libintl or something to probe for code pages and convert some mess to UTF-8 */ 987 | static void convert_mess_to_utf8( const char * p_src, std::size_t p_src_len, std::string & p_dst ) 988 | { 989 | p_dst.assign( p_src, p_src + p_src_len ); 990 | } 991 | 992 | void midi_container::get_meta_data( unsigned long subsong, midi_meta_data & p_out ) 993 | { 994 | char temp[32]; 995 | std::string convert; 996 | 997 | std::vector data; 998 | 999 | bool type_found = false; 1000 | bool type_non_gm_found = false; 1001 | 1002 | for ( unsigned long i = 0; i < m_tracks.size(); ++i ) 1003 | { 1004 | if ( m_form == 2 && i != subsong ) continue; 1005 | 1006 | unsigned long tempo_track = 0; 1007 | if ( m_form == 2 ) tempo_track = i; 1008 | 1009 | const midi_track & track = m_tracks[ i ]; 1010 | for ( unsigned j = 0; j < track.get_count(); ++j ) 1011 | { 1012 | const midi_event & event = track[ j ]; 1013 | if ( event.m_type == midi_event::extended ) 1014 | { 1015 | std::size_t data_count = event.get_data_count(); 1016 | if ( !type_non_gm_found && data_count >= 1 && event.m_data[ 0 ] == 0xF0 ) 1017 | { 1018 | unsigned char test = 0; 1019 | unsigned char test2 = 0; 1020 | if ( data_count > 1 ) test = event.m_data[ 1 ]; 1021 | if ( data_count > 3 ) test2 = event.m_data[ 3 ]; 1022 | 1023 | const char * type = NULL; 1024 | 1025 | switch( test ) 1026 | { 1027 | case 0x7E: 1028 | type_found = true; 1029 | break; 1030 | case 0x43: 1031 | type = "XG"; 1032 | break; 1033 | case 0x42: 1034 | type = "X5"; 1035 | break; 1036 | case 0x41: 1037 | if ( test2 == 0x42 ) type = "GS"; 1038 | else if ( test2 == 0x16 ) type = "MT-32"; 1039 | else if ( test2 == 0x14 ) type = "D-50"; 1040 | } 1041 | 1042 | if ( type ) 1043 | { 1044 | type_found = true; 1045 | type_non_gm_found = true; 1046 | p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "type", type ) ); 1047 | } 1048 | } 1049 | else if ( data_count >= 2 && event.m_data[ 0 ] == 0xFF ) 1050 | { 1051 | data_count -= 2; 1052 | switch ( event.m_data[ 1 ] ) 1053 | { 1054 | case 6: 1055 | data.resize( data_count ); 1056 | event.copy_data( &data[0], 2, data_count ); 1057 | convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); 1058 | p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "track_marker", convert.c_str() ) ); 1059 | break; 1060 | 1061 | case 2: 1062 | data.resize( data_count ); 1063 | event.copy_data( &data[0], 2, data_count ); 1064 | convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); 1065 | p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), "copyright", convert.c_str() ) ); 1066 | break; 1067 | 1068 | case 1: 1069 | data.resize( data_count ); 1070 | event.copy_data( &data[0], 2, data_count ); 1071 | convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); 1072 | snprintf(temp, 31, "track_text_%02lu", i); 1073 | p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), temp, convert.c_str() ) ); 1074 | break; 1075 | 1076 | case 3: 1077 | case 4: 1078 | data.resize( data_count ); 1079 | event.copy_data( &data[0], 2, data_count ); 1080 | convert_mess_to_utf8( ( const char * ) &data[0], data_count, convert ); 1081 | snprintf(temp, 31, "track_name_%02lu", i); 1082 | p_out.add_item( midi_meta_data_item( timestamp_to_ms( event.m_timestamp, tempo_track ), temp, convert.c_str() ) ); 1083 | break; 1084 | } 1085 | } 1086 | } 1087 | } 1088 | } 1089 | 1090 | if ( type_found && !type_non_gm_found ) 1091 | { 1092 | p_out.add_item( midi_meta_data_item( 0, "type", "GM" ) ); 1093 | } 1094 | 1095 | p_out.append( m_extra_meta_data ); 1096 | } 1097 | 1098 | void midi_container::trim_tempo_map( unsigned long p_index, unsigned long base_timestamp ) 1099 | { 1100 | if ( p_index < m_tempo_map.size() ) 1101 | { 1102 | tempo_map & map = m_tempo_map[ p_index ]; 1103 | 1104 | for ( unsigned long i = 0, j = map.get_count(); i < j; ++i ) 1105 | { 1106 | tempo_entry & entry = map[ i ]; 1107 | if ( entry.m_timestamp >= base_timestamp ) 1108 | entry.m_timestamp -= base_timestamp; 1109 | else 1110 | entry.m_timestamp = 0; 1111 | } 1112 | } 1113 | } 1114 | 1115 | void midi_container::trim_range_of_tracks(unsigned long start, unsigned long end) 1116 | { 1117 | unsigned long timestamp_first_note = ~0UL; 1118 | 1119 | for (unsigned long i = start; i <= end; ++i) 1120 | { 1121 | unsigned long j, k; 1122 | 1123 | const midi_track & track = m_tracks[ i ]; 1124 | 1125 | for (j = 0, k = track.get_count(); j < k; ++j) 1126 | { 1127 | const midi_event & event = track[ j ]; 1128 | 1129 | if ( event.m_type == midi_event::note_on && event.m_data[ 0 ] ) 1130 | break; 1131 | } 1132 | 1133 | if ( j < k ) 1134 | { 1135 | if ( track[ j ].m_timestamp < timestamp_first_note ) 1136 | timestamp_first_note = track[ j ].m_timestamp; 1137 | } 1138 | } 1139 | 1140 | if ( timestamp_first_note < ~0UL && timestamp_first_note > 0 ) 1141 | { 1142 | for (unsigned long i = start; i <= end; ++i) 1143 | { 1144 | midi_track & track = m_tracks[ i ]; 1145 | 1146 | for (unsigned long j = 0, k = track.get_count(); j < k; ++j) 1147 | { 1148 | midi_event & event = track[ j ]; 1149 | if ( event.m_timestamp >= timestamp_first_note ) 1150 | event.m_timestamp -= timestamp_first_note; 1151 | else 1152 | event.m_timestamp = 0; 1153 | } 1154 | } 1155 | 1156 | if ( start == end ) 1157 | { 1158 | trim_tempo_map( start, timestamp_first_note ); 1159 | 1160 | m_timestamp_end[ start ] -= timestamp_first_note; 1161 | 1162 | if ( m_timestamp_loop_end[ start ] != ~0UL ) 1163 | m_timestamp_loop_end[ start ] -= timestamp_first_note; 1164 | if ( m_timestamp_loop_start[ start ] != ~0UL ) 1165 | { 1166 | if ( m_timestamp_loop_start[ start ] > timestamp_first_note ) 1167 | m_timestamp_loop_start[ start ] -= timestamp_first_note; 1168 | else 1169 | m_timestamp_loop_start[ start ] = 0; 1170 | } 1171 | } 1172 | else 1173 | { 1174 | trim_tempo_map( 0, timestamp_first_note ); 1175 | 1176 | m_timestamp_end[ 0 ] -= timestamp_first_note; 1177 | 1178 | if ( m_timestamp_loop_end[ 0 ] != ~0UL ) 1179 | m_timestamp_loop_end[ 0 ] -= timestamp_first_note; 1180 | if ( m_timestamp_loop_start[ 0 ] != ~0UL ) 1181 | { 1182 | if ( m_timestamp_loop_start[ 0 ] > timestamp_first_note ) 1183 | m_timestamp_loop_start[ 0 ] -= timestamp_first_note; 1184 | else 1185 | m_timestamp_loop_start[ 0 ] = 0; 1186 | } 1187 | } 1188 | } 1189 | } 1190 | 1191 | void midi_container::trim_start() 1192 | { 1193 | if (m_form == 2) 1194 | { 1195 | for (unsigned long i = 0, j = m_tracks.size(); i < j; ++i) 1196 | { 1197 | trim_range_of_tracks(i, i); 1198 | } 1199 | } 1200 | else 1201 | { 1202 | trim_range_of_tracks(0, m_tracks.size() - 1); 1203 | } 1204 | } 1205 | 1206 | void midi_container::split_by_instrument_changes(split_callback cb) 1207 | { 1208 | if (m_form != 1) /* This would literally die on anything else */ 1209 | return; 1210 | 1211 | for (unsigned long i = 0, j = m_tracks.size(); i < j; ++i) 1212 | { 1213 | midi_track source_track = m_tracks[0]; 1214 | 1215 | m_tracks.erase(m_tracks.begin()); 1216 | 1217 | midi_track output_track; 1218 | midi_track program_change; 1219 | 1220 | for (unsigned long k = 0, l = source_track.get_count(); k < l; ++k) 1221 | { 1222 | const midi_event & event = source_track[ k ]; 1223 | if ( event.m_type == midi_event::program_change || 1224 | ( event.m_type == midi_event::control_change && 1225 | (event.m_data[0] == 0 || event.m_data[0] == 0x20))) 1226 | { 1227 | program_change.add_event( event ); 1228 | } 1229 | else 1230 | { 1231 | if (program_change.get_count()) 1232 | { 1233 | if (output_track.get_count()) 1234 | m_tracks.push_back( output_track ); 1235 | output_track = program_change; 1236 | if (cb) 1237 | { 1238 | unsigned long timestamp = 0; 1239 | uint8_t bank_msb = 0, bank_lsb = 0, instrument = 0; 1240 | for (int i = 0, j = program_change.get_count(); i < j; ++i) 1241 | { 1242 | const midi_event & ev = program_change[i]; 1243 | if (ev.m_type == midi_event::program_change) 1244 | instrument = ev.m_data[0]; 1245 | else if (ev.m_data[0] == 0) 1246 | bank_msb = ev.m_data[1]; 1247 | else 1248 | bank_lsb = ev.m_data[1]; 1249 | if (ev.m_timestamp > timestamp) 1250 | timestamp = ev.m_timestamp; 1251 | } 1252 | 1253 | std::string name = cb(bank_msb, bank_lsb, instrument); 1254 | 1255 | std::vector data; 1256 | 1257 | data.resize(name.length() + 2); 1258 | 1259 | data[0] = 0xFF; 1260 | data[1] = 0x03; 1261 | 1262 | std::copy(name.begin(), name.end(), data.begin() + 2); 1263 | 1264 | output_track.add_event(midi_event(timestamp, midi_event::extended, 0, &data[0], data.size())); 1265 | } 1266 | program_change = midi_track(); 1267 | } 1268 | output_track.add_event( event ); 1269 | } 1270 | } 1271 | 1272 | if (output_track.get_count()) 1273 | m_tracks.push_back(output_track); 1274 | } 1275 | } 1276 | 1277 | void midi_container::scan_for_loops( bool p_xmi_loops, bool p_marker_loops, bool p_rpgmaker_loops, bool p_touhou_loops ) 1278 | { 1279 | std::vector data; 1280 | 1281 | unsigned long subsong_count = m_form == 2 ? m_tracks.size() : 1; 1282 | 1283 | m_timestamp_loop_start.resize( subsong_count ); 1284 | m_timestamp_loop_end.resize( subsong_count ); 1285 | 1286 | for ( unsigned long i = 0; i < subsong_count; ++i ) 1287 | { 1288 | m_timestamp_loop_start[ i ] = ~0UL; 1289 | m_timestamp_loop_end[ i ] = ~0UL; 1290 | } 1291 | 1292 | if ( p_touhou_loops && m_form == 0 ) 1293 | { 1294 | bool loop_start_found = false; 1295 | bool loop_end_found = false; 1296 | bool errored = false; 1297 | 1298 | for ( unsigned long i = 0; !errored && i < m_tracks.size(); ++i ) 1299 | { 1300 | const midi_track & track = m_tracks[ i ]; 1301 | for ( unsigned long j = 0; !errored && j < track.get_count(); ++j ) 1302 | { 1303 | const midi_event & event = track[ j ]; 1304 | if ( event.m_type == midi_event::control_change ) 1305 | { 1306 | if ( event.m_data[ 0 ] == 2 ) 1307 | { 1308 | if ( event.m_data[ 1 ] != 0 ) 1309 | { 1310 | errored = true; 1311 | break; 1312 | } 1313 | m_timestamp_loop_start[ 0 ] = event.m_timestamp; 1314 | loop_start_found = true; 1315 | } 1316 | if ( event.m_data[ 0 ] == 4 ) 1317 | { 1318 | if ( event.m_data[ 1 ] != 0 ) 1319 | { 1320 | errored = true; 1321 | break; 1322 | } 1323 | m_timestamp_loop_end[ 0 ] = event.m_timestamp; 1324 | loop_end_found = true; 1325 | } 1326 | } 1327 | } 1328 | } 1329 | 1330 | if ( errored ) 1331 | { 1332 | m_timestamp_loop_start[ 0 ] = ~0UL; 1333 | m_timestamp_loop_end[ 0 ] = ~0UL; 1334 | } 1335 | } 1336 | 1337 | if ( p_rpgmaker_loops ) 1338 | { 1339 | bool emidi_commands_found = false; 1340 | 1341 | for ( unsigned long i = 0; i < m_tracks.size(); ++i ) 1342 | { 1343 | unsigned long subsong = 0; 1344 | if ( m_form == 2 ) subsong = i; 1345 | 1346 | const midi_track & track = m_tracks[ i ]; 1347 | for ( unsigned long j = 0; j < track.get_count(); ++j ) 1348 | { 1349 | const midi_event & event = track[ j ]; 1350 | if ( event.m_type == midi_event::control_change && 1351 | ( event.m_data[ 0 ] == 110 || event.m_data[ 0 ] == 111 ) ) 1352 | { 1353 | if ( event.m_data[ 0 ] == 110 ) 1354 | { 1355 | emidi_commands_found = true; 1356 | break; 1357 | } 1358 | { 1359 | if ( m_timestamp_loop_start[ subsong ] == ~0UL || m_timestamp_loop_start[ subsong ] > event.m_timestamp ) 1360 | { 1361 | m_timestamp_loop_start[ subsong ] = event.m_timestamp; 1362 | } 1363 | } 1364 | } 1365 | } 1366 | 1367 | if ( emidi_commands_found ) 1368 | { 1369 | m_timestamp_loop_start[ subsong ] = ~0UL; 1370 | m_timestamp_loop_end[ subsong ] = ~0UL; 1371 | break; 1372 | } 1373 | } 1374 | } 1375 | 1376 | if ( p_xmi_loops ) 1377 | { 1378 | for ( unsigned long i = 0; i < m_tracks.size(); ++i ) 1379 | { 1380 | unsigned long subsong = 0; 1381 | if ( m_form == 2 ) subsong = i; 1382 | 1383 | const midi_track & track = m_tracks[ i ]; 1384 | for ( unsigned long j = 0; j < track.get_count(); ++j ) 1385 | { 1386 | const midi_event & event = track[ j ]; 1387 | if ( event.m_type == midi_event::control_change && 1388 | ( event.m_data[ 0 ] >= 0x74 && event.m_data[ 0 ] <= 0x77 ) ) 1389 | { 1390 | if ( event.m_data[ 0 ] == 0x74 || event.m_data[ 0 ] == 0x76 ) 1391 | { 1392 | if ( m_timestamp_loop_start[ subsong ] == ~0UL || m_timestamp_loop_start[ subsong ] > event.m_timestamp ) 1393 | { 1394 | m_timestamp_loop_start[ subsong ] = event.m_timestamp; 1395 | } 1396 | } 1397 | else 1398 | { 1399 | if ( m_timestamp_loop_end[ subsong ] == ~0UL || m_timestamp_loop_end[ subsong ] < event.m_timestamp ) 1400 | { 1401 | m_timestamp_loop_end[ subsong ] = event.m_timestamp; 1402 | } 1403 | } 1404 | } 1405 | } 1406 | } 1407 | } 1408 | 1409 | if ( p_marker_loops ) 1410 | { 1411 | for ( unsigned long i = 0; i < m_tracks.size(); ++i ) 1412 | { 1413 | unsigned long subsong = 0; 1414 | if ( m_form == 2 ) subsong = i; 1415 | 1416 | const midi_track & track = m_tracks[ i ]; 1417 | for ( unsigned long j = 0; j < track.get_count(); ++j ) 1418 | { 1419 | const midi_event & event = track[ j ]; 1420 | if ( event.m_type == midi_event::extended && 1421 | event.get_data_count() >= 9 && 1422 | event.m_data[ 0 ] == 0xFF && event.m_data[ 1 ] == 0x06 ) 1423 | { 1424 | unsigned long data_count = event.get_data_count() - 2; 1425 | data.resize( data_count ); 1426 | event.copy_data( &data[0], 2, data_count ); 1427 | 1428 | if ( data_count == 9 && !strncasecmp( (const char *) &data[0], "loopStart", 9 ) ) 1429 | { 1430 | if ( m_timestamp_loop_start[ subsong ] == ~0UL || m_timestamp_loop_start[ subsong ] > event.m_timestamp ) 1431 | { 1432 | m_timestamp_loop_start[ subsong ] = event.m_timestamp; 1433 | } 1434 | } 1435 | else if ( data_count == 7 && !strncasecmp( (const char *) &data[0], "loopEnd", 7 ) ) 1436 | { 1437 | if ( m_timestamp_loop_end[ subsong ] == ~0UL || m_timestamp_loop_end[ subsong ] < event.m_timestamp ) 1438 | { 1439 | m_timestamp_loop_end[ subsong ] = event.m_timestamp; 1440 | } 1441 | } 1442 | } 1443 | } 1444 | } 1445 | } 1446 | 1447 | // Sanity 1448 | 1449 | for ( unsigned long i = 0; i < subsong_count; ++i ) 1450 | { 1451 | unsigned long timestamp_song_end; 1452 | if ( m_form == 2 ) 1453 | timestamp_song_end = m_tracks[i][m_tracks[i].get_count()-1].m_timestamp; 1454 | else 1455 | { 1456 | timestamp_song_end = 0; 1457 | for (unsigned long j = 0; j < m_tracks.size(); ++j) 1458 | { 1459 | const midi_track & track = m_tracks[j]; 1460 | unsigned long timestamp = track[track.get_count()-1].m_timestamp; 1461 | if (timestamp > timestamp_song_end) 1462 | timestamp_song_end = timestamp; 1463 | } 1464 | } 1465 | 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 ) ) ) 1466 | { 1467 | m_timestamp_loop_start[ i ] = ~0UL; 1468 | m_timestamp_loop_end[ i ] = ~0UL; 1469 | } 1470 | } 1471 | } 1472 | -------------------------------------------------------------------------------- /midi_container.h: -------------------------------------------------------------------------------- 1 | #ifndef _MIDI_CONTAINER_H_ 2 | #define _MIDI_CONTAINER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _MSC_VER 9 | #define strcasecmp _stricmp 10 | #define strncasecmp _strnicmp 11 | #define snprintf sprintf_s 12 | #endif 13 | 14 | struct midi_event 15 | { 16 | enum 17 | { 18 | max_static_data_count = 16 19 | }; 20 | 21 | enum event_type 22 | { 23 | note_off = 0, 24 | note_on, 25 | polyphonic_aftertouch, 26 | control_change, 27 | program_change, 28 | channel_aftertouch, 29 | pitch_wheel, 30 | extended 31 | }; 32 | 33 | unsigned long m_timestamp; 34 | 35 | event_type m_type; 36 | unsigned m_channel; 37 | unsigned long m_data_count; 38 | uint8_t m_data[max_static_data_count]; 39 | std::vector m_ext_data; 40 | 41 | midi_event() : m_timestamp(0), m_type(note_off), m_channel(0), m_data_count(0) { } 42 | midi_event( const midi_event & p_in ); 43 | midi_event( unsigned long p_timestamp, event_type p_type, unsigned p_channel, const uint8_t * p_data, std::size_t p_data_count ); 44 | 45 | unsigned long get_data_count() const; 46 | void copy_data( uint8_t * p_out, unsigned long p_offset, unsigned long p_count ) const; 47 | }; 48 | 49 | class midi_track 50 | { 51 | std::vector m_events; 52 | 53 | public: 54 | midi_track() { } 55 | midi_track(const midi_track & p_in); 56 | 57 | void add_event( const midi_event & p_event ); 58 | std::size_t get_count() const; 59 | const midi_event & operator [] ( std::size_t p_index ) const; 60 | midi_event & operator [] ( std::size_t p_index ); 61 | 62 | void remove_event( unsigned long index ); 63 | }; 64 | 65 | struct tempo_entry 66 | { 67 | unsigned long m_timestamp; 68 | unsigned m_tempo; 69 | 70 | tempo_entry() : m_timestamp(0), m_tempo(0) { } 71 | tempo_entry(unsigned long p_timestamp, unsigned p_tempo); 72 | }; 73 | 74 | class tempo_map 75 | { 76 | std::vector m_entries; 77 | 78 | public: 79 | void add_tempo( unsigned p_tempo, unsigned long p_timestamp ); 80 | unsigned long timestamp_to_ms( unsigned long p_timestamp, unsigned p_dtx ) const; 81 | 82 | std::size_t get_count() const; 83 | const tempo_entry & operator [] ( std::size_t p_index ) const; 84 | tempo_entry & operator [] ( std::size_t p_index ); 85 | }; 86 | 87 | struct system_exclusive_entry 88 | { 89 | std::size_t m_port; 90 | std::size_t m_offset; 91 | std::size_t m_length; 92 | system_exclusive_entry() : m_port(0), m_offset(0), m_length(0) { } 93 | system_exclusive_entry(const system_exclusive_entry & p_in); 94 | system_exclusive_entry(std::size_t p_port, std::size_t p_offset, std::size_t p_length); 95 | }; 96 | 97 | class system_exclusive_table 98 | { 99 | std::vector m_data; 100 | std::vector m_entries; 101 | 102 | public: 103 | unsigned add_entry( const uint8_t * p_data, std::size_t p_size, std::size_t p_port ); 104 | void get_entry( unsigned p_index, const uint8_t * & p_data, std::size_t & p_size, std::size_t & p_port ); 105 | }; 106 | 107 | struct midi_stream_event 108 | { 109 | unsigned long m_timestamp; 110 | uint32_t m_event; 111 | 112 | midi_stream_event() : m_timestamp(0), m_event(0) { } 113 | midi_stream_event(unsigned long p_timestamp, uint32_t p_event); 114 | }; 115 | 116 | struct midi_meta_data_item 117 | { 118 | unsigned long m_timestamp; 119 | std::string m_name; 120 | std::string m_value; 121 | 122 | midi_meta_data_item() : m_timestamp(0) { } 123 | midi_meta_data_item(const midi_meta_data_item & p_in); 124 | midi_meta_data_item(unsigned long p_timestamp, const char * p_name, const char * p_value); 125 | }; 126 | 127 | class midi_meta_data 128 | { 129 | std::vector m_data; 130 | std::vector m_bitmap; 131 | 132 | public: 133 | midi_meta_data() { } 134 | 135 | void add_item( const midi_meta_data_item & p_item ); 136 | 137 | void append( const midi_meta_data & p_data ); 138 | 139 | bool get_item( const char * p_name, midi_meta_data_item & p_out ) const; 140 | 141 | bool get_bitmap( std::vector & p_out ); 142 | 143 | void assign_bitmap( std::vector::const_iterator const& begin, std::vector::const_iterator const& end ); 144 | 145 | std::size_t get_count() const; 146 | 147 | const midi_meta_data_item & operator [] ( std::size_t p_index ) const; 148 | }; 149 | 150 | class midi_container 151 | { 152 | public: 153 | enum 154 | { 155 | clean_flag_emidi = 1 << 0, 156 | clean_flag_instruments = 1 << 1, 157 | clean_flag_banks = 1 << 2, 158 | }; 159 | 160 | private: 161 | unsigned m_form; 162 | unsigned m_dtx; 163 | std::vector m_channel_mask; 164 | std::vector m_tempo_map; 165 | std::vector m_tracks; 166 | 167 | std::vector m_port_numbers; 168 | 169 | std::vector< std::vector< std::string > > m_device_names; 170 | 171 | midi_meta_data m_extra_meta_data; 172 | 173 | std::vector m_timestamp_end; 174 | 175 | std::vector m_timestamp_loop_start; 176 | std::vector m_timestamp_loop_end; 177 | 178 | unsigned long timestamp_to_ms( unsigned long p_timestamp, unsigned long p_subsong ) const; 179 | 180 | /* 181 | * Normalize port numbers properly 182 | */ 183 | template void limit_port_number(T & number) 184 | { 185 | for ( unsigned i = 0; i < m_port_numbers.size(); i++ ) 186 | { 187 | if ( m_port_numbers[ i ] == number ) 188 | { 189 | number = i; 190 | return; 191 | } 192 | } 193 | m_port_numbers.push_back( (const uint8_t) number ); 194 | number = m_port_numbers.size() - 1; 195 | } 196 | 197 | template void limit_port_number(T & number) const 198 | { 199 | for ( unsigned i = 0; i < m_port_numbers.size(); i++ ) 200 | { 201 | if ( m_port_numbers[ i ] == number ) 202 | { 203 | number = i; 204 | return; 205 | } 206 | } 207 | } 208 | 209 | midi_track demote_to_form_0() const; 210 | 211 | public: 212 | midi_container() { m_device_names.resize( 16 ); } 213 | 214 | void initialize( unsigned p_form, unsigned p_dtx ); 215 | 216 | void add_track( const midi_track & p_track ); 217 | 218 | void add_track_event( std::size_t p_track_index, const midi_event & p_event ); 219 | 220 | /* 221 | * These functions are really only designed to merge and later remove System Exclusive message dumps 222 | */ 223 | void merge_tracks( const midi_container & p_source ); 224 | void set_track_count( unsigned count ); 225 | void set_extra_meta_data( const midi_meta_data & p_data ); 226 | 227 | /* 228 | * Blah. 229 | * Hack 0: Remove channel 16 230 | * Hack 1: Remove channels 11-16 231 | */ 232 | void apply_hackfix( unsigned hack ); 233 | 234 | void serialize_as_stream( unsigned long subsong, std::vector & p_stream, system_exclusive_table & p_system_exclusive, unsigned long & loop_start, unsigned long & loop_end, unsigned clean_flags ) const; 235 | 236 | void serialize_as_standard_midi_file( std::vector & p_midi_file ) const; 237 | 238 | void promote_to_form_1(); 239 | 240 | void trim_start(); 241 | 242 | private: 243 | void trim_range_of_tracks(unsigned long start, unsigned long end); 244 | void trim_tempo_map(unsigned long p_index, unsigned long base_timestamp); 245 | 246 | public: 247 | typedef std::string(*split_callback)(uint8_t bank_msb, uint8_t bank_lsb, uint8_t instrument); 248 | 249 | void split_by_instrument_changes(split_callback cb = NULL); 250 | 251 | unsigned long get_subsong_count() const; 252 | unsigned long get_subsong( unsigned long p_index ) const; 253 | 254 | unsigned long get_timestamp_end(unsigned long subsong, bool ms = false) const; 255 | 256 | unsigned get_format() const; 257 | unsigned get_track_count() const; 258 | unsigned get_channel_count(unsigned long subsong) const; 259 | 260 | unsigned long get_timestamp_loop_start(unsigned long subsong, bool ms = false) const; 261 | unsigned long get_timestamp_loop_end(unsigned long subsong, bool ms = false) const; 262 | 263 | void get_meta_data( unsigned long subsong, midi_meta_data & p_out ); 264 | 265 | void scan_for_loops( bool p_xmi_loops, bool p_marker_loops, bool p_rpgmaker_loops, bool p_touhou_loops ); 266 | 267 | static void encode_delta( std::vector & p_out, unsigned long delta ); 268 | }; 269 | 270 | #endif 271 | -------------------------------------------------------------------------------- /midi_processing.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2012-12-24T22:18:46 4 | # 5 | #------------------------------------------------- 6 | 7 | CONFIG -= qt 8 | 9 | TARGET = midi_processing 10 | TEMPLATE = lib 11 | CONFIG += staticlib 12 | 13 | QMAKE_CXXFLAGS += -std=c++0x 14 | macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.7 -stdlib=libc++ 15 | 16 | SOURCES += \ 17 | midi_processor_xmi.cpp \ 18 | midi_processor_syx.cpp \ 19 | midi_processor_standard_midi.cpp \ 20 | midi_processor_riff_midi.cpp \ 21 | midi_processor_mus.cpp \ 22 | midi_processor_mids.cpp \ 23 | midi_processor_lds.cpp \ 24 | midi_processor_hmp.cpp \ 25 | midi_processor_hmi.cpp \ 26 | midi_processor_helpers.cpp \ 27 | midi_processor_gmf.cpp \ 28 | midi_container.cpp 29 | 30 | HEADERS += \ 31 | midi_processor.h \ 32 | midi_container.h 33 | unix:!symbian { 34 | maemo5 { 35 | target.path = /opt/usr/lib 36 | } else { 37 | target.path = /usr/lib 38 | } 39 | INSTALLS += target 40 | } 41 | -------------------------------------------------------------------------------- /midi_processing.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {4573E081-973B-47F0-A67D-551761BA1678} 33 | Win32Proj 34 | midi_processing 35 | 10.0 36 | 37 | 38 | 39 | StaticLibrary 40 | true 41 | v142 42 | Unicode 43 | 44 | 45 | StaticLibrary 46 | false 47 | v142 48 | Unicode 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Level3 66 | Disabled 67 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 68 | MultiThreadedDebugDLL 69 | StreamingSIMDExtensions2 70 | 71 | 72 | Windows 73 | true 74 | 75 | 76 | 77 | 78 | Level3 79 | 80 | 81 | MaxSpeed 82 | true 83 | true 84 | _WIN32_WINNT=0x501;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 85 | MultiThreadedDLL 86 | Fast 87 | StreamingSIMDExtensions2 88 | 89 | 90 | 91 | 92 | Windows 93 | true 94 | true 95 | true 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /midi_processing.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | 52 | 53 | Header Files 54 | 55 | 56 | Header Files 57 | 58 | 59 | -------------------------------------------------------------------------------- /midi_processor.h: -------------------------------------------------------------------------------- 1 | #ifndef _MIDI_PROCESSORS_H_ 2 | #define _MIDI_PROCESSORS_H_ 3 | 4 | #include "midi_container.h" 5 | 6 | #ifndef _countof 7 | template 8 | char ( &_ArraySizeHelper( T (&array)[N] ))[N]; 9 | #define _countof( array ) (sizeof( _ArraySizeHelper( array ) )) 10 | #endif 11 | 12 | class midi_processor 13 | { 14 | static const uint8_t end_of_track[2]; 15 | static const uint8_t loop_start[11]; 16 | static const uint8_t loop_end[9]; 17 | 18 | static const uint8_t hmp_default_tempo[5]; 19 | 20 | static const uint8_t xmi_default_tempo[5]; 21 | 22 | static const uint8_t mus_default_tempo[5]; 23 | static const uint8_t mus_controllers[15]; 24 | 25 | static const uint8_t lds_default_tempo[5]; 26 | 27 | static int decode_delta( std::vector::const_iterator & it, std::vector::const_iterator end ); 28 | static unsigned decode_hmp_delta( std::vector::const_iterator & it, std::vector::const_iterator end ); 29 | static unsigned decode_xmi_delta( std::vector::const_iterator & it, std::vector::const_iterator end ); 30 | 31 | static bool is_standard_midi( std::vector const& p_file ); 32 | static bool is_riff_midi( std::vector const& p_file ); 33 | static bool is_hmp( std::vector const& p_file ); 34 | static bool is_hmi( std::vector const& p_file ); 35 | static bool is_xmi( std::vector const& p_file ); 36 | static bool is_mus( std::vector const& p_file ); 37 | static bool is_mids( std::vector const& p_file ); 38 | static bool is_lds( std::vector const& p_file, const char * p_extension ); 39 | static bool is_gmf( std::vector const& p_file ); 40 | static bool is_syx( std::vector const& p_file ); 41 | 42 | static void process_standard_midi_track( std::vector::const_iterator & it, std::vector::const_iterator end, midi_container & p_out, bool is_gmf ); 43 | 44 | static bool process_standard_midi( std::vector const& p_file, midi_container & p_out ); 45 | static bool process_riff_midi( std::vector const& p_file, midi_container & p_out ); 46 | static bool process_hmp( std::vector const& p_file, midi_container & p_out ); 47 | static bool process_hmi( std::vector const& p_file, midi_container & p_out ); 48 | static bool process_xmi( std::vector const& p_file, midi_container & p_out ); 49 | static bool process_mus( std::vector const& p_file, midi_container & p_out ); 50 | static bool process_mids( std::vector const& p_file, midi_container & p_out ); 51 | static bool process_lds( std::vector const& p_file, midi_container & p_out ); 52 | static bool process_gmf( std::vector const& p_file, midi_container & p_out ); 53 | static bool process_syx( std::vector const& p_file, midi_container & p_out ); 54 | 55 | static bool process_standard_midi_count( std::vector const& p_file, size_t & track_count ); 56 | static bool process_riff_midi_count( std::vector const& p_file, size_t & track_count ); 57 | static bool process_xmi_count( std::vector const& p_file, size_t & track_count ); 58 | 59 | public: 60 | static bool process_track_count( std::vector const& p_file, const char * p_extension, size_t & track_count ); 61 | 62 | static bool process_file( std::vector const& p_file, const char * p_extension, midi_container & p_out ); 63 | 64 | static bool process_syx_file( std::vector const& p_file, midi_container & p_out ); 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /midi_processor_gmf.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | bool midi_processor::is_gmf( std::vector const& p_file ) 4 | { 5 | if ( p_file.size() < 32 ) return false; 6 | if ( p_file[ 0 ] != 'G' || p_file[ 1 ] != 'M' || p_file[ 2 ] != 'F' || p_file[ 3 ] != 1 ) return false; 7 | return true; 8 | } 9 | 10 | bool midi_processor::process_gmf( std::vector const& p_file, midi_container & p_out ) 11 | { 12 | uint8_t buffer[10]; 13 | 14 | p_out.initialize( 0, 0xC0 ); 15 | 16 | uint16_t tempo = ( p_file[ 4 ] << 8 ) | p_file[ 5 ]; 17 | uint32_t tempo_scaled = tempo * 100000; 18 | 19 | midi_track track; 20 | 21 | buffer[0] = 0xFF; 22 | buffer[1] = 0x51; 23 | buffer[2] = tempo_scaled >> 16; 24 | buffer[3] = tempo_scaled >> 8; 25 | buffer[4] = tempo_scaled; 26 | 27 | track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 5 ) ); 28 | 29 | buffer[0] = 0xF0; 30 | buffer[1] = 0x41; 31 | buffer[2] = 0x10; 32 | buffer[3] = 0x16; 33 | buffer[4] = 0x12; 34 | buffer[5] = 0x7F; 35 | buffer[6] = 0x00; 36 | buffer[7] = 0x00; 37 | buffer[8] = 0x01; 38 | buffer[9] = 0xF7; 39 | 40 | track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 10 ) ); 41 | 42 | buffer[0] = 0xFF; 43 | buffer[1] = 0x2F; 44 | 45 | track.add_event( midi_event( 0, midi_event::extended, 0, buffer, 2 ) ); 46 | 47 | p_out.add_track( track ); 48 | 49 | std::vector::const_iterator it = p_file.begin() + 7; 50 | 51 | process_standard_midi_track( it, p_file.end(), p_out, true ); 52 | 53 | return true; 54 | } 55 | -------------------------------------------------------------------------------- /midi_processor_helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | const uint8_t midi_processor::end_of_track[2] = {0xFF, 0x2F}; 4 | const uint8_t midi_processor::loop_start[11] = {0xFF, 0x06, 'l', 'o', 'o', 'p', 'S', 't', 'a', 'r', 't'}; 5 | const uint8_t midi_processor::loop_end[9] = {0xFF, 0x06, 'l', 'o', 'o', 'p', 'E', 'n', 'd'}; 6 | 7 | int midi_processor::decode_delta( std::vector::const_iterator & it, std::vector::const_iterator end ) 8 | { 9 | int delta = 0; 10 | unsigned char byte; 11 | do 12 | { 13 | if ( it == end ) return 0; 14 | byte = *it++; 15 | delta = ( delta << 7 ) + ( byte & 0x7F ); 16 | } 17 | while ( byte & 0x80 ); 18 | return delta; 19 | } 20 | 21 | bool midi_processor::process_file( std::vector const& p_file, const char * p_extension, midi_container & p_out ) 22 | { 23 | if ( is_standard_midi( p_file ) ) 24 | { 25 | return process_standard_midi( p_file, p_out ); 26 | } 27 | else if ( is_riff_midi( p_file ) ) 28 | { 29 | return process_riff_midi( p_file, p_out ); 30 | } 31 | else if ( is_hmp( p_file ) ) 32 | { 33 | return process_hmp( p_file, p_out ); 34 | } 35 | else if ( is_hmi( p_file ) ) 36 | { 37 | return process_hmi( p_file, p_out ); 38 | } 39 | else if ( is_xmi( p_file ) ) 40 | { 41 | return process_xmi( p_file, p_out ); 42 | } 43 | else if ( is_mus( p_file ) ) 44 | { 45 | return process_mus( p_file, p_out ); 46 | } 47 | else if ( is_mids( p_file ) ) 48 | { 49 | return process_mids( p_file, p_out ); 50 | } 51 | else if ( is_lds( p_file, p_extension ) ) 52 | { 53 | return process_lds( p_file, p_out ); 54 | } 55 | else if ( is_gmf( p_file ) ) 56 | { 57 | return process_gmf( p_file, p_out ); 58 | } 59 | else return false; 60 | } 61 | 62 | bool midi_processor::process_syx_file( std::vector const& p_file, midi_container & p_out ) 63 | { 64 | if ( is_syx( p_file ) ) 65 | { 66 | return process_syx( p_file, p_out ); 67 | } 68 | else return false; 69 | } 70 | 71 | bool midi_processor::process_track_count( std::vector const& p_file, const char * p_extension, size_t & track_count ) 72 | { 73 | track_count = 0; 74 | 75 | if ( is_standard_midi( p_file ) ) 76 | { 77 | return process_standard_midi_count( p_file, track_count ); 78 | } 79 | else if ( is_riff_midi( p_file ) ) 80 | { 81 | return process_riff_midi_count( p_file, track_count ); 82 | } 83 | else if ( is_hmp( p_file ) ) 84 | { 85 | track_count = 1; 86 | return true; 87 | } 88 | else if ( is_hmi( p_file ) ) 89 | { 90 | track_count = 1; 91 | return true; 92 | } 93 | else if ( is_xmi( p_file ) ) 94 | { 95 | return process_xmi_count( p_file, track_count ); 96 | } 97 | else if ( is_mus( p_file ) ) 98 | { 99 | track_count = 1; 100 | return true; 101 | } 102 | else if ( is_mids( p_file ) ) 103 | { 104 | track_count = 1; 105 | return true; 106 | } 107 | else if ( is_lds( p_file, p_extension ) ) 108 | { 109 | track_count = 1; 110 | return true; 111 | } 112 | else if ( is_gmf( p_file ) ) 113 | { 114 | track_count = 1; 115 | return true; 116 | } 117 | else return false; 118 | } 119 | -------------------------------------------------------------------------------- /midi_processor_hmi.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | bool midi_processor::is_hmi( std::vector const& p_file ) 4 | { 5 | if ( p_file.size() < 12 ) return false; 6 | if ( p_file[ 0 ] != 'H' || p_file[ 1 ] != 'M' || p_file[ 2 ] != 'I' || p_file[ 3 ] != '-' || 7 | p_file[ 4 ] != 'M' || p_file[ 5 ] != 'I' || p_file[ 6 ] != 'D' || p_file[ 7 ] != 'I' || 8 | p_file[ 8 ] != 'S' || p_file[ 9 ] != 'O' || p_file[ 10 ] != 'N' || p_file[ 11 ] != 'G' ) return false; 9 | return true; 10 | } 11 | 12 | bool midi_processor::process_hmi( std::vector const& p_file, midi_container & p_out ) 13 | { 14 | std::vector buffer; 15 | 16 | std::vector::const_iterator it = p_file.begin() + 0xE4; 17 | 18 | uint32_t track_count = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 19 | uint32_t track_table_offset = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); 20 | 21 | if ( track_table_offset >= p_file.size() || track_table_offset + track_count * 4 > p_file.size() ) 22 | return false; 23 | 24 | it = p_file.begin() + track_table_offset; 25 | 26 | std::vector track_offsets; 27 | track_offsets.resize( track_count ); 28 | 29 | for ( unsigned i = 0; i < track_count; ++i ) 30 | { 31 | track_offsets[ i ] = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 32 | it += 4; 33 | } 34 | 35 | p_out.initialize( 1, 0xC0 ); 36 | 37 | { 38 | midi_track track; 39 | track.add_event( midi_event( 0, midi_event::extended, 0, hmp_default_tempo, _countof( hmp_default_tempo ) ) ); 40 | track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 41 | p_out.add_track( track ); 42 | } 43 | 44 | for ( unsigned i = 0; i < track_count; ++i ) 45 | { 46 | unsigned track_offset = track_offsets[ i ]; 47 | unsigned long track_length; 48 | if ( i + 1 < track_count ) 49 | { 50 | track_length = track_offsets[ i + 1 ] - track_offset; 51 | } 52 | else 53 | { 54 | track_length = p_file.size() - track_offset; 55 | } 56 | if ( track_offset >= p_file.size() || track_offset + track_length > p_file.size() ) 57 | return false; 58 | 59 | std::vector::const_iterator track_body = p_file.begin() + track_offset; 60 | std::vector::const_iterator track_end = track_body + track_length; 61 | 62 | if ( track_length < 13 ) return false; 63 | if ( track_body[ 0 ] != 'H' || track_body[ 1 ] != 'M' || track_body[ 2 ] != 'I' || track_body[ 3 ] != '-' || 64 | track_body[ 4 ] != 'M' || track_body[ 5 ] != 'I' || track_body[ 6 ] != 'D' || track_body[ 7 ] != 'I' || 65 | track_body[ 8 ] != 'T' || track_body[ 9 ] != 'R' || track_body[ 10 ] != 'A' || track_body[ 11 ] != 'C' || 66 | track_body[ 12 ] != 'K' ) return false; 67 | 68 | midi_track track; 69 | unsigned current_timestamp = 0; 70 | unsigned char last_event_code = 0xFF; 71 | 72 | unsigned last_event_timestamp = 0; 73 | 74 | if ( track_length < 0x4B + 4 ) return false; 75 | 76 | uint32_t meta_offset = track_body[ 0x4B ] | ( track_body[ 0x4C ] << 8 ) | ( track_body[ 0x4D ] << 16 ) | ( track_body[ 0x4E ] << 24 ); 77 | if ( meta_offset && meta_offset + 1 < track_length ) 78 | { 79 | buffer.resize( 2 ); 80 | std::copy( track_body + meta_offset, track_body + meta_offset + 2, buffer.begin() ); 81 | unsigned meta_size = buffer[ 1 ]; 82 | if ( meta_offset + 2 + meta_size > track_length ) return false; 83 | buffer.resize( meta_size + 2 ); 84 | std::copy( track_body + meta_offset + 2, track_body + meta_offset + 2 + meta_size, buffer.begin() + 2 ); 85 | while ( meta_size > 0 && buffer[ meta_size + 1 ] == ' ' ) --meta_size; 86 | if ( meta_size > 0 ) 87 | { 88 | buffer[ 0 ] = 0xFF; 89 | buffer[ 1 ] = 0x01; 90 | track.add_event( midi_event( 0, midi_event::extended, 0, &buffer[0], meta_size + 2 ) ); 91 | } 92 | } 93 | 94 | if ( track_length < 0x57 + 4 ) return false; 95 | 96 | uint32_t track_data_offset = track_body[ 0x57 ] | ( track_body[ 0x58 ] << 8 ) | ( track_body[ 0x59 ] << 16 ) | ( track_body[ 0x5A ] << 24 ); 97 | 98 | it = track_body + track_data_offset; 99 | 100 | buffer.resize( 3 ); 101 | 102 | while ( it != track_end ) 103 | { 104 | int delta = decode_delta( it, track_end ); 105 | if ( delta > 0xFFFF || delta < 0 ) 106 | { 107 | current_timestamp = last_event_timestamp; 108 | /*console::formatter() << "[foo_midi] Large HMI delta detected, shunting.";*/ 109 | } 110 | else 111 | { 112 | current_timestamp += delta; 113 | if ( current_timestamp > last_event_timestamp ) 114 | { 115 | last_event_timestamp = current_timestamp; 116 | } 117 | } 118 | 119 | if ( it == track_end ) return false; 120 | buffer[ 0 ] = *it++; 121 | if ( buffer[ 0 ] == 0xFF ) 122 | { 123 | last_event_code = 0xFF; 124 | if ( it == track_end ) return false; 125 | buffer[ 1 ] = *it++; 126 | int meta_count = decode_delta( it, track_end ); 127 | if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid HMI meta message" );*/ 128 | if ( track_end - it < meta_count ) return false; 129 | buffer.resize( meta_count + 2 ); 130 | std::copy( it, it + meta_count, buffer.begin() + 2 ); 131 | it += meta_count; 132 | if ( buffer[ 1 ] == 0x2F && last_event_timestamp > current_timestamp ) 133 | { 134 | current_timestamp = last_event_timestamp; 135 | } 136 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], meta_count + 2 ) ); 137 | if ( buffer[ 1 ] == 0x2F ) break; 138 | } 139 | else if ( buffer[ 0 ] == 0xF0 ) 140 | { 141 | last_event_code = 0xFF; 142 | int system_exclusive_count = decode_delta( it, track_end ); 143 | if ( system_exclusive_count < 0 ) return false; /*throw exception_io_data( "Invalid HMI System Exclusive message" );*/ 144 | if ( track_end - it < system_exclusive_count ) return false; 145 | buffer.resize( system_exclusive_count + 1 ); 146 | std::copy( it, it + system_exclusive_count, buffer.begin() + 1 ); 147 | it += system_exclusive_count; 148 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], system_exclusive_count + 1 ) ); 149 | } 150 | else if ( buffer[ 0 ] == 0xFE ) 151 | { 152 | last_event_code = 0xFF; 153 | if ( it == track_end ) return false; 154 | buffer[ 1 ] = *it++; 155 | if ( buffer[ 1 ] == 0x10 ) 156 | { 157 | if ( track_end - it < 3 ) return false; 158 | it += 2; 159 | buffer[ 2 ] = *it++; 160 | if ( track_end - it < buffer[ 2 ] + 4 ) return false; 161 | it += buffer[ 2 ] + 4; 162 | } 163 | else if ( buffer[ 1 ] == 0x12 ) 164 | { 165 | if ( track_end - it < 2 ) return false; 166 | it += 2; 167 | } 168 | else if ( buffer[ 1 ] == 0x13 ) 169 | { 170 | if ( track_end - it < 10 ) return false; 171 | it += 10; 172 | } 173 | else if ( buffer[ 1 ] == 0x14 ) 174 | { 175 | if ( track_end - it < 2 ) return false; 176 | it += 2; 177 | p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); 178 | } 179 | else if ( buffer[ 1 ] == 0x15 ) 180 | { 181 | if ( track_end - it < 6 ) return false; 182 | it += 6; 183 | p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); 184 | } 185 | else return false; /*throw exception_io_data( "Unexpected HMI meta event" );*/ 186 | } 187 | else if ( buffer[ 0 ] <= 0xEF ) 188 | { 189 | unsigned bytes_read = 1; 190 | if ( buffer[ 0 ] >= 0x80 ) 191 | { 192 | if ( it == track_end ) return false; 193 | buffer[ 1 ] = *it++; 194 | last_event_code = buffer[ 0 ]; 195 | } 196 | else 197 | { 198 | if ( last_event_code == 0xFF ) return false; /*throw exception_io_data( "HMI used shortened event after Meta or SysEx message" );*/ 199 | buffer[ 1 ] = buffer[ 0 ]; 200 | buffer[ 0 ] = last_event_code; 201 | } 202 | midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); 203 | unsigned channel = buffer[ 0 ] & 0x0F; 204 | if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) 205 | { 206 | if ( it == track_end ) return false; 207 | buffer[ 2 ] = *it++; 208 | bytes_read = 2; 209 | } 210 | track.add_event( midi_event( current_timestamp, type, channel, &buffer[ 1 ], bytes_read ) ); 211 | if ( type == midi_event::note_on ) 212 | { 213 | buffer[ 2 ] = 0x00; 214 | int note_length = decode_delta( it, track_end ); 215 | if ( note_length < 0 ) return false; /*throw exception_io_data( "Invalid HMI note message" );*/ 216 | unsigned note_end_timestamp = current_timestamp + note_length; 217 | if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; 218 | track.add_event( midi_event( note_end_timestamp, midi_event::note_on, channel, &buffer[1], bytes_read ) ); 219 | } 220 | } 221 | else return false; /*throw exception_io_data( "Unexpected HMI status code" );*/ 222 | } 223 | 224 | p_out.add_track( track ); 225 | } 226 | 227 | return true; 228 | } 229 | -------------------------------------------------------------------------------- /midi_processor_hmp.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | const uint8_t midi_processor::hmp_default_tempo[5] = {0xFF, 0x51, 0x18, 0x80, 0x00}; 4 | 5 | bool midi_processor::is_hmp( std::vector const& p_file ) 6 | { 7 | if ( p_file.size() < 8 ) return false; 8 | if ( p_file[ 0 ] != 'H' || p_file[ 1 ] != 'M' || p_file[ 2 ] != 'I' || p_file[ 3 ] != 'M' || 9 | p_file[ 4 ] != 'I' || p_file[ 5 ] != 'D' || p_file[ 6 ] != 'I' || 10 | ( p_file[ 7 ] != 'P' && p_file[ 7 ] != 'R' ) ) return false; 11 | return true; 12 | } 13 | 14 | unsigned midi_processor::decode_hmp_delta( std::vector::const_iterator & it, std::vector::const_iterator end ) 15 | { 16 | unsigned delta = 0; 17 | unsigned shift = 0; 18 | unsigned char byte; 19 | do 20 | { 21 | if ( it == end ) return 0; 22 | byte = *it++; 23 | delta = delta + ( ( byte & 0x7F ) << shift ); 24 | shift += 7; 25 | } 26 | while ( !( byte & 0x80 ) ); 27 | return delta; 28 | } 29 | 30 | bool midi_processor::process_hmp( std::vector const& p_file, midi_container & p_out ) 31 | { 32 | bool is_funky = p_file[ 7 ] == 'R'; 33 | 34 | uint8_t track_count_8; 35 | uint16_t dtx = 0xC0; 36 | 37 | uint32_t offset = is_funky ? 0x1A : 0x30; 38 | 39 | if ( offset >= p_file.size() ) 40 | return false; 41 | 42 | std::vector::const_iterator it = p_file.begin() + offset; 43 | std::vector::const_iterator end = p_file.end(); 44 | 45 | track_count_8 = *it; 46 | 47 | if ( is_funky ) 48 | { 49 | if ( p_file.size() <= 0x4D ) 50 | return false; 51 | dtx = ( p_file[ 0x4C ] << 16 ) | p_file[ 0x4D ]; 52 | if ( !dtx ) // dtx == 0, will cause division by zero on tempo calculations 53 | return false; 54 | } 55 | 56 | p_out.initialize( 1, dtx ); 57 | 58 | { 59 | midi_track track; 60 | track.add_event( midi_event( 0, midi_event::extended, 0, hmp_default_tempo, _countof( hmp_default_tempo ) ) ); 61 | track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 62 | p_out.add_track( track ); 63 | } 64 | 65 | uint8_t buffer[ 4 ]; 66 | 67 | if ( it == end ) return false; 68 | buffer[ 0 ] = *it++; 69 | 70 | while ( it != end ) 71 | { 72 | if ( buffer[ 0 ] != 0xFF ) 73 | { 74 | buffer[ 0 ] = *it++; 75 | continue; 76 | } 77 | if ( it == end ) break; 78 | buffer[ 1 ] = *it++; 79 | if ( buffer[ 1 ] != 0x2F ) 80 | { 81 | buffer[ 0 ] = buffer[ 1 ]; 82 | continue; 83 | } 84 | break; 85 | } 86 | 87 | offset = is_funky ? 3 : 5; 88 | if ( (unsigned long)(end - it) < offset ) return false; 89 | it += offset; 90 | 91 | unsigned track_count = track_count_8; 92 | 93 | for ( unsigned i = 1; i < track_count; ++i ) 94 | { 95 | uint16_t track_size_16; 96 | uint32_t track_size_32; 97 | 98 | if ( is_funky ) 99 | { 100 | if ( end - it < 4 ) break; 101 | track_size_16 = it[ 0 ] | ( it[ 1 ] << 8 ); 102 | it += 2; 103 | track_size_32 = track_size_16 - 4; 104 | if ( (unsigned long)(end - it) < track_size_32 + 2 ) break; 105 | it += 2; 106 | } 107 | else 108 | { 109 | if ( end - it < 8 ) break; 110 | track_size_32 = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 111 | it += 4; 112 | track_size_32 -= 12; 113 | if ( (unsigned long)(end - it) < track_size_32 + 8 ) break; 114 | it += 4; 115 | } 116 | 117 | midi_track track; 118 | 119 | unsigned current_timestamp = 0; 120 | 121 | std::vector _buffer; 122 | _buffer.resize( 3 ); 123 | 124 | std::vector::const_iterator track_end = it + track_size_32; 125 | 126 | while ( it != track_end ) 127 | { 128 | unsigned delta = decode_hmp_delta( it, track_end ); 129 | current_timestamp += delta; 130 | if ( it == track_end ) return false; 131 | _buffer[ 0 ] = *it++; 132 | if ( _buffer[ 0 ] == 0xFF ) 133 | { 134 | if ( it == track_end ) return false; 135 | _buffer[ 1 ] = *it++; 136 | int meta_count = decode_delta( it, track_end ); 137 | if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid HMP meta message" );*/ 138 | if ( track_end - it < meta_count ) return false; 139 | _buffer.resize( meta_count + 2 ); 140 | std::copy( it, it + meta_count, _buffer.begin() + 2 ); 141 | it += meta_count; 142 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &_buffer[0], meta_count + 2 ) ); 143 | if ( _buffer[ 1 ] == 0x2F ) break; 144 | } 145 | else if ( _buffer[ 0 ] >= 0x80 && _buffer[ 0 ] <= 0xEF ) 146 | { 147 | unsigned bytes_read = 2; 148 | switch ( _buffer[ 0 ] & 0xF0 ) 149 | { 150 | case 0xC0: 151 | case 0xD0: 152 | bytes_read = 1; 153 | } 154 | if ( (unsigned long)(track_end - it) < bytes_read ) return false; 155 | std::copy( it, it + bytes_read, _buffer.begin() + 1 ); 156 | it += bytes_read; 157 | track.add_event( midi_event( current_timestamp, (midi_event::event_type)( ( _buffer[ 0 ] >> 4 ) - 8 ), _buffer[ 0 ] & 0x0F, &_buffer[1], bytes_read ) ); 158 | } 159 | else return false; /*throw exception_io_data( "Unexpected status code in HMP track" );*/ 160 | } 161 | 162 | offset = is_funky ? 0 : 4; 163 | if ( end - it < (signed long)offset ) return false; 164 | it = track_end + offset; 165 | 166 | p_out.add_track( track ); 167 | } 168 | 169 | return true; 170 | } 171 | -------------------------------------------------------------------------------- /midi_processor_lds.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | #include 4 | 5 | const uint8_t midi_processor::lds_default_tempo[5] = { 0xFF, 0x51, 0x07, 0xA1, 0x20 }; 6 | 7 | #define ENABLE_WHEEL 8 | //#define ENABLE_VIB 9 | //#define ENABLE_ARP 10 | //#define ENABLE_TREM 11 | 12 | #ifdef ENABLE_WHEEL 13 | #define WHEEL_RANGE_HIGH 12 14 | #define WHEEL_RANGE_LOW 0 15 | #define WHEEL_SCALE(x) ((x) * 512 / WHEEL_RANGE_HIGH) 16 | #define WHEEL_SCALE_LOW(x) (WHEEL_SCALE(x) & 127) 17 | #define WHEEL_SCALE_HIGH(x) (((WHEEL_SCALE(x) >> 7) + 64) & 127) 18 | #endif 19 | 20 | #ifdef ENABLE_VIB 21 | // Vibrato (sine) table 22 | static const unsigned char vibtab[] = { 23 | 0, 13, 25, 37, 50, 62, 74, 86, 98, 109, 120, 131, 142, 152, 162, 24 | 171, 180, 189, 197, 205, 212, 219, 225, 231, 236, 240, 244, 247, 25 | 250, 252, 254, 255, 255, 255, 254, 252, 250, 247, 244, 240, 236, 26 | 231, 225, 219, 212, 205, 197, 189, 180, 171, 162, 152, 142, 131, 27 | 120, 109, 98, 86, 74, 62, 50, 37, 25, 13 28 | }; 29 | #endif 30 | 31 | #ifdef ENABLE_TREM 32 | // Tremolo (sine * sine) table 33 | static const unsigned char tremtab[] = { 34 | 0, 0, 1, 1, 2, 4, 5, 7, 10, 12, 15, 18, 21, 25, 29, 33, 37, 42, 47, 35 | 52, 57, 62, 67, 73, 79, 85, 90, 97, 103, 109, 115, 121, 128, 134, 36 | 140, 146, 152, 158, 165, 170, 176, 182, 188, 193, 198, 203, 208, 37 | 213, 218, 222, 226, 230, 234, 237, 240, 243, 245, 248, 250, 251, 38 | 253, 254, 254, 255, 255, 255, 254, 254, 253, 251, 250, 248, 245, 39 | 243, 240, 237, 234, 230, 226, 222, 218, 213, 208, 203, 198, 193, 40 | 188, 182, 176, 170, 165, 158, 152, 146, 140, 134, 127, 121, 115, 41 | 109, 103, 97, 90, 85, 79, 73, 67, 62, 57, 52, 47, 42, 37, 33, 29, 42 | 25, 21, 18, 15, 12, 10, 7, 5, 4, 2, 1, 1, 0 43 | }; 44 | #endif 45 | 46 | bool midi_processor::is_lds( std::vector const& p_file, const char * p_extension ) 47 | { 48 | if ( strcasecmp( p_extension, "LDS" ) ) return false; 49 | if ( p_file.size() < 1 ) return false; 50 | if ( p_file[ 0 ] > 2 ) return false; 51 | return true; 52 | } 53 | 54 | struct sound_patch 55 | { 56 | // skip 11 bytes worth of Adlib crap 57 | uint8_t keyoff; 58 | #ifdef ENABLE_WHEEL 59 | uint8_t portamento; 60 | int8_t glide; 61 | #endif 62 | // skip 1 byte 63 | #ifdef ENABLE_VIB 64 | uint8_t vibrato; 65 | uint8_t vibrato_delay; 66 | #endif 67 | #ifdef ENABLE_TREM 68 | uint8_t modulator_tremolo; 69 | uint8_t carrier_tremolo; 70 | uint8_t tremolo_delay; 71 | #endif 72 | #ifdef ENABLE_ARP 73 | uint8_t arpeggio; 74 | int8_t arpeggio_table[12]; 75 | #endif 76 | // skip 4 bytes worth of digital instrument crap 77 | // skip 3 more bytes worth of Adlib crap that isn't even used 78 | uint8_t midi_instrument; 79 | uint8_t midi_velocity; 80 | uint8_t midi_key; 81 | int8_t midi_transpose; 82 | // skip 2 bytes worth of MIDI dummy fields or whatever 83 | }; 84 | 85 | struct channel_state { 86 | #ifdef ENABLE_WHEEL 87 | int16_t gototune, lasttune; 88 | #endif 89 | uint16_t packpos; 90 | int8_t finetune; 91 | #ifdef ENABLE_WHEEL 92 | uint8_t glideto, portspeed; 93 | #endif 94 | uint8_t nextvol, volmod, volcar, 95 | keycount, packwait; 96 | #ifdef ENABLE_VIB 97 | uint8_t vibwait, vibspeed, vibrate, vibcount; 98 | #endif 99 | #ifdef ENABLE_TREM 100 | uint8_t trmstay, trmwait, trmspeed, trmrate, trmcount, 101 | trcwait, trcspeed, trcrate, trccount; 102 | #endif 103 | #ifdef ENABLE_ARP 104 | uint8_t arp_count, arp_size, arp_speed, arp_pos; 105 | int8_t arp_tab[12]; 106 | #endif 107 | 108 | struct { 109 | uint8_t chandelay, sound; 110 | uint16_t high; 111 | } chancheat; 112 | }; 113 | 114 | 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[], 115 | #ifdef ENABLE_WHEEL 116 | int16_t last_pitch_wheel[], 117 | #endif 118 | channel_state * c, uint8_t allvolume, unsigned current_timestamp, unsigned sound, unsigned chan, unsigned high, midi_track & track ) 119 | { 120 | uint8_t buffer[ 2 ]; 121 | current_instrument[ chan ] = sound; 122 | if ( sound >= patches.size() ) return; 123 | const sound_patch & patch = patches[ current_instrument[ chan ] ]; 124 | unsigned channel = ( patch.midi_instrument >= 0x80 ) ? 9 : ( chan == 9 ) ? 10 : chan; 125 | unsigned saved_last_note = last_note[ chan ]; 126 | unsigned note; 127 | 128 | if ( channel != 9 ) 129 | { 130 | // set fine tune 131 | high += c->finetune; 132 | 133 | // arpeggio handling 134 | #ifdef ENABLE_ARP 135 | if(patch.arpeggio) 136 | { 137 | short arpcalc = patch.arpeggio_table[0] << 4; 138 | 139 | high += arpcalc; 140 | } 141 | #endif 142 | 143 | // and MIDI transpose 144 | high = (int)high + ( patch.midi_transpose << 4 ); 145 | 146 | note = high 147 | #ifdef ENABLE_WHEEL 148 | - c->lasttune 149 | #endif 150 | ; 151 | 152 | // glide handling 153 | #ifdef ENABLE_WHEEL 154 | if(c->glideto != 0) 155 | { 156 | c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune; 157 | c->portspeed = c->glideto; 158 | c->glideto = c->finetune = 0; 159 | return; 160 | } 161 | #endif 162 | 163 | if ( patch.midi_instrument != last_instrument[ chan ] ) 164 | { 165 | buffer[ 0 ] = patch.midi_instrument; 166 | track.add_event( midi_event( current_timestamp, midi_event::program_change, channel, buffer, 1 ) ); 167 | last_instrument[ chan ] = patch.midi_instrument; 168 | } 169 | } 170 | else 171 | { 172 | note = ( patch.midi_instrument & 0x7F ) << 4; 173 | } 174 | 175 | unsigned volume = 127; 176 | 177 | if ( c->nextvol ) 178 | { 179 | volume = ( c->nextvol & 0x3F ) * 127 / 63; 180 | last_volume[ chan ] = volume; 181 | } 182 | 183 | if ( allvolume ) 184 | { 185 | volume = volume * allvolume / 255; 186 | } 187 | 188 | if ( volume != last_sent_volume[ channel ] ) 189 | { 190 | buffer[ 0 ] = 7; 191 | buffer[ 1 ] = volume; 192 | track.add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) ); 193 | last_sent_volume[ channel ] = volume; 194 | } 195 | 196 | if ( saved_last_note != 0xFF ) 197 | { 198 | buffer[ 0 ] = saved_last_note; 199 | buffer[ 1 ] = 127; 200 | track.add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) ); 201 | last_note[ chan ] = 0xFF; 202 | #ifdef ENABLE_WHEEL 203 | if ( channel != 9 ) 204 | { 205 | note += c->lasttune; 206 | c->lasttune = 0; 207 | if ( last_pitch_wheel[ channel ] != 0 ) 208 | { 209 | buffer[ 0 ] = 0; 210 | buffer[ 1 ] = 64; 211 | track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); 212 | last_pitch_wheel[ channel ] = 0; 213 | } 214 | } 215 | #endif 216 | } 217 | #ifdef ENABLE_WHEEL 218 | if ( c->lasttune != last_pitch_wheel[ channel ] ) 219 | { 220 | buffer[ 0 ] = WHEEL_SCALE_LOW( c->lasttune ); 221 | buffer[ 1 ] = WHEEL_SCALE_HIGH( c->lasttune ); 222 | track.add_event( midi_event( current_timestamp, midi_event::pitch_wheel, channel, buffer, 2 ) ); 223 | last_pitch_wheel[ channel ] = c->lasttune; 224 | } 225 | if( !patch.glide || last_note[ chan ] == 0xFF ) 226 | #endif 227 | { 228 | #ifdef ENABLE_WHEEL 229 | if( !patch.portamento || last_note[ chan ] == 0xFF ) 230 | #endif 231 | { 232 | buffer[ 0 ] = note >> 4; 233 | buffer[ 1 ] = patch.midi_velocity; 234 | track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); 235 | last_note[ chan ] = note >> 4; 236 | last_channel[ chan ] = channel; 237 | #ifdef ENABLE_WHEEL 238 | c->gototune = c->lasttune; 239 | #endif 240 | } 241 | #ifdef ENABLE_WHEEL 242 | else 243 | { 244 | c->gototune = note - ( last_note[ chan ] << 4 ) + c->lasttune; 245 | c->portspeed = patch.portamento; 246 | buffer[ 0 ] = last_note[ chan ] = saved_last_note; 247 | buffer[ 1 ] = patch.midi_velocity; 248 | track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); 249 | } 250 | #endif 251 | } 252 | #ifdef ENABLE_WHEEL 253 | else 254 | { 255 | buffer[ 0 ] = note >> 4; 256 | buffer[ 1 ] = patch.midi_velocity; 257 | track.add_event( midi_event( current_timestamp, midi_event::note_on, channel, buffer, 2 ) ); 258 | last_note[ chan ] = note >> 4; 259 | last_channel[ chan ] = channel; 260 | c->gototune = patch.glide; 261 | c->portspeed = patch.portamento; 262 | } 263 | #endif 264 | 265 | #ifdef ENABLE_VIB 266 | if(!patch.vibrato) 267 | { 268 | c->vibwait = c->vibspeed = c->vibrate = 0; 269 | } 270 | else 271 | { 272 | c->vibwait = patch.vibrato_delay; 273 | // PASCAL: c->vibspeed = ((i->vibrato >> 4) & 15) + 1; 274 | c->vibspeed = (patch.vibrato >> 4) + 2; 275 | c->vibrate = (patch.vibrato & 15) + 1; 276 | } 277 | #endif 278 | 279 | #ifdef ENABLE_TREM 280 | if(!(c->trmstay & 0xf0)) 281 | { 282 | c->trmwait = (patch.tremolo_delay & 0xf0) >> 3; 283 | // PASCAL: c->trmspeed = (i->mod_trem >> 4) & 15; 284 | c->trmspeed = patch.modulator_tremolo >> 4; 285 | c->trmrate = patch.modulator_tremolo & 15; 286 | c->trmcount = 0; 287 | } 288 | 289 | if(!(c->trmstay & 0x0f)) 290 | { 291 | c->trcwait = (patch.tremolo_delay & 15) << 1; 292 | // PASCAL: c->trcspeed = (i->car_trem >> 4) & 15; 293 | c->trcspeed = patch.carrier_tremolo >> 4; 294 | c->trcrate = patch.carrier_tremolo & 15; 295 | c->trccount = 0; 296 | } 297 | #endif 298 | 299 | #ifdef ENABLE_ARP 300 | c->arp_size = patch.arpeggio & 15; 301 | c->arp_speed = patch.arpeggio >> 4; 302 | memcpy(c->arp_tab, patch.arpeggio_table, 12); 303 | c->arp_pos = c->arp_count = 0; 304 | #endif 305 | #ifdef ENABLE_VIB 306 | c->vibcount = 0; 307 | #endif 308 | #ifdef ENABLE_WHEEL 309 | c->glideto = 0; 310 | #endif 311 | c->keycount = patch.keyoff; 312 | c->nextvol = c->finetune = 0; 313 | } 314 | 315 | bool midi_processor::process_lds( std::vector const& p_file, midi_container & p_out ) 316 | { 317 | struct position_data 318 | { 319 | uint16_t pattern_number; 320 | uint8_t transpose; 321 | }; 322 | 323 | uint8_t mode; 324 | /*uint16_t speed;*/ 325 | uint8_t tempo; 326 | uint8_t pattern_length; 327 | uint8_t channel_delay[ 9 ]; 328 | /*uint8_t register_bd;*/ 329 | uint16_t patch_count; 330 | std::vector patches; 331 | uint16_t position_count; 332 | std::vector positions; 333 | std::size_t pattern_count; 334 | std::vector patterns; 335 | 336 | std::vector::const_iterator it = p_file.begin(); 337 | std::vector::const_iterator end = p_file.end(); 338 | 339 | if ( end == it ) return false; 340 | mode = *it++; 341 | if ( mode > 2 ) return false; /*throw exception_io_data( "Invalid LDS mode" );*/ 342 | /*speed = it[ 0 ] | ( it[ 1 ] << 8 );*/ 343 | if ( end - it < 4 ) return false; 344 | tempo = it[ 2 ]; 345 | pattern_length = it[ 3 ]; 346 | it += 4; 347 | if ( end - it < 9 ) return false; 348 | for ( unsigned i = 0; i < 9; ++i ) 349 | channel_delay[ i ] = *it++; 350 | /*register_bd = *it++;*/ it++; 351 | 352 | if ( end - it < 2 ) return false; 353 | patch_count = it[ 0 ] | ( it[ 1 ] << 8 ); 354 | if ( !patch_count ) return false; 355 | it += 2; 356 | patches.resize( patch_count ); 357 | if ( end - it < 46 * patch_count ) return false; 358 | for ( unsigned i = 0; i < patch_count; ++i ) 359 | { 360 | sound_patch & patch = patches[ i ]; 361 | it += 11; 362 | patch.keyoff = *it++; 363 | #ifdef ENABLE_WHEEL 364 | patch.portamento = *it++; 365 | patch.glide = *it++; 366 | it++; 367 | #else 368 | it += 3; 369 | #endif 370 | #ifdef ENABLE_VIB 371 | patch.vibrato = *it++; 372 | patch.vibrato_delay = *it++; 373 | #else 374 | it += 2; 375 | #endif 376 | #ifdef ENABLE_TREM 377 | patch.modulator_tremolo = *it++; 378 | patch.carrier_tremolo = *it++; 379 | patch.tremolo_delay = *it++; 380 | #else 381 | it += 3; 382 | #endif 383 | #ifdef ENABLE_ARP 384 | patch.arpeggio = *it++; 385 | for ( unsigned j = 0; j < 12; ++j ) 386 | patch.arpeggio_table[ j ] = *it++; 387 | it += 7; 388 | #else 389 | it += 20; 390 | #endif 391 | patch.midi_instrument = *it++; 392 | patch.midi_velocity = *it++; 393 | patch.midi_key = *it++; 394 | patch.midi_transpose = *it++; 395 | it += 2; 396 | 397 | #ifdef ENABLE_WHEEL 398 | // hax 399 | if ( patch.midi_instrument >= 0x80 ) 400 | { 401 | patch.glide = 0; 402 | } 403 | #endif 404 | } 405 | 406 | if ( end - it < 2 ) return false; 407 | position_count = it[ 0 ] | ( it[ 1 ] << 8 ); 408 | if ( !position_count ) return false; 409 | it += 2; 410 | positions.resize( 9 * position_count ); 411 | if ( end - it < 3 * position_count ) return false; 412 | for ( unsigned i = 0; i < position_count; ++i ) 413 | { 414 | for ( unsigned j = 0; j < 9; ++j ) 415 | { 416 | position_data & position = positions[ i * 9 + j ]; 417 | position.pattern_number = it[ 0 ] | ( it[ 1 ] << 8 ); 418 | if ( position.pattern_number & 1 ) return false; /*throw exception_io_data( "Odd LDS pattern number" );*/ 419 | position.pattern_number >>= 1; 420 | position.transpose = it[ 2 ]; 421 | it += 3; 422 | } 423 | } 424 | 425 | if ( end - it < 2 ) return false; 426 | it += 2; 427 | 428 | pattern_count = ( end - it ) / 2; 429 | patterns.resize( pattern_count ); 430 | for ( unsigned i = 0; i < pattern_count; ++i ) 431 | { 432 | patterns[ i ] = it[ 0 ] | ( it[ 1 ] << 8 ); 433 | it += 2; 434 | } 435 | 436 | uint8_t /*jumping,*/ fadeonoff, allvolume, hardfade, tempo_now, pattplay; 437 | uint16_t posplay, jumppos; 438 | uint32_t mainvolume; 439 | std::vector channel; 440 | channel.resize( 9 ); 441 | std::vector position_timestamps; 442 | position_timestamps.resize( position_count, ~0u ); 443 | 444 | uint8_t current_instrument[9] = { 0 }; 445 | 446 | uint8_t last_channel[9]; 447 | uint8_t last_instrument[9]; 448 | uint8_t last_note[9]; 449 | uint8_t last_volume[9]; 450 | uint8_t last_sent_volume[11]; 451 | #ifdef ENABLE_WHEEL 452 | int16_t last_pitch_wheel[11]; 453 | #endif 454 | uint8_t ticks_without_notes[11]; 455 | 456 | memset( last_channel, 0, sizeof( last_channel ) ); 457 | memset( last_instrument, 0xFF, sizeof( last_instrument ) ); 458 | memset( last_note, 0xFF, sizeof( last_note ) ); 459 | memset( last_volume, 127, sizeof( last_volume ) ); 460 | memset( last_sent_volume, 127, sizeof( last_sent_volume ) ); 461 | #ifdef ENABLE_WHEEL 462 | memset( last_pitch_wheel, 0, sizeof( last_pitch_wheel ) ); 463 | #endif 464 | memset( ticks_without_notes, 0, sizeof( ticks_without_notes ) ); 465 | 466 | unsigned current_timestamp = 0; 467 | 468 | uint8_t buffer[ 2 ]; 469 | 470 | p_out.initialize( 1, 35 ); 471 | 472 | { 473 | midi_track track; 474 | track.add_event( midi_event( 0, midi_event::extended, 0, lds_default_tempo, _countof( lds_default_tempo ) ) ); 475 | for ( unsigned i = 0; i < 11; ++i ) 476 | { 477 | buffer[ 0 ] = 120; 478 | buffer[ 1 ] = 0; 479 | track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); 480 | buffer[ 0 ] = 121; 481 | track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); 482 | #ifdef ENABLE_WHEEL 483 | buffer[ 0 ] = 0x65; 484 | track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); 485 | buffer[ 0 ] = 0x64; 486 | track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); 487 | buffer[ 0 ] = 0x06; 488 | buffer[ 1 ] = WHEEL_RANGE_HIGH; 489 | track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); 490 | buffer[ 0 ] = 0x26; 491 | buffer[ 1 ] = WHEEL_RANGE_LOW; 492 | track.add_event( midi_event( 0, midi_event::control_change, i, buffer, 2 ) ); 493 | buffer[ 0 ] = 0; 494 | buffer[ 1 ] = 64; 495 | track.add_event( midi_event( 0, midi_event::pitch_wheel, i, buffer, 2 ) ); 496 | #endif 497 | } 498 | track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 499 | p_out.add_track( track ); 500 | } 501 | 502 | std::vector tracks; 503 | { 504 | midi_track track; 505 | track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 506 | tracks.resize( 10, track ); 507 | } 508 | 509 | tempo_now = 3; 510 | /*jumping = 0;*/ 511 | fadeonoff = 0; 512 | allvolume = 0; 513 | hardfade = 0; 514 | pattplay = 0; 515 | posplay = 0; 516 | jumppos = 0; 517 | mainvolume = 0; 518 | memset( &channel[0], 0, sizeof( channel_state ) * 9 ); 519 | 520 | const uint16_t maxsound = 0x3F; 521 | const uint16_t maxpos = 0xFF; 522 | 523 | bool playing = true; 524 | while ( playing ) 525 | { 526 | uint16_t chan; 527 | #ifdef ENABLE_VIB 528 | uint16_t wibc; 529 | #endif 530 | #if defined(ENABLE_VIB) || defined(ENABLE_ARP) 531 | int16_t tune; 532 | #endif 533 | #ifdef ENABLE_ARP 534 | int16_t arpreg; 535 | #endif 536 | #ifdef ENABLE_TREM 537 | uint16_t tremc; 538 | #endif 539 | bool vbreak; 540 | unsigned i; 541 | channel_state * c; 542 | 543 | if(fadeonoff) 544 | { 545 | if(fadeonoff <= 128) 546 | { 547 | if(allvolume > fadeonoff || allvolume == 0) 548 | { 549 | allvolume -= fadeonoff; 550 | } 551 | else 552 | { 553 | allvolume = 1; 554 | fadeonoff = 0; 555 | if(hardfade != 0) 556 | { 557 | playing = false; 558 | hardfade = 0; 559 | for(i = 0; i < 9; i++) 560 | channel[i].keycount = 1; 561 | } 562 | } 563 | } 564 | else if((unsigned)((allvolume + (0x100 - fadeonoff)) & 0xff) <= mainvolume) 565 | { 566 | allvolume += 0x100 - fadeonoff; 567 | } 568 | else 569 | { 570 | allvolume = mainvolume; 571 | fadeonoff = 0; 572 | } 573 | } 574 | 575 | // handle channel delay 576 | for(chan = 0; chan < 9; ++chan) 577 | { 578 | channel_state * _c = &channel[chan]; 579 | if(_c->chancheat.chandelay) 580 | { 581 | if(!(--_c->chancheat.chandelay)) 582 | { 583 | playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume, 584 | #ifdef ENABLE_WHEEL 585 | last_pitch_wheel, 586 | #endif 587 | _c, allvolume, current_timestamp, _c->chancheat.sound, chan, _c->chancheat.high, tracks[ chan ] ); 588 | ticks_without_notes[ last_channel[ chan ] ] = 0; 589 | } 590 | } 591 | } 592 | 593 | // handle notes 594 | if(!tempo_now) 595 | { 596 | if ( pattplay == 0 && position_timestamps[ posplay ] == ~0u ) 597 | { 598 | position_timestamps[ posplay ] = current_timestamp; 599 | } 600 | 601 | vbreak = false; 602 | for(unsigned _chan = 0; _chan < 9; _chan++) 603 | { 604 | channel_state * _c = &channel[_chan]; 605 | if(!_c->packwait) 606 | { 607 | unsigned short patnum = positions[posplay * 9 + _chan].pattern_number; 608 | unsigned char transpose = positions[posplay * 9 + _chan].transpose; 609 | 610 | if ( (unsigned long)(patnum + _c->packpos) >= patterns.size() ) return false; /*throw exception_io_data( "Invalid LDS pattern number" );*/ 611 | 612 | unsigned comword = patterns[patnum + _c->packpos]; 613 | unsigned comhi = comword >> 8; 614 | unsigned comlo = comword & 0xff; 615 | if(comword) 616 | { 617 | if(comhi == 0x80) 618 | { 619 | _c->packwait = comlo; 620 | } 621 | else if(comhi >= 0x80) 622 | { 623 | switch(comhi) { 624 | case 0xff: 625 | { 626 | unsigned volume = ( comlo & 0x3F ) * 127 / 63; 627 | last_volume[ _chan ] = volume; 628 | if ( volume != last_sent_volume[ last_channel[ _chan ] ] ) 629 | { 630 | buffer[ 0 ] = 7; 631 | buffer[ 1 ] = volume; 632 | tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) ); 633 | last_sent_volume[ last_channel [ _chan ] ] = volume; 634 | } 635 | } 636 | break; 637 | case 0xfe: 638 | tempo = comword & 0x3f; 639 | break; 640 | case 0xfd: 641 | _c->nextvol = comlo; 642 | break; 643 | case 0xfc: 644 | playing = false; 645 | // in real player there's also full keyoff here, but we don't need it 646 | break; 647 | case 0xfb: 648 | _c->keycount = 1; 649 | break; 650 | case 0xfa: 651 | vbreak = true; 652 | jumppos = (posplay + 1) & maxpos; 653 | break; 654 | case 0xf9: 655 | vbreak = true; 656 | jumppos = comlo & maxpos; 657 | /*jumping = 1;*/ 658 | if(jumppos <= posplay) 659 | { 660 | p_out.add_track_event( 0, midi_event( position_timestamps[ jumppos ], midi_event::extended, 0, loop_start, _countof( loop_start ) ) ); 661 | p_out.add_track_event( 0, midi_event( current_timestamp + tempo - 1, midi_event::extended, 0, loop_end, _countof( loop_end ) ) ); 662 | playing = false; 663 | } 664 | break; 665 | case 0xf8: 666 | #ifdef ENABLE_WHEEL 667 | _c->lasttune = 0; 668 | #endif 669 | break; 670 | case 0xf7: 671 | #ifdef ENABLE_VIB 672 | _c->vibwait = 0; 673 | // PASCAL: _c->vibspeed = ((comlo >> 4) & 15) + 2; 674 | _c->vibspeed = (comlo >> 4) + 2; 675 | _c->vibrate = (comlo & 15) + 1; 676 | #endif 677 | break; 678 | case 0xf6: 679 | #ifdef ENABLE_WHEEL 680 | _c->glideto = comlo; 681 | #endif 682 | break; 683 | case 0xf5: 684 | _c->finetune = comlo; 685 | break; 686 | case 0xf4: 687 | if(!hardfade) { 688 | allvolume = mainvolume = comlo; 689 | fadeonoff = 0; 690 | } 691 | break; 692 | case 0xf3: 693 | if(!hardfade) fadeonoff = comlo; 694 | break; 695 | case 0xf2: 696 | #ifdef ENABLE_TREM 697 | _c->trmstay = comlo; 698 | #endif 699 | break; 700 | case 0xf1: 701 | buffer[ 0 ] = 10; 702 | buffer[ 1 ] = ( comlo & 0x3F ) * 127 / 63; 703 | tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ _chan ], buffer, 2 ) ); 704 | break; 705 | case 0xf0: 706 | buffer[ 0 ] = comlo & 0x7F; 707 | tracks[ _chan ].add_event( midi_event( current_timestamp, midi_event::program_change, last_channel[ _chan ], buffer, 1 ) ); 708 | break; 709 | default: 710 | #ifdef ENABLE_WHEEL 711 | if(comhi < 0xa0) 712 | _c->glideto = comhi & 0x1f; 713 | #endif 714 | break; 715 | } 716 | } 717 | else 718 | { 719 | unsigned char sound; 720 | unsigned short high; 721 | signed char transp = transpose << 1; 722 | transp >>= 1; 723 | 724 | if(transpose & 128) { 725 | sound = (comlo + transp) & maxsound; 726 | high = comhi << 4; 727 | } else { 728 | sound = comlo & maxsound; 729 | high = (comhi + transp) << 4; 730 | } 731 | 732 | /* 733 | PASCAL: 734 | sound = comlo & maxsound; 735 | high = (comhi + (((transpose + 0x24) & 0xff) - 0x24)) << 4; 736 | */ 737 | 738 | if( !channel_delay[ _chan ] ) 739 | { 740 | playsound( current_instrument, patches, last_note, last_channel, last_instrument, last_volume, last_sent_volume, 741 | #ifdef ENABLE_WHEEL 742 | last_pitch_wheel, 743 | #endif 744 | _c, allvolume, current_timestamp, sound, _chan, high, tracks[ _chan ] ); 745 | ticks_without_notes[ last_channel[ _chan ] ] = 0; 746 | } 747 | else 748 | { 749 | _c->chancheat.chandelay = channel_delay[_chan]; 750 | _c->chancheat.sound = sound; 751 | _c->chancheat.high = high; 752 | } 753 | } 754 | } 755 | _c->packpos++; 756 | } 757 | else 758 | { 759 | _c->packwait--; 760 | } 761 | } 762 | 763 | tempo_now = tempo; 764 | /* 765 | The continue table is updated here, but this is only used in the 766 | original player, which can be paused in the middle of a song and then 767 | unpaused. Since AdPlug does all this for us automatically, we don't 768 | have a continue table here. The continue table update code is noted 769 | here for reference only. 770 | 771 | if(!pattplay) { 772 | conttab[speed & maxcont].position = posplay & 0xff; 773 | conttab[speed & maxcont].tempo = tempo; 774 | } 775 | */ 776 | pattplay++; 777 | if(vbreak) 778 | { 779 | pattplay = 0; 780 | for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; 781 | posplay = jumppos; 782 | if ( posplay >= position_count ) return false; /*throw exception_io_data( "Invalid LDS position jump" );*/ 783 | } 784 | else if(pattplay >= pattern_length) 785 | { 786 | pattplay = 0; 787 | for(i = 0; i < 9; i++) channel[i].packpos = channel[i].packwait = 0; 788 | posplay = (posplay + 1) & maxpos; 789 | if ( posplay >= position_count ) playing = false; //throw exception_io_data( "LDS reached the end without a loop or end command" ); 790 | } 791 | } 792 | else 793 | { 794 | tempo_now--; 795 | } 796 | 797 | // make effects 798 | for(chan = 0; chan < 9; ++chan) 799 | { 800 | c = &channel[chan]; 801 | if(c->keycount > 0) 802 | { 803 | if( c->keycount == 1 && last_note[ chan ] != 0xFF ) 804 | { 805 | buffer[ 0 ] = last_note[ chan ]; 806 | buffer[ 1 ] = 127; 807 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::note_off, last_channel[ chan ], buffer, 2 ) ); 808 | last_note[ chan ] = 0xFF; 809 | #ifdef ENABLE_WHEEL 810 | if ( 0 != last_pitch_wheel[ last_channel[ chan ] ] ) 811 | { 812 | buffer[ 0 ] = 0; 813 | buffer[ 1 ] = 64; 814 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); 815 | last_pitch_wheel[ last_channel[ chan ] ] = 0; 816 | c->lasttune = 0; 817 | c->gototune = 0; 818 | } 819 | #endif 820 | } 821 | c->keycount--; 822 | } 823 | 824 | #ifdef ENABLE_ARP 825 | // arpeggio 826 | if(c->arp_size == 0) 827 | { 828 | arpreg = 0; 829 | } 830 | else 831 | { 832 | arpreg = c->arp_tab[c->arp_pos] << 4; 833 | if(arpreg == -0x800) 834 | { 835 | if(c->arp_pos > 0) c->arp_tab[0] = c->arp_tab[c->arp_pos - 1]; 836 | c->arp_size = 1; c->arp_pos = 0; 837 | arpreg = c->arp_tab[0] << 4; 838 | } 839 | 840 | if(c->arp_count == c->arp_speed) { 841 | c->arp_pos++; 842 | if(c->arp_pos >= c->arp_size) c->arp_pos = 0; 843 | c->arp_count = 0; 844 | } 845 | else 846 | { 847 | c->arp_count++; 848 | } 849 | } 850 | #endif 851 | 852 | #ifdef ENABLE_WHEEL 853 | // glide & portamento 854 | if(c->lasttune != c->gototune) 855 | { 856 | if(c->lasttune > c->gototune) 857 | { 858 | if(c->lasttune - c->gototune < c->portspeed) 859 | { 860 | c->lasttune = c->gototune; 861 | } 862 | else 863 | { 864 | c->lasttune -= c->portspeed; 865 | } 866 | } 867 | else 868 | { 869 | if(c->gototune - c->lasttune < c->portspeed) 870 | { 871 | c->lasttune = c->gototune; 872 | } 873 | else 874 | { 875 | c->lasttune += c->portspeed; 876 | } 877 | } 878 | 879 | #ifdef ENABLE_ARP 880 | arpreg += 881 | #else 882 | int16_t arpreg = 883 | #endif 884 | c->lasttune; 885 | 886 | if ( arpreg != last_pitch_wheel[ last_channel[ chan ] ] ) 887 | { 888 | buffer[ 0 ] = WHEEL_SCALE_LOW( arpreg ); 889 | buffer[ 1 ] = WHEEL_SCALE_HIGH( arpreg ); 890 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); 891 | last_pitch_wheel[ last_channel[ chan ] ] = arpreg; 892 | } 893 | } else 894 | { 895 | #ifdef ENABLE_VIB 896 | // vibrato 897 | if(!c->vibwait) 898 | { 899 | if(c->vibrate) 900 | { 901 | wibc = vibtab[c->vibcount & 0x3f] * c->vibrate; 902 | 903 | if((c->vibcount & 0x40) == 0) 904 | tune = c->lasttune + (wibc >> 8); 905 | else 906 | tune = c->lasttune - (wibc >> 8); 907 | 908 | #ifdef ENABLE_ARP 909 | tune += arpreg; 910 | #endif 911 | 912 | if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) 913 | { 914 | buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); 915 | buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); 916 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); 917 | last_pitch_wheel[ last_channel[ chan ] ] = tune; 918 | } 919 | 920 | c->vibcount += c->vibspeed; 921 | } 922 | #ifdef ENABLE_ARP 923 | else if(c->arp_size != 0) 924 | { // no vibrato, just arpeggio 925 | tune = c->lasttune + arpreg; 926 | 927 | if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) 928 | { 929 | buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); 930 | buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); 931 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); 932 | last_pitch_wheel[ last_channel[ chan ] ] = tune; 933 | } 934 | } 935 | #endif 936 | } 937 | #ifdef ENABLE_ARP 938 | else 939 | #endif 940 | #endif 941 | #ifdef ENABLE_ARP 942 | { // no vibrato, just arpeggio 943 | #ifdef ENABLE_VIB 944 | c->vibwait--; 945 | #endif 946 | 947 | if(c->arp_size != 0) 948 | { 949 | tune = c->lasttune + arpreg; 950 | 951 | if ( tune != last_pitch_wheel[ last_channel[ chan ] ] ) 952 | { 953 | buffer[ 0 ] = WHEEL_SCALE_LOW( tune ); 954 | buffer[ 1 ] = WHEEL_SCALE_HIGH( tune ); 955 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::pitch_wheel, last_channel[ chan ], buffer, 2 ) ); 956 | last_pitch_wheel[ last_channel[ chan ] ] = tune; 957 | } 958 | } 959 | } 960 | #endif 961 | } 962 | #endif 963 | 964 | #ifdef ENABLE_TREM 965 | unsigned volume = last_volume[ chan ]; 966 | 967 | // tremolo (modulator) 968 | if(!c->trmwait) 969 | { 970 | if(c->trmrate) 971 | { 972 | tremc = tremtab[c->trmcount & 0x7f] * c->trmrate; 973 | if((tremc >> 7) <= volume) 974 | volume = volume - (tremc >> 7); 975 | else 976 | volume = 0; 977 | 978 | c->trmcount += c->trmspeed; 979 | } 980 | } 981 | else 982 | { 983 | c->trmwait--; 984 | } 985 | 986 | // tremolo (carrier) 987 | if(!c->trcwait) 988 | { 989 | if(c->trcrate) 990 | { 991 | tremc = tremtab[c->trccount & 0x7f] * c->trcrate; 992 | if((tremc >> 7) <= volume) 993 | volume = volume - (tremc >> 8); 994 | else 995 | volume = 0; 996 | } 997 | } 998 | else 999 | { 1000 | c->trcwait--; 1001 | } 1002 | 1003 | if ( allvolume ) 1004 | { 1005 | volume = volume * allvolume / 255; 1006 | } 1007 | 1008 | if ( volume != last_sent_volume[ last_channel[ chan ] ] ) 1009 | { 1010 | buffer[ 0 ] = 7; 1011 | buffer[ 1 ] = volume; 1012 | tracks[ chan ].add_event( midi_event( current_timestamp, midi_event::control_change, last_channel[ chan ], buffer, 2 ) ); 1013 | last_sent_volume[ last_channel[ chan ] ] = volume; 1014 | } 1015 | #endif 1016 | 1017 | } 1018 | 1019 | ++current_timestamp; 1020 | } 1021 | 1022 | --current_timestamp; 1023 | 1024 | for ( unsigned i = 0; i < 9; ++i ) 1025 | { 1026 | midi_track & track = tracks[ i ]; 1027 | unsigned long count = track.get_count(); 1028 | if ( count > 1 ) 1029 | { 1030 | if ( last_note[ i ] != 0xFF ) 1031 | { 1032 | buffer[ 0 ] = last_note[ i ]; 1033 | buffer[ 1 ] = 127; 1034 | track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::note_off, last_channel[ i ], buffer, 2 ) ); 1035 | #ifdef ENABLE_WHEEL 1036 | if ( last_pitch_wheel[ last_channel[ i ] ] != 0 ) 1037 | { 1038 | buffer[ 0 ] = 0; 1039 | buffer[ 1 ] = 0x40; 1040 | track.add_event( midi_event( current_timestamp + channel[ i ].keycount, midi_event::pitch_wheel, last_channel[ i ], buffer, 2 ) ); 1041 | } 1042 | #endif 1043 | } 1044 | p_out.add_track( track ); 1045 | } 1046 | } 1047 | 1048 | return true; 1049 | } 1050 | -------------------------------------------------------------------------------- /midi_processor_mids.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | bool midi_processor::is_mids( std::vector const& p_file ) 4 | { 5 | if ( p_file.size() < 8 ) return false; 6 | if ( p_file[ 0 ] != 'R' || p_file[ 1 ] != 'I' || p_file[ 2 ] != 'F' || p_file[ 3 ] != 'F' ) return false; 7 | uint32_t size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); 8 | if ( size < 8 || ( p_file.size() < size + 8 ) ) return false; 9 | if ( p_file[ 8 ] != 'M' || p_file[ 9 ] != 'I' || p_file[ 10 ] != 'D' || p_file[ 11 ] != 'S' || 10 | p_file[ 12 ] != 'f' || p_file[ 13 ] != 'm' || p_file[ 14 ] != 't' || p_file[ 15 ] != ' ' ) return false; 11 | return true; 12 | } 13 | 14 | bool midi_processor::process_mids( std::vector const& p_file, midi_container & p_out ) 15 | { 16 | if ( p_file.size() < 20 ) return false; 17 | std::vector::const_iterator it = p_file.begin() + 16; 18 | std::vector::const_iterator end = p_file.end(); 19 | 20 | uint32_t fmt_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 21 | it += 4; 22 | if ( (unsigned long)(end - it) < fmt_size ) return false; 23 | 24 | uint32_t time_format = 1; 25 | /*uint32_t max_buffer = 0;*/ 26 | uint32_t flags = 0; 27 | 28 | if ( fmt_size >= 4 ) 29 | { 30 | time_format = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 31 | it += 4; 32 | fmt_size -= 4; 33 | if ( !time_format ) // dtx == 0, will cause division by zero on tempo calculations 34 | return false; 35 | } 36 | if ( fmt_size >= 4 ) 37 | { 38 | /*max_buffer = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );*/ 39 | it += 4; 40 | fmt_size -= 4; 41 | } 42 | if ( fmt_size >= 4 ) 43 | { 44 | flags = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 45 | it += 4; 46 | fmt_size -= 4; 47 | } 48 | 49 | it += fmt_size; 50 | if ( it == end ) return false; 51 | if ( fmt_size & 1 ) ++it; 52 | 53 | p_out.initialize( 0, time_format ); 54 | 55 | if ( end - it < 4 ) return false; 56 | if ( it[ 0 ] != 'd' || it[ 1 ] != 'a' || it[ 2 ] != 't' || it[ 3 ] != 'a' ) return false; /*throw exception_io_data( "MIDS missing RIFF data chunk" );*/ 57 | 58 | it += 4; 59 | 60 | { 61 | midi_track track; 62 | track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 63 | p_out.add_track( track ); 64 | } 65 | 66 | if ( end - it < 4 ) return false; 67 | uint32_t data_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 68 | it += 4; 69 | 70 | std::vector::const_iterator body_end = it + data_size; 71 | 72 | if ( body_end - it < 4 ) return false; 73 | uint32_t segment_count = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 74 | it += 4; 75 | 76 | bool is_eight_byte = !!(flags & 1); 77 | 78 | midi_track track; 79 | 80 | unsigned current_timestamp = 0; 81 | 82 | for ( unsigned i = 0; i < segment_count; ++i ) 83 | { 84 | if ( end - it < 12 ) return false; 85 | it += 4; 86 | uint32_t segment_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 87 | it += 4; 88 | std::vector::const_iterator segment_end = it + segment_size; 89 | while ( it != segment_end && it != body_end ) 90 | { 91 | if ( segment_end - it < 4 ) return false; 92 | uint32_t delta = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 93 | it += 4; 94 | uint32_t event; 95 | current_timestamp += delta; 96 | if ( !is_eight_byte ) 97 | { 98 | if ( segment_end - it < 4 ) return false; 99 | it += 4; 100 | } 101 | if ( segment_end - it < 4 ) return false; 102 | event = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 ); 103 | it += 4; 104 | if ( event >> 24 == 0x01 ) 105 | { 106 | uint8_t buffer[ 5 ] = { 0xFF, 0x51 }; 107 | buffer[ 2 ] = (uint8_t)( event >> 16 ); 108 | buffer[ 3 ] = (uint8_t)( event >> 8 ); 109 | buffer[ 4 ] = (uint8_t)event; 110 | p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, buffer, sizeof( buffer ) ) ); 111 | } 112 | else if ( !( event >> 24 ) ) 113 | { 114 | unsigned event_code = ( event & 0xF0 ) >> 4; 115 | if ( event_code >= 0x8 && event_code <= 0xE ) 116 | { 117 | unsigned bytes_to_write = 1; 118 | uint8_t buffer[2]; 119 | buffer[ 0 ] = (uint8_t)( event >> 8 ); 120 | if ( event_code != 0xC && event_code != 0xD ) 121 | { 122 | buffer[ 1 ] = (uint8_t)( event >> 16 ); 123 | bytes_to_write = 2; 124 | } 125 | track.add_event( midi_event( current_timestamp, (midi_event::event_type)( event_code - 8 ), event & 0x0F, buffer, bytes_to_write ) ); 126 | } 127 | } 128 | } 129 | } 130 | 131 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 132 | 133 | p_out.add_track( track ); 134 | 135 | return true; 136 | } 137 | -------------------------------------------------------------------------------- /midi_processor_mus.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | const uint8_t midi_processor::mus_default_tempo[5] = {0xFF, 0x51, 0x09, 0xA3, 0x1A}; 4 | 5 | const uint8_t midi_processor::mus_controllers[15] = {0,0,1,7,10,11,91,93,64,67,120,123,126,127,121}; 6 | 7 | bool midi_processor::is_mus( std::vector const& p_file ) 8 | { 9 | if ( p_file.size() < 0x20 ) return false; 10 | if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'U' || p_file[ 2 ] != 'S' || p_file[ 3 ] != 0x1A ) return false; 11 | uint16_t length = p_file[ 4 ] | ( p_file[ 5 ] << 8 ); 12 | uint16_t offset = p_file[ 6 ] | ( p_file[ 7 ] << 8 ); 13 | uint16_t instrument_count = p_file[ 12 ] | ( p_file[ 13 ] << 8 ); 14 | if ( offset >= 16 + instrument_count * 2 && offset < 16 + instrument_count * 4 && (size_t)(offset + length) <= p_file.size() ) return true; 15 | return false; 16 | } 17 | 18 | bool midi_processor::process_mus( std::vector const& p_file, midi_container & p_out ) 19 | { 20 | uint16_t length = p_file[ 4 ] | ( p_file[ 5 ] << 8 ); 21 | uint16_t offset = p_file[ 6 ] | ( p_file[ 7 ] << 8 ); 22 | 23 | p_out.initialize( 0, 0x59 ); 24 | 25 | { 26 | midi_track track; 27 | track.add_event( midi_event( 0, midi_event::extended, 0, mus_default_tempo, _countof( mus_default_tempo ) ) ); 28 | track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 29 | p_out.add_track( track ); 30 | } 31 | 32 | midi_track track; 33 | 34 | unsigned current_timestamp = 0; 35 | 36 | uint8_t velocity_levels[ 16 ] = { 0 }; 37 | 38 | if ( (size_t)offset >= p_file.size() || (size_t)(offset + length) > p_file.size() ) 39 | return false; 40 | 41 | std::vector::const_iterator it = p_file.begin() + offset, end = p_file.begin() + offset + length; 42 | 43 | uint8_t buffer[ 4 ]; 44 | 45 | while ( it != end ) 46 | { 47 | buffer[ 0 ] = *it++; 48 | if ( buffer[ 0 ] == 0x60 ) break; 49 | 50 | midi_event::event_type type; 51 | 52 | unsigned bytes_to_write; 53 | 54 | unsigned channel = buffer[ 0 ] & 0x0F; 55 | if ( channel == 0x0F ) channel = 9; 56 | else if ( channel >= 9 ) ++channel; 57 | 58 | switch ( buffer[ 0 ] & 0x70 ) 59 | { 60 | case 0x00: 61 | type = midi_event::note_on; 62 | if ( it == end ) return false; 63 | buffer[ 1 ] = *it++; 64 | buffer[ 2 ] = 0; 65 | bytes_to_write = 2; 66 | break; 67 | 68 | case 0x10: 69 | type = midi_event::note_on; 70 | if ( it == end ) return false; 71 | buffer[ 1 ] = *it++; 72 | if ( buffer[ 1 ] & 0x80 ) 73 | { 74 | if ( it == end ) return false; 75 | buffer[ 2 ] = *it++; 76 | velocity_levels[ channel ] = buffer[ 2 ]; 77 | buffer[ 1 ] &= 0x7F; 78 | } 79 | else 80 | { 81 | buffer[ 2 ] = velocity_levels[ channel ]; 82 | } 83 | bytes_to_write = 2; 84 | break; 85 | 86 | case 0x20: 87 | type = midi_event::pitch_wheel; 88 | if ( it == end ) return false; 89 | buffer[ 1 ] = *it++; 90 | buffer[ 2 ] = buffer[ 1 ] >> 1; 91 | buffer[ 1 ] <<= 7; 92 | bytes_to_write = 2; 93 | break; 94 | 95 | case 0x30: 96 | type = midi_event::control_change; 97 | if ( it == end ) return false; 98 | buffer[ 1 ] = *it++; 99 | if ( buffer[ 1 ] >= 10 && buffer[ 1 ] <= 14 ) 100 | { 101 | buffer[ 1 ] = mus_controllers[ buffer[ 1 ] ]; 102 | buffer[ 2 ] = 1; 103 | bytes_to_write = 2; 104 | } 105 | else return false; /*throw exception_io_data( "Unhandled MUS system event" );*/ 106 | break; 107 | 108 | case 0x40: 109 | if ( it == end ) return false; 110 | buffer[ 1 ] = *it++; 111 | if ( buffer[ 1 ] ) 112 | { 113 | if ( buffer[ 1 ] < 10 ) 114 | { 115 | type = midi_event::control_change; 116 | buffer[ 1 ] = mus_controllers[ buffer[ 1 ] ]; 117 | if ( it == end ) return false; 118 | buffer[ 2 ] = *it++; 119 | bytes_to_write = 2; 120 | } 121 | else return false; /*throw exception_io_data( "Invalid MUS controller change event" );*/ 122 | } 123 | else 124 | { 125 | type = midi_event::program_change; 126 | if ( it == end ) return false; 127 | buffer[ 1 ] = *it++; 128 | bytes_to_write = 1; 129 | } 130 | break; 131 | 132 | default: 133 | return false; /*throw exception_io_data( "Invalid MUS status code" );*/ 134 | } 135 | 136 | track.add_event( midi_event( current_timestamp, type, channel, buffer + 1, bytes_to_write ) ); 137 | 138 | if ( buffer[ 0 ] & 0x80 ) 139 | { 140 | int delta = decode_delta( it, end ); 141 | if ( delta < 0 ) return false; /*throw exception_io_data( "Invalid MUS delta" );*/ 142 | current_timestamp += delta; 143 | } 144 | } 145 | 146 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) ); 147 | 148 | p_out.add_track( track ); 149 | 150 | return true; 151 | } 152 | -------------------------------------------------------------------------------- /midi_processor_riff_midi.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | #include 4 | 5 | static inline bool it_equal( std::vector::const_iterator it1, const char *it2, size_t length ) 6 | { 7 | for ( size_t i = 0; i < length; i++ ) 8 | { 9 | if ( it1[ i ] != it2[ i ] ) 10 | return false; 11 | } 12 | return true; 13 | } 14 | 15 | static inline uint32_t toInt32LE( const uint8_t *in ) 16 | { 17 | return static_cast( in[ 0 ] ) | 18 | static_cast( in[ 1 ] << 8 ) | 19 | static_cast( in[ 2 ] << 16 ) | 20 | static_cast( in[ 3 ] << 24 ); 21 | } 22 | 23 | static inline uint32_t toInt32LE( std::vector::const_iterator in ) 24 | { 25 | return static_cast( in[ 0 ] ) | 26 | static_cast( in[ 1 ] << 8 ) | 27 | static_cast( in[ 2 ] << 16 ) | 28 | static_cast( in[ 3 ] << 24 ); 29 | } 30 | 31 | 32 | bool midi_processor::is_riff_midi( std::vector const& p_file ) 33 | { 34 | if ( p_file.size() < 20 ) return false; 35 | if ( memcmp( &p_file[ 0 ], "RIFF", 4 ) != 0 ) return false; 36 | uint32_t riff_size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); 37 | if ( riff_size < 12 || ( p_file.size() < riff_size + 8 ) ) return false; 38 | if ( memcmp( &p_file[ 8 ], "RMID", 4 ) != 0 || 39 | memcmp( &p_file[ 12 ], "data", 4 ) != 0 ) return false; 40 | uint32_t data_size = toInt32LE(&p_file[ 16 ]); 41 | if ( data_size < 18 || p_file.size() < data_size + 20 || riff_size < data_size + 12 ) return false; 42 | std::vector test; 43 | test.assign( p_file.begin() + 20, p_file.begin() + 20 + 18 ); 44 | return is_standard_midi( test ); 45 | } 46 | 47 | bool midi_processor::process_riff_midi_count( std::vector const& p_file, size_t & track_count ) 48 | { 49 | track_count = 0; 50 | 51 | uint32_t file_size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); 52 | 53 | std::vector::const_iterator it = p_file.begin() + 12; 54 | 55 | std::vector::const_iterator body_end = p_file.begin() + 8 + file_size; 56 | 57 | std::vector extra_buffer; 58 | 59 | while ( it != body_end ) 60 | { 61 | if ( body_end - it < 8 ) return false; 62 | uint32_t chunk_size = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); 63 | if ( (unsigned long)(body_end - it) < chunk_size ) return false; 64 | if ( it_equal(it, "data", 4) ) 65 | { 66 | std::vector midi_file; 67 | midi_file.assign( it + 8, it + 8 + chunk_size ); 68 | return process_standard_midi_count( midi_file, track_count ); 69 | } 70 | else 71 | { 72 | it += chunk_size; 73 | if ( chunk_size & 1 && it != body_end ) ++it; 74 | } 75 | } 76 | 77 | return false; 78 | } 79 | 80 | static const char * riff_tag_mappings[][2] = 81 | { 82 | { "IALB", "album" }, 83 | { "IARL", "archival_location" }, 84 | { "IART", "artist" }, 85 | { "ITRK", "tracknumber" }, 86 | { "ICMS", "commissioned" }, 87 | { "ICMP", "composer" }, 88 | { "ICMT", "comment" }, 89 | { "ICOP", "copyright" }, 90 | { "ICRD", "creation_date" }, 91 | { "IENG", "engineer" }, 92 | { "IGNR", "genre" }, 93 | { "IKEY", "keywords" }, 94 | { "IMED", "medium" }, 95 | { "INAM", "title" }, 96 | { "IPRD", "product" }, 97 | { "ISBJ", "subject" }, 98 | { "ISFT", "software" }, 99 | { "ISRC", "source" }, 100 | { "ISRF", "source_form" }, 101 | { "ITCH", "technician" } 102 | }; 103 | 104 | bool midi_processor::process_riff_midi( std::vector const& p_file, midi_container & p_out ) 105 | { 106 | uint32_t file_size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); 107 | 108 | std::vector::const_iterator it = p_file.begin() + 12; 109 | 110 | std::vector::const_iterator body_end = p_file.begin() + 8 + file_size; 111 | 112 | bool found_data = false; 113 | bool found_info = false; 114 | 115 | midi_meta_data meta_data; 116 | 117 | std::vector extra_buffer; 118 | 119 | while ( it != body_end ) 120 | { 121 | if ( body_end - it < 8 ) return false; 122 | uint32_t chunk_size = toInt32LE( it + 4 ); 123 | if ( (unsigned long)(body_end - it) < chunk_size ) return false; 124 | if ( it_equal( it, "data", 4 ) ) 125 | { 126 | if ( !found_data ) 127 | { 128 | std::vector midi_file; 129 | midi_file.assign( it + 8, it + 8 + chunk_size ); 130 | if ( !process_standard_midi( midi_file, p_out ) ) return false; 131 | found_data = true; 132 | } 133 | else return false; /*throw exception_io_data( "Multiple RIFF data chunks found" );*/ 134 | it += 8 + chunk_size; 135 | if ( chunk_size & 1 && it != body_end ) ++it; 136 | } 137 | else if ( it_equal( it, "DISP", 4 ) ) 138 | { 139 | uint32_t type = toInt32LE( it + 8 ); 140 | if ( type == 1 ) 141 | { 142 | extra_buffer.resize( chunk_size - 4 + 1 ); 143 | std::copy( it + 12, it + 8 + chunk_size, extra_buffer.begin() ); 144 | extra_buffer[ chunk_size - 4 ] = '\0'; 145 | meta_data.add_item( midi_meta_data_item( 0, "display_name", (const char *) &extra_buffer[0] ) ); 146 | } 147 | it += 8 + chunk_size; 148 | if ( chunk_size & 1 && it != body_end ) ++it; 149 | } 150 | else if ( it_equal( it, "LIST", 4 ) ) 151 | { 152 | std::vector::const_iterator chunk_end = it + 8 + chunk_size; 153 | if ( it_equal( it + 8, "INFO", 4 ) ) 154 | { 155 | if ( !found_info ) 156 | { 157 | if ( chunk_end - it < 12 ) return false; 158 | it += 12; 159 | while ( it != chunk_end ) 160 | { 161 | if ( chunk_end - it < 4 ) return false; 162 | uint32_t field_size = toInt32LE( it + 4 ); 163 | if ( (unsigned long)(chunk_end - it) < 8 + field_size ) return false; 164 | std::string field; 165 | field.assign( it, it + 4 ); 166 | for ( unsigned i = 0; i < _countof(riff_tag_mappings); ++i ) 167 | { 168 | if ( !memcmp( &it[0], riff_tag_mappings[ i ][ 0 ], 4 ) ) 169 | { 170 | field = riff_tag_mappings[ i ][ 1 ]; 171 | break; 172 | } 173 | } 174 | extra_buffer.resize( field_size + 1 ); 175 | std::copy( it + 8, it + 8 + field_size, extra_buffer.begin() ); 176 | extra_buffer[ field_size ] = '\0'; 177 | it += 8 + field_size; 178 | meta_data.add_item( midi_meta_data_item( 0, field.c_str(), ( const char * ) &extra_buffer[0] ) ); 179 | if ( field_size & 1 && it != chunk_end ) ++it; 180 | } 181 | found_info = true; 182 | } 183 | else return false; /*throw exception_io_data( "Multiple RIFF LIST INFO chunks found" );*/ 184 | } 185 | else return false; /* unknown LIST chunk */ 186 | it = chunk_end; 187 | if ( chunk_size & 1 && it != body_end ) ++it; 188 | } 189 | else 190 | { 191 | it += chunk_size; 192 | if ( chunk_size & 1 && it != body_end ) ++it; 193 | } 194 | 195 | if ( found_data && found_info ) break; 196 | } 197 | 198 | p_out.set_extra_meta_data( meta_data ); 199 | 200 | return true; 201 | } 202 | -------------------------------------------------------------------------------- /midi_processor_standard_midi.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | bool midi_processor::is_standard_midi( std::vector const& p_file ) 4 | { 5 | if ( p_file.size() < 18 ) return false; 6 | if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'T' || p_file[ 2 ] != 'h' || p_file[ 3 ] != 'd') return false; 7 | if ( p_file[ 4 ] != 0 || p_file[ 5 ] != 0 || p_file[ 6 ] != 0 || p_file[ 7 ] != 6 ) return false; 8 | if ( p_file[ 10 ] == 0 && p_file[ 11 ] == 0 ) return false; // no tracks 9 | if ( p_file[ 12 ] == 0 && p_file[ 13 ] == 0 ) return false; // dtx == 0, will cause division by zero on tempo calculations 10 | return true; 11 | } 12 | 13 | bool midi_processor::process_standard_midi_count( std::vector const& p_file, size_t & track_count ) 14 | { 15 | track_count = 0; 16 | 17 | if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'T' || p_file[ 2 ] != 'h' || p_file[ 3 ] != 'd' ) return false; 18 | 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");*/ 19 | 20 | std::vector::const_iterator it = p_file.begin() + 8; 21 | 22 | uint16_t form = ( it[0] << 8 ) | it[1]; 23 | if ( form > 2 ) return false; 24 | 25 | uint16_t track_count_16 = ( it[2] << 8 ) | it[3]; 26 | 27 | if ( form == 2 ) track_count = track_count_16; 28 | else track_count = 1; 29 | 30 | return true; 31 | } 32 | 33 | void midi_processor::process_standard_midi_track( std::vector::const_iterator & it, std::vector::const_iterator end, midi_container & p_out, bool is_gmf ) 34 | { 35 | bool needs_end_marker = false; 36 | 37 | midi_track track; 38 | unsigned current_timestamp = 0; 39 | unsigned last_event_timestamp = 0; 40 | unsigned char last_event_code = 0xFF; 41 | 42 | unsigned last_sysex_length = 0; 43 | unsigned last_sysex_timestamp = 0; 44 | 45 | std::vector buffer; 46 | buffer.resize( 3 ); 47 | 48 | for (;;) 49 | { 50 | if ( !needs_end_marker && it == end ) break; 51 | int delta = decode_delta( it, end ); 52 | if ( !needs_end_marker && it == end ) break; 53 | 54 | if ( delta < 0 ) 55 | { 56 | /*"MIDI processor encountered negative delta: " << delta << "; flipping sign.";*/ 57 | delta = -delta; 58 | } 59 | 60 | if ( delta > 1000000 ) 61 | break; 62 | 63 | current_timestamp += delta; 64 | if ( it == end ) break; 65 | unsigned char event_code = *it++; 66 | unsigned data_bytes_read = 0; 67 | if ( event_code < 0x80 ) 68 | { 69 | if ( last_event_code == 0xFF ) break; /*throw exception_io_data("First MIDI track event short encoded");*/ 70 | buffer[ data_bytes_read++ ] = event_code; 71 | event_code = last_event_code; 72 | } 73 | if ( event_code < 0xF0 ) 74 | { 75 | if ( last_sysex_length ) 76 | { 77 | track.add_event( midi_event( last_event_timestamp = last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length ) ); 78 | last_sysex_length = 0; 79 | } 80 | 81 | last_event_code = event_code; 82 | if ( is_gmf && ( event_code & 0xF0 ) == 0xE0 ) continue; 83 | if ( data_bytes_read < 1 ) 84 | { 85 | if ( it == end ) break; 86 | buffer[ 0 ] = *it++; 87 | ++data_bytes_read; 88 | } 89 | bool command_valid = true; 90 | switch ( event_code & 0xF0 ) 91 | { 92 | case 0xC0: 93 | case 0xD0: 94 | break; 95 | default: 96 | if ( it == end ) 97 | { 98 | command_valid = false; 99 | break; 100 | } 101 | buffer[ data_bytes_read ] = *it++; 102 | ++data_bytes_read; 103 | } 104 | if ( !command_valid ) break; 105 | track.add_event( midi_event( last_event_timestamp = current_timestamp, (midi_event::event_type)(( event_code >> 4 ) - 8), event_code & 0x0F, &buffer[0], data_bytes_read ) ); 106 | } 107 | else if ( event_code == 0xF0 ) 108 | { 109 | if ( last_sysex_length ) 110 | { 111 | track.add_event( midi_event( last_event_timestamp = last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length ) ); 112 | last_sysex_length = 0; 113 | } 114 | 115 | if ( it == end ) break; 116 | int data_count = decode_delta( it, end ); 117 | if ( data_count < 0 ) break; /*throw exception_io_data( "Invalid System Exclusive message" );*/ 118 | if ( end - it < data_count ) break; 119 | buffer.resize( data_count + 1 ); 120 | buffer[ 0 ] = 0xF0; 121 | std::copy( it, it + data_count, buffer.begin() + 1 ); 122 | it += data_count; 123 | last_sysex_length = data_count + 1; 124 | last_sysex_timestamp = current_timestamp; 125 | } 126 | else if ( event_code == 0xF7 ) // SysEx continuation 127 | { 128 | if ( !last_sysex_length ) break; 129 | if ( it == end ) break; 130 | int data_count = decode_delta( it, end ); 131 | if ( data_count < 0 ) break; 132 | if ( end - it < data_count ) break; 133 | buffer.resize( last_sysex_length + data_count ); 134 | std::copy( it, it + data_count, buffer.begin() + last_sysex_length ); 135 | it += data_count; 136 | last_sysex_length += data_count; 137 | } 138 | else if ( event_code == 0xFF ) 139 | { 140 | if ( last_sysex_length ) 141 | { 142 | track.add_event( midi_event( last_event_timestamp = last_sysex_timestamp, midi_event::extended, 0, &buffer[0], last_sysex_length ) ); 143 | last_sysex_length = 0; 144 | } 145 | 146 | if ( it == end ) break; 147 | unsigned char meta_type = *it++; 148 | if ( it == end ) break; 149 | int data_count = decode_delta( it, end ); 150 | if ( data_count < 0 ) break; /*throw exception_io_data( "Invalid meta message" );*/ 151 | if ( end - it < data_count ) break; 152 | buffer.resize( data_count + 2 ); 153 | buffer[ 0 ] = 0xFF; 154 | buffer[ 1 ] = meta_type; 155 | std::copy( it, it + data_count, buffer.begin() + 2 ); 156 | it += data_count; 157 | if ( meta_type == 0x2F ) 158 | current_timestamp = last_event_timestamp; 159 | else 160 | last_event_timestamp = current_timestamp; 161 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], data_count + 2 ) ); 162 | 163 | if ( meta_type == 0x2F ) 164 | { 165 | needs_end_marker = true; 166 | break; 167 | } 168 | } 169 | else if ( event_code >= 0xF8 && event_code <= 0xFE ) 170 | { 171 | /* Sequencer specific events, single byte */ 172 | buffer[ 0 ] = event_code; 173 | track.add_event( midi_event( last_event_timestamp = current_timestamp, midi_event::extended, 0, &buffer[0], 1 ) ); 174 | } 175 | else break; /*throw exception_io_data("Unhandled MIDI status code");*/ 176 | } 177 | 178 | if ( !needs_end_marker ) 179 | { 180 | buffer[ 0 ] = 0xFF; 181 | buffer[ 1 ] = 0x2F; 182 | track.add_event( midi_event( last_event_timestamp, midi_event::extended, 0, &buffer[0], 2 ) ); 183 | } 184 | 185 | p_out.add_track( track ); 186 | } 187 | 188 | bool midi_processor::process_standard_midi( std::vector const& p_file, midi_container & p_out ) 189 | { 190 | if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'T' || p_file[ 2 ] != 'h' || p_file[ 3 ] != 'd' ) return false; 191 | 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");*/ 192 | 193 | std::vector::const_iterator it = p_file.begin() + 8; 194 | std::vector::const_iterator end = p_file.end(); 195 | 196 | uint16_t form = ( it[0] << 8 ) | it[1]; 197 | if ( form > 2 ) return false; 198 | 199 | uint16_t track_count_16 = ( it[2] << 8 ) | it[3]; 200 | uint16_t dtx = ( it[4] << 8 ) | it[5]; 201 | 202 | if ( !track_count_16 || !dtx ) 203 | return false; 204 | 205 | it += 6; 206 | 207 | std::size_t track_count = track_count_16; 208 | 209 | p_out.initialize( form, dtx ); 210 | 211 | for ( std::size_t i = 0; i < track_count; ++i ) 212 | { 213 | if ( end - it < 8 ) break; 214 | while ( it[0] != 'M' || it[1] != 'T' || it[2] != 'r' || it[3] != 'k' ) { 215 | uint32_t chunk_size = ( it[4] << 24 ) | ( it[5] << 16 ) | ( it[6] << 8 ) | it[7]; 216 | if ( (unsigned long)(end - it) < 8 + chunk_size ) 217 | break; 218 | it += 8 + chunk_size; 219 | if ( end - it < 8 ) break; 220 | } 221 | 222 | if ( end - it < 8 ) break; 223 | 224 | uint32_t track_size = ( it[4] << 24 ) | ( it[5] << 16 ) | ( it[6] << 8 ) | it[7]; 225 | 226 | it += 8; 227 | 228 | intptr_t track_data_offset = it - p_file.begin(); 229 | 230 | if ( (unsigned long)(end - it) < track_size ) 231 | track_size = (uint32_t)(end - it); 232 | 233 | process_standard_midi_track( it, it + track_size, p_out, false ); 234 | 235 | track_data_offset += track_size; 236 | size_t messup_offset = it - p_file.begin(); 237 | if ( messup_offset != track_data_offset ) 238 | { 239 | /* Assume messed up track, attempt to skip it. */ 240 | if ( end - p_file.begin() >= track_data_offset ) 241 | it = p_file.begin() + track_data_offset; 242 | else 243 | break; 244 | } 245 | } 246 | 247 | return !!p_out.get_track_count(); 248 | } 249 | -------------------------------------------------------------------------------- /midi_processor_syx.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | bool midi_processor::is_syx( std::vector const& p_file ) 4 | { 5 | if ( p_file.size() < 2 ) return false; 6 | if ( p_file[ 0 ] != 0xF0 || p_file[ p_file.size() - 1 ] != 0xF7 ) return false; 7 | return true; 8 | } 9 | 10 | bool midi_processor::process_syx( std::vector const& p_file, midi_container & p_out ) 11 | { 12 | const size_t size = p_file.size(); 13 | size_t ptr = 0; 14 | 15 | p_out.initialize( 0, 1 ); 16 | 17 | midi_track track; 18 | 19 | while ( ptr < size ) 20 | { 21 | size_t msg_length = 1; 22 | 23 | if ( p_file[ptr] != 0xF0 ) return false; 24 | 25 | while ( p_file[ptr + msg_length++] != 0xF7 ); 26 | 27 | track.add_event( midi_event( 0, midi_event::extended, 0, &p_file[ptr], msg_length ) ); 28 | 29 | ptr += msg_length; 30 | } 31 | 32 | p_out.add_track( track ); 33 | 34 | return true; 35 | } 36 | -------------------------------------------------------------------------------- /midi_processor_xmi.cpp: -------------------------------------------------------------------------------- 1 | #include "midi_processor.h" 2 | 3 | #include 4 | 5 | bool midi_processor::is_xmi( std::vector const& p_file ) 6 | { 7 | if ( p_file.size() < 0x22 ) return false; 8 | if ( p_file[ 0 ] != 'F' || p_file[ 1 ] != 'O' || p_file[ 2 ] != 'R' || p_file[ 3 ] != 'M' || 9 | p_file[ 8 ] != 'X' || p_file[ 9 ] != 'D' || p_file[ 10 ] != 'I' || p_file[ 11 ] != 'R' || 10 | p_file[ 0x1E ] != 'X' || p_file[ 0x1F ] != 'M' || p_file[ 0x20 ] != 'I' || p_file[ 0x21 ] != 'D' ) return false; 11 | return true; 12 | } 13 | 14 | const uint8_t midi_processor::xmi_default_tempo[5] = {0xFF, 0x51, 0x07, 0xA1, 0x20}; 15 | 16 | unsigned midi_processor::decode_xmi_delta( std::vector::const_iterator & it, std::vector::const_iterator end ) 17 | { 18 | unsigned delta = 0; 19 | if ( it == end ) return 0; 20 | uint8_t byte = *it++; 21 | if ( !( byte & 0x80 ) ) 22 | { 23 | do 24 | { 25 | delta += byte; 26 | if ( it == end ) break; 27 | byte = *it++; 28 | } 29 | while ( !( byte & 0x80 ) && it != end ); 30 | } 31 | --it; 32 | return delta; 33 | } 34 | 35 | struct iff_chunk 36 | { 37 | uint8_t m_id[4]; 38 | uint8_t m_type[4]; 39 | std::vector m_data; 40 | std::vector m_sub_chunks; 41 | 42 | iff_chunk() 43 | { 44 | memset( m_id, 0, sizeof( m_id ) ); 45 | memset( m_type, 0, sizeof( m_type ) ); 46 | } 47 | 48 | iff_chunk( const iff_chunk & p_in ) 49 | { 50 | memcpy( m_id, p_in.m_id, sizeof( m_id ) ); 51 | memcpy( m_type, p_in.m_type, sizeof( m_type ) ); 52 | m_data = p_in.m_data; 53 | m_sub_chunks = p_in.m_sub_chunks; 54 | } 55 | 56 | const iff_chunk & find_sub_chunk( const char * p_id, unsigned index = 0 ) const 57 | { 58 | for ( std::size_t i = 0; i < m_sub_chunks.size(); ++i ) 59 | { 60 | if ( !memcmp( p_id, m_sub_chunks[ i ].m_id, 4 ) ) 61 | { 62 | if ( index ) --index; 63 | if ( !index ) return m_sub_chunks[ i ]; 64 | } 65 | } 66 | /*throw exception_io_data( pfc::string_formatter() << "Missing IFF chunk: " << p_id );*/ 67 | return *this; 68 | } 69 | 70 | unsigned get_chunk_count( const char * p_id ) const 71 | { 72 | unsigned chunk_count = 0; 73 | for ( std::size_t i = 0; i < m_sub_chunks.size(); ++i ) 74 | { 75 | if ( !memcmp( p_id, m_sub_chunks[ i ].m_id, 4 ) ) 76 | { 77 | ++chunk_count; 78 | } 79 | } 80 | return chunk_count; 81 | } 82 | }; 83 | 84 | struct iff_stream 85 | { 86 | std::vector m_chunks; 87 | 88 | iff_chunk fail; 89 | 90 | const iff_chunk & find_chunk( const char * p_id ) const 91 | { 92 | for ( std::size_t i = 0; i < m_chunks.size(); ++i ) 93 | { 94 | if ( !memcmp( p_id, m_chunks[ i ].m_id, 4 ) ) 95 | { 96 | return m_chunks[ i ]; 97 | } 98 | } 99 | /*throw exception_io_data( pfc::string_formatter() << "Missing IFF chunk: " << p_id );*/ 100 | return fail; 101 | } 102 | }; 103 | 104 | static bool read_iff_chunk( std::vector::const_iterator & it, std::vector::const_iterator end, iff_chunk & p_out, bool first_chunk ) 105 | { 106 | if ( end - it < 8 ) return false; 107 | std::copy( it, it + 4, p_out.m_id ); 108 | it += 4; 109 | uint32_t chunk_size = ( it[ 0 ] << 24 ) | ( it[ 1 ] << 16 ) | ( it[ 2 ] << 8 ) | it[ 3 ]; 110 | if ( (unsigned long)(end - it) < chunk_size ) return false; 111 | it += 4; 112 | bool is_cat_chunk = !memcmp( p_out.m_id, "CAT ", 4 ); 113 | bool is_form_chunk = !memcmp( p_out.m_id, "FORM", 4 ); 114 | std::size_t chunk_size_limit = end - it; 115 | if ( chunk_size > chunk_size_limit ) chunk_size = (uint32_t) chunk_size_limit; 116 | if ( ( first_chunk && is_form_chunk ) || ( !first_chunk && is_cat_chunk ) ) 117 | { 118 | if ( end - it < 4 ) return false; 119 | std::vector::const_iterator chunk_end = it + chunk_size; 120 | std::copy( it, it + 4, p_out.m_type ); 121 | it += 4; 122 | while ( it < chunk_end ) 123 | { 124 | iff_chunk chunk; 125 | if ( !read_iff_chunk( it, chunk_end, chunk, is_cat_chunk ) ) return false; 126 | p_out.m_sub_chunks.push_back( chunk ); 127 | } 128 | it = chunk_end; 129 | if ( chunk_size & 1 && it != end ) ++it; 130 | } 131 | else if ( !is_form_chunk && !is_cat_chunk ) 132 | { 133 | p_out.m_data.assign( it, it + chunk_size ); 134 | it += chunk_size; 135 | if ( chunk_size & 1 && it != end ) ++it; 136 | } 137 | else 138 | { 139 | /*if ( first_chunk ) throw exception_io_data( pfc::string_formatter() << "Found " << pfc::string8( (const char *)p_out.m_id, 4 ) << " chunk instead of FORM" ); 140 | else throw exception_io_data( "Found multiple FORM chunks" );*/ 141 | return false; 142 | } 143 | return true; 144 | } 145 | 146 | static bool read_iff_stream( std::vector const& p_file, iff_stream & p_out ) 147 | { 148 | std::vector::const_iterator it = p_file.begin(), end = p_file.end(); 149 | bool first_chunk = true; 150 | while ( it != end ) 151 | { 152 | iff_chunk chunk; 153 | if ( read_iff_chunk( it, end, chunk, first_chunk ) ) 154 | { 155 | p_out.m_chunks.push_back( chunk ); 156 | first_chunk = false; 157 | } 158 | else if ( first_chunk ) 159 | return false; 160 | else 161 | break; 162 | } 163 | return true; 164 | } 165 | 166 | bool midi_processor::process_xmi_count( std::vector const& p_file, size_t & track_count ) 167 | { 168 | track_count = 0; 169 | 170 | iff_stream xmi_file; 171 | if ( !read_iff_stream( p_file, xmi_file ) ) return false; 172 | 173 | const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); 174 | if ( memcmp( form_chunk.m_type, "XDIR", 4 ) ) return false; /*throw exception_io_data( "XMI IFF not XDIR type" );*/ 175 | 176 | const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); 177 | if ( memcmp( cat_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI CAT chunk not XMID type" );*/ 178 | 179 | unsigned _track_count = cat_chunk.get_chunk_count( "FORM" ); 180 | 181 | track_count = _track_count; 182 | 183 | return true; 184 | } 185 | 186 | bool midi_processor::process_xmi( std::vector const& p_file, midi_container & p_out ) 187 | { 188 | iff_stream xmi_file; 189 | if ( !read_iff_stream( p_file, xmi_file ) ) return false; 190 | 191 | const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); 192 | if ( memcmp( form_chunk.m_type, "XDIR", 4 ) ) return false; /*throw exception_io_data( "XMI IFF not XDIR type" );*/ 193 | 194 | const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); 195 | if ( memcmp( cat_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI CAT chunk not XMID type" );*/ 196 | 197 | unsigned track_count = cat_chunk.get_chunk_count( "FORM" ); 198 | 199 | p_out.initialize( track_count > 1 ? 2 : 0, 60 ); 200 | 201 | for ( unsigned i = 0; i < track_count; ++i ) 202 | { 203 | const iff_chunk & xmid_form_chunk = cat_chunk.find_sub_chunk( "FORM", i ); 204 | if ( memcmp( xmid_form_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI nested FORM chunk not XMID type" );*/ 205 | 206 | const iff_chunk & event_chunk = xmid_form_chunk.find_sub_chunk( "EVNT" ); 207 | if ( memcmp( event_chunk.m_id, "EVNT", 4 ) ) return false; /* EVNT chunk not found */ 208 | std::vector const& event_body = event_chunk.m_data; 209 | 210 | midi_track track; 211 | 212 | bool initial_tempo = false; 213 | 214 | unsigned current_timestamp = 0; 215 | 216 | unsigned last_event_timestamp = 0; 217 | 218 | std::vector buffer; 219 | buffer.resize( 3 ); 220 | 221 | std::vector::const_iterator it = event_body.begin(), end = event_body.end(); 222 | 223 | while ( it != end ) 224 | { 225 | unsigned delta = decode_xmi_delta( it, end ); 226 | current_timestamp += delta; 227 | 228 | if ( current_timestamp > last_event_timestamp ) 229 | { 230 | last_event_timestamp = current_timestamp; 231 | } 232 | 233 | if ( it == end ) return false; 234 | buffer[ 0 ] = *it++; 235 | if ( buffer[ 0 ] == 0xFF ) 236 | { 237 | if ( it == end ) return false; 238 | buffer[ 1 ] = *it++; 239 | long meta_count; 240 | if ( buffer[ 1 ] == 0x2F ) 241 | { 242 | meta_count = 0; 243 | } 244 | else 245 | { 246 | meta_count = decode_delta( it, end ); 247 | if ( meta_count < 0 ) return false; /*throw exception_io_data( "Invalid XMI meta message" );*/ 248 | if ( end - it < meta_count ) return false; 249 | buffer.resize( meta_count + 2 ); 250 | std::copy( it, it + meta_count, buffer.begin() + 2 ); 251 | it += meta_count; 252 | } 253 | if ( buffer[ 1 ] == 0x2F && current_timestamp < last_event_timestamp ) 254 | { 255 | current_timestamp = last_event_timestamp; 256 | } 257 | if ( buffer[ 1 ] == 0x51 && meta_count == 3 ) 258 | { 259 | unsigned tempo = buffer[ 2 ] * 0x10000 + buffer[ 3 ] * 0x100 + buffer[ 4 ]; 260 | unsigned ppqn = ( tempo * 3 ) / 25000; 261 | tempo = tempo * 60 / ppqn; 262 | buffer[ 2 ] = tempo / 0x10000; 263 | buffer[ 3 ] = tempo / 0x100; 264 | buffer[ 4 ] = tempo; 265 | if ( current_timestamp == 0 ) initial_tempo = true; 266 | } 267 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], meta_count + 2 ) ); 268 | if ( buffer[ 1 ] == 0x2F ) break; 269 | } 270 | else if ( buffer[ 0 ] == 0xF0 ) 271 | { 272 | long system_exclusive_count = decode_delta( it, end ); 273 | if ( system_exclusive_count < 0 ) return false; /*throw exception_io_data( "Invalid XMI System Exclusive message" );*/ 274 | if ( end - it < system_exclusive_count ) return false; 275 | buffer.resize( system_exclusive_count + 1 ); 276 | std::copy( it, it + system_exclusive_count, buffer.begin() + 1 ); 277 | it += system_exclusive_count; 278 | track.add_event( midi_event( current_timestamp, midi_event::extended, 0, &buffer[0], system_exclusive_count + 1 ) ); 279 | } 280 | else if ( buffer[ 0 ] >= 0x80 && buffer[ 0 ] <= 0xEF ) 281 | { 282 | unsigned bytes_read = 1; 283 | if ( it == end ) return false; 284 | buffer[ 1 ] = *it++; 285 | midi_event::event_type type = (midi_event::event_type)( ( buffer[ 0 ] >> 4 ) - 8 ); 286 | unsigned channel = buffer[ 0 ] & 0x0F; 287 | if ( type != midi_event::program_change && type != midi_event::channel_aftertouch ) 288 | { 289 | if ( it == end ) return false; 290 | buffer[ 2 ] = *it++; 291 | bytes_read = 2; 292 | } 293 | track.add_event( midi_event( current_timestamp, type, channel, &buffer[1], bytes_read ) ); 294 | if ( type == midi_event::note_on ) 295 | { 296 | buffer[ 2 ] = 0x00; 297 | int note_length = decode_delta( it, end ); 298 | if ( note_length < 0 ) return false; /*throw exception_io_data( "Invalid XMI note message" );*/ 299 | unsigned note_end_timestamp = current_timestamp + note_length; 300 | if ( note_end_timestamp > last_event_timestamp ) last_event_timestamp = note_end_timestamp; 301 | track.add_event( midi_event( note_end_timestamp, type, channel, &buffer[1], bytes_read ) ); 302 | } 303 | } 304 | else return false; /*throw exception_io_data( "Unexpected XMI status code" );*/ 305 | } 306 | 307 | if ( !initial_tempo ) 308 | track.add_event( midi_event( 0, midi_event::extended, 0, xmi_default_tempo, _countof( xmi_default_tempo ) ) ); 309 | 310 | p_out.add_track( track ); 311 | } 312 | 313 | return true; 314 | } 315 | --------------------------------------------------------------------------------