diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 51eb635062..dfb3aa6e66 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -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 CueEvents; + + CueEvents _cue_events; void sync_cues (); void sync_cues_from_list (Locations::LocationList const &); -}; + + std::atomic _pending_cue; + std::atomic _active_cue; + void maybe_find_pending_cue (); + void clear_active_cue (); + + }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h index a71b1d3c75..417c8427d0 100644 --- a/libs/ardour/ardour/session_event.h +++ b/libs/ardour/ardour/session_event.h @@ -67,7 +67,6 @@ public: StartRoll, EndRoll, TransportStateChange, - TriggerSceneChange, SyncCues, /* only one of each of these events can be queued at any one time */ diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index 3f434afd59..52eeb2b535 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -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); + /* valid only within the ::run() call tree */ + int32_t active_scene() const { return _active_scene; } + PBD::Signal1 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 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; @@ -630,8 +628,6 @@ class LIBARDOUR_API TriggerBox : public Processor static int _first_midi_note; static TriggerMidiMapMode _midi_map_mode; - static std::atomic _pending_scene; - static std::atomic _active_scene; struct Request { enum Type { diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 3f44fc1fa4..ced3733609 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -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); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index bdbdcfedb1..fdca83ab4c 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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); -} diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 74fc9a7fd1..2d05bdfe75 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -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); } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index fc12cb9c40..d4b32100dc 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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); diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 2dcbfc58c8..4a796fe906 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -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 TriggerBox::_pending_scene (-1); -std::atomic TriggerBox::_active_scene (-1); std::atomic 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; }