Skip to content

Commit

Permalink
Handle real-time MIDI messages correctly - seen in issue #52
Browse files Browse the repository at this point in the history
Added handling of split SysEx messages per RFC9295 pg 18
  • Loading branch information
ravelox committed May 4, 2020
1 parent c46bbb5 commit 9c3b93a
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 14 deletions.
2 changes: 1 addition & 1 deletion raveloxmidi/include/midi_command.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ enum midi_message_type_t {
MIDI_SONG_SELECT,
MIDI_TUNE_REQUEST,
MIDI_END_SYSEX,
MIDI_TIMING_CLOCK,
MIDI_TIMING_CLOCK = 0xf8,
MIDI_START,
MIDI_CONTINUE,
MIDI_STOP,
Expand Down
1 change: 1 addition & 0 deletions raveloxmidi/include/midi_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef struct midi_state_t {
dbuffer_t *hold;
pthread_mutex_t lock;
uint64_t current_delta;
uint8_t partial_sysex;
} midi_state_t;

midi_state_t *midi_state_create( size_t size );
Expand Down
5 changes: 2 additions & 3 deletions raveloxmidi/src/data_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,11 @@ void data_table_destroy( data_table_t **table )
{
if( ! *table ) return;

logging_printf(LOGGING_DEBUG,"data_table_destroy\n");

data_table_dump( *table );

data_table_lock( *table );

logging_printf(LOGGING_DEBUG,"data_table_destroy: table=%p, name=[%s]\n", *table, ( (*table)->name ? (*table)->name : "" ) );

if( (*table)->items )
{
size_t index = 0;
Expand Down
19 changes: 12 additions & 7 deletions raveloxmidi/src/midi_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,22 @@ void midi_command_set( midi_command_t *command, uint64_t delta, uint8_t status,

command->delta = delta;
command->status = status;
command->data = NULL;
command->data_len = 0;

command->data = ( char * ) malloc( data_len );
if( ! command->data )
if( data )
{
logging_printf( LOGGING_ERROR, "midi_command_set: Insufficient memory to create command data buffer\n");
command->data = ( char * ) malloc( data_len );
if( ! command->data )
{
logging_printf( LOGGING_ERROR, "midi_command_set: Insufficient memory to create command data buffer\n");
return;
}
}

memset( command->data, 0, data_len );
memcpy( command->data, data, data_len );
command->data_len = data_len;
memset( command->data, 0, data_len );
memcpy( command->data, data, data_len );
command->data_len = data_len;
}
}

void midi_command_dump( void *data )
Expand Down
44 changes: 41 additions & 3 deletions raveloxmidi/src/midi_state.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
This file is part of raveloxmidi.
This file is part of raveloxmidi
Copyright (C) 2020 Dave Kelly
Expand Down Expand Up @@ -71,6 +71,7 @@ midi_state_t *midi_state_create( size_t buffer_size )
new_midi_state->hold = dbuffer_create( DBUFFER_DEFAULT_BLOCK_SIZE );
new_midi_state->ring = ring_buffer_create( buffer_size );
new_midi_state->running_status = 0;
new_midi_state->partial_sysex = 0;
pthread_mutex_init( &(new_midi_state->lock) , NULL);

return new_midi_state;
Expand Down Expand Up @@ -281,6 +282,23 @@ void midi_state_to_commands( midi_state_t *state , data_table_t **command_table,
state->current_delta <<= 8;
state->current_delta += ( byte & 0x7f );
if( byte & 0x80 ) state->status = MIDI_STATE_WAIT_COMMAND;
logging_printf( LOGGING_DEBUG, "midi_state_to_commands: delta=%lu\n", state->current_delta);
continue;
// Check for real-time MIDI messages that should go through at any time
} else {
if( byte >= MIDI_TIMING_CLOCK )
{
logging_printf( LOGGING_DEBUG, "midi_state_to_commands: real-time message: message=0x%02x\n", byte);
new_command = midi_command_create();
if( ! new_command )
{
logging_printf( LOGGING_DEBUG, "midi_state_to_commands: real-time: Insufficient memory to create command structure\n");
continue;
}
midi_command_set( new_command, state->current_delta, byte, NULL, 0);
data_table_add_item( *command_table, new_command );
continue;
}
}

if( state->status == MIDI_STATE_WAIT_COMMAND )
Expand Down Expand Up @@ -315,9 +333,18 @@ void midi_state_to_commands( midi_state_t *state , data_table_t **command_table,
dbuffer_write( state->hold, &byte, 1);

// Special cases for SysEx
if( byte == 0xF0 )
if( (byte == 0xF0) || ( state->partial_sysex && (byte==0xF7) ) )
{
if( (byte == 0xF0) && (state->partial_sysex == 1) )
{
logging_printf( LOGGING_DEBUG, "midi_state_to_commands: SYSEX 0xF0 read: Expected 0xF7\n");
}
state->status = MIDI_STATE_WAIT_END_SYSEX;
state->running_status = 0;
// RFC6295 - p 19 - Unpaired 0xF7 cancels running status
} else if( byte == MIDI_END_SYSEX ) {
state->status = MIDI_STATE_COMMAND_RECEIVED;
state->running_status = 0;
} else {
bytes_needed = midi_command_bytes_needed( byte & 0xF0 );
logging_printf( LOGGING_DEBUG, "midi_state_to_commands: command byte received: need=%d\n", bytes_needed );
Expand Down Expand Up @@ -366,10 +393,21 @@ void midi_state_to_commands( midi_state_t *state , data_table_t **command_table,
// Copy byte to hold buffer
dbuffer_write( state->hold, &byte, 1 );

if( byte == 0xF7 )
if( (byte==0xF7) || ((state->partial_sysex==1) && (byte==0xF4)) )
{
state->status = MIDI_STATE_COMMAND_RECEIVED;
state->partial_sysex = 0;
}

if( byte == 0xF0 )
{
state->status = MIDI_STATE_COMMAND_RECEIVED;
state->partial_sysex = 1;
}

// Clear the running status
state->running_status = 0;

goto midi_state_to_commands_end;
}

Expand Down

0 comments on commit 9c3b93a

Please sign in to comment.