diff --git a/Frameworks/midi_processing/midi_processing/midi_processor.h b/Frameworks/midi_processing/midi_processing/midi_processor.h index fac8b94f4..23cace4b0 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor.h +++ b/Frameworks/midi_processing/midi_processing/midi_processor.h @@ -51,8 +51,14 @@ class midi_processor static bool process_lds( std::vector const& p_file, midi_container & p_out ); static bool process_gmf( std::vector const& p_file, midi_container & p_out ); static bool process_syx( std::vector const& p_file, midi_container & p_out ); + + static bool process_standard_midi_count( std::vector const& p_file, size_t & track_count ); + static bool process_riff_midi_count( std::vector const& p_file, size_t & track_count ); + static bool process_xmi_count( std::vector const& p_file, size_t & track_count ); public: + static bool process_track_count( std::vector const& p_file, const char * p_extension, size_t & track_count ); + static bool process_file( std::vector const& p_file, const char * p_extension, midi_container & p_out ); static bool process_syx_file( std::vector const& p_file, midi_container & p_out ); diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp index 9175555b8..96ebaf4cf 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_helpers.cpp @@ -67,3 +67,52 @@ bool midi_processor::process_syx_file( std::vector const& p_file, midi_ } else return false; } + +bool midi_processor::process_track_count( std::vector const& p_file, const char * p_extension, size_t & track_count ) +{ + track_count = 0; + + if ( is_standard_midi( p_file ) ) + { + return process_standard_midi_count( p_file, track_count ); + } + else if ( is_riff_midi( p_file ) ) + { + return process_riff_midi_count( p_file, track_count ); + } + else if ( is_hmp( p_file ) ) + { + track_count = 1; + return true; + } + else if ( is_hmi( p_file ) ) + { + track_count = 1; + return true; + } + else if ( is_xmi( p_file ) ) + { + return process_xmi_count( p_file, track_count ); + } + else if ( is_mus( p_file ) ) + { + track_count = 1; + return true; + } + else if ( is_mids( p_file ) ) + { + track_count = 1; + return true; + } + else if ( is_lds( p_file, p_extension ) ) + { + track_count = 1; + return true; + } + else if ( is_gmf( p_file ) ) + { + track_count = 1; + return true; + } + else return false; +} diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp index af19255d9..bd32906b2 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_riff_midi.cpp @@ -17,10 +17,43 @@ bool midi_processor::is_riff_midi( std::vector const& p_file ) return is_standard_midi( test ); } +bool midi_processor::process_riff_midi_count( std::vector const& p_file, size_t & track_count ) +{ + track_count = 0; + + uint32_t file_size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 ); + + std::vector::const_iterator it = p_file.begin() + 12; + + std::vector::const_iterator body_end = p_file.begin() + 8 + file_size; + + std::vector extra_buffer; + + while ( it != body_end ) + { + if ( body_end - it < 8 ) return false; + uint32_t chunk_size = it[ 4 ] | ( it[ 5 ] << 8 ) | ( it[ 6 ] << 16 ) | ( it[ 7 ] << 24 ); + if ( (unsigned long)(body_end - it) < chunk_size ) return false; + if ( it[ 0 ] == 'd' && it[ 1 ] == 'a' && it[ 2 ] == 't' && it[ 3 ] == 'a' ) + { + std::vector midi_file; + midi_file.assign( it + 8, it + 8 + chunk_size ); + return process_standard_midi_count( midi_file, track_count ); + } + else + { + it += chunk_size; + if ( chunk_size & 1 && it != body_end ) ++it; + } + } + + return false; +} + static const char * riff_tag_mappings[][2] = { - { "IALB", "album" }, - { "IARL", "archival_location" }, + { "IALB", "album" }, + { "IARL", "archival_location" }, { "IART", "artist" }, { "ITRK", "tracknumber" }, { "ICMS", "commissioned" }, diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp index 6e0b1f18f..02e3a7242 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_standard_midi.cpp @@ -9,6 +9,26 @@ bool midi_processor::is_standard_midi( std::vector const& p_file ) return true; } +bool midi_processor::process_standard_midi_count( std::vector const& p_file, size_t & track_count ) +{ + track_count = 0; + + if ( p_file[ 0 ] != 'M' || p_file[ 1 ] != 'T' || p_file[ 2 ] != 'h' || p_file[ 3 ] != 'd' ) return false; + if ( p_file[ 4 ] != 0 || p_file[ 5 ] != 0 || p_file[ 6 ] != 0 || p_file[ 7 ] != 6 ) return false; /*throw exception_io_data("Bad MIDI header size");*/ + + std::vector::const_iterator it = p_file.begin() + 8; + + uint16_t form = ( it[0] << 8 ) | it[1]; + if ( form > 2 ) return false; + + uint16_t track_count_16 = ( it[2] << 8 ) | it[3]; + + if ( form == 2 ) track_count = track_count_16; + else track_count = 1; + + return true; +} + bool midi_processor::process_standard_midi_track( std::vector::const_iterator & it, std::vector::const_iterator end, midi_container & p_out, bool needs_end_marker ) { midi_track track; diff --git a/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp b/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp index c1c8f028c..71a3b969f 100644 --- a/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp +++ b/Frameworks/midi_processing/midi_processing/midi_processor_xmi.cpp @@ -163,9 +163,29 @@ static bool read_iff_stream( std::vector const& p_file, iff_stream & p_ return true; } +bool midi_processor::process_xmi_count( std::vector const& p_file, size_t & track_count ) +{ + track_count = 0; + + iff_stream xmi_file; + if ( !read_iff_stream( p_file, xmi_file ) ) return false; + + const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); + if ( memcmp( form_chunk.m_type, "XDIR", 4 ) ) return false; /*throw exception_io_data( "XMI IFF not XDIR type" );*/ + + const iff_chunk & cat_chunk = xmi_file.find_chunk( "CAT " ); + if ( memcmp( cat_chunk.m_type, "XMID", 4 ) ) return false; /*throw exception_io_data( "XMI CAT chunk not XMID type" );*/ + + unsigned _track_count = cat_chunk.get_chunk_count( "FORM" ); + + track_count = _track_count; + + return true; +} + bool midi_processor::process_xmi( std::vector const& p_file, midi_container & p_out ) { - iff_stream xmi_file; + iff_stream xmi_file; if ( !read_iff_stream( p_file, xmi_file ) ) return false; const iff_chunk & form_chunk = xmi_file.find_chunk( "FORM" ); diff --git a/Plugins/MIDI/MIDI/MIDIContainer.mm b/Plugins/MIDI/MIDI/MIDIContainer.mm index 0e791a768..1d7a99fd8 100755 --- a/Plugins/MIDI/MIDI/MIDIContainer.mm +++ b/Plugins/MIDI/MIDI/MIDIContainer.mm @@ -40,10 +40,10 @@ id source = [audioSourceClass audioSourceForURL:url]; if (![source open:url]) - return 0; + return [NSArray array]; if (![source seekable]) - return 0; + return [NSArray array]; [source seek:0 whence:SEEK_END]; long size = [source tell]; @@ -53,18 +53,16 @@ data.resize( size ); [source read:&data[0] amount:size]; - midi_container midi_file; + size_t track_count = 0; - if ( !midi_processor::process_file( data, [[url pathExtension] UTF8String], midi_file) ) - return 0; + if ( !midi_processor::process_track_count( data, [[url pathExtension] UTF8String], track_count) ) + return [NSArray array]; - long track_count = midi_file.get_subsong_count(); - NSMutableArray *tracks = [NSMutableArray array]; long i; for (i = 0; i < track_count; i++) { - [tracks addObject:[NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:@"#%li", midi_file.get_subsong( i )]]]; + [tracks addObject:[NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:@"#%li", i]]]; } return tracks;