Pattern muteing/unmuteing (via GUI or MIDI) takes effect the next time the pattern loops.tags/non-sequencer-v1.9.4
@@ -822,7 +822,8 @@ Grid::mode ( int m ) | |||
{ | |||
_mode = m; | |||
signal_settings_change(); | |||
/* can't do this in RT thread, sorry. */ | |||
/// signal_settings_change(); | |||
} | |||
int | |||
@@ -122,7 +122,7 @@ protected: | |||
volatile mutable tick_t _index; /* playhead, relative to start -- primarily used to draw the playhead */ | |||
volatile mutable bool _playing; /* true if currently playing */ | |||
volatile int _mode; /* mute, solo */ | |||
mutable volatile int _mode; /* mute, solo */ | |||
// FIXME: shouldn't this be "volatile"? | |||
// const volatile data *_rd; /* read only data used by RT thread */ | |||
@@ -185,7 +185,7 @@ if ( Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape ) | |||
if ( maybe_save_song() ) | |||
quit();} open | |||
xywh {209 100 865 800} type Double box PLASTIC_UP_BOX color 37 resizable xclass non size_range {600 420 0 0} visible | |||
xywh {856 305 865 800} type Double box PLASTIC_UP_BOX color 37 resizable xclass non size_range {600 420 0 0} visible | |||
} { | |||
Fl_Menu_Bar menu_bar {open | |||
xywh {0 0 869 30} color 37 | |||
@@ -983,7 +983,7 @@ else | |||
} { | |||
MenuItem {} { | |||
label Pattern | |||
callback {song.play_mode = PATTERN;} | |||
callback {song.play_mode = PATTERN;} selected | |||
xywh {5 5 40 25} | |||
} | |||
MenuItem {} { | |||
@@ -996,6 +996,11 @@ else | |||
callback {song.play_mode = TRIGGER;} | |||
xywh {25 25 40 25} | |||
} | |||
MenuItem {} { | |||
label Queue | |||
callback {song.play_mode = QUEUE;} | |||
xywh {0 0 40 24} | |||
} | |||
} | |||
} | |||
Fl_Group {} {open | |||
@@ -307,6 +307,7 @@ process ( jack_nframes_t nframes, void *arg ) | |||
{ | |||
case PATTERN: | |||
case TRIGGER: | |||
case QUEUE: | |||
DMESSAGE( "Stopping all patterns" ); | |||
stop_all_patterns(); | |||
break; | |||
@@ -343,41 +344,55 @@ process ( jack_nframes_t nframes, void *arg ) | |||
/* no need to pass it to the GUI, we can trigger patterns here */ | |||
if ( e.channel() == 0 && e.is_note_on() ) | |||
{ | |||
if ( e.note() < pattern::patterns() ) | |||
{ | |||
pattern *p = pattern::pattern_by_number( e.note() + 1 ); | |||
if ( p->playing() ) | |||
if ( TRIGGER == song.play_mode ) | |||
{ | |||
DMESSAGE( "Untriggering pattern %i", e.note() ); | |||
if ( e.note() < pattern::patterns() ) | |||
if ( p->playing() ) | |||
{ | |||
pattern *p = pattern::pattern_by_number( e.note() + 1 ); | |||
DMESSAGE( "Untriggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||
p->trigger( ph, e.timestamp() ); | |||
} | |||
else | |||
{ | |||
DMESSAGE( "Triggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||
p->trigger( e.timestamp(), -1 ); | |||
} | |||
} | |||
else | |||
{ | |||
DMESSAGE( "Triggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||
p->trigger( e.timestamp(), -1 ); | |||
if ( p->mode() == PLAY ) | |||
{ | |||
DMESSAGE( "Dequeuing pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||
p->mode( MUTE ); | |||
} | |||
else | |||
{ | |||
DMESSAGE( "Queuing pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); | |||
p->mode( PLAY ); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
switch ( song.play_mode ) | |||
{ | |||
case SEQUENCE: | |||
playlist->play( ph, nph ); | |||
break; | |||
case QUEUE: | |||
case PATTERN: | |||
{ | |||
for ( uint i = pattern::patterns(); i--; ) | |||
@@ -51,7 +51,8 @@ bool save_song ( const char *name ); | |||
enum play_mode_e { | |||
PATTERN, | |||
SEQUENCE, | |||
TRIGGER | |||
TRIGGER, | |||
QUEUE | |||
// PHRASE, | |||
}; | |||
@@ -43,6 +43,9 @@ pattern::pattern ( void ) | |||
_ppqn = 4; | |||
_bpb = 4; | |||
_note = 8; | |||
_queued = -1; | |||
int _bars = 2; | |||
// we need to reinitalize this. | |||
@@ -325,6 +328,12 @@ pattern::stop ( void ) const | |||
void | |||
pattern::mode ( int n ) | |||
{ | |||
if ( QUEUE == song.play_mode ) | |||
{ | |||
queue( n ); | |||
return; | |||
} | |||
if ( n == SOLO ) | |||
{ | |||
if ( pattern::_solo ) | |||
@@ -355,6 +364,19 @@ pattern::mode ( void ) const | |||
return Grid::mode(); | |||
} | |||
/* queue a mode change for the next loop */ | |||
void | |||
pattern::queue ( int m ) | |||
{ | |||
_queued = m; | |||
} | |||
int | |||
pattern::queue ( void ) const | |||
{ | |||
return _queued; | |||
} | |||
/* WARNING: runs in the RT thread! */ | |||
// output notes from /start/ to /end/ (absolute) | |||
void | |||
@@ -389,11 +411,33 @@ pattern::play ( tick_t start, tick_t end ) const | |||
_index = tick % d->length; | |||
bool reset_queued = false; | |||
if ( _index < end - start ) | |||
{ | |||
/* period covers the beginning of the loop */ | |||
DMESSAGE( "%s pattern %d at tick %lu (ls: %lu, le: %lu, o: %lu)", _playing ? "Looped" : "Triggered", number(), start, _start, _end, offset ); | |||
_cleared = false; | |||
if ( PLAY == _queued ) | |||
{ | |||
/* set the start point to loop boundary */ | |||
start = start - _index; | |||
_mode = PLAY; | |||
reset_queued = true; | |||
} | |||
} | |||
else if ( _index >= d->length - ( end - start ) ) | |||
{ | |||
if ( MUTE == _queued ) | |||
{ | |||
/* set the end point to loop boundary */ | |||
end = end - _index; | |||
reset_queued = true; | |||
} | |||
} | |||
_playing = true; | |||
@@ -455,6 +499,12 @@ try_again: | |||
done: | |||
if ( _queued >= 0 && reset_queued ) | |||
{ | |||
_mode = _queued; | |||
_queued = -1; | |||
} | |||
if ( _end == end ) | |||
{ | |||
/* we're done playing this trigger */ | |||
@@ -43,13 +43,12 @@ class pattern : public Grid | |||
bool _recording; | |||
mutable volatile bool _cleared; | |||
volatile bool _triggered; | |||
mutable volatile int _queued; | |||
// int _key; | |||
int _note; | |||
void _add ( void ); | |||
@@ -88,8 +87,8 @@ public: | |||
void record( int mode ); | |||
void record_stop ( void ); | |||
void toggle_trigger ( void ); | |||
bool triggered ( void ) const; | |||
void queue ( int mode ); | |||
int queue ( void ) const; | |||
void randomize_row ( int y, int feel, float probability ); | |||