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;
signal_settings_change();
/* can't do this in RT thread, sorry. */
/// signal_settings_change();
}
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 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 */

View File

@ -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

View File

@ -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--; )

View File

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

View File

@ -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 */

View File

@ -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 );