Attempt to always emit the correct number of NOTE ONs and NOTE OFFs.
This commit is contained in:
parent
614fea7343
commit
0e946a9f73
87
src/jack.C
87
src/jack.C
|
@ -56,10 +56,11 @@ const int subticks_per_tick = 4096;
|
||||||
* purpose). Decremented in each process cycle, when this value
|
* purpose). Decremented in each process cycle, when this value
|
||||||
* reaches zero, a note off is generated--regardless of the state of
|
* reaches zero, a note off is generated--regardless of the state of
|
||||||
* the transport */
|
* the transport */
|
||||||
int notes_on[MAX_PORT][16][128];
|
int note_duration[MAX_PORT][16][128];
|
||||||
|
|
||||||
/* number of notes currently playing on each port */
|
/* tracks the number of concurrent note ons for the same note so that
|
||||||
int port_notes_on[MAX_PORT];
|
* we can be sure to emit the correct number of note offs */
|
||||||
|
int notes_on[MAX_PORT][16][128];
|
||||||
|
|
||||||
typedef unsigned char byte_t;
|
typedef unsigned char byte_t;
|
||||||
|
|
||||||
|
@ -110,7 +111,33 @@ midi_output_event ( int port, const midievent *e )
|
||||||
|
|
||||||
*fe = *e;
|
*fe = *e;
|
||||||
|
|
||||||
output[ port ].events.insert( fe );
|
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 );
|
||||||
|
|
||||||
|
--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 ( duration )
|
||||||
{
|
{
|
||||||
if ( notes_on[ port ][ e->channel() ][ e->note() ] > transport.ticks_per_period * subticks_per_tick )
|
note_duration[ port ][ e->channel() ][ e->note() ] = (duration + e->timestamp()) * subticks_per_tick;
|
||||||
DWARNING( "duplicate note on?" );
|
midi_output_event( port, e );
|
||||||
else
|
|
||||||
{
|
|
||||||
notes_on[ port ][ e->channel() ][ e->note() ] = (duration + e->timestamp()) * subticks_per_tick;
|
|
||||||
|
|
||||||
++port_notes_on[ port ];
|
|
||||||
|
|
||||||
midi_output_event( port, e );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* We allow duplicate notes on and pass notes off through as
|
||||||
/* if ( notes_on[ port ][ e->channel() ][ e->note() ] ) */
|
* is in order to support poly synths. */
|
||||||
/* WARNING( "note still on when note-off came" ); */
|
midi_output_event( port, e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,8 +195,7 @@ midi_output_immediate_event ( int port, const midievent *e )
|
||||||
if ( e->is_note_on() )
|
if ( e->is_note_on() )
|
||||||
{
|
{
|
||||||
/* use timestamp as duration */
|
/* use timestamp as duration */
|
||||||
notes_on[ port ][ e->channel() ][ e->note() ] = e->timestamp() * subticks_per_tick;
|
note_duration[ port ][ e->channel() ][ e->note() ] = e->timestamp() * subticks_per_tick;
|
||||||
++port_notes_on[ port ];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,34 +373,33 @@ schedule:
|
||||||
output[ i ].buf = jack_port_get_buffer( output[ i ].port, nframes );
|
output[ i ].buf = jack_port_get_buffer( output[ i ].port, nframes );
|
||||||
jack_midi_clear_buffer( output[ i ].buf );
|
jack_midi_clear_buffer( output[ i ].buf );
|
||||||
|
|
||||||
if ( port_notes_on[ i ] > 0 )
|
|
||||||
{
|
|
||||||
/* handle scheduled note offs */
|
/* handle scheduled note offs */
|
||||||
for ( uint j = 16; j-- ; )
|
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 )
|
for ( register uint k = 0; k < 128; ++note, ++k )
|
||||||
if ( *note )
|
if ( *note > 0 )
|
||||||
if ( ( *note -= subticks_per_period ) <= 0 )
|
if ( ( *note -= subticks_per_period ) <= 0 )
|
||||||
{
|
{
|
||||||
static midievent e;
|
while ( notes_on[ i ][ j ][ k] > 0 )
|
||||||
|
{
|
||||||
|
static midievent e;
|
||||||
|
|
||||||
e.status( midievent::NOTE_OFF );
|
e.status( midievent::NOTE_OFF );
|
||||||
e.channel( j );
|
e.channel( j );
|
||||||
e.note( k );
|
e.note( k );
|
||||||
e.note_velocity( 64 );
|
e.note_velocity( 64 );
|
||||||
|
|
||||||
e.timestamp( (subticks_per_period + *note) / subticks_per_tick );
|
e.timestamp( (subticks_per_period + *note) / subticks_per_tick );
|
||||||
|
|
||||||
|
midi_output_event( i, &e );
|
||||||
|
}
|
||||||
|
|
||||||
*note = 0;
|
*note = 0;
|
||||||
--port_notes_on[ i ];
|
|
||||||
|
|
||||||
midi_output_event( i, &e );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static midievent e;
|
static midievent e;
|
||||||
/* first, write any immediate events from the UI thread */
|
/* first, write any immediate events from the UI thread */
|
||||||
|
@ -452,10 +469,12 @@ midi_init ( void )
|
||||||
/* clear notes */
|
/* clear notes */
|
||||||
for ( int p = MAX_PORT; p--; )
|
for ( int p = MAX_PORT; p--; )
|
||||||
{
|
{
|
||||||
port_notes_on[ p ] = 0;
|
|
||||||
for ( int c = 16; c-- ; )
|
for ( int c = 16; c-- ; )
|
||||||
for ( int n = 128; n-- ; )
|
for ( int n = 128; n-- ; )
|
||||||
|
{
|
||||||
|
note_duration[ p ][ c ][ n ] = 0;
|
||||||
notes_on[ p ][ c ][ n ] = 0;
|
notes_on[ p ][ c ][ n ] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//1 jack_set_buffer_size_callback( client, bufsize, 0 );
|
//1 jack_set_buffer_size_callback( client, bufsize, 0 );
|
||||||
|
|
Loading…
Reference in New Issue