From 0e946a9f7382ba27a4ba5c88aaf297145c27a2a4 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Mon, 27 Feb 2012 00:02:11 -0800 Subject: [PATCH] Attempt to always emit the correct number of NOTE ONs and NOTE OFFs. --- src/jack.C | 91 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/jack.C b/src/jack.C index 76a7ff8..0ee317e 100644 --- a/src/jack.C +++ b/src/jack.C @@ -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 );