triggerbox: reimplement timeline cues without session events
This commit is contained in:
parent
7c35783d63
commit
a187b5e1fb
|
@ -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
|
||||
|
|
|
@ -67,7 +67,6 @@ public:
|
|||
StartRoll,
|
||||
EndRoll,
|
||||
TransportStateChange,
|
||||
TriggerSceneChange,
|
||||
SyncCues,
|
||||
|
||||
/* only one of each of these events can be queued at any one time */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user