137 lines
5.1 KiB
C++
137 lines
5.1 KiB
C++
#include "midi_processor.h"
|
|
|
|
bool midi_processor::is_mids( std::vector<uint8_t> const& p_file )
|
|
{
|
|
if ( p_file.size() < 8 ) return false;
|
|
if ( p_file[ 0 ] != 'R' || p_file[ 1 ] != 'I' || p_file[ 2 ] != 'F' || p_file[ 3 ] != 'F' ) return false;
|
|
uint32_t size = p_file[ 4 ] | ( p_file[ 5 ] << 8 ) | ( p_file[ 6 ] << 16 ) | ( p_file[ 7 ] << 24 );
|
|
if ( size < 8 || ( p_file.size() < size + 8 ) ) return false;
|
|
if ( p_file[ 8 ] != 'M' || p_file[ 9 ] != 'I' || p_file[ 10 ] != 'D' || p_file[ 11 ] != 'S' ||
|
|
p_file[ 12 ] != 'f' || p_file[ 13 ] != 'm' || p_file[ 14 ] != 't' || p_file[ 15 ] != ' ' ) return false;
|
|
return true;
|
|
}
|
|
|
|
bool midi_processor::process_mids( std::vector<uint8_t> const& p_file, midi_container & p_out )
|
|
{
|
|
if ( p_file.size() < 20 ) return false;
|
|
std::vector<uint8_t>::const_iterator it = p_file.begin() + 16;
|
|
std::vector<uint8_t>::const_iterator end = p_file.end();
|
|
|
|
uint32_t fmt_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
if ( (unsigned long)(end - it) < fmt_size ) return false;
|
|
|
|
uint32_t time_format = 1;
|
|
/*uint32_t max_buffer = 0;*/
|
|
uint32_t flags = 0;
|
|
|
|
if ( fmt_size >= 4 )
|
|
{
|
|
time_format = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
fmt_size -= 4;
|
|
if ( !time_format ) // dtx == 0, will cause division by zero on tempo calculations
|
|
return false;
|
|
}
|
|
if ( fmt_size >= 4 )
|
|
{
|
|
/*max_buffer = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );*/
|
|
it += 4;
|
|
fmt_size -= 4;
|
|
}
|
|
if ( fmt_size >= 4 )
|
|
{
|
|
flags = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
fmt_size -= 4;
|
|
}
|
|
|
|
it += fmt_size;
|
|
if ( it == end ) return false;
|
|
if ( fmt_size & 1 ) ++it;
|
|
|
|
p_out.initialize( 0, time_format );
|
|
|
|
if ( end - it < 4 ) return false;
|
|
if ( it[ 0 ] != 'd' || it[ 1 ] != 'a' || it[ 2 ] != 't' || it[ 3 ] != 'a' ) return false; /*throw exception_io_data( "MIDS missing RIFF data chunk" );*/
|
|
|
|
it += 4;
|
|
|
|
{
|
|
midi_track track;
|
|
track.add_event( midi_event( 0, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
|
|
p_out.add_track( track );
|
|
}
|
|
|
|
if ( end - it < 4 ) return false;
|
|
uint32_t data_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
|
|
std::vector<uint8_t>::const_iterator body_end = it + data_size;
|
|
|
|
if ( body_end - it < 4 ) return false;
|
|
uint32_t segment_count = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
|
|
bool is_eight_byte = !!(flags & 1);
|
|
|
|
midi_track track;
|
|
|
|
unsigned current_timestamp = 0;
|
|
|
|
for ( unsigned i = 0; i < segment_count; ++i )
|
|
{
|
|
if ( end - it < 12 ) return false;
|
|
it += 4;
|
|
uint32_t segment_size = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
std::vector<uint8_t>::const_iterator segment_end = it + segment_size;
|
|
while ( it != segment_end && it != body_end )
|
|
{
|
|
if ( segment_end - it < 4 ) return false;
|
|
uint32_t delta = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
uint32_t event;
|
|
current_timestamp += delta;
|
|
if ( !is_eight_byte )
|
|
{
|
|
if ( segment_end - it < 4 ) return false;
|
|
it += 4;
|
|
}
|
|
if ( segment_end - it < 4 ) return false;
|
|
event = it[ 0 ] | ( it[ 1 ] << 8 ) | ( it[ 2 ] << 16 ) | ( it[ 3 ] << 24 );
|
|
it += 4;
|
|
if ( event >> 24 == 0x01 )
|
|
{
|
|
uint8_t buffer[ 5 ] = { 0xFF, 0x51 };
|
|
buffer[ 2 ] = (uint8_t)( event >> 16 );
|
|
buffer[ 3 ] = (uint8_t)( event >> 8 );
|
|
buffer[ 4 ] = (uint8_t)event;
|
|
p_out.add_track_event( 0, midi_event( current_timestamp, midi_event::extended, 0, buffer, sizeof( buffer ) ) );
|
|
}
|
|
else if ( !( event >> 24 ) )
|
|
{
|
|
unsigned event_code = ( event & 0xF0 ) >> 4;
|
|
if ( event_code >= 0x8 && event_code <= 0xE )
|
|
{
|
|
unsigned bytes_to_write = 1;
|
|
uint8_t buffer[2];
|
|
buffer[ 0 ] = (uint8_t)( event >> 8 );
|
|
if ( event_code != 0xC && event_code != 0xD )
|
|
{
|
|
buffer[ 1 ] = (uint8_t)( event >> 16 );
|
|
bytes_to_write = 2;
|
|
}
|
|
track.add_event( midi_event( current_timestamp, (midi_event::event_type)( event_code - 8 ), event & 0x0F, buffer, bytes_to_write ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
track.add_event( midi_event( current_timestamp, midi_event::extended, 0, end_of_track, _countof( end_of_track ) ) );
|
|
|
|
p_out.add_track( track );
|
|
|
|
return true;
|
|
}
|