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
|
; 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.
|
||||||
|
|
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
|
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(); */
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/phrase.C
32
src/phrase.C
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue