diff --git a/src/grid.C b/src/grid.C index 762032e..ad00874 100644 --- a/src/grid.C +++ b/src/grid.C @@ -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 diff --git a/src/grid.H b/src/grid.H index 8e2134a..8978527 100644 --- a/src/grid.H +++ b/src/grid.H @@ -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 */ diff --git a/src/gui/ui.fl b/src/gui/ui.fl index 0045285..053b95d 100644 --- a/src/gui/ui.fl +++ b/src/gui/ui.fl @@ -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 diff --git a/src/jack.C b/src/jack.C index df230dd..4bbc8b6 100644 --- a/src/jack.C +++ b/src/jack.C @@ -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--; ) diff --git a/src/non.H b/src/non.H index ee73633..5420600 100644 --- a/src/non.H +++ b/src/non.H @@ -51,7 +51,8 @@ bool save_song ( const char *name ); enum play_mode_e { PATTERN, SEQUENCE, - TRIGGER + TRIGGER, + QUEUE // PHRASE, }; diff --git a/src/pattern.C b/src/pattern.C index 456fd64..7dab22e 100644 --- a/src/pattern.C +++ b/src/pattern.C @@ -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 */ diff --git a/src/pattern.H b/src/pattern.H index b7415c8..b10bd36 100644 --- a/src/pattern.H +++ b/src/pattern.H @@ -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 );