Change the way patterns are triggered in sequence mode.

Now patterns should be triggered properly even if we come in in the
middle of a phrase, as happens when randomly relocating the transport.
This commit is contained in:
Jonathan Moore Liles 2008-06-15 12:19:26 -05:00
parent 81f504f88b
commit d70dd3a517
4 changed files with 69 additions and 48 deletions

View File

@ -5,7 +5,6 @@
; General ; General
* TODO: {3} fix transport seeking to the middle of a phrase/pattern in Sequence Mode.
* TODO: {3} deal with dropped ticks from timebase master better when running as slave. * TODO: {3} deal with dropped ticks from timebase master better when running as slave.
* TODO: {2} move keybindings into menus for discoverability (like in Non-DAW) * TODO: {2} move keybindings into menus for discoverability (like in Non-DAW)
* TODO: {2} improve or get rid of the transport.valid test at initialization time. * TODO: {2} improve or get rid of the transport.valid test at initialization time.

View File

@ -202,6 +202,48 @@ midi_all_sound_off ( void )
} }
} }
static void
stop_all_patterns ( void )
{
for ( uint i = pattern::patterns(); i--; )
{
pattern *p = pattern::pattern_by_number( i + 1 );
p->stop();
}
}
static int
sync ( jack_transport_state_t state, jack_position_t *pos, void * )
{
static bool seeking = false;
switch ( state )
{
case JackTransportStopped: /* new position requested */
/* JACK docs lie. This is only called when the transport
is *really* stopped, not when starting a slow-sync
cycle */
stop_all_patterns();
return 1;
case JackTransportStarting: /* this means JACK is polling slow-sync clients */
{
stop_all_patterns();
return 1;
}
case JackTransportRolling: /* JACK's timeout has expired */
/* FIXME: what's the right thing to do here? */
// request_locate( pos->frame );
return 1;
break;
default:
WARNING( "unknown transport state" );
}
return 0;
}
static int static int
process ( jack_nframes_t nframes, void *arg ) process ( jack_nframes_t nframes, void *arg )
{ {
@ -246,29 +288,12 @@ process ( jack_nframes_t nframes, void *arg )
{ {
case PATTERN: case PATTERN:
case TRIGGER: case TRIGGER:
{ stop_all_patterns();
// stop all patterns.
for ( uint i = pattern::patterns(); i--; )
{
pattern *p = pattern::pattern_by_number( i + 1 );
p->stop();
}
break; break;
}
} }
switch ( song.play_mode ) switch ( song.play_mode )
{ {
case SEQUENCE: case SEQUENCE:
// first handle patterns already playing
for ( uint i = pattern::patterns(); i--; )
{
pattern *p = pattern::pattern_by_number( i + 1 );
if ( p && p->playing() )
p->play( ph, nph );
}
playlist->play( ph, nph ); playlist->play( ph, nph );
break; break;
case PATTERN: case PATTERN:
@ -435,7 +460,7 @@ midi_init ( void )
//1 jack_set_buffer_size_callback( client, bufsize, 0 ); //1 jack_set_buffer_size_callback( client, bufsize, 0 );
jack_set_process_callback( client, process, 0 ); jack_set_process_callback( client, process, 0 );
jack_set_sync_callback( client, sync, 0 );
/* /\* initialize buffer size *\/ */ /* /\* initialize buffer size *\/ */
/* transport_poll(); */ /* transport_poll(); */

View File

@ -300,8 +300,7 @@ pattern::draw_row_names ( Canvas *c ) const
void void
pattern::trigger ( tick_t start, tick_t end ) pattern::trigger ( tick_t start, tick_t end )
{ {
if ( start > end ) ASSERT( start <= end, "programming error: invalid loop trigger! (%lu-%lu)", start, end );
ASSERTION( "programming error: invalid loop trigger! (%lu-%lu)", start, end );
_start = start; _start = start;
_end = end; _end = end;
@ -402,8 +401,6 @@ pattern::play ( tick_t start, tick_t end ) const
if ( end > _end ) if ( end > _end )
end = _end; end = _end;
_playing = true;
// where we are in the absolute time // where we are in the absolute time
tick_t tick = start - _start; tick_t tick = start - _start;
int num_played = tick / d->length; int num_played = tick / d->length;
@ -415,13 +412,15 @@ pattern::play ( tick_t start, tick_t end ) const
if ( _index < end - start ) if ( _index < end - start )
{ {
DMESSAGE( "Triggered pattern %d at tick %lu (ls: %lu, le: %lu, o: %lu)", number(), start, _start, _end, offset ); DMESSAGE( "%s pattern %d at tick %lu (ls: %lu, le: %lu, o: %lu)", _playing ? "Looped" : "Triggered", number(), start, _start, _end, offset );
_cleared = false; _cleared = false;
} }
_playing = true;
if ( mode() == MUTE ) if ( mode() == MUTE )
return; goto done;
try_again: try_again:
@ -475,7 +474,15 @@ try_again:
DMESSAGE( "out of events, resetting to satisfy loop" ); DMESSAGE( "out of events, resetting to satisfy loop" );
done: ; done:
if ( _end == end )
{
/* we're doing playing this trigger */
DMESSAGE( "Pattern %d ended at tick %lu (ls: %lu, le: %lu, o: %lu)", number(), end, _start, _end, offset );
stop();
}
} }

View File

@ -186,7 +186,6 @@ phrase::play ( tick_t start, tick_t end )
// not ready yet // not ready yet
return; return;
if ( start < _start ) if ( start < _start )
start = _start; start = _start;
@ -203,7 +202,7 @@ phrase::play ( tick_t start, tick_t end )
_index = tick % d->length; _index = tick % d->length;
if ( _index < end - start ) if ( _index < end - start )
MESSAGE( "Triggered phrase %d at tick %lu (ls: %lu, le: %lu, o: %lu)", number(), start, _start, _end, offset ); DMESSAGE( "Triggered phrase %d at tick %lu (ls: %lu, le: %lu, o: %lu)", number(), start, _start, _end, offset );
try_again: try_again:
@ -215,36 +214,27 @@ try_again:
{ {
// MESSAGE( "s[%ld] -> t[%ld] : %ld, len %ld", start, end, e->timestamp(), _length ); // (*e).print(); // MESSAGE( "s[%ld] -> t[%ld] : %ld, len %ld", start, end, e->timestamp(), _length ); // (*e).print();
tick_t ts = e->timestamp() + offset; const tick_t ts = e->timestamp() + offset;
if ( ts >= end ) if ( ts >= end )
goto done; goto done;
if ( ts >= start ) if ( e->is_note_on() )
{ {
event ne = *e; const tick_t tse = offset + e->link()->timestamp();
if ( ne.is_note_on() || ne.is_note_off() )
if ( tse > start )
{ {
int ev_note = e->note(); pattern *p = pattern::pattern_by_number( 1 + note_to_y( e->note() ) );
// d->mapping.translate( &ne ); if ( ! p->playing() )
p->trigger( ts, offset + e->link()->timestamp() );
pattern *p = pattern::pattern_by_number( 1 + note_to_y( ev_note ) ); p->play( start, end );
if ( p )
{
if ( e->is_note_on() )
{
p->trigger( ts, offset + e->link()->timestamp() );
p->play( ts, end );
}
else
if ( e->is_note_off() )
p->stop();
}
} }
} }
} }
// ran out of events, but there's still some loop left to play. // ran out of events, but there's still some loop left to play.
offset += d->length; offset += d->length;
goto try_again; goto try_again;