Also, use Channel 0 CC 20 0-127 for pattern triggering instead of NOTE ONs.tags/non-sequencer-v1.9.4
@@ -1750,7 +1750,9 @@ widget_class Triggers {open | |||||
} {} | } {} | ||||
Function {populate( void )} {open private return_type void | Function {populate( void )} {open private return_type void | ||||
} { | } { | ||||
code {int bw = (w() / 16); | |||||
code {_timer = 0; | |||||
int bw = (w() / 16); | |||||
int bh = h() / (128/ 16); | int bh = h() / (128/ 16); | ||||
begin(); | begin(); | ||||
@@ -1799,13 +1801,21 @@ redraw();} {} | |||||
} | } | ||||
Function {update( void )} {open return_type void | Function {update( void )} {open return_type void | ||||
} { | } { | ||||
code {if ( ! takesevents() ) | |||||
code {++_timer; | |||||
if ( ! takesevents() ) | |||||
return; | return; | ||||
int i; | int i; | ||||
for ( i = 0; i < MAX_PATTERN; i++ ) | for ( i = 0; i < MAX_PATTERN; i++ ) | ||||
{ | { | ||||
Fl_Color mode_color[3]; | |||||
mode_color[PLAY] = FL_GREEN; | |||||
mode_color[MUTE] = FL_GRAY; | |||||
mode_color[SOLO] = FL_RED; | |||||
Trigger *b = (Trigger*)(((Fl_Pack*)rows->child( i / 16 ))->child( i % 16 )); | Trigger *b = (Trigger*)(((Fl_Pack*)rows->child( i / 16 ))->child( i % 16 )); | ||||
if ( i >= pattern::patterns() ) | if ( i >= pattern::patterns() ) | ||||
@@ -1821,22 +1831,15 @@ for ( i = 0; i < MAX_PATTERN; i++ ) | |||||
{ | { | ||||
b->color( fl_lighter( FL_GRAY ) ); | b->color( fl_lighter( FL_GRAY ) ); | ||||
Fl_Color c = FL_BLUE; | |||||
switch ( p->mode() ) | |||||
{ | |||||
case MUTE: | |||||
c = FL_GRAY; | |||||
break; | |||||
case SOLO: | |||||
c = FL_RED; | |||||
break; | |||||
case PLAY: | |||||
c = FL_GREEN; | |||||
break; | |||||
} | |||||
b->selection_color( c ); | |||||
b->selection_color( mode_color[ p->mode() ] ); | |||||
if ( p->queue() >= 0 ) | |||||
{ | |||||
if ( _timer % 16 < 8 ) | |||||
{ | |||||
b->color( mode_color[ p->queue() ] ); | |||||
} | |||||
} | |||||
b->value( (double)p->index() / p->length() ); | b->value( (double)p->index() / p->length() ); | ||||
} | } | ||||
@@ -1845,7 +1848,8 @@ for ( i = 0; i < MAX_PATTERN; i++ ) | |||||
b->value( 0 ); | b->value( 0 ); | ||||
} | } | ||||
}} {} | |||||
}} {selected | |||||
} | |||||
} | } | ||||
Function {resize( int X, int Y, int W, int H )} {open return_type void | Function {resize( int X, int Y, int W, int H )} {open return_type void | ||||
} { | } { | ||||
@@ -1866,4 +1870,6 @@ for ( i = 0; i < MAX_PATTERN; i++ ) | |||||
Fl_Group::resize( X, Y, W, H );} {} | Fl_Group::resize( X, Y, W, H );} {} | ||||
} | } | ||||
decl {unsigned long _timer;} {private local | |||||
} | |||||
} | } |
@@ -43,6 +43,13 @@ | |||||
#define jack_midi_event_write( b, f, d, s ) jack_midi_event_write( b, f, d, s, nframes ) | #define jack_midi_event_write( b, f, d, s ) jack_midi_event_write( b, f, d, s, nframes ) | ||||
#endif | #endif | ||||
/* MIDI channel to listen for pattern control changes on */ | |||||
int pattern_control_channel = 0; | |||||
/* which control change number to use for pattern control */ | |||||
int pattern_control_cc = 20; | |||||
jack_client_t *client; | jack_client_t *client; | ||||
int sample_rate; | int sample_rate; | ||||
@@ -345,25 +352,26 @@ process ( jack_nframes_t nframes, void *arg ) | |||||
/* no need to pass it to the GUI, we can trigger patterns here */ | /* no need to pass it to the GUI, we can trigger patterns here */ | ||||
if ( e.channel() == 0 && e.is_note_on() ) | |||||
if ( e.channel() == pattern_control_channel && | |||||
e.opcode() == midievent::CONTROL_CHANGE && | |||||
e.lsb() == pattern_control_cc ) | |||||
{ | { | ||||
if ( e.note() < pattern::patterns() ) | |||||
if ( e.msb() < pattern::patterns() ) | |||||
{ | { | ||||
pattern *p = pattern::pattern_by_number( e.note() + 1 ); | |||||
pattern *p = pattern::pattern_by_number( e.msb() + 1 ); | |||||
if ( TRIGGER == song.play_mode ) | if ( TRIGGER == song.play_mode ) | ||||
{ | { | ||||
if ( p->playing() ) | if ( p->playing() ) | ||||
{ | { | ||||
DMESSAGE( "Untriggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||||
DMESSAGE( "Untriggering pattern %i ph=%lu, ts=%lu", e.msb(), ph, e.timestamp() ); | |||||
p->trigger( ph, e.timestamp() ); | p->trigger( ph, e.timestamp() ); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
DMESSAGE( "Triggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||||
DMESSAGE( "Triggering pattern %i ph=%lu, ts=%lu", e.msb(), ph, e.timestamp() ); | |||||
p->trigger( e.timestamp(), -1 ); | p->trigger( e.timestamp(), -1 ); | ||||
} | } | ||||
@@ -372,12 +380,12 @@ process ( jack_nframes_t nframes, void *arg ) | |||||
{ | { | ||||
if ( p->mode() == PLAY ) | if ( p->mode() == PLAY ) | ||||
{ | { | ||||
DMESSAGE( "Dequeuing pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||||
DMESSAGE( "Dequeuing pattern %i ph=%lu, ts=%lu", e.msb(), ph, e.timestamp() ); | |||||
p->mode( MUTE ); | p->mode( MUTE ); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
DMESSAGE( "Queuing pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||||
DMESSAGE( "Queuing pattern %i ph=%lu, ts=%lu", e.msb(), ph, e.timestamp() ); | |||||
p->mode( PLAY ); | p->mode( PLAY ); | ||||
} | } | ||||
@@ -420,12 +420,25 @@ pattern::play ( tick_t start, tick_t end ) const | |||||
_cleared = false; | _cleared = false; | ||||
if ( PLAY == _queued ) | |||||
if ( PLAY == _queued || SOLO == _queued ) | |||||
{ | { | ||||
/* set the start point to loop boundary */ | /* set the start point to loop boundary */ | ||||
start = start - _index; | start = start - _index; | ||||
_mode = PLAY; | |||||
_mode = _queued; | |||||
if ( SOLO == _mode ) | |||||
{ | |||||
if ( pattern::_solo ) | |||||
((Grid*)pattern::pattern_by_number( pattern::_solo ))->mode( PLAY ); | |||||
pattern::_solo = _number; | |||||
} | |||||
else | |||||
{ | |||||
if ( pattern::_solo == _number ) | |||||
pattern::_solo = 0; | |||||
} | |||||
reset_queued = true; | reset_queued = true; | ||||
} | } | ||||
} | } | ||||