Implement Queue playback mode.
Pattern muteing/unmuteing (via GUI or MIDI) takes effect the next time the pattern loops.
This commit is contained in:
parent
802f4c572f
commit
17e32e0282
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
37
src/jack.C
37
src/jack.C
|
@ -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--; )
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue