diff --git a/TODO.mu b/TODO.mu index 5b226a4..df6b9dc 100644 --- a/TODO.mu +++ b/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. diff --git a/src/jack.C b/src/jack.C index 234ec64..7e501a7 100644 --- a/src/jack.C +++ b/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(); */ diff --git a/src/pattern.C b/src/pattern.C index ffb12f6..892f0e4 100644 --- a/src/pattern.C +++ b/src/pattern.C @@ -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(); + } } diff --git a/src/phrase.C b/src/phrase.C index ecc6b82..f47b54b 100644 --- a/src/phrase.C +++ b/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;