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:
parent
81f504f88b
commit
d70dd3a517
1
TODO.mu
1
TODO.mu
|
@ -5,7 +5,6 @@
|
|||
|
||||
; 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: {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.
|
||||
|
|
63
src/jack.C
63
src/jack.C
|
@ -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
|
||||
process ( jack_nframes_t nframes, void *arg )
|
||||
{
|
||||
|
@ -246,29 +288,12 @@ process ( jack_nframes_t nframes, void *arg )
|
|||
{
|
||||
case PATTERN:
|
||||
case TRIGGER:
|
||||
{
|
||||
// stop all patterns.
|
||||
for ( uint i = pattern::patterns(); i--; )
|
||||
{
|
||||
pattern *p = pattern::pattern_by_number( i + 1 );
|
||||
|
||||
p->stop();
|
||||
}
|
||||
|
||||
stop_all_patterns();
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch ( song.play_mode )
|
||||
{
|
||||
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 );
|
||||
break;
|
||||
case PATTERN:
|
||||
|
@ -435,7 +460,7 @@ midi_init ( void )
|
|||
|
||||
//1 jack_set_buffer_size_callback( client, bufsize, 0 );
|
||||
jack_set_process_callback( client, process, 0 );
|
||||
|
||||
jack_set_sync_callback( client, sync, 0 );
|
||||
|
||||
/* /\* initialize buffer size *\/ */
|
||||
/* transport_poll(); */
|
||||
|
|
|
@ -300,8 +300,7 @@ pattern::draw_row_names ( Canvas *c ) const
|
|||
void
|
||||
pattern::trigger ( tick_t start, tick_t end )
|
||||
{
|
||||
if ( start > end )
|
||||
ASSERTION( "programming error: invalid loop trigger! (%lu-%lu)", start, end );
|
||||
ASSERT( start <= end, "programming error: invalid loop trigger! (%lu-%lu)", start, end );
|
||||
|
||||
_start = start;
|
||||
_end = end;
|
||||
|
@ -402,8 +401,6 @@ pattern::play ( tick_t start, tick_t end ) const
|
|||
if ( end > _end )
|
||||
end = _end;
|
||||
|
||||
_playing = true;
|
||||
|
||||
// where we are in the absolute time
|
||||
tick_t tick = start - _start;
|
||||
int num_played = tick / d->length;
|
||||
|
@ -415,13 +412,15 @@ pattern::play ( tick_t start, tick_t end ) const
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
_playing = true;
|
||||
|
||||
if ( mode() == MUTE )
|
||||
return;
|
||||
goto done;
|
||||
|
||||
try_again:
|
||||
|
||||
|
@ -475,7 +474,15 @@ try_again:
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
32
src/phrase.C
32
src/phrase.C
|
@ -186,7 +186,6 @@ phrase::play ( tick_t start, tick_t end )
|
|||
// not ready yet
|
||||
return;
|
||||
|
||||
|
||||
if ( start < _start )
|
||||
start = _start;
|
||||
|
||||
|
@ -203,7 +202,7 @@ phrase::play ( tick_t start, tick_t end )
|
|||
_index = tick % d->length;
|
||||
|
||||
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:
|
||||
|
||||
|
@ -215,36 +214,27 @@ try_again:
|
|||
{
|
||||
// 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 )
|
||||
goto done;
|
||||
|
||||
if ( ts >= start )
|
||||
if ( e->is_note_on() )
|
||||
{
|
||||
event ne = *e;
|
||||
if ( ne.is_note_on() || ne.is_note_off() )
|
||||
const tick_t tse = offset + e->link()->timestamp();
|
||||
|
||||
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 ) );
|
||||
|
||||
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();
|
||||
}
|
||||
p->play( start, end );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ran out of events, but there's still some loop left to play.
|
||||
offset += d->length;
|
||||
goto try_again;
|
||||
|
|
Loading…
Reference in New Issue