Implement Queue playback mode.

Pattern muteing/unmuteing (via GUI or MIDI) takes effect the next time the
pattern loops.
pull/3/head
Jonathan Moore Liles 2012-02-29 01:02:48 -08:00
parent 802f4c572f
commit 17e32e0282
7 changed files with 91 additions and 20 deletions

View File

@ -822,7 +822,8 @@ Grid::mode ( int m )
{ {
_mode = m; _mode = m;
signal_settings_change(); /* can't do this in RT thread, sorry. */
/// signal_settings_change();
} }
int int

View File

@ -122,7 +122,7 @@ protected:
volatile mutable tick_t _index; /* playhead, relative to start -- primarily used to draw the playhead */ volatile mutable tick_t _index; /* playhead, relative to start -- primarily used to draw the playhead */
volatile mutable bool _playing; /* true if currently playing */ 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"? // FIXME: shouldn't this be "volatile"?
// const volatile data *_rd; /* read only data used by RT thread */ // const volatile data *_rd; /* read only data used by RT thread */

View File

@ -185,7 +185,7 @@ if ( Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape )
if ( maybe_save_song() ) if ( maybe_save_song() )
quit();} open 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 Fl_Menu_Bar menu_bar {open
xywh {0 0 869 30} color 37 xywh {0 0 869 30} color 37
@ -983,7 +983,7 @@ else
} { } {
MenuItem {} { MenuItem {} {
label Pattern label Pattern
callback {song.play_mode = PATTERN;} callback {song.play_mode = PATTERN;} selected
xywh {5 5 40 25} xywh {5 5 40 25}
} }
MenuItem {} { MenuItem {} {
@ -996,6 +996,11 @@ else
callback {song.play_mode = TRIGGER;} callback {song.play_mode = TRIGGER;}
xywh {25 25 40 25} xywh {25 25 40 25}
} }
MenuItem {} {
label Queue
callback {song.play_mode = QUEUE;}
xywh {0 0 40 24}
}
} }
} }
Fl_Group {} {open Fl_Group {} {open

View File

@ -307,6 +307,7 @@ process ( jack_nframes_t nframes, void *arg )
{ {
case PATTERN: case PATTERN:
case TRIGGER: case TRIGGER:
case QUEUE:
DMESSAGE( "Stopping all patterns" ); DMESSAGE( "Stopping all patterns" );
stop_all_patterns(); stop_all_patterns();
break; 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 */ /* no need to pass it to the GUI, we can trigger patterns here */
if ( e.channel() == 0 && e.is_note_on() ) if ( e.channel() == 0 && e.is_note_on() )
{ {
if ( e.note() < pattern::patterns() ) if ( e.note() < pattern::patterns() )
{ {
pattern *p = pattern::pattern_by_number( e.note() + 1 ); pattern *p = pattern::pattern_by_number( e.note() + 1 );
if ( p->playing() ) if ( TRIGGER == song.play_mode )
{ {
DMESSAGE( "Untriggering pattern %i", e.note() ); if ( p->playing() )
if ( e.note() < pattern::patterns() )
{ {
pattern *p = pattern::pattern_by_number( e.note() + 1 );
DMESSAGE( "Untriggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); DMESSAGE( "Untriggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() );
p->trigger( 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 else
{ {
DMESSAGE( "Triggering pattern %i ph=%lu, ts=%lu", e.note(), ph, e.timestamp() ); if ( p->mode() == PLAY )
{
p->trigger( e.timestamp(), -1 ); 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 ) switch ( song.play_mode )
{ {
case SEQUENCE: case SEQUENCE:
playlist->play( ph, nph ); playlist->play( ph, nph );
break; break;
case QUEUE:
case PATTERN: case PATTERN:
{ {
for ( uint i = pattern::patterns(); i--; ) for ( uint i = pattern::patterns(); i--; )

View File

@ -51,7 +51,8 @@ bool save_song ( const char *name );
enum play_mode_e { enum play_mode_e {
PATTERN, PATTERN,
SEQUENCE, SEQUENCE,
TRIGGER TRIGGER,
QUEUE
// PHRASE, // PHRASE,
}; };

View File

@ -43,6 +43,9 @@ pattern::pattern ( void )
_ppqn = 4; _ppqn = 4;
_bpb = 4; _bpb = 4;
_note = 8; _note = 8;
_queued = -1;
int _bars = 2; int _bars = 2;
// we need to reinitalize this. // we need to reinitalize this.
@ -325,6 +328,12 @@ pattern::stop ( void ) const
void void
pattern::mode ( int n ) pattern::mode ( int n )
{ {
if ( QUEUE == song.play_mode )
{
queue( n );
return;
}
if ( n == SOLO ) if ( n == SOLO )
{ {
if ( pattern::_solo ) if ( pattern::_solo )
@ -355,6 +364,19 @@ pattern::mode ( void ) const
return Grid::mode(); 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! */ /* WARNING: runs in the RT thread! */
// output notes from /start/ to /end/ (absolute) // output notes from /start/ to /end/ (absolute)
void void
@ -389,11 +411,33 @@ pattern::play ( tick_t start, tick_t end ) const
_index = tick % d->length; _index = tick % d->length;
bool reset_queued = false;
if ( _index < end - start ) 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 ); 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;
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; _playing = true;
@ -455,6 +499,12 @@ try_again:
done: done:
if ( _queued >= 0 && reset_queued )
{
_mode = _queued;
_queued = -1;
}
if ( _end == end ) if ( _end == end )
{ {
/* we're done playing this trigger */ /* we're done playing this trigger */

View File

@ -43,13 +43,12 @@ class pattern : public Grid
bool _recording; bool _recording;
mutable volatile bool _cleared; mutable volatile bool _cleared;
volatile bool _triggered; mutable volatile int _queued;
// int _key; // int _key;
int _note; int _note;
void _add ( void ); void _add ( void );
@ -88,8 +87,8 @@ public:
void record( int mode ); void record( int mode );
void record_stop ( void ); void record_stop ( void );
void toggle_trigger ( void ); void queue ( int mode );
bool triggered ( void ) const; int queue ( void ) const;
void randomize_row ( int y, int feel, float probability ); void randomize_row ( int y, int feel, float probability );