| @@ -56,10 +56,11 @@ const int subticks_per_tick = 4096; | |||
| * purpose). Decremented in each process cycle, when this value | |||
| * reaches zero, a note off is generated--regardless of the state of | |||
| * the transport */ | |||
| int notes_on[MAX_PORT][16][128]; | |||
| int note_duration[MAX_PORT][16][128]; | |||
| /* number of notes currently playing on each port */ | |||
| int port_notes_on[MAX_PORT]; | |||
| /* tracks the number of concurrent note ons for the same note so that | |||
| * we can be sure to emit the correct number of note offs */ | |||
| int notes_on[MAX_PORT][16][128]; | |||
| typedef unsigned char byte_t; | |||
| @@ -109,8 +110,34 @@ midi_output_event ( int port, const midievent *e ) | |||
| freelist.unlink( fe ); | |||
| *fe = *e; | |||
| if ( e->is_note_on() ) | |||
| { | |||
| if ( notes_on[ port ][ e->channel() ][ e->note() ] == 0 ) | |||
| { | |||
| output[ port ].events.insert( fe ); | |||
| ++notes_on[ port ][ e->channel() ][ e->note() ]; | |||
| } | |||
| else | |||
| { | |||
| DMESSAGE( "Dropping extra Note ON" ); | |||
| } | |||
| } | |||
| else if ( e->is_note_off() ) | |||
| { | |||
| if ( notes_on[ port ][ e->channel() ][ e->note() ] == 0 ) | |||
| { | |||
| DMESSAGE( "Dropping extra Note OFF" ); | |||
| WARNING( "Extra Note OFF" ); | |||
| } | |||
| else | |||
| { | |||
| output[ port ].events.insert( fe ); | |||
| output[ port ].events.insert( fe ); | |||
| --notes_on[ port ][ e->channel() ][ e->note() ]; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -120,22 +147,14 @@ midi_output_event ( int port, const midievent *e, tick_t duration ) | |||
| { | |||
| if ( duration ) | |||
| { | |||
| if ( notes_on[ port ][ e->channel() ][ e->note() ] > transport.ticks_per_period * subticks_per_tick ) | |||
| DWARNING( "duplicate note on?" ); | |||
| else | |||
| { | |||
| notes_on[ port ][ e->channel() ][ e->note() ] = (duration + e->timestamp()) * subticks_per_tick; | |||
| ++port_notes_on[ port ]; | |||
| midi_output_event( port, e ); | |||
| } | |||
| note_duration[ port ][ e->channel() ][ e->note() ] = (duration + e->timestamp()) * subticks_per_tick; | |||
| midi_output_event( port, e ); | |||
| } | |||
| else | |||
| { | |||
| /* if ( notes_on[ port ][ e->channel() ][ e->note() ] ) */ | |||
| /* WARNING( "note still on when note-off came" ); */ | |||
| /* We allow duplicate notes on and pass notes off through as | |||
| * is in order to support poly synths. */ | |||
| midi_output_event( port, e ); | |||
| } | |||
| } | |||
| @@ -176,8 +195,7 @@ midi_output_immediate_event ( int port, const midievent *e ) | |||
| if ( e->is_note_on() ) | |||
| { | |||
| /* use timestamp as duration */ | |||
| notes_on[ port ][ e->channel() ][ e->note() ] = e->timestamp() * subticks_per_tick; | |||
| ++port_notes_on[ port ]; | |||
| note_duration[ port ][ e->channel() ][ e->note() ] = e->timestamp() * subticks_per_tick; | |||
| } | |||
| } | |||
| @@ -355,34 +373,33 @@ schedule: | |||
| output[ i ].buf = jack_port_get_buffer( output[ i ].port, nframes ); | |||
| jack_midi_clear_buffer( output[ i ].buf ); | |||
| if ( port_notes_on[ i ] > 0 ) | |||
| { | |||
| /* handle scheduled note offs */ | |||
| for ( uint j = 16; j-- ; ) | |||
| { | |||
| register int *note = ¬es_on[ i ][ j ][ 0 ]; | |||
| register int *note = ¬e_duration[ i ][ j ][ 0 ]; | |||
| for ( register uint k = 0; k < 128; ++note, ++k ) | |||
| if ( *note ) | |||
| if ( *note > 0 ) | |||
| if ( ( *note -= subticks_per_period ) <= 0 ) | |||
| { | |||
| static midievent e; | |||
| e.status( midievent::NOTE_OFF ); | |||
| e.channel( j ); | |||
| e.note( k ); | |||
| e.note_velocity( 64 ); | |||
| e.timestamp( (subticks_per_period + *note) / subticks_per_tick ); | |||
| while ( notes_on[ i ][ j ][ k] > 0 ) | |||
| { | |||
| static midievent e; | |||
| e.status( midievent::NOTE_OFF ); | |||
| e.channel( j ); | |||
| e.note( k ); | |||
| e.note_velocity( 64 ); | |||
| e.timestamp( (subticks_per_period + *note) / subticks_per_tick ); | |||
| midi_output_event( i, &e ); | |||
| } | |||
| *note = 0; | |||
| --port_notes_on[ i ]; | |||
| midi_output_event( i, &e ); | |||
| } | |||
| } | |||
| } | |||
| static midievent e; | |||
| /* first, write any immediate events from the UI thread */ | |||
| @@ -452,10 +469,12 @@ midi_init ( void ) | |||
| /* clear notes */ | |||
| for ( int p = MAX_PORT; p--; ) | |||
| { | |||
| port_notes_on[ p ] = 0; | |||
| for ( int c = 16; c-- ; ) | |||
| for ( int n = 128; n-- ; ) | |||
| { | |||
| note_duration[ p ][ c ][ n ] = 0; | |||
| notes_on[ p ][ c ][ n ] = 0; | |||
| } | |||
| } | |||
| //1 jack_set_buffer_size_callback( client, bufsize, 0 ); | |||