diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index fde62f6680..ba40889566 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -235,6 +235,10 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { double apparent_tempo() const { return _apparent_tempo; } double set_tempo (double t); + void set_pending (Trigger*); + Trigger* swap_pending (Trigger*); + void swap_notify (); + virtual SegmentDescriptor get_segment_descriptor () const = 0; protected: @@ -278,6 +282,8 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { double _apparent_tempo; samplepos_t expected_end_sample; + std::atomic _pending; + void set_region_internal (boost::shared_ptr); virtual void retrigger() = 0; virtual void set_usable_length () = 0; @@ -350,8 +356,6 @@ class LIBARDOUR_API AudioTrigger : public Trigger { samplecnt_t to_pad; samplecnt_t to_drop; - PBD::RingBuffer _deletion_queue; - void drop_data (); int load_data (boost::shared_ptr); void determine_tempo (); @@ -483,7 +487,7 @@ class LIBARDOUR_API TriggerBox : public Processor bool unbang_trigger (TriggerPtr); void add_trigger (TriggerPtr); - void set_pending (uint32_t slot, TriggerPtr); + void set_pending (uint32_t slot, Trigger*); XMLNode& get_state (void); int set_state (const XMLNode&, int version); @@ -515,6 +519,8 @@ class LIBARDOUR_API TriggerBox : public Processor void request_reload (int32_t slot, void*); void set_region (uint32_t slot, boost::shared_ptr region); + PBD::Signal1 TriggerSwapped; + enum TriggerMidiMapMode { AbletonPush, SequentialNote, @@ -557,7 +563,10 @@ class LIBARDOUR_API TriggerBox : public Processor int32_t _order; Glib::Threads::RWLock trigger_lock; /* protects all_triggers */ Triggers all_triggers; - Triggers pending; + + typedef std::vector PendingTriggers; + PendingTriggers pending; + PBD::RingBuffer explicit_queue; /* user queued triggers */ TriggerPtr _currently_playing; Requests _requests; @@ -576,6 +585,8 @@ class LIBARDOUR_API TriggerBox : public Processor int determine_next_trigger (uint32_t n); void stop_all (); + void maybe_swap_pending (uint32_t); + int note_to_trigger (int node, int channel); void note_on (int note_number, int velocity); diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 2d243229d4..6f19ba3576 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -91,6 +91,7 @@ Trigger::Trigger (uint32_t n, TriggerBox& b) , _barcnt (0.) , _apparent_tempo (0.) , expected_end_sample (0) + , _pending ((Trigger*) 0) { add_property (_launch_style); add_property (_use_follow); @@ -107,6 +108,28 @@ Trigger::Trigger (uint32_t n, TriggerBox& b) add_property (_isolated); } +void +Trigger::set_pending (Trigger* t) +{ + Trigger* old = _pending.exchange (t); + if (old) { + /* new pending trigger set before existing pending trigger was used */ + delete old; + } +} + +void +Trigger::swap_notify () +{ + PropertyChanged (Properties::name); +} + +Trigger* +Trigger::swap_pending (Trigger* t) +{ + return _pending.exchange (t); +} + void Trigger::set_use_follow (bool yn) { @@ -276,7 +299,7 @@ Trigger::set_region (boost::shared_ptr r) { if (!r) { /* clear operation, no need to talk to the worker thread */ - _box.set_pending (_index, TriggerPtr()); + set_pending ((Trigger*) 0); } else { /* load data, do analysis in another thread */ TriggerBox::worker->set_region (_box, index(), r); @@ -575,7 +598,6 @@ AudioTrigger::AudioTrigger (uint32_t n, TriggerBox& b) , got_stretcher_padding (false) , to_pad (0) , to_drop (0) - , _deletion_queue (4) { } @@ -1687,7 +1709,9 @@ TriggerBox::TriggerBox (Session& s, DataType dt) } } - pending.reserve (all_triggers.size()); + while (pending.size() < all_triggers.size()) { + pending.push_back (std::atomic(0)); + } Config->ParameterChanged.connect_same_thread (*this, boost::bind (&TriggerBox::parameter_changed, this, _1)); @@ -1706,14 +1730,14 @@ TriggerBox::set_region (uint32_t slot, boost::shared_ptr region) { /* This is called from our worker thread */ - TriggerPtr t; + Trigger* t; switch (_data_type) { case DataType::AUDIO: - t = boost::make_shared (slot, *this); + t = new AudioTrigger (slot, *this); break; case DataType::MIDI: - t = boost::make_shared (slot, *this); + t = new MIDITrigger (slot, *this); break; } @@ -1725,9 +1749,28 @@ TriggerBox::set_region (uint32_t slot, boost::shared_ptr region) } void -TriggerBox::set_pending (uint32_t slot, TriggerPtr t) +TriggerBox::set_pending (uint32_t slot, Trigger* t) { - pending[slot] = t; + all_triggers[slot]->set_pending (t); +} + +void +TriggerBox::maybe_swap_pending (uint32_t slot) +{ + Trigger* p = 0; + + p = all_triggers[slot]->swap_pending (p); + + if (p) { + std::cerr << " box " << order() << " slot " << slot << " pending discovered, switching\n"; + + if (all_triggers[slot]) { + // _deletion_queue....; + } + + all_triggers[slot].reset (p); + TriggerSwapped (slot); /* EMIT SIGNAL */ + } } void @@ -2118,6 +2161,12 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp process_midi_trigger_requests (bufs); + for (uint32_t n = 0; n < all_triggers.size(); ++n) { + if (all_triggers[n] != _currently_playing) { + maybe_swap_pending (n); + } + } + /* STEP SIX: if at this point there is an active cue, make it trigger * our corresponding slot */ @@ -2145,6 +2194,7 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp if (!_currently_playing) { if ((_currently_playing = get_next_trigger()) != 0) { + maybe_swap_pending (_currently_playing->index()); _currently_playing->startup (); PropertyChanged (Properties::currently_playing); active_trigger_boxes.fetch_add (1); @@ -2222,6 +2272,12 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp explicit_queue.increment_read_idx (1); /* consume the entry we peeked at */ nxt->set_legato_offset (_currently_playing->current_pos()); + + /* starting up next trigger, check for pending */ + + maybe_swap_pending (n); + nxt = trigger (n); + nxt->jump_start (); _currently_playing->jump_stop (); /* and switch */ @@ -2236,6 +2292,11 @@ TriggerBox::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp if (_currently_playing->state() == Trigger::Stopped) { explicit_queue.increment_read_idx (1); /* consume the entry we peeked at */ + + /* starting up next trigger, check for pending */ + maybe_swap_pending (n); + nxt = trigger (n); + nxt->startup (); DEBUG_TRACE (DEBUG::Triggers, string_compose ("%1 was finished, started %2\n", _currently_playing->index(), nxt->index())); _currently_playing = nxt;