13
0

triggerbox: reimplement timeline cues without session events

This commit is contained in:
Paul Davis 2022-01-06 00:23:27 -07:00
parent 7c35783d63
commit a187b5e1fb
8 changed files with 124 additions and 131 deletions

View File

@ -1354,6 +1354,9 @@ public:
PBD::TimingStats dsp_stats[NTT];
int32_t first_cue_within (samplepos_t s, samplepos_t e);
void cue_bang (int32_t);
protected:
friend class AudioEngine;
void set_block_size (pframes_t nframes);
@ -2300,9 +2303,32 @@ private:
void setup_thread_local_variables ();
void cue_marker_change (Location*);
struct CueEvent {
int32_t cue;
samplepos_t time;
CueEvent (int32_t c, samplepos_t t) : cue (c), time (t) {}
};
struct CueEventTimeComparator {
bool operator() (CueEvent const & c, samplepos_t s) {
return c.time < s;
}
};
typedef std::vector<CueEvent> CueEvents;
CueEvents _cue_events;
void sync_cues ();
void sync_cues_from_list (Locations::LocationList const &);
};
std::atomic<int32_t> _pending_cue;
std::atomic<int32_t> _active_cue;
void maybe_find_pending_cue ();
void clear_active_cue ();
};
} // namespace ARDOUR

View File

@ -67,7 +67,6 @@ public:
StartRoll,
EndRoll,
TransportStateChange,
TriggerSceneChange,
SyncCues,
/* only one of each of these events can be queued at any one time */

View File

@ -551,6 +551,9 @@ class LIBARDOUR_API TriggerBox : public Processor
void request_reload (int32_t slot, void*);
void set_region (uint32_t slot, boost::shared_ptr<Region> region);
/* valid only within the ::run() call tree */
int32_t active_scene() const { return _active_scene; }
PBD::Signal1<void,uint32_t> TriggerSwapped;
enum TriggerMidiMapMode {
@ -568,12 +571,6 @@ class LIBARDOUR_API TriggerBox : public Processor
static int first_midi_note() { return _first_midi_note; }
static void set_first_midi_note (int n);
static void maybe_find_scene_bang ();
static void clear_scene_bang ();
static void scene_bang (uint32_t scene_number);
static void scene_unbang (uint32_t scene_number);
static int32_t active_scene ();
static void init ();
static const int32_t default_triggers_per_box;
@ -601,10 +598,11 @@ class LIBARDOUR_API TriggerBox : public Processor
PendingTriggers pending;
PBD::RingBuffer<uint32_t> explicit_queue; /* user queued triggers */
TriggerPtr _currently_playing;
Requests _requests;
bool _stop_all;
bool _pass_thru;
TriggerPtr _currently_playing;
Requests _requests;
bool _stop_all;
bool _pass_thru;
int32_t _active_scene;
boost::shared_ptr<SideChain> _sidechain;
@ -630,8 +628,6 @@ class LIBARDOUR_API TriggerBox : public Processor
static int _first_midi_note;
static TriggerMidiMapMode _midi_map_mode;
static std::atomic<int32_t> _pending_scene;
static std::atomic<int32_t> _active_scene;
struct Request {
enum Type {

View File

@ -466,7 +466,7 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (SessionEvent, EndRoll);
REGISTER_CLASS_ENUM (SessionEvent, TransportStateChange);
REGISTER_CLASS_ENUM (SessionEvent, AutoLoop);
REGISTER_CLASS_ENUM (SessionEvent, TriggerSceneChange);
REGISTER_CLASS_ENUM (SessionEvent, SyncCues);
REGISTER (_SessionEvent_Type);
REGISTER_CLASS_ENUM (SessionEvent, Add);

View File

@ -319,6 +319,8 @@ Session::Session (AudioEngine &eng,
, _selection (new CoreSelection (*this))
, _global_locate_pending (false)
, _had_destructive_tracks (false)
, _pending_cue (-1)
, _active_cue (-1)
{
g_atomic_int_set (&_suspend_save, 0);
g_atomic_int_set (&_playback_load, 0);
@ -356,6 +358,8 @@ Session::Session (AudioEngine &eng,
init_name_id_counter (1); // reset for new sessions, start at 1
VCA::set_next_vca_number (1); // reset for new sessions, start at 1
_cue_events.reserve (1024);
pre_engine_init (fullpath); // sets _is_new
setup_lua ();
@ -803,10 +807,6 @@ Session::destroy ()
case SessionEvent::PunchOut:
case SessionEvent::RangeStop:
case SessionEvent::RangeLocate:
case SessionEvent::TriggerSceneChange:
remove = false;
del = false;
break;
case SessionEvent::RealTimeOperation:
process_rtop (ev);
del = false;
@ -7369,9 +7369,3 @@ Session::had_destructive_tracks() const
return _had_destructive_tracks;
}
void
Session::cue_marker_change (Location* loc)
{
SessionEvent* ev = new SessionEvent (SessionEvent::SyncCues, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
queue_event (ev);
}

View File

@ -389,7 +389,7 @@ Session::process_with_events (pframes_t nframes)
// DEBUG_TRACE (DEBUG::Transport, string_compose ("Running count in/latency preroll of %1 & %2\n", _count_in_samples, _remaining_latency_preroll));
TriggerBox::maybe_find_scene_bang ();
maybe_find_pending_cue ();
while (_count_in_samples > 0 || _remaining_latency_preroll > 0) {
samplecnt_t ns;
@ -631,7 +631,7 @@ Session::process_with_events (pframes_t nframes)
} /* implicit release of route lock */
TriggerBox::clear_scene_bang ();
clear_active_cue ();
if (session_needs_butler) {
DEBUG_TRACE (DEBUG::Butler, "p-with-events: session needs butler, call it\n");
@ -696,14 +696,14 @@ Session::process_without_events (pframes_t nframes)
click (_transport_sample, nframes);
TriggerBox::maybe_find_scene_bang ();
maybe_find_pending_cue ();
if (process_routes (nframes, session_needs_butler)) {
fail_roll (nframes);
return;
}
TriggerBox::clear_scene_bang ();
clear_active_cue ();
get_track_statistics ();
@ -971,12 +971,6 @@ Session::process_event (SessionEvent* ev)
}
break;
case SessionEvent::TriggerSceneChange:
TriggerBox::scene_bang (ev->scene);
remove = false;
del = false;
break;
case SessionEvent::PunchIn:
// cerr << "PunchIN at " << transport_sample() << endl;
if (config.get_punch_in() && record_status() == Enabled) {
@ -1611,65 +1605,73 @@ struct LocationByTime
void
Session::sync_cues_from_list (Locations::LocationList const & locs)
{
/* iterate over all cue markers, check there is a SessionEvent for them all */
Locations::LocationList sorted (locs);
LocationByTime cmp;
sorted.sort (cmp);
Events::iterator evi = events.begin();
CueEvents::size_type n = 0;
for (auto const & loc : locs) {
/* this leaves the capacity unchanged */
_cue_events.clear ();
for (auto const & loc : sorted) {
if (loc->is_cue_marker()) {
_cue_events.push_back (CueEvent (loc->cue_id(), loc->start_sample()));
}
const samplepos_t cue_sample = loc->start_sample();
if (evi == events.end()) {
SessionEvent* ev = new SessionEvent (SessionEvent::TriggerSceneChange, SessionEvent::Add, cue_sample, 0, 0);
ev->scene = loc->cue_id();
events.insert (evi, ev);
} else if (cue_sample > (*evi)->target_sample) {
SessionEvent* ev = new SessionEvent (SessionEvent::TriggerSceneChange, SessionEvent::Add, cue_sample, 0, 0);
ev->scene = loc->cue_id();
events.insert (evi, ev);
/* we don't advance evi here because we inserted before it */
} else if ((*evi)->type == SessionEvent::TriggerSceneChange) {
if ((*evi)->action_sample == cue_sample) {
/* replace the contents of the event */
(*evi)->scene = loc->cue_id();
++evi;
} else if ((*evi)->action_sample < cue_sample) {
/* existing event but no corresponding cue marker */
evi = events.erase (evi);
}
} else {
++evi;
}
if (++n >= _cue_events.capacity()) {
break;
}
}
/* Remove any relevant events that are timestamped after the last cue marker */
while (evi != events.end()) {
if ((*evi)->type == SessionEvent::TriggerSceneChange) {
evi = events.erase (evi);
} else {
++evi;
}
}
dump_events ();
set_next_event ();
}
int32_t
Session::first_cue_within (samplepos_t s, samplepos_t e)
{
int32_t active_cue = _active_cue.load ();
if (active_cue >= 0) {
return active_cue;
}
CueEventTimeComparator cmp;
CueEvents::iterator si = lower_bound (_cue_events.begin(), _cue_events.end(), s, cmp);
if (si != _cue_events.end()) {
if (si->time < e) {
return si->cue;
}
}
return -1;
}
void
Session::cue_marker_change (Location* loc)
{
SessionEvent* ev = new SessionEvent (SessionEvent::SyncCues, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
queue_event (ev);
}
void
Session::cue_bang (int32_t cue)
{
_pending_cue.store (cue);
}
void
Session::maybe_find_pending_cue ()
{
int32_t ac = _pending_cue.exchange (-1);
if (ac >= 0) {
_active_cue.store (ac);
}
}
void
Session::clear_active_cue ()
{
_active_cue.store (-1);
}

View File

@ -1849,6 +1849,7 @@ Session::set_state (const XMLNode& node, int version)
}
update_route_record_state ();
sync_cues ();
/* here beginneth the second phase ... */
set_snapshot_name (_current_snapshot_name);

View File

@ -1820,8 +1820,6 @@ Temporal::BBT_Offset TriggerBox::_assumed_trigger_duration (4, 0, 0);
//TriggerBox::TriggerMidiMapMode TriggerBox::_midi_map_mode (TriggerBox::AbletonPush);
TriggerBox::TriggerMidiMapMode TriggerBox::_midi_map_mode (TriggerBox::SequentialNote);
int TriggerBox::_first_midi_note = 60;
std::atomic<int32_t> TriggerBox::_pending_scene (-1);
std::atomic<int32_t> TriggerBox::_active_scene (-1);
std::atomic<int> TriggerBox::active_trigger_boxes (0);
TriggerBoxThread* TriggerBox::worker = 0;
@ -1841,6 +1839,7 @@ TriggerBox::TriggerBox (Session& s, DataType dt)
, _currently_playing (0)
, _stop_all (false)
, _pass_thru (false)
, _active_scene (-1)
, requests (1024)
{
set_display_to_user (false);
@ -1923,40 +1922,6 @@ TriggerBox::maybe_swap_pending (uint32_t slot)
}
}
void
TriggerBox::scene_bang (uint32_t n)
{
DEBUG_TRACE (DEBUG::Triggers, string_compose ("scene bang on %1 for %2\n", n));
_pending_scene = n;
}
void
TriggerBox::scene_unbang (uint32_t n)
{
}
int32_t
TriggerBox::active_scene ()
{
return _active_scene.load ();
}
void
TriggerBox::maybe_find_scene_bang ()
{
int32_t pending = _pending_scene.exchange (-1);
if (pending >= 0) {
_active_scene = pending;
}
}
void
TriggerBox::clear_scene_bang ()
{
(void) _active_scene.exchange (-1);
}
void
TriggerBox::set_order (int32_t n)
{
@ -2385,16 +2350,11 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
_sidechain->run (bufs, start_sample, end_sample, speed, nframes, true);
}
/* STEP FOUR: handle any incoming requests from the GUI or other
* non-MIDI UIs
*/
process_requests (bufs);
/* STEP FIVE: handle any incoming MIDI requests
*/
process_midi_trigger_requests (bufs);
int32_t cue_bang = _session.first_cue_within (start_sample, end_sample);
if (cue_bang >= 0) {
std::cerr << " CUE BANG " << cue_bang << std::endl;
_active_scene = cue_bang;
}
/* STEP SIX: if at this point there is an active cue, make it trigger
* our corresponding slot
@ -2409,6 +2369,17 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
}
}
/* STEP FOUR: handle any incoming requests from the GUI or other
* non-MIDI UIs
*/
process_requests (bufs);
/* STEP FIVE: handle any incoming MIDI requests
*/
process_midi_trigger_requests (bufs);
/* STEP SEVEN: let each slot process any individual state requests
*/
@ -2418,6 +2389,10 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
all_triggers[n]->process_state_requests ();
}
/* cue handling is over at this point, reset _active_scene to reflect this */
_active_scene = -1;
if (_currently_playing && _currently_playing->state() == Trigger::Stopped) {
_currently_playing = 0;
}